diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h --- a/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/llvm/lib/Target/ARM/ARMISelLowering.h @@ -838,6 +838,9 @@ SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGET_ROUNDING(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSET_ROUNDING(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGET_FPENV(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSET_FPENV(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerRESET_FPENV(SDValue Op, SelectionDAG &DAG) const; SDValue LowerConstantFP(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *ST) const; SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, 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 @@ -1407,6 +1407,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, Custom); + setOperationAction(ISD::SET_FPENV, MVT::i32, Custom); + setOperationAction(ISD::RESET_FPENV, MVT::Other, Custom); } // We want to custom lower some of our intrinsics. @@ -6438,6 +6441,35 @@ return DAG.getNode(ISD::INTRINSIC_VOID, DL, MVT::Other, Ops2); } +SDValue ARMTargetLowering::LowerGET_FPENV(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue Ops[] = {Chain, + DAG.getConstant(Intrinsic::arm_get_fpscr, DL, MVT::i32)}; + SDValue FPSCR = + DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL, {MVT::i32, MVT::Other}, Ops); + return DAG.getMergeValues({FPSCR, FPSCR.getValue(1)}, DL); +} + +SDValue ARMTargetLowering::LowerSET_FPENV(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue Env = Op->getOperand(1); + SDValue Ops[] = { + Chain, DAG.getConstant(Intrinsic::arm_set_fpscr, DL, MVT::i32), Env}; + return DAG.getNode(ISD::INTRINSIC_VOID, DL, MVT::Other, Ops); +} + +SDValue ARMTargetLowering::LowerRESET_FPENV(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue Ops[] = {Chain, + DAG.getConstant(Intrinsic::arm_set_fpscr, DL, MVT::i32), + DAG.getConstant(0, DL, MVT::i32)}; + return DAG.getNode(ISD::INTRINSIC_VOID, DL, MVT::Other, Ops); +} + static SDValue LowerCTTZ(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { SDLoc dl(N); @@ -10536,6 +10568,9 @@ case ISD::ZERO_EXTEND: return LowerVectorExtend(Op.getNode(), DAG, Subtarget); case ISD::GET_ROUNDING: return LowerGET_ROUNDING(Op, DAG); case ISD::SET_ROUNDING: return LowerSET_ROUNDING(Op, DAG); + case ISD::GET_FPENV: return LowerGET_FPENV(Op, DAG); + case ISD::SET_FPENV: return LowerSET_FPENV(Op, DAG); + case ISD::RESET_FPENV: return LowerRESET_FPENV(Op, DAG); case ISD::MUL: return LowerMUL(Op, DAG); case ISD::SDIV: if (Subtarget->isTargetWindows() && !Op.getValueType().isVector()) 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,17 @@ ret void } +define void @reset_fpenv_02() nounwind { +; CHECK-LABEL: reset_fpenv_02: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: mov r0, #0 +; CHECK-NEXT: vmsr fpscr, r0 +; 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)