Skip to content

Commit 85ae8cc

Browse files
froydnjkripken
authored andcommitted
better handling of float ops in wasm2asm (#1427)
* explicitly handle binary float operations in processFunctionBody We weren't handling them before, but it wasn't obvious. Make the (non-) handling of them explicit in the code. We'll add handlers for them shortly. * add handling for simple binary float operations min, max, and copysign will require more sophisticated handling. * add handling for float comparisons * move float min/max handling to the correct place It was previously grouped with the i32 ops. * handle float promotion and demotion
1 parent e0f86a2 commit 85ae8cc

File tree

3 files changed

+554
-101
lines changed

3 files changed

+554
-101
lines changed

src/wasm2asm.h

Lines changed: 176 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,12 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
14001400
visit(curr->value, EXPRESSION_RESULT)
14011401
);
14021402
break;
1403+
case PromoteFloat32:
1404+
return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT),
1405+
ASM_DOUBLE);
1406+
case DemoteFloat64:
1407+
return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT),
1408+
ASM_FLOAT);
14031409
// TODO: more complex unary conversions
14041410
default:
14051411
std::cerr << "Unhandled unary float operator: " << curr
@@ -1438,112 +1444,181 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
14381444
Ref left = visit(curr->left, EXPRESSION_RESULT);
14391445
Ref right = visit(curr->right, EXPRESSION_RESULT);
14401446
Ref ret;
1441-
switch (curr->op) {
1442-
case AddInt32:
1443-
ret = ValueBuilder::makeBinary(left, PLUS, right);
1444-
break;
1445-
case SubInt32:
1446-
ret = ValueBuilder::makeBinary(left, MINUS, right);
1447-
break;
1448-
case MulInt32: {
1449-
if (curr->type == i32) {
1450-
// TODO: when one operand is a small int, emit a multiply
1451-
return ValueBuilder::makeCall(MATH_IMUL, left, right);
1452-
} else {
1453-
return ValueBuilder::makeBinary(left, MUL, right);
1447+
switch (curr->type) {
1448+
case i32: {
1449+
switch (curr->op) {
1450+
case AddInt32:
1451+
ret = ValueBuilder::makeBinary(left, PLUS, right);
1452+
break;
1453+
case SubInt32:
1454+
ret = ValueBuilder::makeBinary(left, MINUS, right);
1455+
break;
1456+
case MulInt32: {
1457+
if (curr->type == i32) {
1458+
// TODO: when one operand is a small int, emit a multiply
1459+
return ValueBuilder::makeCall(MATH_IMUL, left, right);
1460+
} else {
1461+
return ValueBuilder::makeBinary(left, MUL, right);
1462+
}
1463+
}
1464+
case DivSInt32:
1465+
ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), DIV,
1466+
makeSigning(right, ASM_SIGNED));
1467+
break;
1468+
case DivUInt32:
1469+
ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), DIV,
1470+
makeSigning(right, ASM_UNSIGNED));
1471+
break;
1472+
case RemSInt32:
1473+
ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), MOD,
1474+
makeSigning(right, ASM_SIGNED));
1475+
break;
1476+
case RemUInt32:
1477+
ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), MOD,
1478+
makeSigning(right, ASM_UNSIGNED));
1479+
break;
1480+
case AndInt32:
1481+
ret = ValueBuilder::makeBinary(left, AND, right);
1482+
break;
1483+
case OrInt32:
1484+
ret = ValueBuilder::makeBinary(left, OR, right);
1485+
break;
1486+
case XorInt32:
1487+
ret = ValueBuilder::makeBinary(left, XOR, right);
1488+
break;
1489+
case ShlInt32:
1490+
ret = ValueBuilder::makeBinary(left, LSHIFT, right);
1491+
break;
1492+
case ShrUInt32:
1493+
ret = ValueBuilder::makeBinary(left, TRSHIFT, right);
1494+
break;
1495+
case ShrSInt32:
1496+
ret = ValueBuilder::makeBinary(left, RSHIFT, right);
1497+
break;
1498+
case EqInt32: {
1499+
// TODO: check if this condition is still valid/necessary
1500+
if (curr->left->type == i32) {
1501+
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), EQ,
1502+
makeSigning(right, ASM_SIGNED));
1503+
} else {
1504+
return ValueBuilder::makeBinary(left, EQ, right);
1505+
}
1506+
}
1507+
case NeInt32: {
1508+
if (curr->left->type == i32) {
1509+
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), NE,
1510+
makeSigning(right, ASM_SIGNED));
1511+
} else {
1512+
return ValueBuilder::makeBinary(left, NE, right);
1513+
}
1514+
}
1515+
case LtSInt32:
1516+
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LT,
1517+
makeSigning(right, ASM_SIGNED));
1518+
case LtUInt32:
1519+
return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LT,
1520+
makeSigning(right, ASM_UNSIGNED));
1521+
case LeSInt32:
1522+
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LE,
1523+
makeSigning(right, ASM_SIGNED));
1524+
case LeUInt32:
1525+
return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LE,
1526+
makeSigning(right, ASM_UNSIGNED));
1527+
case GtSInt32:
1528+
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GT,
1529+
makeSigning(right, ASM_SIGNED));
1530+
case GtUInt32:
1531+
return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GT,
1532+
makeSigning(right, ASM_UNSIGNED));
1533+
case GeSInt32:
1534+
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GE,
1535+
makeSigning(right, ASM_SIGNED));
1536+
case GeUInt32:
1537+
return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GE,
1538+
makeSigning(right, ASM_UNSIGNED));
1539+
case RotLInt32:
1540+
return makeSigning(ValueBuilder::makeCall(WASM_ROTL32, left, right),
1541+
ASM_SIGNED);
1542+
case RotRInt32:
1543+
return makeSigning(ValueBuilder::makeCall(WASM_ROTR32, left, right),
1544+
ASM_SIGNED);
1545+
case EqFloat32:
1546+
return makeAsmCoercion(ValueBuilder::makeBinary(left, EQ, right),
1547+
ASM_FLOAT);
1548+
case EqFloat64:
1549+
return ValueBuilder::makeBinary(left, EQ, right);
1550+
case NeFloat32:
1551+
return makeAsmCoercion(ValueBuilder::makeBinary(left, NE, right),
1552+
ASM_FLOAT);
1553+
case NeFloat64:
1554+
return ValueBuilder::makeBinary(left, NE, right);
1555+
case GeFloat32:
1556+
return makeAsmCoercion(ValueBuilder::makeBinary(left, GE, right),
1557+
ASM_FLOAT);
1558+
case GeFloat64:
1559+
return ValueBuilder::makeBinary(left, GE, right);
1560+
case GtFloat32:
1561+
return makeAsmCoercion(ValueBuilder::makeBinary(left, GT, right),
1562+
ASM_FLOAT);
1563+
case GtFloat64:
1564+
return ValueBuilder::makeBinary(left, GT, right);
1565+
case LeFloat32:
1566+
return makeAsmCoercion(ValueBuilder::makeBinary(left, LE, right),
1567+
ASM_FLOAT);
1568+
case LeFloat64:
1569+
return ValueBuilder::makeBinary(left, LE, right);
1570+
case LtFloat32:
1571+
return makeAsmCoercion(ValueBuilder::makeBinary(left, LT, right),
1572+
ASM_FLOAT);
1573+
case LtFloat64:
1574+
return ValueBuilder::makeBinary(left, LT, right);
1575+
default: {
1576+
std::cerr << "Unhandled i32 binary operator: " << curr << std::endl;
1577+
abort();
1578+
}
14541579
}
1455-
}
1456-
case DivSInt32:
1457-
ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), DIV,
1458-
makeSigning(right, ASM_SIGNED));
1459-
break;
1460-
case DivUInt32:
1461-
ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), DIV,
1462-
makeSigning(right, ASM_UNSIGNED));
1463-
break;
1464-
case RemSInt32:
1465-
ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), MOD,
1466-
makeSigning(right, ASM_SIGNED));
1467-
break;
1468-
case RemUInt32:
1469-
ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), MOD,
1470-
makeSigning(right, ASM_UNSIGNED));
1471-
break;
1472-
case AndInt32:
1473-
ret = ValueBuilder::makeBinary(left, AND, right);
1474-
break;
1475-
case OrInt32:
1476-
ret = ValueBuilder::makeBinary(left, OR, right);
1477-
break;
1478-
case XorInt32:
1479-
ret = ValueBuilder::makeBinary(left, XOR, right);
1480-
break;
1481-
case ShlInt32:
1482-
ret = ValueBuilder::makeBinary(left, LSHIFT, right);
14831580
break;
1484-
case ShrUInt32:
1485-
ret = ValueBuilder::makeBinary(left, TRSHIFT, right);
1486-
break;
1487-
case ShrSInt32:
1488-
ret = ValueBuilder::makeBinary(left, RSHIFT, right);
1489-
break;
1490-
case MinFloat32:
1491-
ret = ValueBuilder::makeCall(MATH_MIN, left, right);
1492-
break;
1493-
case MaxFloat32:
1494-
ret = ValueBuilder::makeCall(MATH_MAX, left, right);
1495-
break;
1496-
case EqInt32: {
1497-
// TODO: check if this condition is still valid/necessary
1498-
if (curr->left->type == i32) {
1499-
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), EQ,
1500-
makeSigning(right, ASM_SIGNED));
1501-
} else {
1502-
return ValueBuilder::makeBinary(left, EQ, right);
1503-
}
15041581
}
1505-
case NeInt32: {
1506-
if (curr->left->type == i32) {
1507-
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), NE,
1508-
makeSigning(right, ASM_SIGNED));
1509-
} else {
1510-
return ValueBuilder::makeBinary(left, NE, right);
1582+
case f32:
1583+
case f64:
1584+
switch (curr->op) {
1585+
case AddFloat32:
1586+
case AddFloat64:
1587+
ret = ValueBuilder::makeBinary(left, PLUS, right);
1588+
break;
1589+
case SubFloat32:
1590+
case SubFloat64:
1591+
ret = ValueBuilder::makeBinary(left, MINUS, right);
1592+
break;
1593+
case MulFloat32:
1594+
case MulFloat64:
1595+
ret = ValueBuilder::makeBinary(left, MUL, right);
1596+
break;
1597+
case DivFloat32:
1598+
case DivFloat64:
1599+
ret = ValueBuilder::makeBinary(left, DIV, right);
1600+
break;
1601+
case MinFloat32:
1602+
case MinFloat64:
1603+
ret = ValueBuilder::makeCall(MATH_MIN, left, right);
1604+
break;
1605+
case MaxFloat32:
1606+
case MaxFloat64:
1607+
ret = ValueBuilder::makeCall(MATH_MAX, left, right);
1608+
break;
1609+
case CopySignFloat32:
1610+
case CopySignFloat64:
1611+
default:
1612+
std::cerr << "Unhandled binary float operator: " << curr << std::endl;
1613+
abort();
15111614
}
1512-
}
1513-
case LtSInt32:
1514-
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LT,
1515-
makeSigning(right, ASM_SIGNED));
1516-
case LtUInt32:
1517-
return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LT,
1518-
makeSigning(right, ASM_UNSIGNED));
1519-
case LeSInt32:
1520-
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LE,
1521-
makeSigning(right, ASM_SIGNED));
1522-
case LeUInt32:
1523-
return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LE,
1524-
makeSigning(right, ASM_UNSIGNED));
1525-
case GtSInt32:
1526-
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GT,
1527-
makeSigning(right, ASM_SIGNED));
1528-
case GtUInt32:
1529-
return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GT,
1530-
makeSigning(right, ASM_UNSIGNED));
1531-
case GeSInt32:
1532-
return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GE,
1533-
makeSigning(right, ASM_SIGNED));
1534-
case GeUInt32:
1535-
return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GE,
1536-
makeSigning(right, ASM_UNSIGNED));
1537-
case RotLInt32:
1538-
return makeSigning(ValueBuilder::makeCall(WASM_ROTL32, left, right),
1539-
ASM_SIGNED);
1540-
case RotRInt32:
1541-
return makeSigning(ValueBuilder::makeCall(WASM_ROTR32, left, right),
1542-
ASM_SIGNED);
1543-
default: {
1544-
std::cerr << "Unhandled binary operator: " << curr << std::endl;
1615+
if (curr->type == f32) {
1616+
return makeAsmCoercion(ret, ASM_FLOAT);
1617+
}
1618+
return ret;
1619+
default:
1620+
std::cerr << "Unhandled type in binary: " << curr << std::endl;
15451621
abort();
1546-
}
15471622
}
15481623
return makeAsmCoercion(ret, wasmToAsmType(curr->type));
15491624
}

0 commit comments

Comments
 (0)