@@ -219,15 +219,36 @@ void WasmValidator::visitSetLocal(SetLocal *curr) {
219219 }
220220}
221221void WasmValidator::visitLoad (Load *curr) {
222- validateAlignment (curr->align , curr->type , curr->bytes );
222+ validateMemBytes (curr->bytes , curr->type , curr);
223+ validateAlignment (curr->align , curr->type , curr->bytes , curr->isAtomic , curr);
223224 shouldBeEqualOrFirstIsUnreachable (curr->ptr ->type , i32 , curr, " load pointer type must be i32" );
224225}
225226void WasmValidator::visitStore (Store *curr) {
226- validateAlignment (curr->align , curr->type , curr->bytes );
227+ validateMemBytes (curr->bytes , curr->valueType , curr);
228+ validateAlignment (curr->align , curr->type , curr->bytes , curr->isAtomic , curr);
227229 shouldBeEqualOrFirstIsUnreachable (curr->ptr ->type , i32 , curr, " store pointer type must be i32" );
228230 shouldBeUnequal (curr->value ->type , none, curr, " store value type must not be none" );
229231 shouldBeEqualOrFirstIsUnreachable (curr->value ->type , curr->valueType , curr, " store value type must match" );
230232}
233+ void WasmValidator::visitAtomicRMW (AtomicRMW* curr) {
234+ validateMemBytes (curr->bytes , curr->type , curr);
235+ }
236+ void WasmValidator::visitAtomicCmpxchg (AtomicCmpxchg* curr) {
237+ validateMemBytes (curr->bytes , curr->type , curr);
238+ }
239+ void WasmValidator::validateMemBytes (uint8_t bytes, WasmType ty, Expression* curr) {
240+ switch (bytes) {
241+ case 1 :
242+ case 2 :
243+ case 4 :
244+ break ;
245+ case 8 : {
246+ shouldBeEqual (getWasmTypeSize (ty), 8U , curr, " 8-byte mem operations are only allowed with 8-byte wasm types" );
247+ break ;
248+ }
249+ default : fail (" Memory operations must be 1,2,4, or 8 bytes" , curr);
250+ }
251+ }
231252void WasmValidator::visitBinary (Binary *curr) {
232253 if (curr->left ->type != unreachable && curr->right ->type != unreachable) {
233254 shouldBeEqual (curr->left ->type , curr->right ->type , curr, " binary child types must be equal" );
@@ -566,28 +587,32 @@ void WasmValidator::visitModule(Module *curr) {
566587 }
567588}
568589
569- void WasmValidator::validateAlignment (size_t align, WasmType type, Index bytes) {
590+ void WasmValidator::validateAlignment (size_t align, WasmType type, Index bytes,
591+ bool isAtomic, Expression* curr) {
592+ if (isAtomic) {
593+ shouldBeEqual (align, (size_t )bytes, curr, " atomic accesses must have natural alignment" );
594+ return ;
595+ }
570596 switch (align) {
571597 case 1 :
572598 case 2 :
573599 case 4 :
574600 case 8 : break ;
575601 default :{
576- fail () << " bad alignment: " << align << std::endl;
577- valid = false ;
602+ fail (" bad alignment: " + std::to_string (align), curr);
578603 break ;
579604 }
580605 }
581- shouldBeTrue (align <= bytes, align , " alignment must not exceed natural" );
606+ shouldBeTrue (align <= bytes, curr , " alignment must not exceed natural" );
582607 switch (type) {
583608 case i32 :
584609 case f32 : {
585- shouldBeTrue (align <= 4 , align , " alignment must not exceed natural" );
610+ shouldBeTrue (align <= 4 , curr , " alignment must not exceed natural" );
586611 break ;
587612 }
588613 case i64 :
589614 case f64 : {
590- shouldBeTrue (align <= 8 , align , " alignment must not exceed natural" );
615+ shouldBeTrue (align <= 8 , curr , " alignment must not exceed natural" );
591616 break ;
592617 }
593618 default : {}
@@ -614,7 +639,7 @@ void WasmValidator::validateBinaryenIR(Module& wasm) {
614639 // The block has an added type, not derived from the ast itself, so it is
615640 // ok for it to be either i32 or unreachable.
616641 if (!(isConcreteWasmType (oldType) && newType == unreachable)) {
617- parent.fail () << " stale type found in " << (getFunction () ? getFunction ()->name : Name (" (global scope)" )) << " on " << curr << " \n (marked as " << printWasmType (oldType) << " , should be " << printWasmType (newType) << " )\n " ;
642+ parent.printFailureHeader () << " stale type found in " << (getFunction () ? getFunction ()->name : Name (" (global scope)" )) << " on " << curr << " \n (marked as " << printWasmType (oldType) << " , should be " << printWasmType (newType) << " )\n " ;
618643 parent.valid = false ;
619644 }
620645 curr->type = oldType;
@@ -625,7 +650,14 @@ void WasmValidator::validateBinaryenIR(Module& wasm) {
625650 binaryenIRValidator.walkModule (&wasm);
626651}
627652
628- std::ostream& WasmValidator::fail () {
653+ template <typename T, typename S>
654+ std::ostream& WasmValidator::fail (T curr, S text) {
655+ valid = false ;
656+ auto & ret = printFailureHeader () << text << " , on \n " ;
657+ return printModuleComponent (curr, ret);
658+ }
659+
660+ std::ostream& WasmValidator::printFailureHeader () {
629661 Colors::red (std::cerr);
630662 if (getFunction ()) {
631663 std::cerr << " [wasm-validator error in function " ;
0 commit comments