fprintf(stderr, ")\n");
}
-static bool isEmptyRecord(ASTContext &Context, QualType T);
+static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
/// isEmptyField - Return true iff a the field is "empty", that is it
/// is an unnamed bit-field or an (array of) empty record(s).
-static bool isEmptyField(ASTContext &Context, const FieldDecl *FD) {
+static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
+ bool AllowArrays) {
if (FD->isUnnamedBitfield())
return true;
QualType FT = FD->getType();
- // Constant arrays of empty records count as empty, strip them off.
- while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
- FT = AT->getElementType();
- return isEmptyRecord(Context, FT);
+ // Constant arrays of empty records count as empty, strip them off.
+ if (AllowArrays)
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
+ FT = AT->getElementType();
+
+ return isEmptyRecord(Context, FT, AllowArrays);
}
/// isEmptyRecord - Return true iff a structure contains only empty
/// fields. Note that a structure with a flexible array member is not
/// considered empty.
-static bool isEmptyRecord(ASTContext &Context, QualType T) {
+static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return 0;
return false;
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i)
- if (!isEmptyField(Context, *i))
+ if (!isEmptyField(Context, *i, AllowArrays))
return false;
return true;
}
QualType FT = FD->getType();
// Ignore empty fields.
- if (isEmptyField(Context, FD))
+ if (isEmptyField(Context, FD, true))
continue;
// If we already found an element then this isn't a single-element
const FieldDecl *FD = *i;
// Empty fields are ignored.
- if (isEmptyField(Context, FD))
+ if (isEmptyField(Context, FD, true))
continue;
// Check fields recursively.
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
ASTContext &Context,
llvm::LLVMContext &VMContext) const {
- if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty))
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
+
// FIXME: This is kind of nasty... but there isn't much choice because the ARM
// backend doesn't support byval.
// FIXME: This doesn't handle alignment > 64 bits.
return ABIArgInfo::getCoerce(STy);
}
+static bool isIntegerLikeType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) {
+ // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure
+ // is called integer-like if its size is less than or equal to one word, and
+ // the offset of each of its addressable sub-fields is zero.
+
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // Check that the type fits in a word.
+ if (Size > 32)
+ return false;
+
+ // FIXME: Handle vector types!
+ if (Ty->isVectorType())
+ return false;
+
+ // If this is a builtin or pointer type then it is ok.
+ if (Ty->getAsBuiltinType() || Ty->isPointerType())
+ return true;
+
+ // Complex types "should" be ok by the definition above, but they are not.
+ if (Ty->isAnyComplexType())
+ return false;
+
+ // Single element and zero sized arrays should be allowed, by the definition
+ // above, but they are not.
+
+ // Otherwise, it must be a record type.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT) return false;
+
+ // Ignore records with flexible arrays.
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+
+ // Check that all sub-fields are at offset 0, and are themselves "integer
+ // like".
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ bool HadField = false;
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i, ++idx) {
+ const FieldDecl *FD = *i;
+
+ // Check if this field is at offset 0.
+ uint64_t Offset = Layout.getFieldOffset(idx);
+ if (Offset != 0) {
+ // Allow padding bit-fields, but only if they are all at the end of the
+ // structure (despite the wording above, this matches gcc).
+ if (FD->isBitField() &&
+ !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ for (; i != e; ++i)
+ if (!i->isBitField() ||
+ i->getBitWidth()->EvaluateAsInt(Context).getZExtValue())
+ return false;
+
+ // All remaining fields are padding, allow this.
+ return true;
+ }
+
+ return false;
+ }
+
+ if (!isIntegerLikeType(FD->getType(), Context, VMContext))
+ return false;
+
+ // Only allow at most one field in a structure. Again this doesn't match the
+ // wording above, but follows gcc.
+ if (!RD->isUnion()) {
+ if (HadField)
+ return false;
+
+ HadField = true;
+ }
+ }
+
+ return true;
+}
+
ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
ASTContext &Context,
llvm::LLVMContext &VMContext) const {
- if (RetTy->isVoidType()) {
+ if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
- } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
- // Aggregates <= 4 bytes are returned in r0; other aggregates
- // are returned indirectly.
- uint64_t Size = Context.getTypeSize(RetTy);
- if (Size <= 32)
- return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
- return ABIArgInfo::getIndirect(0);
- } else {
+
+ if (!CodeGenFunction::hasAggregateLLVMType(RetTy))
return (RetTy->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ // Are we following APCS?
+ if (getABIKind() == APCS) {
+ if (isEmptyRecord(Context, RetTy, false))
+ return ABIArgInfo::getIgnore();
+
+ // Integer like structures are returned in r0.
+ if (isIntegerLikeType(RetTy, Context, VMContext)) {
+ // Return in the smallest viable integer type.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 8)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
+ if (Size <= 16)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
+ return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
+ }
+
+ // Otherwise return in memory.
+ return ABIArgInfo::getIndirect(0);
}
+
+ // Otherwise this is an AAPCS variant.
+
+ // Aggregates <= 4 bytes are returned in r0; other aggregates
+ // are returned indirectly.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 32)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
+ return ABIArgInfo::getIndirect(0);
}
llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
-// RUN: clang-cc -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
+// RUX: iphone-llvm-gcc -arch armv7 -flto -S -o - %s | FileCheck %s
+// RUN: clang-cc -triple armv7-apple-darwin9 -emit-llvm -w -o - %s | FileCheck %s
// CHECK: define arm_apcscc signext i8 @f0()
char f0(void) {
return 0;
}
+
+// CHECK: define arm_apcscc i8 @f1()
+struct s1 { char f0; };
+struct s1 f1(void) {}
+
+// CHECK: define arm_apcscc i16 @f2()
+struct s2 { short f0; };
+struct s2 f2(void) {}
+
+// CHECK: define arm_apcscc i32 @f3()
+struct s3 { int f0; };
+struct s3 f3(void) {}
+
+// CHECK: define arm_apcscc i32 @f4()
+struct s4 { struct s4_0 { int f0; } f0; };
+struct s4 f4(void) {}
+
+// CHECK: define arm_apcscc void @f5(
+// CHECK: struct.s5* noalias sret
+struct s5 { struct { } f0; int f1; };
+struct s5 f5(void) {}
+
+// CHECK: define arm_apcscc void @f6(
+// CHECK: struct.s6* noalias sret
+struct s6 { int f0[1]; };
+struct s6 f6(void) {}
+
+// CHECK: define arm_apcscc void @f7()
+struct s7 { struct { int : 0; } f0; };
+struct s7 f7(void) {}
+
+// CHECK: define arm_apcscc void @f8(
+// CHECK: struct.s8* noalias sret
+struct s8 { struct { int : 0; } f0[1]; };
+struct s8 f8(void) {}
+
+// CHECK: define arm_apcscc i32 @f9()
+struct s9 { int f0; int : 0; };
+struct s9 f9(void) {}
+
+// CHECK: define arm_apcscc i32 @f10()
+struct s10 { int f0; int : 0; int : 0; };
+struct s10 f10(void) {}
+
+// CHECK: define arm_apcscc void @f11(
+// CHECK: struct.s10* noalias sret
+struct s11 { int : 0; int f0; };
+struct s11 f11(void) {}
+
+// CHECK: define arm_apcscc i32 @f12()
+union u12 { char f0; short f1; int f2; };
+union u12 f12(void) {}