authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-15 20:26:53+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-19 14:30:13+02:00
logfcd4280a8cabf7859fab450cc0d4b65f6adaabe5
tree3cea87c6ea1fbb7bdf0d679b5ab0a1ca39c95b77
parent33cf6ef621114daad63d14067b6ff374e664d410
signaturelock-open Commit is signed but in an unrecognized format.

wasm: implement saturating add, sub for unsigned

Implements +| and -| for unsigned integers <= 64 bits.

1 files changed, 63 insertions(+), 2 deletions(-)

src/arch/wasm/CodeGen.zig+63-2
......@@ -1432,8 +1432,10 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
14321432 .const_ty => unreachable,
14331433
14341434 .add => self.airBinOp(inst, .add),
1435 .add_sat => self.airSatBinOp(inst, .add),
14351436 .addwrap => self.airWrapBinOp(inst, .add),
14361437 .sub => self.airBinOp(inst, .sub),
1438 .sub_sat => self.airSatBinOp(inst, .sub),
14371439 .subwrap => self.airWrapBinOp(inst, .sub),
14381440 .mul => self.airBinOp(inst, .mul),
14391441 .mulwrap => self.airWrapBinOp(inst, .mul),
......@@ -1583,8 +1585,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
15831585
15841586 .memcpy => self.airMemcpy(inst),
15851587
1586 .add_sat,
1587 .sub_sat,
15881588 .mul_sat,
15891589 .mod,
15901590 .assembly,
......@@ -4878,3 +4878,64 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValu
48784878 try self.addLabel(.local_set, result.local);
48794879 return result;
48804880}
4881
4882fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
4883 assert(op == .add or op == .sub);
4884 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
4885
4886 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
4887 const ty = self.air.typeOfIndex(inst);
4888 const lhs_operand = try self.resolveInst(bin_op.lhs);
4889 const rhs_operand = try self.resolveInst(bin_op.rhs);
4890
4891 const int_info = ty.intInfo(self.target);
4892 const is_signed = int_info.signedness == .signed;
4893
4894 if (int_info.bits > 64) {
4895 return self.fail("TODO: saturating arithmetic for integers with bitsize '{d}'", .{int_info.bits});
4896 }
4897
4898 const wasm_bits = toWasmBits(int_info.bits).?;
4899
4900 const lhs = if (is_signed) blk: {
4901 break :blk try self.signAbsValue(lhs_operand, ty);
4902 } else lhs_operand;
4903 const rhs = if (is_signed) blk: {
4904 break :blk try self.signAbsValue(rhs_operand, ty);
4905 } else rhs_operand;
4906
4907 const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, self.target) });
4908 try self.emitWValue(lhs);
4909 try self.emitWValue(rhs);
4910 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
4911 const bin_result = try self.allocLocal(ty);
4912 try self.addLabel(.local_set, bin_result.local);
4913
4914 if (wasm_bits != int_info.bits and op == .add) {
4915 const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1);
4916 const imm_val = switch (wasm_bits) {
4917 32 => WValue{ .imm32 = @intCast(u32, val) },
4918 64 => WValue{ .imm64 = val },
4919 else => unreachable,
4920 };
4921
4922 const cmp_result = try self.cmp(bin_result, imm_val, ty, if (op == .add) .lt else .gt);
4923 try self.emitWValue(bin_result);
4924 try self.emitWValue(imm_val);
4925 try self.emitWValue(cmp_result);
4926 } else {
4927 const cmp_result = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);
4928 switch (wasm_bits) {
4929 32 => try self.addImm32(if (op == .add) @as(i32, -1) else 0),
4930 64 => try self.addImm64(if (op == .add) @bitCast(u64, @as(i64, -1)) else 0),
4931 else => unreachable,
4932 }
4933 try self.emitWValue(bin_result);
4934 try self.emitWValue(cmp_result);
4935 }
4936
4937 try self.addTag(.select);
4938 const result = try self.allocLocal(ty);
4939 try self.addLabel(.local_set, result.local);
4940 return result;
4941}