[cfe-commits] r81671 - in /cfe/trunk: lib/CodeGen/TargetABIInfo.cpp test/CodeGen/arm-apcs-arguments.c

Daniel Dunbar daniel at zuster.org
Sun Sep 13 01:03:59 PDT 2009


Author: ddunbar
Date: Sun Sep 13 03:03:58 2009
New Revision: 81671

URL: http://llvm.org/viewvc/llvm-project?rev=81671&view=rev
Log:
ARM/APCS: Only "integer like" aggregates should be returned in r0 (following
gcc's interpretation of APCS' somewhat loose specification).

Modified:
    cfe/trunk/lib/CodeGen/TargetABIInfo.cpp
    cfe/trunk/test/CodeGen/arm-apcs-arguments.c

Modified: cfe/trunk/lib/CodeGen/TargetABIInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetABIInfo.cpp?rev=81671&r1=81670&r2=81671&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/TargetABIInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetABIInfo.cpp Sun Sep 13 03:03:58 2009
@@ -50,26 +50,29 @@
   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;
@@ -78,7 +81,7 @@
     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;
 }
@@ -107,7 +110,7 @@
     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
@@ -286,7 +289,7 @@
     const FieldDecl *FD = *i;
 
     // Empty fields are ignored.
-    if (isEmptyField(Context, FD))
+    if (isEmptyField(Context, FD, true))
       continue;
 
     // Check fields recursively.
@@ -1388,10 +1391,10 @@
 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.
@@ -1410,22 +1413,126 @@
   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,

Modified: cfe/trunk/test/CodeGen/arm-apcs-arguments.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/arm-apcs-arguments.c?rev=81671&r1=81670&r2=81671&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/arm-apcs-arguments.c (original)
+++ cfe/trunk/test/CodeGen/arm-apcs-arguments.c Sun Sep 13 03:03:58 2009
@@ -1,6 +1,59 @@
-// 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) {}





More information about the cfe-commits mailing list