[cfe-commits] r107123 - in /cfe/trunk: lib/CodeGen/TargetInfo.cpp test/CodeGen/x86_64-arguments.c test/CodeGenCXX/x86_64-arguments.cpp

Chris Lattner sabre at nondot.org
Mon Jun 28 23:01:59 PDT 2010


Author: lattner
Date: Tue Jun 29 01:01:59 2010
New Revision: 107123

URL: http://llvm.org/viewvc/llvm-project?rev=107123&view=rev
Log:
Change X86_64ABIInfo to have ASTContext and TargetData ivars to
avoid passing ASTContext down through all the methods it has.

When classifying an argument, or argument piece, as INTEGER, check
to see if we have a pointer at exactly the same offset in the 
preferred type.  If so, use that pointer type instead of i64.  This
allows us to compile A function taking a stringref into something
like this:

define i8* @foo(i64 %D.coerce0, i8* %D.coerce1) nounwind ssp {
entry:
  %D = alloca %struct.DeclGroup, align 8          ; <%struct.DeclGroup*> [#uses=4]
  %0 = getelementptr %struct.DeclGroup* %D, i32 0, i32 0 ; <i64*> [#uses=1]
  store i64 %D.coerce0, i64* %0
  %1 = getelementptr %struct.DeclGroup* %D, i32 0, i32 1 ; <i8**> [#uses=1]
  store i8* %D.coerce1, i8** %1
  %tmp = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 0 ; <i64*> [#uses=1]
  %tmp1 = load i64* %tmp                          ; <i64> [#uses=1]
  %tmp2 = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 1 ; <i8**> [#uses=1]
  %tmp3 = load i8** %tmp2                         ; <i8*> [#uses=1]
  %add.ptr = getelementptr inbounds i8* %tmp3, i64 %tmp1 ; <i8*> [#uses=1]
  ret i8* %add.ptr
}

instead of this:

define i8* @foo(i64 %D.coerce0, i64 %D.coerce1) nounwind ssp {
entry:
  %D = alloca %struct.DeclGroup, align 8          ; <%struct.DeclGroup*> [#uses=3]
  %0 = insertvalue %0 undef, i64 %D.coerce0, 0    ; <%0> [#uses=1]
  %1 = insertvalue %0 %0, i64 %D.coerce1, 1       ; <%0> [#uses=1]
  %2 = bitcast %struct.DeclGroup* %D to %0*       ; <%0*> [#uses=1]
  store %0 %1, %0* %2, align 1
  %tmp = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 0 ; <i64*> [#uses=1]
  %tmp1 = load i64* %tmp                          ; <i64> [#uses=1]
  %tmp2 = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 1 ; <i8**> [#uses=1]
  %tmp3 = load i8** %tmp2                         ; <i8*> [#uses=1]
  %add.ptr = getelementptr inbounds i8* %tmp3, i64 %tmp1 ; <i8*> [#uses=1]
  ret i8* %add.ptr
}

This implements rdar://7375902 - [codegen quality] clang x86-64 ABI lowering code punishing StringRef


Modified:
    cfe/trunk/lib/CodeGen/TargetInfo.cpp
    cfe/trunk/test/CodeGen/x86_64-arguments.c
    cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=107123&r1=107122&r2=107123&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Tue Jun 29 01:01:59 2010
@@ -17,6 +17,7 @@
 #include "CodeGenFunction.h"
 #include "clang/AST/RecordLayout.h"
 #include "llvm/Type.h"
+#include "llvm/Target/TargetData.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Support/raw_ostream.h"
@@ -672,6 +673,9 @@
 namespace {
 /// X86_64ABIInfo - The X86_64 ABI information.
 class X86_64ABIInfo : public ABIInfo {
+  ASTContext &Context;
+  const llvm::TargetData &TD;
+  
   enum Class {
     Integer = 0,
     SSE,
@@ -715,8 +719,7 @@
   ///
   /// If the \arg Lo class is ComplexX87, then the \arg Hi class will
   /// also be ComplexX87.
-  void classify(QualType T, ASTContext &Context, uint64_t OffsetBase,
-                Class &Lo, Class &Hi) const;
+  void classify(QualType T, uint64_t OffsetBase, Class &Lo, Class &Hi) const;
 
   /// getCoerceResult - Given a source type \arg Ty and an LLVM type
   /// to coerce to, chose the best way to pass Ty in the same place
@@ -728,29 +731,29 @@
   /// type. This makes this code more explicit, and it makes it clearer that we
   /// are also doing this for correctness in the case of passing scalar types.
   ABIArgInfo getCoerceResult(QualType Ty,
-                             const llvm::Type *CoerceTo,
-                             ASTContext &Context) const;
+                             const llvm::Type *CoerceTo) const;
 
   /// getIndirectResult - Give a source type \arg Ty, return a suitable result
   /// such that the argument will be returned in memory.
-  ABIArgInfo getIndirectReturnResult(QualType Ty, ASTContext &Context) const;
+  ABIArgInfo getIndirectReturnResult(QualType Ty) const;
 
   /// getIndirectResult - Give a source type \arg Ty, return a suitable result
   /// such that the argument will be passed in memory.
-  ABIArgInfo getIndirectResult(QualType Ty, ASTContext &Context) const;
+  ABIArgInfo getIndirectResult(QualType Ty) const;
 
   ABIArgInfo classifyReturnType(QualType RetTy,
-                                ASTContext &Context,
                                 llvm::LLVMContext &VMContext) const;
 
   ABIArgInfo classifyArgumentType(QualType Ty,
-                                  ASTContext &Context,
                                   llvm::LLVMContext &VMContext,
                                   unsigned &neededInt,
                                   unsigned &neededSSE,
                                   const llvm::Type *PrefType) const;
 
 public:
+  X86_64ABIInfo(ASTContext &Ctx, const llvm::TargetData &td)
+    : Context(Ctx), TD(td) {}
+
   virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
                            llvm::LLVMContext &VMContext,
                            const llvm::Type *const *PrefTypes,
@@ -762,7 +765,8 @@
 
 class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
 public:
-  X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {}
+  X86_64TargetCodeGenInfo(ASTContext &Ctx, const llvm::TargetData &TD)
+    : TargetCodeGenInfo(new X86_64ABIInfo(Ctx, TD)) {}
 
   int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
     return 7;
@@ -827,7 +831,6 @@
 }
 
 void X86_64ABIInfo::classify(QualType Ty,
-                             ASTContext &Context,
                              uint64_t OffsetBase,
                              Class &Lo, Class &Hi) const {
   // FIXME: This code can be simplified by introducing a simple value class for
@@ -866,7 +869,7 @@
   
   if (const EnumType *ET = Ty->getAs<EnumType>()) {
     // Classify the underlying integer type.
-    classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi);
+    classify(ET->getDecl()->getIntegerType(), OffsetBase, Lo, Hi);
     return;
   }
   
@@ -968,7 +971,7 @@
     uint64_t ArraySize = AT->getSize().getZExtValue();
     for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) {
       Class FieldLo, FieldHi;
-      classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi);
+      classify(AT->getElementType(), Offset, FieldLo, FieldHi);
       Lo = merge(Lo, FieldLo);
       Hi = merge(Hi, FieldHi);
       if (Lo == Memory || Hi == Memory)
@@ -1023,7 +1026,7 @@
         // initialized to class NO_CLASS.
         Class FieldLo, FieldHi;
         uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base);
-        classify(i->getType(), Context, Offset, FieldLo, FieldHi);
+        classify(i->getType(), Offset, FieldLo, FieldHi);
         Lo = merge(Lo, FieldLo);
         Hi = merge(Hi, FieldHi);
         if (Lo == Memory || Hi == Memory)
@@ -1082,7 +1085,7 @@
           FieldHi = EB_Hi ? Integer : NoClass;
         }
       } else
-        classify(i->getType(), Context, Offset, FieldLo, FieldHi);
+        classify(i->getType(), Offset, FieldLo, FieldHi);
       Lo = merge(Lo, FieldLo);
       Hi = merge(Hi, FieldHi);
       if (Lo == Memory || Hi == Memory)
@@ -1109,9 +1112,8 @@
 }
 
 ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
-                                          const llvm::Type *CoerceTo,
-                                          ASTContext &Context) const {
-  if (CoerceTo->isIntegerTy(64)) {
+                                          const llvm::Type *CoerceTo) const {
+  if (CoerceTo->isIntegerTy(64) || isa<llvm::PointerType>(CoerceTo)) {
     // Integer and pointer types will end up in a general purpose
     // register.
 
@@ -1151,8 +1153,7 @@
   return ABIArgInfo::getCoerce(CoerceTo);
 }
 
-ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty,
-                                                  ASTContext &Context) const {
+ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
   // If this is a scalar LLVM value then assume LLVM will pass it in the right
   // place naturally.
   if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
@@ -1167,8 +1168,7 @@
   return ABIArgInfo::getIndirect(0);
 }
 
-ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
-                                            ASTContext &Context) const {
+ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const {
   // If this is a scalar LLVM value then assume LLVM will pass it in the right
   // place naturally.
   if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
@@ -1193,12 +1193,11 @@
 }
 
 ABIArgInfo X86_64ABIInfo::
-classifyReturnType(QualType RetTy, ASTContext &Context,
-                   llvm::LLVMContext &VMContext) const {
+classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const {
   // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
   // classification algorithm.
   X86_64ABIInfo::Class Lo, Hi;
-  classify(RetTy, Context, 0, Lo, Hi);
+  classify(RetTy, 0, Lo, Hi);
 
   // Check some invariants.
   assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
@@ -1217,7 +1216,7 @@
     // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
     // hidden argument.
   case Memory:
-    return getIndirectReturnResult(RetTy, Context);
+    return getIndirectReturnResult(RetTy);
 
     // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
     // available register of the sequence %rax, %rdx is used.
@@ -1287,16 +1286,40 @@
     break;
   }
 
-  return getCoerceResult(RetTy, ResType, Context);
+  return getCoerceResult(RetTy, ResType);
+}
+
+static const llvm::Type *Get8ByteTypeAtOffset(const llvm::Type *PrefType,
+                                              unsigned Offset,
+                                              const llvm::TargetData &TD) {
+  if (PrefType == 0) return 0;
+  
+  // Pointers are always 8-bytes at offset 0.
+  if (Offset == 0 && isa<llvm::PointerType>(PrefType))
+    return PrefType;
+  
+  // TODO: 1/2/4/8 byte integers are also interesting, but we have to know that
+  // the "hole" is not used in the containing struct (just undef padding).
+  const llvm::StructType *STy = dyn_cast<llvm::StructType>(PrefType);
+  if (STy == 0) return 0;
+ 
+  // If this is a struct, recurse into the field at the specified offset.
+  const llvm::StructLayout *SL = TD.getStructLayout(STy);
+  if (Offset >= SL->getSizeInBytes()) return 0;
+  
+  unsigned FieldIdx = SL->getElementContainingOffset(Offset);
+  Offset -= SL->getElementOffset(FieldIdx);
+  
+  return Get8ByteTypeAtOffset(STy->getElementType(FieldIdx), Offset, TD);
 }
 
-ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
+ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty,
                                                llvm::LLVMContext &VMContext,
                                                unsigned &neededInt,
                                                unsigned &neededSSE,
                                                const llvm::Type *PrefType)const{
   X86_64ABIInfo::Class Lo, Hi;
-  classify(Ty, Context, 0, Lo, Hi);
+  classify(Ty, 0, Lo, Hi);
 
   // Check some invariants.
   // FIXME: Enforce these by construction.
@@ -1319,7 +1342,7 @@
     // COMPLEX_X87, it is passed in memory.
   case X87:
   case ComplexX87:
-    return getIndirectResult(Ty, Context);
+    return getIndirectResult(Ty);
 
   case SSEUp:
   case X87Up:
@@ -1329,8 +1352,16 @@
     // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8
     // and %r9 is used.
   case Integer:
-    ++neededInt;
+    // It is always safe to classify this as an i64 argument.
     ResType = llvm::Type::getInt64Ty(VMContext);
+    ++neededInt;
+      
+    // If we can choose a better 8-byte type based on the preferred type, and if
+    // that type is still passed in a GPR, use it.
+    if (const llvm::Type *PrefTypeLo = Get8ByteTypeAtOffset(PrefType, 0, TD))
+      if (isa<llvm::IntegerType>(PrefTypeLo) ||
+          isa<llvm::PointerType>(PrefTypeLo))
+        ResType = PrefTypeLo;
     break;
 
     // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next
@@ -1353,11 +1384,22 @@
     break;
 
   case NoClass: break;
-  case Integer:
-    ResType = llvm::StructType::get(VMContext, ResType,
-                                    llvm::Type::getInt64Ty(VMContext), NULL);
+      
+  case Integer: {
+    // It is always safe to classify this as an i64 argument.
+    const llvm::Type *HiType = llvm::Type::getInt64Ty(VMContext);
     ++neededInt;
+
+    // If we can choose a better 8-byte type based on the preferred type, and if
+    // that type is still passed in a GPR, use it.
+    if (const llvm::Type *PrefTypeHi = Get8ByteTypeAtOffset(PrefType, 8, TD))
+      if (isa<llvm::IntegerType>(PrefTypeHi) ||
+          isa<llvm::PointerType>(PrefTypeHi))
+        HiType = PrefTypeHi;
+      
+    ResType = llvm::StructType::get(VMContext, ResType, HiType, NULL);
     break;
+  }
 
     // X87Up generally doesn't occur here (long double is passed in
     // memory), except in situations involving unions.
@@ -1377,15 +1419,14 @@
     break;
   }
 
-  return getCoerceResult(Ty, ResType, Context);
+  return getCoerceResult(Ty, ResType);
 }
 
 void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
                                 llvm::LLVMContext &VMContext,
                                 const llvm::Type *const *PrefTypes,
                                 unsigned NumPrefTypes) const {
-  FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
-                                          Context, VMContext);
+  FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), VMContext);
 
   // Keep track of the number of assigned registers.
   unsigned freeIntRegs = 6, freeSSERegs = 8;
@@ -1408,7 +1449,7 @@
     }
       
     unsigned neededInt, neededSSE;
-    it->info = classifyArgumentType(it->type, Context, VMContext,
+    it->info = classifyArgumentType(it->type, VMContext,
                                     neededInt, neededSSE, PrefType);
 
     // AMD64-ABI 3.2.3p3: If there are no registers available for any
@@ -1419,7 +1460,7 @@
       freeIntRegs -= neededInt;
       freeSSERegs -= neededSSE;
     } else {
-      it->info = getIndirectResult(it->type, Context);
+      it->info = getIndirectResult(it->type);
     }
   }
 }
@@ -1489,8 +1530,7 @@
   unsigned neededInt, neededSSE;
   
   Ty = CGF.getContext().getCanonicalType(Ty);
-  ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext,
-                                       neededInt, neededSSE, 0);
+  ABIArgInfo AI = classifyArgumentType(Ty, VMContext, neededInt, neededSSE, 0);
 
   // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
   // in the registers. If not go to step 7.
@@ -2283,10 +2323,10 @@
   // For now we just cache the TargetCodeGenInfo in CodeGenModule and don't
   // free it.
 
-  const llvm::Triple &Triple(getContext().Target.getTriple());
+  const llvm::Triple &Triple = getContext().Target.getTriple();
   switch (Triple.getArch()) {
   default:
-    return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo);
+    return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo());
 
   case llvm::Triple::mips:
   case llvm::Triple::mipsel:
@@ -2335,6 +2375,7 @@
     }
 
   case llvm::Triple::x86_64:
-    return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo());
+    return *(TheTargetCodeGenInfo =
+               new X86_64TargetCodeGenInfo(Context, TheTargetData));
   }
 }

Modified: cfe/trunk/test/CodeGen/x86_64-arguments.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/x86_64-arguments.c?rev=107123&r1=107122&r2=107123&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/x86_64-arguments.c (original)
+++ cfe/trunk/test/CodeGen/x86_64-arguments.c Tue Jun 29 01:01:59 2010
@@ -113,3 +113,13 @@
   int y;
 };
 void f20(struct s20 x) {}
+
+struct StringRef {
+  long x;
+  const char *Ptr;
+};
+
+// rdar://7375902
+// CHECK: define i8* @f21(i64 %S.coerce0, i8* %S.coerce1) 
+const char *f21(struct StringRef S) { return S.x+S.Ptr; }
+

Modified: cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp?rev=107123&r1=107122&r2=107123&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp Tue Jun 29 01:01:59 2010
@@ -1,12 +1,9 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
 
-// CHECK: [[i64_i64_ty:%.*]] = type { i64, i64 }
-// CHECK: [[i64_double_ty:%.*]] = type { i64, double }
-
 // Basic base class test.
 struct f0_s0 { unsigned a; };
 struct f0_s1 : public f0_s0 { void *b; };
-// CHECK: define void @_Z2f05f0_s1(i64 %a0.coerce0, i64 %a0.coerce1)
+// CHECK: define void @_Z2f05f0_s1(i64 %a0.coerce0, i8* %a0.coerce1)
 void f0(f0_s1 a0) { }
 
 // Check with two eight-bytes in base class.
@@ -27,7 +24,7 @@
 void f3(struct s3_1 x) {}
 
 // CHECK: define i64 @_Z4f4_0M2s4i(i64 %a.coerce)
-// CHECK: define [[i64_i64_ty]] @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1)
+// CHECK: define {{.*}} @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1)
 struct s4 {};
 typedef int s4::* s4_mdp;
 typedef int (s4::*s4_mfp)();





More information about the cfe-commits mailing list