authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-17 21:56:11+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-18 07:43:33+02:00
loged25ce77f58cd0ddfd5e3f5412c4cb66d1cc1331
treeca9e9208fa7ed2bb42c11f2dcfb224bbc3098c27
parentfd081c74f10de71eaf00b0ccd7c4e4a0c0c5c3ad

wasm: Implement {add/sub}WithOverflow for 128bit


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

src/arch/wasm/CodeGen.zig+63
......@@ -3801,6 +3801,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
38013801/// Compares big integers by checking both its high bits and low bits.
38023802/// TODO: Lower this to compiler_rt call when bitsize > 128
38033803fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3804 assert(operand_ty.abiSize(self.target) >= 16);
38043805 if (operand_ty.intInfo(self.target).bits > 128) {
38053806 return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits});
38063807 }
......@@ -4093,6 +4094,10 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
40934094 return self.fail("TODO: Implement {{add/sub}}_with_overflow for integer bitsize: {d}", .{int_info.bits});
40944095 };
40954096
4097 if (wasm_bits == 128) {
4098 return self.airAddSubWithOverflowBigInt(lhs_op, rhs_op, lhs_ty, self.air.typeOfIndex(inst), op);
4099 }
4100
40964101 const zero = switch (wasm_bits) {
40974102 32 => WValue{ .imm32 = 0 },
40984103 64 => WValue{ .imm64 = 0 },
......@@ -4144,6 +4149,64 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
41444149 return result_ptr;
41454150}
41464151
4152fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, result_ty: Type, op: Op) InnerError!WValue {
4153 assert(op == .add or op == .sub);
4154 const int_info = ty.intInfo(self.target);
4155 const is_signed = int_info.signedness == .signed;
4156 if (int_info.bits != 128) {
4157 return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits});
4158 }
4159
4160 const lhs_high_bit = try self.load(lhs, Type.u64, 0);
4161 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
4162 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
4163 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
4164
4165 const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
4166 const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);
4167
4168 const lt = if (op == .add) blk: {
4169 break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt);
4170 } else if (op == .sub) blk: {
4171 break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);
4172 } else unreachable;
4173 const tmp = try self.intcast(lt, Type.u32, Type.u64);
4174 const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op);
4175
4176 const overflow_bit = if (is_signed) blk: {
4177 const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor);
4178 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
4179 const to_wrap = if (op == .add) wrap: {
4180 break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
4181 } else xor_low;
4182 const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and");
4183 break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed
4184 } else blk: {
4185 const eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq);
4186 const op_eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt);
4187
4188 const first_arg = if (op == .sub) arg: {
4189 break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt);
4190 } else lt;
4191
4192 try self.emitWValue(first_arg);
4193 try self.emitWValue(op_eq);
4194 try self.emitWValue(eq);
4195 try self.addTag(.select);
4196
4197 const overflow_bit = try self.allocLocal(Type.initTag(.u1));
4198 try self.addLabel(.local_set, overflow_bit.local);
4199 break :blk overflow_bit;
4200 };
4201
4202 const result_ptr = try self.allocStack(result_ty);
4203 try self.store(result_ptr, high_op_res, Type.u64, 0);
4204 try self.store(result_ptr, tmp_op, Type.u64, 8);
4205 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), 16);
4206
4207 return result_ptr;
4208}
4209
41474210fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
41484211 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
41494212 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;