diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index 3824b1c66951e..c005218c80f44 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -687,6 +687,9 @@ HANDLE_TARGET_OPCODE(G_FMINIMUM) HANDLE_TARGET_OPCODE(G_FMAXIMUM) /// Access to FP environment. +HANDLE_TARGET_OPCODE(G_GET_FPENV) +HANDLE_TARGET_OPCODE(G_SET_FPENV) +HANDLE_TARGET_OPCODE(G_RESET_FPENV) HANDLE_TARGET_OPCODE(G_GET_FPMODE) HANDLE_TARGET_OPCODE(G_SET_FPMODE) HANDLE_TARGET_OPCODE(G_RESET_FPMODE) diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index 73e38b15bf671..2c73b67f9e1af 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -1020,6 +1020,27 @@ def G_FNEARBYINT : GenericInstruction { // it is modeled as a side effect, because constrained intrinsics use the same // method. +// Reading floating-point environment. +def G_GET_FPENV : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins); + let hasSideEffects = true; +} + +// Setting floating-point environment. +def G_SET_FPENV : GenericInstruction { + let OutOperandList = (outs); + let InOperandList = (ins type0:$src); + let hasSideEffects = true; +} + +// Setting default floating-point environment. +def G_RESET_FPENV : GenericInstruction { + let OutOperandList = (outs); + let InOperandList = (ins); + let hasSideEffects = true; +} + // Reading floating-point control modes. def G_GET_FPMODE : GenericInstruction { let OutOperandList = (outs type0:$dst); diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td index 5e704f0b9a758..f792237203b43 100644 --- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td +++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -116,6 +116,9 @@ def : GINodeEquiv { let IfConvergent = G_INTRINSIC_CONVERGENT; } +def : GINodeEquiv; +def : GINodeEquiv; +def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 9c11113902a24..1f7c67e4f3b0c 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1844,6 +1844,8 @@ unsigned IRTranslator::getSimpleIntrinsicOpcode(Intrinsic::ID ID) { return TargetOpcode::G_LROUND; case Intrinsic::llround: return TargetOpcode::G_LLROUND; + case Intrinsic::get_fpenv: + return TargetOpcode::G_GET_FPENV; case Intrinsic::get_fpmode: return TargetOpcode::G_GET_FPMODE; } @@ -2427,6 +2429,16 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, return true; } + case Intrinsic::set_fpenv: { + Value *FPEnv = CI.getOperand(0); + MIRBuilder.buildInstr(TargetOpcode::G_SET_FPENV, {}, + {getOrCreateVReg(*FPEnv)}); + return true; + } + case Intrinsic::reset_fpenv: { + MIRBuilder.buildInstr(TargetOpcode::G_RESET_FPENV, {}, {}); + return true; + } case Intrinsic::set_fpmode: { Value *FPState = CI.getOperand(0); MIRBuilder.buildInstr(TargetOpcode::G_SET_FPMODE, {}, diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index def7f6ebeb011..21947a55874aa 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -958,6 +958,13 @@ static RTLIB::Libcall getStateLibraryFunctionFor(MachineInstr &MI, const TargetLowering &TLI) { RTLIB::Libcall RTLibcall; switch (MI.getOpcode()) { + case TargetOpcode::G_GET_FPENV: + RTLibcall = RTLIB::FEGETENV; + break; + case TargetOpcode::G_SET_FPENV: + case TargetOpcode::G_RESET_FPENV: + RTLibcall = RTLIB::FESETENV; + break; case TargetOpcode::G_GET_FPMODE: RTLibcall = RTLIB::FEGETMODE; break; @@ -1232,18 +1239,21 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) { MI.eraseFromParent(); return Result; } + case TargetOpcode::G_GET_FPENV: case TargetOpcode::G_GET_FPMODE: { LegalizeResult Result = createGetStateLibcall(MIRBuilder, MI, LocObserver); if (Result != Legalized) return Result; break; } + case TargetOpcode::G_SET_FPENV: case TargetOpcode::G_SET_FPMODE: { LegalizeResult Result = createSetStateLibcall(MIRBuilder, MI, LocObserver); if (Result != Legalized) return Result; break; } + case TargetOpcode::G_RESET_FPENV: case TargetOpcode::G_RESET_FPMODE: { LegalizeResult Result = createResetStateLibcall(MIRBuilder, MI, LocObserver); diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp index 470742cdc30e6..2ad5590c5439f 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp @@ -1165,7 +1165,8 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) getActionDefinitionsBuilder(G_FMAD).lower(); // Access to floating-point environment. - getActionDefinitionsBuilder({G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE}) + getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_RESET_FPENV, + G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE}) .libcall(); getActionDefinitionsBuilder(G_IS_FPCLASS).lower(); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/fpenv.ll b/llvm/test/CodeGen/AArch64/GlobalISel/fpenv.ll new file mode 100644 index 0000000000000..a95d650518378 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/fpenv.ll @@ -0,0 +1,43 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 +; RUN: llc -mtriple=aarch64-none-linux-gnu -verify-machineinstrs -global-isel -global-isel-abort=1 %s -o - | FileCheck %s + +declare i64 @llvm.get.fpenv.i64() +declare void @llvm.set.fpenv.i64(i64 %fpenv) +declare void @llvm.reset.fpenv() + +define i64 @get_fpenv_01() nounwind { +; CHECK-LABEL: get_fpenv_01: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: add x0, sp, #8 +; CHECK-NEXT: bl fegetenv +; CHECK-NEXT: ldr x0, [sp, #8] +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +entry: + %fpenv = call i64 @llvm.get.fpenv.i64() + ret i64 %fpenv +} + +define void @set_fpenv_01(i64 %fpenv) nounwind { +; CHECK-LABEL: set_fpenv_01: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: stp x30, x0, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: add x0, sp, #8 +; CHECK-NEXT: bl fesetenv +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +entry: + call void @llvm.set.fpenv.i64(i64 %fpenv) + ret void +} + +define void @reset_fpenv_01() nounwind { +; CHECK-LABEL: reset_fpenv_01: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: mov x0, #-1 // =0xffffffffffffffff +; CHECK-NEXT: b fesetenv +entry: + call void @llvm.reset.fpenv() + ret void +} diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-fpenv.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-fpenv.ll index fda9269d423d0..9a8e5529f0a1e 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-fpenv.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-fpenv.ll @@ -1,10 +1,47 @@ ; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py ; RUN: llc -O0 -mtriple=aarch64-linux-gnu -global-isel -stop-after=irtranslator %s -o - | FileCheck %s +declare i64 @llvm.get.fpenv.i64() +declare void @llvm.set.fpenv.i64(i64 %fpenv) +declare void @llvm.reset.fpenv() declare i32 @llvm.get.fpmode.i32() declare void @llvm.set.fpmode.i32(i32 %fpmode) declare void @llvm.reset.fpmode() +define i64 @func_get_fpenv() #0 { + ; CHECK-LABEL: name: func_get_fpenv + ; CHECK: bb.1.entry: + ; CHECK-NEXT: [[GET_FPENV:%[0-9]+]]:_(s64) = G_GET_FPENV + ; CHECK-NEXT: $x0 = COPY [[GET_FPENV]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 +entry: + %fpenv = call i64 @llvm.get.fpenv.i64() + ret i64 %fpenv +} + +define void @func_set_fpenv(i64 %fpenv) #0 { + ; CHECK-LABEL: name: func_set_fpenv + ; CHECK: bb.1.entry: + ; CHECK-NEXT: liveins: $x0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: G_SET_FPENV [[COPY]](s64) + ; CHECK-NEXT: RET_ReallyLR +entry: + call void @llvm.set.fpenv.i64(i64 %fpenv) + ret void +} + +define void @func_reset_fpenv() #0 { + ; CHECK-LABEL: name: func_reset_fpenv + ; CHECK: bb.1.entry: + ; CHECK-NEXT: G_RESET_FPENV + ; CHECK-NEXT: RET_ReallyLR +entry: + call void @llvm.reset.fpenv() + ret void +} + define i32 @func_get_fpmode() #0 { ; CHECK-LABEL: name: func_get_fpmode ; CHECK: bb.1.entry: diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fpenv.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fpenv.mir new file mode 100644 index 0000000000000..936f839280c4d --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fpenv.mir @@ -0,0 +1,59 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 2 +# RUN: llc -mtriple=aarch64-linux-gnu -run-pass=legalizer %s -o - | FileCheck %s + +--- +name: func_get_fpenv +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: func_get_fpenv + ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0 + ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: $x0 = COPY [[FRAME_INDEX]](p0) + ; CHECK-NEXT: BL &fegetenv, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0 + ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s64) from %stack.0) + ; CHECK-NEXT: $x0 = COPY [[LOAD]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = G_GET_FPENV + $x0 = COPY %0(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: func_set_fpenv +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + + ; CHECK-LABEL: name: func_set_fpenv + ; CHECK: liveins: $x0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0 + ; CHECK-NEXT: G_STORE [[COPY]](s64), [[FRAME_INDEX]](p0) :: (store (s64) into %stack.0) + ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: $x0 = COPY [[FRAME_INDEX]](p0) + ; CHECK-NEXT: BL &fesetenv, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0 + ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: RET_ReallyLR + %0:_(s64) = COPY $x0 + G_SET_FPENV %0(s64) + RET_ReallyLR + +... +--- +name: func_reset +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: func_reset + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1 + ; CHECK-NEXT: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[C]](s64) + ; CHECK-NEXT: $x0 = COPY [[INTTOPTR]](p0) + ; CHECK-NEXT: TCRETURNdi &fesetenv, 0, csr_aarch64_aapcs, implicit $sp, implicit $x0 + G_RESET_FPENV + RET_ReallyLR + +... diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir index 2adf9763a96b6..c90c31aa27ef5 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir @@ -553,7 +553,19 @@ # DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}} # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected +# DEBUG-NEXT: G_GET_FPENV (opcode {{[0-9]+}}): 1 type index, 0 imm indices +# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected +# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected +# DEBUG-NEXT: G_SET_FPENV (opcode {{[0-9]+}}): 1 type index, 0 imm indices +# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}} +# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected +# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected +# DEBUG-NEXT: G_RESET_FPENV (opcode {{[0-9]+}}): 0 type indices, 0 imm indices +# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}} +# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected +# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: G_GET_FPMODE (opcode {{[0-9]+}}): 1 type index, 0 imm indices +# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}} # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: G_SET_FPMODE (opcode {{[0-9]+}}): 1 type index, 0 imm indices diff --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td index f9d7d2dcccdbb..dd3ac6cc3672a 100644 --- a/llvm/test/TableGen/GlobalISelEmitter.td +++ b/llvm/test/TableGen/GlobalISelEmitter.td @@ -518,7 +518,7 @@ def : Pat<(frag GPR32:$src1, complex:$src2, complex:$src3), // R00O-NEXT: GIM_Reject, // R00O: // Label [[DEFAULT_NUM]]: @[[DEFAULT]] // R00O-NEXT: GIM_Reject, -// R00O-NEXT: }; // Size: 2007 bytes +// R00O-NEXT: }; // Size: 2019 bytes def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4), [(set GPR32:$dst,