Skip to content

Commit cde16f6

Browse files
committed
wasm: wrapOperand - leave value on the stack
This also does it for `wrapBinOp` which internally uses the already refactored `binOp` and `wrapOperand` heavily simplifying this function and not duplicate the logic from `binOp`
1 parent 699bc61 commit cde16f6

File tree

1 file changed

+33
-52
lines changed

1 file changed

+33
-52
lines changed

src/arch/wasm/CodeGen.zig

Lines changed: 33 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,40 +2179,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
21792179
return self.fail("TODO: Implement wrapping arithmetic for vectors", .{});
21802180
}
21812181

2182-
return self.wrapBinOp(lhs, rhs, ty, op);
2182+
return (try self.wrapBinOp(lhs, rhs, ty, op)).toLocal(self, ty);
21832183
}
21842184

2185+
/// Performs a wrapping binary operation.
2186+
/// Asserts rhs is not a stack value when lhs also isn't.
2187+
/// NOTE: Leaves the result on the stack when its Type is <= 64 bits
21852188
fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2186-
const bit_size = ty.intInfo(self.target).bits;
2187-
var wasm_bits = toWasmBits(bit_size) orelse {
2188-
return self.fail("TODO: Implement wrapping arithmetic for integers with bitsize: {d}\n", .{bit_size});
2189-
};
2190-
2191-
if (wasm_bits == 128) {
2192-
const bin_op = try self.binOpBigInt(lhs, rhs, ty, op);
2193-
return self.wrapOperand(bin_op, ty);
2194-
}
2195-
2196-
const opcode: wasm.Opcode = buildOpcode(.{
2197-
.op = op,
2198-
.valtype1 = typeToValtype(ty, self.target),
2199-
.signedness = if (ty.isSignedInt()) .signed else .unsigned,
2200-
});
2201-
2202-
try self.emitWValue(lhs);
2203-
try self.emitWValue(rhs);
2204-
try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
2205-
const bin_local = try self.allocLocal(ty);
2206-
try self.addLabel(.local_set, bin_local.local);
2207-
2189+
const bin_local = try self.binOp(lhs, rhs, ty, op);
22082190
return self.wrapOperand(bin_local, ty);
22092191
}
22102192

22112193
/// Wraps an operand based on a given type's bitsize.
22122194
/// Asserts `Type` is <= 128 bits.
2195+
/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack.
22132196
fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
22142197
assert(ty.abiSize(self.target) <= 16);
2215-
const result_local = try self.allocLocal(ty);
22162198
const bitsize = ty.intInfo(self.target).bits;
22172199
const wasm_bits = toWasmBits(bitsize) orelse {
22182200
return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize});
@@ -2246,8 +2228,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
22462228
try self.addTag(.i64_and);
22472229
} else unreachable;
22482230

2249-
try self.addLabel(.local_set, result_local.local);
2250-
return result_local;
2231+
return WValue{ .stack = {} };
22512232
}
22522233

22532234
fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {
@@ -3471,11 +3452,11 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34713452
return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits});
34723453
}
34733454

3474-
const result = try self.intcast(operand, op_ty, wanted_ty);
3455+
var result = try self.intcast(operand, op_ty, wanted_ty);
34753456
const wanted_bits = wanted_ty.intInfo(self.target).bits;
34763457
const wasm_bits = toWasmBits(wanted_bits).?;
34773458
if (wasm_bits != wanted_bits) {
3478-
return self.wrapOperand(result, wanted_ty);
3459+
result = try self.wrapOperand(result, wanted_ty);
34793460
}
34803461
return result.toLocal(self, wanted_ty);
34813462
}
@@ -3749,11 +3730,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
37493730
.signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,
37503731
});
37513732
try self.addTag(Mir.Inst.Tag.fromOpcode(op));
3752-
3753-
const result = try self.allocLocal(dest_ty);
3754-
try self.addLabel(.local_set, result.local);
3755-
3756-
return self.wrapOperand(result, dest_ty);
3733+
const wrapped = try self.wrapOperand(.{ .stack = {} }, dest_ty);
3734+
return wrapped.toLocal(self, dest_ty);
37573735
}
37583736

37593737
fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
@@ -4339,7 +4317,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
43394317

43404318
const bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty);
43414319
const result = if (wasm_bits != int_info.bits) blk: {
4342-
break :blk try self.wrapOperand(bin_op, lhs_ty);
4320+
break :blk try (try self.wrapOperand(bin_op, lhs_ty)).toLocal(self, lhs_ty);
43434321
} else bin_op;
43444322

43454323
const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt;
@@ -4438,13 +4416,15 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
44384416

44394417
const shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty);
44404418
const result = if (wasm_bits != int_info.bits) blk: {
4441-
break :blk try self.wrapOperand(shl, lhs_ty);
4419+
break :blk try (try self.wrapOperand(shl, lhs_ty)).toLocal(self, lhs_ty);
44424420
} else shl;
44434421

44444422
const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: {
44454423
const abs = try self.signAbsValue(shl, lhs_ty);
4424+
// emit lhs to stack to we can keep 'wrapped' on the stack also
4425+
try self.emitWValue(lhs);
44464426
const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr);
4447-
break :blk try self.cmp(lhs, wrapped, lhs_ty, .neq);
4427+
break :blk try self.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq);
44484428
} else blk: {
44494429
const shr = try (try self.binOp(result, rhs, lhs_ty, .shr)).toLocal(self, lhs_ty);
44504430
break :blk try self.cmp(lhs, shr, lhs_ty, .neq);
@@ -4499,7 +4479,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
44994479
const wrap = try self.intcast(shr, new_ty, lhs_ty);
45004480
_ = try self.cmp(wrap, zero, lhs_ty, .neq);
45014481
try self.addLabel(.local_set, overflow_bit.local);
4502-
break :blk try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);
4482+
break :blk try self.intcast(bin_op, new_ty, lhs_ty);
45034483
} else {
45044484
const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);
45054485
const shr = try (try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(self, lhs_ty);
@@ -4529,9 +4509,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
45294509
try self.addLabel(.local_set, overflow_bit.local);
45304510
break :blk try self.wrapOperand(bin_op, lhs_ty);
45314511
};
4512+
const bin_op_local = try bin_op.toLocal(self, lhs_ty);
45324513

45334514
const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
4534-
try self.store(result_ptr, bin_op, lhs_ty, 0);
4515+
try self.store(result_ptr, bin_op_local, lhs_ty, 0);
45354516
const offset = @intCast(u32, lhs_ty.abiSize(self.target));
45364517
try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset);
45374518

@@ -4854,29 +4835,29 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
48544835
switch (int_info.bits) {
48554836
16 => {
48564837
const shl_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl);
4857-
const lhs = try (try self.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and")).toLocal(self, ty);
4858-
const shr_res = try (try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty);
4838+
const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and");
4839+
const shr_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr);
48594840
const res = if (int_info.signedness == .signed) blk: {
48604841
break :blk try self.wrapOperand(shr_res, Type.u8);
48614842
} else shr_res;
48624843
return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty);
48634844
},
48644845
24 => {
4865-
const msb = try self.wrapOperand(operand, Type.u16);
4866-
const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr);
4846+
const msb = try (try self.wrapOperand(operand, Type.u16)).toLocal(self, Type.u16);
48674847

48684848
const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl);
4869-
const lhs = try (try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and")).toLocal(self, Type.u16);
4870-
const shr_res = try (try self.binOp(msb, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty);
4849+
const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and");
4850+
const shr_res = try self.binOp(msb, .{ .imm32 = 8 }, ty, .shr);
48714851

48724852
const res = if (int_info.signedness == .signed) blk: {
48734853
break :blk try self.wrapOperand(shr_res, Type.u8);
48744854
} else shr_res;
48754855
const lhs_tmp = try self.binOp(lhs, res, ty, .@"or");
4876-
const lhs_result = try (try self.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty);
4856+
const lhs_result = try self.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr);
48774857
const rhs_wrap = try self.wrapOperand(msb, Type.u8);
4878-
const rhs_result = try (try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl)).toLocal(self, ty);
4858+
const rhs_result = try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl);
48794859

4860+
const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr);
48804861
const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or");
48814862
return (try self.binOp(tmp, lsb, ty, .@"or")).toLocal(self, ty);
48824863
},
@@ -4887,11 +4868,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
48874868
const rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty);
48884869
const tmp_or = try (try self.binOp(lhs, rhs, ty, .@"or")).toLocal(self, ty);
48894870

4890-
const shr = try (try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr)).toLocal(self, ty);
4871+
const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);
4872+
const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr);
48914873
const res = if (int_info.signedness == .signed) blk: {
48924874
break :blk try self.wrapOperand(shr, Type.u16);
48934875
} else shr;
4894-
const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);
48954876
return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty);
48964877
},
48974878
else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),
@@ -5178,7 +5159,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
51785159
_ = try self.cmp(bin_result, min_wvalue, ty, .gt);
51795160
try self.addTag(.select);
51805161
try self.addLabel(.local_set, bin_result.local); // re-use local
5181-
return self.wrapOperand(bin_result, ty);
5162+
return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty);
51825163
} else {
51835164
const zero = switch (wasm_bits) {
51845165
32 => WValue{ .imm32 = 0 },
@@ -5289,11 +5270,11 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
52895270
_ = try self.cmp(shl_res, shr, ty, .neq);
52905271
try self.addTag(.select);
52915272
try self.addLabel(.local_set, result.local);
5292-
const shift_result = try (try self.binOp(result, shift_value, ty, .shr)).toLocal(self, ty);
5273+
var shift_result = try self.binOp(result, shift_value, ty, .shr);
52935274
if (is_signed) {
5294-
return self.wrapOperand(shift_result, ty);
5275+
shift_result = try self.wrapOperand(shift_result, ty);
52955276
}
5296-
return shift_result;
5277+
return try shift_result.toLocal(self, ty);
52975278
}
52985279
}
52995280

0 commit comments

Comments
 (0)