diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-06-19 15:50:03 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-06-19 15:50:03 +0200 |
| commit | 05600a6d8438595bf7fc40ea21d0c47076d2935d (patch) | |
| tree | 16877371e41351d7b1681d795084b2a9c186cdcc /src | |
| parent | 53831442ef7e87c32501967f13dfb5fb9b0d0b0f (diff) | |
| download | zig-05600a6d8438595bf7fc40ea21d0c47076d2935d.tar.gz zig-05600a6d8438595bf7fc40ea21d0c47076d2935d.zip | |
wasm: saturating shift-left for signed integers
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 65 |
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); |
