authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-10 21:53:43+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-11 19:38:00+02:00
log18afcc34c61a18ada7bda0fc50f48e929866ab82
tree3c2f959b0c6fadcc65ec586a276f1beec9af512c
parent3011ef2d82fe29d47b9c6877b6a8bbea0938d7c4

wasm: implement `@divFloor` for signed integers


1 files changed, 89 insertions(+), 22 deletions(-)

src/arch/wasm/CodeGen.zig+89-22
......@@ -2266,7 +2266,7 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
22662266 const WantedT = std.meta.Int(.unsigned, @typeInfo(T).Int.bits);
22672267 if (value >= 0) return @bitCast(WantedT, value);
22682268 const max_value = @intCast(u64, (@as(u65, 1) << bits) - 1);
2269 const flipped = (~-value) + 1;
2269 const flipped = @intCast(T, (~-@as(i65, value)) + 1);
22702270 const result = @bitCast(WantedT, flipped) & max_value;
22712271 return @intCast(WantedT, result);
22722272}
......@@ -2294,7 +2294,10 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
22942294 val.toSignedInt(),
22952295 @intCast(u6, int_info.bits),
22962296 )) },
2297 33...64 => return WValue{ .imm64 = @bitCast(u64, val.toSignedInt()) },
2297 33...64 => return WValue{ .imm64 = toTwosComplement(
2298 val.toSignedInt(),
2299 @intCast(u7, int_info.bits),
2300 ) },
22982301 else => unreachable,
22992302 },
23002303 .unsigned => switch (int_info.bits) {
......@@ -4781,18 +4784,56 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
47814784 const lhs = try self.resolveInst(bin_op.lhs);
47824785 const rhs = try self.resolveInst(bin_op.rhs);
47834786
4784 const div_result = try self.binOp(lhs, rhs, ty, .div);
47854787 if (ty.isUnsignedInt()) {
4786 return div_result;
4788 return self.binOp(lhs, rhs, ty, .div);
47874789 } else if (ty.isSignedInt()) {
4788 return self.fail("TODO: `@divFloor` for signed integers", .{});
4789 }
4790 const int_bits = ty.intInfo(self.target).bits;
4791 const wasm_bits = toWasmBits(int_bits) orelse {
4792 return self.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits});
4793 };
4794 const lhs_res = if (wasm_bits != int_bits) blk: {
4795 break :blk try self.signAbsValue(lhs, ty);
4796 } else lhs;
4797 const rhs_res = if (wasm_bits != int_bits) blk: {
4798 break :blk try self.signAbsValue(rhs, ty);
4799 } else rhs;
4800
4801 const div_result = try self.binOp(lhs_res, rhs_res, ty, .div);
4802 const rem_result = try self.binOp(lhs_res, rhs_res, ty, .rem);
4803
4804 const zero = switch (wasm_bits) {
4805 32 => WValue{ .imm32 = 0 },
4806 64 => WValue{ .imm64 = 0 },
4807 else => unreachable,
4808 };
4809 const lhs_less_than_zero = try self.cmp(lhs_res, zero, ty, .lt);
4810 const rhs_less_than_zero = try self.cmp(rhs_res, zero, ty, .lt);
47904811
4791 try self.emitWValue(div_result);
4792 switch (ty.floatBits(self.target)) {
4793 32 => try self.addTag(.f32_floor),
4794 64 => try self.addTag(.f64_floor),
4795 else => |bit_size| return self.fail("TODO: `@divFloor` for floats with bitsize: {d}", .{bit_size}),
4812 try self.emitWValue(div_result);
4813 try self.emitWValue(lhs_less_than_zero);
4814 try self.emitWValue(rhs_less_than_zero);
4815 switch (wasm_bits) {
4816 32 => {
4817 try self.addTag(.i32_xor);
4818 try self.addTag(.i32_sub);
4819 },
4820 64 => {
4821 try self.addTag(.i64_xor);
4822 try self.addTag(.i64_sub);
4823 },
4824 else => unreachable,
4825 }
4826 try self.emitWValue(div_result);
4827 try self.emitWValue(rem_result);
4828 try self.addTag(.select);
4829 } else {
4830 const div_result = try self.binOp(lhs, rhs, ty, .div);
4831 try self.emitWValue(div_result);
4832 switch (ty.floatBits(self.target)) {
4833 32 => try self.addTag(.f32_floor),
4834 64 => try self.addTag(.f64_floor),
4835 else => |bit_size| return self.fail("TODO: `@divFloor` for floats with bitsize: {d}", .{bit_size}),
4836 }
47964837 }
47974838
47984839 const result = try self.allocLocal(ty);
......@@ -4811,17 +4852,10 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
48114852 }
48124853
48134854 if (wasm_bits != int_bits) {
4814 const shift_val = switch (wasm_bits) {
4815 32 => WValue{ .imm32 = wasm_bits - int_bits },
4816 64 => WValue{ .imm64 = wasm_bits - int_bits },
4817 else => unreachable,
4818 };
4819 const shl_lhs = try self.binOp(lhs, shift_val, ty, .shl);
4820 const shr_lhs = try self.binOp(shl_lhs, shift_val, ty, .shr);
4821 const shl_rhs = try self.binOp(rhs, shift_val, ty, .shl);
4822 const shr_rhs = try self.binOp(shl_rhs, shift_val, ty, .shr);
4823 try self.emitWValue(shr_lhs);
4824 try self.emitWValue(shr_rhs);
4855 const lhs_abs = try self.signAbsValue(lhs, ty);
4856 const rhs_abs = try self.signAbsValue(rhs, ty);
4857 try self.emitWValue(lhs_abs);
4858 try self.emitWValue(rhs_abs);
48254859 } else {
48264860 try self.emitWValue(lhs);
48274861 try self.emitWValue(rhs);
......@@ -4832,3 +4866,36 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
48324866 try self.addLabel(.local_set, result.local);
48334867 return result;
48344868}
4869
4870fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
4871 const int_bits = ty.intInfo(self.target).bits;
4872 const wasm_bits = toWasmBits(int_bits) orelse {
4873 return self.fail("TODO: signAbsValue for signed integers larger than '{d}' bits", .{int_bits});
4874 };
4875
4876 const shift_val = switch (wasm_bits) {
4877 32 => WValue{ .imm32 = wasm_bits - int_bits },
4878 64 => WValue{ .imm64 = wasm_bits - int_bits },
4879 else => return self.fail("TODO: signAbsValue for i128", .{}),
4880 };
4881
4882 try self.emitWValue(operand);
4883 switch (wasm_bits) {
4884 32 => {
4885 try self.emitWValue(shift_val);
4886 try self.addTag(.i32_shl);
4887 try self.emitWValue(shift_val);
4888 try self.addTag(.i32_shr_s);
4889 },
4890 64 => {
4891 try self.emitWValue(shift_val);
4892 try self.addTag(.i64_shl);
4893 try self.emitWValue(shift_val);
4894 try self.addTag(.i64_shr_s);
4895 },
4896 else => unreachable,
4897 }
4898 const result = try self.allocLocal(ty);
4899 try self.addLabel(.local_set, result.local);
4900 return result;
4901}