| ... | ... | @@ -1888,8 +1888,54 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1888 | 1888 | } |
| 1889 | 1889 | |
| 1890 | 1890 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1891 | | _ = inst; |
| 1892 | | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); |
| 1891 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1892 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1893 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 1894 | const result: MCValue = result: { |
| 1895 | const lhs = try self.resolveInst(extra.lhs); |
| 1896 | const rhs = try self.resolveInst(extra.rhs); |
| 1897 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 1898 | const rhs_ty = self.air.typeOf(extra.rhs); |
| 1899 | |
| 1900 | const tuple_ty = self.air.typeOfIndex(inst); |
| 1901 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); |
| 1902 | const tuple_align = tuple_ty.abiAlignment(self.target.*); |
| 1903 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); |
| 1904 | |
| 1905 | switch (lhs_ty.zigTypeTag()) { |
| 1906 | .Vector => return self.fail("TODO implement shl_with_overflow for vectors", .{}), |
| 1907 | .Int => { |
| 1908 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1909 | if (int_info.bits <= 64) { |
| 1910 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1911 | |
| 1912 | if (lhs == .register) self.register_manager.freezeRegs(&.{lhs.register}); |
| 1913 | defer if (lhs == .register) self.register_manager.unfreezeRegs(&.{lhs.register}); |
| 1914 | |
| 1915 | try self.spillCompareFlagsIfOccupied(); |
| 1916 | self.compare_flags_inst = null; |
| 1917 | |
| 1918 | // lsl dest, lhs, rhs |
| 1919 | const dest = try self.binOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty); |
| 1920 | |
| 1921 | // asr/lsr reconstructed, dest, rhs |
| 1922 | const reconstructed = try self.binOp(.shr, null, dest, rhs, lhs_ty, rhs_ty); |
| 1923 | |
| 1924 | // cmp lhs, reconstructed |
| 1925 | _ = try self.binOp(.cmp_eq, null, lhs, reconstructed, lhs_ty, lhs_ty); |
| 1926 | |
| 1927 | try self.genSetStack(lhs_ty, stack_offset, dest); |
| 1928 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq }); |
| 1929 | |
| 1930 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1931 | } else { |
| 1932 | return self.fail("TODO overflow operations on integers > u64/i64", .{}); |
| 1933 | } |
| 1934 | }, |
| 1935 | else => unreachable, |
| 1936 | } |
| 1937 | }; |
| 1938 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1893 | 1939 | } |
| 1894 | 1940 | |
| 1895 | 1941 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |