Skip to content

Commit da680fd

Browse files
authored
fix f32 frem in asm2wasm #1105 (#1106)
1 parent 9ff9885 commit da680fd

8 files changed

+126
-34
lines changed

src/asm2wasm.h

+20-33
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,19 @@ class Asm2WasmBuilder {
675675
return ret;
676676
}
677677

678+
// converts an f32 to an f64 if necessary
679+
Expression* ensureDouble(Expression* expr) {
680+
if (expr->type == f32) {
681+
auto conv = allocator.alloc<Unary>();
682+
conv->op = PromoteFloat32;
683+
conv->value = expr;
684+
conv->type = WasmType::f64;
685+
return conv;
686+
}
687+
assert(expr->type == f64);
688+
return expr;
689+
}
690+
678691
// Some binary opts might trap, so emit them safely if necessary
679692
Expression* makeTrappingI32Binary(BinaryOp op, Expression* left, Expression* right) {
680693
if (trapMode == TrapMode::Allow) return builder.makeBinary(op, left, right);
@@ -803,14 +816,7 @@ class Asm2WasmBuilder {
803816
}
804817
// WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we must do something
805818
// First, normalize input to f64
806-
auto input = value;
807-
if (input->type == f32) {
808-
auto conv = allocator.alloc<Unary>();
809-
conv->op = PromoteFloat32;
810-
conv->value = input;
811-
conv->type = WasmType::f64;
812-
input = conv;
813-
}
819+
auto input = ensureDouble(value);
814820
// We can handle this in one of two ways: clamping, which is fast, or JS, which
815821
// is precisely like JS but in order to do that we do a slow ffi
816822
if (trapMode == TrapMode::JS) {
@@ -894,14 +900,7 @@ class Asm2WasmBuilder {
894900
}
895901
// WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we must do something
896902
// First, normalize input to f64
897-
auto input = value;
898-
if (input->type == f32) {
899-
auto conv = allocator.alloc<Unary>();
900-
conv->op = PromoteFloat32;
901-
conv->value = input;
902-
conv->type = WasmType::f64;
903-
input = conv;
904-
}
903+
auto input = ensureDouble(value);
905904
// There is no "JS" way to handle this, as no i64s in JS, so always clamp if we don't allow traps
906905
Call *ret = allocator.alloc<Call>();
907906
ret->target = F64_TO_INT64;
@@ -1795,11 +1794,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
17951794
conv->type = WasmType::f32;
17961795
ret->value = conv;
17971796
} else if (ret->valueType == f64 && ret->value->type == f32) {
1798-
auto conv = allocator.alloc<Unary>();
1799-
conv->op = PromoteFloat32;
1800-
conv->value = ret->value;
1801-
conv->type = WasmType::f64;
1802-
ret->value = conv;
1797+
ret->value = ensureDouble(ret->value);
18031798
} else {
18041799
abort_on("bad sub[] types", ast);
18051800
}
@@ -1822,8 +1817,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
18221817
// WebAssembly does not have floating-point remainder, we have to emit a call to a special import of ours
18231818
CallImport *call = allocator.alloc<CallImport>();
18241819
call->target = F64_REM;
1825-
call->operands.push_back(ret->left);
1826-
call->operands.push_back(ret->right);
1820+
call->operands.push_back(ensureDouble(ret->left));
1821+
call->operands.push_back(ensureDouble(ret->right));
18271822
call->type = f64;
18281823
static bool addedImport = false;
18291824
if (!addedImport) {
@@ -1873,11 +1868,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
18731868
return conv;
18741869
}
18751870
if (ret->type == f32) {
1876-
auto conv = allocator.alloc<Unary>();
1877-
conv->op = PromoteFloat32;
1878-
conv->value = ret;
1879-
conv->type = WasmType::f64;
1880-
return conv;
1871+
return ensureDouble(ret);
18811872
}
18821873
fixCallType(ret, f64);
18831874
return ret;
@@ -2485,11 +2476,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
24852476
conv->value = process(writtenValue);
24862477
conv->type = WasmType::f32;
24872478
if (readType == ASM_DOUBLE) {
2488-
auto promote = allocator.alloc<Unary>();
2489-
promote->op = PromoteFloat32;
2490-
promote->value = conv;
2491-
promote->type = WasmType::f64;
2492-
return promote;
2479+
return ensureDouble(conv);
24932480
}
24942481
return conv;
24952482
} else if (writeType == ASM_FLOAT && readType == ASM_INT) {

test/unit.asm.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ function asm(global, env, buffer) {
137137
function frem() {
138138
return +(5.5 % 1.2);
139139
}
140+
function frem_float() {
141+
return Math_fround(Math_fround(5.5) % Math_fround(1.2));
142+
}
140143
function big_uint_div_u() {
141144
var x = 0;
142145
x = (4294967295 / 2)&-1;
@@ -740,6 +743,6 @@ function asm(global, env, buffer) {
740743
var FUNCTION_TABLE_vi = [ vi, vi, vi, vi, vi, vi, vi, vi ];
741744
var FUNCTION_TABLE_ii = [ ii ];
742745

743-
return { big_negative: big_negative, pick: forgetMe, pick: exportMe, doubleCompares: doubleCompares, intOps: intOps, conversions: conversions, switcher: switcher, frem: frem, big_uint_div_u: big_uint_div_u, fr: fr, negZero: negZero, neg: neg, smallCompare: smallCompare, cneg_nosemicolon: cneg_nosemicolon, forLoop: forLoop, ceiling_32_64: ceiling_32_64, aborts: aborts, continues: continues, bitcasts: bitcasts, recursiveBlockMerging: recursiveBlockMerging, lb: lb, zeroInit: zeroInit, phi: phi, smallIf: smallIf, dropCall: dropCall, useSetGlobal: useSetGlobal, usesSetGlobal2: usesSetGlobal2, breakThroughMany: breakThroughMany, ifChainEmpty: ifChainEmpty, heap8NoShift: heap8NoShift, conditionalTypeFun: conditionalTypeFun, loadSigned: loadSigned, globalOpts: globalOpts, dropCallImport: dropCallImport, loophi: loophi, loophi2: loophi2, relooperJumpThreading: relooperJumpThreading, relooperJumpThreading__ZN4game14preloadweaponsEv: relooperJumpThreading__ZN4game14preloadweaponsEv, __Z12multi_varargiz: __Z12multi_varargiz, jumpThreadDrop: jumpThreadDrop, dropIgnoredImportInIf: dropIgnoredImportInIf, dropIgnoredImportsInIf: dropIgnoredImportsInIf, relooperJumpThreading_irreducible: relooperJumpThreading_irreducible, store_fround: store_fround, exportedNumber: 42, relocatableAndModules: relocatableAndModules, exported_f32_user: exported_f32_user, keepAlive: keepAlive };
746+
return { big_negative: big_negative, pick: forgetMe, pick: exportMe, doubleCompares: doubleCompares, intOps: intOps, conversions: conversions, switcher: switcher, frem: frem, frem_float: frem_float, big_uint_div_u: big_uint_div_u, fr: fr, negZero: negZero, neg: neg, smallCompare: smallCompare, cneg_nosemicolon: cneg_nosemicolon, forLoop: forLoop, ceiling_32_64: ceiling_32_64, aborts: aborts, continues: continues, bitcasts: bitcasts, recursiveBlockMerging: recursiveBlockMerging, lb: lb, zeroInit: zeroInit, phi: phi, smallIf: smallIf, dropCall: dropCall, useSetGlobal: useSetGlobal, usesSetGlobal2: usesSetGlobal2, breakThroughMany: breakThroughMany, ifChainEmpty: ifChainEmpty, heap8NoShift: heap8NoShift, conditionalTypeFun: conditionalTypeFun, loadSigned: loadSigned, globalOpts: globalOpts, dropCallImport: dropCallImport, loophi: loophi, loophi2: loophi2, relooperJumpThreading: relooperJumpThreading, relooperJumpThreading__ZN4game14preloadweaponsEv: relooperJumpThreading__ZN4game14preloadweaponsEv, __Z12multi_varargiz: __Z12multi_varargiz, jumpThreadDrop: jumpThreadDrop, dropIgnoredImportInIf: dropIgnoredImportInIf, dropIgnoredImportsInIf: dropIgnoredImportsInIf, relooperJumpThreading_irreducible: relooperJumpThreading_irreducible, store_fround: store_fround, exportedNumber: 42, relocatableAndModules: relocatableAndModules, exported_f32_user: exported_f32_user, keepAlive: keepAlive };
744747
}
745748

test/unit.fromasm

+14
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
(export "conversions" (func $conversions))
3434
(export "switcher" (func $switcher))
3535
(export "frem" (func $frem))
36+
(export "frem_float" (func $legalstub$frem_float))
3637
(export "big_uint_div_u" (func $big_uint_div_u))
3738
(export "fr" (func $legalstub$fr))
3839
(export "negZero" (func $negZero))
@@ -245,6 +246,14 @@
245246
(f64.const 1.2)
246247
)
247248
)
249+
(func $frem_float (result f32)
250+
(f32.demote/f64
251+
(call $f64-rem
252+
(f64.const 5.5)
253+
(f64.const 1.2000000476837158)
254+
)
255+
)
256+
)
248257
(func $i32u-div (param $0 i32) (param $1 i32) (result i32)
249258
(if (result i32)
250259
(get_local $1)
@@ -1217,6 +1226,11 @@
12171226
(func $ii (param $0 i32) (result i32)
12181227
(get_local $0)
12191228
)
1229+
(func $legalstub$frem_float (result f64)
1230+
(f64.promote/f32
1231+
(call $frem_float)
1232+
)
1233+
)
12201234
(func $legalstub$fr (param $0 f64)
12211235
(call $fr
12221236
(f32.demote/f64

test/unit.fromasm.clamp

+14
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
(export "conversions" (func $conversions))
3232
(export "switcher" (func $switcher))
3333
(export "frem" (func $frem))
34+
(export "frem_float" (func $legalstub$frem_float))
3435
(export "big_uint_div_u" (func $big_uint_div_u))
3536
(export "fr" (func $legalstub$fr))
3637
(export "negZero" (func $negZero))
@@ -269,6 +270,14 @@
269270
(f64.const 1.2)
270271
)
271272
)
273+
(func $frem_float (result f32)
274+
(f32.demote/f64
275+
(call $f64-rem
276+
(f64.const 5.5)
277+
(f64.const 1.2000000476837158)
278+
)
279+
)
280+
)
272281
(func $i32u-div (param $0 i32) (param $1 i32) (result i32)
273282
(if (result i32)
274283
(get_local $1)
@@ -1241,6 +1250,11 @@
12411250
(func $ii (param $0 i32) (result i32)
12421251
(get_local $0)
12431252
)
1253+
(func $legalstub$frem_float (result f64)
1254+
(f64.promote/f32
1255+
(call $frem_float)
1256+
)
1257+
)
12441258
(func $legalstub$fr (param $0 f64)
12451259
(call $fr
12461260
(f32.demote/f64

test/unit.fromasm.clamp.no-opts

+20
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
(export "conversions" (func $conversions))
3939
(export "switcher" (func $switcher))
4040
(export "frem" (func $frem))
41+
(export "frem_float" (func $legalstub$frem_float))
4142
(export "big_uint_div_u" (func $big_uint_div_u))
4243
(export "fr" (func $legalstub$fr))
4344
(export "negZero" (func $negZero))
@@ -407,6 +408,20 @@
407408
)
408409
)
409410
)
411+
(func $frem_float (result f32)
412+
(return
413+
(f32.demote/f64
414+
(call $f64-rem
415+
(f64.promote/f32
416+
(f32.const 5.5)
417+
)
418+
(f64.promote/f32
419+
(f32.const 1.2000000476837158)
420+
)
421+
)
422+
)
423+
)
424+
)
410425
(func $i32u-div (param $0 i32) (param $1 i32) (result i32)
411426
(if (result i32)
412427
(i32.eqz
@@ -2030,6 +2045,11 @@
20302045
(get_local $x)
20312046
)
20322047
)
2048+
(func $legalstub$frem_float (result f64)
2049+
(f64.promote/f32
2050+
(call $frem_float)
2051+
)
2052+
)
20332053
(func $legalstub$fr (param $0 f64)
20342054
(call $fr
20352055
(f32.demote/f64

test/unit.fromasm.imprecise

+14
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
(export "conversions" (func $big_negative))
3131
(export "switcher" (func $switcher))
3232
(export "frem" (func $frem))
33+
(export "frem_float" (func $legalstub$frem_float))
3334
(export "big_uint_div_u" (func $big_uint_div_u))
3435
(export "fr" (func $legalstub$fr))
3536
(export "negZero" (func $negZero))
@@ -226,6 +227,14 @@
226227
(f64.const 1.2)
227228
)
228229
)
230+
(func $frem_float (result f32)
231+
(f32.demote/f64
232+
(call $f64-rem
233+
(f64.const 5.5)
234+
(f64.const 1.2000000476837158)
235+
)
236+
)
237+
)
229238
(func $big_uint_div_u (result i32)
230239
(i32.const 2147483647)
231240
)
@@ -1190,6 +1199,11 @@
11901199
(func $ii (param $0 i32) (result i32)
11911200
(get_local $0)
11921201
)
1202+
(func $legalstub$frem_float (result f64)
1203+
(f64.promote/f32
1204+
(call $frem_float)
1205+
)
1206+
)
11931207
(func $legalstub$fr (param $0 f64)
11941208
(call $fr
11951209
(f32.demote/f64

test/unit.fromasm.imprecise.no-opts

+20
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
(export "conversions" (func $conversions))
3939
(export "switcher" (func $switcher))
4040
(export "frem" (func $frem))
41+
(export "frem_float" (func $legalstub$frem_float))
4142
(export "big_uint_div_u" (func $big_uint_div_u))
4243
(export "fr" (func $legalstub$fr))
4344
(export "negZero" (func $negZero))
@@ -379,6 +380,20 @@
379380
)
380381
)
381382
)
383+
(func $frem_float (result f32)
384+
(return
385+
(f32.demote/f64
386+
(call $f64-rem
387+
(f64.promote/f32
388+
(f32.const 5.5)
389+
)
390+
(f64.promote/f32
391+
(f32.const 1.2000000476837158)
392+
)
393+
)
394+
)
395+
)
396+
)
382397
(func $big_uint_div_u (result i32)
383398
(local $x i32)
384399
(set_local $x
@@ -1990,6 +2005,11 @@
19902005
(get_local $x)
19912006
)
19922007
)
2008+
(func $legalstub$frem_float (result f64)
2009+
(f64.promote/f32
2010+
(call $frem_float)
2011+
)
2012+
)
19932013
(func $legalstub$fr (param $0 f64)
19942014
(call $fr
19952015
(f32.demote/f64

test/unit.fromasm.no-opts

+20
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
(export "conversions" (func $conversions))
4141
(export "switcher" (func $switcher))
4242
(export "frem" (func $frem))
43+
(export "frem_float" (func $legalstub$frem_float))
4344
(export "big_uint_div_u" (func $big_uint_div_u))
4445
(export "fr" (func $legalstub$fr))
4546
(export "negZero" (func $negZero))
@@ -383,6 +384,20 @@
383384
)
384385
)
385386
)
387+
(func $frem_float (result f32)
388+
(return
389+
(f32.demote/f64
390+
(call $f64-rem
391+
(f64.promote/f32
392+
(f32.const 5.5)
393+
)
394+
(f64.promote/f32
395+
(f32.const 1.2000000476837158)
396+
)
397+
)
398+
)
399+
)
400+
)
386401
(func $i32u-div (param $0 i32) (param $1 i32) (result i32)
387402
(if (result i32)
388403
(i32.eqz
@@ -2006,6 +2021,11 @@
20062021
(get_local $x)
20072022
)
20082023
)
2024+
(func $legalstub$frem_float (result f64)
2025+
(f64.promote/f32
2026+
(call $frem_float)
2027+
)
2028+
)
20092029
(func $legalstub$fr (param $0 f64)
20102030
(call $fr
20112031
(f32.demote/f64

0 commit comments

Comments
 (0)