| ... | ... | @@ -2266,7 +2266,7 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( |
| 2266 | 2266 | const WantedT = std.meta.Int(.unsigned, @typeInfo(T).Int.bits); |
| 2267 | 2267 | if (value >= 0) return @bitCast(WantedT, value); |
| 2268 | 2268 | const max_value = @intCast(u64, (@as(u65, 1) << bits) - 1); |
| 2269 | | const flipped = (~-value) + 1; |
| 2269 | const flipped = @intCast(T, (~-@as(i65, value)) + 1); |
| 2270 | 2270 | const result = @bitCast(WantedT, flipped) & max_value; |
| 2271 | 2271 | return @intCast(WantedT, result); |
| 2272 | 2272 | } |
| ... | ... | @@ -2294,7 +2294,10 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 2294 | 2294 | val.toSignedInt(), |
| 2295 | 2295 | @intCast(u6, int_info.bits), |
| 2296 | 2296 | )) }, |
| 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 | ) }, |
| 2298 | 2301 | else => unreachable, |
| 2299 | 2302 | }, |
| 2300 | 2303 | .unsigned => switch (int_info.bits) { |
| ... | ... | @@ -4781,18 +4784,56 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4781 | 4784 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4782 | 4785 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4783 | 4786 | |
| 4784 | | const div_result = try self.binOp(lhs, rhs, ty, .div); |
| 4785 | 4787 | if (ty.isUnsignedInt()) { |
| 4786 | | return div_result; |
| 4788 | return self.binOp(lhs, rhs, ty, .div); |
| 4787 | 4789 | } 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); |
| 4790 | 4811 | |
| 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 | } |
| 4796 | 4837 | } |
| 4797 | 4838 | |
| 4798 | 4839 | const result = try self.allocLocal(ty); |
| ... | ... | @@ -4811,17 +4852,10 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue |
| 4811 | 4852 | } |
| 4812 | 4853 | |
| 4813 | 4854 | 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); |
| 4825 | 4859 | } else { |
| 4826 | 4860 | try self.emitWValue(lhs); |
| 4827 | 4861 | try self.emitWValue(rhs); |
| ... | ... | @@ -4832,3 +4866,36 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue |
| 4832 | 4866 | try self.addLabel(.local_set, result.local); |
| 4833 | 4867 | return result; |
| 4834 | 4868 | } |
| 4869 | |
| 4870 | fn 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 | } |