Skip to content

Commit bebbeb5

Browse files
authored
Implement nontrapping float-to-int instructions (#1780)
1 parent b4badb8 commit bebbeb5

29 files changed

+1983
-1561
lines changed

build-js.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ export_function "_BinaryenTruncSFloat64ToInt32"
263263
export_function "_BinaryenTruncSFloat64ToInt64"
264264
export_function "_BinaryenTruncUFloat64ToInt32"
265265
export_function "_BinaryenTruncUFloat64ToInt64"
266+
export_function "_BinaryenTruncSatSFloat32ToInt32"
267+
export_function "_BinaryenTruncSatSFloat32ToInt64"
268+
export_function "_BinaryenTruncSatUFloat32ToInt32"
269+
export_function "_BinaryenTruncSatUFloat32ToInt64"
270+
export_function "_BinaryenTruncSatSFloat64ToInt32"
271+
export_function "_BinaryenTruncSatSFloat64ToInt64"
272+
export_function "_BinaryenTruncSatUFloat64ToInt32"
273+
export_function "_BinaryenTruncSatUFloat64ToInt64"
266274
export_function "_BinaryenReinterpretFloat32"
267275
export_function "_BinaryenReinterpretFloat64"
268276
export_function "_BinaryenConvertSInt32ToFloat32"

scripts/gen-s-parser.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,16 @@
258258
("i64.atomic.rmw8_u.cmpxchg", "makeAtomicRMWOrCmpxchg(s, i64)"),
259259
("i64.atomic.rmw16_u.cmpxchg", "makeAtomicRMWOrCmpxchg(s, i64)"),
260260
("i64.atomic.rmw32_u.cmpxchg", "makeAtomicRMWOrCmpxchg(s, i64)"),
261-
("i64.atomic.rmw.cmpxchg", "makeAtomicRMWOrCmpxchg(s, i64)")
261+
("i64.atomic.rmw.cmpxchg", "makeAtomicRMWOrCmpxchg(s, i64)"),
262+
# nontrapping float-to-int instructions
263+
("i32.trunc_s:sat/f32", "makeUnary(s, UnaryOp::TruncSatSFloat32ToInt32)"),
264+
("i32.trunc_u:sat/f32", "makeUnary(s, UnaryOp::TruncSatUFloat32ToInt32)"),
265+
("i32.trunc_s:sat/f64", "makeUnary(s, UnaryOp::TruncSatSFloat64ToInt32)"),
266+
("i32.trunc_u:sat/f64", "makeUnary(s, UnaryOp::TruncSatUFloat64ToInt32)"),
267+
("i64.trunc_s:sat/f32", "makeUnary(s, UnaryOp::TruncSatSFloat32ToInt64)"),
268+
("i64.trunc_u:sat/f32", "makeUnary(s, UnaryOp::TruncSatUFloat32ToInt64)"),
269+
("i64.trunc_s:sat/f64", "makeUnary(s, UnaryOp::TruncSatSFloat64ToInt64)"),
270+
("i64.trunc_u:sat/f64", "makeUnary(s, UnaryOp::TruncSatUFloat64ToInt64)"),
262271
]
263272

264273

src/binaryen-c.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,14 @@ BinaryenOp BinaryenAtomicRMWAnd(void) { return AtomicRMWOp::And; }
394394
BinaryenOp BinaryenAtomicRMWOr(void) { return AtomicRMWOp::Or; }
395395
BinaryenOp BinaryenAtomicRMWXor(void) { return AtomicRMWOp::Xor; }
396396
BinaryenOp BinaryenAtomicRMWXchg(void) { return AtomicRMWOp::Xchg; }
397+
BinaryenOp BinaryenTruncSatSFloat32ToInt32(void) { return TruncSatSFloat32ToInt32; }
398+
BinaryenOp BinaryenTruncSatSFloat32ToInt64(void) { return TruncSatSFloat32ToInt64; }
399+
BinaryenOp BinaryenTruncSatUFloat32ToInt32(void) { return TruncSatUFloat32ToInt32; }
400+
BinaryenOp BinaryenTruncSatUFloat32ToInt64(void) { return TruncSatUFloat32ToInt64; }
401+
BinaryenOp BinaryenTruncSatSFloat64ToInt32(void) { return TruncSatSFloat64ToInt32; }
402+
BinaryenOp BinaryenTruncSatSFloat64ToInt64(void) { return TruncSatSFloat64ToInt64; }
403+
BinaryenOp BinaryenTruncSatUFloat64ToInt32(void) { return TruncSatUFloat64ToInt32; }
404+
BinaryenOp BinaryenTruncSatUFloat64ToInt64(void) { return TruncSatUFloat64ToInt64; }
397405

398406
BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren, BinaryenType type) {
399407
auto* ret = ((Module*)module)->allocator.alloc<Block>();

src/binaryen-c.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,14 @@ BinaryenOp BinaryenAtomicRMWAnd(void);
324324
BinaryenOp BinaryenAtomicRMWOr(void);
325325
BinaryenOp BinaryenAtomicRMWXor(void);
326326
BinaryenOp BinaryenAtomicRMWXchg(void);
327+
BinaryenOp BinaryenTruncSatSFloat32ToInt32(void);
328+
BinaryenOp BinaryenTruncSatSFloat32ToInt64(void);
329+
BinaryenOp BinaryenTruncSatUFloat32ToInt32(void);
330+
BinaryenOp BinaryenTruncSatUFloat32ToInt64(void);
331+
BinaryenOp BinaryenTruncSatSFloat64ToInt32(void);
332+
BinaryenOp BinaryenTruncSatSFloat64ToInt64(void);
333+
BinaryenOp BinaryenTruncSatUFloat64ToInt32(void);
334+
BinaryenOp BinaryenTruncSatUFloat64ToInt64(void);
327335

328336
typedef void* BinaryenExpressionRef;
329337

src/gen-s-parser.inc

Lines changed: 92 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -778,24 +778,56 @@ switch (op[0]) {
778778
case 't': {
779779
switch (op[10]) {
780780
case 's': {
781-
switch (op[13]) {
782-
case '3':
783-
if (strcmp(op, "i32.trunc_s/f32") == 0) return makeUnary(s, UnaryOp::TruncSFloat32ToInt32);
784-
goto parse_error;
785-
case '6':
786-
if (strcmp(op, "i32.trunc_s/f64") == 0) return makeUnary(s, UnaryOp::TruncSFloat64ToInt32);
787-
goto parse_error;
781+
switch (op[11]) {
782+
case '/': {
783+
switch (op[13]) {
784+
case '3':
785+
if (strcmp(op, "i32.trunc_s/f32") == 0) return makeUnary(s, UnaryOp::TruncSFloat32ToInt32);
786+
goto parse_error;
787+
case '6':
788+
if (strcmp(op, "i32.trunc_s/f64") == 0) return makeUnary(s, UnaryOp::TruncSFloat64ToInt32);
789+
goto parse_error;
790+
default: goto parse_error;
791+
}
792+
}
793+
case ':': {
794+
switch (op[17]) {
795+
case '3':
796+
if (strcmp(op, "i32.trunc_s:sat/f32") == 0) return makeUnary(s, UnaryOp::TruncSatSFloat32ToInt32);
797+
goto parse_error;
798+
case '6':
799+
if (strcmp(op, "i32.trunc_s:sat/f64") == 0) return makeUnary(s, UnaryOp::TruncSatSFloat64ToInt32);
800+
goto parse_error;
801+
default: goto parse_error;
802+
}
803+
}
788804
default: goto parse_error;
789805
}
790806
}
791807
case 'u': {
792-
switch (op[13]) {
793-
case '3':
794-
if (strcmp(op, "i32.trunc_u/f32") == 0) return makeUnary(s, UnaryOp::TruncUFloat32ToInt32);
795-
goto parse_error;
796-
case '6':
797-
if (strcmp(op, "i32.trunc_u/f64") == 0) return makeUnary(s, UnaryOp::TruncUFloat64ToInt32);
798-
goto parse_error;
808+
switch (op[11]) {
809+
case '/': {
810+
switch (op[13]) {
811+
case '3':
812+
if (strcmp(op, "i32.trunc_u/f32") == 0) return makeUnary(s, UnaryOp::TruncUFloat32ToInt32);
813+
goto parse_error;
814+
case '6':
815+
if (strcmp(op, "i32.trunc_u/f64") == 0) return makeUnary(s, UnaryOp::TruncUFloat64ToInt32);
816+
goto parse_error;
817+
default: goto parse_error;
818+
}
819+
}
820+
case ':': {
821+
switch (op[17]) {
822+
case '3':
823+
if (strcmp(op, "i32.trunc_u:sat/f32") == 0) return makeUnary(s, UnaryOp::TruncSatUFloat32ToInt32);
824+
goto parse_error;
825+
case '6':
826+
if (strcmp(op, "i32.trunc_u:sat/f64") == 0) return makeUnary(s, UnaryOp::TruncSatUFloat64ToInt32);
827+
goto parse_error;
828+
default: goto parse_error;
829+
}
830+
}
799831
default: goto parse_error;
800832
}
801833
}
@@ -1275,24 +1307,56 @@ switch (op[0]) {
12751307
case 't': {
12761308
switch (op[10]) {
12771309
case 's': {
1278-
switch (op[13]) {
1279-
case '3':
1280-
if (strcmp(op, "i64.trunc_s/f32") == 0) return makeUnary(s, UnaryOp::TruncSFloat32ToInt64);
1281-
goto parse_error;
1282-
case '6':
1283-
if (strcmp(op, "i64.trunc_s/f64") == 0) return makeUnary(s, UnaryOp::TruncSFloat64ToInt64);
1284-
goto parse_error;
1310+
switch (op[11]) {
1311+
case '/': {
1312+
switch (op[13]) {
1313+
case '3':
1314+
if (strcmp(op, "i64.trunc_s/f32") == 0) return makeUnary(s, UnaryOp::TruncSFloat32ToInt64);
1315+
goto parse_error;
1316+
case '6':
1317+
if (strcmp(op, "i64.trunc_s/f64") == 0) return makeUnary(s, UnaryOp::TruncSFloat64ToInt64);
1318+
goto parse_error;
1319+
default: goto parse_error;
1320+
}
1321+
}
1322+
case ':': {
1323+
switch (op[17]) {
1324+
case '3':
1325+
if (strcmp(op, "i64.trunc_s:sat/f32") == 0) return makeUnary(s, UnaryOp::TruncSatSFloat32ToInt64);
1326+
goto parse_error;
1327+
case '6':
1328+
if (strcmp(op, "i64.trunc_s:sat/f64") == 0) return makeUnary(s, UnaryOp::TruncSatSFloat64ToInt64);
1329+
goto parse_error;
1330+
default: goto parse_error;
1331+
}
1332+
}
12851333
default: goto parse_error;
12861334
}
12871335
}
12881336
case 'u': {
1289-
switch (op[13]) {
1290-
case '3':
1291-
if (strcmp(op, "i64.trunc_u/f32") == 0) return makeUnary(s, UnaryOp::TruncUFloat32ToInt64);
1292-
goto parse_error;
1293-
case '6':
1294-
if (strcmp(op, "i64.trunc_u/f64") == 0) return makeUnary(s, UnaryOp::TruncUFloat64ToInt64);
1295-
goto parse_error;
1337+
switch (op[11]) {
1338+
case '/': {
1339+
switch (op[13]) {
1340+
case '3':
1341+
if (strcmp(op, "i64.trunc_u/f32") == 0) return makeUnary(s, UnaryOp::TruncUFloat32ToInt64);
1342+
goto parse_error;
1343+
case '6':
1344+
if (strcmp(op, "i64.trunc_u/f64") == 0) return makeUnary(s, UnaryOp::TruncUFloat64ToInt64);
1345+
goto parse_error;
1346+
default: goto parse_error;
1347+
}
1348+
}
1349+
case ':': {
1350+
switch (op[17]) {
1351+
case '3':
1352+
if (strcmp(op, "i64.trunc_u:sat/f32") == 0) return makeUnary(s, UnaryOp::TruncSatUFloat32ToInt64);
1353+
goto parse_error;
1354+
case '6':
1355+
if (strcmp(op, "i64.trunc_u:sat/f64") == 0) return makeUnary(s, UnaryOp::TruncSatUFloat64ToInt64);
1356+
goto parse_error;
1357+
default: goto parse_error;
1358+
}
1359+
}
12961360
default: goto parse_error;
12971361
}
12981362
}

src/ir/cost.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,15 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
141141
case ExtendS16Int32:
142142
case ExtendS8Int64:
143143
case ExtendS16Int64:
144-
case ExtendS32Int64: ret = 1; break;
144+
case ExtendS32Int64:
145+
case TruncSatSFloat32ToInt32:
146+
case TruncSatUFloat32ToInt32:
147+
case TruncSatSFloat64ToInt32:
148+
case TruncSatUFloat64ToInt32:
149+
case TruncSatSFloat32ToInt64:
150+
case TruncSatUFloat32ToInt64:
151+
case TruncSatSFloat64ToInt64:
152+
case TruncSatUFloat64ToInt64: ret = 1; break;
145153
case SqrtFloat32:
146154
case SqrtFloat64: ret = 2; break;
147155
case InvalidUnary: WASM_UNREACHABLE();

src/js/binaryen.js-post.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ Module['TruncSFloat64ToInt32'] = Module['_BinaryenTruncSFloat64ToInt32']();
101101
Module['TruncSFloat64ToInt64'] = Module['_BinaryenTruncSFloat64ToInt64']();
102102
Module['TruncUFloat64ToInt32'] = Module['_BinaryenTruncUFloat64ToInt32']();
103103
Module['TruncUFloat64ToInt64'] = Module['_BinaryenTruncUFloat64ToInt64']();
104+
Module['TruncSatSFloat32ToInt32'] = Module['_BinaryenTruncSatSFloat32ToInt32']();
105+
Module['TruncSatSFloat32ToInt64'] = Module['_BinaryenTruncSatSFloat32ToInt64']();
106+
Module['TruncSatUFloat32ToInt32'] = Module['_BinaryenTruncSatUFloat32ToInt32']();
107+
Module['TruncSatUFloat32ToInt64'] = Module['_BinaryenTruncSatUFloat32ToInt64']();
108+
Module['TruncSatSFloat64ToInt32'] = Module['_BinaryenTruncSatSFloat64ToInt32']();
109+
Module['TruncSatSFloat64ToInt64'] = Module['_BinaryenTruncSatSFloat64ToInt64']();
110+
Module['TruncSatUFloat64ToInt32'] = Module['_BinaryenTruncSatUFloat64ToInt32']();
111+
Module['TruncSatUFloat64ToInt64'] = Module['_BinaryenTruncSatUFloat64ToInt64']();
104112
Module['ReinterpretFloat32'] = Module['_BinaryenReinterpretFloat32']();
105113
Module['ReinterpretFloat64'] = Module['_BinaryenReinterpretFloat64']();
106114
Module['ConvertSInt32ToFloat32'] = Module['_BinaryenConvertSInt32ToFloat32']();
@@ -354,6 +362,22 @@ function wrapModule(module, self) {
354362
return Module['_BinaryenUnary'](module, Module['TruncUFloat64ToInt32'], value);
355363
},
356364
},
365+
'trunc_s_sat': {
366+
'f32': function(value) {
367+
return Module['_BinaryenUnary'](module, Module['TruncSatSFloat32ToInt32'], value);
368+
},
369+
'f64': function(value) {
370+
return Module['_BinaryenUnary'](module, Module['TruncSatSFloat64ToInt32'], value);
371+
},
372+
},
373+
'trunc_u_sat': {
374+
'f32': function(value) {
375+
return Module['_BinaryenUnary'](module, Module['TruncSatUFloat32ToInt32'], value);
376+
},
377+
'f64': function(value) {
378+
return Module['_BinaryenUnary'](module, Module['TruncSatUFloat64ToInt32'], value);
379+
},
380+
},
357381
'reinterpret': function(value) {
358382
return Module['_BinaryenUnary'](module, Module['ReinterpretFloat32'], value);
359383
},
@@ -601,6 +625,22 @@ function wrapModule(module, self) {
601625
return Module['_BinaryenUnary'](module, Module['TruncUFloat64ToInt64'], value);
602626
},
603627
},
628+
'trunc_s_sat': {
629+
'f32': function(value) {
630+
return Module['_BinaryenUnary'](module, Module['TruncSatSFloat32ToInt64'], value);
631+
},
632+
'f64': function(value) {
633+
return Module['_BinaryenUnary'](module, Module['TruncSatSFloat64ToInt64'], value);
634+
},
635+
},
636+
'trunc_u_sat': {
637+
'f32': function(value) {
638+
return Module['_BinaryenUnary'](module, Module['TruncSatUFloat32ToInt64'], value);
639+
},
640+
'f64': function(value) {
641+
return Module['_BinaryenUnary'](module, Module['TruncSatUFloat64ToInt64'], value);
642+
},
643+
},
604644
'reinterpret': function(value) {
605645
return Module['_BinaryenUnary'](module, Module['ReinterpretFloat64'], value);
606646
},

src/literal.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,15 @@ class Literal {
100100
Literal truncateToI32() const;
101101
Literal truncateToF32() const;
102102

103-
Literal convertSToF32() const;
104-
Literal convertUToF32() const;
105-
Literal convertSToF64() const;
106-
Literal convertUToF64() const;
103+
Literal truncSIToF32() const;
104+
Literal truncUIToF32() const;
105+
Literal truncSIToF64() const;
106+
Literal truncUIToF64() const;
107+
108+
Literal truncSatToSI32() const;
109+
Literal truncSatToSI64() const;
110+
Literal truncSatToUI32() const;
111+
Literal truncSatToUI64() const;
107112

108113
Literal eqz() const;
109114
Literal neg() const;

src/passes/Print.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,14 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
292292
case ExtendS8Int64: o << "i64.extend8_s"; break;
293293
case ExtendS16Int64: o << "i64.extend16_s"; break;
294294
case ExtendS32Int64: o << "i64.extend32_s"; break;
295+
case TruncSatSFloat32ToInt32: o << "i32.trunc_s:sat/f32"; break;
296+
case TruncSatUFloat32ToInt32: o << "i32.trunc_u:sat/f32"; break;
297+
case TruncSatSFloat64ToInt32: o << "i32.trunc_s:sat/f64"; break;
298+
case TruncSatUFloat64ToInt32: o << "i32.trunc_u:sat/f64"; break;
299+
case TruncSatSFloat32ToInt64: o << "i64.trunc_s:sat/f32"; break;
300+
case TruncSatUFloat32ToInt64: o << "i64.trunc_u:sat/f32"; break;
301+
case TruncSatSFloat64ToInt64: o << "i64.trunc_s:sat/f64"; break;
302+
case TruncSatUFloat64ToInt64: o << "i64.trunc_u:sat/f64"; break;
295303
case InvalidUnary: WASM_UNREACHABLE();
296304
}
297305
}

src/tools/fuzzing.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,8 +1322,22 @@ class TranslateToFuzzReader {
13221322
break;
13231323
}
13241324
case 1: return makeUnary({ pick(EqZInt64, WrapInt64), make(i64) });
1325-
case 2: return makeUnary({ pick(TruncSFloat32ToInt32, TruncUFloat32ToInt32, ReinterpretFloat32), make(f32) });
1326-
case 3: return makeUnary({ pick(TruncSFloat64ToInt32, TruncUFloat64ToInt32), make(f64) });
1325+
case 2: {
1326+
if (features.hasTruncSat()) {
1327+
return makeUnary({ pick(TruncSFloat32ToInt32, TruncUFloat32ToInt32, ReinterpretFloat32, TruncSatSFloat32ToInt32, TruncSatUFloat32ToInt32), make(f32) });
1328+
} else {
1329+
return makeUnary({ pick(TruncSFloat32ToInt32, TruncUFloat32ToInt32, ReinterpretFloat32), make(f32) });
1330+
}
1331+
break;
1332+
}
1333+
case 3: {
1334+
if (features.hasTruncSat()) {
1335+
return makeUnary({ pick(TruncSFloat64ToInt32, TruncUFloat64ToInt32, TruncSatSFloat64ToInt32, TruncSatUFloat64ToInt32), make(f64) });
1336+
} else {
1337+
return makeUnary({ pick(TruncSFloat64ToInt32, TruncUFloat64ToInt32), make(f64) });
1338+
}
1339+
break;
1340+
}
13271341
}
13281342
WASM_UNREACHABLE();
13291343
}
@@ -1338,8 +1352,22 @@ class TranslateToFuzzReader {
13381352
break;
13391353
}
13401354
case 1: return makeUnary({ pick(ExtendSInt32, ExtendUInt32), make(i32) });
1341-
case 2: return makeUnary({ pick(TruncSFloat32ToInt64, TruncUFloat32ToInt64), make(f32) });
1342-
case 3: return makeUnary({ pick(TruncSFloat64ToInt64, TruncUFloat64ToInt64, ReinterpretFloat64), make(f64) });
1355+
case 2: {
1356+
if (features.hasTruncSat()) {
1357+
return makeUnary({ pick(TruncSFloat32ToInt64, TruncUFloat32ToInt64, TruncSatSFloat32ToInt64, TruncSatUFloat32ToInt64), make(f32) });
1358+
} else {
1359+
return makeUnary({ pick(TruncSFloat32ToInt64, TruncUFloat32ToInt64), make(f32) });
1360+
}
1361+
break;
1362+
}
1363+
case 3: {
1364+
if (features.hasTruncSat()) {
1365+
return makeUnary({ pick(TruncSFloat64ToInt64, TruncUFloat64ToInt64, ReinterpretFloat64, TruncSatSFloat64ToInt64, TruncSatUFloat64ToInt64), make(f64) });
1366+
} else {
1367+
return makeUnary({ pick(TruncSFloat64ToInt64, TruncUFloat64ToInt64, ReinterpretFloat64), make(f64) });
1368+
}
1369+
break;
1370+
}
13431371
}
13441372
WASM_UNREACHABLE();
13451373
}

0 commit comments

Comments
 (0)