<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Dec 15, 2015 at 11:23 AM, James Y Knight via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: jyknight<br>
Date: Tue Dec 15 13:23:12 2015<br>
New Revision: 255668<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=255668&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=255668&view=rev</a><br>
Log:<br>
[Sparc] Fix handling of double incoming arguments on sparc little-endian.<br>
<br>
On SparcV8, doubles get passed in two 32-bit integer registers. The call<br>
code was already handling endianness correctly, but the incoming<br>
argument code was not -- it got the two halves in opposite order.<br>
<br>
Also remove some dead code in LowerFormalArguments_32 to handle<br>
less-than-32bit values, which can't actually happen.<br>
<br>
Finally, add some test cases for the 32-bit calling convention, cribbed<br>
from the 64abi.ll test, and run for both big and little-endian.<br>
<br>
Added:<br>
    llvm/trunk/test/CodeGen/SPARC/32abi.ll<br>
Modified:<br>
    llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp<br>
<br>
Modified: llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp?rev=255668&r1=255667&r2=255668&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp?rev=255668&r1=255667&r2=255668&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp (original)<br>
+++ llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp Tue Dec 15 13:23:12 2015<br>
@@ -400,6 +400,7 @@ LowerFormalArguments_32(SDValue Chain,<br>
   CCInfo.AnalyzeFormalArguments(Ins, CC_Sparc32);<br>
<br>
   const unsigned StackOffset = 92;<br>
+  bool IsLittleEndian = DAG.getDataLayout().isLittleEndian();<br>
<br>
   unsigned InIdx = 0;<br>
   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i, ++InIdx) {<br>
@@ -442,6 +443,10 @@ LowerFormalArguments_32(SDValue Chain,<br>
                                         &SP::IntRegsRegClass);<br>
           LoVal = DAG.getCopyFromReg(Chain, dl, loReg, MVT::i32);<br>
         }<br>
+<br>
+        if (IsLittleEndian)<br>
+          std::swap(LoVal, HiVal);<br>
+<br>
         SDValue WholeValue =<br>
           DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal);<br>
         WholeValue = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), WholeValue);<br>
@@ -498,6 +503,9 @@ LowerFormalArguments_32(SDValue Chain,<br>
                                   MachinePointerInfo(),<br>
                                   false, false, false, 0);<br>
<br>
+      if (IsLittleEndian)<br>
+        std::swap(LoVal, HiVal);<br>
+<br>
       SDValue WholeValue =<br>
         DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal);<br>
       WholeValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), WholeValue);<br>
@@ -514,16 +522,12 @@ LowerFormalArguments_32(SDValue Chain,<br>
       Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr,<br>
                          MachinePointerInfo(),<br>
                          false, false, false, 0);<br>
+    } else if (VA.getValVT() == MVT::f128) {<br>
+      report_fatal_error("SPARCv8 does not handle f128 in calls; "<br>
+                         "pass indirectly");<br>
     } else {<br>
-      ISD::LoadExtType LoadOp = ISD::SEXTLOAD;<br>
-      // Sparc is big endian, so add an offset based on the ObjectVT.<br>
-      unsigned Offset = 4-std::max(1U, VA.getValVT().getSizeInBits()/8);<br>
-      FIPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, FIPtr,<br>
-                          DAG.getConstant(Offset, dl, MVT::i32));<br>
-      Load = DAG.getExtLoad(LoadOp, dl, MVT::i32, Chain, FIPtr,<br>
-                            MachinePointerInfo(),<br>
-                            VA.getValVT(), false, false, false,0);<br>
-      Load = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Load);<br>
+      // We shouldn't see any other value types here.<br>
+      assert(false && "Unexpected ValVT encountered in frame lowering.");<br></blockquote><div><br></div><div>llvm_unreachable is preferred to assert(false && ...)</div><div><br></div><div>-- Sean Silva</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     }<br>
     InVals.push_back(Load);<br>
   }<br>
<br>
Added: llvm/trunk/test/CodeGen/SPARC/32abi.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SPARC/32abi.ll?rev=255668&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SPARC/32abi.ll?rev=255668&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/SPARC/32abi.ll (added)<br>
+++ llvm/trunk/test/CodeGen/SPARC/32abi.ll Tue Dec 15 13:23:12 2015<br>
@@ -0,0 +1,191 @@<br>
+; RUN: llc < %s -march=sparc -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BE<br>
+; RUN: llc < %s -march=sparcel -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-LE<br>
+<br>
+; CHECK-LABEL: intarg:<br>
+; The save/restore frame is not strictly necessary here, but we would need to<br>
+; refer to %o registers instead.<br>
+; CHECK: save %sp, -96, %sp<br>
+; CHECK: ld [%fp+96], [[R2:%[gilo][0-7]]]<br>
+; CHECK: ld [%fp+92], [[R1:%[gilo][0-7]]]<br>
+; CHECK: stb %i0, [%i4]<br>
+; CHECK: stb %i1, [%i4]<br>
+; CHECK: sth %i2, [%i4]<br>
+; CHECK: st  %i3, [%i4]<br>
+; CHECK: st  %i4, [%i4]<br>
+; CHECK: st  %i5, [%i4]<br>
+; CHECK: st  [[R1]], [%i4]<br>
+; CHECK: st  [[R2]], [%i4]<br>
+; CHECK: restore<br>
+define void @intarg(i8  %a0,   ; %i0<br>
+                    i8  %a1,   ; %i1<br>
+                    i16 %a2,   ; %i2<br>
+                    i32 %a3,   ; %i3<br>
+                    i8* %a4,   ; %i4<br>
+                    i32 %a5,   ; %i5<br>
+                    i32 signext %a6,   ; [%fp+92]<br>
+                    i8* %a7) { ; [%fp+96]<br>
+  store i8 %a0, i8* %a4<br>
+  store i8 %a1, i8* %a4<br>
+  %p16 = bitcast i8* %a4 to i16*<br>
+  store i16 %a2, i16* %p16<br>
+  %p32 = bitcast i8* %a4 to i32*<br>
+  store i32 %a3, i32* %p32<br>
+  %pp = bitcast i8* %a4 to i8**<br>
+  store i8* %a4, i8** %pp<br>
+  store i32 %a5, i32* %p32<br>
+  store i32 %a6, i32* %p32<br>
+  store i8* %a7, i8** %pp<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: call_intarg:<br>
+; CHECK: save %sp, -104, %sp<br>
+; Use %o0-%o5 for outgoing arguments<br>
+; CHECK: mov 5, %o5<br>
+; CHECK: st %i0, [%sp+92]<br>
+; CHECK: call intarg<br>
+; CHECK-NOT: add %sp<br>
+; CHECK: restore<br>
+define void @call_intarg(i32 %i0, i8* %i1) {<br>
+  call void @intarg(i8 0, i8 1, i16 2, i32 3, i8* undef, i32 5, i32 %i0, i8* %i1)<br>
+  ret void<br>
+}<br>
+<br>
+;; Verify doubles starting with an even reg, starting with an odd reg,<br>
+;; straddling the boundary of regs and mem, and floats in regs and mem.<br>
+;<br>
+; CHECK-LABEL: floatarg:<br>
+; CHECK: save %sp, -120, %sp<br>
+; CHECK: mov %i5, %g2<br>
+; CHECK-NEXT: ld [%fp+92], %g3<br>
+; CHECK-NEXT: mov %i4, %i5<br>
+; CHECK-NEXT: std %g2, [%fp+-24]<br>
+; CHECK-NEXT: mov %i3, %i4<br>
+; CHECK-NEXT: std %i4, [%fp+-16]<br>
+; CHECK-NEXT: std %i0, [%fp+-8]<br>
+; CHECK-NEXT: st %i2, [%fp+-28]<br>
+; CHECK-NEXT: ld [%fp+104], %f0<br>
+; CHECK-NEXT: ldd [%fp+96], %f2<br>
+; CHECK-NEXT: ld [%fp+-28], %f1<br>
+; CHECK-NEXT: ldd [%fp+-8], %f4<br>
+; CHECK-NEXT: ldd [%fp+-16], %f6<br>
+; CHECK-NEXT: ldd [%fp+-24], %f8<br>
+; CHECK-NEXT: fstod %f1, %f10<br>
+; CHECK-NEXT: faddd %f4, %f10, %f4<br>
+; CHECK-NEXT: faddd %f6, %f4, %f4<br>
+; CHECK-NEXT: faddd %f8, %f4, %f4<br>
+; CHECK-NEXT: faddd %f2, %f4, %f2<br>
+; CHECK-NEXT: fstod %f0, %f0<br>
+; CHECK-NEXT: faddd %f0, %f2, %f0<br>
+; CHECK-NEXT: restore<br>
+define double @floatarg(double %a0,   ; %i0,%i1<br>
+                        float %a1,    ; %i2<br>
+                        double %a2,   ; %i3, %i4<br>
+                        double %a3,   ; %i5, [%fp+92] (using 4 bytes)<br>
+                        double %a4,   ; [%fp+96] (using 8 bytes)<br>
+                        float %a5) {  ; [%fp+104] (using 4 bytes)<br>
+  %d1 = fpext float %a1 to double<br>
+  %s1 = fadd double %a0, %d1<br>
+  %s2 = fadd double %a2, %s1<br>
+  %s3 = fadd double %a3, %s2<br>
+  %s4 = fadd double %a4, %s3<br>
+  %d5 = fpext float %a5 to double<br>
+  %s5 = fadd double %d5, %s4<br>
+  ret double %s5<br>
+}<br>
+<br>
+; CHECK-LABEL: call_floatarg:<br>
+; CHECK: save %sp, -112, %sp<br>
+; CHECK: mov %i2, %o1<br>
+; CHECK-NEXT: mov %i1, %o0<br>
+; CHECK-NEXT: st %i0, [%sp+104]<br>
+; CHECK-NEXT: std %o0, [%sp+96]<br>
+; CHECK-NEXT: st %o1, [%sp+92]<br>
+; CHECK-NEXT: mov %i0, %o2<br>
+; CHECK-NEXT: mov %o0, %o3<br>
+; CHECK-NEXT: mov %o1, %o4<br>
+; CHECK-NEXT: mov %o0, %o5<br>
+; CHECK-NEXT: call floatarg<br>
+; CHECK: std %f0, [%i4]<br>
+; CHECK: restore<br>
+define void @call_floatarg(float %f1, double %d2, float %f5, double *%p) {<br>
+  %r = call double @floatarg(double %d2, float %f1, double %d2, double %d2,<br>
+                             double %d2, float %f1)<br>
+  store double %r, double* %p<br>
+  ret void<br>
+}<br>
+<br>
+;; i64 arguments should effectively work the same as double: split<br>
+;; into two locations.  This is different for little-endian vs big<br>
+;; endian, since the 64-bit math needs to be split<br>
+; CHECK-LABEL: i64arg:<br>
+; CHECK:  save %sp, -96, %sp<br>
+; CHECK-BE: ld [%fp+100], %g2<br>
+; CHECK-BE-NEXT: ld [%fp+96], %g3<br>
+; CHECK-BE-NEXT: ld [%fp+92], %g4<br>
+; CHECK-BE-NEXT: addcc %i1, %i2, %i1<br>
+; CHECK-BE-NEXT: addxcc %i0, 0, %i0<br>
+; CHECK-BE-NEXT: addcc %i4, %i1, %i1<br>
+; CHECK-BE-NEXT: addxcc %i3, %i0, %i0<br>
+; CHECK-BE-NEXT: addcc %g4, %i1, %i1<br>
+; CHECK-BE-NEXT: ld [%fp+104], %i2<br>
+; CHECK-BE-NEXT: addxcc %i5, %i0, %i0<br>
+; CHECK-BE-NEXT: addcc %g2, %i1, %i1<br>
+; CHECK-BE-NEXT: addxcc %g3, %i0, %i0<br>
+; CHECK-BE-NEXT: addcc %i2, %i1, %i1<br>
+; CHECK-BE-NEXT: addxcc %i0, 0, %i0<br>
+;<br>
+; CHECK-LE: ld [%fp+96], %g2<br>
+; CHECK-LE-NEXT: ld [%fp+100], %g3<br>
+; CHECK-LE-NEXT: ld [%fp+92], %g4<br>
+; CHECK-LE-NEXT: addcc %i0, %i2, %i0<br>
+; CHECK-LE-NEXT: addxcc %i1, 0, %i1<br>
+; CHECK-LE-NEXT: addcc %i3, %i0, %i0<br>
+; CHECK-LE-NEXT: addxcc %i4, %i1, %i1<br>
+; CHECK-LE-NEXT: addcc %i5, %i0, %i0<br>
+; CHECK-LE-NEXT: ld [%fp+104], %i2<br>
+; CHECK-LE-NEXT: addxcc %g4, %i1, %i1<br>
+; CHECK-LE-NEXT: addcc %g2, %i0, %i0<br>
+; CHECK-LE-NEXT: addxcc %g3, %i1, %i1<br>
+; CHECK-LE-NEXT: addcc %i2, %i0, %i0<br>
+; CHECK-LE-NEXT: addxcc %i1, 0, %i1<br>
+; CHECK-NEXT: restore<br>
+<br>
+<br>
+define i64 @i64arg(i64 %a0,    ; %i0,%i1<br>
+                  i32 %a1,    ; %i2<br>
+                  i64 %a2,    ; %i3, %i4<br>
+                  i64 %a3,    ; %i5, [%fp+92] (using 4 bytes)<br>
+                  i64 %a4,    ; [%fp+96] (using 8 bytes)<br>
+                   i32 %a5) {  ; [%fp+104] (using 4 bytes)<br>
+  %a1L = zext i32 %a1 to i64<br>
+  %s1 = add i64 %a0, %a1L<br>
+  %s2 = add i64 %a2, %s1<br>
+  %s3 = add i64 %a3, %s2<br>
+  %s4 = add i64 %a4, %s3<br>
+  %a5L = zext i32 %a5 to i64<br>
+  %s5 = add i64 %a5L, %s4<br>
+  ret i64 %s5<br>
+}<br>
+<br>
+; CHECK-LABEL: call_i64arg:<br>
+; CHECK: save %sp, -112, %sp<br>
+; CHECK: st %i0, [%sp+104]<br>
+; CHECK-NEXT: st %i2, [%sp+100]<br>
+; CHECK-NEXT: st %i1, [%sp+96]<br>
+; CHECK-NEXT: st %i2, [%sp+92]<br>
+; CHECK-NEXT: mov      %i1, %o0<br>
+; CHECK-NEXT: mov      %i2, %o1<br>
+; CHECK-NEXT: mov      %i0, %o2<br>
+; CHECK-NEXT: mov      %i1, %o3<br>
+; CHECK-NEXT: mov      %i2, %o4<br>
+; CHECK-NEXT: mov      %i1, %o5<br>
+; CHECK-NEXT: call i64arg<br>
+; CHECK: std %o0, [%i3]<br>
+; CHECK-NEXT: restore<br>
+<br>
+define void @call_i64arg(i32 %a0, i64 %a1, i64* %p) {<br>
+  %r = call i64 @i64arg(i64 %a1, i32 %a0, i64 %a1, i64 %a1, i64 %a1, i32 %a0)<br>
+  store i64 %r, i64* %p<br>
+  ret void<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>