diff --git a/src/compiler.ts b/src/compiler.ts index d3a5525164..7e87baf7fd 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -4574,19 +4574,31 @@ export class Compiler extends DiagnosticEmitter { } leftExpr = this.convertExpression(leftExpr, leftType, commonType, false, left); leftType = commonType; + + // This is sometimes needed to make the left trivial + let leftPrecompExpr = module.runExpression(leftExpr, ExpressionRunnerFlags.PreserveSideeffects); + if (leftPrecompExpr) leftExpr = leftPrecompExpr; + rightExpr = this.convertExpression(rightExpr, rightType, commonType, false, right); rightType = commonType; - // simplify if copying left is trivial - if (expr = module.tryCopyTrivialExpression(leftExpr)) { + let condExpr = this.makeIsTrueish(leftExpr, this.currentType, left); + let condKind = this.evaluateCondition(condExpr); + + if (condKind != ConditionKind.Unknown) { + // simplify if left is a constant + expr = condKind == ConditionKind.True + ? rightExpr + : leftExpr; + } else if (expr = module.tryCopyTrivialExpression(leftExpr)) { + // simplify if copying left is trivial expr = module.if( - this.makeIsTrueish(leftExpr, this.currentType, left), + condExpr, rightExpr, expr ); - - // if not possible, tee left to a temp } else { + // if not possible, tee left to a temp let tempLocal = flow.getTempLocal(leftType); if (!flow.canOverflow(leftExpr, leftType)) flow.setLocalFlag(tempLocal.index, LocalFlags.Wrapped); if (flow.isNonnull(leftExpr, leftType)) flow.setLocalFlag(tempLocal.index, LocalFlags.NonNull); @@ -4654,19 +4666,31 @@ export class Compiler extends DiagnosticEmitter { let possiblyNull = leftType.is(TypeFlags.Nullable) && rightType.is(TypeFlags.Nullable); leftExpr = this.convertExpression(leftExpr, leftType, commonType, false, left); leftType = commonType; + + // This is sometimes needed to make the left trivial + let leftPrecompExpr = module.runExpression(leftExpr, ExpressionRunnerFlags.PreserveSideeffects); + if (leftPrecompExpr) leftExpr = leftPrecompExpr; + rightExpr = this.convertExpression(rightExpr, rightType, commonType, false, right); rightType = commonType; - // simplify if copying left is trivial - if (expr = module.tryCopyTrivialExpression(leftExpr)) { + let condExpr = this.makeIsTrueish(leftExpr, this.currentType, left); + let condKind = this.evaluateCondition(condExpr); + + if (condKind != ConditionKind.Unknown) { + // simplify if left is a constant + expr = condKind == ConditionKind.True + ? leftExpr + : rightExpr; + } else if (expr = module.tryCopyTrivialExpression(leftExpr)) { + // otherwise, simplify if copying left is trivial expr = module.if( - this.makeIsTrueish(leftExpr, leftType, left), + condExpr, expr, rightExpr ); - - // if not possible, tee left to a temp. local } else { + // if not possible, tee left to a temp. local let temp = flow.getTempLocal(leftType); let tempIndex = temp.index; if (!flow.canOverflow(leftExpr, leftType)) flow.setLocalFlag(tempIndex, LocalFlags.Wrapped); diff --git a/tests/compiler/logical.debug.wat b/tests/compiler/logical.debug.wat index 78f3bc8b0e..d5fc0a82e6 100644 --- a/tests/compiler/logical.debug.wat +++ b/tests/compiler/logical.debug.wat @@ -28,6 +28,10 @@ (global $~lib/rt/itcms/fromSpace (mut i32) (i32.const 0)) (global $~lib/rt/tlsf/ROOT (mut i32) (i32.const 0)) (global $~lib/native/ASC_LOW_MEMORY_LIMIT i32 (i32.const 0)) + (global $logical/foo (mut i32) (i32.const 456)) + (global $logical/bar (mut f64) (f64.const -0)) + (global $logical/baz (mut i32) (i32.const 321)) + (global $logical/qux (mut f64) (f64.const 2.718)) (global $logical/b (mut i32) (i32.const 0)) (global $logical/c (mut i32) (i32.const 0)) (global $~lib/rt/__rtti_base i32 (i32.const 464)) @@ -47,6 +51,10 @@ (data $9 (i32.const 464) "\08\00\00\00 \00\00\00 \00\00\00 \00\00\00\00\00\00\00 \00\00\00 \00\00\00 \00\00\00 \00\00\00") (table $0 1 1 funcref) (elem $0 (i32.const 1)) + (export "foo" (global $logical/foo)) + (export "bar" (global $logical/bar)) + (export "baz" (global $logical/baz)) + (export "qux" (global $logical/qux)) (export "memory" (memory $0)) (start $~start) (func $logical/testShortcutAnd (param $a i64) (param $b i32) (result i32) @@ -2583,26 +2591,9 @@ i64.const -9007199254740994 i64.le_u drop - i32.const 1 - if (result i32) - i32.const 2 - else - i32.const 1 - end + i32.const 2 drop - f64.const 1 - i64.reinterpret_f64 - i64.const 1 - i64.shl - i64.const 2 - i64.sub - i64.const -9007199254740994 - i64.le_u - if (result f64) - f64.const 2 - else - f64.const 1 - end + f64.const 2 i64.reinterpret_f64 i64.const 1 i64.shl @@ -2611,12 +2602,7 @@ i64.const -9007199254740994 i64.le_u drop - i32.const 1 - if (result i32) - i32.const 2 - else - i32.const 1 - end + i32.const 2 global.set $logical/i global.get $logical/i i32.const 2 @@ -2630,12 +2616,7 @@ call $~lib/builtins/abort unreachable end - i32.const 0 - if (result i32) - i32.const 0 - else - i32.const 1 - end + i32.const 1 global.set $logical/i global.get $logical/i i32.const 1 @@ -2649,14 +2630,7 @@ call $~lib/builtins/abort unreachable end - i64.const 1 - i64.const 0 - i64.ne - if (result i64) - i64.const 2 - else - i64.const 1 - end + i64.const 2 global.set $logical/I global.get $logical/I i64.const 2 @@ -2670,14 +2644,7 @@ call $~lib/builtins/abort unreachable end - i64.const 0 - i64.const 0 - i64.ne - if (result i64) - i64.const 0 - else - i64.const 1 - end + i64.const 1 global.set $logical/I global.get $logical/I i64.const 1 @@ -2691,19 +2658,7 @@ call $~lib/builtins/abort unreachable end - f32.const 1 - i32.reinterpret_f32 - i32.const 1 - i32.shl - i32.const 2 - i32.sub - i32.const -16777218 - i32.le_u - if (result f32) - f32.const 2 - else - f32.const 1 - end + f32.const 2 global.set $logical/f global.get $logical/f f32.const 2 @@ -2717,19 +2672,7 @@ call $~lib/builtins/abort unreachable end - f32.const 0 - i32.reinterpret_f32 - i32.const 1 - i32.shl - i32.const 2 - i32.sub - i32.const -16777218 - i32.le_u - if (result f32) - f32.const 0 - else - f32.const 1 - end + f32.const 1 global.set $logical/f global.get $logical/f f32.const 1 @@ -2743,19 +2686,7 @@ call $~lib/builtins/abort unreachable end - f64.const 1 - i64.reinterpret_f64 - i64.const 1 - i64.shl - i64.const 2 - i64.sub - i64.const -9007199254740994 - i64.le_u - if (result f64) - f64.const 2 - else - f64.const 1 - end + f64.const 2 global.set $logical/F global.get $logical/F f64.const 2 @@ -2769,19 +2700,7 @@ call $~lib/builtins/abort unreachable end - f64.const 0 - i64.reinterpret_f64 - i64.const 1 - i64.shl - i64.const 2 - i64.sub - i64.const -9007199254740994 - i64.le_u - if (result f64) - f64.const 0 - else - f64.const 1 - end + f64.const 1 global.set $logical/F global.get $logical/F f64.const 1 @@ -2795,19 +2714,7 @@ call $~lib/builtins/abort unreachable end - f32.const nan:0x400000 - i32.reinterpret_f32 - i32.const 1 - i32.shl - i32.const 2 - i32.sub - i32.const -16777218 - i32.le_u - if (result f32) - f32.const nan:0x400000 - else - f32.const 1 - end + f32.const 1 global.set $logical/f global.get $logical/f f32.const 1 @@ -2822,18 +2729,6 @@ unreachable end f32.const 1 - i32.reinterpret_f32 - i32.const 1 - i32.shl - i32.const 2 - i32.sub - i32.const -16777218 - i32.le_u - if (result f32) - f32.const 1 - else - f32.const nan:0x400000 - end global.set $logical/f global.get $logical/f f32.const 1 @@ -2847,19 +2742,7 @@ call $~lib/builtins/abort unreachable end - f64.const nan:0x8000000000000 - i64.reinterpret_f64 - i64.const 1 - i64.shl - i64.const 2 - i64.sub - i64.const -9007199254740994 - i64.le_u - if (result f64) - f64.const nan:0x8000000000000 - else - f64.const 1 - end + f64.const 1 global.set $logical/F global.get $logical/F f64.const 1 @@ -2874,18 +2757,6 @@ unreachable end f64.const 1 - i64.reinterpret_f64 - i64.const 1 - i64.shl - i64.const 2 - i64.sub - i64.const -9007199254740994 - i64.le_u - if (result f64) - f64.const 1 - else - f64.const nan:0x8000000000000 - end global.set $logical/F global.get $logical/F f64.const 1 @@ -2899,19 +2770,7 @@ call $~lib/builtins/abort unreachable end - f32.const 1 - i32.reinterpret_f32 - i32.const 1 - i32.shl - i32.const 2 - i32.sub - i32.const -16777218 - i32.le_u - if (result f32) - f32.const nan:0x400000 - else - f32.const 1 - end + f32.const nan:0x400000 global.set $logical/f global.get $logical/f local.tee $0 @@ -2927,18 +2786,6 @@ unreachable end f32.const nan:0x400000 - i32.reinterpret_f32 - i32.const 1 - i32.shl - i32.const 2 - i32.sub - i32.const -16777218 - i32.le_u - if (result f32) - f32.const 1 - else - f32.const nan:0x400000 - end global.set $logical/f global.get $logical/f local.tee $1 @@ -2953,19 +2800,7 @@ call $~lib/builtins/abort unreachable end - f64.const 1 - i64.reinterpret_f64 - i64.const 1 - i64.shl - i64.const 2 - i64.sub - i64.const -9007199254740994 - i64.le_u - if (result f64) - f64.const nan:0x8000000000000 - else - f64.const 1 - end + f64.const nan:0x8000000000000 global.set $logical/F global.get $logical/F local.tee $2 @@ -2981,18 +2816,6 @@ unreachable end f64.const nan:0x8000000000000 - i64.reinterpret_f64 - i64.const 1 - i64.shl - i64.const 2 - i64.sub - i64.const -9007199254740994 - i64.le_u - if (result f64) - f64.const 1 - else - f64.const nan:0x8000000000000 - end global.set $logical/F global.get $logical/F local.tee $3 @@ -3111,7 +2934,7 @@ if i32.const 0 i32.const 32 - i32.const 106 + i32.const 114 i32.const 1 call $~lib/builtins/abort unreachable @@ -3124,7 +2947,7 @@ if i32.const 0 i32.const 32 - i32.const 107 + i32.const 115 i32.const 1 call $~lib/builtins/abort unreachable @@ -3142,7 +2965,7 @@ if i32.const 0 i32.const 32 - i32.const 112 + i32.const 120 i32.const 1 call $~lib/builtins/abort unreachable @@ -3155,7 +2978,7 @@ if i32.const 0 i32.const 32 - i32.const 113 + i32.const 121 i32.const 1 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/logical.release.wat b/tests/compiler/logical.release.wat index 185b69545e..a244889d24 100644 --- a/tests/compiler/logical.release.wat +++ b/tests/compiler/logical.release.wat @@ -17,6 +17,10 @@ (global $~lib/rt/itcms/white (mut i32) (i32.const 0)) (global $~lib/rt/itcms/fromSpace (mut i32) (i32.const 0)) (global $~lib/rt/tlsf/ROOT (mut i32) (i32.const 0)) + (global $logical/foo (mut i32) (i32.const 456)) + (global $logical/bar (mut f64) (f64.const -0)) + (global $logical/baz (mut i32) (i32.const 321)) + (global $logical/qux (mut f64) (f64.const 2.718)) (global $logical/b (mut i32) (i32.const 0)) (global $logical/c (mut i32) (i32.const 0)) (global $~lib/memory/__stack_pointer (mut i32) (i32.const 34292)) @@ -34,6 +38,10 @@ (data $8 (i32.const 1420) "<") (data $8.1 (i32.const 1432) "\02\00\00\00\1e\00\00\00~\00l\00i\00b\00/\00r\00t\00/\00t\00l\00s\00f\00.\00t\00s") (data $9 (i32.const 1488) "\08\00\00\00 \00\00\00 \00\00\00 \00\00\00\00\00\00\00 \00\00\00 \00\00\00 \00\00\00 ") + (export "foo" (global $logical/foo)) + (export "bar" (global $logical/bar)) + (export "baz" (global $logical/baz)) + (export "qux" (global $logical/qux)) (export "memory" (memory $0)) (start $~start) (func $~lib/rt/itcms/visitRoots @@ -1420,7 +1428,7 @@ ) (func $~start (local $0 i32) - block $__inlined_func$start:logical + block $__inlined_func$start:logical$1 global.get $~lib/memory/__stack_pointer i32.const 4 i32.sub @@ -1568,7 +1576,7 @@ if i32.const 0 i32.const 1056 - i32.const 106 + i32.const 114 i32.const 1 call $~lib/builtins/abort unreachable @@ -1586,7 +1594,7 @@ if i32.const 0 i32.const 1056 - i32.const 112 + i32.const 120 i32.const 1 call $~lib/builtins/abort unreachable @@ -1595,7 +1603,7 @@ i32.const 4 i32.add global.set $~lib/memory/__stack_pointer - br $__inlined_func$start:logical + br $__inlined_func$start:logical$1 end i32.const 34320 i32.const 34368 diff --git a/tests/compiler/logical.ts b/tests/compiler/logical.ts index 62a26f9d66..a5943a4f3f 100644 --- a/tests/compiler/logical.ts +++ b/tests/compiler/logical.ts @@ -91,6 +91,14 @@ function testContextualBoolOr(someObj: Obj, someInt: i32): bool { } assert(testContextualBoolOr(new Obj(), 0)); +// Test simplification with precomputable LHS operands +// see: https://github.com/AssemblyScript/assemblyscript/issues/2946 + +export let foo = 123 && 456; +export let bar = -0.0 && 1.23; +export let baz = 321 || 654; +export let qux = NaN || 2.718; + // Common type class A {} diff --git a/tests/compiler/resolve-binary.debug.wat b/tests/compiler/resolve-binary.debug.wat index 86ec23b334..4b6d25a00f 100644 --- a/tests/compiler/resolve-binary.debug.wat +++ b/tests/compiler/resolve-binary.debug.wat @@ -6623,12 +6623,7 @@ call $~lib/builtins/abort unreachable end - i32.const 1 - if (result i32) - i32.const 2 - else - i32.const 1 - end + i32.const 2 i32.const 10 call $~lib/number/I32#toString local.set $0 @@ -6648,11 +6643,6 @@ unreachable end i32.const 0 - if (result i32) - i32.const 2 - else - i32.const 0 - end i32.const 10 call $~lib/number/I32#toString local.set $0 @@ -6672,11 +6662,6 @@ unreachable end i32.const 1 - if (result i32) - i32.const 1 - else - i32.const 2 - end i32.const 10 call $~lib/number/I32#toString local.set $0 @@ -6695,12 +6680,7 @@ call $~lib/builtins/abort unreachable end - i32.const 0 - if (result i32) - i32.const 0 - else - i32.const 2 - end + i32.const 2 i32.const 10 call $~lib/number/I32#toString local.set $0