Skip to content

Commit a4dc45e

Browse files
authored
Refactor binary expression compilation to be reusable in builtins (#1489)
BREAKING CHANGE: The compiler's `convertExpression` does no longer take a `wrap` argument.
1 parent b4ca3f9 commit a4dc45e

File tree

2 files changed

+1355
-1685
lines changed

2 files changed

+1355
-1685
lines changed

src/builtins.ts

Lines changed: 36 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,11 +2070,8 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef {
20702070
inType.size < type.size // int to larger int (clear garbage bits)
20712071
)
20722072
) {
2073-
arg1 = compiler.convertExpression(arg1,
2074-
inType, type,
2075-
false, false, // still clears garbage bits when not wrapping
2076-
operands[1]
2077-
);
2073+
// either conversion or memory operation clears garbage bits
2074+
arg1 = compiler.convertExpression(arg1, inType, type, false, operands[1]);
20782075
inType = type;
20792076
}
20802077
var immOffset = 0;
@@ -2102,81 +2099,44 @@ builtins.set(BuiltinNames.store, builtin_store);
21022099
function builtin_add(ctx: BuiltinContext): ExpressionRef {
21032100
var compiler = ctx.compiler;
21042101
var module = compiler.module;
2105-
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2))
2102+
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) {
21062103
return module.unreachable();
2104+
}
21072105
var operands = ctx.operands;
21082106
var typeArguments = ctx.typeArguments;
21092107
var left = operands[0];
21102108
var arg0 = typeArguments
21112109
? compiler.compileExpression(
21122110
left,
21132111
typeArguments[0],
2114-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2112+
Constraints.CONV_IMPLICIT
21152113
)
2116-
: compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP);
2114+
: compiler.compileExpression(operands[0], Type.auto);
21172115
var type = compiler.currentType;
21182116
if (type.isValue) {
21192117
let arg1: ExpressionRef;
21202118
if (!typeArguments && left.isNumericLiteral) {
21212119
// prefer right type
21222120
arg1 = compiler.compileExpression(
21232121
operands[1],
2124-
type,
2125-
Constraints.MUST_WRAP
2122+
type
21262123
);
21272124
if (compiler.currentType != type) {
21282125
arg0 = compiler.compileExpression(
21292126
left,
21302127
(type = compiler.currentType),
2131-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2128+
Constraints.CONV_IMPLICIT
21322129
);
21332130
}
21342131
} else {
21352132
arg1 = compiler.compileExpression(
21362133
operands[1],
21372134
type,
2138-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2135+
Constraints.CONV_IMPLICIT
21392136
);
21402137
}
2141-
let op: BinaryOp = -1;
2142-
switch (type.kind) {
2143-
case TypeKind.I8:
2144-
case TypeKind.I16:
2145-
case TypeKind.U8:
2146-
case TypeKind.U16:
2147-
case TypeKind.BOOL: {
2148-
return compiler.ensureSmallIntegerWrap(
2149-
module.binary(BinaryOp.AddI32, arg0, arg1),
2150-
type
2151-
);
2152-
}
2153-
case TypeKind.I32:
2154-
case TypeKind.U32:
2155-
{
2156-
op = BinaryOp.AddI32;
2157-
break;
2158-
}
2159-
case TypeKind.I64:
2160-
case TypeKind.U64: {
2161-
op = BinaryOp.AddI64;
2162-
break;
2163-
}
2164-
case TypeKind.ISIZE:
2165-
case TypeKind.USIZE: {
2166-
op = compiler.options.isWasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32;
2167-
break;
2168-
}
2169-
case TypeKind.F32: {
2170-
op = BinaryOp.AddF32;
2171-
break;
2172-
}
2173-
case TypeKind.F64: {
2174-
op = BinaryOp.AddF64;
2175-
break;
2176-
}
2177-
}
2178-
if (op != -1) {
2179-
return module.binary(op, arg0, arg1);
2138+
if (type.isNumericValue) {
2139+
return compiler.makeAdd(arg0, arg1, type);
21802140
}
21812141
}
21822142
compiler.error(
@@ -2193,81 +2153,44 @@ builtins.set(BuiltinNames.add, builtin_add);
21932153
function builtin_sub(ctx: BuiltinContext): ExpressionRef {
21942154
var compiler = ctx.compiler;
21952155
var module = compiler.module;
2196-
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2))
2156+
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) {
21972157
return module.unreachable();
2158+
}
21982159
var operands = ctx.operands;
21992160
var typeArguments = ctx.typeArguments;
22002161
var left = operands[0];
22012162
var arg0 = typeArguments
22022163
? compiler.compileExpression(
22032164
left,
22042165
typeArguments[0],
2205-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2166+
Constraints.CONV_IMPLICIT
22062167
)
2207-
: compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP);
2168+
: compiler.compileExpression(operands[0], Type.auto);
22082169
var type = compiler.currentType;
22092170
if (type.isValue) {
22102171
let arg1: ExpressionRef;
22112172
if (!typeArguments && left.isNumericLiteral) {
22122173
// prefer right type
22132174
arg1 = compiler.compileExpression(
22142175
operands[1],
2215-
type,
2216-
Constraints.MUST_WRAP
2176+
type
22172177
);
22182178
if (compiler.currentType != type) {
22192179
arg0 = compiler.compileExpression(
22202180
left,
22212181
(type = compiler.currentType),
2222-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2182+
Constraints.CONV_IMPLICIT
22232183
);
22242184
}
22252185
} else {
22262186
arg1 = compiler.compileExpression(
22272187
operands[1],
22282188
type,
2229-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2189+
Constraints.CONV_IMPLICIT
22302190
);
22312191
}
2232-
let op: BinaryOp = -1;
2233-
switch (type.kind) {
2234-
case TypeKind.I8:
2235-
case TypeKind.I16:
2236-
case TypeKind.U8:
2237-
case TypeKind.U16:
2238-
case TypeKind.BOOL: {
2239-
return compiler.ensureSmallIntegerWrap(
2240-
module.binary(BinaryOp.SubI32, arg0, arg1),
2241-
type
2242-
);
2243-
}
2244-
case TypeKind.I32:
2245-
case TypeKind.U32:
2246-
{
2247-
op = BinaryOp.SubI32;
2248-
break;
2249-
}
2250-
case TypeKind.I64:
2251-
case TypeKind.U64: {
2252-
op = BinaryOp.SubI64;
2253-
break;
2254-
}
2255-
case TypeKind.ISIZE:
2256-
case TypeKind.USIZE: {
2257-
op = compiler.options.isWasm64 ? BinaryOp.SubI64 : BinaryOp.SubI32;
2258-
break;
2259-
}
2260-
case TypeKind.F32: {
2261-
op = BinaryOp.SubF32;
2262-
break;
2263-
}
2264-
case TypeKind.F64: {
2265-
op = BinaryOp.SubF64;
2266-
break;
2267-
}
2268-
}
2269-
if (op != -1) {
2270-
return module.binary(op, arg0, arg1);
2192+
if (type.isNumericValue) {
2193+
return compiler.makeSub(arg0, arg1, type);
22712194
}
22722195
}
22732196
compiler.error(
@@ -2284,81 +2207,44 @@ builtins.set(BuiltinNames.sub, builtin_sub);
22842207
function builtin_mul(ctx: BuiltinContext): ExpressionRef {
22852208
var compiler = ctx.compiler;
22862209
var module = compiler.module;
2287-
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2))
2210+
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) {
22882211
return module.unreachable();
2212+
}
22892213
var operands = ctx.operands;
22902214
var typeArguments = ctx.typeArguments;
22912215
var left = operands[0];
22922216
var arg0 = typeArguments
22932217
? compiler.compileExpression(
22942218
left,
22952219
typeArguments[0],
2296-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2220+
Constraints.CONV_IMPLICIT
22972221
)
2298-
: compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP);
2222+
: compiler.compileExpression(operands[0], Type.auto);
22992223
var type = compiler.currentType;
23002224
if (type.isValue) {
23012225
let arg1: ExpressionRef;
23022226
if (!typeArguments && left.isNumericLiteral) {
23032227
// prefer right type
23042228
arg1 = compiler.compileExpression(
23052229
operands[1],
2306-
type,
2307-
Constraints.MUST_WRAP
2230+
type
23082231
);
23092232
if (compiler.currentType != type) {
23102233
arg0 = compiler.compileExpression(
23112234
left,
23122235
(type = compiler.currentType),
2313-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2236+
Constraints.CONV_IMPLICIT
23142237
);
23152238
}
23162239
} else {
23172240
arg1 = compiler.compileExpression(
23182241
operands[1],
23192242
type,
2320-
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
2243+
Constraints.CONV_IMPLICIT
23212244
);
23222245
}
2323-
let op: BinaryOp = -1;
2324-
switch (type.kind) {
2325-
case TypeKind.I8:
2326-
case TypeKind.I16:
2327-
case TypeKind.U8:
2328-
case TypeKind.U16:
2329-
case TypeKind.BOOL: {
2330-
return compiler.ensureSmallIntegerWrap(
2331-
module.binary(BinaryOp.MulI32, arg0, arg1),
2332-
type
2333-
);
2334-
}
2335-
case TypeKind.I32:
2336-
case TypeKind.U32:
2337-
{
2338-
op = BinaryOp.MulI32;
2339-
break;
2340-
}
2341-
case TypeKind.I64:
2342-
case TypeKind.U64: {
2343-
op = BinaryOp.MulI64;
2344-
break;
2345-
}
2346-
case TypeKind.ISIZE:
2347-
case TypeKind.USIZE: {
2348-
op = compiler.options.isWasm64 ? BinaryOp.MulI64 : BinaryOp.MulI32;
2349-
break;
2350-
}
2351-
case TypeKind.F32: {
2352-
op = BinaryOp.MulF32;
2353-
break;
2354-
}
2355-
case TypeKind.F64: {
2356-
op = BinaryOp.MulF64;
2357-
break;
2358-
}
2359-
}
2360-
if (op != -1) {
2361-
return module.binary(op, arg0, arg1);
2246+
if (type.isNumericValue) {
2247+
return compiler.makeMul(arg0, arg1, type);
23622248
}
23632249
}
23642250
compiler.error(
@@ -2458,11 +2344,8 @@ function builtin_atomic_store(ctx: BuiltinContext): ExpressionRef {
24582344
inType.size < type.size // int to larger int (clear garbage bits)
24592345
)
24602346
) {
2461-
arg1 = compiler.convertExpression(arg1,
2462-
inType, type,
2463-
false, false, // still clears garbage bits when not wrapping
2464-
operands[1]
2465-
);
2347+
// either conversion or memory operation clears garbage bits
2348+
arg1 = compiler.convertExpression(arg1, inType, type, false, operands[1]);
24662349
inType = type;
24672350
}
24682351
var immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports
@@ -2519,11 +2402,8 @@ function builtin_atomic_binary(ctx: BuiltinContext, op: AtomicRMWOp, opName: str
25192402
inType.size < type.size // int to larger int (clear garbage bits)
25202403
)
25212404
) {
2522-
arg1 = compiler.convertExpression(arg1,
2523-
inType, type,
2524-
false, false, // still clears garbage bits when not wrapping
2525-
operands[1]
2526-
);
2405+
// either conversion or memory operation clears garbage bits
2406+
arg1 = compiler.convertExpression(arg1, inType, type, false, operands[1]);
25272407
inType = type;
25282408
}
25292409
var immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports
@@ -2619,16 +2499,9 @@ function builtin_atomic_cmpxchg(ctx: BuiltinContext): ExpressionRef {
26192499
inType.size < type.size // int to larger int (clear garbage bits)
26202500
)
26212501
) {
2622-
arg1 = compiler.convertExpression(arg1,
2623-
inType, type,
2624-
false, false, // still clears garbage bits when not wrapping
2625-
operands[1]
2626-
);
2627-
arg2 = compiler.convertExpression(arg2,
2628-
inType, type,
2629-
false, false, // still clears garbage bits when not wrapping
2630-
operands[2]
2631-
);
2502+
// either conversion or memory operation clears garbage bits
2503+
arg1 = compiler.convertExpression(arg1, inType, type, false, operands[1]);
2504+
arg2 = compiler.convertExpression(arg2, inType, type, false, operands[2]);
26322505
inType = type;
26332506
}
26342507
var immOffset = operands.length == 4 ? evaluateImmediateOffset(operands[3], compiler) : 0; // reports

0 commit comments

Comments
 (0)