Skip to content

Commit 131f152

Browse files
committed
Update according to the obtained feedback
- Bundles are renamed: "fp.control" -> "fp.round", - Corrected documentation, - DAG nodes STRICT_* are used to lower the supported intrinsics, - Constrained properties in IRBuilder are reused for handling FP bundles, - DAG gets methods for lowering FP operations, - IR dump prints FP memory effects, - Fixed some problems in IRBuilderBase::CreateCall, - Added a new check to Verifier, - Added tests for checking code generation.
1 parent 617dee0 commit 131f152

File tree

18 files changed

+615
-225
lines changed

18 files changed

+615
-225
lines changed

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
10921092
if ((FD && (FD->UsesFPIntrin() || FD->hasAttr<StrictFPAttr>())) ||
10931093
(!FD && (FPExceptionBehavior != llvm::fp::ebIgnore ||
10941094
RM != llvm::RoundingMode::NearestTiesToEven))) {
1095-
Builder.setIsFPConstrained(true);
1095+
Builder.setIsFPConstrained(true, false);
10961096
Fn->addFnAttr(llvm::Attribute::StrictFP);
10971097
}
10981098

llvm/docs/LangRef.rst

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,43 +3098,48 @@ Floating-point Operand Bundles
30983098
These operand bundles are used for calls that involve floating-point
30993099
operations and interact with :ref:`floating-point environment <floatenv>` or
31003100
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.
31033101

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-
3108-
Rounding mode is represented by a metadata string value, which specifies the
3109-
the mode used for the operation evaluation. Possible values are:
3102+
An operand bundle tagged with "fp.round" contains information about the
3103+
rounding mode used for the operation execution (the effective rounding mode).
3104+
This mode is represented by a metadata string value and specifies the mode used
3105+
for the operation evaluation. Possible values are:
31103106

31113107
::
31123108

3113-
"rtz" - toward zero
3114-
"rte" - to nearest, ties to even
3115-
"rtp" - toward positive infinity
3116-
"rtn" - toward negative infinity
3117-
"rmm" - to nearest, ties away from zero
3118-
"dyn" - rounding mode is taken from control register
3109+
"towardzero"
3110+
"tonearest"
3111+
"upward"
3112+
"downward"
3113+
"tonearestaway"
3114+
"dynamic"
31193115

3120-
Only one such value may be specified. If "fp.control" is absent, the default
3121-
rounding rounding mode is taken from the control register (dynamic rounding).
3122-
In the particular case of :ref:`default floating-point environment <floatenv>`,
3123-
the operation uses rounding to nearest, ties to even.
3116+
Only one value may be specified. If the "fp.round" bundle is absent, and
3117+
the operation depends on rounding mode, the default behavior is to use the value
3118+
from a control register (dynamic rounding). In the specific case of
3119+
:ref:`default floating-point environment <floatenv>`, the register is assumed to
3120+
set rounding to nearest, ties to even.
31243121

31253122
An operand bundle tagged with "fp.except" may be associated with operations
3126-
that can read or write floating-point exception flags. It contains a single
3127-
metadata string value, which can have one of the following values:
3123+
that can raise floating-point exceptions. It contains a single metadata string
3124+
value, which can have one of the following:
31283125

31293126
::
31303127

31313128
"ignore"
31323129
"strict"
3133-
"maytrap"
3134-
3135-
It has the same meaning as the corresponding argument in
3136-
:ref:`constrained intrinsics <constrainedfp>`.
31373130

3131+
If the argument is "ignore", floating-point exceptions raised by the call are not
3132+
intended to be observed. Optimization transformations may reorder such operations
3133+
or omit them in some cases. For example, if the call result is unused, the call
3134+
may be removed, even if it could raise exceptions. This is the only permitted value
3135+
in the :ref:`default floating-point environment <floatenv>`.
3136+
3137+
If the argument of "fp.except" is "strict", all transformations must preserve the
3138+
floating-point exception semantics of the original code. Any exception that would
3139+
have been raised by the original code must also be raised by the transformed code
3140+
unless it can be proven unobservable. No new observable floating-point exceptions
3141+
may be introduced. This value may only be used only in functions with
3142+
``strictfp`` attribute.
31383143

31393144
.. _moduleasm:
31403145

llvm/include/llvm/IR/FloatingPointOps.def

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,21 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
// Describes floating-point operation.
14+
// Arguments of the entries are:
15+
// N - intrinsic function name,
16+
// D - DAG node corresponding to the intrinsic.
1317
#ifndef FUNCTION
1418
#define FUNCTION(N,D)
1519
#endif
1620

17-
// Arguments of the entries are:
18-
// - intrinsic function name,
19-
// - DAG node corresponding to the intrinsic.
21+
// Describes floating-point operation, which lowers to STRICT_* nodes in DAG.
22+
#ifndef LEGACY_DAG
23+
#define LEGACY_DAG(N,D) FUNCTION(N,D)
24+
#endif
2025

21-
FUNCTION(nearbyint, FNEARBYINT)
22-
FUNCTION(trunc, FTRUNC)
26+
LEGACY_DAG(nearbyint, FNEARBYINT)
27+
LEGACY_DAG(trunc, FTRUNC)
2328

2429
#undef FUNCTION
30+
#undef LEGACY_DAG

llvm/include/llvm/IR/IRBuilder.h

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ class IRBuilderBase {
153153
FastMathFlags FMF;
154154

155155
bool IsFPConstrained = false;
156-
fp::ExceptionBehavior DefaultConstrainedExcept = fp::ebStrict;
157-
RoundingMode DefaultConstrainedRounding = RoundingMode::Dynamic;
156+
fp::ExceptionBehavior DefaultConstrainedExcept = fp::ebIgnore;
157+
RoundingMode DefaultConstrainedRounding = RoundingMode::NearestTiesToEven;
158158

159159
ArrayRef<OperandBundleDef> DefaultOperandBundles;
160160

@@ -348,7 +348,18 @@ class IRBuilderBase {
348348
/// enabled the CreateF<op>() calls instead create constrained
349349
/// floating point intrinsic calls. Fast math flags are unaffected
350350
/// by this setting.
351-
void setIsFPConstrained(bool IsCon) { IsFPConstrained = IsCon; }
351+
void setIsFPConstrained(bool IsCon, bool AndReset = true) {
352+
if (AndReset) {
353+
if (IsCon) {
354+
setDefaultConstrainedRounding(RoundingMode::Dynamic);
355+
setDefaultConstrainedExcept(fp::ebStrict);
356+
} else {
357+
setDefaultConstrainedRounding(RoundingMode::NearestTiesToEven);
358+
setDefaultConstrainedExcept(fp::ebIgnore);
359+
}
360+
}
361+
IsFPConstrained = IsCon;
362+
}
352363

353364
/// Query for the use of constrained floating point math
354365
bool getIsFPConstrained() { return IsFPConstrained; }
@@ -2761,23 +2772,21 @@ class IRBuilderBase {
27612772
LLVM_ABI CallInst *CreateDereferenceableAssumption(Value *PtrValue,
27622773
Value *SizeValue);
27632774

2764-
/// Create an operand bundle in the provided bundle set to represent given FP
2765-
/// rounding mode.
2775+
/// Create an operand bundle in the provided bundle set to represent the given
2776+
/// floating-point rounding mode.
27662777
///
27672778
/// If the rounding mode is not defined, adds the default rounding mode,
27682779
/// stored in this builder object.
2769-
void
2770-
createFPRoundingBundle(SmallVectorImpl<OperandBundleDef> &Bundles,
2771-
std::optional<RoundingMode> Rounding = std::nullopt);
2780+
void createRoundingBundle(SmallVectorImpl<OperandBundleDef> &Bundles,
2781+
RoundingMode RM);
27722782

2773-
/// Create an operand bundle in the provided bundle set to represent FP
2774-
/// exception behavior.
2783+
/// Create an operand bundle in the provided bundle set to represent the given
2784+
/// floating-point exception behavior.
27752785
///
27762786
/// If the exception behavior is not defined, adds the default behavior,
27772787
/// stored in this builder object.
2778-
void createFPExceptionBundle(
2779-
SmallVectorImpl<OperandBundleDef> &Bundles,
2780-
std::optional<fp::ExceptionBehavior> Except = std::nullopt);
2788+
void createExceptionBundle(SmallVectorImpl<OperandBundleDef> &Bundles,
2789+
fp::ExceptionBehavior Except);
27812790
};
27822791

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

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,12 +1096,17 @@ template <typename InputTy> class OperandBundleDefT {
10961096
using OperandBundleDef = OperandBundleDefT<Value *>;
10971097
using ConstOperandBundleDef = OperandBundleDefT<const Value *>;
10981098

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);
1099+
/// Add a bundle with tag "fp.round" and the specified rounding to the given
1100+
/// bundle set.
1101+
void addRoundingBundle(LLVMContext &Ctx,
1102+
SmallVectorImpl<OperandBundleDef> &Bundles,
1103+
RoundingMode Rounding);
1104+
1105+
/// Add a bundle with tag "fp.except" and the specified exception behavior to
1106+
/// the given bundle set.
1107+
void addExceptionBundle(LLVMContext &Ctx,
1108+
SmallVectorImpl<OperandBundleDef> &Bundles,
1109+
fp::ExceptionBehavior Except);
11051110

11061111
//===----------------------------------------------------------------------===//
11071112
// CallBase Class
@@ -1162,6 +1167,7 @@ class CallBase : public Instruction {
11621167
/// number of extra operands.
11631168
LLVM_ABI unsigned getNumSubclassExtraOperandsDynamic() const;
11641169

1170+
/// Get memory effects specific to floating-point operations.
11651171
MemoryEffects getFloatingPointMemoryEffects() const;
11661172

11671173
public:
@@ -2174,10 +2180,10 @@ class CallBase : public Instruction {
21742180
return false;
21752181
}
21762182

2177-
/// Return rounding mode specified for this call.
2183+
/// Return the effective rounding mode for this call.
21782184
RoundingMode getRoundingMode() const;
21792185

2180-
/// Return exception behavior specified for this call.
2186+
/// Return the effective exception behavior for this call.
21812187
fp::ExceptionBehavior getExceptionBehavior() const;
21822188

21832189
/// Used to keep track of an operand bundle. See the main comment on

llvm/include/llvm/IR/LLVMContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class LLVMContext {
9797
OB_ptrauth = 7, // "ptrauth"
9898
OB_kcfi = 8, // "kcfi"
9999
OB_convergencectrl = 9, // "convergencectrl"
100-
OB_fp_control = 10, // "fp.control"
100+
OB_fp_round = 10, // "fp.round"
101101
OB_fp_except = 11, // "fp.except"
102102
};
103103

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6816,9 +6816,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
68166816
case Intrinsic::exp10:
68176817
case Intrinsic::floor:
68186818
case Intrinsic::ceil:
6819-
case Intrinsic::trunc:
68206819
case Intrinsic::rint:
6821-
case Intrinsic::nearbyint:
68226820
case Intrinsic::round:
68236821
case Intrinsic::roundeven:
68246822
case Intrinsic::canonicalize: {
@@ -6840,9 +6838,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
68406838
case Intrinsic::exp10: Opcode = ISD::FEXP10; break;
68416839
case Intrinsic::floor: Opcode = ISD::FFLOOR; break;
68426840
case Intrinsic::ceil: Opcode = ISD::FCEIL; break;
6843-
case Intrinsic::trunc: Opcode = ISD::FTRUNC; break;
68446841
case Intrinsic::rint: Opcode = ISD::FRINT; break;
6845-
case Intrinsic::nearbyint: Opcode = ISD::FNEARBYINT; break;
68466842
case Intrinsic::round: Opcode = ISD::FROUND; break;
68476843
case Intrinsic::roundeven: Opcode = ISD::FROUNDEVEN; break;
68486844
case Intrinsic::canonicalize: Opcode = ISD::FCANONICALIZE; break;
@@ -6977,6 +6973,11 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
69776973
#include "llvm/IR/VPIntrinsics.def"
69786974
visitVectorPredicationIntrinsic(cast<VPIntrinsic>(I));
69796975
return;
6976+
#define FUNCTION(NAME, DAGN) \
6977+
case Intrinsic::NAME: \
6978+
visitFPOperation(I, ISD::DAGN); \
6979+
break;
6980+
#include "llvm/IR/FloatingPointOps.def"
69806981
case Intrinsic::fptrunc_round: {
69816982
// Get the last argument, the metadata and convert it to an integer in the
69826983
// call
@@ -8273,6 +8274,33 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
82738274
}
82748275
}
82758276

8277+
void SelectionDAGBuilder::pushOutChain(SDValue Result,
8278+
fp::ExceptionBehavior EB) {
8279+
assert(Result.getNode()->getNumValues() == 2);
8280+
8281+
// Push node to the appropriate list so that future instructions can be
8282+
// chained up correctly.
8283+
SDValue OutChain = Result.getValue(1);
8284+
switch (EB) {
8285+
case fp::ExceptionBehavior::ebIgnore:
8286+
// The only reason why ebIgnore nodes still need to be chained is that
8287+
// they might depend on the current rounding mode, and therefore must
8288+
// not be moved across instruction that may change that mode.
8289+
[[fallthrough]];
8290+
case fp::ExceptionBehavior::ebMayTrap:
8291+
// These must not be moved across calls or instructions that may change
8292+
// floating-point exception masks.
8293+
PendingConstrainedFP.push_back(OutChain);
8294+
break;
8295+
case fp::ExceptionBehavior::ebStrict:
8296+
// These must not be moved across calls or instructions that may change
8297+
// floating-point exception masks or read floating-point exception flags.
8298+
// In addition, they cannot be optimized out even if unused.
8299+
PendingConstrainedFPStrict.push_back(OutChain);
8300+
break;
8301+
}
8302+
}
8303+
82768304
void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
82778305
const ConstrainedFPIntrinsic &FPI) {
82788306
SDLoc sdl = getCurSDLoc();
@@ -8286,32 +8314,6 @@ void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
82868314
for (unsigned I = 0, E = FPI.getNonMetadataArgCount(); I != E; ++I)
82878315
Opers.push_back(getValue(FPI.getArgOperand(I)));
82888316

8289-
auto pushOutChain = [this](SDValue Result, fp::ExceptionBehavior EB) {
8290-
assert(Result.getNode()->getNumValues() == 2);
8291-
8292-
// Push node to the appropriate list so that future instructions can be
8293-
// chained up correctly.
8294-
SDValue OutChain = Result.getValue(1);
8295-
switch (EB) {
8296-
case fp::ExceptionBehavior::ebIgnore:
8297-
// The only reason why ebIgnore nodes still need to be chained is that
8298-
// they might depend on the current rounding mode, and therefore must
8299-
// not be moved across instruction that may change that mode.
8300-
[[fallthrough]];
8301-
case fp::ExceptionBehavior::ebMayTrap:
8302-
// These must not be moved across calls or instructions that may change
8303-
// floating-point exception masks.
8304-
PendingConstrainedFP.push_back(OutChain);
8305-
break;
8306-
case fp::ExceptionBehavior::ebStrict:
8307-
// These must not be moved across calls or instructions that may change
8308-
// floating-point exception masks or read floating-point exception flags.
8309-
// In addition, they cannot be optimized out even if unused.
8310-
PendingConstrainedFPStrict.push_back(OutChain);
8311-
break;
8312-
}
8313-
};
8314-
83158317
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
83168318
EVT VT = TLI.getValueType(DAG.getDataLayout(), FPI.getType());
83178319
SDVTList VTs = DAG.getVTList(VT, MVT::Other);
@@ -9355,6 +9357,56 @@ bool SelectionDAGBuilder::visitBinaryFloatCall(const CallInst &I,
93559357
return true;
93569358
}
93579359

9360+
bool SelectionDAGBuilder::visitFPOperation(const CallInst &I, unsigned Opcode) {
9361+
// We already checked this call's prototype; verify it doesn't modify errno.
9362+
MemoryEffects ME = I.getMemoryEffects();
9363+
if (!ME.onlyAccessesInaccessibleMem())
9364+
return false;
9365+
9366+
SmallVector<SDValue, 4> Operands;
9367+
bool HasChain = ME.doesAccessInaccessibleMem();
9368+
if (HasChain)
9369+
Operands.push_back(getRoot());
9370+
for (auto &Arg : I.args())
9371+
Operands.push_back(getValue(Arg));
9372+
9373+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
9374+
EVT VT = TLI.getValueType(DAG.getDataLayout(), I.getType(), true);
9375+
SDVTList NodeVT;
9376+
if (HasChain)
9377+
NodeVT = DAG.getVTList(VT, MVT::Other);
9378+
else
9379+
NodeVT = DAG.getVTList(VT);
9380+
9381+
SDNodeFlags Flags;
9382+
fp::ExceptionBehavior EB = I.getExceptionBehavior();
9383+
if (EB == fp::ExceptionBehavior::ebIgnore)
9384+
Flags.setNoFPExcept(true);
9385+
if (auto *FPOp = dyn_cast<FPMathOperator>(&I))
9386+
Flags.copyFMF(*FPOp);
9387+
9388+
// Temporary solution: use STRICT_* nodes.
9389+
if (HasChain)
9390+
switch (Opcode) {
9391+
default:
9392+
break;
9393+
#define LEGACY_DAG(NAME, DAGN) \
9394+
case ISD::DAGN: \
9395+
Opcode = ISD::STRICT_##DAGN; \
9396+
break;
9397+
#include "llvm/IR/FloatingPointOps.def"
9398+
}
9399+
9400+
SDLoc sdl = getCurSDLoc();
9401+
SDValue Result = DAG.getNode(Opcode, sdl, NodeVT, Operands, Flags);
9402+
if (HasChain)
9403+
pushOutChain(Result, EB);
9404+
9405+
SDValue FPResult = Result.getValue(0);
9406+
setValue(&I, FPResult);
9407+
return true;
9408+
}
9409+
93589410
void SelectionDAGBuilder::visitCall(const CallInst &I) {
93599411
// Handle inline assembly differently.
93609412
if (I.isInlineAsm()) {

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ class SelectionDAGBuilder {
367367
/// Evict any dangling debug information, attempting to salvage it first.
368368
void resolveOrClearDbgInfo();
369369

370+
void pushOutChain(SDValue Result, fp::ExceptionBehavior EB);
371+
370372
SDValue getValue(const Value *V);
371373

372374
SDValue getNonRegisterValue(const Value *V);
@@ -611,6 +613,7 @@ class SelectionDAGBuilder {
611613
bool visitStrNLenCall(const CallInst &I);
612614
bool visitUnaryFloatCall(const CallInst &I, unsigned Opcode);
613615
bool visitBinaryFloatCall(const CallInst &I, unsigned Opcode);
616+
bool visitFPOperation(const CallInst &I, unsigned Opcode);
614617
void visitAtomicLoad(const LoadInst &I);
615618
void visitAtomicStore(const StoreInst &I);
616619
void visitLoadFromSwiftError(const LoadInst &I);

0 commit comments

Comments
 (0)