diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -17180,6 +17180,49 @@ would and handles error conditions in the same way. +Floating Point Environment Manipulation intrinsics +-------------------------------------------------- + +These functions read or write floating point environment, such as rounding +mode or state of floating point exceptions. + +'``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 +compatible with the values returned by ``FLT_ROUNDS``: + +:: + + 0 - toward zero + 1 - to nearest, ties to even + 2 - toward positive infinity + 3 - toward negative infinity + 4 - to nearest, ties away from zero + +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 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 @@ -666,6 +666,12 @@ /// FSINCOS - Compute both fsin and fcos as a single operation. FSINCOS, + /// Set rounding mode. + /// The first operand is a chain pointer. The second specifies the required + /// rounding mode, encoded in the same way as in the intrinsic + /// 'set_rounding'. + SET_ROUNDING, + /// LOAD and STORE have token chains as their first operand, then the same /// operands as an LLVM load/store instruction, then an offset node that /// is added / subtracted from the base pointer to form the address (for 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 @@ -913,6 +913,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.h b/llvm/include/llvm/IR/Intrinsics.h --- a/llvm/include/llvm/IR/Intrinsics.h +++ b/llvm/include/llvm/IR/Intrinsics.h @@ -29,6 +29,17 @@ class Module; class AttributeList; +/// Rounding mode encoding used by 'set_rounding'. +/// These values must agree with values reported by FLT_ROUNDS. +enum RoundingMode { + TowardZero = 0, + ToNearestTiesToEven = 1, + Upward = 2, + Downward = 3, + ToNearestTiesToAway = 4, + Indeterminable = -1 +}; + /// This namespace contains an enum with a value for every intrinsic/builtin /// function known by LLVM. The enum values are returned by /// Function::getIntrinsicID(). 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 @@ -603,6 +603,10 @@ [IntrNoMem, IntrSpeculatable, IntrWillReturn, ImmArg<1>, ImmArg<2>, ImmArg<3>]>, GCCBuiltin<"__builtin_object_size">; +def int_set_rounding : Intrinsic<[], + [llvm_i32_ty], + [IntrInaccessibleMemOnly, IntrWillReturn]>; + //===--------------- 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 @@ -6289,6 +6289,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, + { DAG.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 @@ -391,6 +391,9 @@ case ISD::GC_TRANSITION_END: return "gc_transition.end"; case ISD::GET_DYNAMIC_AREA_OFFSET: return "get.dynamic.area.offset"; + // Floating point environment manipulation + 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 @@ -121,6 +121,10 @@ EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma); EXPECT_TRUE(II->hasNoInfs()); EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.CreateSetRounding(Builder.getInt32(RoundingMode::TowardZero)); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::set_rounding); } TEST_F(IRBuilderTest, IntrinsicsWithScalableVectors) {