aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2022-06-19 15:50:03 +0200
committerLuuk de Gram <luuk@degram.dev>2022-06-19 15:50:03 +0200
commit05600a6d8438595bf7fc40ea21d0c47076d2935d (patch)
tree16877371e41351d7b1681d795084b2a9c186cdcc /src
parent53831442ef7e87c32501967f13dfb5fb9b0d0b0f (diff)
downloadzig-05600a6d8438595bf7fc40ea21d0c47076d2935d.tar.gz
zig-05600a6d8438595bf7fc40ea21d0c47076d2935d.zip
wasm: saturating shift-left for signed integers
Diffstat (limited to 'src')
-rw-r--r--src/arch/wasm/CodeGen.zig65
1 files changed, 55 insertions, 10 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 1a0df89c96..ac604957b6 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -4995,13 +4995,13 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const ty = self.air.typeOfIndex(inst);
const int_info = ty.intInfo(self.target);
+ const is_signed = int_info.signedness == .signed;
if (int_info.bits > 64) {
return self.fail("TODO: Saturating shifting left for integers with bitsize '{d}'", .{int_info.bits});
}
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
- if (int_info.signedness == .signed) {}
const wasm_bits = toWasmBits(int_info.bits).?;
const result = try self.allocLocal(ty);
@@ -5009,10 +5009,32 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const shl = try self.binOp(lhs, rhs, ty, .shl);
const shr = try self.binOp(shl, rhs, ty, .shr);
const cmp_result = try self.cmp(lhs, shr, ty, .neq);
- if (wasm_bits == 32)
- try self.addImm32(-1)
- else
- try self.addImm64(@bitCast(u64, @as(i64, -1)));
+
+ switch (wasm_bits) {
+ 32 => blk: {
+ if (!is_signed) {
+ try self.addImm32(-1);
+ break :blk;
+ }
+ const less_than_zero = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
+ try self.addImm32(std.math.minInt(i32));
+ try self.addImm32(std.math.maxInt(i32));
+ try self.emitWValue(less_than_zero);
+ try self.addTag(.select);
+ },
+ 64 => blk: {
+ if (!is_signed) {
+ try self.addImm64(@bitCast(u64, @as(i64, -1)));
+ break :blk;
+ }
+ const less_than_zero = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
+ try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));
+ try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64))));
+ try self.emitWValue(less_than_zero);
+ try self.addTag(.select);
+ },
+ else => unreachable,
+ }
try self.emitWValue(shl);
try self.emitWValue(cmp_result);
try self.addTag(.select);
@@ -5029,12 +5051,35 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const shl_res = try self.binOp(lhs, shift_value, ty, .shl);
const shl = try self.binOp(shl_res, rhs, ty, .shl);
const shr = try self.binOp(shl, rhs, ty, .shr);
-
const cmp_result = try self.cmp(shl_res, shr, ty, .neq);
- if (wasm_bits == 32)
- try self.addImm32(-1)
- else
- try self.addImm64(@bitCast(u64, @as(i64, -1)));
+
+ switch (wasm_bits) {
+ 32 => blk: {
+ if (!is_signed) {
+ try self.addImm32(-1);
+ break :blk;
+ }
+
+ const less_than_zero = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt);
+ try self.addImm32(std.math.minInt(i32));
+ try self.addImm32(std.math.maxInt(i32));
+ try self.emitWValue(less_than_zero);
+ try self.addTag(.select);
+ },
+ 64 => blk: {
+ if (!is_signed) {
+ try self.addImm64(@bitCast(u64, @as(i64, -1)));
+ break :blk;
+ }
+
+ const less_than_zero = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt);
+ try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));
+ try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64))));
+ try self.emitWValue(less_than_zero);
+ try self.addTag(.select);
+ },
+ else => unreachable,
+ }
try self.emitWValue(shl);
try self.emitWValue(cmp_result);
try self.addTag(.select);