Index: lib/Target/SystemZ/SystemZISelLowering.h =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.h +++ lib/Target/SystemZ/SystemZISelLowering.h @@ -638,6 +638,8 @@ MachineBasicBlock *emitLoadAndTestCmp0(MachineInstr &MI, MachineBasicBlock *MBB, unsigned Opcode) const; + MachineBasicBlock *emitFPScalarImm(MachineInstr &MI, + MachineBasicBlock *MBB) const; const TargetRegisterClass *getRepRegClassFor(MVT VT) const override; }; Index: lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.cpp +++ lib/Target/SystemZ/SystemZISelLowering.cpp @@ -577,9 +577,25 @@ return false; } +static bool analyzeFPImm(const APFloat &Imm, unsigned &Start, unsigned &End, + const SystemZInstrInfo *TII) { + APInt IntImm = Imm.bitcastToAPInt(); + if (IntImm.getActiveBits() > 64) + return false; + + // See if this immediate could be generated with VGM. + return TII->isRxSBGMask(uint64_t(IntImm.getZExtValue()), 64, Start, End); +} + bool SystemZTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { // We can load zero using LZ?R and negative zero using LZ?R;LC?BR. - return Imm.isZero() || Imm.isNegZero(); + if (Imm.isZero() || Imm.isNegZero()) + return true; + + const SystemZInstrInfo *TII = + static_cast(Subtarget.getInstrInfo()); + unsigned Start, End; + return analyzeFPImm(Imm, Start, End, TII); } bool SystemZTargetLowering::isLegalICmpImmediate(int64_t Imm) const { @@ -7172,6 +7188,34 @@ return MBB; } +MachineBasicBlock *SystemZTargetLowering::emitFPScalarImm( + MachineInstr &MI, MachineBasicBlock *MBB) const { + MachineFunction &MF = *MBB->getParent(); + MachineRegisterInfo *MRI = &MF.getRegInfo(); + const SystemZInstrInfo *TII = + static_cast(Subtarget.getInstrInfo()); + + APFloat Imm = MI.getOperand(1).getFPImm()->getValueAPF(); + assert(!Imm.isZero() && !Imm.isNegZero() && "Expected non-zero FP immediate"); + unsigned Start, End; + bool Success = analyzeFPImm(Imm, Start, End, TII); + assert(Success && "Can't build FP immediate."); + + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned SubRegIdx = (MRI->getRegClass(DstReg) == &SystemZ::FP32BitRegClass ? + SystemZ::subreg_h32 : SystemZ::subreg_h64); + unsigned VReg = MRI->createVirtualRegister(&SystemZ::VF128BitRegClass); + DebugLoc DL = MI.getDebugLoc(); + BuildMI(*MBB, MI, DL, TII->get(SystemZ::VGMG), VReg) + .addImm(Start) + .addImm(End); + BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::COPY), DstReg) + .addReg(VReg, RegState::Kill, SubRegIdx); + + MI.eraseFromParent(); + return MBB; +} + MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *MBB) const { switch (MI.getOpcode()) { @@ -7436,6 +7480,10 @@ case TargetOpcode::PATCHPOINT: return emitPatchPoint(MI, MBB); + case SystemZ::FP32ScalarImmPseudo: + case SystemZ::FP64ScalarImmPseudo: + return emitFPScalarImm(MI, MBB); + default: llvm_unreachable("Unexpected instr type to insert"); } Index: lib/Target/SystemZ/SystemZInstrFP.td =================================================================== --- lib/Target/SystemZ/SystemZInstrFP.td +++ lib/Target/SystemZ/SystemZInstrFP.td @@ -41,6 +41,15 @@ def LZXR : InherentRRE<"lzxr", 0xB376, FP128, fpimm0>; } +// Load scalar floating-point immediate with a VGM. +let isAsCheapAsAMove = 1, isMoveImm = 1, usesCustomInserter = 1, + hasNoSchedulingInfo = 1 in { + def FP32ScalarImmPseudo : Pseudo<(outs FP32:$R1), (ins FP32:$Imm), + [(set FP32:$R1, (fpimm:$Imm))]>; + def FP64ScalarImmPseudo : Pseudo<(outs FP64:$R1), (ins FP64:$Imm), + [(set FP64:$R1, (fpimm:$Imm))]>; +} + // Moves between two floating-point registers. def LER : UnaryRR <"ler", 0x38, null_frag, FP32, FP32>; def LDR : UnaryRR <"ldr", 0x28, null_frag, FP64, FP64>; Index: test/CodeGen/SystemZ/args-07.ll =================================================================== --- test/CodeGen/SystemZ/args-07.ll +++ test/CodeGen/SystemZ/args-07.ll @@ -29,13 +29,11 @@ define { double, double, double, double } @f3() { ; CHECK-LABEL: f3: ; CHECK: larl [[TMP:%r[0-5]]], .LCPI -; CHECK: ldeb %f0, 0([[TMP]]) -; CHECK: larl [[TMP:%r[0-5]]], .LCPI -; CHECK: ldeb %f2, 0([[TMP]]) -; CHECK: larl [[TMP:%r[0-5]]], .LCPI ; CHECK: ldeb %f4, 0([[TMP]]) ; CHECK: larl [[TMP:%r[0-5]]], .LCPI ; CHECK: ldeb %f6, 0([[TMP]]) +; CHECK: vgmg %v0, 2, 11 +; CHECK: vgmg %v2, 1, 1 ; CHECK: br %r14 ret { double, double, double, double } { double 1.0, double 2.0, double 3.0, double 4.0 } Index: test/CodeGen/SystemZ/fp-const-12.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/fp-const-12.ll @@ -0,0 +1,63 @@ +; Test loads of FP constants with VGM. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s + +define double @f1() { +; CHECK-LABEL: f1: +; CHECK: vgmg %v0, 2, 11 + ret double 1.0 +} + +define double @f2() { +; CHECK-LABEL: f2: +; CHECK: vgmg %v0, 1, 1 + ret double 2.0 +} + +define double @f3() { +; CHECK-LABEL: f3: +; CHECK: vgmg %v0, 0, 1 + ret double -2.0 +} + +define double @f4() { +; CHECK-LABEL: f4: +; CHECK: vgmg %v0, 2, 10 + ret double 0.5 +} + +define double @f5() { +; CHECK-LABEL: f5: +; CHECK: vgmg %v0, 2, 9 + ret double 0.125 +} + +define float @f6() { +; CHECK-LABEL: f6: +; CHECK: vgmg %v0, 34, 40 + ret float 1.0 +} + +define float @f7() { +; CHECK-LABEL: f7: +; CHECK: vgmg %v0, 33, 33 + ret float 2.0 +} + +define float @f8() { +; CHECK-LABEL: f8: +; CHECK: vgmg %v0, 32, 33 + ret float -2.0 +} + +define float @f9() { +; CHECK-LABEL: f9: +; CHECK: vgmg %v0, 34, 39 + ret float 0.5 +} + +define float @f10() { +; CHECK-LABEL: f10: +; CHECK: vgmg %v0, 34, 38 + ret float 0.125 +} Index: test/CodeGen/SystemZ/subregliveness-02.ll =================================================================== --- test/CodeGen/SystemZ/subregliveness-02.ll +++ test/CodeGen/SystemZ/subregliveness-02.ll @@ -1,7 +1,7 @@ ; RUN: llc -mtriple=s390x-linux-gnu -mcpu=z13 -systemz-subreg-liveness < %s | FileCheck %s ; Check for successful compilation. -; CHECK: meeb %f0, 0(%r1) +; CHECK: meebr %f1, %f0 target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64" target triple = "s390x-ibm-linux" Index: test/CodeGen/SystemZ/swifterror.ll =================================================================== --- test/CodeGen/SystemZ/swifterror.ll +++ test/CodeGen/SystemZ/swifterror.ll @@ -71,7 +71,7 @@ ; CHECK: lghi %r9, 0 ; CHECK: brasl %r14, foo ; CHECK: cgijlh %r9, 0, -; CHECK: ceb %f0, +; CHECK: cebr %f0, ; CHECK: jnh ; Access part of the error object and save it to error_ref ; CHECK: lb %r[[REG2:[0-9]+]], 8(%r9) @@ -157,7 +157,7 @@ ; CHECK: lghi %r2, 16 ; CHECK: brasl %r14, malloc ; CHECK: mvi 8(%r2), 1 -; CHECK: ceb %f8, +; CHECK: cebr %f8, ; CHECK: jnh ; CHECK: lgr %r9, %r2 ; CHECK: br %r14 Index: test/CodeGen/SystemZ/tdc-03.ll =================================================================== --- test/CodeGen/SystemZ/tdc-03.ll +++ test/CodeGen/SystemZ/tdc-03.ll @@ -34,7 +34,7 @@ define i32 @f3(float %x) { ; CHECK-LABEL: f3 ; CHECK-NOT: tceb -; CHECK: ceb %f0, 0(%r{{[0-9]+}}) +; CHECK: cebr %f0, %f{{[0-9]+}} ; CHECK-NOT: tceb %res = fcmp ult float %x, 0x7ff0000000000000 %xres = zext i1 %res to i32 @@ -55,7 +55,7 @@ define i32 @f5(float %x) { ; CHECK-LABEL: f5 ; CHECK-NOT: tceb -; CHECK: ceb %f0, 0(%r{{[0-9]+}}) +; CHECK: cebr %f0, %f{{[0-9]+}} ; CHECK-NOT: tceb %res = fcmp ult float %x, 0x3810000000000000 %xres = zext i1 %res to i32 @@ -77,7 +77,7 @@ ; CHECK-LABEL: f7 ; CHECK-NOT: tceb ; CHECK: lpdfr [[REG:%f[0-9]+]], %f0 -; CHECK: ceb [[REG]], 0(%r{{[0-9]+}}) +; CHECK: cebr [[REG]], %f{{[0-9]+}} ; CHECK-NOT: tceb %y = call float @llvm.fabs.f32(float %x) %res = fcmp ugt float %y, 0x3810000000000000 @@ -90,7 +90,7 @@ ; CHECK-LABEL: f8 ; CHECK-NOT: tceb ; CHECK: lpdfr [[REG:%f[0-9]+]], %f0 -; CHECK: ceb [[REG]], 0(%r{{[0-9]+}}) +; CHECK: cebr [[REG]], %f{{[0-9]+}} ; CHECK-NOT: tceb %y = call float @llvm.fabs.f32(float %x) %res = fcmp ult float %y, 0x3ff0000000000000