Author: pirama Date: Wed Jul 27 14:01:51 2016 New Revision: 276904 URL: http://llvm.org/viewvc/llvm-project?rev=276904&view=rev Log: Adjust coercion of aggregates on RenderScript
Summary: In RenderScript, the size of the argument or return value emitted in the IR is expected to be the same as the size of corresponding qualified type. For ARM and AArch64, the coercion performed by Clang can change the parameter or return value to a type whose size is different (usually larger) than the original aggregate type. Specifically, this can happen in the following cases: - Aggregate parameters of size <= 64 bytes and return values smaller than 4 bytes on ARM - Aggregate parameters and return values smaller than bytes on AArch64 This patch coerces the cases above to an integer array that is the same size and alignment as the original aggregate. A new field is added to TargetInfo to detect a RenderScript target and limit this coercion just to that case. Tests added to test/CodeGen/renderscript.c Reviewers: rsmith Subscribers: aemerson, srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D22822 Modified: cfe/trunk/include/clang/Basic/TargetInfo.h cfe/trunk/lib/Basic/TargetInfo.cpp cfe/trunk/lib/Basic/Targets.cpp cfe/trunk/lib/CodeGen/TargetInfo.cpp cfe/trunk/test/CodeGen/renderscript.c Modified: cfe/trunk/include/clang/Basic/TargetInfo.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=276904&r1=276903&r2=276904&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/TargetInfo.h (original) +++ cfe/trunk/include/clang/Basic/TargetInfo.h Wed Jul 27 14:01:51 2016 @@ -92,6 +92,8 @@ protected: unsigned HasBuiltinMSVaList : 1; + unsigned IsRenderScriptTarget : 1; + // TargetInfo Constructor. Default initializes all fields. TargetInfo(const llvm::Triple &T); @@ -565,6 +567,9 @@ public: /// available on this target. bool hasBuiltinMSVaList() const { return HasBuiltinMSVaList; } + /// Returns true for RenderScript. + bool isRenderScriptTarget() const { return IsRenderScriptTarget; } + /// \brief Returns whether the passed in string is a valid clobber in an /// inline asm statement. /// Modified: cfe/trunk/lib/Basic/TargetInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/TargetInfo.cpp?rev=276904&r1=276903&r2=276904&view=diff ============================================================================== --- cfe/trunk/lib/Basic/TargetInfo.cpp (original) +++ cfe/trunk/lib/Basic/TargetInfo.cpp Wed Jul 27 14:01:51 2016 @@ -80,6 +80,7 @@ TargetInfo::TargetInfo(const llvm::Tripl SSERegParmMax = 0; HasAlignMac68kSupport = false; HasBuiltinMSVaList = false; + IsRenderScriptTarget = false; // Default to no types using fpret. RealTypeUsesObjCFPRet = 0; Modified: cfe/trunk/lib/Basic/Targets.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets.cpp?rev=276904&r1=276903&r2=276904&view=diff ============================================================================== --- cfe/trunk/lib/Basic/Targets.cpp (original) +++ cfe/trunk/lib/Basic/Targets.cpp Wed Jul 27 14:01:51 2016 @@ -8113,6 +8113,7 @@ public: Triple.getOSName(), Triple.getEnvironmentName()), Opts) { + IsRenderScriptTarget = true; LongWidth = LongAlign = 64; } void getTargetDefines(const LangOptions &Opts, @@ -8130,7 +8131,9 @@ public: : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(), Triple.getOSName(), Triple.getEnvironmentName()), - Opts) {} + Opts) { + IsRenderScriptTarget = true; + } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=276904&r1=276903&r2=276904&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Wed Jul 27 14:01:51 2016 @@ -31,6 +31,31 @@ using namespace clang; using namespace CodeGen; +// Helper for coercing an aggregate argument or return value into an integer +// array of the same size (including padding) and alignment. This alternate +// coercion happens only for the RenderScript ABI and can be removed after +// runtimes that rely on it are no longer supported. +// +// RenderScript assumes that the size of the argument / return value in the IR +// is the same as the size of the corresponding qualified type. This helper +// coerces the aggregate type into an array of the same size (including +// padding). This coercion is used in lieu of expansion of struct members or +// other canonical coercions that return a coerced-type of larger size. +// +// Ty - The argument / return value type +// Context - The associated ASTContext +// LLVMContext - The associated LLVMContext +static ABIArgInfo coerceToIntArray(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &LLVMContext) { + // Alignment and Size are measured in bits. + const uint64_t Size = Context.getTypeSize(Ty); + const uint64_t Alignment = Context.getTypeAlign(Ty); + llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Alignment); + const uint64_t NumElements = (Size + Alignment - 1) / Alignment; + return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements)); +} + static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder, llvm::Value *Array, llvm::Value *Value, @@ -4556,6 +4581,11 @@ ABIArgInfo AArch64ABIInfo::classifyArgum // Aggregates <= 16 bytes are passed directly in registers or on the stack. uint64_t Size = getContext().getTypeSize(Ty); if (Size <= 128) { + // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of + // same size and alignment. + if (getTarget().isRenderScriptTarget()) { + return coerceToIntArray(Ty, getContext(), getVMContext()); + } unsigned Alignment = getContext().getTypeAlign(Ty); Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes @@ -4601,6 +4631,11 @@ ABIArgInfo AArch64ABIInfo::classifyRetur // Aggregates <= 16 bytes are returned directly in registers or on the stack. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 128) { + // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of + // same size and alignment. + if (getTarget().isRenderScriptTarget()) { + return coerceToIntArray(RetTy, getContext(), getVMContext()); + } unsigned Alignment = getContext().getTypeAlign(RetTy); Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes @@ -5291,6 +5326,12 @@ ABIArgInfo ARMABIInfo::classifyArgumentT /*Realign=*/TyAlign > ABIAlign); } + // On RenderScript, coerce Aggregates <= 64 bytes to an integer array of + // same size and alignment. + if (getTarget().isRenderScriptTarget()) { + return coerceToIntArray(Ty, getContext(), getVMContext()); + } + // Otherwise, pass by coercing to a structure of the appropriate size. llvm::Type* ElemTy; unsigned SizeRegs; @@ -5472,6 +5513,11 @@ ABIArgInfo ARMABIInfo::classifyReturnTyp // are returned indirectly. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 32) { + // On RenderScript, coerce Aggregates <= 4 bytes to an integer array of + // same size and alignment. + if (getTarget().isRenderScriptTarget()) { + return coerceToIntArray(RetTy, getContext(), getVMContext()); + } if (getDataLayout().isBigEndian()) // Return in 32 bit integer integer type (as if loaded by LDR, AAPCS 5.4) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); Modified: cfe/trunk/test/CodeGen/renderscript.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/renderscript.c?rev=276904&r1=276903&r2=276904&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/renderscript.c (original) +++ cfe/trunk/test/CodeGen/renderscript.c Wed Jul 27 14:01:51 2016 @@ -23,3 +23,118 @@ _Static_assert(_Alignof(long) == LONG_WI long test_long(long v) { return v + 1; } + +// ============================================================================= +// Test coercion of aggregate argument or return value into integer arrays +// ============================================================================= + +// ============================================================================= +// aggregate parameter <= 4 bytes: coerced to [a x iNN] for both 32-bit and +// 64-bit RenderScript +// ============================================================================== + +typedef struct {char c1, c2, c3; } sChar3; +typedef struct {short s; char c;} sShortChar; + +// CHECK-RS32: void @argChar3([3 x i8] %s.coerce) +// CHECK-RS64: void @argChar3([3 x i8] %s.coerce) +void argChar3(sChar3 s) {} + +// CHECK-RS32: void @argShortChar([2 x i16] %s.coerce) +// CHECK-RS64: void @argShortChar([2 x i16] %s.coerce) +void argShortChar(sShortChar s) {} + +// ============================================================================= +// aggregate return value <= 4 bytes: coerced to [a x iNN] for both 32-bit and +// 64-bit RenderScript +// ============================================================================= + +// CHECK-RS32: [3 x i8] @retChar3() +// CHECK-RS64: [3 x i8] @retChar3() +sChar3 retChar3() { sChar3 r; return r; } + +// CHECK-RS32: [2 x i16] @retShortChar() +// CHECK-RS64: [2 x i16] @retShortChar() +sShortChar retShortChar() { sShortChar r; return r; } + +// ============================================================================= +// aggregate parameter <= 16 bytes: coerced to [a x iNN] for both 32-bit and +// 64-bit RenderScript +// ============================================================================= + +typedef struct {short s1; char c; short s2; } sShortCharShort; +typedef struct {int i; short s; char c; } sIntShortChar; +typedef struct {long l; int i; } sLongInt; + +// CHECK-RS32: void @argShortCharShort([3 x i16] %s.coerce) +// CHECK-RS64: void @argShortCharShort([3 x i16] %s.coerce) +void argShortCharShort(sShortCharShort s) {} + +// CHECK-RS32: void @argIntShortChar([2 x i32] %s.coerce) +// CHECK-RS64: void @argIntShortChar([2 x i32] %s.coerce) +void argIntShortChar(sIntShortChar s) {} + +// CHECK-RS32: void @argLongInt([2 x i64] %s.coerce) +// CHECK-RS64: void @argLongInt([2 x i64] %s.coerce) +void argLongInt(sLongInt s) {} + +// ============================================================================= +// aggregate return value <= 16 bytes: returned on stack for 32-bit RenderScript +// and coerced to [a x iNN] for 64-bit RenderScript +// ============================================================================= + +// CHECK-RS32: void @retShortCharShort(%struct.sShortCharShort* noalias sret %agg.result) +// CHECK-RS64: [3 x i16] @retShortCharShort() +sShortCharShort retShortCharShort() { sShortCharShort r; return r; } + +// CHECK-RS32: void @retIntShortChar(%struct.sIntShortChar* noalias sret %agg.result) +// CHECK-RS64: [2 x i32] @retIntShortChar() +sIntShortChar retIntShortChar() { sIntShortChar r; return r; } + +// CHECK-RS32: void @retLongInt(%struct.sLongInt* noalias sret %agg.result) +// CHECK-RS64: [2 x i64] @retLongInt() +sLongInt retLongInt() { sLongInt r; return r; } + +// ============================================================================= +// aggregate parameter <= 64 bytes: coerced to [a x iNN] for 32-bit RenderScript +// and passed on the stack for 64-bit RenderScript +// ============================================================================= + +typedef struct {int i1, i2, i3, i4, i5; } sInt5; +typedef struct {long l1, l2; char c; } sLong2Char; + +// CHECK-RS32: void @argInt5([5 x i32] %s.coerce) +// CHECK-RS64: void @argInt5(%struct.sInt5* %s) +void argInt5(sInt5 s) {} + +// CHECK-RS32: void @argLong2Char([3 x i64] %s.coerce) +// CHECK-RS64: void @argLong2Char(%struct.sLong2Char* %s) +void argLong2Char(sLong2Char s) {} + +// ============================================================================= +// aggregate return value <= 64 bytes: returned on stack for both 32-bit and +// 64-bit RenderScript +// ============================================================================= + +// CHECK-RS32: void @retInt5(%struct.sInt5* noalias sret %agg.result) +// CHECK-RS64: void @retInt5(%struct.sInt5* noalias sret %agg.result) +sInt5 retInt5() { sInt5 r; return r;} + +// CHECK-RS32: void @retLong2Char(%struct.sLong2Char* noalias sret %agg.result) +// CHECK-RS64: void @retLong2Char(%struct.sLong2Char* noalias sret %agg.result) +sLong2Char retLong2Char() { sLong2Char r; return r;} + +// ============================================================================= +// aggregate parameters and return values > 64 bytes: passed and returned on the +// stack for both 32-bit and 64-bit RenderScript +// ============================================================================= + +typedef struct {long l1, l2, l3, l4, l5, l6, l7, l8, l9; } sLong9; + +// CHECK-RS32: void @argLong9(%struct.sLong9* byval align 8 %s) +// CHECK-RS64: void @argLong9(%struct.sLong9* %s) +void argLong9(sLong9 s) {} + +// CHECK-RS32: void @retLong9(%struct.sLong9* noalias sret %agg.result) +// CHECK-RS64: void @retLong9(%struct.sLong9* noalias sret %agg.result) +sLong9 retLong9() { sLong9 r; return r; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits