#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"
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,
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
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);
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;
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 {
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() {
setAction({G_FPEXT, s64}, Legal);
setAction({G_FPEXT, 1, s32}, Legal);
+
+ // Constants
+ setAction({TargetOpcode::G_FCONSTANT, s64}, Legal);
}
void X86LegalizerInfo::setLegalizerInfoSSE41() {
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;
--- /dev/null
+; 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
+}
+
-# 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: _ }
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
+...
%conv = fpext float %a to double
ret double %conv
}
+
+ define void @test_fconstant() {
+ ret void
+ }
...
---
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
+...
--- /dev/null
+#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
+
+...