diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -19222,6 +19222,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 @@ -737,15 +737,21 @@ /// 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. 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/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h --- a/llvm/include/llvm/IR/IRBuilder.h +++ b/llvm/include/llvm/IR/IRBuilder.h @@ -901,6 +901,11 @@ return CreateBinaryIntrinsic(Intrinsic::maximum, LHS, RHS, nullptr, Name); } + /// Create call to the set_rounding intrinsic. + CallInst *createSetRounding(Value *RM, const Twine &Name = "") { + return CreateIntrinsic(Intrinsic::set_rounding, {}, {RM}, nullptr, Name); + } + private: /// Create a call to a masked intrinsic with given Id. CallInst *CreateMaskedIntrinsic(Intrinsic::ID Id, ArrayRef Ops, 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 @@ -665,6 +665,7 @@ let IntrProperties = [IntrInaccessibleMemOnly, IntrWillReturn] in { def int_flt_rounds : Intrinsic<[llvm_i32_ty], []>; + def int_set_rounding : Intrinsic<[], [llvm_i32_ty]>; } //===--------------- Constrained Floating Point Intrinsics ----------------===// 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 @@ -6170,6 +6170,12 @@ DAG.getNode(ISD::BITCAST, sdl, MVT::f16, getValue(I.getArgOperand(0))))); 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 @@ -334,7 +334,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"; @@ -403,6 +402,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/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -5102,6 +5102,12 @@ break; } + case Intrinsic::set_rounding: { + if (auto RM = dyn_cast(Call.getArgOperand(0))) { + Assert(RM->getZExtValue() < static_cast(RoundingMode::Dynamic), + "invalid value of rounding mode"); + } + } }; } 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,11 @@ EXPECT_EQ(II->getIntrinsicID(), Intrinsic::roundeven); EXPECT_FALSE(II->hasNoInfs()); EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.createSetRounding( + Builder.getInt32(static_cast(RoundingMode::TowardZero))); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::set_rounding); } TEST_F(IRBuilderTest, IntrinsicsWithScalableVectors) {