Add field PaddingType to ABIArgInfo which specifies the type of padding that
authorAkira Hatanaka <ahatanaka@mips.com>
Sat, 7 Jan 2012 00:25:33 +0000 (00:25 +0000)
committerAkira Hatanaka <ahatanaka@mips.com>
Sat, 7 Jan 2012 00:25:33 +0000 (00:25 +0000)
is inserted before the real argument. Padding is needed to ensure the backend
reads from or writes to the correct argument slots when the original alignment
of a byval structure is unavailable due to flattening.

llvm-svn: 147699

clang/lib/CodeGen/ABIInfo.h
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/TargetInfo.cpp
clang/test/CodeGen/mips64-padding-arg.c [new file with mode: 0644]

index 1381238..2853bc8 100644 (file)
@@ -42,7 +42,8 @@ namespace clang {
       /// type, or by coercing to another specified type stored in
       /// 'CoerceToType').  If an offset is specified (in UIntData), then the
       /// argument passed is offset by some number of bytes in the memory
-      /// representation.
+      /// representation. A dummy argument is emitted before the real argument
+      /// if the specified type stored in "PaddingType" is not zero.
       Direct,
 
       /// Extend - Valid only for integer argument types. Same as 'direct'
@@ -69,19 +70,22 @@ namespace clang {
   private:
     Kind TheKind;
     llvm::Type *TypeData;
+    llvm::Type *PaddingType; // Currently allowed only for Direct.
     unsigned UIntData;
     bool BoolData0;
     bool BoolData1;
 
-    ABIArgInfo(Kind K, llvm::Type *TD=0,
-               unsigned UI=0, bool B0 = false, bool B1 = false)
-      : TheKind(K), TypeData(TD), UIntData(UI), BoolData0(B0), BoolData1(B1) {}
+    ABIArgInfo(Kind K, llvm::Type *TD=0, unsigned UI=0,
+               bool B0 = false, bool B1 = false, llvm::Type* P = 0)
+      : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
+        BoolData1(B1) {}
 
   public:
     ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
 
-    static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0) {
-      return ABIArgInfo(Direct, T, Offset);
+    static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
+                                llvm::Type *Padding = 0) {
+      return ABIArgInfo(Direct, T, Offset, false, false, Padding);
     }
     static ABIArgInfo getExtend(llvm::Type *T = 0) {
       return ABIArgInfo(Extend, T, 0);
@@ -113,6 +117,11 @@ namespace clang {
       assert((isDirect() || isExtend()) && "Not a direct or extend kind");
       return UIntData;
     }
+
+    llvm::Type *getPaddingType() const {
+      return PaddingType;
+    }
+
     llvm::Type *getCoerceToType() const {
       assert(canHaveCoerceToType() && "Invalid kind!");
       return TypeData;
index 3457b5b..962339a 100644 (file)
@@ -686,6 +686,9 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
 
     case ABIArgInfo::Extend:
     case ABIArgInfo::Direct: {
+      // Insert a padding type to ensure proper alignment.
+      if (llvm::Type *PaddingType = argAI.getPaddingType())
+        argTypes.push_back(PaddingType);
       // If the coerce-to type is a first class aggregate, flatten it.  Either
       // way is semantically identical, but fast-isel and the optimizer
       // generally likes scalar values better than FCAs.
@@ -840,6 +843,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
       }
       // FIXME: handle sseregparm someday...
 
+      // Increment Index if there is padding.
+      Index += (AI.getPaddingType() != 0);
+
       if (llvm::StructType *STy =
             dyn_cast<llvm::StructType>(AI.getCoerceToType()))
         Index += STy->getNumElements()-1;  // 1 will be added below.
@@ -1024,6 +1030,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
                           llvm::PointerType::getUnqual(ArgI.getCoerceToType()));
       }
 
+      // Skip the dummy padding argument.
+      if (ArgI.getPaddingType())
+        ++AI;
+
       // If the coerce-to type is a first class aggregate, we flatten it and
       // pass the elements. Either way is semantically identical, but fast-isel
       // and the optimizer generally likes scalar values better than FCAs.
@@ -1658,6 +1668,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
 
     case ABIArgInfo::Extend:
     case ABIArgInfo::Direct: {
+      // Insert a padding argument to ensure proper alignment.
+      if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
+        Args.push_back(llvm::UndefValue::get(PaddingType));
+        ++IRArgNo;
+      }
+
       if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
           ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
           ArgInfo.getDirectOffset() == 0) {
index 0ce5957..d1bebc1 100644 (file)
@@ -3047,7 +3047,7 @@ public:
     ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8) {}
 
   ABIArgInfo classifyReturnType(QualType RetTy) const;
-  ABIArgInfo classifyArgumentType(QualType RetTy) const;
+  ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;
   virtual void computeInfo(CGFunctionInfo &FI) const;
   virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
                                  CodeGenFunction &CGF) const;
@@ -3132,28 +3132,41 @@ llvm::Type* MipsABIInfo::HandleStructTy(QualType Ty) const {
   return llvm::StructType::get(getVMContext(), ArgList);
 }
 
-ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const {
+ABIArgInfo
+MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
   if (isAggregateTypeForABI(Ty)) {
     // Ignore empty aggregates.
-    if (getContext().getTypeSize(Ty) == 0)
+    uint64_t TySize = getContext().getTypeSize(Ty);
+    if (TySize == 0)
       return ABIArgInfo::getIgnore();
 
     // Records with non trivial destructors/constructors should not be passed
     // by value.
-    if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+    if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) {
+      Offset += 8;
       return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+    }
 
-    llvm::Type *ResType;
-    if ((ResType = HandleStructTy(Ty)))
-      return ABIArgInfo::getDirect(ResType);
-
-    return ABIArgInfo::getIndirect(0);
+    // If we have reached here, aggregates are passed either indirectly via a
+    // byval pointer or directly by coercing to another structure type. In the
+    // latter case, padding is inserted if the offset of the aggregate is
+    // unaligned.
+    llvm::Type *ResType = HandleStructTy(Ty);
+    uint64_t Align = getContext().getTypeAlign(Ty) / 8;
+    assert(Align <= 16 && "Alignment larger than 16 not handled.");
+    llvm::Type *PaddingTy = (ResType && Align == 16 && Offset & 0xf) ?
+      llvm::IntegerType::get(getVMContext(), 64) : 0;
+    Offset = llvm::RoundUpToAlignment(Offset, std::max(Align, (uint64_t)8));
+    Offset += llvm::RoundUpToAlignment(TySize, 8);
+    return ResType ? ABIArgInfo::getDirect(ResType, 0, PaddingTy) :
+                     ABIArgInfo::getIndirect(0);
   }
 
   // Treat an enum type as its underlying type.
   if (const EnumType *EnumTy = Ty->getAs<EnumType>())
     Ty = EnumTy->getDecl()->getIntegerType();
 
+  Offset += 8;
   return (Ty->isPromotableIntegerType() ?
           ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
 }
@@ -3230,9 +3243,10 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
 
 void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
   FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+  uint64_t Offset = 0;
   for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
        it != ie; ++it)
-    it->info = classifyArgumentType(it->type);
+    it->info = classifyArgumentType(it->type, Offset);
 }
 
 llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
diff --git a/clang/test/CodeGen/mips64-padding-arg.c b/clang/test/CodeGen/mips64-padding-arg.c
new file mode 100644 (file)
index 0000000..658e6eb
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: %clang -ccc-host-triple mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+
+typedef struct {
+  double d;
+  long double ld;
+} S0;
+
+// Insert padding to ensure arugments of type S0 are aligned to 16-byte boundaries.
+
+// CHECK: define void @foo1(i32 %a0, i64, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 %b, i64, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
+// CHECK: tail call void @foo2(i32 1, i32 2, i32 %a0, i64 undef, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 3, i64 undef, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
+// CHECK: declare void @foo2(i32, i32, i32, i64, double, i64, i64, i64, double, i64, i64, i64, i32, i64, double, i64, i64, i64)
+
+extern void foo2(int, int, int, S0, S0, int, S0);
+
+void foo1(int a0, S0 a1, S0 a2, int b, S0 a3) {
+  foo2(1, 2, a0, a1, a2, 3, a3);
+}
+