From: Jacques Pienaar Date: Tue, 26 Apr 2016 00:09:29 +0000 (+0000) Subject: [lanai] Update handling of structs in arguments to be passed in registers. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2caa01588dd928d954891c15277383ea629638c3;p=clang [lanai] Update handling of structs in arguments to be passed in registers. Previously aggregate types were passed byval, change the ABI to pass these in registers instead. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@267496 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 8ad3290192..9170d5884f 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -6691,6 +6691,7 @@ public: I.info = classifyArgumentType(I.type, State); } + ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const; ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; }; } // end anonymous namespace @@ -6712,21 +6713,72 @@ bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const { return true; } +ABIArgInfo LanaiABIInfo::getIndirectResult(QualType Ty, bool ByVal, + CCState &State) const { + if (!ByVal) { + if (State.FreeRegs) { + --State.FreeRegs; // Non-byval indirects just use one pointer. + return getNaturalAlignIndirectInReg(Ty); + } + return getNaturalAlignIndirect(Ty, false); + } + + // Compute the byval alignment. + constexpr unsigned MinABIStackAlignInBytes = 4; + unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; + return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true, + /*Realign=*/TypeAlign > + MinABIStackAlignInBytes); +} + ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty, CCState &State) const { - if (isAggregateTypeForABI(Ty)) - return getNaturalAlignIndirect(Ty); + // Check with the C++ ABI first. + const RecordType *RT = Ty->getAs(); + if (RT) { + CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); + if (RAA == CGCXXABI::RAA_Indirect) { + return getIndirectResult(Ty, /*ByVal=*/false, State); + } else if (RAA == CGCXXABI::RAA_DirectInMemory) { + return getNaturalAlignIndirect(Ty, /*ByRef=*/true); + } + } + + if (isAggregateTypeForABI(Ty)) { + // Structures with flexible arrays are always indirect. + if (RT && RT->getDecl()->hasFlexibleArrayMember()) + return getIndirectResult(Ty, /*ByVal=*/true, State); + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + llvm::LLVMContext &LLVMContext = getVMContext(); + unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; + if (SizeInRegs <= State.FreeRegs) { + llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); + SmallVector Elements(SizeInRegs, Int32); + llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); + State.FreeRegs -= SizeInRegs; + return ABIArgInfo::getDirectInReg(Result); + } else { + State.FreeRegs = 0; + } + return getIndirectResult(Ty, true, State); + } // Treat an enum type as its underlying type. if (const auto *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); - if (shouldUseInReg(Ty, State)) - return ABIArgInfo::getDirectInReg(); - - if (Ty->isPromotableIntegerType()) + bool InReg = shouldUseInReg(Ty, State); + if (Ty->isPromotableIntegerType()) { + if (InReg) + return ABIArgInfo::getDirectInReg(); return ABIArgInfo::getExtend(); - + } + if (InReg) + return ABIArgInfo::getDirectInReg(); return ABIArgInfo::getDirect(); } diff --git a/test/CodeGen/lanai-arguments.c b/test/CodeGen/lanai-arguments.c index 43a6c3280c..9ce4ed98a7 100644 --- a/test/CodeGen/lanai-arguments.c +++ b/test/CodeGen/lanai-arguments.c @@ -10,7 +10,7 @@ typedef struct { int aa; int bb; } s1; -// CHECK: define void @f1(%struct.s1* byval align 4 %i) +// CHECK: define void @f1(i32 inreg %i.coerce0, i32 inreg %i.coerce1) void f1(s1 i) {} typedef struct { @@ -61,8 +61,8 @@ union simple_union { int a; char b; }; -// Unions should be passed as byval structs. -// CHECK: define void @f9(%union.simple_union* byval align 4 %s) +// Unions should be passed inreg. +// CHECK: define void @f9(i32 inreg %s.coerce) void f9(union simple_union s) {} typedef struct { @@ -70,6 +70,6 @@ typedef struct { int b3 : 3; int b8 : 8; } bitfield1; -// Bitfields should be passed as byval structs. -// CHECK: define void @f10(%struct.bitfield1* byval align 4 %bf1) +// Bitfields should be passed inreg. +// CHECK: define void @f10(i32 inreg %bf1.coerce) void f10(bitfield1 bf1) {}