aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2022-06-16 20:22:14 +0200
committerLuuk de Gram <luuk@degram.dev>2022-06-19 14:30:17 +0200
commit53831442ef7e87c32501967f13dfb5fb9b0d0b0f (patch)
tree28a150a2f1b66ada6227d4b9ed8e5b14b0397fed /src
parentce5d934f5f713a0dbc8787d9ffe58b4962042f8f (diff)
downloadzig-53831442ef7e87c32501967f13dfb5fb9b0d0b0f.tar.gz
zig-53831442ef7e87c32501967f13dfb5fb9b0d0b0f.zip
wasm: saturating shift-left for unsigned integers
Diffstat (limited to 'src')
-rw-r--r--src/arch/wasm/CodeGen.zig56
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);
+ }
+}