Skip to content

Commit c30c62e

Browse files
authored
Cast to bool by comparing to zero (AssemblyScript#343)
1 parent b723ff3 commit c30c62e

38 files changed

+1072
-1023
lines changed

src/compiler.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7516,9 +7516,10 @@ export class Compiler extends DiagnosticEmitter {
75167516
}
75177517
case TypeKind.BOOL: {
75187518
if (flow.canOverflow(expr, type)) {
7519-
expr = module.createBinary(BinaryOp.AndI32,
7519+
// bool is special in that it compares to 0 instead of masking with 0x1
7520+
expr = module.createBinary(BinaryOp.NeI32,
75207521
expr,
7521-
module.createI32(0x1)
7522+
module.createI32(0)
75227523
);
75237524
}
75247525
break;

src/module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,10 @@ export function isTeeLocal(expr: ExpressionRef): bool {
11691169
return _BinaryenSetLocalIsTee(expr);
11701170
}
11711171

1172+
export function getGetGlobalName(expr: ExpressionRef): string | null {
1173+
return readString(_BinaryenGetGlobalGetName(expr));
1174+
}
1175+
11721176
export function getBinaryOp(expr: ExpressionRef): BinaryOp {
11731177
return _BinaryenBinaryGetOp(expr);
11741178
}

src/program.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ import {
101101
getBlockName,
102102
getConstValueF32,
103103
getConstValueF64,
104-
getConstValueI64Low
104+
getConstValueI64Low,
105+
getGetGlobalName
105106
} from "./module";
106107

107108
import {
@@ -3314,7 +3315,7 @@ export class Flow {
33143315
/**
33153316
* Tests if an expression can possibly overflow in the context of this flow. Assumes that the
33163317
* expression might already have overflown and returns `false` only if the operation neglects
3317-
* any possibly combination of garbage bits being present.
3318+
* any possible combination of garbage bits being present.
33183319
*/
33193320
canOverflow(expr: ExpressionRef, type: Type): bool {
33203321
// TODO: the following catches most common and a few uncommon cases, but there are additional
@@ -3336,13 +3337,18 @@ export class Flow {
33363337
}
33373338

33383339
// overflows if the value does
3339-
case ExpressionId.SetLocal: {
3340+
case ExpressionId.SetLocal: { // tee
33403341
assert(isTeeLocal(expr));
33413342
return this.canOverflow(getSetLocalValue(expr), type);
33423343
}
33433344

3344-
// never overflows because globals are wrapped on set
3345-
case ExpressionId.GetGlobal: return false;
3345+
// overflows if the conversion does (globals are wrapped on set)
3346+
case ExpressionId.GetGlobal: {
3347+
// TODO: this is inefficient because it has to read a string
3348+
let global = assert(this.currentFunction.program.elementsLookup.get(assert(getGetGlobalName(expr))));
3349+
assert(global.kind == ElementKind.GLOBAL);
3350+
return canConversionOverflow(assert((<Global>global).type), type);
3351+
}
33463352

33473353
case ExpressionId.Binary: {
33483354
switch (getBinaryOp(expr)) {
@@ -3567,9 +3573,7 @@ export class Flow {
35673573

35683574
/** Tests if a conversion from one type to another can technically overflow. */
35693575
function canConversionOverflow(fromType: Type, toType: Type): bool {
3570-
var fromSize = fromType.byteSize;
3571-
var toSize = toType.byteSize;
35723576
return !fromType.is(TypeFlags.INTEGER) // non-i32 locals or returns
3573-
|| fromSize > toSize
3577+
|| fromType.size > toType.size
35743578
|| fromType.is(TypeFlags.SIGNED) != toType.is(TypeFlags.SIGNED);
35753579
}

tests/compiler/abi.untouched.wat

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@
157157
i32.ctz
158158
set_local $0
159159
get_local $0
160-
i32.const 1
161-
i32.and
160+
i32.const 0
161+
i32.ne
162162
i32.eqz
163163
if
164164
i32.const 0
@@ -172,8 +172,8 @@
172172
i32.clz
173173
set_local $0
174174
get_local $0
175-
i32.const 1
176-
i32.and
175+
i32.const 0
176+
i32.ne
177177
i32.eqz
178178
if
179179
i32.const 0

tests/compiler/binary.optimized.wat

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@
9797
set_local $3
9898
end
9999
get_local $3
100-
i32.const 1
101-
i32.and
102100
if
103101
get_local $0
104102
get_local $0
@@ -655,27 +653,25 @@
655653
get_global $binary/f
656654
call $~lib/math/NativeMathf.mod
657655
set_global $binary/f
658-
block $__inlined_func$~lib/math/NativeMathf.pow0
659-
get_global $binary/f
660-
tee_local $0
661-
i32.reinterpret/f32
662-
i32.const 2147483647
663-
i32.and
664-
i32.const 2139095040
665-
i32.gt_s
666-
tee_local $1
667-
i32.eqz
668-
if
669-
i32.const 0
670-
set_local $1
671-
end
672-
get_local $1
673-
if
674-
get_local $0
675-
f32.const 1
676-
f32.add
677-
set_local $0
678-
end
656+
get_global $binary/f
657+
tee_local $0
658+
i32.reinterpret/f32
659+
i32.const 2147483647
660+
i32.and
661+
i32.const 2139095040
662+
i32.gt_s
663+
tee_local $1
664+
i32.eqz
665+
if
666+
i32.const 0
667+
set_local $1
668+
end
669+
get_local $1
670+
if
671+
get_local $0
672+
f32.const 1
673+
f32.add
674+
set_local $0
679675
end
680676
get_local $0
681677
set_global $binary/f
@@ -690,27 +686,25 @@
690686
get_global $binary/f
691687
call $~lib/math/NativeMathf.mod
692688
set_global $binary/f
693-
block $__inlined_func$~lib/math/NativeMathf.pow2
694-
get_global $binary/f
695-
tee_local $0
696-
i32.reinterpret/f32
697-
i32.const 2147483647
698-
i32.and
699-
i32.const 2139095040
700-
i32.gt_s
701-
tee_local $1
702-
i32.eqz
703-
if
704-
i32.const 0
705-
set_local $1
706-
end
707-
get_local $1
708-
if
709-
get_local $0
710-
f32.const 1
711-
f32.add
712-
set_local $0
713-
end
689+
get_global $binary/f
690+
tee_local $0
691+
i32.reinterpret/f32
692+
i32.const 2147483647
693+
i32.and
694+
i32.const 2139095040
695+
i32.gt_s
696+
tee_local $1
697+
i32.eqz
698+
if
699+
i32.const 0
700+
set_local $1
701+
end
702+
get_local $1
703+
if
704+
get_local $0
705+
f32.const 1
706+
f32.add
707+
set_local $0
714708
end
715709
get_local $0
716710
set_global $binary/f

tests/compiler/binary.untouched.wat

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,8 +1250,8 @@
12501250
get_local $1
12511251
f32.ne
12521252
end
1253-
i32.const 1
1254-
i32.and
1253+
i32.const 0
1254+
i32.ne
12551255
if
12561256
get_local $0
12571257
get_local $1
@@ -2531,8 +2531,8 @@
25312531
get_local $1
25322532
f64.ne
25332533
end
2534-
i32.const 1
2535-
i32.and
2534+
i32.const 0
2535+
i32.ne
25362536
if
25372537
get_local $0
25382538
get_local $1

tests/compiler/bool.optimized.wat

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
(module
2+
(type $iiiiv (func (param i32 i32 i32 i32)))
3+
(type $v (func))
4+
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
5+
(memory $0 1)
6+
(data (i32.const 8) "\07\00\00\00b\00o\00o\00l\00.\00t\00s")
7+
(table $0 1 anyfunc)
8+
(elem (i32.const 0) $null)
9+
(global $bool/i (mut i32) (i32.const 2))
10+
(global $bool/I (mut i64) (i64.const 2))
11+
(global $bool/u (mut i32) (i32.const 2))
12+
(global $bool/U (mut i64) (i64.const 2))
13+
(global $bool/f (mut f32) (f32.const 2))
14+
(global $bool/F (mut f64) (f64.const 2))
15+
(global $bool/uu (mut i32) (i32.const 2))
16+
(export "memory" (memory $0))
17+
(export "table" (table $0))
18+
(start $start)
19+
(func $start (; 1 ;) (type $v)
20+
get_global $bool/i
21+
i32.const 0
22+
i32.ne
23+
i32.const 1
24+
i32.ne
25+
if
26+
i32.const 0
27+
i32.const 8
28+
i32.const 2
29+
i32.const 0
30+
call $~lib/env/abort
31+
unreachable
32+
end
33+
get_global $bool/I
34+
i32.wrap/i64
35+
i32.const 0
36+
i32.ne
37+
i32.const 1
38+
i32.ne
39+
if
40+
i32.const 0
41+
i32.const 8
42+
i32.const 4
43+
i32.const 0
44+
call $~lib/env/abort
45+
unreachable
46+
end
47+
get_global $bool/u
48+
i32.const 0
49+
i32.ne
50+
i32.const 1
51+
i32.ne
52+
if
53+
i32.const 0
54+
i32.const 8
55+
i32.const 6
56+
i32.const 0
57+
call $~lib/env/abort
58+
unreachable
59+
end
60+
get_global $bool/U
61+
i32.wrap/i64
62+
i32.const 0
63+
i32.ne
64+
i32.const 1
65+
i32.ne
66+
if
67+
i32.const 0
68+
i32.const 8
69+
i32.const 8
70+
i32.const 0
71+
call $~lib/env/abort
72+
unreachable
73+
end
74+
get_global $bool/f
75+
i32.trunc_u/f32
76+
i32.const 0
77+
i32.ne
78+
i32.const 1
79+
i32.ne
80+
if
81+
i32.const 0
82+
i32.const 8
83+
i32.const 10
84+
i32.const 0
85+
call $~lib/env/abort
86+
unreachable
87+
end
88+
get_global $bool/F
89+
i32.trunc_u/f64
90+
i32.const 0
91+
i32.ne
92+
i32.const 1
93+
i32.ne
94+
if
95+
i32.const 0
96+
i32.const 8
97+
i32.const 12
98+
i32.const 0
99+
call $~lib/env/abort
100+
unreachable
101+
end
102+
get_global $bool/uu
103+
i32.const 0
104+
i32.ne
105+
i32.const 1
106+
i32.ne
107+
if
108+
i32.const 0
109+
i32.const 8
110+
i32.const 14
111+
i32.const 0
112+
call $~lib/env/abort
113+
unreachable
114+
end
115+
)
116+
(func $null (; 2 ;) (type $v)
117+
nop
118+
)
119+
)

tests/compiler/bool.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
var i = <i32>2;
2+
assert(<bool>i == true);
3+
var I = <i64>2;
4+
assert(<bool>I == true);
5+
var u = <u32>2;
6+
assert(<bool>u == true);
7+
var U = <u64>2;
8+
assert(<bool>U == true);
9+
var f = <f32>2;
10+
assert(<bool>f == true);
11+
var F = <f64>2;
12+
assert(<bool>F == true);
13+
var uu = <u8>2;
14+
assert(<bool>uu == true);

0 commit comments

Comments
 (0)