Handle functions with struct arguments or return types and the regparm
attribute. It is a variation of the x86_64 ABI:

* A struct returned indirectly uses the first register argument to pass the
  pointer.
* Floats, Doubles and structs containing only one of them are not passed in
  registers.
* Other structs are split into registers if they fit on the remaining ones.
  Otherwise they are passed in memory.
* When a struct doesn't fit it still consumes the registers.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161022 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index 838cb29..86f5380 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -74,31 +74,42 @@
     unsigned UIntData;
     bool BoolData0;
     bool BoolData1;
+    bool InReg;
 
-    ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1,
+    ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR,
                llvm::Type* P)
       : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
-        BoolData1(B1) {}
+        BoolData1(B1), InReg(IR) {}
 
   public:
     ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
 
     static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
                                 llvm::Type *Padding = 0) {
-      return ABIArgInfo(Direct, T, Offset, false, false, Padding);
+      return ABIArgInfo(Direct, T, Offset, false, false, false, Padding);
+    }
+    static ABIArgInfo getDirectInReg(llvm::Type *T) {
+      return ABIArgInfo(Direct, T, 0, false, false, true, 0);
     }
     static ABIArgInfo getExtend(llvm::Type *T = 0) {
-      return ABIArgInfo(Extend, T, 0, false, false, 0);
+      return ABIArgInfo(Extend, T, 0, false, false, false, 0);
+    }
+    static ABIArgInfo getExtendInReg(llvm::Type *T = 0) {
+      return ABIArgInfo(Extend, T, 0, false, false, true, 0);
     }
     static ABIArgInfo getIgnore() {
-      return ABIArgInfo(Ignore, 0, 0, false, false, 0);
+      return ABIArgInfo(Ignore, 0, 0, false, false, false, 0);
     }
     static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
                                   , bool Realign = false) {
-      return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, 0);
+      return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, 0);
+    }
+    static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
+                                  , bool Realign = false) {
+      return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, 0);
     }
     static ABIArgInfo getExpand() {
-      return ABIArgInfo(Expand, 0, 0, false, false, 0);
+      return ABIArgInfo(Expand, 0, 0, false, false, false, 0);
     }
 
     Kind getKind() const { return TheKind; }
@@ -132,6 +143,11 @@
       TypeData = T;
     }
 
+    bool getInReg() const {
+      assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
+      return InReg;
+    }
+
     // Indirect accessors
     unsigned getIndirectAlign() const {
       assert(TheKind == Indirect && "Invalid kind!");
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 9deec19..7d2b9d3 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -983,14 +983,18 @@
   case ABIArgInfo::Ignore:
     break;
 
-  case ABIArgInfo::Indirect:
-    PAL.push_back(llvm::AttributeWithIndex::get(Index,
-                                                llvm::Attribute::StructRet));
+  case ABIArgInfo::Indirect: {
+    llvm::Attributes SRETAttrs = llvm::Attribute::StructRet;
+    if (RetAI.getInReg())
+      SRETAttrs |= llvm::Attribute::InReg;
+    PAL.push_back(llvm::AttributeWithIndex::get(Index, SRETAttrs));
+
     ++Index;
     // sret disables readnone and readonly
     FuncAttrs &= ~(llvm::Attribute::ReadOnly |
                    llvm::Attribute::ReadNone);
     break;
+  }
 
   case ABIArgInfo::Expand:
     llvm_unreachable("Invalid ABI kind for return argument");
@@ -999,14 +1003,6 @@
   if (RetAttrs)
     PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs));
 
-  // FIXME: RegParm should be reduced in case of global register variable.
-  signed RegParm;
-  if (FI.getHasRegParm())
-    RegParm = FI.getRegParm();
-  else
-    RegParm = CodeGenOpts.NumRegisterParameters;
-
-  unsigned PointerWidth = getContext().getTargetInfo().getPointerWidth(0);
   for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
          ie = FI.arg_end(); it != ie; ++it) {
     QualType ParamType = it->type;
@@ -1024,22 +1020,22 @@
         Attrs |= llvm::Attribute::ZExt;
       // FALL THROUGH
     case ABIArgInfo::Direct:
-      if (RegParm > 0 &&
-          (ParamType->isIntegerType() || ParamType->isPointerType() ||
-           ParamType->isReferenceType())) {
-        RegParm -=
-        (Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth;
-        if (RegParm >= 0)
+      if (AI.getInReg())
           Attrs |= llvm::Attribute::InReg;
-      }
+
       // 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.
+          dyn_cast<llvm::StructType>(AI.getCoerceToType())) {
+        unsigned Extra = STy->getNumElements()-1;  // 1 will be added below.
+        if (Attrs != llvm::Attribute::None)
+          for (unsigned I = 0; I < Extra; ++I)
+            PAL.push_back(llvm::AttributeWithIndex::get(Index + I, Attrs));
+        Index += Extra;
+      }
       break;
 
     case ABIArgInfo::Indirect:
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 06e1a3e..2095cb9 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -413,12 +413,18 @@
 
 /// X86_32ABIInfo - The X86-32 ABI information.
 class X86_32ABIInfo : public ABIInfo {
+  enum Class {
+    Integer,
+    Float
+  };
+
   static const unsigned MinABIStackAlignInBytes = 4;
 
   bool IsDarwinVectorABI;
   bool IsSmallStructInRegABI;
   bool IsMMXDisabled;
   bool IsWin32FloatStructABI;
+  unsigned DefaultNumRegisterParameters;
 
   static bool isRegisterSize(unsigned Size) {
     return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
@@ -434,8 +440,11 @@
   /// \brief Return the alignment to use for the given type on the stack.
   unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
 
+  Class classify(QualType Ty) const;
   ABIArgInfo classifyReturnType(QualType RetTy,
                                 unsigned callingConvention) const;
+  ABIArgInfo classifyArgumentTypeWithReg(QualType RetTy,
+                                         unsigned &FreeRegs) const;
   ABIArgInfo classifyArgumentType(QualType RetTy) const;
 
 public:
@@ -444,16 +453,18 @@
   virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
                                  CodeGenFunction &CGF) const;
 
-  X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m, bool w)
+  X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m, bool w,
+                unsigned r)
     : ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p),
-      IsMMXDisabled(m), IsWin32FloatStructABI(w) {}
+      IsMMXDisabled(m), IsWin32FloatStructABI(w),
+      DefaultNumRegisterParameters(r) {}
 };
 
 class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
 public:
   X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
-      bool d, bool p, bool m, bool w)
-    :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w)) {}
+      bool d, bool p, bool m, bool w, unsigned r)
+    :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w, r)) {}
 
   void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
                            CodeGen::CodeGenModule &CGM) const;
@@ -690,6 +701,57 @@
   return ABIArgInfo::getIndirect(StackAlign);
 }
 
+X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
+  const Type *T = isSingleElementStruct(Ty, getContext());
+  if (!T)
+    T = Ty.getTypePtr();
+
+  if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
+    BuiltinType::Kind K = BT->getKind();
+    if (K == BuiltinType::Float || K == BuiltinType::Double)
+      return Float;
+  }
+  return Integer;
+}
+
+ABIArgInfo
+X86_32ABIInfo::classifyArgumentTypeWithReg(QualType Ty,
+                                           unsigned &FreeRegs) const {
+  // Common case first.
+  if (FreeRegs == 0)
+    return classifyArgumentType(Ty);
+
+  Class C = classify(Ty);
+  if (C == Float)
+    return classifyArgumentType(Ty);
+
+  unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+  if (SizeInRegs == 0)
+    return classifyArgumentType(Ty);
+
+  if (SizeInRegs > FreeRegs) {
+    FreeRegs = 0;
+    return classifyArgumentType(Ty);
+  }
+  assert(SizeInRegs >= 1 && SizeInRegs <= 3);
+  FreeRegs -= SizeInRegs;
+
+  // If it is a simple scalar, keep the type so that we produce a cleaner IR.
+  ABIArgInfo Foo = classifyArgumentType(Ty);
+  if (Foo.isDirect() && !Foo.getDirectOffset() && !Foo.getPaddingType())
+    return ABIArgInfo::getDirectInReg(Foo.getCoerceToType());
+  if (Foo.isExtend())
+    return ABIArgInfo::getExtendInReg(Foo.getCoerceToType());
+
+  llvm::LLVMContext &LLVMContext = getVMContext();
+  llvm::Type *Int32 = llvm::Type::getInt32Ty(LLVMContext);
+  SmallVector<llvm::Type*, 3> Elements;
+  for (unsigned I = 0; I < SizeInRegs; ++I)
+    Elements.push_back(Int32);
+  llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
+  return ABIArgInfo::getDirectInReg(Result);
+}
+
 ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
   // FIXME: Set alignment on indirect arguments.
   if (isAggregateTypeForABI(Ty)) {
@@ -754,9 +816,23 @@
 void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
   FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
                                           FI.getCallingConvention());
+
+  unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() :
+    DefaultNumRegisterParameters;
+
+  // If the return value is indirect, then the hidden argument is consuming one
+  // integer register.
+  if (FI.getReturnInfo().isIndirect() && FreeRegs) {
+    --FreeRegs;
+    ABIArgInfo &Old = FI.getReturnInfo();
+    Old = ABIArgInfo::getIndirectInReg(Old.getIndirectAlign(),
+                                       Old.getIndirectByVal(),
+                                       Old.getIndirectRealign());
+  }
+
   for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
        it != ie; ++it)
-    it->info = classifyArgumentType(it->type);
+    it->info = classifyArgumentTypeWithReg(it->type, FreeRegs);
 }
 
 llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -3735,8 +3811,8 @@
 
     if (Triple.isOSDarwin())
       return *(TheTargetCodeGenInfo =
-               new X86_32TargetCodeGenInfo(
-                 Types, true, true, DisableMMX, false));
+               new X86_32TargetCodeGenInfo(Types, true, true, DisableMMX, false,
+                                           CodeGenOpts.NumRegisterParameters));
 
     switch (Triple.getOS()) {
     case llvm::Triple::Cygwin:
@@ -3746,18 +3822,20 @@
     case llvm::Triple::FreeBSD:
     case llvm::Triple::OpenBSD:
       return *(TheTargetCodeGenInfo =
-               new X86_32TargetCodeGenInfo(
-                 Types, false, true, DisableMMX, false));
+               new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX,
+                                           false,
+                                           CodeGenOpts.NumRegisterParameters));
 
     case llvm::Triple::Win32:
       return *(TheTargetCodeGenInfo =
-               new X86_32TargetCodeGenInfo(
-                 Types, false, true, DisableMMX, true));
+               new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX, true,
+                                           CodeGenOpts.NumRegisterParameters));
 
     default:
       return *(TheTargetCodeGenInfo =
-               new X86_32TargetCodeGenInfo(
-                 Types, false, false, DisableMMX, false));
+               new X86_32TargetCodeGenInfo(Types, false, false, DisableMMX,
+                                           false,
+                                           CodeGenOpts.NumRegisterParameters));
     }
   }
 
diff --git a/test/CodeGen/regparm-struct.c b/test/CodeGen/regparm-struct.c
new file mode 100644
index 0000000..b319012
--- /dev/null
+++ b/test/CodeGen/regparm-struct.c
@@ -0,0 +1,177 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+__attribute__((regparm(3))) void f1(int a, int b, int c, int d);
+// CHECK: declare void @f1(i32 inreg, i32 inreg, i32 inreg, i32)
+void g1() {
+  f1(41, 42, 43, 44);
+}
+
+struct s1 {
+  int x1;
+};
+__attribute__((regparm(3))) void f2(int a, int b, struct s1 c, int d);
+// CHECK: declare void @f2(i32 inreg, i32 inreg, i32 inreg, i32)
+void g2() {
+  struct s1 x = {43};
+  f2(41, 42, x, 44);
+}
+
+struct s2 {
+  int x1;
+  int x2;
+};
+__attribute__((regparm(3))) void f3(int a, int b, struct s2 c, int d);
+// CHECK: declare void @f3(i32 inreg, i32 inreg, i32, i32, i32)
+void g3() {
+  struct s2 x = {43, 44};
+  f3(41, 42, x, 45);
+}
+__attribute__((regparm(3))) void f4(int a, struct s2 b, int c);
+// CHECK: declare void @f4(i32 inreg, i32 inreg, i32 inreg, i32)
+void g4() {
+  struct s2 x = {42, 43};
+  f4(41, x, 44);
+}
+
+struct s3 {
+  int x1;
+  int x2;
+  int x3;
+};
+__attribute__((regparm(3))) void f5(int a, struct s3 b, int c);
+// CHECK: declare void @f5(i32 inreg, i32, i32, i32, i32)
+void g5() {
+  struct s3 x = {42, 43, 44};
+  f5(41, x, 45);
+}
+__attribute__((regparm(3))) void f6(struct s3 a, int b);
+// CHECK: declare void @f6(i32 inreg, i32 inreg, i32 inreg, i32)
+void g6() {
+  struct s3 x = {41, 42, 43};
+  f6(x, 44);
+}
+
+struct s4 {
+  int x1;
+  int x2;
+  int x3;
+  int x4;
+};
+__attribute__((regparm(3))) void f7(struct s4 a, int b);
+// CHECK: declare void @f7(i32, i32, i32, i32, i32)
+void g7() {
+  struct s4 x = {41, 42, 43, 44};
+  f7(x, 45);
+}
+
+__attribute__((regparm(3))) void f8(float a, int b);
+// CHECK: declare void @f8(float, i32 inreg)
+void g8(void) {
+  f8(41, 42);
+}
+
+struct s5 {
+  float x1;
+};
+__attribute__((regparm(3))) void f9(struct s5 a, int b);
+// CHECK: declare void @f9(float, i32 inreg)
+void g9(void) {
+  struct s5 x = {41};
+  f9(x, 42);
+}
+
+struct s6 {
+  float x1;
+  int x2;
+};
+__attribute__((regparm(3))) void f10(struct s6 a, int b);
+// CHECK: declare void @f10(i32 inreg, i32 inreg, i32 inreg)
+void g10(void) {
+  struct s6 x = {41, 42};
+  f10(x, 43);
+}
+
+struct s7 {
+  float x1;
+  int x2;
+  float x3;
+};
+__attribute__((regparm(3))) void f11(struct s7 a, int b);
+// CHECK: declare void @f11(i32 inreg, i32 inreg, i32 inreg, i32)
+void g11(void) {
+  struct s7 x = {41, 42, 43};
+  f11(x, 44);
+}
+
+struct s8 {
+  float x1;
+  float x2;
+};
+__attribute__((regparm(3))) void f12(struct s8 a, int b);
+// CHECK: declare void @f12(i32 inreg, i32 inreg, i32 inreg)
+void g12(void) {
+  struct s8 x = {41, 42};
+  f12(x, 43);
+}
+
+struct s9 {
+  float x1;
+  float x2;
+  float x3;
+};
+__attribute__((regparm(3))) void f13(struct s9 a, int b);
+// CHECK: declare void @f13(i32 inreg, i32 inreg, i32 inreg, i32)
+void g13(void) {
+  struct s9 x = {41, 42, 43};
+  f13(x, 44);
+}
+
+struct s10 {
+  double x1;
+};
+__attribute__((regparm(3))) void f14(struct s10 a, int b, int c);
+// CHECK: declare void @f14(double, i32 inreg, i32 inreg)
+void g14(void) {
+  struct s10 x = { 41 };
+  f14(x, 42, 43);
+}
+
+struct s11 {
+  double x1;
+  double x2;
+};
+__attribute__((regparm(3))) void f15(struct s11 a, int b);
+// CHECK: declare void @f15(double, double, i32)
+void g15(void) {
+  struct s11 x = { 41, 42 };
+  f15(x, 43);
+}
+
+struct s12 {
+  double x1;
+  float x2;
+};
+__attribute__((regparm(3))) void f16(struct s12 a, int b);
+// CHECK: declare void @f16(i32 inreg, i32 inreg, i32 inreg, i32)
+void g16(void) {
+  struct s12 x = { 41, 42 };
+  f16(x, 43);
+}
+
+__attribute__((regparm(3))) struct s12 f17(int a, int b, int c);
+// CHECK: declare void @f17(%struct.s12* inreg sret, i32 inreg, i32 inreg, i32)
+void g17(void) {
+  f17(41, 42, 43);
+}
+
+struct s13 {
+  struct inner {
+    float x;
+  } y;
+};
+__attribute__((regparm(3))) void f18(struct s13 a, int b, int c, int d);
+// CHECK: declare void @f18(%struct.s13* byval align 4, i32 inreg, i32 inreg, i32 inreg)
+void g18(void) {
+  struct s13 x = {{41}};
+  f18(x, 42, 43, 44);
+}
diff --git a/test/CodeGenCXX/pr13396.cpp b/test/CodeGenCXX/pr13396.cpp
index b390eea..7d4e2ce 100644
--- a/test/CodeGenCXX/pr13396.cpp
+++ b/test/CodeGenCXX/pr13396.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu %s -emit-llvm -o - | FileCheck %s
 struct foo {
   template<typename T>
   __attribute__ ((regparm (3))) foo(T x) {}