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));
     }
   }