diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp index e792b1bce3c5c..374fb95974a62 100644 --- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp +++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp @@ -126,6 +126,13 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI, G_FSINCOS, G_FCEIL, G_FFLOOR}) .libcall(); + getActionDefinitionsBuilder(G_FNEG) + .legalFor(UseX87 && !HasSSE1, {s32}) + .legalFor(UseX87 && !HasSSE2, {s64}) + .legalFor(UseX87, {s80}) + .customFor(UseX87 && !Is64Bit, {s32}) + .lowerFor({s32, s64}); + getActionDefinitionsBuilder(G_FSQRT) .legalFor(HasSSE1 || UseX87, {s32}) .legalFor(HasSSE2 || UseX87, {s64}) @@ -623,6 +630,8 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, return legalizeGETROUNDING(MI, MRI, Helper); case TargetOpcode::G_SET_ROUNDING: return legalizeSETROUNDING(MI, MRI, Helper); + case TargetOpcode::G_FNEG: + return legalizeFNEG(MI, MRI, Helper); } llvm_unreachable("expected switch to return"); } @@ -993,6 +1002,35 @@ bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI, return true; } +bool X86LegalizerInfo::legalizeFNEG(MachineInstr &MI, MachineRegisterInfo &MRI, + LegalizerHelper &Helper) const { + bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87(); + bool Is64Bit = Subtarget.is64Bit(); + + if (!(UseX87 && !Is64Bit)) + return false; + + Register DstReg = MI.getOperand(0).getReg(); + Register SrcReg = MI.getOperand(1).getReg(); + + LLT S32 = LLT::scalar(32); + LLT S80 = LLT::scalar(80); + + if (MRI.getType(SrcReg) != S32 || MRI.getType(DstReg) != S32) + return false; + + Register ExtReg = MRI.createGenericVirtualRegister(S80); + Helper.MIRBuilder.buildFPExt(ExtReg, SrcReg); + + Register NegReg = MRI.createGenericVirtualRegister(S80); + Helper.MIRBuilder.buildFNeg(NegReg, ExtReg); + + Helper.MIRBuilder.buildFPTrunc(DstReg, NegReg); + + MI.eraseFromParent(); + return true; +} + bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, MachineInstr &MI) const { return true; diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h index 09c727c8e8685..d239256fb406a 100644 --- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h +++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h @@ -60,6 +60,9 @@ class X86LegalizerInfo : public LegalizerInfo { bool legalizeSETROUNDING(MachineInstr &MI, MachineRegisterInfo &MRI, LegalizerHelper &Helper) const; + + bool legalizeFNEG(MachineInstr &MI, MachineRegisterInfo &MRI, + LegalizerHelper &Helper) const; }; } // namespace llvm #endif diff --git a/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp b/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp index b23d791501729..4cb7b5cc6775c 100644 --- a/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp +++ b/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp @@ -292,6 +292,7 @@ X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { switch (Opc) { case TargetOpcode::G_FSQRT: case TargetOpcode::G_FPEXT: + case TargetOpcode::G_FNEG: case TargetOpcode::G_FPTRUNC: case TargetOpcode::G_FCONSTANT: // Instruction having only floating-point operands (all scalars in diff --git a/llvm/test/CodeGen/X86/GlobalISel/isel-fneg.mir b/llvm/test/CodeGen/X86/GlobalISel/isel-fneg.mir new file mode 100644 index 0000000000000..7aa5478dcdd95 --- /dev/null +++ b/llvm/test/CodeGen/X86/GlobalISel/isel-fneg.mir @@ -0,0 +1,116 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6 +# RUN: llc -mtriple=i686-linux-gnu -run-pass=regbankselect,instruction-select %s -o - | FileCheck %s --check-prefixes GISEL-I686 + +--- +name: fneg_f64 +alignment: 16 +legalized: true +fixedStack: + - { id: 0, type: default, offset: 0, size: 8, alignment: 16, stack-id: default, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.1: + ; GISEL-I686-LABEL: name: fneg_f64 + ; GISEL-I686: [[DEF:%[0-9]+]]:rfp64 = IMPLICIT_DEF + ; GISEL-I686-NEXT: [[CHS_Fp64_:%[0-9]+]]:rfp64 = CHS_Fp64 [[DEF]], implicit-def dead $fpsw + ; GISEL-I686-NEXT: $fp0 = COPY [[CHS_Fp64_]] + ; GISEL-I686-NEXT: RET 0, implicit $fp0 + %1:_(p0) = G_FRAME_INDEX %fixed-stack.0 + %0:_(s64) = IMPLICIT_DEF + %2:_(s64) = G_FNEG %0 + $fp0 = COPY %2(s64) + RET 0, implicit $fp0 +... +--- +name: fneg_f32 +alignment: 16 +legalized: true +fixedStack: + - { id: 0, type: default, offset: 0, size: 4, alignment: 16, stack-id: default, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.1: + ; GISEL-I686-LABEL: name: fneg_f32 + ; GISEL-I686: [[LD_Fp32m:%[0-9]+]]:rfp32 = nofpexcept LD_Fp32m %fixed-stack.0, 1, $noreg, 0, $noreg, implicit-def dead $fpsw, implicit $fpcw :: (invariant load (s32) from %fixed-stack.0, align 16) + ; GISEL-I686-NEXT: [[CHS_Fp32_:%[0-9]+]]:rfp32 = CHS_Fp32 [[LD_Fp32m]], implicit-def dead $fpsw + ; GISEL-I686-NEXT: $fp0 = COPY [[CHS_Fp32_]] + ; GISEL-I686-NEXT: RET 0, implicit $fp0 + %1:_(p0) = G_FRAME_INDEX %fixed-stack.0 + %0:_(s32) = G_LOAD %1(p0) :: (invariant load (s32) from %fixed-stack.0, align 16) + %2:_(s32) = G_FNEG %0 + $fp0 = COPY %2(s32) + RET 0, implicit $fp0 +... +--- +name: fneg_f64_mem +alignment: 16 +legalized: true +fixedStack: + - { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: default, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } + - { id: 1, type: default, offset: 0, size: 4, alignment: 16, stack-id: default, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.1: + ; GISEL-I686-LABEL: name: fneg_f64_mem + ; GISEL-I686: [[DEF:%[0-9]+]]:rfp64 = IMPLICIT_DEF + ; GISEL-I686-NEXT: [[CHS_Fp64_:%[0-9]+]]:rfp64 = CHS_Fp64 [[DEF]], implicit-def dead $fpsw + ; GISEL-I686-NEXT: $fp0 = COPY [[CHS_Fp64_]] + ; GISEL-I686-NEXT: RET 0, implicit $fp0 + %1:_(p0) = G_FRAME_INDEX %fixed-stack.1 + %0:_(s64) = IMPLICIT_DEF + %2:_(s64) = G_FNEG %0 + $fp0 = COPY %2(s64) + RET 0, implicit $fp0 +... +--- +name: fneg_f32_mem +alignment: 16 +legalized: true +fixedStack: + - { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: default, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } + - { id: 1, type: default, offset: 0, size: 4, alignment: 16, stack-id: default, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.1: + ; GISEL-I686-LABEL: name: fneg_f32_mem + ; GISEL-I686: [[LD_Fp32m:%[0-9]+]]:rfp32 = nofpexcept LD_Fp32m %fixed-stack.1, 1, $noreg, 0, $noreg, implicit-def dead $fpsw, implicit $fpcw :: (invariant load (p0) from %fixed-stack.1) + ; GISEL-I686-NEXT: [[CHS_Fp32_:%[0-9]+]]:rfp32 = CHS_Fp32 [[LD_Fp32m]], implicit-def dead $fpsw + ; GISEL-I686-NEXT: $fp0 = COPY [[CHS_Fp32_]] + ; GISEL-I686-NEXT: RET 0, implicit $fp0 + %2:_(p0) = G_FRAME_INDEX %fixed-stack.1 + %0:_(p0) = G_LOAD %2(p0) :: (invariant load (p0) from %fixed-stack.1, align 16) + %3:_(p0) = G_FRAME_INDEX %fixed-stack.0 + %1:_(s32) = G_LOAD %3(p0) :: (invariant load (p0) from %fixed-stack.0) + %4:_(s32) = G_FNEG %1 + $fp0 = COPY %4(s32) + RET 0, implicit $fp0 +... +--- +name: test_fp80 +alignment: 16 +legalized: true +fixedStack: + - { id: 0, type: default, offset: 0, size: 10, alignment: 16, stack-id: default, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.1: + ; GISEL-I686-LABEL: name: test_fp80 + ; GISEL-I686: [[LD_Fp80m:%[0-9]+]]:rfp80 = nofpexcept LD_Fp80m %fixed-stack.0, 1, $noreg, 0, $noreg, implicit-def dead $fpsw, implicit $fpcw :: (invariant load (s80) from %fixed-stack.0, align 16) + ; GISEL-I686-NEXT: [[CHS_Fp80_:%[0-9]+]]:rfp80 = CHS_Fp80 [[LD_Fp80m]], implicit-def dead $fpsw + ; GISEL-I686-NEXT: $fp0 = COPY [[CHS_Fp80_]] + ; GISEL-I686-NEXT: RET 0, implicit $fp0 + %1:_(p0) = G_FRAME_INDEX %fixed-stack.0 + %0:_(s80) = G_LOAD %1(p0) :: (invariant load (s80) from %fixed-stack.0, align 16) + %2:_(s80) = G_FNEG %0 + $fp0 = COPY %2(s80) + RET 0, implicit $fp0 +... diff --git a/llvm/test/CodeGen/X86/isel-fneg.ll b/llvm/test/CodeGen/X86/isel-fneg.ll index 77b3f263213a9..e77c46c9d10d8 100644 --- a/llvm/test/CodeGen/X86/isel-fneg.ll +++ b/llvm/test/CodeGen/X86/isel-fneg.ll @@ -1,13 +1,13 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 ; RUN: llc < %s -mtriple=i686-linux-gnu -fast-isel | FileCheck %s --check-prefixes=X86,FASTISEL-X86 ; RUN: llc < %s -mtriple=i686-linux-gnu -global-isel=0 -fast-isel=0 | FileCheck %s --check-prefixes=X86,SDAG-X86 -; DISABLED: llc < %s -mtriple=i686-linux-gnu -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes=X86,GISEL-X86 +; RUN: llc < %s -mtriple=i686-linux-gnu -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes=X86,GISEL-X86 ; RUN: llc < %s -mtriple=i686-linux-gnu -fast-isel -mattr=+sse | FileCheck %s --check-prefixes=X86,SSE-X86,FASTISEL-SSE-X86 ; RUN: llc < %s -mtriple=i686-linux-gnu -global-isel=0 -fast-isel=0 -mattr=+sse | FileCheck %s --check-prefixes=X86,SSE-X86,SDAG-SSE-X86 -; DISABLED: llc < %s -mtriple=i686-linux-gnu -global-isel=1 -global-isel-abort=2 -mattr=+sse | FileCheck %s --check-prefixes=X86,SSE-X86,GISEL-SSE-X86 +; RUN: llc < %s -mtriple=i686-linux-gnu -global-isel=1 -global-isel-abort=2 -mattr=+sse | FileCheck %s --check-prefixes=X86,SSE-X86,GISEL-SSE-X86 ; RUN: llc < %s -mtriple=x86_64-linux-gnu -fast-isel -mattr=+sse | FileCheck %s --check-prefixes=X64,SSE-X64,FASTISEL-SSE-X64 ; RUN: llc < %s -mtriple=x86_64-linux-gnu -global-isel=0 -fast-isel=0 -mattr=+sse | FileCheck %s --check-prefixes=X64,SSE-X64,SDAG-SSE-X64 -; RUN: llc < %s -mtriple=x86_64-linux-gnu -global-isel=1 -global-isel-abort=2 -mattr=+sse | FileCheck %s --check-prefixes=X64,SSE-X64,GISEL-SSE-X64 +; RUN: llc < %s -mtriple=x86_64-linux-gnu -global-isel=1 -global-isel-abort=1 -mattr=+sse | FileCheck %s --check-prefixes=X64,SSE-X64,GISEL-SSE-X64 define double @fneg_f64(double %x) nounwind { ; X86-LABEL: fneg_f64: @@ -53,6 +53,12 @@ define float @fneg_f32(float %x) nounwind { ; SDAG-X86-NEXT: fchs ; SDAG-X86-NEXT: retl ; +; GISEL-X86-LABEL: fneg_f32: +; GISEL-X86: # %bb.0: +; GISEL-X86-NEXT: flds {{[0-9]+}}(%esp) +; GISEL-X86-NEXT: fchs +; GISEL-X86-NEXT: retl +; ; SSE-X86-LABEL: fneg_f32: ; SSE-X86: # %bb.0: ; SSE-X86-NEXT: pushl %eax @@ -143,6 +149,15 @@ define void @fneg_f32_mem(ptr %x, ptr %y) nounwind { ; SDAG-X86-NEXT: movl %edx, (%eax) ; SDAG-X86-NEXT: retl ; +; GISEL-X86-LABEL: fneg_f32_mem: +; GISEL-X86: # %bb.0: +; GISEL-X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; GISEL-X86-NEXT: movl {{[0-9]+}}(%esp), %ecx +; GISEL-X86-NEXT: flds (%eax) +; GISEL-X86-NEXT: fchs +; GISEL-X86-NEXT: fstps (%ecx) +; GISEL-X86-NEXT: retl +; ; FASTISEL-SSE-X86-LABEL: fneg_f32_mem: ; FASTISEL-SSE-X86: # %bb.0: ; FASTISEL-SSE-X86-NEXT: movl {{[0-9]+}}(%esp), %eax @@ -161,6 +176,15 @@ define void @fneg_f32_mem(ptr %x, ptr %y) nounwind { ; SDAG-SSE-X86-NEXT: movl %edx, (%eax) ; SDAG-SSE-X86-NEXT: retl ; +; GISEL-SSE-X86-LABEL: fneg_f32_mem: +; GISEL-SSE-X86: # %bb.0: +; GISEL-SSE-X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; GISEL-SSE-X86-NEXT: movl {{[0-9]+}}(%esp), %ecx +; GISEL-SSE-X86-NEXT: movl $-2147483648, %edx # imm = 0x80000000 +; GISEL-SSE-X86-NEXT: xorl (%ecx), %edx +; GISEL-SSE-X86-NEXT: movl %edx, (%eax) +; GISEL-SSE-X86-NEXT: retl +; ; FASTISEL-SSE-X64-LABEL: fneg_f32_mem: ; FASTISEL-SSE-X64: # %bb.0: ; FASTISEL-SSE-X64-NEXT: movd {{.*#+}} xmm0 = mem[0],zero,zero,zero