]> granicus.if.org Git - clang/commitdiff
Change X86_64ABIInfo to have ASTContext and TargetData ivars to
authorChris Lattner <sabre@nondot.org>
Tue, 29 Jun 2010 06:01:59 +0000 (06:01 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 29 Jun 2010 06:01:59 +0000 (06:01 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107123 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/TargetInfo.cpp
test/CodeGen/x86_64-arguments.c
test/CodeGenCXX/x86_64-arguments.cpp

index 292f58eef452e9fbdf85f04446f3adfe2f4ab6d8..2ba19f10963d3038bb58ff1d5f8f8040b3cb3888 100644 (file)
@@ -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 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
 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 @@ class X86_64ABIInfo : public ABIInfo {
   ///
   /// 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 @@ class X86_64ABIInfo : public ABIInfo {
   /// 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 @@ public:
 
 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 @@ X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) {
 }
 
 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 @@ void X86_64ABIInfo::classify(QualType Ty,
   
   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 @@ void X86_64ABIInfo::classify(QualType Ty,
     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 @@ void X86_64ABIInfo::classify(QualType Ty,
         // 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 @@ void X86_64ABIInfo::classify(QualType Ty,
           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 @@ void X86_64ABIInfo::classify(QualType Ty,
 }
 
 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 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
   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 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty,
   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::getIndirectResult(QualType Ty,
 }
 
 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 @@ classifyReturnType(QualType RetTy, ASTContext &Context,
     // 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 @@ classifyReturnType(QualType RetTy, ASTContext &Context,
     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 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
     // 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 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
     // 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 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
     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 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
     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 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
     }
       
     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 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
       freeIntRegs -= neededInt;
       freeSSERegs -= neededSSE;
     } else {
-      it->info = getIndirectResult(it->type, Context);
+      it->info = getIndirectResult(it->type);
     }
   }
 }
@@ -1489,8 +1530,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
   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 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const {
   // 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 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const {
     }
 
   case llvm::Triple::x86_64:
-    return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo());
+    return *(TheTargetCodeGenInfo =
+               new X86_64TargetCodeGenInfo(Context, TheTargetData));
   }
 }
index 595f2a816d6f2161d1ddf5d27fba3d30ea48b9ad..ba9045a1f48e61fbb3ec59692ed1500d36cf18ae 100644 (file)
@@ -113,3 +113,13 @@ struct __attribute__((aligned(32))) s20 {
   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; }
+
index 2c7e5b80d931f77e8261b3b493533ebcb09fabb9..8a21fddec4bee9138824604c7d5b97acf3bc0d59 100644 (file)
@@ -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 @@ struct s3_1 { struct s3_0 a; long b; };
 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)();