summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2020-07-31 15:45:47 -0700
committerGitHub <noreply@github.com>2020-07-31 15:45:47 -0700
commitae56f9919a7263c7f8df00f0552ee0f302f8d286 (patch)
treea9e970b286be3ab20fa8bd8e4e418e81582a2320
parentd09c607ff2f2c264546b7d4ea3593ae75a037750 (diff)
downloadbinaryen-ae56f9919a7263c7f8df00f0552ee0f302f8d286.tar.gz
binaryen-ae56f9919a7263c7f8df00f0552ee0f302f8d286.tar.bz2
binaryen-ae56f9919a7263c7f8df00f0552ee0f302f8d286.zip
AlignmentLowering: Handle all possible cases for i64, f32, f64 (#3008)
Previously we only handled i32. That was enough for all real-world code people have run through wasm2js apparently (which is the only place the pass is needed - it lowers unaligned loads to individual loads etc., as unaligned operations fail in JS). Apparently it's pretty rare to have unaligned f32 loads for example. This will be useful in fuzzing wasm2js, as without this we can't compare results to the interpreter (which does alignment properly).
-rw-r--r--src/passes/AlignmentLowering.cpp178
-rw-r--r--test/passes/alignment-lowering.txt1422
-rw-r--r--test/passes/alignment-lowering.wast40
3 files changed, 1613 insertions, 27 deletions
diff --git a/src/passes/AlignmentLowering.cpp b/src/passes/AlignmentLowering.cpp
index 818189056..26815b389 100644
--- a/src/passes/AlignmentLowering.cpp
+++ b/src/passes/AlignmentLowering.cpp
@@ -27,16 +27,15 @@
namespace wasm {
struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
- void visitLoad(Load* curr) {
+ // Core lowering of a 32-bit load: ensures it is done using aligned
+ // operations, which means we can leave it alone if it's already aligned, or
+ // else we break it up into smaller loads that are.
+ Expression* lowerLoadI32(Load* curr) {
if (curr->align == 0 || curr->align == curr->bytes) {
- return;
+ return curr;
}
Builder builder(*getModule());
- if (curr->type == Type::unreachable) {
- replaceCurrent(curr->ptr);
- return;
- }
- assert(curr->type == Type::i32); // TODO: i64, f32, f64
+ assert(curr->type == Type::i32);
auto temp = builder.addVar(getFunction(), Type::i32);
Expression* ret;
if (curr->bytes == 2) {
@@ -125,21 +124,16 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
} else {
WASM_UNREACHABLE("invalid size");
}
- replaceCurrent(
- builder.makeBlock({builder.makeLocalSet(temp, curr->ptr), ret}));
+ return builder.makeBlock({builder.makeLocalSet(temp, curr->ptr), ret});
}
- void visitStore(Store* curr) {
+ // Core lowering of a 32-bit store.
+ Expression* lowerStoreI32(Store* curr) {
if (curr->align == 0 || curr->align == curr->bytes) {
- return;
+ return curr;
}
Builder builder(*getModule());
- if (curr->type == Type::unreachable) {
- replaceCurrent(builder.makeBlock(
- {builder.makeDrop(curr->ptr), builder.makeDrop(curr->value)}));
- return;
- }
- assert(curr->value->type == Type::i32); // TODO: i64, f32, f64
+ assert(curr->value->type == Type::i32);
auto tempPtr = builder.addVar(getFunction(), Type::i32);
auto tempValue = builder.addVar(getFunction(), Type::i32);
auto* block =
@@ -222,7 +216,155 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
WASM_UNREACHABLE("invalid size");
}
block->finalize();
- replaceCurrent(block);
+ return block;
+ }
+
+ void visitLoad(Load* curr) {
+ // If unreachable, just remove the load, which removes the unaligned
+ // operation in a trivial way.
+ if (curr->type == Type::unreachable) {
+ replaceCurrent(curr->ptr);
+ return;
+ }
+ if (curr->align == 0 || curr->align == curr->bytes) {
+ // Nothing to do: leave the node unchanged. All code lower down assumes
+ // the operation is unaligned.
+ return;
+ }
+ Builder builder(*getModule());
+ auto type = curr->type.getSingle();
+ Expression* replacement;
+ switch (type) {
+ default:
+ WASM_UNREACHABLE("unhandled unaligned load");
+ case Type::i32:
+ replacement = lowerLoadI32(curr);
+ break;
+ case Type::f32:
+ curr->type = Type::i32;
+ replacement = builder.makeUnary(ReinterpretInt32, lowerLoadI32(curr));
+ break;
+ case Type::i64:
+ case Type::f64:
+ if (type == Type::i64 && curr->bytes != 8) {
+ // A load of <64 bits.
+ curr->type = Type::i32;
+ replacement = builder.makeUnary(
+ curr->signed_ ? ExtendSInt32 : ExtendUInt32, lowerLoadI32(curr));
+ break;
+ }
+ // Load two 32-bit pieces, and combine them.
+ auto temp = builder.addVar(getFunction(), Type::i32);
+ auto* set = builder.makeLocalSet(temp, curr->ptr);
+ Expression* low =
+ lowerLoadI32(builder.makeLoad(4,
+ false,
+ curr->offset,
+ curr->align,
+ builder.makeLocalGet(temp, Type::i32),
+ Type::i32));
+ low = builder.makeUnary(ExtendUInt32, low);
+ // Note that the alignment is assumed to be the same here, even though
+ // we add an offset of 4. That is because this is an unaligned load, so
+ // the alignment is 1, 2, or 4, which means it stays the same after
+ // adding 4.
+ Expression* high =
+ lowerLoadI32(builder.makeLoad(4,
+ false,
+ curr->offset + 4,
+ curr->align,
+ builder.makeLocalGet(temp, Type::i32),
+ Type::i32));
+ high = builder.makeUnary(ExtendUInt32, high);
+ high =
+ builder.makeBinary(ShlInt64, high, builder.makeConst(int64_t(32)));
+ auto* combined = builder.makeBinary(OrInt64, low, high);
+ replacement = builder.makeSequence(set, combined);
+ // Ensure the proper output type.
+ if (type == Type::f64) {
+ replacement = builder.makeUnary(ReinterpretInt64, replacement);
+ }
+ break;
+ }
+ replaceCurrent(replacement);
+ }
+
+ void visitStore(Store* curr) {
+ Builder builder(*getModule());
+ // If unreachable, just remove the store, which removes the unaligned
+ // operation in a trivial way.
+ if (curr->type == Type::unreachable) {
+ replaceCurrent(builder.makeBlock(
+ {builder.makeDrop(curr->ptr), builder.makeDrop(curr->value)}));
+ return;
+ }
+ if (curr->align == 0 || curr->align == curr->bytes) {
+ // Nothing to do: leave the node unchanged. All code lower down assumes
+ // the operation is unaligned.
+ return;
+ }
+ auto type = curr->value->type.getSingle();
+ Expression* replacement;
+ switch (type) {
+ default:
+ WASM_UNREACHABLE("unhandled unaligned store");
+ case Type::i32:
+ replacement = lowerStoreI32(curr);
+ break;
+ case Type::f32:
+ curr->type = Type::i32;
+ curr->value = builder.makeUnary(ReinterpretFloat32, curr->value);
+ replacement = lowerStoreI32(curr);
+ break;
+ case Type::i64:
+ case Type::f64:
+ if (type == Type::i64 && curr->bytes != 8) {
+ // A store of <64 bits.
+ curr->type = Type::i32;
+ curr->value = builder.makeUnary(WrapInt64, curr->value);
+ replacement = lowerStoreI32(curr);
+ break;
+ }
+ // Otherwise, fall through to f64 case for a 64-bit load.
+ // Ensure an integer input value.
+ auto* value = curr->value;
+ if (type == Type::f64) {
+ value = builder.makeUnary(ReinterpretFloat64, value);
+ }
+ // Store as two 32-bit pieces.
+ auto tempPtr = builder.addVar(getFunction(), Type::i32);
+ auto* setPtr = builder.makeLocalSet(tempPtr, curr->ptr);
+ auto tempValue = builder.addVar(getFunction(), Type::i64);
+ auto* setValue = builder.makeLocalSet(tempValue, value);
+ Expression* low = builder.makeUnary(
+ WrapInt64, builder.makeLocalGet(tempValue, Type::i64));
+ low = lowerStoreI32(
+ builder.makeStore(4,
+ curr->offset,
+ curr->align,
+ builder.makeLocalGet(tempPtr, Type::i32),
+ low,
+ Type::i32));
+ Expression* high =
+ builder.makeBinary(ShrUInt64,
+ builder.makeLocalGet(tempValue, Type::i64),
+ builder.makeConst(int64_t(32)));
+ high = builder.makeUnary(WrapInt64, high);
+ // Note that the alignment is assumed to be the same here, even though
+ // we add an offset of 4. That is because this is an unaligned store, so
+ // the alignment is 1, 2, or 4, which means it stays the same after
+ // adding 4.
+ high = lowerStoreI32(
+ builder.makeStore(4,
+ curr->offset + 4,
+ curr->align,
+ builder.makeLocalGet(tempPtr, Type::i32),
+ high,
+ Type::i32));
+ replacement = builder.makeBlock({setPtr, setValue, low, high});
+ break;
+ }
+ replaceCurrent(replacement);
}
};
diff --git a/test/passes/alignment-lowering.txt b/test/passes/alignment-lowering.txt
index b3e276a9f..0ea97136f 100644
--- a/test/passes/alignment-lowering.txt
+++ b/test/passes/alignment-lowering.txt
@@ -437,9 +437,7 @@
)
)
(drop
- (i32.load offset=100
- (unreachable)
- )
+ (unreachable)
)
(i32.store8
(i32.const 4)
@@ -457,13 +455,21 @@
(i32.const 4)
(i32.const 8)
)
- (i32.store8 offset=100
- (unreachable)
- (i32.const 8)
+ (block
+ (drop
+ (unreachable)
+ )
+ (drop
+ (i32.const 8)
+ )
)
- (i32.store8 offset=100
- (i32.const 4)
- (unreachable)
+ (block
+ (drop
+ (i32.const 4)
+ )
+ (drop
+ (unreachable)
+ )
)
)
(func $func_signed
@@ -541,4 +547,1402 @@
(unreachable)
)
)
+ (func $i64-load
+ (local $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (local $6 i32)
+ (local $7 i32)
+ (local $8 i32)
+ (local $9 i32)
+ (local $10 i32)
+ (local $11 i32)
+ (local $12 i32)
+ (local $13 i32)
+ (drop
+ (block (result i64)
+ (local.set $0
+ (i32.const 12)
+ )
+ (i64.or
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $1
+ (local.get $0)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u
+ (local.get $1)
+ )
+ (i32.shl
+ (i32.load8_u offset=1
+ (local.get $1)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=2
+ (local.get $1)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=3
+ (local.get $1)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ (i64.shl
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $2
+ (local.get $0)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u offset=4
+ (local.get $2)
+ )
+ (i32.shl
+ (i32.load8_u offset=5
+ (local.get $2)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=6
+ (local.get $2)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=7
+ (local.get $2)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ (drop
+ (block (result i64)
+ (local.set $3
+ (i32.const 16)
+ )
+ (i64.or
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $4
+ (local.get $3)
+ )
+ (i32.or
+ (i32.load16_u
+ (local.get $4)
+ )
+ (i32.shl
+ (i32.load16_u offset=2
+ (local.get $4)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
+ (i64.shl
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $5
+ (local.get $3)
+ )
+ (i32.or
+ (i32.load16_u offset=4
+ (local.get $5)
+ )
+ (i32.shl
+ (i32.load16_u offset=6
+ (local.get $5)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ (drop
+ (block (result i64)
+ (local.set $6
+ (i32.const 20)
+ )
+ (i64.or
+ (i64.extend_i32_u
+ (i32.load
+ (local.get $6)
+ )
+ )
+ (i64.shl
+ (i64.extend_i32_u
+ (i32.load offset=4
+ (local.get $6)
+ )
+ )
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ (drop
+ (block (result i64)
+ (local.set $7
+ (i32.const 20)
+ )
+ (i64.or
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $8
+ (local.get $7)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u offset=3
+ (local.get $8)
+ )
+ (i32.shl
+ (i32.load8_u offset=4
+ (local.get $8)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=5
+ (local.get $8)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=6
+ (local.get $8)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ (i64.shl
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $9
+ (local.get $7)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u offset=7
+ (local.get $9)
+ )
+ (i32.shl
+ (i32.load8_u offset=8
+ (local.get $9)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=9
+ (local.get $9)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=10
+ (local.get $9)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ (drop
+ (i64.extend_i32_s
+ (block (result i32)
+ (local.set $10
+ (i32.const 28)
+ )
+ (i32.shr_s
+ (i32.shl
+ (i32.or
+ (i32.load8_u
+ (local.get $10)
+ )
+ (i32.shl
+ (i32.load8_u offset=1
+ (local.get $10)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.const 16)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
+ (drop
+ (i64.extend_i32_s
+ (block (result i32)
+ (local.set $11
+ (i32.const 32)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u
+ (local.get $11)
+ )
+ (i32.shl
+ (i32.load8_u offset=1
+ (local.get $11)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=2
+ (local.get $11)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=3
+ (local.get $11)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ )
+ (drop
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $12
+ (i32.const 40)
+ )
+ (i32.or
+ (i32.load8_u
+ (local.get $12)
+ )
+ (i32.shl
+ (i32.load8_u offset=1
+ (local.get $12)
+ )
+ (i32.const 8)
+ )
+ )
+ )
+ )
+ )
+ (drop
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $13
+ (i32.const 44)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u
+ (local.get $13)
+ )
+ (i32.shl
+ (i32.load8_u offset=1
+ (local.get $13)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=2
+ (local.get $13)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=3
+ (local.get $13)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ (func $f32-load
+ (local $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (drop
+ (f32.reinterpret_i32
+ (block (result i32)
+ (local.set $0
+ (i32.const 12)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u
+ (local.get $0)
+ )
+ (i32.shl
+ (i32.load8_u offset=1
+ (local.get $0)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=2
+ (local.get $0)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=3
+ (local.get $0)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ )
+ (drop
+ (f32.reinterpret_i32
+ (block (result i32)
+ (local.set $1
+ (i32.const 16)
+ )
+ (i32.or
+ (i32.load16_u
+ (local.get $1)
+ )
+ (i32.shl
+ (i32.load16_u offset=2
+ (local.get $1)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
+ )
+ (drop
+ (f32.reinterpret_i32
+ (block (result i32)
+ (local.set $2
+ (i32.const 20)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u offset=3
+ (local.get $2)
+ )
+ (i32.shl
+ (i32.load8_u offset=4
+ (local.get $2)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=5
+ (local.get $2)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=6
+ (local.get $2)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ (func $f64-load
+ (local $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (local $6 i32)
+ (local $7 i32)
+ (local $8 i32)
+ (local $9 i32)
+ (drop
+ (f64.reinterpret_i64
+ (block (result i64)
+ (local.set $0
+ (i32.const 12)
+ )
+ (i64.or
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $1
+ (local.get $0)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u
+ (local.get $1)
+ )
+ (i32.shl
+ (i32.load8_u offset=1
+ (local.get $1)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=2
+ (local.get $1)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=3
+ (local.get $1)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ (i64.shl
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $2
+ (local.get $0)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u offset=4
+ (local.get $2)
+ )
+ (i32.shl
+ (i32.load8_u offset=5
+ (local.get $2)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=6
+ (local.get $2)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=7
+ (local.get $2)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ )
+ (drop
+ (f64.reinterpret_i64
+ (block (result i64)
+ (local.set $3
+ (i32.const 16)
+ )
+ (i64.or
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $4
+ (local.get $3)
+ )
+ (i32.or
+ (i32.load16_u
+ (local.get $4)
+ )
+ (i32.shl
+ (i32.load16_u offset=2
+ (local.get $4)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
+ (i64.shl
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $5
+ (local.get $3)
+ )
+ (i32.or
+ (i32.load16_u offset=4
+ (local.get $5)
+ )
+ (i32.shl
+ (i32.load16_u offset=6
+ (local.get $5)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ )
+ (drop
+ (f64.reinterpret_i64
+ (block (result i64)
+ (local.set $6
+ (i32.const 20)
+ )
+ (i64.or
+ (i64.extend_i32_u
+ (i32.load
+ (local.get $6)
+ )
+ )
+ (i64.shl
+ (i64.extend_i32_u
+ (i32.load offset=4
+ (local.get $6)
+ )
+ )
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ )
+ (drop
+ (f64.reinterpret_i64
+ (block (result i64)
+ (local.set $7
+ (i32.const 20)
+ )
+ (i64.or
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $8
+ (local.get $7)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u offset=3
+ (local.get $8)
+ )
+ (i32.shl
+ (i32.load8_u offset=4
+ (local.get $8)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=5
+ (local.get $8)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=6
+ (local.get $8)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ (i64.shl
+ (i64.extend_i32_u
+ (block (result i32)
+ (local.set $9
+ (local.get $7)
+ )
+ (i32.or
+ (i32.or
+ (i32.load8_u offset=7
+ (local.get $9)
+ )
+ (i32.shl
+ (i32.load8_u offset=8
+ (local.get $9)
+ )
+ (i32.const 8)
+ )
+ )
+ (i32.or
+ (i32.shl
+ (i32.load8_u offset=9
+ (local.get $9)
+ )
+ (i32.const 16)
+ )
+ (i32.shl
+ (i32.load8_u offset=10
+ (local.get $9)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ )
+ )
+ (func $i64-store
+ (local $0 i32)
+ (local $1 i64)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (local $6 i32)
+ (local $7 i64)
+ (local $8 i32)
+ (local $9 i32)
+ (local $10 i32)
+ (local $11 i32)
+ (local $12 i32)
+ (local $13 i64)
+ (local $14 i32)
+ (local $15 i64)
+ (local $16 i32)
+ (local $17 i32)
+ (local $18 i32)
+ (local $19 i32)
+ (local $20 i32)
+ (local $21 i32)
+ (local $22 i32)
+ (local $23 i32)
+ (block
+ (local.set $0
+ (i32.const 12)
+ )
+ (local.set $1
+ (i64.const 100)
+ )
+ (block
+ (local.set $2
+ (local.get $0)
+ )
+ (local.set $3
+ (i32.wrap_i64
+ (local.get $1)
+ )
+ )
+ (i32.store8
+ (local.get $2)
+ (local.get $3)
+ )
+ (i32.store8 offset=1
+ (local.get $2)
+ (i32.shr_u
+ (local.get $3)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=2
+ (local.get $2)
+ (i32.shr_u
+ (local.get $3)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=3
+ (local.get $2)
+ (i32.shr_u
+ (local.get $3)
+ (i32.const 24)
+ )
+ )
+ )
+ (block
+ (local.set $4
+ (local.get $0)
+ )
+ (local.set $5
+ (i32.wrap_i64
+ (i64.shr_u
+ (local.get $1)
+ (i64.const 32)
+ )
+ )
+ )
+ (i32.store8 offset=4
+ (local.get $4)
+ (local.get $5)
+ )
+ (i32.store8 offset=5
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=6
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=7
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ (block
+ (local.set $6
+ (i32.const 16)
+ )
+ (local.set $7
+ (i64.const 200)
+ )
+ (block
+ (local.set $8
+ (local.get $6)
+ )
+ (local.set $9
+ (i32.wrap_i64
+ (local.get $7)
+ )
+ )
+ (i32.store16
+ (local.get $8)
+ (local.get $9)
+ )
+ (i32.store16 offset=2
+ (local.get $8)
+ (i32.shr_u
+ (local.get $9)
+ (i32.const 16)
+ )
+ )
+ )
+ (block
+ (local.set $10
+ (local.get $6)
+ )
+ (local.set $11
+ (i32.wrap_i64
+ (i64.shr_u
+ (local.get $7)
+ (i64.const 32)
+ )
+ )
+ )
+ (i32.store16 offset=4
+ (local.get $10)
+ (local.get $11)
+ )
+ (i32.store16 offset=6
+ (local.get $10)
+ (i32.shr_u
+ (local.get $11)
+ (i32.const 16)
+ )
+ )
+ )
+ )
+ (block
+ (local.set $12
+ (i32.const 20)
+ )
+ (local.set $13
+ (i64.const 300)
+ )
+ (i32.store
+ (local.get $12)
+ (i32.wrap_i64
+ (local.get $13)
+ )
+ )
+ (i32.store offset=4
+ (local.get $12)
+ (i32.wrap_i64
+ (i64.shr_u
+ (local.get $13)
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ (block
+ (local.set $14
+ (i32.const 24)
+ )
+ (local.set $15
+ (i64.const 400)
+ )
+ (block
+ (local.set $16
+ (local.get $14)
+ )
+ (local.set $17
+ (i32.wrap_i64
+ (local.get $15)
+ )
+ )
+ (i32.store8 offset=3
+ (local.get $16)
+ (local.get $17)
+ )
+ (i32.store8 offset=4
+ (local.get $16)
+ (i32.shr_u
+ (local.get $17)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=5
+ (local.get $16)
+ (i32.shr_u
+ (local.get $17)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=6
+ (local.get $16)
+ (i32.shr_u
+ (local.get $17)
+ (i32.const 24)
+ )
+ )
+ )
+ (block
+ (local.set $18
+ (local.get $14)
+ )
+ (local.set $19
+ (i32.wrap_i64
+ (i64.shr_u
+ (local.get $15)
+ (i64.const 32)
+ )
+ )
+ )
+ (i32.store8 offset=7
+ (local.get $18)
+ (local.get $19)
+ )
+ (i32.store8 offset=8
+ (local.get $18)
+ (i32.shr_u
+ (local.get $19)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=9
+ (local.get $18)
+ (i32.shr_u
+ (local.get $19)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=10
+ (local.get $18)
+ (i32.shr_u
+ (local.get $19)
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ (block
+ (local.set $20
+ (i32.const 20)
+ )
+ (local.set $21
+ (i32.wrap_i64
+ (i64.const 600)
+ )
+ )
+ (i32.store8
+ (local.get $20)
+ (local.get $21)
+ )
+ (i32.store8 offset=1
+ (local.get $20)
+ (i32.shr_u
+ (local.get $21)
+ (i32.const 8)
+ )
+ )
+ )
+ (block
+ (local.set $22
+ (i32.const 20)
+ )
+ (local.set $23
+ (i32.wrap_i64
+ (i64.const 700)
+ )
+ )
+ (i32.store8
+ (local.get $22)
+ (local.get $23)
+ )
+ (i32.store8 offset=1
+ (local.get $22)
+ (i32.shr_u
+ (local.get $23)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=2
+ (local.get $22)
+ (i32.shr_u
+ (local.get $23)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=3
+ (local.get $22)
+ (i32.shr_u
+ (local.get $23)
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ (func $f32-store
+ (local $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (block
+ (local.set $0
+ (i32.const 12)
+ )
+ (local.set $1
+ (i32.reinterpret_f32
+ (f32.const 100)
+ )
+ )
+ (i32.store8
+ (local.get $0)
+ (local.get $1)
+ )
+ (i32.store8 offset=1
+ (local.get $0)
+ (i32.shr_u
+ (local.get $1)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=2
+ (local.get $0)
+ (i32.shr_u
+ (local.get $1)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=3
+ (local.get $0)
+ (i32.shr_u
+ (local.get $1)
+ (i32.const 24)
+ )
+ )
+ )
+ (block
+ (local.set $2
+ (i32.const 16)
+ )
+ (local.set $3
+ (i32.reinterpret_f32
+ (f32.const 200)
+ )
+ )
+ (i32.store16
+ (local.get $2)
+ (local.get $3)
+ )
+ (i32.store16 offset=2
+ (local.get $2)
+ (i32.shr_u
+ (local.get $3)
+ (i32.const 16)
+ )
+ )
+ )
+ (block
+ (local.set $4
+ (i32.const 24)
+ )
+ (local.set $5
+ (i32.reinterpret_f32
+ (f32.const 400)
+ )
+ )
+ (i32.store8 offset=3
+ (local.get $4)
+ (local.get $5)
+ )
+ (i32.store8 offset=4
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=5
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=6
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ (func $f64-store
+ (local $0 i32)
+ (local $1 i64)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (local $6 i32)
+ (local $7 i64)
+ (local $8 i32)
+ (local $9 i32)
+ (local $10 i32)
+ (local $11 i32)
+ (local $12 i32)
+ (local $13 i64)
+ (local $14 i32)
+ (local $15 i64)
+ (local $16 i32)
+ (local $17 i32)
+ (local $18 i32)
+ (local $19 i32)
+ (block
+ (local.set $0
+ (i32.const 12)
+ )
+ (local.set $1
+ (i64.reinterpret_f64
+ (f64.const 100)
+ )
+ )
+ (block
+ (local.set $2
+ (local.get $0)
+ )
+ (local.set $3
+ (i32.wrap_i64
+ (local.get $1)
+ )
+ )
+ (i32.store8
+ (local.get $2)
+ (local.get $3)
+ )
+ (i32.store8 offset=1
+ (local.get $2)
+ (i32.shr_u
+ (local.get $3)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=2
+ (local.get $2)
+ (i32.shr_u
+ (local.get $3)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=3
+ (local.get $2)
+ (i32.shr_u
+ (local.get $3)
+ (i32.const 24)
+ )
+ )
+ )
+ (block
+ (local.set $4
+ (local.get $0)
+ )
+ (local.set $5
+ (i32.wrap_i64
+ (i64.shr_u
+ (local.get $1)
+ (i64.const 32)
+ )
+ )
+ )
+ (i32.store8 offset=4
+ (local.get $4)
+ (local.get $5)
+ )
+ (i32.store8 offset=5
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=6
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=7
+ (local.get $4)
+ (i32.shr_u
+ (local.get $5)
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ (block
+ (local.set $6
+ (i32.const 16)
+ )
+ (local.set $7
+ (i64.reinterpret_f64
+ (f64.const 200)
+ )
+ )
+ (block
+ (local.set $8
+ (local.get $6)
+ )
+ (local.set $9
+ (i32.wrap_i64
+ (local.get $7)
+ )
+ )
+ (i32.store16
+ (local.get $8)
+ (local.get $9)
+ )
+ (i32.store16 offset=2
+ (local.get $8)
+ (i32.shr_u
+ (local.get $9)
+ (i32.const 16)
+ )
+ )
+ )
+ (block
+ (local.set $10
+ (local.get $6)
+ )
+ (local.set $11
+ (i32.wrap_i64
+ (i64.shr_u
+ (local.get $7)
+ (i64.const 32)
+ )
+ )
+ )
+ (i32.store16 offset=4
+ (local.get $10)
+ (local.get $11)
+ )
+ (i32.store16 offset=6
+ (local.get $10)
+ (i32.shr_u
+ (local.get $11)
+ (i32.const 16)
+ )
+ )
+ )
+ )
+ (block
+ (local.set $12
+ (i32.const 20)
+ )
+ (local.set $13
+ (i64.reinterpret_f64
+ (f64.const 300)
+ )
+ )
+ (i32.store
+ (local.get $12)
+ (i32.wrap_i64
+ (local.get $13)
+ )
+ )
+ (i32.store offset=4
+ (local.get $12)
+ (i32.wrap_i64
+ (i64.shr_u
+ (local.get $13)
+ (i64.const 32)
+ )
+ )
+ )
+ )
+ (block
+ (local.set $14
+ (i32.const 24)
+ )
+ (local.set $15
+ (i64.reinterpret_f64
+ (f64.const 400)
+ )
+ )
+ (block
+ (local.set $16
+ (local.get $14)
+ )
+ (local.set $17
+ (i32.wrap_i64
+ (local.get $15)
+ )
+ )
+ (i32.store8 offset=3
+ (local.get $16)
+ (local.get $17)
+ )
+ (i32.store8 offset=4
+ (local.get $16)
+ (i32.shr_u
+ (local.get $17)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=5
+ (local.get $16)
+ (i32.shr_u
+ (local.get $17)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=6
+ (local.get $16)
+ (i32.shr_u
+ (local.get $17)
+ (i32.const 24)
+ )
+ )
+ )
+ (block
+ (local.set $18
+ (local.get $14)
+ )
+ (local.set $19
+ (i32.wrap_i64
+ (i64.shr_u
+ (local.get $15)
+ (i64.const 32)
+ )
+ )
+ )
+ (i32.store8 offset=7
+ (local.get $18)
+ (local.get $19)
+ )
+ (i32.store8 offset=8
+ (local.get $18)
+ (i32.shr_u
+ (local.get $19)
+ (i32.const 8)
+ )
+ )
+ (i32.store8 offset=9
+ (local.get $18)
+ (i32.shr_u
+ (local.get $19)
+ (i32.const 16)
+ )
+ )
+ (i32.store8 offset=10
+ (local.get $18)
+ (i32.shr_u
+ (local.get $19)
+ (i32.const 24)
+ )
+ )
+ )
+ )
+ )
)
diff --git a/test/passes/alignment-lowering.wast b/test/passes/alignment-lowering.wast
index 135fd281e..bbfdd5cb2 100644
--- a/test/passes/alignment-lowering.wast
+++ b/test/passes/alignment-lowering.wast
@@ -60,4 +60,44 @@
(drop (i32.load16_s offset=100 align=2 (i32.const 4)))
(drop (i32.load16_s offset=100 align=1 (unreachable)))
)
+ (func $i64-load
+ (drop (i64.load align=1 (i32.const 12)))
+ (drop (i64.load align=2 (i32.const 16)))
+ (drop (i64.load align=4 (i32.const 20)))
+ (drop (i64.load align=1 offset=3 (i32.const 20)))
+ (drop (i64.load16_s align=1 (i32.const 28)))
+ (drop (i64.load32_s align=1 (i32.const 32)))
+ (drop (i64.load16_u align=1 (i32.const 40)))
+ (drop (i64.load32_u align=1 (i32.const 44)))
+ )
+ (func $f32-load
+ (drop (f32.load align=1 (i32.const 12)))
+ (drop (f32.load align=2 (i32.const 16)))
+ (drop (f32.load align=1 offset=3 (i32.const 20)))
+ )
+ (func $f64-load
+ (drop (f64.load align=1 (i32.const 12)))
+ (drop (f64.load align=2 (i32.const 16)))
+ (drop (f64.load align=4 (i32.const 20)))
+ (drop (f64.load align=1 offset=3 (i32.const 20)))
+ )
+ (func $i64-store
+ (i64.store align=1 (i32.const 12) (i64.const 100))
+ (i64.store align=2 (i32.const 16) (i64.const 200))
+ (i64.store align=4 (i32.const 20) (i64.const 300))
+ (i64.store align=1 offset=3 (i32.const 24) (i64.const 400))
+ (i64.store16 align=1 (i32.const 20) (i64.const 600))
+ (i64.store32 align=1 (i32.const 20) (i64.const 700))
+ )
+ (func $f32-store
+ (f32.store align=1 (i32.const 12) (f32.const 100))
+ (f32.store align=2 (i32.const 16) (f32.const 200))
+ (f32.store align=1 offset=3 (i32.const 24) (f32.const 400))
+ )
+ (func $f64-store
+ (f64.store align=1 (i32.const 12) (f64.const 100))
+ (f64.store align=2 (i32.const 16) (f64.const 200))
+ (f64.store align=4 (i32.const 20) (f64.const 300))
+ (f64.store align=1 offset=3 (i32.const 24) (f64.const 400))
+ )
)