From e74d91314abb82891dcd3e6f8ef6d91e4e97c981 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Tue, 26 Apr 2016 00:09:29 +0000 Subject: [PATCH] [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. llvm-svn: 267496 --- clang/lib/CodeGen/TargetInfo.cpp | 66 ++++++++++++++++++++++++++++++++---- clang/test/CodeGen/lanai-arguments.c | 10 +++--- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 8ad3290..9170d58 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/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/clang/test/CodeGen/lanai-arguments.c b/clang/test/CodeGen/lanai-arguments.c index 43a6c32..9ce4ed9 100644 --- a/clang/test/CodeGen/lanai-arguments.c +++ b/clang/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) {} -- 2.7.4