@@ -27,6 +27,7 @@ class AtomicInfo {
2727 CharUnits atomicAlign;
2828 CharUnits valueAlign;
2929 TypeEvaluationKind evaluationKind = cir::TEK_Scalar;
30+ bool useLibCall = true ;
3031 LValue lvalue;
3132 mlir::Location loc;
3233
@@ -62,8 +63,8 @@ class AtomicInfo {
6263 assert (!cir::MissingFeatures::atomicInfo ());
6364 cgf.cgm .errorNYI (loc, " AtomicInfo: non-simple lvalue" );
6465 }
65-
66- assert (! cir::MissingFeatures::atomicUseLibCall ( ));
66+ useLibCall = !ctx. getTargetInfo (). hasBuiltinAtomic (
67+ atomicSizeInBits, ctx. toBits (lvalue. getAlignment () ));
6768 }
6869
6970 QualType getValueType () const { return valueTy; }
@@ -75,6 +76,8 @@ class AtomicInfo {
7576 assert (!cir::MissingFeatures::atomicInfoGetAtomicPointer ());
7677 return nullptr ;
7778 }
79+ bool shouldUseLibCall () const { return useLibCall; }
80+ const LValue &getAtomicLValue () const { return lvalue; }
7881 Address getAtomicAddress () const {
7982 mlir::Type elemTy;
8083 if (lvalue.isSimple ()) {
@@ -96,6 +99,8 @@ class AtomicInfo {
9699
97100 bool emitMemSetZeroIfNecessary () const ;
98101
102+ mlir::Value getScalarRValValueOrNull (RValue rvalue) const ;
103+
99104 // / Cast the given pointer to an integer pointer suitable for atomic
100105 // / operations on the source.
101106 Address castToAtomicIntPointer (Address addr) const ;
@@ -105,6 +110,9 @@ class AtomicInfo {
105110 // / copy the value across.
106111 Address convertToAtomicIntPointer (Address addr) const ;
107112
113+ // / Converts a rvalue to integer value.
114+ mlir::Value convertRValueToInt (RValue rvalue, bool cmpxchg = false ) const ;
115+
108116 // / Copy an atomic r-value into atomic-layout memory.
109117 void emitCopyIntoMemory (RValue rvalue) const ;
110118
@@ -195,6 +203,12 @@ Address AtomicInfo::createTempAlloca() const {
195203 return tempAlloca;
196204}
197205
206+ mlir::Value AtomicInfo::getScalarRValValueOrNull (RValue rvalue) const {
207+ if (rvalue.isScalar () && (!hasPadding () || !lvalue.isSimple ()))
208+ return rvalue.getValue ();
209+ return nullptr ;
210+ }
211+
198212Address AtomicInfo::castToAtomicIntPointer (Address addr) const {
199213 auto intTy = mlir::dyn_cast<cir::IntType>(addr.getElementType ());
200214 // Don't bother with int casts if the integer size is the same.
@@ -215,6 +229,34 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const {
215229 return false ;
216230}
217231
232+ // / Return true if \param valueTy is a type that should be casted to integer
233+ // / around the atomic memory operation. If \param cmpxchg is true, then the
234+ // / cast of a floating point type is made as that instruction can not have
235+ // / floating point operands. TODO: Allow compare-and-exchange and FP - see
236+ // / comment in CIRGenAtomicExpandPass.cpp.
237+ static bool shouldCastToInt (mlir::Type valueTy, bool cmpxchg) {
238+ if (cir::isAnyFloatingPointType (valueTy))
239+ return isa<cir::FP80Type>(valueTy) || cmpxchg;
240+ return !isa<cir::IntType>(valueTy) && !isa<cir::PointerType>(valueTy);
241+ }
242+
243+ mlir::Value AtomicInfo::convertRValueToInt (RValue rvalue, bool cmpxchg) const {
244+ // If we've got a scalar value of the right size, try to avoid going
245+ // through memory. Floats get casted if needed by AtomicExpandPass.
246+ if (mlir::Value value = getScalarRValValueOrNull (rvalue)) {
247+ if (!shouldCastToInt (value.getType (), cmpxchg))
248+ return cgf.emitToMemory (value, valueTy);
249+
250+ cgf.cgm .errorNYI (
251+ loc, " AtomicInfo::convertRValueToInt: cast scalar rvalue to int" );
252+ return nullptr ;
253+ }
254+
255+ cgf.cgm .errorNYI (
256+ loc, " AtomicInfo::convertRValueToInt: cast non-scalar rvalue to int" );
257+ return nullptr ;
258+ }
259+
218260// / Copy an r-value into memory as part of storing to an atomic type.
219261// / This needs to create a bit-pattern suitable for atomic operations.
220262void AtomicInfo::emitCopyIntoMemory (RValue rvalue) const {
@@ -815,6 +857,85 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
815857 e->getExprLoc ());
816858}
817859
860+ void CIRGenFunction::emitAtomicStore (RValue rvalue, LValue dest, bool isInit) {
861+ bool isVolatile = dest.isVolatileQualified ();
862+ cir::MemOrder order;
863+ if (dest.getType ()->isAtomicType ()) {
864+ order = cir::MemOrder::SequentiallyConsistent;
865+ } else {
866+ order = cir::MemOrder::Release;
867+ isVolatile = true ;
868+ }
869+ return emitAtomicStore (rvalue, dest, order, isVolatile, isInit);
870+ }
871+
872+ // / Emit a store to an l-value of atomic type.
873+ // /
874+ // / Note that the r-value is expected to be an r-value of the atomic type; this
875+ // / means that for aggregate r-values, it should include storage for any padding
876+ // / that was necessary.
877+ void CIRGenFunction::emitAtomicStore (RValue rvalue, LValue dest,
878+ cir::MemOrder order, bool isVolatile,
879+ bool isInit) {
880+ // If this is an aggregate r-value, it should agree in type except
881+ // maybe for address-space qualification.
882+ auto loc = dest.getPointer ().getLoc ();
883+ assert (!rvalue.isAggregate () ||
884+ rvalue.getAggregateAddress ().getElementType () ==
885+ dest.getAddress ().getElementType ());
886+
887+ AtomicInfo atomics (*this , dest, loc);
888+ LValue lvalue = atomics.getAtomicLValue ();
889+
890+ // If this is an initialization, just put the value there normally.
891+ if (lvalue.isSimple ()) {
892+ if (isInit) {
893+ atomics.emitCopyIntoMemory (rvalue);
894+ return ;
895+ }
896+
897+ // Check whether we should use a library call.
898+ if (atomics.shouldUseLibCall ()) {
899+ assert (!cir::MissingFeatures::atomicUseLibCall ());
900+ cgm.errorNYI (loc, " emitAtomicStore: atomic store with library call" );
901+ return ;
902+ }
903+
904+ // Okay, we're doing this natively.
905+ mlir::Value valueToStore = atomics.convertRValueToInt (rvalue);
906+
907+ // Do the atomic store.
908+ Address addr = atomics.getAtomicAddress ();
909+ if (mlir::Value value = atomics.getScalarRValValueOrNull (rvalue)) {
910+ if (shouldCastToInt (value.getType (), /* CmpXchg=*/ false )) {
911+ addr = atomics.castToAtomicIntPointer (addr);
912+ valueToStore =
913+ builder.createIntCast (valueToStore, addr.getElementType ());
914+ }
915+ }
916+ cir::StoreOp store = builder.createStore (loc, valueToStore, addr);
917+
918+ // Initializations don't need to be atomic.
919+ if (!isInit) {
920+ if (order == cir::MemOrder::Acquire)
921+ order = cir::MemOrder::Relaxed; // Monotonic
922+ else if (order == cir::MemOrder::AcquireRelease)
923+ order = cir::MemOrder::Release;
924+ store.setMemOrder (order);
925+ }
926+
927+ // Other decoration.
928+ if (isVolatile)
929+ store.setIsVolatile (true );
930+
931+ assert (!cir::MissingFeatures::opLoadStoreTbaa ());
932+ return ;
933+ }
934+
935+ cgm.errorNYI (loc, " emitAtomicStore: non-simple atomic lvalue" );
936+ assert (!cir::MissingFeatures::opLoadStoreAtomic ());
937+ }
938+
818939void CIRGenFunction::emitAtomicInit (Expr *init, LValue dest) {
819940 AtomicInfo atomics (*this , dest, getLoc (init->getSourceRange ()));
820941
0 commit comments