@@ -2598,6 +2598,12 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
25982598 if (typeStructFields.find (type) != typeStructFields.end ()) {
25992599 options.add (FeatureSet::ReferenceTypes | FeatureSet::GC,
26002600 &Self::makeStructGet);
2601+ options.add (FeatureSet::ReferenceTypes | FeatureSet::GC |
2602+ FeatureSet::Atomics | FeatureSet::SharedEverything,
2603+ &Self::makeStructRMW);
2604+ options.add (FeatureSet::ReferenceTypes | FeatureSet::GC |
2605+ FeatureSet::Atomics | FeatureSet::SharedEverything,
2606+ &Self::makeStructCmpxchg);
26012607 }
26022608 if (typeArrays.find (type) != typeArrays.end ()) {
26032609 options.add (FeatureSet::ReferenceTypes | FeatureSet::GC,
@@ -5583,8 +5589,65 @@ Expression* TranslateToFuzzReader::makeStructGet(Type type) {
55835589 auto [structType, fieldIndex] = pick (structFields);
55845590 auto * ref = makeTrappingRefUse (structType);
55855591 auto signed_ = maybeSignedGet (structType.getStruct ().fields [fieldIndex]);
5586- return builder.makeStructGet (
5587- fieldIndex, ref, MemoryOrder::Unordered, type, signed_);
5592+ auto order = MemoryOrder::Unordered;
5593+ if (wasm.features .hasAtomics () && wasm.features .hasSharedEverything () &&
5594+ oneIn (2 )) {
5595+ order = oneIn (2 ) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5596+ }
5597+ return builder.makeStructGet (fieldIndex, ref, order, type, signed_);
5598+ }
5599+
5600+ Expression* TranslateToFuzzReader::makeStructRMW (Type type) {
5601+ bool isAny =
5602+ type.isRef () &&
5603+ HeapType (type.getHeapType ().getTop ()).isMaybeShared (HeapType::any);
5604+ if (type != Type::i32 && type != Type::i64 && !isAny) {
5605+ // Not a valid field type for an RMW operation.
5606+ return makeStructGet (type);
5607+ }
5608+ auto & structFields = typeStructFields[type];
5609+ assert (!structFields.empty ());
5610+ auto [structType, fieldIndex] = pick (structFields);
5611+ const auto & field = structType.getStruct ().fields [fieldIndex];
5612+ if (field.isPacked () || field.mutable_ == Immutable) {
5613+ // Cannot RMW a packed or immutable field.
5614+ return makeStructGet (type);
5615+ }
5616+ AtomicRMWOp op = RMWXchg;
5617+ if (type == Type::i32 || type == Type::i64 ) {
5618+ op = pick (RMWAdd, RMWSub, RMWAnd, RMWOr, RMWXor, RMWXchg);
5619+ }
5620+ auto * ref = makeTrappingRefUse (structType);
5621+ auto * value = make (type);
5622+ auto order = oneIn (2 ) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5623+ return builder.makeStructRMW (op, fieldIndex, ref, value, order);
5624+ }
5625+
5626+ Expression* TranslateToFuzzReader::makeStructCmpxchg (Type type) {
5627+ bool isShared = type.isRef () && type.getHeapType ().isShared ();
5628+ Type eq (HeapTypes::eq.getBasic (isShared ? Shared : Unshared), Nullable);
5629+ bool isEq = Type::isSubType (type, eq);
5630+ if (type != Type::i32 && type != Type::i64 && !isEq) {
5631+ // Not a valid field type for a cmpxchg operation.
5632+ return makeStructGet (type);
5633+ }
5634+ auto & structFields = typeStructFields[type];
5635+ assert (!structFields.empty ());
5636+ auto [structType, fieldIndex] = pick (structFields);
5637+ const auto & field = structType.getStruct ().fields [fieldIndex];
5638+ if (field.isPacked () || field.mutable_ == Immutable) {
5639+ // Cannot RMW a packed or immutable field.
5640+ return makeStructGet (type);
5641+ }
5642+ auto * ref = makeTrappingRefUse (structType);
5643+ // For reference fields, expected can be a subtype of eq. Only do use the
5644+ // extra flexibility occasionally because it makes the expected value less
5645+ // likely to be equal to the actual value.
5646+ auto * expected = make (isEq && oneIn (4 ) ? eq : type);
5647+ auto * replacement = make (type);
5648+ auto order = oneIn (2 ) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5649+ return builder.makeStructCmpxchg (
5650+ fieldIndex, ref, expected, replacement, order);
55885651}
55895652
55905653Expression* TranslateToFuzzReader::makeStructSet (Type type) {
@@ -5596,7 +5659,12 @@ Expression* TranslateToFuzzReader::makeStructSet(Type type) {
55965659 auto fieldType = structType.getStruct ().fields [fieldIndex].type ;
55975660 auto * ref = makeTrappingRefUse (structType);
55985661 auto * value = make (fieldType);
5599- return builder.makeStructSet (fieldIndex, ref, value, MemoryOrder::Unordered);
5662+ auto order = MemoryOrder::Unordered;
5663+ if (wasm.features .hasAtomics () && wasm.features .hasSharedEverything () &&
5664+ oneIn (2 )) {
5665+ order = oneIn (2 ) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5666+ }
5667+ return builder.makeStructSet (fieldIndex, ref, value, order);
56005668}
56015669
56025670// Make a bounds check for an array operation, given a ref + index. An optional
0 commit comments