authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-16 20:22:14+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-19 14:30:17+02:00
log53831442ef7e87c32501967f13dfb5fb9b0d0b0f
tree28a150a2f1b66ada6227d4b9ed8e5b14b0397fed
parentce5d934f5f713a0dbc8787d9ffe58b4962042f8f
signaturelock-open Commit is signed but in an unrecognized format.

wasm: saturating shift-left for unsigned integers


1 files changed, 55 insertions(+), 1 deletions(-)

src/arch/wasm/CodeGen.zig+55-1
......@@ -1454,6 +1454,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
14541454 .rem => self.airBinOp(inst, .rem),
14551455 .shl => self.airWrapBinOp(inst, .shl),
14561456 .shl_exact => self.airBinOp(inst, .shl),
1457 .shl_sat => self.airShlSat(inst),
14571458 .shr, .shr_exact => self.airBinOp(inst, .shr),
14581459 .xor => self.airBinOp(inst, .xor),
14591460 .max => self.airMaxMin(inst, .max),
......@@ -1588,7 +1589,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
15881589 .mul_sat,
15891590 .mod,
15901591 .assembly,
1591 .shl_sat,
15921592 .ret_addr,
15931593 .frame_addr,
15941594 .bit_reverse,
......@@ -4988,3 +4988,57 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
49884988 return bin_result;
49894989 }
49904990}
4991
4992fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4993 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
4994
4995 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
4996 const ty = self.air.typeOfIndex(inst);
4997 const int_info = ty.intInfo(self.target);
4998 if (int_info.bits > 64) {
4999 return self.fail("TODO: Saturating shifting left for integers with bitsize '{d}'", .{int_info.bits});
5000 }
5001
5002 const lhs = try self.resolveInst(bin_op.lhs);
5003 const rhs = try self.resolveInst(bin_op.rhs);
5004 if (int_info.signedness == .signed) {}
5005 const wasm_bits = toWasmBits(int_info.bits).?;
5006 const result = try self.allocLocal(ty);
5007
5008 if (wasm_bits == int_info.bits) {
5009 const shl = try self.binOp(lhs, rhs, ty, .shl);
5010 const shr = try self.binOp(shl, rhs, ty, .shr);
5011 const cmp_result = try self.cmp(lhs, shr, ty, .neq);
5012 if (wasm_bits == 32)
5013 try self.addImm32(-1)
5014 else
5015 try self.addImm64(@bitCast(u64, @as(i64, -1)));
5016 try self.emitWValue(shl);
5017 try self.emitWValue(cmp_result);
5018 try self.addTag(.select);
5019 try self.addLabel(.local_set, result.local);
5020 return result;
5021 } else {
5022 const shift_size = wasm_bits - int_info.bits;
5023 const shift_value = switch (wasm_bits) {
5024 32 => WValue{ .imm32 = shift_size },
5025 64 => WValue{ .imm64 = shift_size },
5026 else => unreachable,
5027 };
5028
5029 const shl_res = try self.binOp(lhs, shift_value, ty, .shl);
5030 const shl = try self.binOp(shl_res, rhs, ty, .shl);
5031 const shr = try self.binOp(shl, rhs, ty, .shr);
5032
5033 const cmp_result = try self.cmp(shl_res, shr, ty, .neq);
5034 if (wasm_bits == 32)
5035 try self.addImm32(-1)
5036 else
5037 try self.addImm64(@bitCast(u64, @as(i64, -1)));
5038 try self.emitWValue(shl);
5039 try self.emitWValue(cmp_result);
5040 try self.addTag(.select);
5041 try self.addLabel(.local_set, result.local);
5042 return self.binOp(result, shift_value, ty, .shr);
5043 }
5044}