[PowerPC] Fix the calling convention for i1 arguments on PPC32
authorLion Yang <lion@aosc.io>
Fri, 14 Sep 2018 21:26:05 +0000 (21:26 +0000)
committerLion Yang <lion@aosc.io>
Fri, 14 Sep 2018 21:26:05 +0000 (21:26 +0000)
Summary:
Integer types smaller than i32 must be extended to i32 by default.
The feature "crbits" introduced at r202451 handles i1 as a special case,
but it did not extend properly.
The caller was, therefore, passing i1 stack arguments by writing 0/1 to
the first byte of the 4-byte stack object and callee was
reading the first byte for the value.

"crbits" is enabled if the optimization level is greater than 1,
which is very common in "release builds".
Such discrepancies with ABI specification also introduces
potential incompatibility with programs or libraries
built with other compilers e.g. GCC.

Fixes PR38661

Reviewers: hfinkel, cuviper

Subscribers: sylvestre.ledru, glaubitz, nagisa, nemanjai, kbarton, llvm-commits

Differential Revision: https://reviews.llvm.org/D51108

llvm-svn: 342288

llvm/lib/Target/PowerPC/PPCISelLowering.cpp
llvm/test/CodeGen/PowerPC/ppc32-i1-stack-arguments-abi-bug.ll [new file with mode: 0644]

index 48f093c..5dee7b1 100644 (file)
@@ -3511,9 +3511,14 @@ SDValue PPCTargetLowering::LowerFormalArguments_32SVR4(
       // Argument stored in memory.
       assert(VA.isMemLoc());
 
+      // Get the extended size of the argument type in stack
       unsigned ArgSize = VA.getLocVT().getStoreSize();
-      int FI = MFI.CreateFixedObject(ArgSize, VA.getLocMemOffset(),
-                                     isImmutable);
+      // Get the actual size of the argument type
+      unsigned ObjSize = VA.getValVT().getStoreSize();
+      unsigned ArgOffset = VA.getLocMemOffset();
+      // Stack objects in PPC32 are right justified.
+      ArgOffset += ArgSize - ObjSize;
+      int FI = MFI.CreateFixedObject(ArgSize, ArgOffset, isImmutable);
 
       // Create load nodes to retrieve arguments from the stack.
       SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
@@ -5468,10 +5473,15 @@ SDValue PPCTargetLowering::LowerCall_32SVR4(
       Arg = PtrOff;
     }
 
-    if (VA.isRegLoc()) {
-      if (Arg.getValueType() == MVT::i1)
-        Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Arg);
+    // When useCRBits() is true, there can be i1 arguments.
+    // It is because getRegisterType(MVT::i1) => MVT::i1,
+    // and for other integer types getRegisterType() => MVT::i32.
+    // Extend i1 and ensure callee will get i32.
+    if (Arg.getValueType() == MVT::i1)
+      Arg = DAG.getNode(Flags.isSExt() ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND,
+                        dl, MVT::i32, Arg);
 
+    if (VA.isRegLoc()) {
       seenFloatArg |= VA.getLocVT().isFloatingPoint();
       // Put argument in a physical register.
       RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
diff --git a/llvm/test/CodeGen/PowerPC/ppc32-i1-stack-arguments-abi-bug.ll b/llvm/test/CodeGen/PowerPC/ppc32-i1-stack-arguments-abi-bug.ll
new file mode 100644 (file)
index 0000000..7252082
--- /dev/null
@@ -0,0 +1,24 @@
+; RUN: llc -verify-machineinstrs < %s -mcpu=ppc32 -mattr=+crbits | FileCheck %s
+target triple = "powerpc-unknown-linux-gnu"
+
+define void @check_callee(
+  i32, i32, i32, i32,
+  i32, i32, i32, i32,
+  i1 zeroext %s1
+) {
+  call void @check_caller(
+    i32 9, i32 9, i32 9, i32 9,
+    i32 9, i32 9, i32 9, i32 9,
+    i1 zeroext %s1)
+  ret void
+}
+
+; CHECK-LABEL: @check_callee
+; CHECK: lbz {{[0-9]+}}, 27(1)
+; CHECK: stw {{[0-9]+}}, 8(1)
+
+declare void @check_caller(
+  i32, i32, i32, i32,
+  i32, i32, i32, i32,
+  i1 zeroext
+)