diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -19726,6 +19726,37 @@ Other values may be used to represent additional rounding modes, supported by a target. These values are target-specific. + +'``llvm.set.rounding``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare void @llvm.set.rounding(i32 ) + +Overview: +""""""""" + +The '``llvm.set.rounding``' intrinsic sets current rounding mode. + +Arguments: +"""""""""" + +The argument is the required rounding mode. Encoding of rounding mode is +the same as used by '``llvm.flt.rounds``'. + +Semantics: +"""""""""" + +The '``llvm.set.rounding``' intrinsic sets the current rounding mode. It is +similar to C library function 'fesetround', however this intrinsic does not +return any value and uses platform-independent representation of IEEE rounding +modes. + + General Intrinsics ------------------ diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h --- a/llvm/include/llvm/CodeGen/ISDOpcodes.h +++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h @@ -762,15 +762,22 @@ /// FP_EXTEND(FP_ROUND(X,0)) because the extra bits aren't removed. FP_ROUND, - /// FLT_ROUNDS_ - Returns current rounding mode: + /// Returns current rounding mode: /// -1 Undefined /// 0 Round to 0 - /// 1 Round to nearest + /// 1 Round to nearest, ties to even /// 2 Round to +inf /// 3 Round to -inf + /// 4 Round to nearest, ties to zero /// Result is rounding mode and chain. Input is a chain. + /// TODO: Rename this node to GET_ROUNDING. FLT_ROUNDS_, + /// Set rounding mode. + /// The first operand is a chain pointer. The second specifies the required + /// rounding mode, encoded in the same way as used in '``FLT_ROUNDS_``'. + SET_ROUNDING, + /// X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type. FP_EXTEND, diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -689,6 +689,7 @@ let IntrProperties = [IntrInaccessibleMemOnly, IntrWillReturn] in { def int_flt_rounds : DefaultAttrsIntrinsic<[llvm_i32_ty], []>; + def int_set_rounding : DefaultAttrsIntrinsic<[], [llvm_i32_ty]>; } //===--------------- Constrained Floating Point Intrinsics ----------------===// diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1544,6 +1544,8 @@ case ISD::VECREDUCE_SMIN: case ISD::VECREDUCE_UMAX: case ISD::VECREDUCE_UMIN: Res = PromoteIntOp_VECREDUCE(N); break; + + case ISD::SET_ROUNDING: Res = PromoteIntOp_SET_ROUNDING(N); break; } // If the result is null, the sub-method took care of registering results etc. @@ -2009,6 +2011,11 @@ return DAG.getNode(ISD::TRUNCATE, dl, VT, Reduce); } +SDValue DAGTypeLegalizer::PromoteIntOp_SET_ROUNDING(SDNode *N) { + SDValue Op = ZExtPromotedInteger(N->getOperand(1)); + return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), Op), 0); +} + //===----------------------------------------------------------------------===// // Integer Result Expansion //===----------------------------------------------------------------------===// diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -390,6 +390,7 @@ SDValue PromoteIntOp_FIX(SDNode *N); SDValue PromoteIntOp_FPOWI(SDNode *N); SDValue PromoteIntOp_VECREDUCE(SDNode *N); + SDValue PromoteIntOp_SET_ROUNDING(SDNode *N); void PromoteSetCCOperands(SDValue &LHS,SDValue &RHS, ISD::CondCode Code); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6228,6 +6228,12 @@ getValue(I.getArgOperand(0)), SatW)); return; } + case Intrinsic::set_rounding: + Res = DAG.getNode(ISD::SET_ROUNDING, sdl, MVT::Other, + {getRoot(), getValue(I.getArgOperand(0))}); + setValue(&I, Res); + DAG.setRoot(Res.getValue(0)); + return; case Intrinsic::pcmarker: { SDValue Tmp = getValue(I.getArgOperand(0)); DAG.setRoot(DAG.getNode(ISD::PCMARKER, sdl, MVT::Other, getRoot(), Tmp)); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -336,7 +336,6 @@ case ISD::TRUNCATE: return "truncate"; case ISD::FP_ROUND: return "fp_round"; case ISD::STRICT_FP_ROUND: return "strict_fp_round"; - case ISD::FLT_ROUNDS_: return "flt_rounds"; case ISD::FP_EXTEND: return "fp_extend"; case ISD::STRICT_FP_EXTEND: return "strict_fp_extend"; @@ -410,6 +409,10 @@ case ISD::PREALLOCATED_ARG: return "call_alloc"; + // Floating point environment manipulation + case ISD::FLT_ROUNDS_: return "flt_rounds"; + case ISD::SET_ROUNDING: return "set_rounding"; + // Bit manipulation case ISD::ABS: return "abs"; case ISD::BITREVERSE: return "bitreverse"; diff --git a/llvm/unittests/IR/IRBuilderTest.cpp b/llvm/unittests/IR/IRBuilderTest.cpp --- a/llvm/unittests/IR/IRBuilderTest.cpp +++ b/llvm/unittests/IR/IRBuilderTest.cpp @@ -127,6 +127,12 @@ EXPECT_EQ(II->getIntrinsicID(), Intrinsic::roundeven); EXPECT_FALSE(II->hasNoInfs()); EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.CreateIntrinsic( + Intrinsic::set_rounding, {}, + {Builder.getInt32(static_cast(RoundingMode::TowardZero))}); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::set_rounding); } TEST_F(IRBuilderTest, IntrinsicsWithScalableVectors) {