@@ -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.
@@ -211,10 +225,38 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const {
211225 return false ;
212226
213227 cgf.cgm .errorNYI (loc,
214- " AtomicInfo::emitMemSetZeroIfNecessary : emit memset zero" );
228+ " AtomicInfo::emitMemSetZeroIfNecaessary : emit memset zero" );
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,79 @@ 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+ auto order = cir::MemOrder::SequentiallyConsistent;
863+ if (!dest.getType ()->isAtomicType ()) {
864+ assert (!cir::MissingFeatures::atomicMicrosoftVolatile ());
865+ }
866+ return emitAtomicStore (rvalue, dest, order, isVolatile, isInit);
867+ }
868+
869+ // / Emit a store to an l-value of atomic type.
870+ // /
871+ // / Note that the r-value is expected to be an r-value of the atomic type; this
872+ // / means that for aggregate r-values, it should include storage for any padding
873+ // / that was necessary.
874+ void CIRGenFunction::emitAtomicStore (RValue rvalue, LValue dest,
875+ cir::MemOrder order, bool isVolatile,
876+ bool isInit) {
877+ // If this is an aggregate r-value, it should agree in type except
878+ // maybe for address-space qualification.
879+ mlir::Location loc = dest.getPointer ().getLoc ();
880+ assert (!rvalue.isAggregate () ||
881+ rvalue.getAggregateAddress ().getElementType () ==
882+ dest.getAddress ().getElementType ());
883+
884+ AtomicInfo atomics (*this , dest, loc);
885+ LValue lvalue = atomics.getAtomicLValue ();
886+
887+ if (lvalue.isSimple ()) {
888+ // If this is an initialization, just put the value there normally.
889+ if (isInit) {
890+ atomics.emitCopyIntoMemory (rvalue);
891+ return ;
892+ }
893+
894+ // Check whether we should use a library call.
895+ if (atomics.shouldUseLibCall ()) {
896+ assert (!cir::MissingFeatures::atomicUseLibCall ());
897+ cgm.errorNYI (loc, " emitAtomicStore: atomic store with library call" );
898+ return ;
899+ }
900+
901+ // Okay, we're doing this natively.
902+ mlir::Value valueToStore = atomics.convertRValueToInt (rvalue);
903+
904+ // Do the atomic store.
905+ Address addr = atomics.getAtomicAddress ();
906+ if (mlir::Value value = atomics.getScalarRValValueOrNull (rvalue)) {
907+ if (shouldCastToInt (value.getType (), /* CmpXchg=*/ false )) {
908+ addr = atomics.castToAtomicIntPointer (addr);
909+ valueToStore =
910+ builder.createIntCast (valueToStore, addr.getElementType ());
911+ }
912+ }
913+ cir::StoreOp store = builder.createStore (loc, valueToStore, addr);
914+
915+ // Initializations don't need to be atomic.
916+ if (!isInit) {
917+ assert (!cir::MissingFeatures::atomicOpenMP ());
918+ store.setMemOrder (order);
919+ }
920+
921+ // Other decoration.
922+ if (isVolatile)
923+ store.setIsVolatile (true );
924+
925+ assert (!cir::MissingFeatures::opLoadStoreTbaa ());
926+ return ;
927+ }
928+
929+ cgm.errorNYI (loc, " emitAtomicStore: non-simple atomic lvalue" );
930+ assert (!cir::MissingFeatures::opLoadStoreAtomic ());
931+ }
932+
818933void CIRGenFunction::emitAtomicInit (Expr *init, LValue dest) {
819934 AtomicInfo atomics (*this , dest, getLoc (init->getSourceRange ()));
820935
0 commit comments