Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 50 additions & 28 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8280,6 +8280,54 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
}
}

void SelectionDAGBuilder::pushFPOpOutChain(SDValue Result,
fp::ExceptionBehavior EB) {
assert(Result.getNode()->getNumValues() == 2);
SDValue OutChain = Result.getValue(1);
assert(OutChain.getValueType() == MVT::Other);

// Instead of updating the root immediately, push the produced chain to the
// appropriate list, deferring the update until the root is requested. In this
// case, the nodes from the lists are chained using TokenFactor, indicating
// that the operations are independent.
//
// In particular, the root is updated before any call that might access the
// floating-point environment, except for constrained intrinsics.
switch (EB) {
case fp::ExceptionBehavior::ebMayTrap:
case fp::ExceptionBehavior::ebIgnore:
// Floating-point exceptions produced by such operations are not intended
// to be observed, so the sequence of these operations does not need to be
// preserved.
//
// They however must not be mixed with the instructions that have strict
// exception behavior. Placing an operation with 'ebIgnore' behavior between
// 'ebStrict' operations could distort the observed exception behavior.
if (!PendingConstrainedFPStrict.empty()) {
assert(PendingConstrainedFP.empty());
updateRoot(PendingConstrainedFPStrict);
}
PendingConstrainedFP.push_back(OutChain);
break;
case fp::ExceptionBehavior::ebStrict:
// Floating-point exception produced by these operations may be observed, so
// they must be correctly chained. If trapping on FP exceptions is
// disabled, the exceptions can be observed only by functions that read
// exception flags, like 'llvm.get_fpenv' or 'fetestexcept'. It means that
// the order of operations is not significant between barriers.
//
// If trapping is enabled, each operation becomes an implicit observation
// point, so the operations must be sequenced according their original
// source order.
if (!PendingConstrainedFP.empty()) {
assert(PendingConstrainedFPStrict.empty());
updateRoot(PendingConstrainedFP);
}
PendingConstrainedFPStrict.push_back(OutChain);
// TODO: Add support for trapping-enabled scenarios.
}
}

void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
const ConstrainedFPIntrinsic &FPI) {
SDLoc sdl = getCurSDLoc();
Expand All @@ -8293,32 +8341,6 @@ void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
for (unsigned I = 0, E = FPI.getNonMetadataArgCount(); I != E; ++I)
Opers.push_back(getValue(FPI.getArgOperand(I)));

auto pushOutChain = [this](SDValue Result, fp::ExceptionBehavior EB) {
assert(Result.getNode()->getNumValues() == 2);

// Push node to the appropriate list so that future instructions can be
// chained up correctly.
SDValue OutChain = Result.getValue(1);
switch (EB) {
case fp::ExceptionBehavior::ebIgnore:
// The only reason why ebIgnore nodes still need to be chained is that
// they might depend on the current rounding mode, and therefore must
// not be moved across instruction that may change that mode.
[[fallthrough]];
case fp::ExceptionBehavior::ebMayTrap:
// These must not be moved across calls or instructions that may change
// floating-point exception masks.
PendingConstrainedFP.push_back(OutChain);
break;
case fp::ExceptionBehavior::ebStrict:
// These must not be moved across calls or instructions that may change
// floating-point exception masks or read floating-point exception flags.
// In addition, they cannot be optimized out even if unused.
PendingConstrainedFPStrict.push_back(OutChain);
break;
}
};

const TargetLowering &TLI = DAG.getTargetLoweringInfo();
EVT VT = TLI.getValueType(DAG.getDataLayout(), FPI.getType());
SDVTList VTs = DAG.getVTList(VT, MVT::Other);
Expand Down Expand Up @@ -8346,7 +8368,7 @@ void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
!TLI.isFMAFasterThanFMulAndFAdd(DAG.getMachineFunction(), VT)) {
Opers.pop_back();
SDValue Mul = DAG.getNode(ISD::STRICT_FMUL, sdl, VTs, Opers, Flags);
pushOutChain(Mul, EB);
pushFPOpOutChain(Mul, EB);
Opcode = ISD::STRICT_FADD;
Opers.clear();
Opers.push_back(Mul.getValue(1));
Expand Down Expand Up @@ -8377,7 +8399,7 @@ void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
}

SDValue Result = DAG.getNode(Opcode, sdl, VTs, Opers, Flags);
pushOutChain(Result, EB);
pushFPOpOutChain(Result, EB);

SDValue FPResult = Result.getValue(0);
setValue(&FPI, FPResult);
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ class SelectionDAGBuilder {
/// Update root to include all chains from the Pending list.
SDValue updateRoot(SmallVectorImpl<SDValue> &Pending);

/// Given a node representing a floating-point operation and its specified
/// exception behavior, this either updates the root or stores the node in
/// a list to be added to chains latter.
void pushFPOpOutChain(SDValue Result, fp::ExceptionBehavior EB);

/// A unique monotonically increasing number used to order the SDNodes we
/// create.
unsigned SDNodeOrder;
Expand Down