LLVM-1163: AAPCS-VFP violation when CPRC allocated to stack
authorOliver Stannard <oliver.stannard@arm.com>
Fri, 7 Feb 2014 11:19:53 +0000 (11:19 +0000)
committerOliver Stannard <oliver.stannard@arm.com>
Fri, 7 Feb 2014 11:19:53 +0000 (11:19 +0000)
According to the AAPCS, when a CPRC is allocated to the stack, all other
VFP registers should be marked as unavailable.

I have also modified the rules for allocating non-CPRCs to the stack, to make
it more explicit that all GPRs must be made unavailable. I cannot think of a
case where the old version would produce incorrect answers, so there is no test
for this.

llvm-svn: 200970

llvm/include/llvm/CodeGen/CallingConvLower.h
llvm/include/llvm/Target/TargetCallingConv.td
llvm/lib/Target/ARM/ARMCallingConv.td
llvm/test/CodeGen/ARM/2014-02-05-vfp-regs-after-stack.ll [new file with mode: 0644]
llvm/utils/TableGen/CallingConvEmitter.cpp

index f824e73..4bc8cec 100644 (file)
@@ -348,6 +348,15 @@ public:
     return AllocateStack(Size, Align);
   }
 
+  /// Version of AllocateStack with list of extra registers to be shadowed.
+  /// Note that, unlike AllocateReg, this shadows ALL of the shadow registers.
+  unsigned AllocateStack(unsigned Size, unsigned Align,
+                         const uint16_t *ShadowRegs, unsigned NumShadowRegs) {
+    for (unsigned i = 0; i < NumShadowRegs; ++i)
+      MarkAllocated(ShadowRegs[i]);
+    return AllocateStack(Size, Align);
+  }
+
   // HandleByVal - Allocate a stack slot large enough to pass an argument by
   // value. The size and alignment information of the argument is encoded in its
   // parameter attribute.
index c1bef28..9d1dc38 100644 (file)
@@ -89,11 +89,15 @@ class CCAssignToStack<int size, int align> : CCAction {
   int Align = align;
 }
 
-/// CCAssignToStackWithShadow - Same as CCAssignToStack, but with a register
-/// to be shadowed.
-class CCAssignToStackWithShadow<int size, int align, Register reg> :
-        CCAssignToStack<size, align> {
-  Register ShadowReg = reg;
+/// CCAssignToStackWithShadow - Same as CCAssignToStack, but with a list of
+/// registers to be shadowed. Note that, unlike CCAssignToRegWithShadow, this
+/// shadows ALL of the registers in shadowList.
+class CCAssignToStackWithShadow<int size,
+                                int align,
+                                list<Register> shadowList> : CCAction {
+  int Size = size;
+  int Align = align;
+  list<Register> ShadowRegList = shadowList;
 }
 
 /// CCPassByVal - This action always matches: it assigns the value to a stack
index 9bea4b2..9ca2e46 100644 (file)
@@ -114,10 +114,11 @@ def CC_ARM_AAPCS_Common : CallingConv<[
   CCIfType<[i32], CCIf<"ArgFlags.getOrigAlign() != 8",
                        CCAssignToReg<[R0, R1, R2, R3]>>>,
 
-  CCIfType<[i32], CCIfAlign<"8", CCAssignToStackWithShadow<4, 8, R3>>>,
-  CCIfType<[i32, f32], CCAssignToStack<4, 4>>,
-  CCIfType<[f64], CCAssignToStack<8, 8>>,
-  CCIfType<[v2f64], CCAssignToStack<16, 8>>
+  CCIfType<[i32], CCIfAlign<"8", CCAssignToStackWithShadow<4, 8, [R0, R1, R2, R3]>>>,
+  CCIfType<[i32], CCAssignToStackWithShadow<4, 4, [R0, R1, R2, R3]>>,
+  CCIfType<[f32], CCAssignToStackWithShadow<4, 4, [Q0, Q1, Q2, Q3]>>,
+  CCIfType<[f64], CCAssignToStackWithShadow<8, 8, [Q0, Q1, Q2, Q3]>>,
+  CCIfType<[v2f64], CCAssignToStackWithShadow<16, 8, [Q0, Q1, Q2, Q3]>>
 ]>;
 
 def RetCC_ARM_AAPCS_Common : CallingConv<[
diff --git a/llvm/test/CodeGen/ARM/2014-02-05-vfp-regs-after-stack.ll b/llvm/test/CodeGen/ARM/2014-02-05-vfp-regs-after-stack.ll
new file mode 100644 (file)
index 0000000..4c36a2a
--- /dev/null
@@ -0,0 +1,22 @@
+; RUN: llc < %s -o - -filetype=asm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+target triple = "armv8-none--eabi"
+
+; CHECK-LABEL: fn1:
+define arm_aapcs_vfpcc float @fn1(double %a, double %b, double %c, double %d, double %e, double %f, double %g, float %h, double %i, float %j) {
+  ret float %j
+; CHECK: vldr    s0, [sp, #8]
+}
+
+; CHECK-LABEL: fn2:
+define arm_aapcs_vfpcc float @fn2(double %a, double %b, double %c, double %d, double %e, double %f, float %h, <4 x float> %i, float %j) {
+  ret float %j
+; CHECK: vldr    s0, [sp, #16]
+}
+
+; CHECK-LABEL: fn3:
+define arm_aapcs_vfpcc float @fn3(float %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, float %j) #0 {
+  ret float %j
+; CHECK: vldr    s0, [sp, #8]
+}
index e316e86..96bd336 100644 (file)
@@ -185,12 +185,34 @@ void CallingConvEmitter::EmitAction(Record *Action,
       else
         O << "\n" << IndentStr << "  State.getTarget().getDataLayout()"
           "->getABITypeAlignment(EVT(LocVT).getTypeForEVT(State.getContext()))";
-      if (Action->isSubClassOf("CCAssignToStackWithShadow"))
-        O << ", " << getQualifiedName(Action->getValueAsDef("ShadowReg"));
       O << ");\n" << IndentStr
         << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"
         << Counter << ", LocVT, LocInfo));\n";
       O << IndentStr << "return false;\n";
+    } else if (Action->isSubClassOf("CCAssignToStackWithShadow")) {
+      int Size = Action->getValueAsInt("Size");
+      int Align = Action->getValueAsInt("Align");
+      ListInit *ShadowRegList = Action->getValueAsListInit("ShadowRegList");
+
+      unsigned ShadowRegListNumber = ++Counter;
+
+      O << IndentStr << "static const uint16_t ShadowRegList"
+          << ShadowRegListNumber << "[] = {\n";
+      O << IndentStr << "  ";
+      for (unsigned i = 0, e = ShadowRegList->getSize(); i != e; ++i) {
+        if (i != 0) O << ", ";
+        O << getQualifiedName(ShadowRegList->getElementAsRecord(i));
+      }
+      O << "\n" << IndentStr << "};\n";
+
+      O << IndentStr << "unsigned Offset" << ++Counter
+        << " = State.AllocateStack("
+        << Size << ", " << Align << ", "
+        << "ShadowRegList" << ShadowRegListNumber << ", "
+        << ShadowRegList->getSize() << ");\n";
+      O << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"
+        << Counter << ", LocVT, LocInfo));\n";
+      O << IndentStr << "return false;\n";
     } else if (Action->isSubClassOf("CCPromoteToType")) {
       Record *DestTy = Action->getValueAsDef("DestTy");
       MVT::SimpleValueType DestVT = getValueType(DestTy);