Index: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -92,6 +92,8 @@ unsigned HasBuiltinMSVaList : 1; + unsigned IsRenderScriptTarget : 1; + // TargetInfo Constructor. Default initializes all fields. TargetInfo(const llvm::Triple &T); @@ -565,6 +567,9 @@ /// 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. /// Index: lib/Basic/TargetInfo.cpp =================================================================== --- lib/Basic/TargetInfo.cpp +++ lib/Basic/TargetInfo.cpp @@ -80,6 +80,7 @@ SSERegParmMax = 0; HasAlignMac68kSupport = false; HasBuiltinMSVaList = false; + IsRenderScriptTarget = false; // Default to no types using fpret. RealTypeUsesObjCFPRet = 0; Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -8113,6 +8113,7 @@ Triple.getOSName(), Triple.getEnvironmentName()), Opts) { + IsRenderScriptTarget = true; LongWidth = LongAlign = 64; } void getTargetDefines(const LangOptions &Opts, @@ -8130,7 +8131,9 @@ : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(), Triple.getOSName(), Triple.getEnvironmentName()), - Opts) {} + Opts) { + IsRenderScriptTarget = true; + } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -31,6 +31,30 @@ 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 is used by RenderScript on ARM and AArch64. 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 +4580,11 @@ // 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 +4630,11 @@ // 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 +5325,12 @@ /*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 +5512,11 @@ // 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())); Index: test/CodeGen/renderscript.c =================================================================== --- test/CodeGen/renderscript.c +++ test/CodeGen/renderscript.c @@ -23,3 +23,118 @@ 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* +// CHECK-RS64: [3 x i16] @retShortCharShort() +sShortCharShort retShortCharShort() { sShortCharShort r; return r; } + +// CHECK-RS32: void @retIntShortChar(%struct.sIntShortChar* +// CHECK-RS64: [2 x i32] @retIntShortChar() +sIntShortChar retIntShortChar() { sIntShortChar r; return r; } + +// CHECK-RS32: void @retLongInt(%struct.sLongInt* +// 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* +// CHECK-RS64: void @retInt5(%struct.sInt5* +sInt5 retInt5() { sInt5 r; return r;} + +// CHECK-RS32: void @retLong2Char(%struct.sLong2Char* +// CHECK-RS64: void @retLong2Char(%struct.sLong2Char* +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* +// CHECK-RS64: void @argLong9(%struct.sLong9* +void argLong9(sLong9 s) {} + +// CHECK-RS32: void @retLong9(%struct.sLong9* +// CHECK-RS64: void @retLong9(%struct.sLong9* +sLong9 retLong9() { sLong9 r; return r; }