Skip to content

Commit 423a1ea

Browse files
huixie90aokblast
authored andcommitted
[clang] [libc++] fix _Atomic c11 compare exchange does not update expected results (llvm#78707)
fixes llvm#30023 The issue is that for compare exchange builtin, if the type's size is not power of 2, it creates a temporary of size power of 2, then emit the compare exchange operation. And later, the results of the compare exchange operation has two components: 1. a boolean whether or not the exchange happens. 2. the old value we are supposed to write the old value into user's "expected" value. However, in case the type is not power of 2, what we actually wrote to is the temporary that was created. The fix is to pass the "expected" address all the way down so it can wrote to the correct address
1 parent 8ca0bcd commit 423a1ea

File tree

4 files changed

+302
-61
lines changed

4 files changed

+302
-61
lines changed

clang/lib/CodeGen/CGAtomic.cpp

Lines changed: 93 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,9 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const {
374374
}
375375

376376
static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
377-
Address Dest, Address Ptr,
378-
Address Val1, Address Val2,
379-
uint64_t Size,
380-
llvm::AtomicOrdering SuccessOrder,
377+
Address Dest, Address Ptr, Address Val1,
378+
Address Val2, Address ExpectedResult,
379+
uint64_t Size, llvm::AtomicOrdering SuccessOrder,
381380
llvm::AtomicOrdering FailureOrder,
382381
llvm::SyncScope::ID Scope) {
383382
// Note that cmpxchg doesn't support weak cmpxchg, at least at the moment.
@@ -411,8 +410,30 @@ static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
411410

412411
CGF.Builder.SetInsertPoint(StoreExpectedBB);
413412
// Update the memory at Expected with Old's value.
414-
auto *I = CGF.Builder.CreateStore(Old, Val1);
415-
CGF.addInstToCurrentSourceAtom(I, Old);
413+
llvm::Type *ExpectedType = ExpectedResult.getElementType();
414+
const llvm::DataLayout &DL = CGF.CGM.getDataLayout();
415+
uint64_t ExpectedSizeInBytes = DL.getTypeStoreSize(ExpectedType);
416+
417+
if (ExpectedSizeInBytes == Size) {
418+
// Sizes match: store directly
419+
auto *I = CGF.Builder.CreateStore(Old, ExpectedResult);
420+
CGF.addInstToCurrentSourceAtom(I, Old);
421+
} else {
422+
// store only the first ExpectedSizeInBytes bytes of Old
423+
llvm::Type *OldType = Old->getType();
424+
425+
// Allocate temporary storage for Old value
426+
Address OldTmp =
427+
CGF.CreateTempAlloca(OldType, Ptr.getAlignment(), "old.tmp");
428+
429+
// Store Old into this temporary
430+
auto *I = CGF.Builder.CreateStore(Old, OldTmp);
431+
CGF.addInstToCurrentSourceAtom(I, Old);
432+
433+
// Perform memcpy for first ExpectedSizeInBytes bytes
434+
CGF.Builder.CreateMemCpy(ExpectedResult, OldTmp, ExpectedSizeInBytes,
435+
/*isVolatile=*/false);
436+
}
416437

417438
// Finally, branch to the exit point.
418439
CGF.Builder.CreateBr(ContinueBB);
@@ -425,13 +446,11 @@ static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
425446
/// Given an ordering required on success, emit all possible cmpxchg
426447
/// instructions to cope with the provided (but possibly only dynamically known)
427448
/// FailureOrder.
428-
static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
429-
bool IsWeak, Address Dest, Address Ptr,
430-
Address Val1, Address Val2,
431-
llvm::Value *FailureOrderVal,
432-
uint64_t Size,
433-
llvm::AtomicOrdering SuccessOrder,
434-
llvm::SyncScope::ID Scope) {
449+
static void emitAtomicCmpXchgFailureSet(
450+
CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak, Address Dest, Address Ptr,
451+
Address Val1, Address Val2, Address ExpectedResult,
452+
llvm::Value *FailureOrderVal, uint64_t Size,
453+
llvm::AtomicOrdering SuccessOrder, llvm::SyncScope::ID Scope) {
435454
llvm::AtomicOrdering FailureOrder;
436455
if (llvm::ConstantInt *FO = dyn_cast<llvm::ConstantInt>(FailureOrderVal)) {
437456
auto FOS = FO->getSExtValue();
@@ -458,8 +477,8 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
458477
// success argument". This condition has been lifted and the only
459478
// precondition is 31.7.2.18. Effectively treat this as a DR and skip
460479
// language version checks.
461-
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
462-
FailureOrder, Scope);
480+
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, ExpectedResult,
481+
Size, SuccessOrder, FailureOrder, Scope);
463482
return;
464483
}
465484

@@ -483,18 +502,19 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
483502

484503
// Emit all the different atomics
485504
CGF.Builder.SetInsertPoint(MonotonicBB);
486-
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
487-
Size, SuccessOrder, llvm::AtomicOrdering::Monotonic, Scope);
505+
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, ExpectedResult, Size,
506+
SuccessOrder, llvm::AtomicOrdering::Monotonic, Scope);
488507
CGF.Builder.CreateBr(ContBB);
489508

490509
CGF.Builder.SetInsertPoint(AcquireBB);
491-
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
492-
llvm::AtomicOrdering::Acquire, Scope);
510+
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, ExpectedResult, Size,
511+
SuccessOrder, llvm::AtomicOrdering::Acquire, Scope);
493512
CGF.Builder.CreateBr(ContBB);
494513

495514
CGF.Builder.SetInsertPoint(SeqCstBB);
496-
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
497-
llvm::AtomicOrdering::SequentiallyConsistent, Scope);
515+
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, ExpectedResult, Size,
516+
SuccessOrder, llvm::AtomicOrdering::SequentiallyConsistent,
517+
Scope);
498518
CGF.Builder.CreateBr(ContBB);
499519

500520
CGF.Builder.SetInsertPoint(ContBB);
@@ -538,8 +558,9 @@ static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder,
538558

539559
static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
540560
Address Ptr, Address Val1, Address Val2,
541-
llvm::Value *IsWeak, llvm::Value *FailureOrder,
542-
uint64_t Size, llvm::AtomicOrdering Order,
561+
Address ExpectedResult, llvm::Value *IsWeak,
562+
llvm::Value *FailureOrder, uint64_t Size,
563+
llvm::AtomicOrdering Order,
543564
llvm::SyncScope::ID Scope) {
544565
llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
545566
bool PostOpMinMax = false;
@@ -554,21 +575,24 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
554575
case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
555576
case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
556577
emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
557-
FailureOrder, Size, Order, Scope);
578+
ExpectedResult, FailureOrder, Size, Order,
579+
Scope);
558580
return;
559581
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
560582
case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
561583
case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
562584
emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
563-
FailureOrder, Size, Order, Scope);
585+
ExpectedResult, FailureOrder, Size, Order,
586+
Scope);
564587
return;
565588
case AtomicExpr::AO__atomic_compare_exchange:
566589
case AtomicExpr::AO__atomic_compare_exchange_n:
567590
case AtomicExpr::AO__scoped_atomic_compare_exchange:
568591
case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
569592
if (llvm::ConstantInt *IsWeakC = dyn_cast<llvm::ConstantInt>(IsWeak)) {
570593
emitAtomicCmpXchgFailureSet(CGF, E, IsWeakC->getZExtValue(), Dest, Ptr,
571-
Val1, Val2, FailureOrder, Size, Order, Scope);
594+
Val1, Val2, ExpectedResult, FailureOrder,
595+
Size, Order, Scope);
572596
} else {
573597
// Create all the relevant BB's
574598
llvm::BasicBlock *StrongBB =
@@ -582,12 +606,14 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
582606

583607
CGF.Builder.SetInsertPoint(StrongBB);
584608
emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
585-
FailureOrder, Size, Order, Scope);
609+
ExpectedResult, FailureOrder, Size, Order,
610+
Scope);
586611
CGF.Builder.CreateBr(ContBB);
587612

588613
CGF.Builder.SetInsertPoint(WeakBB);
589614
emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
590-
FailureOrder, Size, Order, Scope);
615+
ExpectedResult, FailureOrder, Size, Order,
616+
Scope);
591617
CGF.Builder.CreateBr(ContBB);
592618

593619
CGF.Builder.SetInsertPoint(ContBB);
@@ -797,9 +823,9 @@ EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
797823

798824
static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
799825
Address Ptr, Address Val1, Address Val2,
800-
llvm::Value *IsWeak, llvm::Value *FailureOrder,
801-
uint64_t Size, llvm::AtomicOrdering Order,
802-
llvm::Value *Scope) {
826+
Address OriginalVal1, llvm::Value *IsWeak,
827+
llvm::Value *FailureOrder, uint64_t Size,
828+
llvm::AtomicOrdering Order, llvm::Value *Scope) {
803829
auto ScopeModel = Expr->getScopeModel();
804830

805831
// LLVM atomic instructions always have sync scope. If clang atomic
@@ -816,8 +842,8 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
816842
Order, CGF.getLLVMContext());
817843
else
818844
SS = llvm::SyncScope::System;
819-
EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
820-
Order, SS);
845+
EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
846+
FailureOrder, Size, Order, SS);
821847
return;
822848
}
823849

@@ -826,8 +852,8 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
826852
auto SCID = CGF.getTargetHooks().getLLVMSyncScopeID(
827853
CGF.CGM.getLangOpts(), ScopeModel->map(SC->getZExtValue()),
828854
Order, CGF.CGM.getLLVMContext());
829-
EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
830-
Order, SCID);
855+
EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
856+
FailureOrder, Size, Order, SCID);
831857
return;
832858
}
833859

@@ -852,12 +878,11 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
852878
SI->addCase(Builder.getInt32(S), B);
853879

854880
Builder.SetInsertPoint(B);
855-
EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
856-
Order,
857-
CGF.getTargetHooks().getLLVMSyncScopeID(CGF.CGM.getLangOpts(),
858-
ScopeModel->map(S),
859-
Order,
860-
CGF.getLLVMContext()));
881+
EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
882+
FailureOrder, Size, Order,
883+
CGF.getTargetHooks().getLLVMSyncScopeID(
884+
CGF.CGM.getLangOpts(), ScopeModel->map(S), Order,
885+
CGF.getLLVMContext()));
861886
Builder.CreateBr(ContBB);
862887
}
863888

@@ -1058,6 +1083,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
10581083
LValue AtomicVal = MakeAddrLValue(Ptr, AtomicTy);
10591084
AtomicInfo Atomics(*this, AtomicVal);
10601085

1086+
Address OriginalVal1 = Val1;
10611087
if (ShouldCastToIntPtrTy) {
10621088
Ptr = Atomics.castToAtomicIntPointer(Ptr);
10631089
if (Val1.isValid())
@@ -1301,30 +1327,32 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
13011327
if (llvm::isValidAtomicOrderingCABI(ord))
13021328
switch ((llvm::AtomicOrderingCABI)ord) {
13031329
case llvm::AtomicOrderingCABI::relaxed:
1304-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1305-
llvm::AtomicOrdering::Monotonic, Scope);
1330+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
1331+
OrderFail, Size, llvm::AtomicOrdering::Monotonic, Scope);
13061332
break;
13071333
case llvm::AtomicOrderingCABI::consume:
13081334
case llvm::AtomicOrderingCABI::acquire:
13091335
if (IsStore)
13101336
break; // Avoid crashing on code with undefined behavior
1311-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1312-
llvm::AtomicOrdering::Acquire, Scope);
1337+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
1338+
OrderFail, Size, llvm::AtomicOrdering::Acquire, Scope);
13131339
break;
13141340
case llvm::AtomicOrderingCABI::release:
13151341
if (IsLoad)
13161342
break; // Avoid crashing on code with undefined behavior
1317-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1318-
llvm::AtomicOrdering::Release, Scope);
1343+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
1344+
OrderFail, Size, llvm::AtomicOrdering::Release, Scope);
13191345
break;
13201346
case llvm::AtomicOrderingCABI::acq_rel:
13211347
if (IsLoad || IsStore)
13221348
break; // Avoid crashing on code with undefined behavior
1323-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1324-
llvm::AtomicOrdering::AcquireRelease, Scope);
1349+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
1350+
OrderFail, Size, llvm::AtomicOrdering::AcquireRelease,
1351+
Scope);
13251352
break;
13261353
case llvm::AtomicOrderingCABI::seq_cst:
1327-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1354+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
1355+
OrderFail, Size,
13281356
llvm::AtomicOrdering::SequentiallyConsistent, Scope);
13291357
break;
13301358
}
@@ -1360,13 +1388,13 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
13601388

13611389
// Emit all the different atomics
13621390
Builder.SetInsertPoint(MonotonicBB);
1363-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1364-
llvm::AtomicOrdering::Monotonic, Scope);
1391+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak, OrderFail,
1392+
Size, llvm::AtomicOrdering::Monotonic, Scope);
13651393
Builder.CreateBr(ContBB);
13661394
if (!IsStore) {
13671395
Builder.SetInsertPoint(AcquireBB);
1368-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1369-
llvm::AtomicOrdering::Acquire, Scope);
1396+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
1397+
OrderFail, Size, llvm::AtomicOrdering::Acquire, Scope);
13701398
Builder.CreateBr(ContBB);
13711399
SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
13721400
AcquireBB);
@@ -1375,23 +1403,23 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
13751403
}
13761404
if (!IsLoad) {
13771405
Builder.SetInsertPoint(ReleaseBB);
1378-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1379-
llvm::AtomicOrdering::Release, Scope);
1406+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
1407+
OrderFail, Size, llvm::AtomicOrdering::Release, Scope);
13801408
Builder.CreateBr(ContBB);
13811409
SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::release),
13821410
ReleaseBB);
13831411
}
13841412
if (!IsLoad && !IsStore) {
13851413
Builder.SetInsertPoint(AcqRelBB);
1386-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1387-
llvm::AtomicOrdering::AcquireRelease, Scope);
1414+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak,
1415+
OrderFail, Size, llvm::AtomicOrdering::AcquireRelease, Scope);
13881416
Builder.CreateBr(ContBB);
13891417
SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acq_rel),
13901418
AcqRelBB);
13911419
}
13921420
Builder.SetInsertPoint(SeqCstBB);
1393-
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
1394-
llvm::AtomicOrdering::SequentiallyConsistent, Scope);
1421+
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, OriginalVal1, IsWeak, OrderFail,
1422+
Size, llvm::AtomicOrdering::SequentiallyConsistent, Scope);
13951423
Builder.CreateBr(ContBB);
13961424
SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
13971425
SeqCstBB);
@@ -1417,6 +1445,11 @@ Address AtomicInfo::convertToAtomicIntPointer(Address Addr) const {
14171445
uint64_t SourceSizeInBits = CGF.CGM.getDataLayout().getTypeSizeInBits(Ty);
14181446
if (SourceSizeInBits != AtomicSizeInBits) {
14191447
Address Tmp = CreateTempAlloca();
1448+
CGF.Builder.CreateMemSet(
1449+
Tmp.emitRawPointer(CGF), llvm::ConstantInt::get(CGF.Int8Ty, 0),
1450+
CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(),
1451+
Tmp.getAlignment().getAsAlign());
1452+
14201453
CGF.Builder.CreateMemCpy(Tmp, Addr,
14211454
std::min(AtomicSizeInBits, SourceSizeInBits) / 8);
14221455
Addr = Tmp;

clang/test/CodeGen/c11atomics-ios.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ _Bool test_promoted_cmpxchg(_Atomic(PS) *addr, PS *desired, PS *new) {
235235
// CHECK: [[ATOMIC_DESIRED:%.*]] = alloca { %struct.PS, [2 x i8] }, align 8
236236
// CHECK: [[ATOMIC_NEW:%.*]] = alloca { %struct.PS, [2 x i8] }, align 8
237237
// CHECK: [[RES_ADDR:%.*]] = alloca i8, align 1
238+
// CHECK: [[OLD_TMP:%.*]] = alloca i64, align 8
238239
// CHECK: store ptr %addr, ptr [[ADDR_ARG]], align 4
239240
// CHECK: store ptr %desired, ptr [[DESIRED_ARG]], align 4
240241
// CHECK: store ptr %new, ptr [[NEW_ARG]], align 4
@@ -251,7 +252,8 @@ _Bool test_promoted_cmpxchg(_Atomic(PS) *addr, PS *desired, PS *new) {
251252
// CHECK: [[RES_BOOL:%.*]] = extractvalue { i64, i1 } [[RES]], 1
252253
// CHECK: br i1 [[RES_BOOL]], label {{%.*}}, label {{%.*}}
253254

254-
// CHECK: store i64 [[RES_VAL64]], ptr [[ATOMIC_DESIRED]], align 8
255+
// CHECK: store i64 [[RES_VAL64]], ptr [[OLD_TMP]], align 8
256+
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 2 [[DESIRED_ARG:%.*]], ptr align 8 [[OLD_TMP]], i64 6, i1 false)
255257
// CHECK: br label {{%.*}}
256258

257259
// CHECK: [[RES_BOOL8:%.*]] = zext i1 [[RES_BOOL]] to i8

0 commit comments

Comments
 (0)