diff --git a/src/ir/bits.h b/src/ir/bits.h index e8f2b4f50cc..6add10a8be9 100644 --- a/src/ir/bits.h +++ b/src/ir/bits.h @@ -456,6 +456,10 @@ Index getMaxBits(Expression* curr, if (LoadUtils::isSignRelevant(load) && !load->signed_) { return 8 * load->bytes; } + } else if (auto* block = curr->dynCast()) { + if (!block->name.is() && !block->list.empty() && block->type.isConcrete()) { + return getMaxBits(block->list.back(), localInfoProvider); + } } switch (curr->type.getBasic()) { case Type::i32: diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index a8a2c6bf5bc..17c2553f265 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2586,8 +2586,13 @@ struct OptimizeInstructions } Index getMaxBitsForLocal(LocalGet* get) { - // check what we know about the local - return localInfo[get->index].maxBits; + // check what we know about the local (we may know nothing, if this local + // was added after the pass scanned for locals; in that case, full + // optimization may require another cycle) + if (get->index < localInfo.size()) { + return localInfo[get->index].maxBits; + } + return getBitsForType(get->type); } private: diff --git a/test/lit/passes/optimize-instructions-mvp.wast b/test/lit/passes/optimize-instructions-mvp.wast index 7b5551a67a9..19b3d94529b 100644 --- a/test/lit/passes/optimize-instructions-mvp.wast +++ b/test/lit/passes/optimize-instructions-mvp.wast @@ -8412,36 +8412,129 @@ (i32.const 0) ) ) - ;; CHECK: (func $andZero (param $0 i32) (result i32) + ;; CHECK: (func $andZero (param $0 i32) (param $1 i64) (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i64) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (i64.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (call $andZero - ;; CHECK-NEXT: (i32.const 1234) + ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i64) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (i64.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i64) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (i64.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - (func $andZero (param $0 i32) (result i32) + (func $andZero (param $0 i32) (param $1 i64) (result i32) (drop (i32.and (local.get $0) (i32.const 0) ) ) + (drop + (i64.and + (local.get $1) + (i64.const 0) + ) + ) + ;; side effects. we must keep the tee, but + ;; can drop it. (drop (i32.and - (call $andZero (i32.const 1234)) ;; side effects, we must keep this, but - ;; can drop it. + (local.tee $0 + (i32.const 1) + ) (i32.const 0) ) ) + (drop + (i64.and + (local.tee $1 + (i64.const 1) + ) + (i64.const 0) + ) + ) + ;; We can optimize out the |and| even if the 0 is at the end of a block. + (drop + (i32.and + (local.tee $0 + (i32.const 1) + ) + (block (result i32) + (local.set $0 + (i32.const 1) + ) + (i32.const 0) + ) + ) + ) + (drop + (i64.and + (local.tee $1 + (i64.const 1) + ) + (block (result i64) + (local.set $1 + (i64.const 1) + ) + (i64.const 0) + ) + ) + ) (unreachable) ) ;; CHECK: (func $abstract-additions (param $x32 i32) (param $x64 i64) (param $y32 f32) (param $y64 f64)