- min
- umax
- umin
-- fadd
-- fsub
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 type with the same size constraints as
-integers. For fadd/fsub, 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
-``atomicrmw`` with other :ref:`volatile operations <volatile>`.
+integers. 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 ``atomicrmw`` with other :ref:`volatile operations <volatile>`.
A ``atomicrmw`` instruction can also take an optional
":ref:`syncscope <syncscope>`" argument.
comparison)
- 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)
Example:
""""""""
RMW_MAX = 7,
RMW_MIN = 8,
RMW_UMAX = 9,
- RMW_UMIN = 10,
- RMW_FADD = 11,
- RMW_FSUB = 12
+ RMW_UMIN = 10
};
/// OverflowingBinaryOperatorOptionalFlags - Flags for serializing
/// Returns how the IR-level AtomicExpand pass should expand the given
/// AtomicRMW, if at all. Default is to never expand.
- virtual AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const {
- return RMW->isFloatingPointOperation() ?
- AtomicExpansionKind::CmpXChg : AtomicExpansionKind::None;
+ virtual AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *) const {
+ return AtomicExpansionKind::None;
}
/// On some platforms, an AtomicRMW that never actually modifies the value
/// *p = old <unsigned v ? old : v
UMin,
- /// *p = old + v
- FAdd,
-
- /// *p = old - v
- FSub,
-
FIRST_BINOP = Xchg,
- LAST_BINOP = FSub,
+ LAST_BINOP = UMin,
BAD_BINOP
};
static StringRef getOperationName(BinOp Op);
- static bool isFPOperation(BinOp Op) {
- switch (Op) {
- case AtomicRMWInst::FAdd:
- case AtomicRMWInst::FSub:
- return true;
- default:
- return false;
- }
- }
-
void setOperation(BinOp Operation) {
unsigned short SubclassData = getSubclassDataFromInstruction();
setInstructionSubclassData((SubclassData & 31) |
return getPointerOperand()->getType()->getPointerAddressSpace();
}
- bool isFloatingPointOperation() const {
- return isFPOperation(getOperation());
- }
-
// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Instruction *I) {
return I->getOpcode() == Instruction::AtomicRMW;
AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
SyncScope::ID SSID = SyncScope::System;
bool isVolatile = false;
- bool IsFP = false;
AtomicRMWInst::BinOp Operation;
if (EatIfPresent(lltok::kw_volatile))
case lltok::kw_min: Operation = AtomicRMWInst::Min; break;
case lltok::kw_umax: Operation = AtomicRMWInst::UMax; break;
case lltok::kw_umin: Operation = AtomicRMWInst::UMin; break;
- case lltok::kw_fadd:
- Operation = AtomicRMWInst::FAdd;
- IsFP = true;
- break;
- case lltok::kw_fsub:
- Operation = AtomicRMWInst::FSub;
- IsFP = true;
- break;
}
Lex.Lex(); // Eat the operation.
if (cast<PointerType>(Ptr->getType())->getElementType() != Val->getType())
return Error(ValLoc, "atomicrmw value and pointer type do not match");
- if (Operation == AtomicRMWInst::Xchg) {
- if (!Val->getType()->isIntegerTy() &&
- !Val->getType()->isFloatingPointTy()) {
- return Error(ValLoc, "atomicrmw " +
- AtomicRMWInst::getOperationName(Operation) +
- " operand must be an integer or floating point type");
- }
- } else if (IsFP) {
- if (!Val->getType()->isFloatingPointTy()) {
- return Error(ValLoc, "atomicrmw " +
- AtomicRMWInst::getOperationName(Operation) +
- " operand must be a floating point type");
- }
- } else {
- if (!Val->getType()->isIntegerTy()) {
- return Error(ValLoc, "atomicrmw " +
- AtomicRMWInst::getOperationName(Operation) +
- " operand must be an integer");
- }
+ if (Operation != AtomicRMWInst::Xchg && !Val->getType()->isIntegerTy()) {
+ return Error(ValLoc, "atomicrmw " +
+ AtomicRMWInst::getOperationName(Operation) +
+ " operand must be an integer");
+ }
+
+ if (Operation == AtomicRMWInst::Xchg &&
+ !Val->getType()->isIntegerTy() &&
+ !Val->getType()->isFloatingPointTy()) {
+ return Error(ValLoc, "atomicrmw " +
+ AtomicRMWInst::getOperationName(Operation) +
+ " operand must be an integer or floating point type");
}
unsigned Size = Val->getType()->getPrimitiveSizeInBits();
case bitc::RMW_MIN: return AtomicRMWInst::Min;
case bitc::RMW_UMAX: return AtomicRMWInst::UMax;
case bitc::RMW_UMIN: return AtomicRMWInst::UMin;
- case bitc::RMW_FADD: return AtomicRMWInst::FAdd;
- case bitc::RMW_FSUB: return AtomicRMWInst::FSub;
}
}
case AtomicRMWInst::Min: return bitc::RMW_MIN;
case AtomicRMWInst::UMax: return bitc::RMW_UMAX;
case AtomicRMWInst::UMin: return bitc::RMW_UMIN;
- case AtomicRMWInst::FAdd: return bitc::RMW_FADD;
- case AtomicRMWInst::FSub: return bitc::RMW_FSUB;
}
}
case AtomicRMWInst::UMin:
NewVal = Builder.CreateICmpULE(Loaded, Inc);
return Builder.CreateSelect(NewVal, Loaded, Inc, "new");
- case AtomicRMWInst::FAdd:
- return Builder.CreateFAdd(Loaded, Inc, "new");
- case AtomicRMWInst::FSub:
- return Builder.CreateFSub(Loaded, Inc, "new");
default:
llvm_unreachable("Unknown atomic op");
}
case AtomicRMWInst::Min:
case AtomicRMWInst::UMax:
case AtomicRMWInst::UMin:
- case AtomicRMWInst::FAdd:
- case AtomicRMWInst::FSub:
// No atomic libcalls are available for max/min/umax/umin.
return {};
}
return "umax";
case AtomicRMWInst::UMin:
return "umin";
- case AtomicRMWInst::FAdd:
- return "fadd";
- case AtomicRMWInst::FSub:
- return "fsub";
case AtomicRMWInst::BAD_BINOP:
return "<invalid operation>";
}
AtomicRMWInst::getOperationName(Op) +
" operand must have integer or floating point type!",
&RMWI, ElTy);
- } else if (AtomicRMWInst::isFPOperation(Op)) {
- Assert(ElTy->isFloatingPointTy(), "atomicrmw " +
- AtomicRMWInst::getOperationName(Op) +
- " operand must have floating point type!",
- &RMWI, ElTy);
} else {
Assert(ElTy->isIntegerTy(), "atomicrmw " +
AtomicRMWInst::getOperationName(Op) +
// For the real atomic operations, we have ldxr/stxr up to 128 bits,
TargetLowering::AtomicExpansionKind
AArch64TargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
- if (AI->isFloatingPointOperation())
- return AtomicExpansionKind::CmpXChg;
-
unsigned Size = AI->getType()->getPrimitiveSizeInBits();
if (Size > 128) return AtomicExpansionKind::None;
// Nand not supported in LSE.
// and up to 64 bits on the non-M profiles
TargetLowering::AtomicExpansionKind
ARMTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
- if (AI->isFloatingPointOperation())
- return AtomicExpansionKind::CmpXChg;
-
unsigned Size = AI->getType()->getPrimitiveSizeInBits();
bool hasAtomicRMW = !Subtarget->isThumb() || Subtarget->hasV8MBaselineOps();
return (Size <= (Subtarget->isMClass() ? 32U : 64U) && hasAtomicRMW)
AtomicOrdering Ord) const {
BasicBlock *BB = Builder.GetInsertBlock();
Module *M = BB->getParent()->getParent();
- auto PT = cast<PointerType>(Addr->getType());
- Type *Ty = PT->getElementType();
+ Type *Ty = cast<PointerType>(Addr->getType())->getElementType();
unsigned SZ = Ty->getPrimitiveSizeInBits();
assert((SZ == 32 || SZ == 64) && "Only 32/64-bit atomic loads supported");
Intrinsic::ID IntID = (SZ == 32) ? Intrinsic::hexagon_L2_loadw_locked
: Intrinsic::hexagon_L4_loadd_locked;
-
- PointerType *NewPtrTy
- = Builder.getIntNTy(SZ)->getPointerTo(PT->getAddressSpace());
- Addr = Builder.CreateBitCast(Addr, NewPtrTy);
-
Value *Fn = Intrinsic::getDeclaration(M, IntID);
- Value *Call = Builder.CreateCall(Fn, Addr, "larx");
-
- return Builder.CreateBitCast(Call, Ty);
+ return Builder.CreateCall(Fn, Addr, "larx");
}
/// Perform a store-conditional operation to Addr. Return the status of the
Module *M = BB->getParent()->getParent();
Type *Ty = Val->getType();
unsigned SZ = Ty->getPrimitiveSizeInBits();
-
- Type *CastTy = Builder.getIntNTy(SZ);
assert((SZ == 32 || SZ == 64) && "Only 32/64-bit atomic stores supported");
Intrinsic::ID IntID = (SZ == 32) ? Intrinsic::hexagon_S2_storew_locked
: Intrinsic::hexagon_S4_stored_locked;
Value *Fn = Intrinsic::getDeclaration(M, IntID);
-
- unsigned AS = Addr->getType()->getPointerAddressSpace();
- Addr = Builder.CreateBitCast(Addr, CastTy->getPointerTo(AS));
- Val = Builder.CreateBitCast(Val, CastTy);
-
Value *Call = Builder.CreateCall(Fn, {Addr, Val}, "stcx");
Value *Cmp = Builder.CreateICmpEQ(Call, Builder.getInt32(0), "");
Value *Ext = Builder.CreateZExt(Cmp, Type::getInt32Ty(M->getContext()));
TargetLowering::AtomicExpansionKind
RISCVTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
- // atomicrmw {fadd,fsub} must be expanded to use compare-exchange, as
- // floating point operations can't be used in an lr/sc sequence without
- // brekaing the forward-progress guarantee.
- if (AI->isFloatingPointOperation())
- return AtomicExpansionKind::CmpXChg;
-
unsigned Size = AI->getType()->getPrimitiveSizeInBits();
if (Size == 8 || Size == 16)
return AtomicExpansionKind::MaskedIntrinsic;
fence syncscope("device") seq_cst
ret void
}
-
-define void @fp_atomics(float* %x) {
- ; CHECK: atomicrmw fadd float* %x, float 1.000000e+00 seq_cst
- atomicrmw fadd float* %x, float 1.0 seq_cst
-
- ; CHECK: atomicrmw volatile fadd float* %x, float 1.000000e+00 seq_cst
- atomicrmw volatile fadd float* %x, float 1.0 seq_cst
-
- ret void
-}
+++ /dev/null
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: error: atomicrmw fadd operand must be a floating point type
-define void @f(i32* %ptr) {
- atomicrmw fadd i32* %ptr, i32 2 seq_cst
- ret void
-}
+++ /dev/null
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: error: atomicrmw fsub operand must be a floating point type
-define void @f(i32* %ptr) {
- atomicrmw fsub i32* %ptr, i32 2 seq_cst
- ret void
-}
define void @fp_atomics(float* %word) {
; CHECK: %atomicrmw.xchg = atomicrmw xchg float* %word, float 1.000000e+00 monotonic
%atomicrmw.xchg = atomicrmw xchg float* %word, float 1.0 monotonic
-
-; CHECK: %atomicrmw.fadd = atomicrmw fadd float* %word, float 1.000000e+00 monotonic
- %atomicrmw.fadd = atomicrmw fadd float* %word, float 1.0 monotonic
-
-; CHECK: %atomicrmw.fsub = atomicrmw fsub float* %word, float 1.000000e+00 monotonic
- %atomicrmw.fsub = atomicrmw fsub float* %word, float 1.0 monotonic
-
ret void
}
+++ /dev/null
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -mtriple=aarch64-linux-gnu -atomic-expand %s | FileCheck %s
-
-define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fadd_f32(
-; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
-; CHECK-NEXT: [[NEW:%.*]] = fadd float [[LOADED]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
-; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] seq_cst seq_cst
-; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
-; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
-; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
-; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: ret float [[TMP6]]
-;
- %res = atomicrmw fadd float* %ptr, float %value seq_cst
- ret float %res
-}
-
-define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fsub_f32(
-; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
-; CHECK-NEXT: [[NEW:%.*]] = fsub float [[LOADED]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
-; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] seq_cst seq_cst
-; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
-; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
-; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
-; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: ret float [[TMP6]]
-;
- %res = atomicrmw fsub float* %ptr, float %value seq_cst
- ret float %res
-}
-
+++ /dev/null
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -mtriple=armv7-apple-ios7.0 -atomic-expand %s | FileCheck %s
-
-define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fadd_f32(
-; CHECK-NEXT: call void @llvm.arm.dmb(i32 11)
-; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
-; CHECK-NEXT: [[NEW:%.*]] = fadd float [[LOADED]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
-; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] monotonic monotonic
-; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
-; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
-; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
-; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: call void @llvm.arm.dmb(i32 11)
-; CHECK-NEXT: ret float [[TMP6]]
-;
- %res = atomicrmw fadd float* %ptr, float %value seq_cst
- ret float %res
-}
-
-define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fsub_f32(
-; CHECK-NEXT: call void @llvm.arm.dmb(i32 11)
-; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
-; CHECK-NEXT: [[NEW:%.*]] = fsub float [[LOADED]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
-; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] monotonic monotonic
-; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
-; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
-; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
-; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: call void @llvm.arm.dmb(i32 11)
-; CHECK-NEXT: ret float [[TMP6]]
-;
- %res = atomicrmw fsub float* %ptr, float %value seq_cst
- ret float %res
-}
-
+++ /dev/null
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -mtriple=hexagon-- -atomic-expand %s | FileCheck %s
-
-define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fadd_f32(
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[TMP1:%.*]] = bitcast float* [[PTR:%.*]] to i32*
-; CHECK-NEXT: [[LARX:%.*]] = call i32 @llvm.hexagon.L2.loadw.locked(i32* [[TMP1]])
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[LARX]] to float
-; CHECK-NEXT: [[NEW:%.*]] = fadd float [[TMP2]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[STCX:%.*]] = call i32 @llvm.hexagon.S2.storew.locked(i32* [[TMP3]], i32 [[TMP4]])
-; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[STCX]], 0
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: [[TRYAGAIN:%.*]] = icmp ne i32 [[TMP6]], 0
-; CHECK-NEXT: br i1 [[TRYAGAIN]], label [[ATOMICRMW_START]], label [[ATOMICRMW_END:%.*]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: ret float [[TMP2]]
-;
- %res = atomicrmw fadd float* %ptr, float %value seq_cst
- ret float %res
-}
-
-define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fsub_f32(
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[TMP1:%.*]] = bitcast float* [[PTR:%.*]] to i32*
-; CHECK-NEXT: [[LARX:%.*]] = call i32 @llvm.hexagon.L2.loadw.locked(i32* [[TMP1]])
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[LARX]] to float
-; CHECK-NEXT: [[NEW:%.*]] = fsub float [[TMP2]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[STCX:%.*]] = call i32 @llvm.hexagon.S2.storew.locked(i32* [[TMP3]], i32 [[TMP4]])
-; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[STCX]], 0
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: [[TRYAGAIN:%.*]] = icmp ne i32 [[TMP6]], 0
-; CHECK-NEXT: br i1 [[TRYAGAIN]], label [[ATOMICRMW_START]], label [[ATOMICRMW_END:%.*]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: ret float [[TMP2]]
-;
- %res = atomicrmw fsub float* %ptr, float %value seq_cst
- ret float %res
-}
-
+++ /dev/null
-if not 'Hexagon' in config.root.targets:
- config.unsupported = True
+++ /dev/null
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -mtriple=mips64-mti-linux-gnu -atomic-expand %s | FileCheck %s
-
-define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fadd_f32(
-; CHECK-NEXT: fence seq_cst
-; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
-; CHECK-NEXT: [[NEW:%.*]] = fadd float [[LOADED]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
-; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] monotonic monotonic
-; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
-; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
-; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
-; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: fence seq_cst
-; CHECK-NEXT: ret float [[TMP6]]
-;
- %res = atomicrmw fadd float* %ptr, float %value seq_cst
- ret float %res
-}
-
-define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fsub_f32(
-; CHECK-NEXT: fence seq_cst
-; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
-; CHECK-NEXT: [[NEW:%.*]] = fsub float [[LOADED]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
-; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] monotonic monotonic
-; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
-; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
-; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
-; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: fence seq_cst
-; CHECK-NEXT: ret float [[TMP6]]
-;
- %res = atomicrmw fsub float* %ptr, float %value seq_cst
- ret float %res
-}
-
+++ /dev/null
-if not 'Mips' in config.root.targets:
- config.unsupported = True
+++ /dev/null
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -mtriple=riscv32-- -atomic-expand %s | FileCheck %s
-
-define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fadd_f32(
-; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
-; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
-; CHECK-NEXT: [[NEW:%.*]] = fadd float [[LOADED]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
-; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] seq_cst seq_cst
-; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
-; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
-; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
-; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: ret float [[TMP6]]
-;
- %res = atomicrmw fadd float* %ptr, float %value seq_cst
- ret float %res
-}
-
-define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
-; CHECK-LABEL: @test_atomicrmw_fsub_f32(
-; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
-; CHECK-NEXT: br label [[ATOMIxbCRMW_START:%.*]]
-; CHECK: atomicrmw.start:
-; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
-; CHECK-NEXT: [[NEW:%.*]] = fsub float [[LOADED]], [[VALUE:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
-; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
-; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
-; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] seq_cst seq_cst
-; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
-; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
-; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
-; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
-; CHECK: atomicrmw.end:
-; CHECK-NEXT: ret float [[TMP6]]
-;
- %res = atomicrmw fsub float* %ptr, float %value seq_cst
- ret float %res
-}
-
+++ /dev/null
-config.suffixes = ['.ll']
-
-targets = set(config.root.targets_to_build.split())
-if not 'RISCV' in targets:
- config.unsupported = True