@@ -374,10 +374,9 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const {
374374}
375375
376376static 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
539559static 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
798824static 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;
0 commit comments