-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AArch64 ABI lowering cir.var_arg, squashed related commits
- Loading branch information
Showing
11 changed files
with
513 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
181 changes: 181 additions & 0 deletions
181
clang/lib/CIR/Dialect/Transforms/LoweringPrepareAArch64CXXABI.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
//====- LoweringPrepareArm64CXXABI.cpp - Arm64 ABI specific code -----====// | ||
// | ||
// Part of the LLVM Project, | ||
// under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===------------------------------------------------------------------===// | ||
// | ||
// This file provides ARM64 C++ ABI specific code that is used during LLVMIR | ||
// lowering prepare. | ||
// | ||
//===------------------------------------------------------------------===// | ||
|
||
#include "../IR/MissingFeatures.h" | ||
#include "LoweringPrepareItaniumCXXABI.h" | ||
|
||
#include <assert.h> | ||
|
||
using cir::LoweringPrepareCXXABI; | ||
using cir::MissingFeatures; | ||
|
||
using namespace mlir; | ||
using namespace mlir::cir; | ||
|
||
namespace { | ||
class LoweringPrepareAArch64CXXABI : public LoweringPrepareItaniumCXXABI { | ||
public: | ||
LoweringPrepareAArch64CXXABI(clang::TargetCXXABI::Kind k) : Kind(k) {} | ||
mlir::Value lowerVAArg(CIRBaseBuilderTy &builder, | ||
mlir::cir::VAArgOp op) override; | ||
|
||
private: | ||
clang::TargetCXXABI::Kind Kind; | ||
mlir::Value lowerAAPCSVAArg(CIRBaseBuilderTy &builder, mlir::cir::VAArgOp op); | ||
}; | ||
} // namespace | ||
|
||
LoweringPrepareCXXABI * | ||
LoweringPrepareCXXABI::createAArch64ABI(clang::TargetCXXABI::Kind k) { | ||
return new LoweringPrepareAArch64CXXABI(k); | ||
} | ||
|
||
mlir::Value | ||
LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(CIRBaseBuilderTy &builder, | ||
mlir::cir::VAArgOp op) { | ||
auto loc = op->getLoc(); | ||
auto valist = op->getOperand(0); | ||
auto opResTy = op.getType(); | ||
// front end should not produce non-scalar type of VAArgOp | ||
bool isSupportedType = | ||
opResTy.isa<mlir::cir::IntType, mlir::cir::SingleType, | ||
mlir::cir::PointerType, mlir::cir::BoolType, | ||
mlir::cir::DoubleType>(); | ||
|
||
// Homogenous Aggregate type not supported and indirect arg | ||
// passing not supported yet. And for these supported types, | ||
// we should not have alignment greater than 8 problem. | ||
assert(isSupportedType); | ||
assert(!MissingFeatures::handleAArch64Indirect()); | ||
|
||
bool isFloatingType = | ||
opResTy.isa<mlir::cir::SingleType, mlir::cir::DoubleType>(); | ||
|
||
// The AArch64 va_list type and handling is specified in the Procedure Call | ||
// Standard, section B.4: | ||
// | ||
// struct { | ||
// void *__stack; | ||
// void *__gr_top; | ||
// void *__vr_top; | ||
// int __gr_offs; | ||
// int __vr_offs; | ||
// }; | ||
auto curInsertionP = builder.saveInsertionPoint(); | ||
auto currentBlock = builder.getInsertionBlock(); | ||
auto boolTy = builder.getBoolTy(); | ||
|
||
auto maybeRegBlock = builder.createBlock(builder.getBlock()->getParent()); | ||
auto inRegBlock = builder.createBlock(builder.getBlock()->getParent()); | ||
auto onStackBlock = builder.createBlock(builder.getBlock()->getParent()); | ||
|
||
//======================================= | ||
// Find out where argument was passed | ||
//======================================= | ||
|
||
// If v/gr_offs >= 0 we're already using the stack for this type of | ||
// argument. We don't want to keep updating reg_offs (in case it overflows, | ||
// though anyone passing 2GB of arguments, each at most 16 bytes, deserves | ||
// whatever they get). | ||
builder.restoreInsertionPoint(curInsertionP); | ||
// 3 is the field number of __gr_offs, 4 is the field number of __vr_offs | ||
auto offsP = builder.createGetMemberOp(loc, valist, | ||
isFloatingType ? "vr_offs" : "gr_offs", | ||
isFloatingType ? 4 : 3); | ||
auto offs = builder.create<mlir::cir::LoadOp>(loc, offsP); | ||
auto zeroValue = builder.create<mlir::cir::ConstantOp>( | ||
loc, offs.getType(), mlir::cir::IntAttr::get(offs.getType(), 0)); | ||
auto cmpRes = builder.create<mlir::cir::CmpOp>(loc, boolTy, CmpOpKind::ge, | ||
offs, zeroValue); | ||
builder.create<mlir::cir::BrCondOp>(loc, cmpRes, onStackBlock, maybeRegBlock); | ||
auto newEndBlock = currentBlock->splitBlock(op); | ||
|
||
// maybeRegBlock updates the gr_offs/vr_offs pointer for next call to va_arg | ||
// on this va_list. The fact that this is done unconditionally reflects the | ||
// fact that allocating an argument to the stack also uses up all the | ||
// remaining registers of the appropriate kind. | ||
builder.setInsertionPointToEnd(maybeRegBlock); | ||
auto boundaryValue = builder.create<mlir::cir::ConstantOp>( | ||
loc, offs.getType(), | ||
mlir::cir::IntAttr::get(offs.getType(), isFloatingType ? 16 : 8)); | ||
auto newRegsOffs = builder.create<mlir::cir::BinOp>( | ||
loc, offs.getType(), mlir::cir::BinOpKind::Add, offs, boundaryValue); | ||
builder.createStore(loc, newRegsOffs, offsP); | ||
// Now we're in a position to decide whether this argument really was in | ||
// registers or not. | ||
auto maybeRegCmpRes = builder.create<mlir::cir::CmpOp>( | ||
loc, boolTy, CmpOpKind::le, newRegsOffs, zeroValue); | ||
builder.create<mlir::cir::BrCondOp>(loc, maybeRegCmpRes, inRegBlock, | ||
onStackBlock); | ||
|
||
//======================================= | ||
// Argument was on the stack | ||
//======================================= | ||
builder.setInsertionPointToEnd(onStackBlock); | ||
auto stackP = builder.createGetMemberOp(loc, valist, "stack", 0); | ||
// On big-endian platforms, the value will be right-aligned in its stack slot. | ||
assert(!MissingFeatures::handleBigEndian()); | ||
auto stack = builder.create<mlir::cir::LoadOp>(loc, stackP); | ||
auto ptrDiffTy = | ||
mlir::cir::IntType::get(builder.getContext(), 64, /*signed=*/false); | ||
auto eight = builder.create<mlir::cir::ConstantOp>( | ||
loc, ptrDiffTy, mlir::cir::IntAttr::get(ptrDiffTy, 8)); | ||
auto i8Ty = IntegerType::get(builder.getContext(), 8); | ||
auto i8PtrTy = PointerType::get(builder.getContext(), i8Ty); | ||
auto castStack = builder.createBitcast(stack, i8PtrTy); | ||
// Write the new value of __stack for the next call to va_arg | ||
auto newStackAsi8Ptr = builder.create<mlir::cir::PtrStrideOp>( | ||
loc, castStack.getType(), castStack, eight); | ||
auto newStack = builder.createBitcast(newStackAsi8Ptr, stack.getType()); | ||
builder.createStore(loc, newStack, stackP); | ||
builder.create<mlir::cir::BrOp>(loc, mlir::ValueRange{stack}, newEndBlock); | ||
|
||
//======================================= | ||
// Argument was in registers | ||
//======================================= | ||
// Now we emit the code for if the argument was originally passed in | ||
// registers. First start the appropriate block: | ||
builder.setInsertionPointToEnd(inRegBlock); | ||
auto regTopP = builder.createGetMemberOp(loc, valist, | ||
isFloatingType ? "vr_top" : "gr_top", | ||
isFloatingType ? 2 : 1); | ||
auto regTop = builder.create<mlir::cir::LoadOp>(loc, regTopP); | ||
auto castRegTop = builder.createBitcast(regTop, i8PtrTy); | ||
// On big-endian platforms, the value will be right-aligned in its stack slot. | ||
assert(!MissingFeatures::handleBigEndian()); | ||
auto resAsInt8P = builder.create<mlir::cir::PtrStrideOp>( | ||
loc, castRegTop.getType(), castRegTop, offs); | ||
auto resAsVoidP = builder.createBitcast(resAsInt8P, regTop.getType()); | ||
builder.create<mlir::cir::BrOp>(loc, mlir::ValueRange{resAsVoidP}, | ||
newEndBlock); | ||
|
||
// generate additional instructions for end block | ||
builder.setInsertionPoint(op); | ||
newEndBlock->addArgument(stack.getType(), loc); | ||
auto resP = newEndBlock->getArgument(0); | ||
assert(resP.getType().isa<mlir::cir::PointerType>()); | ||
auto opResPTy = PointerType::get(builder.getContext(), opResTy); | ||
auto castResP = builder.createBitcast(resP, opResPTy); | ||
auto res = builder.create<mlir::cir::LoadOp>(loc, castResP); | ||
return res.getResult(); | ||
} | ||
|
||
mlir::Value LoweringPrepareAArch64CXXABI::lowerVAArg(CIRBaseBuilderTy &builder, | ||
mlir::cir::VAArgOp op) { | ||
|
||
if (Kind == clang::TargetCXXABI::GenericAArch64) { | ||
return lowerAAPCSVAArg(builder, op); | ||
} | ||
assert(0 && "unsupported AArch64 CXX ABI"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
//====- LoweringPrepareItaniumCXXABI.h - Itanium ABI specific code --------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file provides Itanium C++ ABI specific code that is used during LLVMIR | ||
// lowering prepare. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "LoweringPrepareCXXABI.h" | ||
|
||
using cir::CIRBaseBuilderTy; | ||
|
||
class LoweringPrepareItaniumCXXABI : public cir::LoweringPrepareCXXABI { | ||
public: | ||
mlir::Value lowerDynamicCast(CIRBaseBuilderTy &builder, | ||
clang::ASTContext &astCtx, | ||
mlir::cir::DynamicCastOp op) override; | ||
mlir::Value lowerVAArg(CIRBaseBuilderTy &builder, | ||
mlir::cir::VAArgOp op) override; | ||
}; |
Oops, something went wrong.