r256495 - [X86] Better support for the MCU psABI (clang part)

Michael Kuperstein via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 28 06:39:54 PST 2015


Author: mkuper
Date: Mon Dec 28 08:39:54 2015
New Revision: 256495

URL: http://llvm.org/viewvc/llvm-project?rev=256495&view=rev
Log:
[X86] Better support for the MCU psABI (clang part)

This adds support for the MCU psABI in a way different from r251223 and r251224,
basically reverting most of these two patches. The problem with the approach
taken in r251223/4 is that it only handled libcalls that originated from the backend.
However, the mid-end also inserts quite a few libcalls and assumes these use the
platform's default calling convention.

The previous patch tried to insert inregs when necessary both in the FE and,
somewhat hackily, in the CG. Instead, we now define a new default calling convention
for the MCU, which doesn't use inreg marking at all, similarly to what x86-64 does.

Differential Revision: http://reviews.llvm.org/D15055

Modified:
    cfe/trunk/lib/CodeGen/TargetInfo.cpp
    cfe/trunk/test/CodeGen/x86_32-arguments-iamcu.c

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=256495&r1=256494&r2=256495&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Mon Dec 28 08:39:54 2015
@@ -841,7 +841,13 @@ class X86_32ABIInfo : public ABIInfo {
   Class classify(QualType Ty) const;
   ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
   ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
-  bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const;
+  /// \brief Updates the number of available free registers, returns 
+  /// true if any registers were allocated.
+  bool updateFreeRegs(QualType Ty, CCState &State) const;
+
+  bool shouldAggregateUseDirect(QualType Ty, CCState &State, bool &InReg,
+                                bool &NeedsPadding) const;
+  bool shouldPrimitiveUseInReg(QualType Ty, CCState &State) const;
 
   /// \brief Rewrite the function info so that all memory arguments use
   /// inalloca.
@@ -1003,9 +1009,10 @@ bool X86_32ABIInfo::shouldReturnTypeInRe
                                                ASTContext &Context) const {
   uint64_t Size = Context.getTypeSize(Ty);
 
-  // Type must be register sized.
-  if (!isRegisterSize(Size))
-    return false;
+  // For i386, type must be register sized.
+  // For the MCU ABI, it only needs to be <= 8-byte
+  if ((IsMCUABI && Size > 64) || (!IsMCUABI && !isRegisterSize(Size)))
+   return false;
 
   if (Ty->isVectorType()) {
     // 64- and 128- bit vectors inside structures are not returned in
@@ -1052,7 +1059,8 @@ ABIArgInfo X86_32ABIInfo::getIndirectRet
   // integer register.
   if (State.FreeRegs) {
     --State.FreeRegs;
-    return getNaturalAlignIndirectInReg(RetTy);
+    if (!IsMCUABI)
+      return getNaturalAlignIndirectInReg(RetTy);
   }
   return getNaturalAlignIndirect(RetTy, /*ByVal=*/false);
 }
@@ -1192,7 +1200,8 @@ ABIArgInfo X86_32ABIInfo::getIndirectRes
   if (!ByVal) {
     if (State.FreeRegs) {
       --State.FreeRegs; // Non-byval indirects just use one pointer.
-      return getNaturalAlignIndirectInReg(Ty);
+      if (!IsMCUABI)
+        return getNaturalAlignIndirectInReg(Ty);
     }
     return getNaturalAlignIndirect(Ty, false);
   }
@@ -1223,9 +1232,7 @@ X86_32ABIInfo::Class X86_32ABIInfo::clas
   return Integer;
 }
 
-bool X86_32ABIInfo::shouldUseInReg(QualType Ty, CCState &State,
-                                   bool &NeedsPadding) const {
-  NeedsPadding = false;
+bool X86_32ABIInfo::updateFreeRegs(QualType Ty, CCState &State) const {
   if (!IsSoftFloatABI) {
     Class C = classify(Ty);
     if (C == Float)
@@ -1253,25 +1260,46 @@ bool X86_32ABIInfo::shouldUseInReg(QualT
   }
 
   State.FreeRegs -= SizeInRegs;
+  return true;
+}
+
+bool X86_32ABIInfo::shouldAggregateUseDirect(QualType Ty, CCState &State, 
+                                             bool &InReg,
+                                             bool &NeedsPadding) const {
+  NeedsPadding = false;
+  InReg = !IsMCUABI;
+
+  if (!updateFreeRegs(Ty, State))
+    return false;
+
+  if (IsMCUABI)
+    return true;
 
   if (State.CC == llvm::CallingConv::X86_FastCall ||
       State.CC == llvm::CallingConv::X86_VectorCall) {
-    if (Size > 32)
-      return false;
-
-    if (Ty->isIntegralOrEnumerationType())
-      return true;
+    if (getContext().getTypeSize(Ty) <= 32 && State.FreeRegs)
+      NeedsPadding = true;
 
-    if (Ty->isPointerType())
-      return true;
+    return false;
+  }
 
-    if (Ty->isReferenceType())
-      return true;
+  return true;
+}
 
-    if (State.FreeRegs)
-      NeedsPadding = true;
+bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const {
+  if (!updateFreeRegs(Ty, State))
+    return false;
 
+  if (IsMCUABI)
     return false;
+
+  if (State.CC == llvm::CallingConv::X86_FastCall ||
+      State.CC == llvm::CallingConv::X86_VectorCall) {
+    if (getContext().getTypeSize(Ty) > 32)
+      return false;
+
+    return (Ty->isIntegralOrEnumerationType() || Ty->isPointerType() || 
+        Ty->isReferenceType());
   }
 
   return true;
@@ -1327,12 +1355,15 @@ ABIArgInfo X86_32ABIInfo::classifyArgume
 
     llvm::LLVMContext &LLVMContext = getVMContext();
     llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
-    bool NeedsPadding;
-    if (shouldUseInReg(Ty, State, NeedsPadding)) {
+    bool NeedsPadding, InReg;
+    if (shouldAggregateUseDirect(Ty, State, InReg, NeedsPadding)) {
       unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
       SmallVector<llvm::Type*, 3> Elements(SizeInRegs, Int32);
       llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
-      return ABIArgInfo::getDirectInReg(Result);
+      if (InReg)
+        return ABIArgInfo::getDirectInReg(Result);
+      else
+        return ABIArgInfo::getDirect(Result);
     }
     llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : nullptr;
 
@@ -1340,8 +1371,11 @@ ABIArgInfo X86_32ABIInfo::classifyArgume
     // of those arguments will match the struct. This is important because the
     // LLVM backend isn't smart enough to remove byval, which inhibits many
     // optimizations.
+    // Don't do this for the MCU if there are still free integer registers
+    // (see X86_64 ABI for full explanation).
     if (getContext().getTypeSize(Ty) <= 4*32 &&
-        canExpandIndirectArgument(Ty, getContext()))
+        canExpandIndirectArgument(Ty, getContext()) &&
+        (!IsMCUABI || State.FreeRegs == 0))
       return ABIArgInfo::getExpandWithPadding(
           State.CC == llvm::CallingConv::X86_FastCall ||
               State.CC == llvm::CallingConv::X86_VectorCall,
@@ -1371,14 +1405,14 @@ ABIArgInfo X86_32ABIInfo::classifyArgume
   if (const EnumType *EnumTy = Ty->getAs<EnumType>())
     Ty = EnumTy->getDecl()->getIntegerType();
 
-  bool NeedsPadding;
-  bool InReg = shouldUseInReg(Ty, State, NeedsPadding);
+  bool InReg = shouldPrimitiveUseInReg(Ty, State);
 
   if (Ty->isPromotableIntegerType()) {
     if (InReg)
       return ABIArgInfo::getExtendInReg();
     return ABIArgInfo::getExtend();
   }
+
   if (InReg)
     return ABIArgInfo::getDirectInReg();
   return ABIArgInfo::getDirect();
@@ -1386,15 +1420,15 @@ ABIArgInfo X86_32ABIInfo::classifyArgume
 
 void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
   CCState State(FI.getCallingConvention());
-  if (State.CC == llvm::CallingConv::X86_FastCall)
+  if (IsMCUABI)
+    State.FreeRegs = 3;
+  else if (State.CC == llvm::CallingConv::X86_FastCall)
     State.FreeRegs = 2;
   else if (State.CC == llvm::CallingConv::X86_VectorCall) {
     State.FreeRegs = 2;
     State.FreeSSERegs = 6;
   } else if (FI.getHasRegParm())
     State.FreeRegs = FI.getRegParm();
-  else if (IsMCUABI)
-    State.FreeRegs = 3;
   else
     State.FreeRegs = DefaultNumRegisterParameters;
 
@@ -1405,7 +1439,8 @@ void X86_32ABIInfo::computeInfo(CGFuncti
     // return value was sret and put it in a register ourselves if appropriate.
     if (State.FreeRegs) {
       --State.FreeRegs;  // The sret parameter consumes a register.
-      FI.getReturnInfo().setInReg(true);
+      if (!IsMCUABI)
+        FI.getReturnInfo().setInReg(true);
     }
   }
 

Modified: cfe/trunk/test/CodeGen/x86_32-arguments-iamcu.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/x86_32-arguments-iamcu.c?rev=256495&r1=256494&r2=256495&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/x86_32-arguments-iamcu.c (original)
+++ cfe/trunk/test/CodeGen/x86_32-arguments-iamcu.c Mon Dec 28 08:39:54 2015
@@ -1,20 +1,24 @@
 // RUN: %clang_cc1 -w -triple i386-pc-elfiamcu -mfloat-abi soft -emit-llvm -o - %s | FileCheck %s
 
-// CHECK-LABEL: define void @ints(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 %d)
+// CHECK-LABEL: define void @ints(i32 %a, i32 %b, i32 %c, i32 %d)
 void ints(int a, int b, int c, int d) {}
 
-// CHECK-LABEL: define void @floats(float inreg %a, float inreg %b, float inreg %c, float %d)
+// CHECK-LABEL: define void @floats(float %a, float %b, float %c, float %d)
 void floats(float a, float b, float c, float d) {}
 
-// CHECK-LABEL: define void @mixed(i32 inreg %a, float inreg %b, i32 inreg %c, float %d)
+// CHECK-LABEL: define void @mixed(i32 %a, float %b, i32 %c, float %d)
 void mixed(int a, float b, int c, float d) {}
 
-// CHECK-LABEL: define void @doubles(double inreg %d1, double %d2)
+// CHECK-LABEL: define void @doubles(double %d1, double %d2)
 void doubles(double d1, double d2) {}
 
-// CHECK-LABEL: define void @mixedDoubles(i32 inreg %a, double inreg %d1)
+// CHECK-LABEL: define void @mixedDoubles(i32 %a, double %d1)
 void mixedDoubles(int a, double d1) {}
 
+typedef struct st3_t {
+  char a[3];
+} st3_t;
+
 typedef struct st4_t {
   int a;
 } st4_t;
@@ -30,33 +34,36 @@ typedef  struct st12_t {
   int c;
 } st12_t;
 
-// CHECK-LABEL: define void @smallStructs(i32 inreg %st1.coerce, i32 inreg %st2.coerce, i32 inreg %st3.coerce)
+// CHECK-LABEL: define void @smallStructs(i32 %st1.coerce, i32 %st2.coerce, i32 %st3.coerce)
 void smallStructs(st4_t st1, st4_t st2, st4_t st3) {}
 
-// CHECK-LABEL: define void @paddedStruct(i32 inreg %i1, i32 inreg %st.coerce0, i32 inreg %st.coerce1, i32 %st4.0)
+// CHECK-LABEL: define void @paddedStruct(i32 %i1, i32 %st.coerce0, i32 %st.coerce1, i32 %st4.0)
 void paddedStruct(int i1, st5_t st, st4_t st4) {}
 
-// CHECK-LABEL: define void @largeStruct(i32 %st.0, i32 %st.1, i32 %st.2)
-void largeStruct(st12_t st) {}
+// CHECK-LABEL: define void @largeStructBegin(%struct.st12_t* byval align 4 %st)
+void largeStructBegin(st12_t st) {}
 
-// CHECK-LABEL: define void @largeStructMiddle(i32 inreg %i1, i32 %st.0, i32 %st.1, i32 %st.2, i32 inreg %i2, i32 inreg %i3)
+// CHECK-LABEL: define void @largeStructMiddle(i32 %i1, %struct.st12_t* byval align 4 %st, i32 %i2, i32 %i3)
 void largeStructMiddle(int i1, st12_t st, int i2, int i3) {}
 
-// CHECK-LABEL: define i32 @retSmallStruct(i32 inreg %r.coerce)
+// CHECK-LABEL: define void @largeStructEnd(i32 %i1, i32 %i2, i32 %i3, i32 %st.0, i32 %st.1, i32 %st.2)
+void largeStructEnd(int i1, int i2, int i3, st12_t st) {}
+
+// CHECK-LABEL: define i24 @retNonPow2Struct(i32 %r.coerce)
+st3_t retNonPow2Struct(st3_t r) { return r; }
+
+// CHECK-LABEL: define i32 @retSmallStruct(i32 %r.coerce)
 st4_t retSmallStruct(st4_t r) { return r; }
 
-// CHECK-LABEL: define i64 @retPaddedStruct(i32 inreg %r.coerce0, i32 inreg %r.coerce1)
+// CHECK-LABEL: define i64 @retPaddedStruct(i32 %r.coerce0, i32 %r.coerce1)
 st5_t retPaddedStruct(st5_t r) { return r; }
 
-// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* inreg noalias sret %agg.result, i32 inreg %i1, i32 %r.0, i32 %r.1, i32 %r.2)
+// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* noalias sret %agg.result, i32 %i1, %struct.st12_t* byval align 4 %r)
 st12_t retLargeStruct(int i1, st12_t r) { return r; }
 
-// FIXME: We really shouldn't be marking this inreg. Right now the
-// inreg gets ignored by the CG for varargs functions, but that's
-// insane.
-// CHECK-LABEL: define i32 @varArgs(i32 inreg %i1, ...)
+// CHECK-LABEL: define i32 @varArgs(i32 %i1, ...)
 int varArgs(int i1, ...) { return i1; }
 
-// CHECK-LABEL: define double @longDoubleArg(double inreg %ld1)
+// CHECK-LABEL: define double @longDoubleArg(double %ld1)
 long double longDoubleArg(long double ld1) { return ld1; }
 




More information about the cfe-commits mailing list