[cfe-commits] r56293 - /cfe/trunk/lib/CodeGen/CGCall.cpp

Daniel Dunbar daniel at zuster.org
Wed Sep 17 14:22:34 PDT 2008


Author: ddunbar
Date: Wed Sep 17 16:22:33 2008
New Revision: 56293

URL: http://llvm.org/viewvc/llvm-project?rev=56293&view=rev
Log:
Improve x86 ABI compatibility.
 - Enables use of ABIArgInfo::Expand when needed. This greatly
   improves our x86 ABI compatibility.

 - As the infrastructure for target specific ABI handling isn't built
   yet, this change means ABI compatibility on other platforms is once
   again broken in a different way than before.

 - Upcoming: Figure out how to refactor ABI handling into
   targets. More documentation.

Modified:
    cfe/trunk/lib/CodeGen/CGCall.cpp

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Sep 17 16:22:33 2008
@@ -170,11 +170,122 @@
 
 /***/
 
+/// isEmptyStruct - Return true iff a structure has no non-empty
+/// members. Note that a structure with a flexible array member is not
+/// considered empty.
+static bool isEmptyStruct(QualType T) {
+  const RecordType *RT = T->getAsStructureType();
+  if (!RT)
+    return 0;
+  const RecordDecl *RD = RT->getDecl();
+  if (RD->hasFlexibleArrayMember())
+    return false;
+  for (RecordDecl::field_const_iterator i = RD->field_begin(), 
+         e = RD->field_end(); i != e; ++i) {
+    const FieldDecl *FD = *i;
+    if (!isEmptyStruct(FD->getType()))
+      return false;
+  }
+  return true;
+}
+
+/// isSingleElementStruct - Determine if a structure is a "single
+/// element struct", i.e. it has exactly one non-empty field or
+/// exactly one field which is itself a single element
+/// struct. Structures with flexible array members are never
+/// considered single element structs.
+///
+/// \return The field declaration for the single non-empty field, if
+/// it exists.
+static const FieldDecl *isSingleElementStruct(QualType T) {
+  const RecordType *RT = T->getAsStructureType();
+  if (!RT)
+    return 0;
+
+  const RecordDecl *RD = RT->getDecl();
+  if (RD->hasFlexibleArrayMember())
+    return 0;
+
+  const FieldDecl *Found = 0;
+  for (RecordDecl::field_const_iterator i = RD->field_begin(), 
+         e = RD->field_end(); i != e; ++i) {
+    const FieldDecl *FD = *i;
+    QualType FT = FD->getType();
+
+    if (isEmptyStruct(FT)) {
+      // Ignore
+    } else if (Found) {
+      return 0;
+    } else if (!CodeGenFunction::hasAggregateLLVMType(FT)) {
+      Found = FD;
+    } else {
+      Found = isSingleElementStruct(FT);
+      if (!Found)
+        return 0;
+    }
+  }
+
+  return Found;
+}
+
+static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
+  if (!Ty->getAsBuiltinType() && !Ty->isPointerType())
+    return false;
+
+  uint64_t Size = Context.getTypeSize(Ty);
+  return Size == 32 || Size == 64;
+}
+
+static bool areAllFields32Or64BitBasicType(const RecordDecl *RD,
+                                           ASTContext &Context) {
+  for (RecordDecl::field_const_iterator i = RD->field_begin(), 
+         e = RD->field_end(); i != e; ++i) {
+    const FieldDecl *FD = *i;
+
+    if (!is32Or64BitBasicType(FD->getType(), Context))
+      return false;
+    
+    // If this is a bit-field we need to make sure it is still a
+    // 32-bit or 64-bit type.
+    if (Expr *BW = FD->getBitWidth()) {
+      unsigned Width = BW->getIntegerConstantExprValue(Context).getZExtValue();
+      if (Width <= 16)
+        return false;
+    }
+  }
+  return true;
+}
+
 static ABIArgInfo classifyReturnType(QualType RetTy,
                                      ASTContext &Context) {
   assert(!RetTy->isArrayType() && 
          "Array types cannot be passed directly.");
   if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+    // Classify "single element" structs as their element type.
+    const FieldDecl *SeltFD = isSingleElementStruct(RetTy);
+    if (SeltFD) {
+      QualType SeltTy = SeltFD->getType()->getDesugaredType();
+      if (const BuiltinType *BT = SeltTy->getAsBuiltinType()) {
+        // FIXME: This is gross, it would be nice if we could just
+        // pass back SeltTy and have clients deal with it. Is it worth
+        // supporting coerce to both LLVM and clang Types?
+        if (BT->isIntegerType()) {
+          uint64_t Size = Context.getTypeSize(SeltTy);
+          return ABIArgInfo::getCoerce(llvm::IntegerType::get((unsigned) Size));
+        } else if (BT->getKind() == BuiltinType::Float) {
+          return ABIArgInfo::getCoerce(llvm::Type::FloatTy);
+        } else if (BT->getKind() == BuiltinType::Double) {
+          return ABIArgInfo::getCoerce(llvm::Type::DoubleTy);
+        }
+      } else if (SeltTy->isPointerType()) {
+        // FIXME: It would be really nice if this could come out as
+        // the proper pointer type.
+        llvm::Type *PtrTy = 
+          llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+        return ABIArgInfo::getCoerce(PtrTy);
+      }
+    }
+
     uint64_t Size = Context.getTypeSize(RetTy);
     if (Size == 8) {
       return ABIArgInfo::getCoerce(llvm::Type::Int8Ty);
@@ -196,6 +307,25 @@
                                        ASTContext &Context) {
   assert(!Ty->isArrayType() && "Array types cannot be passed directly.");
   if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+    // Structures with flexible arrays are always byval.
+    if (const RecordType *RT = Ty->getAsStructureType())
+      if (RT->getDecl()->hasFlexibleArrayMember())
+        return ABIArgInfo::getByVal(0);
+
+    // Expand empty structs (i.e. ignore)
+    uint64_t Size = Context.getTypeSize(Ty);
+    if (Ty->isStructureType() && Size == 0)
+      return ABIArgInfo::getExpand();
+
+    // Expand structs with size <= 128-bits which consist only of
+    // basic types (int, long long, float, double, xxx*). This is
+    // non-recursive and does not ignore empty fields.
+    if (const RecordType *RT = Ty->getAsStructureType()) {
+      if (Context.getTypeSize(Ty) <= 4*32 &&
+          areAllFields32Or64BitBasicType(RT->getDecl(), Context))
+        return ABIArgInfo::getExpand();
+    }
+
     return ABIArgInfo::getByVal(0);
   } else {
     return ABIArgInfo::getDefault();
@@ -407,7 +537,8 @@
 
   case ABIArgInfo::StructRet:
     PAL.push_back(llvm::ParamAttrsWithIndex::get(Index, 
-                                                 llvm::ParamAttr::StructRet));
+                                                 llvm::ParamAttr::StructRet|
+                                                 llvm::ParamAttr::NoAlias));
     ++Index;
     break;
 





More information about the cfe-commits mailing list