Skip to content

Commit

Permalink
[LLVM] Add the support for fmax and fmin in atomicrmw instruction
Browse files Browse the repository at this point in the history
This patch adds the support for `fmax` and `fmin` operations in `atomicrmw`
instruction. For now (at least in this patch), the instruction will be expanded
to CAS loop. There are already a couple of targets supporting the feature. I'll
create another patch(es) to enable them accordingly.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D127041
  • Loading branch information
shiltian committed Jul 6, 2022
1 parent f8e0264 commit 1023dda
Show file tree
Hide file tree
Showing 36 changed files with 230 additions and 9 deletions.
5 changes: 4 additions & 1 deletion llvm/docs/GlobalISel/GenericOpcode.rst
Expand Up @@ -727,7 +727,10 @@ G_ATOMIC_CMPXCHG
Generic atomic cmpxchg. Expects a MachineMemOperand in addition to explicit
operands.

G_ATOMICRMW_XCHG, G_ATOMICRMW_ADD, G_ATOMICRMW_SUB, G_ATOMICRMW_AND, G_ATOMICRMW_NAND, G_ATOMICRMW_OR, G_ATOMICRMW_XOR, G_ATOMICRMW_MAX, G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN, G_ATOMICRMW_FADD, G_ATOMICRMW_FSUB
G_ATOMICRMW_XCHG, G_ATOMICRMW_ADD, G_ATOMICRMW_SUB, G_ATOMICRMW_AND,
G_ATOMICRMW_NAND, G_ATOMICRMW_OR, G_ATOMICRMW_XOR, G_ATOMICRMW_MAX,
G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN, G_ATOMICRMW_FADD,
G_ATOMICRMW_FSUB, G_ATOMICRMW_FMAX, G_ATOMICRMW_FMIN
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Generic atomicrmw. Expects a MachineMemOperand in addition to explicit
Expand Down
6 changes: 5 additions & 1 deletion llvm/docs/LangRef.rst
Expand Up @@ -10330,12 +10330,14 @@ operation. The operation must be one of the following keywords:
- umin
- fadd
- fsub
- fmax
- fmin

For most of these operations, the type of '<value>' must be an integer
type whose bit width is a power of two greater than or equal to eight
and less than or equal to a target-specific size limit. For xchg, this
may also be a floating point or a pointer type with the same size constraints
as integers. For fadd/fsub, this must be a floating point type. The
as integers. For fadd/fsub/fmax/fmin, this must be a floating point type. The
type of the '``<pointer>``' operand must be a pointer to that type. If
the ``atomicrmw`` is marked as ``volatile``, then the optimizer is not
allowed to modify the number or order of execution of this
Expand Down Expand Up @@ -10372,6 +10374,8 @@ operation argument:
- umin: ``*ptr = *ptr < val ? *ptr : val`` (using an unsigned comparison)
- fadd: ``*ptr = *ptr + val`` (using floating point arithmetic)
- fsub: ``*ptr = *ptr - val`` (using floating point arithmetic)
- fmax: ``*ptr = maxnum(*ptr, val)`` (match the `llvm.maxnum.*`` intrinsic)
- fmin: ``*ptr = minnum(*ptr, val)`` (match the `llvm.minnum.*`` intrinsic)

Example:
""""""""
Expand Down
3 changes: 3 additions & 0 deletions llvm/docs/ReleaseNotes.rst
Expand Up @@ -76,6 +76,9 @@ Changes to the LLVM IR
* ``sdiv``
* ``urem``
* ``srem``
* Added the support for ``fmax`` and ``fmin`` in ``atomicrmw`` instruction. The
comparison is expected to match the behavior of ``llvm.maxnum.*`` and
``llvm.minnum.*`` respectively.

Changes to building LLVM
------------------------
Expand Down
10 changes: 8 additions & 2 deletions llvm/include/llvm-c/Core.h
Expand Up @@ -381,8 +381,14 @@ typedef enum {
the old one */
LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the
old one */
LLVMAtomicRMWBinOpFSub /**< Subtract a floating point value and return the
old one */
LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the
old one */
LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the
original using an floating point comparison and
return the old one */
} LLVMAtomicRMWBinOp;

typedef enum {
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/AsmParser/LLToken.h
Expand Up @@ -221,6 +221,8 @@ enum Kind {
kw_min,
kw_umax,
kw_umin,
kw_fmax,
kw_fmin,

// Instruction Opcodes (Opcode in UIntVal).
kw_fneg,
Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/Bitcode/LLVMBitCodes.h
Expand Up @@ -458,7 +458,9 @@ enum RMWOperations {
RMW_UMAX = 9,
RMW_UMIN = 10,
RMW_FADD = 11,
RMW_FSUB = 12
RMW_FSUB = 12,
RMW_FMAX = 13,
RMW_FMIN = 14
};

/// OverflowingBinaryOperatorOptionalFlags - Flags for serializing
Expand Down
34 changes: 34 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
Expand Up @@ -1401,6 +1401,40 @@ class MachineIRBuilder {
const DstOp &OldValRes, const SrcOp &Addr, const SrcOp &Val,
MachineMemOperand &MMO);

/// Build and insert `OldValRes<def> = G_ATOMICRMW_FMAX Addr, Val, MMO`.
///
/// Atomically replace the value at \p Addr with the floating point maximum of
/// \p Val and the original value. Puts the original value from \p Addr in \p
/// OldValRes.
///
/// \pre setBasicBlock or setMI must have been called.
/// \pre \p OldValRes must be a generic virtual register.
/// \pre \p Addr must be a generic virtual register with pointer type.
/// \pre \p OldValRes, and \p Val must be generic virtual registers of the
/// same type.
///
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildAtomicRMWFMax(
const DstOp &OldValRes, const SrcOp &Addr, const SrcOp &Val,
MachineMemOperand &MMO);

/// Build and insert `OldValRes<def> = G_ATOMICRMW_FMIN Addr, Val, MMO`.
///
/// Atomically replace the value at \p Addr with the floating point minimum of
/// \p Val and the original value. Puts the original value from \p Addr in \p
/// OldValRes.
///
/// \pre setBasicBlock or setMI must have been called.
/// \pre \p OldValRes must be a generic virtual register.
/// \pre \p Addr must be a generic virtual register with pointer type.
/// \pre \p OldValRes, and \p Val must be generic virtual registers of the
/// same type.
///
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildAtomicRMWFMin(
const DstOp &OldValRes, const SrcOp &Addr, const SrcOp &Val,
MachineMemOperand &MMO);

/// Build and insert `G_FENCE Ordering, Scope`.
MachineInstrBuilder buildFence(unsigned Ordering, unsigned Scope);

Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/ISDOpcodes.h
Expand Up @@ -1195,6 +1195,8 @@ enum NodeType {
ATOMIC_LOAD_UMAX,
ATOMIC_LOAD_FADD,
ATOMIC_LOAD_FSUB,
ATOMIC_LOAD_FMAX,
ATOMIC_LOAD_FMIN,

// Masked load and store - consecutive vector load and store operations
// with additional mask operand that prevents memory accesses to the
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/SelectionDAGNodes.h
Expand Up @@ -1403,6 +1403,8 @@ class MemSDNode : public SDNode {
case ISD::ATOMIC_LOAD_UMAX:
case ISD::ATOMIC_LOAD_FADD:
case ISD::ATOMIC_LOAD_FSUB:
case ISD::ATOMIC_LOAD_FMAX:
case ISD::ATOMIC_LOAD_FMIN:
case ISD::ATOMIC_LOAD:
case ISD::ATOMIC_STORE:
case ISD::MLOAD:
Expand Down Expand Up @@ -1468,6 +1470,8 @@ class AtomicSDNode : public MemSDNode {
N->getOpcode() == ISD::ATOMIC_LOAD_UMAX ||
N->getOpcode() == ISD::ATOMIC_LOAD_FADD ||
N->getOpcode() == ISD::ATOMIC_LOAD_FSUB ||
N->getOpcode() == ISD::ATOMIC_LOAD_FMAX ||
N->getOpcode() == ISD::ATOMIC_LOAD_FMIN ||
N->getOpcode() == ISD::ATOMIC_LOAD ||
N->getOpcode() == ISD::ATOMIC_STORE;
}
Expand Down
12 changes: 11 additions & 1 deletion llvm/include/llvm/IR/Instructions.h
Expand Up @@ -753,8 +753,16 @@ class AtomicRMWInst : public Instruction {
/// *p = old - v
FSub,

/// *p = maxnum(old, v)
/// \p maxnum matches the behavior of \p llvm.maxnum.*.
FMax,

/// *p = minnum(old, v)
/// \p minnum matches the behavior of \p llvm.minnum.*.
FMin,

FIRST_BINOP = Xchg,
LAST_BINOP = FSub,
LAST_BINOP = FMin,
BAD_BINOP
};

Expand Down Expand Up @@ -797,6 +805,8 @@ class AtomicRMWInst : public Instruction {
switch (Op) {
case AtomicRMWInst::FAdd:
case AtomicRMWInst::FSub:
case AtomicRMWInst::FMax:
case AtomicRMWInst::FMin:
return true;
default:
return false;
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Support/TargetOpcodes.def
Expand Up @@ -384,6 +384,8 @@ HANDLE_TARGET_OPCODE(G_ATOMICRMW_UMAX)
HANDLE_TARGET_OPCODE(G_ATOMICRMW_UMIN)
HANDLE_TARGET_OPCODE(G_ATOMICRMW_FADD)
HANDLE_TARGET_OPCODE(G_ATOMICRMW_FSUB)
HANDLE_TARGET_OPCODE(G_ATOMICRMW_FMAX)
HANDLE_TARGET_OPCODE(G_ATOMICRMW_FMIN)

// Generic atomic fence
HANDLE_TARGET_OPCODE(G_FENCE)
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Target/GenericOpcodes.td
Expand Up @@ -1126,6 +1126,8 @@ def G_ATOMICRMW_UMAX : G_ATOMICRMW_OP;
def G_ATOMICRMW_UMIN : G_ATOMICRMW_OP;
def G_ATOMICRMW_FADD : G_ATOMICRMW_OP;
def G_ATOMICRMW_FSUB : G_ATOMICRMW_OP;
def G_ATOMICRMW_FMAX : G_ATOMICRMW_OP;
def G_ATOMICRMW_FMIN : G_ATOMICRMW_OP;

def G_FENCE : GenericInstruction {
let OutOperandList = (outs);
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
Expand Up @@ -206,6 +206,8 @@ def : GINodeEquiv<G_ATOMICRMW_UMIN, atomic_load_umin>;
def : GINodeEquiv<G_ATOMICRMW_UMAX, atomic_load_umax>;
def : GINodeEquiv<G_ATOMICRMW_FADD, atomic_load_fadd>;
def : GINodeEquiv<G_ATOMICRMW_FSUB, atomic_load_fsub>;
def : GINodeEquiv<G_ATOMICRMW_FMAX, atomic_load_fmax>;
def : GINodeEquiv<G_ATOMICRMW_FMIN, atomic_load_fmin>;
def : GINodeEquiv<G_FENCE, atomic_fence>;

// Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern.
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/Target/TargetSelectionDAG.td
Expand Up @@ -651,6 +651,10 @@ def atomic_load_fadd : SDNode<"ISD::ATOMIC_LOAD_FADD" , SDTFPAtomic2,
[SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>;
def atomic_load_fsub : SDNode<"ISD::ATOMIC_LOAD_FSUB" , SDTFPAtomic2,
[SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>;
def atomic_load_fmax : SDNode<"ISD::ATOMIC_LOAD_FMAX", SDTFPAtomic2,
[SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>;
def atomic_load_fmin : SDNode<"ISD::ATOMIC_LOAD_FMIN", SDTFPAtomic2,
[SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>;

def atomic_load : SDNode<"ISD::ATOMIC_LOAD", SDTAtomicLoad,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/AsmParser/LLLexer.cpp
Expand Up @@ -661,7 +661,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(oge); KEYWORD(ord); KEYWORD(uno); KEYWORD(ueq); KEYWORD(une);

KEYWORD(xchg); KEYWORD(nand); KEYWORD(max); KEYWORD(min); KEYWORD(umax);
KEYWORD(umin);
KEYWORD(umin); KEYWORD(fmax); KEYWORD(fmin);

KEYWORD(vscale);
KEYWORD(x);
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Expand Up @@ -7463,6 +7463,14 @@ int LLParser::parseAtomicRMW(Instruction *&Inst, PerFunctionState &PFS) {
Operation = AtomicRMWInst::FSub;
IsFP = true;
break;
case lltok::kw_fmax:
Operation = AtomicRMWInst::FMax;
IsFP = true;
break;
case lltok::kw_fmin:
Operation = AtomicRMWInst::FMin;
IsFP = true;
break;
}
Lex.Lex(); // Eat the operation.

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Expand Up @@ -1243,6 +1243,8 @@ static AtomicRMWInst::BinOp getDecodedRMWOperation(unsigned Val) {
case bitc::RMW_UMIN: return AtomicRMWInst::UMin;
case bitc::RMW_FADD: return AtomicRMWInst::FAdd;
case bitc::RMW_FSUB: return AtomicRMWInst::FSub;
case bitc::RMW_FMAX: return AtomicRMWInst::FMax;
case bitc::RMW_FMIN: return AtomicRMWInst::FMin;
}
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Expand Up @@ -577,6 +577,8 @@ static unsigned getEncodedRMWOperation(AtomicRMWInst::BinOp Op) {
case AtomicRMWInst::UMin: return bitc::RMW_UMIN;
case AtomicRMWInst::FAdd: return bitc::RMW_FADD;
case AtomicRMWInst::FSub: return bitc::RMW_FSUB;
case AtomicRMWInst::FMax: return bitc::RMW_FMAX;
case AtomicRMWInst::FMin: return bitc::RMW_FMIN;
}
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/AtomicExpandPass.cpp
Expand Up @@ -1646,6 +1646,8 @@ static ArrayRef<RTLIB::Libcall> GetRMWLibcall(AtomicRMWInst::BinOp Op) {
case AtomicRMWInst::Min:
case AtomicRMWInst::UMax:
case AtomicRMWInst::UMin:
case AtomicRMWInst::FMax:
case AtomicRMWInst::FMin:
case AtomicRMWInst::FAdd:
case AtomicRMWInst::FSub:
// No atomic libcalls are available for max/min/umax/umin.
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Expand Up @@ -2883,6 +2883,12 @@ bool IRTranslator::translateAtomicRMW(const User &U,
case AtomicRMWInst::FSub:
Opcode = TargetOpcode::G_ATOMICRMW_FSUB;
break;
case AtomicRMWInst::FMax:
Opcode = TargetOpcode::G_ATOMICRMW_FMAX;
break;
case AtomicRMWInst::FMin:
Opcode = TargetOpcode::G_ATOMICRMW_FMIN;
break;
}

MIRBuilder.buildAtomicRMW(
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
Expand Up @@ -937,6 +937,20 @@ MachineIRBuilder::buildAtomicRMWFSub(const DstOp &OldValRes, const SrcOp &Addr,
MMO);
}

MachineInstrBuilder
MachineIRBuilder::buildAtomicRMWFMax(const DstOp &OldValRes, const SrcOp &Addr,
const SrcOp &Val, MachineMemOperand &MMO) {
return buildAtomicRMW(TargetOpcode::G_ATOMICRMW_FMAX, OldValRes, Addr, Val,
MMO);
}

MachineInstrBuilder
MachineIRBuilder::buildAtomicRMWFMin(const DstOp &OldValRes, const SrcOp &Addr,
const SrcOp &Val, MachineMemOperand &MMO) {
return buildAtomicRMW(TargetOpcode::G_ATOMICRMW_FMIN, OldValRes, Addr, Val,
MMO);
}

MachineInstrBuilder
MachineIRBuilder::buildFence(unsigned Ordering, unsigned Scope) {
return buildInstr(TargetOpcode::G_FENCE)
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Expand Up @@ -7505,6 +7505,8 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT,
Opcode == ISD::ATOMIC_LOAD_UMAX ||
Opcode == ISD::ATOMIC_LOAD_FADD ||
Opcode == ISD::ATOMIC_LOAD_FSUB ||
Opcode == ISD::ATOMIC_LOAD_FMAX ||
Opcode == ISD::ATOMIC_LOAD_FMIN ||
Opcode == ISD::ATOMIC_SWAP ||
Opcode == ISD::ATOMIC_STORE) &&
"Invalid Atomic Op");
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Expand Up @@ -4611,6 +4611,8 @@ void SelectionDAGBuilder::visitAtomicRMW(const AtomicRMWInst &I) {
case AtomicRMWInst::UMin: NT = ISD::ATOMIC_LOAD_UMIN; break;
case AtomicRMWInst::FAdd: NT = ISD::ATOMIC_LOAD_FADD; break;
case AtomicRMWInst::FSub: NT = ISD::ATOMIC_LOAD_FSUB; break;
case AtomicRMWInst::FMax: NT = ISD::ATOMIC_LOAD_FMAX; break;
case AtomicRMWInst::FMin: NT = ISD::ATOMIC_LOAD_FMIN; break;
}
AtomicOrdering Ordering = I.getOrdering();
SyncScope::ID SSID = I.getSyncScopeID();
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
Expand Up @@ -3962,6 +3962,8 @@ Value *OpenMPIRBuilder::emitRMWOpAsInstruction(Value *Src1, Value *Src2,
case AtomicRMWInst::Min:
case AtomicRMWInst::UMax:
case AtomicRMWInst::UMin:
case AtomicRMWInst::FMax:
case AtomicRMWInst::FMin:
llvm_unreachable("Unsupported atomic update operation");
}
llvm_unreachable("Unsupported atomic update operation");
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/IR/Core.cpp
Expand Up @@ -3620,6 +3620,8 @@ static AtomicRMWInst::BinOp mapFromLLVMRMWBinOp(LLVMAtomicRMWBinOp BinOp) {
case LLVMAtomicRMWBinOpUMin: return AtomicRMWInst::UMin;
case LLVMAtomicRMWBinOpFAdd: return AtomicRMWInst::FAdd;
case LLVMAtomicRMWBinOpFSub: return AtomicRMWInst::FSub;
case LLVMAtomicRMWBinOpFMax: return AtomicRMWInst::FMax;
case LLVMAtomicRMWBinOpFMin: return AtomicRMWInst::FMin;
}

llvm_unreachable("Invalid LLVMAtomicRMWBinOp value!");
Expand All @@ -3640,6 +3642,8 @@ static LLVMAtomicRMWBinOp mapToLLVMRMWBinOp(AtomicRMWInst::BinOp BinOp) {
case AtomicRMWInst::UMin: return LLVMAtomicRMWBinOpUMin;
case AtomicRMWInst::FAdd: return LLVMAtomicRMWBinOpFAdd;
case AtomicRMWInst::FSub: return LLVMAtomicRMWBinOpFSub;
case AtomicRMWInst::FMax: return LLVMAtomicRMWBinOpFMax;
case AtomicRMWInst::FMin: return LLVMAtomicRMWBinOpFMin;
default: break;
}

Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/IR/Instructions.cpp
Expand Up @@ -1696,6 +1696,10 @@ StringRef AtomicRMWInst::getOperationName(BinOp Op) {
return "fadd";
case AtomicRMWInst::FSub:
return "fsub";
case AtomicRMWInst::FMax:
return "fmax";
case AtomicRMWInst::FMin:
return "fmin";
case AtomicRMWInst::BAD_BINOP:
return "<invalid operation>";
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
Expand Up @@ -4803,6 +4803,8 @@ AMDGPUTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const {
case AtomicRMWInst::Nand:
case AtomicRMWInst::FAdd:
case AtomicRMWInst::FSub:
case AtomicRMWInst::FMax:
case AtomicRMWInst::FMin:
return AtomicExpansionKind::CmpXChg;
default:
return AtomicExpansionKind::None;
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
Expand Up @@ -595,6 +595,10 @@ unsigned DXILBitcodeWriter::getEncodedRMWOperation(AtomicRMWInst::BinOp Op) {
return bitc::RMW_FADD;
case AtomicRMWInst::FSub:
return bitc::RMW_FSUB;
case AtomicRMWInst::FMax:
return bitc::RMW_FMAX;
case AtomicRMWInst::FMin:
return bitc::RMW_FMIN;
}
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Expand Up @@ -30800,6 +30800,8 @@ X86TargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
case AtomicRMWInst::UMin:
case AtomicRMWInst::FAdd:
case AtomicRMWInst::FSub:
case AtomicRMWInst::FMax:
case AtomicRMWInst::FMin:
// These always require a non-trivial set of data operations on x86. We must
// use a cmpxchg loop.
return AtomicExpansionKind::CmpXChg;
Expand Down

0 comments on commit 1023dda

Please sign in to comment.