Skip to content

Commit 5cf5876

Browse files
committed
Atomics: support min/max orthogonally
We seem to have been gradually growing support for atomic min/max operations (exposing longstanding IR atomicrmw instructions). But until now there have been gaps in the expected intrinsics. This adds support for the C11-style intrinsics (i.e. taking _Atomic, rather than individually blessed by C11 standard), and the variants that return the new value instead of the original one. That way, people won't be misled by trying one form and it not working, and the front-end is more friendly to people using _Atomic types, as we recommend.
1 parent 9f3fdb0 commit 5cf5876

File tree

9 files changed

+193
-31
lines changed

9 files changed

+193
-31
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,6 +2586,8 @@ the corresponding C11 operations, are:
25862586
* ``__c11_atomic_fetch_and``
25872587
* ``__c11_atomic_fetch_or``
25882588
* ``__c11_atomic_fetch_xor``
2589+
* ``__c11_atomic_fetch_max``
2590+
* ``__c11_atomic_fetch_min``
25892591
25902592
The macros ``__ATOMIC_RELAXED``, ``__ATOMIC_CONSUME``, ``__ATOMIC_ACQUIRE``,
25912593
``__ATOMIC_RELEASE``, ``__ATOMIC_ACQ_REL``, and ``__ATOMIC_SEQ_CST`` are

clang/include/clang/Basic/Builtins.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,8 @@ ATOMIC_BUILTIN(__c11_atomic_fetch_sub, "v.", "t")
718718
ATOMIC_BUILTIN(__c11_atomic_fetch_and, "v.", "t")
719719
ATOMIC_BUILTIN(__c11_atomic_fetch_or, "v.", "t")
720720
ATOMIC_BUILTIN(__c11_atomic_fetch_xor, "v.", "t")
721+
ATOMIC_BUILTIN(__c11_atomic_fetch_max, "v.", "t")
722+
ATOMIC_BUILTIN(__c11_atomic_fetch_min, "v.", "t")
721723
BUILTIN(__c11_atomic_thread_fence, "vi", "n")
722724
BUILTIN(__c11_atomic_signal_fence, "vi", "n")
723725
BUILTIN(__c11_atomic_is_lock_free, "iz", "n")
@@ -742,6 +744,8 @@ ATOMIC_BUILTIN(__atomic_sub_fetch, "v.", "t")
742744
ATOMIC_BUILTIN(__atomic_and_fetch, "v.", "t")
743745
ATOMIC_BUILTIN(__atomic_or_fetch, "v.", "t")
744746
ATOMIC_BUILTIN(__atomic_xor_fetch, "v.", "t")
747+
ATOMIC_BUILTIN(__atomic_max_fetch, "v.", "t")
748+
ATOMIC_BUILTIN(__atomic_min_fetch, "v.", "t")
745749
ATOMIC_BUILTIN(__atomic_nand_fetch, "v.", "t")
746750
BUILTIN(__atomic_test_and_set, "bvD*i", "n")
747751
BUILTIN(__atomic_clear, "vvD*i", "n")

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7430,10 +7430,8 @@ def err_atomic_op_needs_trivial_copy : Error<
74307430
def err_atomic_op_needs_atomic_int_or_ptr : Error<
74317431
"address argument to atomic operation must be a pointer to %select{|atomic }0"
74327432
"integer or pointer (%1 invalid)">;
7433-
def err_atomic_op_needs_int32_or_ptr : Error<
7434-
"address argument to atomic operation must be a pointer to signed or unsigned 32-bit integer">;
7435-
def err_atomic_op_bitwise_needs_atomic_int : Error<
7436-
"address argument to bitwise atomic operation must be a pointer to "
7433+
def err_atomic_op_needs_atomic_int : Error<
7434+
"address argument to atomic operation must be a pointer to "
74377435
"%select{|atomic }0integer (%1 invalid)">;
74387436
def warn_atomic_op_has_invalid_memory_order : Warning<
74397437
"memory order argument to atomic operation is invalid">,

clang/lib/AST/Expr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4603,6 +4603,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
46034603
case AO__c11_atomic_fetch_and:
46044604
case AO__c11_atomic_fetch_or:
46054605
case AO__c11_atomic_fetch_xor:
4606+
case AO__c11_atomic_fetch_max:
4607+
case AO__c11_atomic_fetch_min:
46064608
case AO__atomic_fetch_add:
46074609
case AO__atomic_fetch_sub:
46084610
case AO__atomic_fetch_and:
@@ -4615,6 +4617,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
46154617
case AO__atomic_or_fetch:
46164618
case AO__atomic_xor_fetch:
46174619
case AO__atomic_nand_fetch:
4620+
case AO__atomic_min_fetch:
4621+
case AO__atomic_max_fetch:
46184622
case AO__atomic_fetch_min:
46194623
case AO__atomic_fetch_max:
46204624
return 3;

clang/lib/CodeGen/CGAtomic.cpp

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -488,13 +488,36 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
488488
CGF.Builder.SetInsertPoint(ContBB);
489489
}
490490

491+
/// Duplicate the atomic min/max operation in conventional IR for the builtin
492+
/// variants that return the new rather than the original value.
493+
static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder,
494+
AtomicExpr::AtomicOp Op,
495+
bool IsSigned,
496+
llvm::Value *OldVal,
497+
llvm::Value *RHS) {
498+
llvm::CmpInst::Predicate Pred;
499+
switch (Op) {
500+
default:
501+
llvm_unreachable("Unexpected min/max operation");
502+
case AtomicExpr::AO__atomic_max_fetch:
503+
Pred = IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT;
504+
break;
505+
case AtomicExpr::AO__atomic_min_fetch:
506+
Pred = IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT;
507+
break;
508+
}
509+
llvm::Value *Cmp = Builder.CreateICmp(Pred, OldVal, RHS, "tst");
510+
return Builder.CreateSelect(Cmp, OldVal, RHS, "newval");
511+
}
512+
491513
static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
492514
Address Ptr, Address Val1, Address Val2,
493515
llvm::Value *IsWeak, llvm::Value *FailureOrder,
494516
uint64_t Size, llvm::AtomicOrdering Order,
495517
llvm::SyncScope::ID Scope) {
496518
llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
497-
llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
519+
bool PostOpMinMax = false;
520+
unsigned PostOp = 0;
498521

499522
switch (E->getOp()) {
500523
case AtomicExpr::AO__c11_atomic_init:
@@ -588,12 +611,20 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
588611
Op = llvm::AtomicRMWInst::Sub;
589612
break;
590613

614+
case AtomicExpr::AO__atomic_min_fetch:
615+
PostOpMinMax = true;
616+
LLVM_FALLTHROUGH;
617+
case AtomicExpr::AO__c11_atomic_fetch_min:
591618
case AtomicExpr::AO__opencl_atomic_fetch_min:
592619
case AtomicExpr::AO__atomic_fetch_min:
593620
Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Min
594621
: llvm::AtomicRMWInst::UMin;
595622
break;
596623

624+
case AtomicExpr::AO__atomic_max_fetch:
625+
PostOpMinMax = true;
626+
LLVM_FALLTHROUGH;
627+
case AtomicExpr::AO__c11_atomic_fetch_max:
597628
case AtomicExpr::AO__opencl_atomic_fetch_max:
598629
case AtomicExpr::AO__atomic_fetch_max:
599630
Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Max
@@ -643,8 +674,13 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
643674
// For __atomic_*_fetch operations, perform the operation again to
644675
// determine the value which was written.
645676
llvm::Value *Result = RMWI;
646-
if (PostOp)
647-
Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
677+
if (PostOpMinMax)
678+
Result = EmitPostAtomicMinMax(CGF.Builder, E->getOp(),
679+
E->getValueType()->isSignedIntegerType(),
680+
RMWI, LoadVal1);
681+
else if (PostOp)
682+
Result = CGF.Builder.CreateBinOp((llvm::Instruction::BinaryOps)PostOp, RMWI,
683+
LoadVal1);
648684
if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
649685
Result = CGF.Builder.CreateNot(Result);
650686
CGF.Builder.CreateStore(Result, Dest);
@@ -853,6 +889,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
853889
case AtomicExpr::AO__c11_atomic_fetch_and:
854890
case AtomicExpr::AO__c11_atomic_fetch_or:
855891
case AtomicExpr::AO__c11_atomic_fetch_xor:
892+
case AtomicExpr::AO__c11_atomic_fetch_max:
893+
case AtomicExpr::AO__c11_atomic_fetch_min:
856894
case AtomicExpr::AO__opencl_atomic_fetch_and:
857895
case AtomicExpr::AO__opencl_atomic_fetch_or:
858896
case AtomicExpr::AO__opencl_atomic_fetch_xor:
@@ -866,8 +904,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
866904
case AtomicExpr::AO__atomic_or_fetch:
867905
case AtomicExpr::AO__atomic_xor_fetch:
868906
case AtomicExpr::AO__atomic_nand_fetch:
869-
case AtomicExpr::AO__atomic_fetch_min:
907+
case AtomicExpr::AO__atomic_max_fetch:
908+
case AtomicExpr::AO__atomic_min_fetch:
870909
case AtomicExpr::AO__atomic_fetch_max:
910+
case AtomicExpr::AO__atomic_fetch_min:
871911
Val1 = EmitValToTemp(*this, E->getVal1());
872912
break;
873913
}
@@ -916,14 +956,18 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
916956
case AtomicExpr::AO__opencl_atomic_fetch_min:
917957
case AtomicExpr::AO__opencl_atomic_fetch_max:
918958
case AtomicExpr::AO__atomic_fetch_xor:
959+
case AtomicExpr::AO__c11_atomic_fetch_max:
960+
case AtomicExpr::AO__c11_atomic_fetch_min:
919961
case AtomicExpr::AO__atomic_add_fetch:
920962
case AtomicExpr::AO__atomic_and_fetch:
921963
case AtomicExpr::AO__atomic_nand_fetch:
922964
case AtomicExpr::AO__atomic_or_fetch:
923965
case AtomicExpr::AO__atomic_sub_fetch:
924966
case AtomicExpr::AO__atomic_xor_fetch:
925-
case AtomicExpr::AO__atomic_fetch_min:
926967
case AtomicExpr::AO__atomic_fetch_max:
968+
case AtomicExpr::AO__atomic_fetch_min:
969+
case AtomicExpr::AO__atomic_max_fetch:
970+
case AtomicExpr::AO__atomic_min_fetch:
927971
// For these, only library calls for certain sizes exist.
928972
UseOptimizedLibcall = true;
929973
break;
@@ -991,6 +1035,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
9911035
QualType RetTy;
9921036
bool HaveRetTy = false;
9931037
llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
1038+
bool PostOpMinMax = false;
9941039
switch (E->getOp()) {
9951040
case AtomicExpr::AO__c11_atomic_init:
9961041
case AtomicExpr::AO__opencl_atomic_init:
@@ -1112,6 +1157,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
11121157
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
11131158
MemTy, E->getExprLoc(), sizeChars);
11141159
break;
1160+
case AtomicExpr::AO__atomic_min_fetch:
1161+
PostOpMinMax = true;
1162+
LLVM_FALLTHROUGH;
1163+
case AtomicExpr::AO__c11_atomic_fetch_min:
11151164
case AtomicExpr::AO__atomic_fetch_min:
11161165
case AtomicExpr::AO__opencl_atomic_fetch_min:
11171166
LibCallName = E->getValueType()->isSignedIntegerType()
@@ -1120,6 +1169,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
11201169
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
11211170
LoweredMemTy, E->getExprLoc(), sizeChars);
11221171
break;
1172+
case AtomicExpr::AO__atomic_max_fetch:
1173+
PostOpMinMax = true;
1174+
LLVM_FALLTHROUGH;
1175+
case AtomicExpr::AO__c11_atomic_fetch_max:
11231176
case AtomicExpr::AO__atomic_fetch_max:
11241177
case AtomicExpr::AO__opencl_atomic_fetch_max:
11251178
LibCallName = E->getValueType()->isSignedIntegerType()
@@ -1171,7 +1224,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
11711224
// PostOp is only needed for the atomic_*_fetch operations, and
11721225
// thus is only needed for and implemented in the
11731226
// UseOptimizedLibcall codepath.
1174-
assert(UseOptimizedLibcall || !PostOp);
1227+
assert(UseOptimizedLibcall || (!PostOp && !PostOpMinMax));
11751228

11761229
RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args);
11771230
// The value is returned directly from the libcall.
@@ -1182,7 +1235,12 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
11821235
// provided an out-param.
11831236
if (UseOptimizedLibcall && Res.getScalarVal()) {
11841237
llvm::Value *ResVal = Res.getScalarVal();
1185-
if (PostOp) {
1238+
if (PostOpMinMax) {
1239+
llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal();
1240+
ResVal = EmitPostAtomicMinMax(Builder, E->getOp(),
1241+
E->getValueType()->isSignedIntegerType(),
1242+
ResVal, LoadVal1);
1243+
} else if (PostOp) {
11861244
llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal();
11871245
ResVal = Builder.CreateBinOp(PostOp, ResVal, LoadVal1);
11881246
}

clang/lib/Sema/SemaChecking.cpp

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4572,20 +4572,19 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
45724572
&& sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
45734573
"need to update code for modified forms");
45744574
static_assert(AtomicExpr::AO__c11_atomic_init == 0 &&
4575-
AtomicExpr::AO__c11_atomic_fetch_xor + 1 ==
4575+
AtomicExpr::AO__c11_atomic_fetch_min + 1 ==
45764576
AtomicExpr::AO__atomic_load,
45774577
"need to update code for modified C11 atomics");
45784578
bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init &&
45794579
Op <= AtomicExpr::AO__opencl_atomic_fetch_max;
45804580
bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init &&
4581-
Op <= AtomicExpr::AO__c11_atomic_fetch_xor) ||
4581+
Op <= AtomicExpr::AO__c11_atomic_fetch_min) ||
45824582
IsOpenCL;
45834583
bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
45844584
Op == AtomicExpr::AO__atomic_store_n ||
45854585
Op == AtomicExpr::AO__atomic_exchange_n ||
45864586
Op == AtomicExpr::AO__atomic_compare_exchange_n;
45874587
bool IsAddSub = false;
4588-
bool IsMinMax = false;
45894588

45904589
switch (Op) {
45914590
case AtomicExpr::AO__c11_atomic_init:
@@ -4636,12 +4635,12 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
46364635
case AtomicExpr::AO__atomic_or_fetch:
46374636
case AtomicExpr::AO__atomic_xor_fetch:
46384637
case AtomicExpr::AO__atomic_nand_fetch:
4639-
Form = Arithmetic;
4640-
break;
4641-
4638+
case AtomicExpr::AO__c11_atomic_fetch_min:
4639+
case AtomicExpr::AO__c11_atomic_fetch_max:
4640+
case AtomicExpr::AO__atomic_min_fetch:
4641+
case AtomicExpr::AO__atomic_max_fetch:
46424642
case AtomicExpr::AO__atomic_fetch_min:
46434643
case AtomicExpr::AO__atomic_fetch_max:
4644-
IsMinMax = true;
46454644
Form = Arithmetic;
46464645
break;
46474646

@@ -4733,16 +4732,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
47334732
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
47344733
return ExprError();
47354734
}
4736-
if (IsMinMax) {
4737-
const BuiltinType *BT = ValType->getAs<BuiltinType>();
4738-
if (!BT || (BT->getKind() != BuiltinType::Int &&
4739-
BT->getKind() != BuiltinType::UInt)) {
4740-
Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_int32_or_ptr);
4741-
return ExprError();
4742-
}
4743-
}
4744-
if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) {
4745-
Diag(ExprRange.getBegin(), diag::err_atomic_op_bitwise_needs_atomic_int)
4735+
if (!IsAddSub && !ValType->isIntegerType()) {
4736+
Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int)
47464737
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
47474738
return ExprError();
47484739
}

clang/test/CodeGen/atomic-ops.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,4 +661,81 @@ void test_underaligned() {
661661
__atomic_compare_exchange(&aligned_a, &aligned_b, &aligned_c, 1, memory_order_seq_cst, memory_order_seq_cst);
662662
}
663663

664+
void test_c11_minmax(_Atomic(int) * si, _Atomic(unsigned) * ui, _Atomic(short) * ss, _Atomic(unsigned char) * uc, _Atomic(long long) * sll) {
665+
// CHECK-LABEL: @test_c11_minmax
666+
667+
// CHECK: atomicrmw max i32
668+
*si = __c11_atomic_fetch_max(si, 42, memory_order_acquire);
669+
// CHECK: atomicrmw min i32
670+
*si = __c11_atomic_fetch_min(si, 42, memory_order_acquire);
671+
// CHECK: atomicrmw umax i32
672+
*ui = __c11_atomic_fetch_max(ui, 42, memory_order_acquire);
673+
// CHECK: atomicrmw umin i32
674+
*ui = __c11_atomic_fetch_min(ui, 42, memory_order_acquire);
675+
676+
// CHECK: atomicrmw max i16
677+
*ss = __c11_atomic_fetch_max(ss, 42, memory_order_acquire);
678+
// CHECK: atomicrmw min i16
679+
*ss = __c11_atomic_fetch_min(ss, 42, memory_order_acquire);
680+
681+
// CHECK: atomicrmw umax i8
682+
*uc = __c11_atomic_fetch_max(uc, 42, memory_order_acquire);
683+
// CHECK: atomicrmw umin i8
684+
*uc = __c11_atomic_fetch_min(uc, 42, memory_order_acquire);
685+
686+
// CHECK: atomicrmw max i64
687+
*sll = __c11_atomic_fetch_max(sll, 42, memory_order_acquire);
688+
// CHECK: atomicrmw min i64
689+
*sll = __c11_atomic_fetch_min(sll, 42, memory_order_acquire);
690+
691+
}
692+
693+
void test_minmax_postop(int *si, unsigned *ui, unsigned short *us, signed char *sc, unsigned long long *ull) {
694+
int val = 42;
695+
// CHECK-LABEL: @test_minmax_postop
696+
697+
// CHECK: [[OLD:%.*]] = atomicrmw max i32* [[PTR:%.*]], i32 [[RHS:%.*]] release
698+
// CHECK: [[TST:%.*]] = icmp sgt i32 [[OLD]], [[RHS]]
699+
// CHECK: [[NEW:%.*]] = select i1 [[TST]], i32 [[OLD]], i32 [[RHS]]
700+
// CHECK: store i32 [[NEW]], i32*
701+
*si = __atomic_max_fetch(si, 42, memory_order_release);
702+
703+
// CHECK: [[OLD:%.*]] = atomicrmw min i32* [[PTR:%.*]], i32 [[RHS:%.*]] release
704+
// CHECK: [[TST:%.*]] = icmp slt i32 [[OLD]], [[RHS]]
705+
// CHECK: [[NEW:%.*]] = select i1 [[TST]], i32 [[OLD]], i32 [[RHS]]
706+
// CHECK: store i32 [[NEW]], i32*
707+
*si = __atomic_min_fetch(si, 42, memory_order_release);
708+
709+
// CHECK: [[OLD:%.*]] = atomicrmw umax i32* [[PTR:%.*]], i32 [[RHS:%.*]] release
710+
// CHECK: [[TST:%.*]] = icmp ugt i32 [[OLD]], [[RHS]]
711+
// CHECK: [[NEW:%.*]] = select i1 [[TST]], i32 [[OLD]], i32 [[RHS]]
712+
// CHECK: store i32 [[NEW]], i32*
713+
*ui = __atomic_max_fetch(ui, 42, memory_order_release);
714+
715+
// CHECK: [[OLD:%.*]] = atomicrmw umin i32* [[PTR:%.*]], i32 [[RHS:%.*]] release
716+
// CHECK: [[TST:%.*]] = icmp ult i32 [[OLD]], [[RHS]]
717+
// CHECK: [[NEW:%.*]] = select i1 [[TST]], i32 [[OLD]], i32 [[RHS]]
718+
// CHECK: store i32 [[NEW]], i32*
719+
*ui = __atomic_min_fetch(ui, 42, memory_order_release);
720+
721+
// CHECK: [[OLD:%.*]] = atomicrmw umin i16* [[PTR:%.*]], i16 [[RHS:%.*]] release
722+
// CHECK: [[TST:%.*]] = icmp ult i16 [[OLD]], [[RHS]]
723+
// CHECK: [[NEW:%.*]] = select i1 [[TST]], i16 [[OLD]], i16 [[RHS]]
724+
// CHECK: store i16 [[NEW]], i16*
725+
*us = __atomic_min_fetch(us, 42, memory_order_release);
726+
727+
// CHECK: [[OLD:%.*]] = atomicrmw min i8* [[PTR:%.*]], i8 [[RHS:%.*]] release
728+
// CHECK: [[TST:%.*]] = icmp slt i8 [[OLD]], [[RHS]]
729+
// CHECK: [[NEW:%.*]] = select i1 [[TST]], i8 [[OLD]], i8 [[RHS]]
730+
// CHECK: store i8 [[NEW]], i8*
731+
*sc = __atomic_min_fetch(sc, 42, memory_order_release);
732+
733+
// CHECK: [[OLD:%.*]] = call i64 @__atomic_fetch_umin_8(i8* {{%.*}}, i64 [[RHS:%.*]],
734+
// CHECK: [[TST:%.*]] = icmp ult i64 [[OLD]], [[RHS]]
735+
// CHECK: [[NEW:%.*]] = select i1 [[TST]], i64 [[OLD]], i64 [[RHS]]
736+
// CHECK: store i64 [[NEW]], i64*
737+
*ull = __atomic_min_fetch(ull, 42, memory_order_release);
738+
739+
}
740+
664741
#endif

0 commit comments

Comments
 (0)