-
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
479 additions
and
21 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
176 changes: 176 additions & 0 deletions
176
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,176 @@ | ||
//====- 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 lowerGenericAArch64VAArg(CIRBaseBuilderTy &builder, | ||
mlir::cir::VAArgOp op); | ||
}; | ||
} // namespace | ||
|
||
LoweringPrepareCXXABI * | ||
LoweringPrepareCXXABI::createAArch64ABI(clang::TargetCXXABI::Kind k) { | ||
return new LoweringPrepareAArch64CXXABI(k); | ||
} | ||
|
||
mlir::Value LoweringPrepareAArch64CXXABI::lowerGenericAArch64VAArg( | ||
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>(); | ||
assert(isSupportedType); | ||
|
||
assert(!MissingFeatures::handleBigEndian()); | ||
|
||
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); | ||
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); | ||
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 lowerGenericAArch64VAArg(builder, op); | ||
} | ||
// Return empty value here so CIR Lowering don't do anything. | ||
// This would leave the responsibility to LLVM Lowering to handle cir.va_arg | ||
// which could be better if algorithm is simple. | ||
return mlir::Value(); | ||
} |
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
24 changes: 24 additions & 0 deletions
24
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,24 @@ | ||
//====- 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, | ||
mlir::cir::DynamicCastOp op) override; | ||
mlir::Value lowerVAArg(CIRBaseBuilderTy &builder, | ||
mlir::cir::VAArgOp op) override; | ||
}; |
Oops, something went wrong.