Skip to content

Commit 1cc46ac

Browse files
committed
Minimal support of floating-point operand bundles
This is a lite version of llvm#109798, where code changes are minimized to facilitate discussion about the implementation. The motivations and ideas behind the new floating-point operation support are described in that PR and in the discussion https://discourse.llvm.org/t/rfc-change-of-strict-fp-operation-representation-in-ir/85021. There are concerns that the proposed changes are too invasive and a new approach is required to make the transition smoother. This implementation is essentially a subset of PR109798, where everything beyond the minimum is removed. It tries to build eventually the same implementation as that PR but in different steps. The patch does not attempt to modify the existing implementation based on the constrained intrinsics. Instead it introduces a new one using operand bundles. This new implementation initially has very limited functionality, which latter will be extended and finally can replace the existing one. This PR introduces the notion of floating-point operation, this is an intrinsic, that is listed in the file "FloatingPointOps.def". These have two additional properties: 1. In the strict environment (a function with strictfp attribute) calls to these operations acquire side effect, now it is read/write access to inaccessible memory, just as constrained intrinsics do. 2. Calls to these operations may have floating-point operand bundles. There are two kinds of such bundles, tagged with "fp.control" and "fp.except", which are used to carry additional information about control modes and exception handling. Initially the set of control modes consists of rounding mode only. The set of operations enlisted in "FloatingPointOps.def" and in "ConstrainedOps.def" are completely independent, an intrinsic may be in one list or in both. The set of floating-point operations is expected to grow and finally all FP intrinsics will be available in the new implementation. In this patch set of intrinsics in "FloatingPointOps.def" is minimum necessary for tests.
1 parent 900d20d commit 1cc46ac

File tree

18 files changed

+717
-21
lines changed

18 files changed

+717
-21
lines changed

llvm/docs/LangRef.rst

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3090,6 +3090,51 @@ A "convergencectrl" operand bundle is only valid on a ``convergent`` operation.
30903090
When present, the operand bundle must contain exactly one value of token type.
30913091
See the :doc:`ConvergentOperations` document for details.
30923092

3093+
.. _ob_fp:
3094+
3095+
Floating-point Operand Bundles
3096+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3097+
3098+
These operand bundles are used for calls that involve floating-point
3099+
operations and interact with :ref:`floating-point environment <floatenv>` or
3100+
depend on floating-point options, such as rounding mode, denormal modes, etc.
3101+
There are two kinds of such operand bundles, which represent the value of
3102+
floating-point control modes and the treatment of status bits respectively.
3103+
3104+
An operand bundle tagged with "fp.control" contains information about the
3105+
control modes used for the operation execution. Operands specified in this
3106+
bundle represent particular options. Currently, only rounding mode is supported.
3107+
It is represented by a metadata string value, which specifies the rounding mode
3108+
to be used for the operation evaluation. Possible values are:
3109+
3110+
::
3111+
3112+
"rtz" - toward zero
3113+
"rte" - to nearest, ties to even
3114+
"rtp" - toward positive infinity
3115+
"rtn" - toward negative infinity
3116+
"rmm" - to nearest, ties away from zero
3117+
"dyn" - rounding mode is taken from control register
3118+
3119+
If "fp.control" is absent, the default rounding rounding mode is taken from the
3120+
control register (dynamic rounding). In the particular case of
3121+
:ref:`default floating-point environment <floatenv>`, it must be rounding to
3122+
nearest, ties to even.
3123+
3124+
An operand bundle tagged with "fp.except" may be associated with operations
3125+
that can read or write floating-point exception flags. It contains a single
3126+
metadata string value, which can have one of the following values:
3127+
3128+
::
3129+
3130+
"ignore"
3131+
"strict"
3132+
"maytrap"
3133+
3134+
It has the same meaning as the corresponding argument in
3135+
:ref:`constrained intrinsics <constrainedfp>`.
3136+
3137+
30933138
.. _moduleasm:
30943139

30953140
Module-Level Inline Assembly
@@ -3831,9 +3876,9 @@ round-to-nearest rounding mode, and subnormals are assumed to be preserved.
38313876
Running LLVM code in an environment where these assumptions are not met
38323877
typically leads to undefined behavior. The ``strictfp`` and ``denormal-fp-math``
38333878
attributes as well as :ref:`Constrained Floating-Point Intrinsics
3834-
<constrainedfp>` can be used to weaken LLVM's assumptions and ensure defined
3835-
behavior in non-default floating-point environments; see their respective
3836-
documentation for details.
3879+
<constrainedfp>` or :ref:`floating-point operand bundles<ob_fp>` can be used to
3880+
weaken LLVM's assumptions and ensure defined behavior in non-default
3881+
floating-point environments; see their respective documentation for details.
38373882

38383883
.. _floatnan:
38393884

llvm/docs/ReleaseNotes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ Makes programs 10x faster by doing Special New Thing.
5656
Changes to the LLVM IR
5757
----------------------
5858

59+
* Floating-point operand bundles have been added.
60+
5961
Changes to LLVM infrastructure
6062
------------------------------
6163

llvm/include/llvm/IR/FPEnv.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,38 @@ enum ExceptionBehavior : uint8_t {
4949
/// metadata.
5050
LLVM_ABI std::optional<RoundingMode> convertStrToRoundingMode(StringRef);
5151

52+
/// Returns a valid RoundingMode enumerator given a string that is used as
53+
/// rounding mode specifier in operand bundles.
54+
std::optional<RoundingMode> convertBundleToRoundingMode(StringRef);
55+
5256
/// For any RoundingMode enumerator, returns a string valid as input in
5357
/// constrained intrinsic rounding mode metadata.
5458
LLVM_ABI std::optional<StringRef> convertRoundingModeToStr(RoundingMode);
5559

60+
/// For any RoundingMode enumerator, returns a string to be used in operand
61+
/// bundles.
62+
std::optional<StringRef> convertRoundingModeToBundle(RoundingMode);
63+
5664
/// Returns a valid ExceptionBehavior enumerator when given a string
5765
/// valid as input in constrained intrinsic exception behavior metadata.
5866
LLVM_ABI std::optional<fp::ExceptionBehavior>
5967
convertStrToExceptionBehavior(StringRef);
6068

69+
/// Returns a valid ExceptionBehavior enumerator given a string from the operand
70+
/// bundle argument.
71+
std::optional<fp::ExceptionBehavior>
72+
convertBundleToExceptionBehavior(StringRef);
73+
6174
/// For any ExceptionBehavior enumerator, returns a string valid as
6275
/// input in constrained intrinsic exception behavior metadata.
6376
LLVM_ABI std::optional<StringRef>
6477
convertExceptionBehaviorToStr(fp::ExceptionBehavior);
6578

79+
/// Return string representing the given exception behavior for use in operand
80+
/// bundles
81+
std::optional<StringRef>
82+
convertExceptionBehaviorToBundle(fp::ExceptionBehavior);
83+
6684
/// Returns true if the exception handling behavior and rounding mode
6785
/// match what is used in the default floating point environment.
6886
inline bool isDefaultFPEnvironment(fp::ExceptionBehavior EB, RoundingMode RM) {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===- llvm/IR/FloatingPointOps.def - FP intrinsics -------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Defines set of intrinsics, which are classified as floating-point operations.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FUNCTION
14+
#define FUNCTION(N,D)
15+
#endif
16+
17+
// Arguments of the entries are:
18+
// - intrinsic function name,
19+
// - DAG node corresponding to the intrinsic.
20+
21+
FUNCTION(nearbyint, FNEARBYINT)
22+
FUNCTION(trunc, FTRUNC)
23+
24+
#undef FUNCTION

llvm/include/llvm/IR/IRBuilder.h

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,16 @@ class IRBuilderBase {
10051005
FMFSource FMFSource = {},
10061006
const Twine &Name = "");
10071007

1008+
/// Create a call to intrinsic \p ID with \p Args, mangled using \p Types and
1009+
/// with operand bundles.
1010+
/// If \p FMFSource is provided, copy fast-math-flags from that instruction to
1011+
/// the intrinsic.
1012+
CallInst *CreateIntrinsic(Intrinsic::ID ID, ArrayRef<Type *> Types,
1013+
ArrayRef<Value *> Args,
1014+
ArrayRef<OperandBundleDef> OpBundles,
1015+
Instruction *FMFSource = nullptr,
1016+
const Twine &Name = "");
1017+
10081018
/// Create a call to non-overloaded intrinsic \p ID with \p Args. If
10091019
/// \p FMFSource is provided, copy fast-math-flags from that instruction to
10101020
/// the intrinsic.
@@ -2510,24 +2520,13 @@ class IRBuilderBase {
25102520
CallInst *CreateCall(FunctionType *FTy, Value *Callee,
25112521
ArrayRef<Value *> Args = {}, const Twine &Name = "",
25122522
MDNode *FPMathTag = nullptr) {
2513-
CallInst *CI = CallInst::Create(FTy, Callee, Args, DefaultOperandBundles);
2514-
if (IsFPConstrained)
2515-
setConstrainedFPCallAttr(CI);
2516-
if (isa<FPMathOperator>(CI))
2517-
setFPAttrs(CI, FPMathTag, FMF);
2518-
return Insert(CI, Name);
2523+
return CreateCall(FTy, Callee, Args, DefaultOperandBundles, Name,
2524+
FPMathTag);
25192525
}
25202526

25212527
CallInst *CreateCall(FunctionType *FTy, Value *Callee, ArrayRef<Value *> Args,
25222528
ArrayRef<OperandBundleDef> OpBundles,
2523-
const Twine &Name = "", MDNode *FPMathTag = nullptr) {
2524-
CallInst *CI = CallInst::Create(FTy, Callee, Args, OpBundles);
2525-
if (IsFPConstrained)
2526-
setConstrainedFPCallAttr(CI);
2527-
if (isa<FPMathOperator>(CI))
2528-
setFPAttrs(CI, FPMathTag, FMF);
2529-
return Insert(CI, Name);
2530-
}
2529+
const Twine &Name = "", MDNode *FPMathTag = nullptr);
25312530

25322531
CallInst *CreateCall(FunctionCallee Callee, ArrayRef<Value *> Args = {},
25332532
const Twine &Name = "", MDNode *FPMathTag = nullptr) {
@@ -2761,6 +2760,24 @@ class IRBuilderBase {
27612760
/// assumption on the provided pointer.
27622761
LLVM_ABI CallInst *CreateDereferenceableAssumption(Value *PtrValue,
27632762
Value *SizeValue);
2763+
2764+
/// Create an operand bundle in the provided bundle set to represent given FP
2765+
/// rounding mode.
2766+
///
2767+
/// If the rounding mode is not defined, adds the default rounding mode,
2768+
/// stored in this builder object.
2769+
void
2770+
createFPRoundingBundle(SmallVectorImpl<OperandBundleDef> &Bundles,
2771+
std::optional<RoundingMode> Rounding = std::nullopt);
2772+
2773+
/// Create an operand bundle in the provided bundle set to represent FP
2774+
/// exception behavior.
2775+
///
2776+
/// If the exception behavior is not defined, adds the default behavior,
2777+
/// stored in this builder object.
2778+
void createFPExceptionBundle(
2779+
SmallVectorImpl<OperandBundleDef> &Bundles,
2780+
std::optional<fp::ExceptionBehavior> Except = std::nullopt);
27642781
};
27652782

27662783
/// This provides a uniform API for creating instructions and inserting

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/IR/CallingConv.h"
2626
#include "llvm/IR/DerivedTypes.h"
2727
#include "llvm/IR/FMF.h"
28+
#include "llvm/IR/FPEnv.h"
2829
#include "llvm/IR/Function.h"
2930
#include "llvm/IR/Instruction.h"
3031
#include "llvm/IR/LLVMContext.h"
@@ -1095,6 +1096,13 @@ template <typename InputTy> class OperandBundleDefT {
10951096
using OperandBundleDef = OperandBundleDefT<Value *>;
10961097
using ConstOperandBundleDef = OperandBundleDefT<const Value *>;
10971098

1099+
void addFPRoundingBundle(LLVMContext &Ctx,
1100+
SmallVectorImpl<OperandBundleDef> &Bundles,
1101+
RoundingMode Rounding);
1102+
void addFPExceptionBundle(LLVMContext &Ctx,
1103+
SmallVectorImpl<OperandBundleDef> &Bundles,
1104+
fp::ExceptionBehavior Except);
1105+
10981106
//===----------------------------------------------------------------------===//
10991107
// CallBase Class
11001108
//===----------------------------------------------------------------------===//
@@ -1154,6 +1162,8 @@ class CallBase : public Instruction {
11541162
/// number of extra operands.
11551163
LLVM_ABI unsigned getNumSubclassExtraOperandsDynamic() const;
11561164

1165+
MemoryEffects getFloatingPointMemoryEffects() const;
1166+
11571167
public:
11581168
using Instruction::getContext;
11591169

@@ -2164,6 +2174,12 @@ class CallBase : public Instruction {
21642174
return false;
21652175
}
21662176

2177+
/// Return rounding mode specified by operand bundles.
2178+
RoundingMode getRoundingMode() const;
2179+
2180+
/// Return exception behavior specified by operand bundles.
2181+
std::optional<fp::ExceptionBehavior> getExceptionBehavior() const;
2182+
21672183
/// Used to keep track of an operand bundle. See the main comment on
21682184
/// OperandBundleUser above.
21692185
struct BundleOpInfo {

llvm/include/llvm/IR/IntrinsicInst.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ class IntrinsicInst : public CallInst {
129129
/// course of IR transformations
130130
LLVM_ABI static bool mayLowerToFunctionCall(Intrinsic::ID IID);
131131

132+
/// Check if \p ID represents a function that may access FP environment and
133+
/// may have FP operand bundles.
134+
///
135+
/// Access to FP environment means that in the strict FP environment the
136+
/// function has read/write memory effect, which is used to maintain proper
137+
/// instructions ordering.
138+
static bool isFloatingPointOperation(Intrinsic::ID IID);
139+
132140
/// Methods for support type inquiry through isa, cast, and dyn_cast:
133141
static bool classof(const CallInst *I) {
134142
auto *F = dyn_cast_or_null<Function>(I->getCalledOperand());

llvm/include/llvm/IR/LLVMContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ class LLVMContext {
9797
OB_ptrauth = 7, // "ptrauth"
9898
OB_kcfi = 8, // "kcfi"
9999
OB_convergencectrl = 9, // "convergencectrl"
100+
OB_fp_control = 10, // "fp.control"
101+
OB_fp_except = 11, // "fp.except"
100102
};
101103

102104
/// getMDKindID - Return a unique non-zero ID for the specified metadata kind.

llvm/include/llvm/Support/ModRef.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ template <typename LocationEnum> class MemoryEffectsBase {
235235
return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory();
236236
}
237237

238+
/// Whether this function accesses inaccessible memory.
239+
bool doesAccessInaccessibleMem() const {
240+
return isModOrRefSet(getModRef(Location::InaccessibleMem));
241+
}
242+
238243
/// Whether this function only (at most) accesses errno memory.
239244
bool onlyAccessesErrnoMem() const {
240245
return getWithoutLoc(Location::ErrnoMem).doesNotAccessMemory();

llvm/lib/IR/FPEnv.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ std::optional<RoundingMode> convertStrToRoundingMode(StringRef RoundingArg) {
3434
.Default(std::nullopt);
3535
}
3636

37+
std::optional<RoundingMode> convertBundleToRoundingMode(StringRef RoundingArg) {
38+
return StringSwitch<std::optional<RoundingMode>>(RoundingArg)
39+
.Case("dyn", RoundingMode::Dynamic)
40+
.Case("rte", RoundingMode::NearestTiesToEven)
41+
.Case("rmm", RoundingMode::NearestTiesToAway)
42+
.Case("rtn", RoundingMode::TowardNegative)
43+
.Case("rtp", RoundingMode::TowardPositive)
44+
.Case("rtz", RoundingMode::TowardZero)
45+
.Default(std::nullopt);
46+
}
47+
3748
std::optional<StringRef> convertRoundingModeToStr(RoundingMode UseRounding) {
3849
std::optional<StringRef> RoundingStr;
3950
switch (UseRounding) {
@@ -61,6 +72,33 @@ std::optional<StringRef> convertRoundingModeToStr(RoundingMode UseRounding) {
6172
return RoundingStr;
6273
}
6374

75+
std::optional<StringRef> convertRoundingModeToBundle(RoundingMode UseRounding) {
76+
std::optional<StringRef> RoundingStr;
77+
switch (UseRounding) {
78+
case RoundingMode::Dynamic:
79+
RoundingStr = "dyn";
80+
break;
81+
case RoundingMode::NearestTiesToEven:
82+
RoundingStr = "rte";
83+
break;
84+
case RoundingMode::NearestTiesToAway:
85+
RoundingStr = "rmm";
86+
break;
87+
case RoundingMode::TowardNegative:
88+
RoundingStr = "rtn";
89+
break;
90+
case RoundingMode::TowardPositive:
91+
RoundingStr = "rtp";
92+
break;
93+
case RoundingMode::TowardZero:
94+
RoundingStr = "rtz";
95+
break;
96+
default:
97+
break;
98+
}
99+
return RoundingStr;
100+
}
101+
64102
std::optional<fp::ExceptionBehavior>
65103
convertStrToExceptionBehavior(StringRef ExceptionArg) {
66104
return StringSwitch<std::optional<fp::ExceptionBehavior>>(ExceptionArg)
@@ -70,6 +108,15 @@ convertStrToExceptionBehavior(StringRef ExceptionArg) {
70108
.Default(std::nullopt);
71109
}
72110

111+
std::optional<fp::ExceptionBehavior>
112+
convertBundleToExceptionBehavior(StringRef ExceptionArg) {
113+
return StringSwitch<std::optional<fp::ExceptionBehavior>>(ExceptionArg)
114+
.Case("ignore", fp::ebIgnore)
115+
.Case("maytrap", fp::ebMayTrap)
116+
.Case("strict", fp::ebStrict)
117+
.Default(std::nullopt);
118+
}
119+
73120
std::optional<StringRef>
74121
convertExceptionBehaviorToStr(fp::ExceptionBehavior UseExcept) {
75122
std::optional<StringRef> ExceptStr;
@@ -87,6 +134,23 @@ convertExceptionBehaviorToStr(fp::ExceptionBehavior UseExcept) {
87134
return ExceptStr;
88135
}
89136

137+
std::optional<StringRef>
138+
convertExceptionBehaviorToBundle(fp::ExceptionBehavior UseExcept) {
139+
std::optional<StringRef> ExceptStr;
140+
switch (UseExcept) {
141+
case fp::ebStrict:
142+
ExceptStr = "strict";
143+
break;
144+
case fp::ebIgnore:
145+
ExceptStr = "ignore";
146+
break;
147+
case fp::ebMayTrap:
148+
ExceptStr = "maytrap";
149+
break;
150+
}
151+
return ExceptStr;
152+
}
153+
90154
Intrinsic::ID getConstrainedIntrinsicID(const Instruction &Instr) {
91155
Intrinsic::ID IID = Intrinsic::not_intrinsic;
92156
switch (Instr.getOpcode()) {

0 commit comments

Comments
 (0)