diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td --- a/llvm/include/llvm/Target/TargetSelectionDAG.td +++ b/llvm/include/llvm/Target/TargetSelectionDAG.td @@ -617,6 +617,9 @@ def strict_fsetcc : SDNode<"ISD::STRICT_FSETCC", SDTSetCC, [SDNPHasChain]>; def strict_fsetccs : SDNode<"ISD::STRICT_FSETCCS", SDTSetCC, [SDNPHasChain]>; +def get_fpenv : SDNode<"ISD::GET_FPENV", SDTGetFPStateOp, [SDNPHasChain]>; +def set_fpenv : SDNode<"ISD::SET_FPENV", SDTSetFPStateOp, [SDNPHasChain]>; +def reset_fpenv : SDNode<"ISD::RESET_FPENV", SDTNone, [SDNPHasChain]>; def get_fpmode : SDNode<"ISD::GET_FPMODE", SDTGetFPStateOp, [SDNPHasChain]>; def set_fpmode : SDNode<"ISD::SET_FPMODE", SDTSetFPStateOp, [SDNPHasChain]>; def reset_fpmode : SDNode<"ISD::RESET_FPMODE", SDTNone, [SDNPHasChain]>; diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -1411,6 +1411,9 @@ setOperationAction(ISD::BITCAST, MVT::i64, Custom); setOperationAction(ISD::GET_ROUNDING, MVT::i32, Custom); setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom); + setOperationAction(ISD::GET_FPENV, MVT::i32, Legal); + setOperationAction(ISD::SET_FPENV, MVT::i32, Legal); + setOperationAction(ISD::RESET_FPENV, MVT::Other, Legal); } // We want to custom lower some of our intrinsics. diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td --- a/llvm/lib/Target/ARM/ARMInstrVFP.td +++ b/llvm/lib/Target/ARM/ARMInstrVFP.td @@ -2670,6 +2670,11 @@ let Predicates = [HasFullFP16]; } +// Floating-point environment management. +def : Pat<(get_fpenv), (VMRS)>; +def : Pat<(set_fpenv GPRnopc:$Rt), (VMSR GPRnopc:$Rt)>; +def : Pat<(reset_fpenv), (VMSR 0)>; + //===----------------------------------------------------------------------===// // Assembler aliases. // diff --git a/llvm/test/CodeGen/ARM/fpenv.ll b/llvm/test/CodeGen/ARM/fpenv.ll --- a/llvm/test/CodeGen/ARM/fpenv.ll +++ b/llvm/test/CodeGen/ARM/fpenv.ll @@ -79,6 +79,16 @@ ret i32 %fpenv } +define i32 @get_fpenv_02() nounwind { +; CHECK-LABEL: get_fpenv_02: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmrs r0, fpscr +; CHECK-NEXT: mov pc, lr +entry: + %fpenv = call i32 @llvm.get.fpenv.i32() + ret i32 %fpenv +} + define void @set_fpenv_01(i32 %fpenv) #0 { ; CHECK-LABEL: set_fpenv_01: ; CHECK: @ %bb.0: @ %entry @@ -97,6 +107,16 @@ ret void } +define void @set_fpenv_02(i32 %fpenv) nounwind { +; CHECK-LABEL: set_fpenv_02: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmsr fpscr, r0 +; CHECK-NEXT: mov pc, lr +entry: + call void @llvm.set.fpenv.i32(i32 %fpenv) + ret void +} + define void @reset_fpenv_01() #0 { ; CHECK-LABEL: reset_fpenv_01: ; CHECK: @ %bb.0: @ %entry @@ -111,6 +131,16 @@ ret void } +define void @reset_fpenv_02() nounwind { +; CHECK-LABEL: reset_fpenv_02: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmsr fpscr, #0 +; CHECK-NEXT: mov pc, lr +entry: + call void @llvm.reset.fpenv() + ret void +} + attributes #0 = { nounwind "use-soft-float"="true" } declare void @llvm.set.rounding(i32)