diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-06-16 20:22:14 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-06-19 14:30:17 +0200 |
| commit | 53831442ef7e87c32501967f13dfb5fb9b0d0b0f (patch) | |
| tree | 28a150a2f1b66ada6227d4b9ed8e5b14b0397fed /src | |
| parent | ce5d934f5f713a0dbc8787d9ffe58b4962042f8f (diff) | |
| download | zig-53831442ef7e87c32501967f13dfb5fb9b0d0b0f.tar.gz zig-53831442ef7e87c32501967f13dfb5fb9b0d0b0f.zip | |
wasm: saturating shift-left for unsigned integers
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 0a93db7fb5..1a0df89c96 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1454,6 +1454,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .rem => self.airBinOp(inst, .rem), .shl => self.airWrapBinOp(inst, .shl), .shl_exact => self.airBinOp(inst, .shl), + .shl_sat => self.airShlSat(inst), .shr, .shr_exact => self.airBinOp(inst, .shr), .xor => self.airBinOp(inst, .xor), .max => self.airMaxMin(inst, .max), @@ -1588,7 +1589,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .mul_sat, .mod, .assembly, - .shl_sat, .ret_addr, .frame_addr, .bit_reverse, @@ -4988,3 +4988,57 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op return bin_result; } } + +fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { + if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; + + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const ty = self.air.typeOfIndex(inst); + const int_info = ty.intInfo(self.target); + 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); + + if (wasm_bits == int_info.bits) { + 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))); + try self.emitWValue(shl); + try self.emitWValue(cmp_result); + try self.addTag(.select); + try self.addLabel(.local_set, result.local); + return result; + } else { + const shift_size = wasm_bits - int_info.bits; + const shift_value = switch (wasm_bits) { + 32 => WValue{ .imm32 = shift_size }, + 64 => WValue{ .imm64 = shift_size }, + else => unreachable, + }; + + 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))); + try self.emitWValue(shl); + try self.emitWValue(cmp_result); + try self.addTag(.select); + try self.addLabel(.local_set, result.local); + return self.binOp(result, shift_value, ty, .shr); + } +} |
