Index: lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- lib/Target/X86/X86InstructionSelector.cpp +++ lib/Target/X86/X86InstructionSelector.cpp @@ -21,6 +21,7 @@ #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" #include "llvm/CodeGen/GlobalISel/Utils.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -55,7 +56,7 @@ bool selectImpl(MachineInstr &I) const; // TODO: remove after supported by Tablegen-erated instruction selection. - unsigned getLoadStoreOp(LLT &Ty, const RegisterBank &RB, unsigned Opc, + unsigned getLoadStoreOp(const LLT &Ty, const RegisterBank &RB, unsigned Opc, uint64_t Alignment) const; bool selectLoadStoreOp(MachineInstr &I, MachineRegisterInfo &MRI, @@ -87,6 +88,8 @@ MachineFunction &MF) const; bool selectCondBranch(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; + bool materializeFP(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF) const; bool selectImplicitDefOrPHI(MachineInstr &I, MachineRegisterInfo &MRI) const; // emit insert subreg instruction and insert it before MachineInstr &I @@ -336,13 +339,16 @@ return true; if (selectCondBranch(I, MRI, MF)) return true; + if (materializeFP(I, MRI, MF)) + return true; if (selectImplicitDefOrPHI(I, MRI)) return true; return false; } -unsigned X86InstructionSelector::getLoadStoreOp(LLT &Ty, const RegisterBank &RB, +unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty, + const RegisterBank &RB, unsigned Opc, uint64_t Alignment) const { bool Isload = (Opc == TargetOpcode::G_LOAD); @@ -740,11 +746,11 @@ const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI); const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI); - assert (DstRB.getID() == SrcRB.getID() && - "G_ANYEXT input/output on different banks\n"); + assert(DstRB.getID() == SrcRB.getID() && + "G_ANYEXT input/output on different banks\n"); - assert (DstTy.getSizeInBits() > SrcTy.getSizeInBits() && - "G_ANYEXT incorrect operand size"); + assert(DstTy.getSizeInBits() > SrcTy.getSizeInBits() && + "G_ANYEXT incorrect operand size"); if (DstRB.getID() != X86::GPRRegBankID) return false; @@ -1183,6 +1189,73 @@ return true; } +bool X86InstructionSelector::materializeFP(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + if (I.getOpcode() != TargetOpcode::G_FCONSTANT) + return false; + + // Can't handle alternate code models yet. + CodeModel::Model CM = TM.getCodeModel(); + if (CM != CodeModel::Small && CM != CodeModel::Large) + return false; + + const unsigned DstReg = I.getOperand(0).getReg(); + const LLT DstTy = MRI.getType(DstReg); + const RegisterBank &RegBank = *RBI.getRegBank(DstReg, MRI, TRI); + unsigned Align = DstTy.getSizeInBits(); + const DebugLoc &DbgLoc = I.getDebugLoc(); + + unsigned Opc = getLoadStoreOp(DstTy, RegBank, TargetOpcode::G_LOAD, Align); + + // Create the load from the constant pool. + const ConstantFP *CFP = I.getOperand(1).getFPImm(); + unsigned CPI = MF.getConstantPool()->getConstantPoolIndex(CFP, Align); + MachineInstr *LoadInst = nullptr; + unsigned char OpFlag = STI.classifyLocalReference(nullptr); + + if (CM == CodeModel::Large && STI.is64Bit()) { + // Under X86-64 non-small code model, GV (and friends) are 64-bits, so + // they cannot be folded into immediate fields. + + unsigned AddrReg = MRI.createVirtualRegister(&X86::GR64RegClass); + BuildMI(*I.getParent(), I, DbgLoc, TII.get(X86::MOV64ri), AddrReg) + .addConstantPoolIndex(CPI, 0, OpFlag); + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad, + MF.getDataLayout().getPointerSize(), Align); + + LoadInst = + addDirectMem(BuildMI(*I.getParent(), I, DbgLoc, TII.get(Opc), DstReg), + AddrReg) + .addMemOperand(MMO); + + } else if(CM == CodeModel::Small || !STI.is64Bit()){ + // Handle the case when globals fit in our immediate field. + // This is true for X86-32 always and X86-64 when in -mcmodel=small mode. + + // x86-32 PIC requires a PIC base register for constant pools. + unsigned PICBase = 0; + if (OpFlag == X86II::MO_PIC_BASE_OFFSET || OpFlag == X86II::MO_GOTOFF) { + // PICBase can be allocated by TII.getGlobalBaseReg(&MF). + // In DAGISEL the code that initialize it generated by the CGBR pass. + return false; // TODO support the mode. + } + else if (STI.is64Bit() && TM.getCodeModel() == CodeModel::Small) + PICBase = X86::RIP; + + LoadInst = addConstantPoolReference( + BuildMI(*I.getParent(), I, DbgLoc, TII.get(Opc), DstReg), CPI, PICBase, + OpFlag); + } else + return false; + + constrainSelectedInstRegOperands(*LoadInst, TII, TRI, RBI); + I.eraseFromParent(); + return true; +} + bool X86InstructionSelector::selectImplicitDefOrPHI( MachineInstr &I, MachineRegisterInfo &MRI) const { Index: lib/Target/X86/X86LegalizerInfo.cpp =================================================================== --- lib/Target/X86/X86LegalizerInfo.cpp +++ lib/Target/X86/X86LegalizerInfo.cpp @@ -164,6 +164,9 @@ for (unsigned MemOp : {G_LOAD, G_STORE}) for (auto Ty : {v4s32, v2s64}) setAction({MemOp, Ty}, Legal); + + // Constants + setAction({TargetOpcode::G_FCONSTANT, s32}, Legal); } void X86LegalizerInfo::setLegalizerInfoSSE2() { @@ -189,6 +192,9 @@ setAction({G_FPEXT, s64}, Legal); setAction({G_FPEXT, 1, s32}, Legal); + + // Constants + setAction({TargetOpcode::G_FCONSTANT, s64}, Legal); } void X86LegalizerInfo::setLegalizerInfoSSE41() { Index: lib/Target/X86/X86RegisterBankInfo.cpp =================================================================== --- lib/Target/X86/X86RegisterBankInfo.cpp +++ lib/Target/X86/X86RegisterBankInfo.cpp @@ -186,6 +186,7 @@ switch (Opc) { case TargetOpcode::G_FPEXT: + case TargetOpcode::G_FCONSTANT: // Instruction having only floating-point operands (all scalars in VECRReg) getInstrPartialMappingIdxs(MI, MRI, /* isFP */ true, OpRegBankIdx); break; Index: test/CodeGen/X86/GlobalISel/fconstant.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/fconstant.ll @@ -0,0 +1,40 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse2 -global-isel -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK64 --check-prefix=CHECK_SMALL --check-prefix=CHECK_SMALL64 --check-prefix=CHECK_NOPIC64 +; RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse2 -global-isel -code-model=large -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK64 --check-prefix=CHECK_LARGE --check-prefix=CHECK_LARGE64 +; RUN: llc -mtriple=i386-linux-gnu -mattr=+sse2 -global-isel -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK32 --check-prefix=CHECK_SMALL --check-prefix=CHECK_SMALL32 +; RUN: llc -mtriple=i386-linux-gnu -mattr=+sse2 -global-isel -code-model=large -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK32 --check-prefix=CHECK_LARGE --check-prefix=CHECK_LARGE32 +; RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse2 -global-isel -relocation-model=pic -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK64 --check-prefix=CHECK_SMALL --check-prefix=CHECK_SMALL64 --check-prefix=CHECK_PIC64 + +define void @test_float(float* %a , float %b) { +; CHECK_SMALL64-LABEL: test_float: +; CHECK_SMALL64: # BB#0: # %entry +; CHECK_SMALL64-NEXT: movss .LCPI0_0(%rip), %xmm1 # xmm1 = mem[0],zero,zero,zero +; CHECK_SMALL64-NEXT: addss %xmm0, %xmm1 +; CHECK_SMALL64-NEXT: movd %xmm1, %eax +; CHECK_SMALL64-NEXT: movl %eax, (%rdi) +; CHECK_SMALL64-NEXT: retq +; +; CHECK_LARGE64-LABEL: test_float: +; CHECK_LARGE64: # BB#0: # %entry +; CHECK_LARGE64-NEXT: movabsq $.LCPI0_0, %rax +; CHECK_LARGE64-NEXT: addss (%rax), %xmm0 +; CHECK_LARGE64-NEXT: movd %xmm0, %eax +; CHECK_LARGE64-NEXT: movl %eax, (%rdi) +; CHECK_LARGE64-NEXT: retq +; +; CHECK32-LABEL: test_float: +; CHECK32: # BB#0: # %entry +; CHECK32-NEXT: movl 4(%esp), %eax +; CHECK32-NEXT: movl 8(%esp), %ecx +; CHECK32-NEXT: movss .LCPI0_0, %xmm0 # xmm0 = mem[0],zero,zero,zero +; CHECK32-NEXT: movd %ecx, %xmm1 +; CHECK32-NEXT: addss %xmm0, %xmm1 +; CHECK32-NEXT: movd %xmm1, %ecx +; CHECK32-NEXT: movl %ecx, (%eax) +; CHECK32-NEXT: retl +entry: + %aa = fadd float 5.500000e+00, %b + store float %aa, float* %a + ret void +} + Index: test/CodeGen/X86/GlobalISel/legalize-constant.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-constant.mir +++ test/CodeGen/X86/GlobalISel/legalize-constant.mir @@ -1,15 +1,14 @@ -# RUN: llc -mtriple=i386-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X32 -# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64 +# RUN: llc -mtriple=i386-linux-gnu -mattr=+sse2 -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X32 +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64 --- | - define void @constInt_check() { - ret void - } + define void @test_constant() { ret void } + define void @test_fconstant() { ret void } ... --- -name: constInt_check -# ALL-LABEL: name: constInt_check +name: test_constant +# ALL-LABEL: name: test_constant registers: - { id: 0, class: _ } - { id: 1, class: _ } @@ -40,4 +39,18 @@ RET 0 ... +--- +name: test_fconstant +# ALL-LABEL: name: test_fconstant +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } +body: | + bb.0: + ; ALL: %0(s32) = G_FCONSTANT float 1.000000e+00 + ; ALL: %1(s64) = G_FCONSTANT double 2.000000e+00 + + %0(s32) = G_FCONSTANT float 1.0 + %1(s64) = G_FCONSTANT double 2.0 +... Index: test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir =================================================================== --- test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir +++ test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir @@ -236,6 +236,10 @@ %conv = fpext float %a to double ret double %conv } + + define void @test_fconstant() { + ret void + } ... --- @@ -1411,4 +1415,19 @@ RET 0, implicit %xmm0 ... +--- +name: test_fconstant +# ALL-LABEL: name: test_fconstant +legalized: true +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: vecr, preferred-register: '' } +# CHECK-NEXT: - { id: 1, class: vecr, preferred-register: '' } +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } +body: | + bb.0: + %0(s32) = G_FCONSTANT float 1.0 + %1(s64) = G_FCONSTANT double 2.0 +... Index: test/CodeGen/X86/GlobalISel/select-fconstant.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/select-fconstant.mir @@ -0,0 +1,94 @@ +#RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse2 -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK64 --check-prefix=CHECK_SMALL --check-prefix=CHECK_SMALL64 --check-prefix=CHECK_NOPIC64 +#RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse2 -global-isel -code-model=large -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK64 --check-prefix=CHECK_LARGE --check-prefix=CHECK_LARGE64 +#RUN: llc -mtriple=i386-linux-gnu -mattr=+sse2 -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK32 --check-prefix=CHECK_SMALL --check-prefix=CHECK_SMALL32 +#RUN: llc -mtriple=i386-linux-gnu -mattr=+sse2 -global-isel -code-model=large -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK32 --check-prefix=CHECK_LARGE --check-prefix=CHECK_LARGE32 +#RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse2 -global-isel -relocation-model=pic -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK64 --check-prefix=CHECK_SMALL --check-prefix=CHECK_SMALL64 --check-prefix=CHECK_PIC64 + +--- | + define float @test_float() { + entry: + ret float 5.500000e+00 + } + + define double @test_double() { + entry: + ret double 5.500000e+00 + } +--- +name: test_float +# CHECK64-LABEL: name: test_float +# +# CHECK32-LABEL: name: test_float +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# CHECK_SMALL64: registers: +# CHECK_SMALL64-NEXT: - { id: 0, class: fr32, preferred-register: '' } +# +# CHECK_LARGE64: registers: +# CHECK_LARGE64-NEXT: - { id: 0, class: fr32, preferred-register: '' } +# CHECK_LARGE64-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# +# CHECK32: registers: +# CHECK32-NEXT: - { id: 0, class: fr32, preferred-register: '' } +registers: + - { id: 0, class: vecr, preferred-register: '' } +# CHECK_SMALL64: %0 = MOVSSrm %rip, 1, _, %const.0, _ +# CHECK_SMALL64-NEXT: %xmm0 = COPY %0 +# CHECK_SMALL64-NEXT: RET 0, implicit %xmm0 +# +# CHECK_LARGE64: %1 = MOV64ri %const.0 +# CHECK_LARGE64-NEXT: %0 = MOVSSrm %1, 1, _, 0, _ :: (load 8 from constant-pool, align 32) +# CHECK_LARGE64-NEXT: %xmm0 = COPY %0 +# CHECK_LARGE64-NEXT: RET 0, implicit %xmm0 +# +# CHECK32: %0 = MOVSSrm _, 1, _, %const.0, _ +# CHECK32-NEXT: %xmm0 = COPY %0 +# CHECK32-NEXT: RET 0, implicit %xmm0 +body: | + bb.1.entry: + %0(s32) = G_FCONSTANT float 5.500000e+00 + %xmm0 = COPY %0(s32) + RET 0, implicit %xmm0 + +... +--- +name: test_double +# CHECK64-LABEL: name: test_double +# +# CHECK32-LABEL: name: test_double +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# CHECK_SMALL64: registers: +# CHECK_SMALL64-NEXT: - { id: 0, class: fr64, preferred-register: '' } +# +# CHECK_LARGE64: registers: +# CHECK_LARGE64-NEXT: - { id: 0, class: fr64, preferred-register: '' } +# CHECK_LARGE64-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# +# CHECK32: registers: +# CHECK32-NEXT: - { id: 0, class: fr64, preferred-register: '' } +registers: + - { id: 0, class: vecr, preferred-register: '' } +# CHECK_SMALL64: %0 = MOVSDrm %rip, 1, _, %const.0, _ +# CHECK_SMALL64-NEXT: %xmm0 = COPY %0 +# CHECK_SMALL64-NEXT: RET 0, implicit %xmm0 +# +# CHECK_LARGE64: %1 = MOV64ri %const.0 +# CHECK_LARGE64-NEXT: %0 = MOVSDrm %1, 1, _, 0, _ :: (load 8 from constant-pool, align 64) +# CHECK_LARGE64-NEXT: %xmm0 = COPY %0 +# CHECK_LARGE64-NEXT: RET 0, implicit %xmm0 +# +# CHECK32: %0 = MOVSDrm _, 1, _, %const.0, _ +# CHECK32-NEXT: %xmm0 = COPY %0 +# CHECK32-NEXT: RET 0, implicit %xmm0 +body: | + bb.1.entry: + %0(s64) = G_FCONSTANT double 5.500000e+00 + %xmm0 = COPY %0(s64) + RET 0, implicit %xmm0 + +...