From: Diana Picus Date: Thu, 16 Feb 2017 07:53:07 +0000 (+0000) Subject: [ARM] GlobalISel: Lower double precision FP args X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cb363f5625ea93d106a897f230cdccc7c546b370;p=llvm [ARM] GlobalISel: Lower double precision FP args For the hard float calling convention, we just use the D registers. For the soft-fp calling convention, we use the R registers and move values to/from the D registers by means of G_SEQUENCE/G_EXTRACT. While doing so, we make sure to honor the endianness of the target, since the CCAssignFn doesn't do that for us. For pure soft float targets, we still bail out because we don't support the libcalls yet. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@295295 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/GlobalISel/CallLowering.h b/include/llvm/CodeGen/GlobalISel/CallLowering.h index 41bba8a4750..fac5a8bd80a 100644 --- a/include/llvm/CodeGen/GlobalISel/CallLowering.h +++ b/include/llvm/CodeGen/GlobalISel/CallLowering.h @@ -70,6 +70,17 @@ public: uint64_t Size, MachinePointerInfo &MPO, CCValAssign &VA) = 0; + /// Handle custom values, which may be passed into one or more of \p VAs. + /// \return The number of \p VAs that have been assigned after the first + /// one, and which should therefore be skipped from further + /// processing. + virtual unsigned assignCustomValue(const ArgInfo &Arg, + ArrayRef VAs) { + // This is not a pure virtual method because not all targets need to worry + // about custom values. + llvm_unreachable("Custom values not supported"); + } + unsigned extendRegister(unsigned ValReg, CCValAssign &VA); virtual bool assignArg(unsigned ValNo, MVT ValVT, MVT LocVT, diff --git a/lib/CodeGen/GlobalISel/CallLowering.cpp b/lib/CodeGen/GlobalISel/CallLowering.cpp index 2d6f7d23e3b..90427b27cd0 100644 --- a/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -132,8 +132,16 @@ bool CallLowering::handleAssignments(MachineIRBuilder &MIRBuilder, return false; } - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - CCValAssign &VA = ArgLocs[i]; + for (unsigned i = 0, e = Args.size(), j = 0; i != e; ++i, ++j) { + assert(j < ArgLocs.size() && "Skipped too many arg locs"); + + CCValAssign &VA = ArgLocs[j]; + assert(VA.getValNo() == i && "Location doesn't correspond to current arg"); + + if (VA.needsCustom()) { + j += Handler.assignCustomValue(Args[i], makeArrayRef(ArgLocs).slice(j)); + continue; + } if (VA.isRegLoc()) Handler.assignValueToReg(Args[i].Reg, VA.getLocReg(), VA); diff --git a/lib/Target/ARM/ARMCallLowering.cpp b/lib/Target/ARM/ARMCallLowering.cpp index 34b81681948..d79d9173635 100644 --- a/lib/Target/ARM/ARMCallLowering.cpp +++ b/lib/Target/ARM/ARMCallLowering.cpp @@ -39,6 +39,11 @@ static bool isSupportedType(const DataLayout &DL, const ARMTargetLowering &TLI, return false; unsigned VTSize = VT.getSimpleVT().getSizeInBits(); + + if (VTSize == 64) + // FIXME: Support i64 too + return VT.isFloatingPoint(); + return VTSize == 1 || VTSize == 8 || VTSize == 16 || VTSize == 32; } @@ -58,8 +63,8 @@ struct FuncReturnHandler : public CallLowering::ValueHandler { assert(VA.isRegLoc() && "Value shouldn't be assigned to reg"); assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?"); - assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size"); - assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size"); + assert(VA.getValVT().getSizeInBits() <= 64 && "Unsupported value size"); + assert(VA.getLocVT().getSizeInBits() <= 64 && "Unsupported location size"); unsigned ExtReg = extendRegister(ValVReg, VA); MIRBuilder.buildCopy(PhysReg, ExtReg); @@ -71,6 +76,37 @@ struct FuncReturnHandler : public CallLowering::ValueHandler { llvm_unreachable("Don't know how to assign a value to an address yet"); } + unsigned assignCustomValue(const CallLowering::ArgInfo &Arg, + ArrayRef VAs) override { + CCValAssign VA = VAs[0]; + assert(VA.needsCustom() && "Value doesn't need custom handling"); + assert(VA.getValVT() == MVT::f64 && "Unsupported type"); + + CCValAssign NextVA = VAs[1]; + assert(NextVA.needsCustom() && "Value doesn't need custom handling"); + assert(NextVA.getValVT() == MVT::f64 && "Unsupported type"); + + assert(VA.getValNo() == NextVA.getValNo() && + "Values belong to different arguments"); + + assert(VA.isRegLoc() && "Value should be in reg"); + assert(NextVA.isRegLoc() && "Value should be in reg"); + + unsigned NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)), + MRI.createGenericVirtualRegister(LLT::scalar(32))}; + + MIRBuilder.buildExtract(NewRegs, {0, 32}, Arg.Reg); + + bool IsLittle = MIRBuilder.getMF().getSubtarget().isLittle(); + if (!IsLittle) + std::swap(NewRegs[0], NewRegs[1]); + + assignValueToReg(NewRegs[0], VA.getLocReg(), VA); + assignValueToReg(NewRegs[1], NextVA.getLocReg(), NextVA); + + return 1; + } + MachineInstrBuilder &MIB; }; } // End anonymous namespace. @@ -144,7 +180,8 @@ struct FormalArgHandler : public CallLowering::ValueHandler { unsigned getStackAddress(uint64_t Size, int64_t Offset, MachinePointerInfo &MPO) override { - assert((Size == 1 || Size == 2 || Size == 4) && "Unsupported size"); + assert((Size == 1 || Size == 2 || Size == 4 || Size == 8) && + "Unsupported size"); auto &MFI = MIRBuilder.getMF().getFrameInfo(); @@ -160,7 +197,8 @@ struct FormalArgHandler : public CallLowering::ValueHandler { void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size, MachinePointerInfo &MPO, CCValAssign &VA) override { - assert((Size == 1 || Size == 2 || Size == 4) && "Unsupported size"); + assert((Size == 1 || Size == 2 || Size == 4 || Size == 8) && + "Unsupported size"); if (VA.getLocInfo() == CCValAssign::SExt || VA.getLocInfo() == CCValAssign::ZExt) { @@ -181,13 +219,44 @@ struct FormalArgHandler : public CallLowering::ValueHandler { assert(VA.isRegLoc() && "Value shouldn't be assigned to reg"); assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?"); - assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size"); - assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size"); + assert(VA.getValVT().getSizeInBits() <= 64 && "Unsupported value size"); + assert(VA.getLocVT().getSizeInBits() <= 64 && "Unsupported location size"); // The caller should handle all necesary extensions. MIRBuilder.getMBB().addLiveIn(PhysReg); MIRBuilder.buildCopy(ValVReg, PhysReg); } + + unsigned assignCustomValue(const llvm::ARMCallLowering::ArgInfo &Arg, + ArrayRef VAs) override { + CCValAssign VA = VAs[0]; + assert(VA.needsCustom() && "Value doesn't need custom handling"); + assert(VA.getValVT() == MVT::f64 && "Unsupported type"); + + CCValAssign NextVA = VAs[1]; + assert(NextVA.needsCustom() && "Value doesn't need custom handling"); + assert(NextVA.getValVT() == MVT::f64 && "Unsupported type"); + + assert(VA.getValNo() == NextVA.getValNo() && + "Values belong to different arguments"); + + assert(VA.isRegLoc() && "Value should be in reg"); + assert(NextVA.isRegLoc() && "Value should be in reg"); + + unsigned NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)), + MRI.createGenericVirtualRegister(LLT::scalar(32))}; + + assignValueToReg(NewRegs[0], VA.getLocReg(), VA); + assignValueToReg(NewRegs[1], NextVA.getLocReg(), NextVA); + + bool IsLittle = MIRBuilder.getMF().getSubtarget().isLittle(); + if (!IsLittle) + std::swap(NewRegs[0], NewRegs[1]); + + MIRBuilder.buildSequence(Arg.Reg, NewRegs, {0, 32}); + + return 1; + } }; } // End anonymous namespace diff --git a/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll b/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll index cba1344d2c1..ead9950ecac 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll +++ b/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll @@ -1,4 +1,5 @@ -; RUN: llc -mtriple arm-unknown -mattr=+vfp2 -global-isel -stop-after=irtranslator %s -o - | FileCheck %s +; RUN: llc -mtriple arm-unknown -mattr=+vfp2 -global-isel -stop-after=irtranslator %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=LITTLE +; RUN: llc -mtriple armeb-unknown -mattr=+vfp2 -global-isel -stop-after=irtranslator %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=BIG define void @test_void_return() { ; CHECK-LABEL: name: test_void_return @@ -220,3 +221,117 @@ entry: ret float %v } +define arm_aapcs_vfpcc double @test_double_vfpcc(double %p0, double %p1, double %p2, + double %p3, double %p4, double %p5, + double %reasonable, + double %parameters, + double %q0, double %q1) { +; CHECK-LABEL: name: test_double_vfpcc +; CHECK: fixedStack: +; CHECK-DAG: id: [[Q0:[0-9]+]]{{.*}}offset: 0{{.*}}size: 8 +; CHECK-DAG: id: [[Q1:[0-9]+]]{{.*}}offset: 8{{.*}}size: 8 +; CHECK: liveins: %d0, %d1, %d2, %d3, %d4, %d5, %d6, %d7 +; CHECK: [[VREGP1:%[0-9]+]](s64) = COPY %d1 +; CHECK: [[FIQ1:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[Q1]] +; CHECK: [[VREGQ1:%[0-9]+]](s64) = G_LOAD [[FIQ1]](p0) +; CHECK: [[VREGV:%[0-9]+]](s64) = G_FADD [[VREGP1]], [[VREGQ1]] +; CHECK: %d0 = COPY [[VREGV]] +; CHECK: BX_RET 14, _, implicit %d0 +entry: + %v = fadd double %p1, %q1 + ret double %v +} + +define arm_aapcscc double @test_double_aapcscc(double %p0, double %p1, double %p2, + double %p3, double %p4, double %p5) { +; CHECK-LABEL: name: test_double_aapcscc +; CHECK: fixedStack: +; CHECK-DAG: id: [[P2:[0-9]+]]{{.*}}offset: 0{{.*}}size: 8 +; CHECK-DAG: id: [[P3:[0-9]+]]{{.*}}offset: 8{{.*}}size: 8 +; CHECK-DAG: id: [[P4:[0-9]+]]{{.*}}offset: 16{{.*}}size: 8 +; CHECK-DAG: id: [[P5:[0-9]+]]{{.*}}offset: 24{{.*}}size: 8 +; CHECK: liveins: %r0, %r1, %r2, %r3 +; CHECK-DAG: [[VREGP1LO:%[0-9]+]](s32) = COPY %r2 +; CHECK-DAG: [[VREGP1HI:%[0-9]+]](s32) = COPY %r3 +; LITTLE: [[VREGP1:%[0-9]+]](s64) = G_SEQUENCE [[VREGP1LO]](s32), 0, [[VREGP1HI]](s32), 32 +; BIG: [[VREGP1:%[0-9]+]](s64) = G_SEQUENCE [[VREGP1HI]](s32), 0, [[VREGP1LO]](s32), 32 +; CHECK: [[FIP5:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[P5]] +; CHECK: [[VREGP5:%[0-9]+]](s64) = G_LOAD [[FIP5]](p0) +; CHECK: [[VREGV:%[0-9]+]](s64) = G_FADD [[VREGP1]], [[VREGP5]] +; LITTLE: [[VREGVLO:%[0-9]+]](s32), [[VREGVHI:%[0-9]+]](s32) = G_EXTRACT [[VREGV]](s64), 0, 32 +; BIG: [[VREGVHI:%[0-9]+]](s32), [[VREGVLO:%[0-9]+]](s32) = G_EXTRACT [[VREGV]](s64), 0, 32 +; CHECK-DAG: %r0 = COPY [[VREGVLO]] +; CHECK-DAG: %r1 = COPY [[VREGVHI]] +; CHECK: BX_RET 14, _, implicit %r0, implicit %r1 +entry: + %v = fadd double %p1, %p5 + ret double %v +} + +define arm_aapcs_vfpcc double @test_double_gap_vfpcc(double %p0, float %filler, + double %p1, double %p2, + double %p3, double %p4, + double %reasonable, + double %parameters, + double %q0, double %q1) { +; CHECK-LABEL: name: test_double_gap_vfpcc +; CHECK: fixedStack: +; CHECK-DAG: id: [[Q0:[0-9]+]]{{.*}}offset: 0{{.*}}size: 8 +; CHECK-DAG: id: [[Q1:[0-9]+]]{{.*}}offset: 8{{.*}}size: 8 +; CHECK: liveins: %d0, %d2, %d3, %d4, %d5, %d6, %d7, %s2 +; CHECK: [[VREGP1:%[0-9]+]](s64) = COPY %d2 +; CHECK: [[FIQ1:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[Q1]] +; CHECK: [[VREGQ1:%[0-9]+]](s64) = G_LOAD [[FIQ1]](p0) +; CHECK: [[VREGV:%[0-9]+]](s64) = G_FADD [[VREGP1]], [[VREGQ1]] +; CHECK: %d0 = COPY [[VREGV]] +; CHECK: BX_RET 14, _, implicit %d0 +entry: + %v = fadd double %p1, %q1 + ret double %v +} + +define arm_aapcscc double @test_double_gap_aapcscc(float %filler, double %p0, + double %p1) { +; CHECK-LABEL: name: test_double_gap_aapcscc +; CHECK: fixedStack: +; CHECK-DAG: id: [[P1:[0-9]+]]{{.*}}offset: 0{{.*}}size: 8 +; CHECK: liveins: %r0, %r2, %r3 +; CHECK-DAG: [[VREGP0LO:%[0-9]+]](s32) = COPY %r2 +; CHECK-DAG: [[VREGP0HI:%[0-9]+]](s32) = COPY %r3 +; LITTLE: [[VREGP0:%[0-9]+]](s64) = G_SEQUENCE [[VREGP0LO]](s32), 0, [[VREGP0HI]](s32), 32 +; BIG: [[VREGP0:%[0-9]+]](s64) = G_SEQUENCE [[VREGP0HI]](s32), 0, [[VREGP0LO]](s32), 32 +; CHECK: [[FIP1:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[P1]] +; CHECK: [[VREGP1:%[0-9]+]](s64) = G_LOAD [[FIP1]](p0) +; CHECK: [[VREGV:%[0-9]+]](s64) = G_FADD [[VREGP0]], [[VREGP1]] +; LITTLE: [[VREGVLO:%[0-9]+]](s32), [[VREGVHI:%[0-9]+]](s32) = G_EXTRACT [[VREGV]](s64), 0, 32 +; BIG: [[VREGVHI:%[0-9]+]](s32), [[VREGVLO:%[0-9]+]](s32) = G_EXTRACT [[VREGV]](s64), 0, 32 +; CHECK-DAG: %r0 = COPY [[VREGVLO]] +; CHECK-DAG: %r1 = COPY [[VREGVHI]] +; CHECK: BX_RET 14, _, implicit %r0, implicit %r1 +entry: + %v = fadd double %p0, %p1 + ret double %v +} + +define arm_aapcscc double @test_double_gap2_aapcscc(double %p0, float %filler, + double %p1) { +; CHECK-LABEL: name: test_double_gap2_aapcscc +; CHECK: fixedStack: +; CHECK-DAG: id: [[P1:[0-9]+]]{{.*}}offset: 0{{.*}}size: 8 +; CHECK: liveins: %r0, %r1, %r2 +; CHECK-DAG: [[VREGP0LO:%[0-9]+]](s32) = COPY %r0 +; CHECK-DAG: [[VREGP0HI:%[0-9]+]](s32) = COPY %r1 +; LITTLE: [[VREGP0:%[0-9]+]](s64) = G_SEQUENCE [[VREGP0LO]](s32), 0, [[VREGP0HI]](s32), 32 +; BIG: [[VREGP0:%[0-9]+]](s64) = G_SEQUENCE [[VREGP0HI]](s32), 0, [[VREGP0LO]](s32), 32 +; CHECK: [[FIP1:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[P1]] +; CHECK: [[VREGP1:%[0-9]+]](s64) = G_LOAD [[FIP1]](p0) +; CHECK: [[VREGV:%[0-9]+]](s64) = G_FADD [[VREGP0]], [[VREGP1]] +; LITTLE: [[VREGVLO:%[0-9]+]](s32), [[VREGVHI:%[0-9]+]](s32) = G_EXTRACT [[VREGV]](s64), 0, 32 +; BIG: [[VREGVHI:%[0-9]+]](s32), [[VREGVLO:%[0-9]+]](s32) = G_EXTRACT [[VREGV]](s64), 0, 32 +; CHECK-DAG: %r0 = COPY [[VREGVLO]] +; CHECK-DAG: %r1 = COPY [[VREGVHI]] +; CHECK: BX_RET 14, _, implicit %r0, implicit %r1 +entry: + %v = fadd double %p0, %p1 + ret double %v +}