Add a coerce-and-expand ABIArgInfo as a generalization of some
of the things we do with Expand / Direct. NFC for now, but this will be used by swiftcall expansion. llvm-svn: 263192
This commit is contained in:
parent
c56a8b3284
commit
f26e73df75
|
@ -19,15 +19,11 @@
|
|||
#include "clang/AST/CanonicalType.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
class Type;
|
||||
class StructType;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
|
||||
|
@ -64,6 +60,12 @@ public:
|
|||
/// are all scalar types or are themselves expandable types.
|
||||
Expand,
|
||||
|
||||
/// CoerceAndExpand - Only valid for aggregate argument types. The
|
||||
/// structure should be expanded into consecutive arguments corresponding
|
||||
/// to the non-array elements of the type stored in CoerceToType.
|
||||
/// Array elements in the type are assumed to be padding and skipped.
|
||||
CoerceAndExpand,
|
||||
|
||||
/// InAlloca - Pass the argument directly using the LLVM inalloca attribute.
|
||||
/// This is similar to indirect with byval, except it only applies to
|
||||
/// arguments stored in memory and forbids any implicit copies. When
|
||||
|
@ -75,8 +77,11 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
llvm::Type *TypeData; // isDirect() || isExtend()
|
||||
llvm::Type *PaddingType;
|
||||
llvm::Type *TypeData; // canHaveCoerceToType()
|
||||
union {
|
||||
llvm::Type *PaddingType; // canHavePaddingType()
|
||||
llvm::Type *UnpaddedCoerceAndExpandType; // isCoerceAndExpand()
|
||||
};
|
||||
union {
|
||||
unsigned DirectOffset; // isDirect() || isExtend()
|
||||
unsigned IndirectAlign; // isIndirect()
|
||||
|
@ -91,8 +96,22 @@ private:
|
|||
bool InReg : 1; // isDirect() || isExtend() || isIndirect()
|
||||
bool CanBeFlattened: 1; // isDirect()
|
||||
|
||||
bool canHavePaddingType() const {
|
||||
return isDirect() || isExtend() || isIndirect() || isExpand();
|
||||
}
|
||||
void setPaddingType(llvm::Type *T) {
|
||||
assert(canHavePaddingType());
|
||||
PaddingType = T;
|
||||
}
|
||||
|
||||
void setUnpaddedCoerceToType(llvm::Type *T) {
|
||||
assert(isCoerceAndExpand());
|
||||
UnpaddedCoerceAndExpandType = T;
|
||||
}
|
||||
|
||||
ABIArgInfo(Kind K)
|
||||
: PaddingType(nullptr), TheKind(K), PaddingInReg(false), InReg(false) {}
|
||||
: TheKind(K), PaddingInReg(false), InReg(false) {
|
||||
}
|
||||
|
||||
public:
|
||||
ABIArgInfo()
|
||||
|
@ -104,8 +123,8 @@ public:
|
|||
bool CanBeFlattened = true) {
|
||||
auto AI = ABIArgInfo(Direct);
|
||||
AI.setCoerceToType(T);
|
||||
AI.setDirectOffset(Offset);
|
||||
AI.setPaddingType(Padding);
|
||||
AI.setDirectOffset(Offset);
|
||||
AI.setCanBeFlattened(CanBeFlattened);
|
||||
return AI;
|
||||
}
|
||||
|
@ -117,6 +136,7 @@ public:
|
|||
static ABIArgInfo getExtend(llvm::Type *T = nullptr) {
|
||||
auto AI = ABIArgInfo(Extend);
|
||||
AI.setCoerceToType(T);
|
||||
AI.setPaddingType(nullptr);
|
||||
AI.setDirectOffset(0);
|
||||
return AI;
|
||||
}
|
||||
|
@ -151,7 +171,9 @@ public:
|
|||
return AI;
|
||||
}
|
||||
static ABIArgInfo getExpand() {
|
||||
return ABIArgInfo(Expand);
|
||||
auto AI = ABIArgInfo(Expand);
|
||||
AI.setPaddingType(nullptr);
|
||||
return AI;
|
||||
}
|
||||
static ABIArgInfo getExpandWithPadding(bool PaddingInReg,
|
||||
llvm::Type *Padding) {
|
||||
|
@ -161,6 +183,54 @@ public:
|
|||
return AI;
|
||||
}
|
||||
|
||||
/// \param unpaddedCoerceToType The coerce-to type with padding elements
|
||||
/// removed, canonicalized to a single element if it would otherwise
|
||||
/// have exactly one element.
|
||||
static ABIArgInfo getCoerceAndExpand(llvm::StructType *coerceToType,
|
||||
llvm::Type *unpaddedCoerceToType) {
|
||||
#ifndef NDEBUG
|
||||
// Sanity checks on unpaddedCoerceToType.
|
||||
|
||||
// Assert that we only have a struct type if there are multiple elements.
|
||||
auto unpaddedStruct = dyn_cast<llvm::StructType>(unpaddedCoerceToType);
|
||||
assert(!unpaddedStruct || unpaddedStruct->getNumElements() != 1);
|
||||
|
||||
// Assert that all the non-padding elements have a corresponding element
|
||||
// in the unpadded type.
|
||||
unsigned unpaddedIndex = 0;
|
||||
for (auto eltType : coerceToType->elements()) {
|
||||
if (isPaddingForCoerceAndExpand(eltType)) continue;
|
||||
if (unpaddedStruct) {
|
||||
assert(unpaddedStruct->getElementType(unpaddedIndex) == eltType);
|
||||
} else {
|
||||
assert(unpaddedIndex == 0 && unpaddedCoerceToType == eltType);
|
||||
}
|
||||
unpaddedIndex++;
|
||||
}
|
||||
|
||||
// Assert that there aren't extra elements in the unpadded type.
|
||||
if (unpaddedStruct) {
|
||||
assert(unpaddedStruct->getNumElements() == unpaddedIndex);
|
||||
} else {
|
||||
assert(unpaddedIndex == 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto AI = ABIArgInfo(CoerceAndExpand);
|
||||
AI.setCoerceToType(coerceToType);
|
||||
AI.setUnpaddedCoerceToType(unpaddedCoerceToType);
|
||||
return AI;
|
||||
}
|
||||
|
||||
static bool isPaddingForCoerceAndExpand(llvm::Type *eltType) {
|
||||
if (eltType->isArrayTy()) {
|
||||
assert(eltType->getArrayElementType()->isIntegerTy(8));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Kind getKind() const { return TheKind; }
|
||||
bool isDirect() const { return TheKind == Direct; }
|
||||
bool isInAlloca() const { return TheKind == InAlloca; }
|
||||
|
@ -168,8 +238,11 @@ public:
|
|||
bool isIgnore() const { return TheKind == Ignore; }
|
||||
bool isIndirect() const { return TheKind == Indirect; }
|
||||
bool isExpand() const { return TheKind == Expand; }
|
||||
bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
|
||||
|
||||
bool canHaveCoerceToType() const { return isDirect() || isExtend(); }
|
||||
bool canHaveCoerceToType() const {
|
||||
return isDirect() || isExtend() || isCoerceAndExpand();
|
||||
}
|
||||
|
||||
// Direct/Extend accessors
|
||||
unsigned getDirectOffset() const {
|
||||
|
@ -181,9 +254,9 @@ public:
|
|||
DirectOffset = Offset;
|
||||
}
|
||||
|
||||
llvm::Type *getPaddingType() const { return PaddingType; }
|
||||
|
||||
void setPaddingType(llvm::Type *T) { PaddingType = T; }
|
||||
llvm::Type *getPaddingType() const {
|
||||
return (canHavePaddingType() ? PaddingType : nullptr);
|
||||
}
|
||||
|
||||
bool getPaddingInReg() const {
|
||||
return PaddingInReg;
|
||||
|
@ -202,6 +275,26 @@ public:
|
|||
TypeData = T;
|
||||
}
|
||||
|
||||
llvm::StructType *getCoerceAndExpandType() const {
|
||||
assert(isCoerceAndExpand());
|
||||
return cast<llvm::StructType>(TypeData);
|
||||
}
|
||||
|
||||
llvm::Type *getUnpaddedCoerceAndExpandType() const {
|
||||
assert(isCoerceAndExpand());
|
||||
return UnpaddedCoerceAndExpandType;
|
||||
}
|
||||
|
||||
ArrayRef<llvm::Type *>getCoerceAndExpandTypeSequence() const {
|
||||
assert(isCoerceAndExpand());
|
||||
if (auto structTy =
|
||||
dyn_cast<llvm::StructType>(UnpaddedCoerceAndExpandType)) {
|
||||
return structTy->elements();
|
||||
} else {
|
||||
return llvm::makeArrayRef(&UnpaddedCoerceAndExpandType, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool getInReg() const {
|
||||
assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
|
||||
return InReg;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
|
||||
#define LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
|
||||
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "Address.h"
|
||||
#include "CodeGenTypeCache.h"
|
||||
|
@ -194,6 +195,12 @@ public:
|
|||
Addr.getPointer(), Index, Name),
|
||||
Addr.getAlignment().alignmentAtOffset(Offset));
|
||||
}
|
||||
Address CreateStructGEP(Address Addr, unsigned Index,
|
||||
const llvm::StructLayout *Layout,
|
||||
const llvm::Twine &Name = "") {
|
||||
auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index));
|
||||
return CreateStructGEP(Addr, Index, Offset, Name);
|
||||
}
|
||||
|
||||
/// Given
|
||||
/// %addr = [n x T]* ...
|
||||
|
|
|
@ -1357,11 +1357,13 @@ void ClangToLLVMArgMapping::construct(const ASTContext &Context,
|
|||
// ignore and inalloca doesn't have matching LLVM parameters.
|
||||
IRArgs.NumberOfArgs = 0;
|
||||
break;
|
||||
case ABIArgInfo::Expand: {
|
||||
case ABIArgInfo::CoerceAndExpand:
|
||||
IRArgs.NumberOfArgs = AI.getCoerceAndExpandTypeSequence().size();
|
||||
break;
|
||||
case ABIArgInfo::Expand:
|
||||
IRArgs.NumberOfArgs = getExpansionSize(ArgType, Context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (IRArgs.NumberOfArgs > 0) {
|
||||
IRArgs.FirstArgIndex = IRArgNo;
|
||||
|
@ -1460,6 +1462,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
|
|||
case ABIArgInfo::Ignore:
|
||||
resultType = llvm::Type::getVoidTy(getLLVMContext());
|
||||
break;
|
||||
|
||||
case ABIArgInfo::CoerceAndExpand:
|
||||
resultType = retAI.getUnpaddedCoerceAndExpandType();
|
||||
break;
|
||||
}
|
||||
|
||||
ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI, true);
|
||||
|
@ -1527,6 +1533,15 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
|
|||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::CoerceAndExpand: {
|
||||
auto ArgTypesIter = ArgTypes.begin() + FirstIRArg;
|
||||
for (auto EltTy : ArgInfo.getCoerceAndExpandTypeSequence()) {
|
||||
*ArgTypesIter++ = EltTy;
|
||||
}
|
||||
assert(ArgTypesIter == ArgTypes.begin() + FirstIRArg + NumIRArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::Expand:
|
||||
auto ArgTypesIter = ArgTypes.begin() + FirstIRArg;
|
||||
getExpandedTypes(it->type, ArgTypesIter);
|
||||
|
@ -1768,6 +1783,9 @@ void CodeGenModule::ConstructAttributeList(
|
|||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::CoerceAndExpand:
|
||||
break;
|
||||
|
||||
case ABIArgInfo::Expand:
|
||||
llvm_unreachable("Invalid ABI kind for return argument");
|
||||
}
|
||||
|
@ -1875,7 +1893,8 @@ void CodeGenModule::ConstructAttributeList(
|
|||
}
|
||||
case ABIArgInfo::Ignore:
|
||||
case ABIArgInfo::Expand:
|
||||
continue;
|
||||
case ABIArgInfo::CoerceAndExpand:
|
||||
break;
|
||||
|
||||
case ABIArgInfo::InAlloca:
|
||||
// inalloca disables readnone and readonly.
|
||||
|
@ -2248,6 +2267,29 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
|||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::CoerceAndExpand: {
|
||||
// Reconstruct into a temporary.
|
||||
Address alloca = CreateMemTemp(Ty, getContext().getDeclAlign(Arg));
|
||||
ArgVals.push_back(ParamValue::forIndirect(alloca));
|
||||
|
||||
auto coercionType = ArgI.getCoerceAndExpandType();
|
||||
alloca = Builder.CreateElementBitCast(alloca, coercionType);
|
||||
auto layout = CGM.getDataLayout().getStructLayout(coercionType);
|
||||
|
||||
unsigned argIndex = FirstIRArg;
|
||||
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
|
||||
llvm::Type *eltType = coercionType->getElementType(i);
|
||||
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType))
|
||||
continue;
|
||||
|
||||
auto eltAddr = Builder.CreateStructGEP(alloca, i, layout);
|
||||
auto elt = FnArgs[argIndex++];
|
||||
Builder.CreateStore(elt, eltAddr);
|
||||
}
|
||||
assert(argIndex == FirstIRArg + NumIRArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::Expand: {
|
||||
// If this structure was expanded into multiple arguments then
|
||||
// we need to create a temporary and reconstruct it from the
|
||||
|
@ -2638,6 +2680,40 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
|||
case ABIArgInfo::Ignore:
|
||||
break;
|
||||
|
||||
case ABIArgInfo::CoerceAndExpand: {
|
||||
auto coercionType = RetAI.getCoerceAndExpandType();
|
||||
auto layout = CGM.getDataLayout().getStructLayout(coercionType);
|
||||
|
||||
// Load all of the coerced elements out into results.
|
||||
llvm::SmallVector<llvm::Value*, 4> results;
|
||||
Address addr = Builder.CreateElementBitCast(ReturnValue, coercionType);
|
||||
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
|
||||
auto coercedEltType = coercionType->getElementType(i);
|
||||
if (ABIArgInfo::isPaddingForCoerceAndExpand(coercedEltType))
|
||||
continue;
|
||||
|
||||
auto eltAddr = Builder.CreateStructGEP(addr, i, layout);
|
||||
auto elt = Builder.CreateLoad(eltAddr);
|
||||
results.push_back(elt);
|
||||
}
|
||||
|
||||
// If we have one result, it's the single direct result type.
|
||||
if (results.size() == 1) {
|
||||
RV = results[0];
|
||||
|
||||
// Otherwise, we need to make a first-class aggregate.
|
||||
} else {
|
||||
// Construct a return type that lacks padding elements.
|
||||
llvm::Type *returnType = RetAI.getUnpaddedCoerceAndExpandType();
|
||||
|
||||
RV = llvm::UndefValue::get(returnType);
|
||||
for (unsigned i = 0, e = results.size(); i != e; ++i) {
|
||||
RV = Builder.CreateInsertValue(RV, results[i], i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::Expand:
|
||||
llvm_unreachable("Invalid ABI kind for return argument");
|
||||
}
|
||||
|
@ -3377,7 +3453,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
|||
// alloca to hold the result, unless one is given to us.
|
||||
Address SRetPtr = Address::invalid();
|
||||
size_t UnusedReturnSize = 0;
|
||||
if (RetAI.isIndirect() || RetAI.isInAlloca()) {
|
||||
if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) {
|
||||
if (!ReturnValue.isNull()) {
|
||||
SRetPtr = ReturnValue.getValue();
|
||||
} else {
|
||||
|
@ -3391,7 +3467,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
|||
}
|
||||
if (IRFunctionArgs.hasSRetArg()) {
|
||||
IRCallArgs[IRFunctionArgs.getSRetArgNo()] = SRetPtr.getPointer();
|
||||
} else {
|
||||
} else if (RetAI.isInAlloca()) {
|
||||
Address Addr = createInAllocaStructGEP(RetAI.getInAllocaFieldIndex());
|
||||
Builder.CreateStore(SRetPtr.getPointer(), Addr);
|
||||
}
|
||||
|
@ -3571,6 +3647,29 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
|||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::CoerceAndExpand: {
|
||||
assert(RV.isAggregate() &&
|
||||
"CoerceAndExpand does not support non-aggregate types yet");
|
||||
|
||||
auto coercionType = ArgInfo.getCoerceAndExpandType();
|
||||
auto layout = CGM.getDataLayout().getStructLayout(coercionType);
|
||||
|
||||
Address addr = RV.getAggregateAddress();
|
||||
addr = Builder.CreateElementBitCast(addr, coercionType);
|
||||
|
||||
unsigned IRArgPos = FirstIRArg;
|
||||
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
|
||||
llvm::Type *eltType = coercionType->getElementType(i);
|
||||
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
|
||||
Address eltAddr = Builder.CreateStructGEP(addr, i, layout);
|
||||
llvm::Value *elt = Builder.CreateLoad(eltAddr);
|
||||
IRCallArgs[IRArgPos++] = elt;
|
||||
}
|
||||
assert(IRArgPos == FirstIRArg + NumIRArgs);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::Expand:
|
||||
unsigned IRArgPos = FirstIRArg;
|
||||
ExpandTypeToArgs(I->Ty, RV, IRFuncTy, IRCallArgs, IRArgPos);
|
||||
|
@ -3770,6 +3869,24 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
|||
return ret;
|
||||
}
|
||||
|
||||
case ABIArgInfo::CoerceAndExpand: {
|
||||
auto coercionType = RetAI.getCoerceAndExpandType();
|
||||
auto layout = CGM.getDataLayout().getStructLayout(coercionType);
|
||||
|
||||
Address addr = SRetPtr;
|
||||
addr = Builder.CreateElementBitCast(addr, coercionType);
|
||||
|
||||
unsigned unpaddedIndex = 0;
|
||||
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
|
||||
llvm::Type *eltType = coercionType->getElementType(i);
|
||||
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
|
||||
Address eltAddr = Builder.CreateStructGEP(addr, i, layout);
|
||||
llvm::Value *elt = Builder.CreateExtractValue(CI, unpaddedIndex++);
|
||||
Builder.CreateStore(elt, eltAddr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ABIArgInfo::Ignore:
|
||||
// If we are ignoring an argument that had a result, make sure to
|
||||
// construct the appropriate return value for our caller.
|
||||
|
|
|
@ -160,6 +160,10 @@ LLVM_DUMP_METHOD void ABIArgInfo::dump() const {
|
|||
case Expand:
|
||||
OS << "Expand";
|
||||
break;
|
||||
case CoerceAndExpand:
|
||||
OS << "CoerceAndExpand Type=";
|
||||
getCoerceAndExpandType()->print(OS);
|
||||
break;
|
||||
}
|
||||
OS << ")\n";
|
||||
}
|
||||
|
@ -1570,6 +1574,7 @@ static bool isArgInAlloca(const ABIArgInfo &Info) {
|
|||
case ABIArgInfo::Direct:
|
||||
case ABIArgInfo::Extend:
|
||||
case ABIArgInfo::Expand:
|
||||
case ABIArgInfo::CoerceAndExpand:
|
||||
if (Info.getInReg())
|
||||
return false;
|
||||
return true;
|
||||
|
@ -6829,6 +6834,7 @@ Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|||
CharUnits Stride;
|
||||
switch (AI.getKind()) {
|
||||
case ABIArgInfo::Expand:
|
||||
case ABIArgInfo::CoerceAndExpand:
|
||||
case ABIArgInfo::InAlloca:
|
||||
llvm_unreachable("Unsupported ABI kind for va_arg");
|
||||
|
||||
|
@ -7059,6 +7065,7 @@ Address XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|||
CharUnits ArgSize = CharUnits::Zero();
|
||||
switch (AI.getKind()) {
|
||||
case ABIArgInfo::Expand:
|
||||
case ABIArgInfo::CoerceAndExpand:
|
||||
case ABIArgInfo::InAlloca:
|
||||
llvm_unreachable("Unsupported ABI kind for va_arg");
|
||||
case ABIArgInfo::Ignore:
|
||||
|
|
Loading…
Reference in New Issue