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,72 @@ 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); + + // x86-32 PIC requires a PIC base register for constant pools. + unsigned PICBase = 0; + unsigned char OpFlag = STI.classifyLocalReference(nullptr); + if (OpFlag == X86II::MO_PIC_BASE_OFFSET || OpFlag == X86II::MO_GOTOFF) + PICBase = TII.getGlobalBaseReg(&MF); + else if (STI.is64Bit() && TM.getCodeModel() == CodeModel::Small) + PICBase = X86::RIP; + + // Create the load from the constant pool. + const ConstantFP *CFP = I.getOperand(1).getFPImm(); + unsigned CPI = MF.getConstantPool()->getConstantPoolIndex(CFP, Align); + + if (CM == CodeModel::Large) { + unsigned AddrReg = MRI.createVirtualRegister(&X86::GR64RegClass); + BuildMI(*I.getParent(), I, DbgLoc, TII.get(X86::MOV64ri), AddrReg) + .addConstantPoolIndex(CPI, 0, OpFlag); + MachineInstrBuilder MIB = + BuildMI(*I.getParent(), I, DbgLoc, TII.get(Opc), DstReg); + addDirectMem(MIB, AddrReg); + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad, + MF.getDataLayout().getPointerSize(), Align); + MIB->addMemOperand(MF, MMO); + + } else { + + BuildMI(*I.getParent(), I, DbgLoc, TII.get(Opc), DstReg) + .addReg(PICBase) + .addImm(1) + .addReg(0) + .addConstantPoolIndex(CPI, 0, OpFlag) + .addReg(0); + } + + if (!MRI.getRegClassOrNull(DstReg)) { + const TargetRegisterClass *RC = getRegClass(DstTy, RegBank); + if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { + DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) + << " operand\n"); + return false; + } + } + + 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/constant.ll =================================================================== --- test/CodeGen/X86/GlobalISel/constant.ll +++ test/CodeGen/X86/GlobalISel/constant.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64 +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=CHECK_SMALL +; RUN: llc -mtriple=x86_64-linux-gnu -code-model=large -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=CHECK_LARGE define i8 @const_i8() { ; ALL-LABEL: const_i8: @@ -51,8 +52,8 @@ ret i64 -1 } -define void @main(i32 ** %data) { -; ALL-LABEL: main: +define void @check_ptr(i32 ** %data) { +; ALL-LABEL: check_ptr: ; ALL: # BB#0: ; ALL-NEXT: movq $0, %rax ; ALL-NEXT: movq %rax, (%rdi) @@ -61,3 +62,32 @@ ret void } + +define float @test_float() { +; CHECK_SMALL-LABEL: test_float: +; CHECK_SMALL: # BB#0: +; CHECK_SMALL-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK_SMALL-NEXT: retq +; +; CHECK_LARGE-LABEL: test_float: +; CHECK_LARGE: # BB#0: +; CHECK_LARGE-NEXT: movabsq ${{\.LCPI.*}}, %rax +; CHECK_LARGE-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK_LARGE-NEXT: retq + ret float 5.500000e+00 +} + +; Function Attrs: norecurse nounwind readnone uwtable +define double @test_double() { +; CHECK_SMALL-LABEL: test_double: +; CHECK_SMALL: # BB#0: +; CHECK_SMALL-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK_SMALL-NEXT: retq +; +; CHECK_LARGE-LABEL: test_double: +; CHECK_LARGE: # BB#0: +; CHECK_LARGE-NEXT: movabsq ${{\.LCPI.*}}, %rax +; CHECK_LARGE-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK_LARGE-NEXT: retq + ret double 5.500000e+00 +} 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-constant.mir =================================================================== --- test/CodeGen/X86/GlobalISel/select-constant.mir +++ test/CodeGen/X86/GlobalISel/select-constant.mir @@ -1,4 +1,5 @@ -# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK_SMALL +# RUN: llc -mtriple=x86_64-linux-gnu -code-model=large -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK_LARGE --- | define i8 @const_i8() { @@ -29,11 +30,21 @@ ret i64 -1 } - define void @main(i32** %data) { + define void @const_ptr(i32** %data) { store i32* null, i32** %data, align 8 ret void } + define float @test_float() { + entry: + ret float 5.500000e+00 + } + + define double @test_double() { + entry: + ret double 5.500000e+00 + } + ... --- name: const_i8 @@ -168,8 +179,8 @@ ... --- -name: main -# CHECK-LABEL: name: main +name: const_ptr +# CHECK-LABEL: name: const_ptr alignment: 4 legalized: true regBankSelected: true @@ -193,3 +204,64 @@ RET 0 ... +--- +name: test_float +# CHECK-LABEL: name: test_float +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# CHECK_SMALL: registers: +# CHECK_SMALL-NEXT: - { id: 0, class: fr32, preferred-register: '' } +# +# CHECK_LARGE: registers: +# CHECK_LARGE-NEXT: - { id: 0, class: fr32, preferred-register: '' } +# CHECK_LARGE-NEXT: - { id: 1, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: vecr, preferred-register: '' } +# CHECK_SMALL: %0 = MOVSSrm %rip, 1, _, %const.0, _ +# CHECK_SMALL-NEXT: %xmm0 = COPY %0 +# CHECK_SMALL-NEXT: RET 0, implicit %xmm0 +# +# CHECK_LARGE: %1 = MOV64ri %const.0 +# CHECK_LARGE-NEXT: %0 = MOVSSrm %1, 1, _, 0, _ :: (load 8 from constant-pool, align 32) +# CHECK_LARGE-NEXT: %xmm0 = COPY %0 +# CHECK_LARGE-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 +# CHECK-LABEL: name: test_double +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# CHECK_SMALL: registers: +# CHECK_SMALL-NEXT: - { id: 0, class: fr64, preferred-register: '' } +# +# CHECK_LARGE: registers: +# CHECK_LARGE-NEXT: - { id: 0, class: fr64, preferred-register: '' } +# CHECK_LARGE-NEXT: - { id: 1, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: vecr, preferred-register: '' } +# CHECK_SMALL: %0 = MOVSDrm %rip, 1, _, %const.0, _ +# CHECK_SMALL-NEXT: %xmm0 = COPY %0 +# CHECK_SMALL-NEXT: RET 0, implicit %xmm0 +# +# CHECK_LARGE: %1 = MOV64ri %const.0 +# CHECK_LARGE-NEXT: %0 = MOVSDrm %1, 1, _, 0, _ :: (load 8 from constant-pool, align 64) +# CHECK_LARGE-NEXT: %xmm0 = COPY %0 +# CHECK_LARGE-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 + +... +