authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-02 04:34:14-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-02 04:49:53-04:00
logc713c863896d4ef6b4fd0817e8db59f5992b2303
treef74a229e227356d22f6e02f1eec44363e95c8c6e
parentb80cdde4f079181ad4b3ba937771fcfd1de94bdb

x86_64: implement wide multiply


1 files changed, 210 insertions(+), 147 deletions(-)

src/arch/x86_64/CodeGen.zig+210-147
......@@ -1625,24 +1625,68 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
16251625 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
16261626}
16271627
1628fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 {
1629 const air_tag = self.air.instructions.items(.tag);
1630 const air_data = self.air.instructions.items(.data);
1631
1632 const dst_ty = self.air.typeOf(dst_air);
1633 const dst_info = dst_ty.intInfo(self.target.*);
1634 if (Air.refToIndex(dst_air)) |inst| {
1635 switch (air_tag[inst]) {
1636 .constant => {
1637 const src_val = self.air.values[air_data[inst].ty_pl.payload];
1638 var space: Value.BigIntSpace = undefined;
1639 const src_int = src_val.toBigInt(&space, self.target.*);
1640 return @intCast(u16, src_int.bitCountTwosComp()) +
1641 @boolToInt(src_int.positive and dst_info.signedness == .signed);
1642 },
1643 .intcast => {
1644 const src_ty = self.air.typeOf(air_data[inst].ty_op.operand);
1645 const src_info = src_ty.intInfo(self.target.*);
1646 return @min(switch (src_info.signedness) {
1647 .signed => switch (dst_info.signedness) {
1648 .signed => src_info.bits,
1649 .unsigned => src_info.bits - 1,
1650 },
1651 .unsigned => switch (dst_info.signedness) {
1652 .signed => src_info.bits + 1,
1653 .unsigned => src_info.bits,
1654 },
1655 }, dst_info.bits);
1656 },
1657 else => {},
1658 }
1659 }
1660 return dst_info.bits;
1661}
1662
16281663fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
16291664 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1630 const result = result: {
1631 if (self.liveness.isUnused(inst)) break :result .dead;
1632
1665 const result = if (self.liveness.isUnused(inst)) .dead else result: {
16331666 const tag = self.air.instructions.items(.tag)[inst];
1634 const ty = self.air.typeOfIndex(inst);
1635
1636 if (ty.zigTypeTag() == .Float) {
1667 const dst_ty = self.air.typeOfIndex(inst);
1668 if (dst_ty.zigTypeTag() == .Float)
16371669 break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
1638 }
16391670
1640 try self.spillRegisters(&.{ .rax, .rdx });
1671 const dst_info = dst_ty.intInfo(self.target.*);
1672 var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) {
1673 .signed => .int_signed,
1674 .unsigned => .int_unsigned,
1675 } }, .data = switch (tag) {
1676 else => unreachable,
1677 .mul, .mulwrap => std.math.max3(
1678 self.activeIntBits(bin_op.lhs),
1679 self.activeIntBits(bin_op.rhs),
1680 dst_info.bits / 2,
1681 ),
1682 .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_info.bits,
1683 } };
1684 const src_ty = Type.initPayload(&src_pl.base);
16411685
1686 try self.spillRegisters(&.{ .rax, .rdx });
16421687 const lhs = try self.resolveInst(bin_op.lhs);
16431688 const rhs = try self.resolveInst(bin_op.rhs);
1644
1645 break :result try self.genMulDivBinOp(tag, inst, ty, lhs, rhs);
1689 break :result try self.genMulDivBinOp(tag, inst, dst_ty, src_ty, lhs, rhs);
16461690 };
16471691 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
16481692}
......@@ -1795,7 +1839,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
17951839 break :cc .c;
17961840 };
17971841
1798 const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, lhs_mcv, rhs_mcv);
1842 const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv);
17991843 const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2));
18001844 try self.asmCmovccRegisterRegister(
18011845 registerAlias(dst_mcv.register, abi_size),
......@@ -1809,9 +1853,9 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
18091853
18101854fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
18111855 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1812 const tag = self.air.instructions.items(.tag)[inst];
18131856 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1814 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1857 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1858 const tag = self.air.instructions.items(.tag)[inst];
18151859 const ty = self.air.typeOf(bin_op.lhs);
18161860 const abi_size = ty.abiSize(self.target.*);
18171861 switch (ty.zigTypeTag()) {
......@@ -1842,21 +1886,17 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
18421886
18431887 const int_info = ty.intInfo(self.target.*);
18441888
1845 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1889 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
18461890 self.eflags_inst = inst;
1847
1848 const cc: Condition = switch (int_info.signedness) {
1849 .unsigned => .c,
1850 .signed => .o,
1851 };
1852 break :result MCValue{ .register_overflow = .{
1891 break :result .{ .register_overflow = .{
18531892 .reg = partial.register,
1854 .eflags = cc,
1893 .eflags = switch (int_info.signedness) {
1894 .unsigned => .c,
1895 .signed => .o,
1896 },
18551897 } };
18561898 }
18571899
1858 self.eflags_inst = null;
1859
18601900 const tuple_ty = self.air.typeOfIndex(inst);
18611901 const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));
18621902 const tuple_align = tuple_ty.abiAlignment(self.target.*);
......@@ -1865,12 +1905,11 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
18651905
18661906 try self.genSetStackTruncatedOverflowCompare(ty, stack_offset, overflow_bit_offset, partial.register);
18671907
1868 break :result MCValue{ .stack_offset = stack_offset };
1908 break :result .{ .stack_offset = stack_offset };
18691909 },
18701910 else => unreachable,
18711911 }
18721912 };
1873
18741913 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
18751914}
18761915
......@@ -1931,48 +1970,56 @@ fn genSetStackTruncatedOverflowCompare(
19311970fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19321971 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
19331972 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1934
1935 if (self.liveness.isUnused(inst)) {
1936 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1937 }
1938
1939 const ty = self.air.typeOf(bin_op.lhs);
1940 const abi_size = ty.abiSize(self.target.*);
1941 const result: MCValue = result: {
1942 switch (ty.zigTypeTag()) {
1973 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1974 const dst_ty = self.air.typeOf(bin_op.lhs);
1975 switch (dst_ty.zigTypeTag()) {
19431976 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
19441977 .Int => {
1945 if (abi_size > 8) {
1946 return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{});
1947 }
1948
1949 const int_info = ty.intInfo(self.target.*);
1978 try self.spillEflagsIfOccupied();
19501979
1951 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1952 try self.spillEflagsIfOccupied();
1953 self.eflags_inst = inst;
1980 const dst_info = dst_ty.intInfo(self.target.*);
1981 if (dst_info.bits >= 8 and math.isPowerOfTwo(dst_info.bits)) {
1982 var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) {
1983 .signed => .int_signed,
1984 .unsigned => .int_unsigned,
1985 } }, .data = std.math.max3(
1986 self.activeIntBits(bin_op.lhs),
1987 self.activeIntBits(bin_op.rhs),
1988 dst_info.bits / 2,
1989 ) };
1990 const src_ty = Type.initPayload(&src_pl.base);
19541991
19551992 try self.spillRegisters(&.{ .rax, .rdx });
1956
19571993 const lhs = try self.resolveInst(bin_op.lhs);
19581994 const rhs = try self.resolveInst(bin_op.rhs);
19591995
1960 const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs);
1961 const cc: Condition = switch (int_info.signedness) {
1996 const partial = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs);
1997 const cc: Condition = switch (dst_info.signedness) {
19621998 .unsigned => .c,
19631999 .signed => .o,
19642000 };
1965 break :result MCValue{ .register_overflow = .{
1966 .reg = partial.register,
1967 .eflags = cc,
1968 } };
1969 }
2001 switch (partial) {
2002 .register => |reg| {
2003 self.eflags_inst = inst;
2004 break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
2005 },
2006 else => {},
2007 }
19702008
1971 try self.spillEflagsIfOccupied();
1972 self.eflags_inst = null;
2009 const dst_abi_size = @intCast(i32, dst_ty.abiSize(self.target.*));
2010 const dst_mcv = try self.allocRegOrMem(inst, false);
2011 try self.genSetStack(
2012 Type.u1,
2013 dst_mcv.stack_offset - dst_abi_size,
2014 .{ .eflags = cc },
2015 .{},
2016 );
2017 try self.genSetStack(dst_ty, dst_mcv.stack_offset, partial, .{});
2018 break :result dst_mcv;
2019 }
19732020
19742021 const dst_reg: Register = dst_reg: {
1975 switch (int_info.signedness) {
2022 switch (dst_info.signedness) {
19762023 .signed => {
19772024 const lhs = try self.resolveInst(bin_op.lhs);
19782025 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -1985,14 +2032,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19852032
19862033 const dst_reg: Register = blk: {
19872034 if (lhs.isRegister()) break :blk lhs.register;
1988 break :blk try self.copyToTmpRegister(ty, lhs);
2035 break :blk try self.copyToTmpRegister(dst_ty, lhs);
19892036 };
19902037 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
19912038 defer self.register_manager.unlockReg(dst_reg_lock);
19922039
19932040 const rhs_mcv: MCValue = blk: {
19942041 if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
1995 break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) };
2042 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) };
19962043 };
19972044 const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) {
19982045 .register => |reg| self.register_manager.lockReg(reg),
......@@ -2010,7 +2057,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20102057 const lhs = try self.resolveInst(bin_op.lhs);
20112058 const rhs = try self.resolveInst(bin_op.rhs);
20122059
2013 const dst_mcv = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs);
2060 const dst_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, dst_ty, lhs, rhs);
20142061 break :dst_reg dst_mcv.register;
20152062 },
20162063 }
......@@ -2022,14 +2069,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20222069 const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*));
20232070 const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align));
20242071
2025 try self.genSetStackTruncatedOverflowCompare(ty, stack_offset, overflow_bit_offset, dst_reg);
2072 try self.genSetStackTruncatedOverflowCompare(dst_ty, stack_offset, overflow_bit_offset, dst_reg);
20262073
2027 break :result MCValue{ .stack_offset = stack_offset };
2074 break :result .{ .stack_offset = stack_offset };
20282075 },
20292076 else => unreachable,
20302077 }
20312078 };
2032
20332079 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
20342080}
20352081
......@@ -2040,7 +2086,6 @@ fn genIntMulDivOpMir(
20402086 self: *Self,
20412087 tag: Mir.Inst.Tag,
20422088 ty: Type,
2043 signedness: std.builtin.Signedness,
20442089 lhs: MCValue,
20452090 rhs: MCValue,
20462091) !void {
......@@ -2057,26 +2102,23 @@ fn genIntMulDivOpMir(
20572102 try self.genSetReg(ty, .rax, lhs);
20582103 }
20592104
2060 switch (signedness) {
2061 .signed => try self.asmOpOnly(.cqo),
2062 .unsigned => try self.asmRegisterRegister(.xor, .rdx, .rdx),
2105 switch (tag) {
2106 else => unreachable,
2107 .mul, .imul => {},
2108 .div => try self.asmRegisterRegister(.xor, .edx, .edx),
2109 .idiv => try self.asmOpOnly(.cqo),
20632110 }
20642111
2065 const factor = switch (rhs) {
2066 .register => rhs,
2067 .stack_offset => rhs,
2068 else => blk: {
2069 const reg = try self.copyToTmpRegister(ty, rhs);
2070 break :blk MCValue{ .register = reg };
2071 },
2112 const factor: MCValue = switch (rhs) {
2113 .register, .stack_offset => rhs,
2114 else => .{ .register = try self.copyToTmpRegister(ty, rhs) },
20722115 };
2073
20742116 switch (factor) {
20752117 .register => |reg| try self.asmRegister(tag, reg),
2076 .stack_offset => |off| try self.asmMemory(tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
2077 .base = .rbp,
2078 .disp = -off,
2079 })),
2118 .stack_offset => |off| try self.asmMemory(tag, Memory.sib(
2119 Memory.PtrSize.fromSize(abi_size),
2120 .{ .base = .rbp, .disp = -off },
2121 )),
20802122 else => unreachable,
20812123 }
20822124}
......@@ -2102,7 +2144,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
21022144 try self.genIntMulDivOpMir(switch (signedness) {
21032145 .signed => .idiv,
21042146 .unsigned => .div,
2105 }, Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor });
2147 }, Type.isize, .{ .register = dividend }, .{ .register = divisor });
21062148
21072149 try self.asmRegisterRegister(.xor, divisor.to64(), dividend.to64());
21082150 try self.asmRegisterImmediate(.sar, divisor.to64(), Immediate.u(63));
......@@ -3938,14 +3980,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
39383980 .register_overflow => |ro| {
39393981 switch (index) {
39403982 // Get wrapped value for overflow operation.
3941 0 => if (self.liveness.operandDies(inst, 0)) {
3942 self.eflags_inst = null;
3943 break :result .{ .register = ro.reg };
3944 } else break :result try self.copyToRegisterWithInstTracking(
3945 inst,
3946 Type.usize,
3947 .{ .register = ro.reg },
3948 ),
3983 0 => break :result if (self.liveness.operandDies(inst, 0))
3984 .{ .register = ro.reg }
3985 else
3986 try self.copyToRegisterWithInstTracking(
3987 inst,
3988 Type.usize,
3989 .{ .register = ro.reg },
3990 ),
39493991 // Get overflow bit.
39503992 1 => if (self.liveness.operandDies(inst, 0)) {
39513993 self.eflags_inst = inst;
......@@ -4318,20 +4360,26 @@ fn genMulDivBinOp(
43184360 self: *Self,
43194361 tag: Air.Inst.Tag,
43204362 maybe_inst: ?Air.Inst.Index,
4321 ty: Type,
4363 dst_ty: Type,
4364 src_ty: Type,
43224365 lhs: MCValue,
43234366 rhs: MCValue,
43244367) !MCValue {
4325 if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {
4326 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
4327 }
4328 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4329 if (abi_size > 8) {
4330 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
4331 }
4332 if (tag == .div_float) {
4333 return self.fail("TODO implement genMulDivBinOp for div_float", .{});
4368 if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) {
4369 return self.fail("TODO implement genMulDivBinOp for {}", .{dst_ty.fmtDebug()});
43344370 }
4371 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
4372 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
4373 if (switch (tag) {
4374 else => unreachable,
4375 .mul, .mulwrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2,
4376 .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size,
4377 } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{
4378 src_ty.fmt(self.bin_file.options.module.?),
4379 dst_ty.fmt(self.bin_file.options.module.?),
4380 });
4381 const ty = if (dst_abi_size <= 8) dst_ty else src_ty;
4382 const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size;
43354383
43364384 assert(self.register_manager.isRegFree(.rax));
43374385 assert(self.register_manager.isRegFree(.rdx));
......@@ -4339,9 +4387,7 @@ fn genMulDivBinOp(
43394387 const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
43404388 defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
43414389
4342 const int_info = ty.intInfo(self.target.*);
4343 const signedness = int_info.signedness;
4344
4390 const signedness = ty.intInfo(self.target.*).signedness;
43454391 switch (tag) {
43464392 .mul,
43474393 .mulwrap,
......@@ -4349,11 +4395,12 @@ fn genMulDivBinOp(
43494395 .div_trunc,
43504396 .div_exact,
43514397 => {
4352 const track_inst_rax: ?Air.Inst.Index = switch (tag) {
4353 .mul, .mulwrap, .div_exact, .div_trunc => maybe_inst,
4398 const track_inst_rax = switch (tag) {
4399 .mul, .mulwrap => if (dst_abi_size <= 8) maybe_inst else null,
4400 .div_exact, .div_trunc => maybe_inst,
43544401 else => null,
43554402 };
4356 const track_inst_rdx: ?Air.Inst.Index = switch (tag) {
4403 const track_inst_rdx = switch (tag) {
43574404 .rem => maybe_inst,
43584405 else => null,
43594406 };
......@@ -4373,13 +4420,24 @@ fn genMulDivBinOp(
43734420 },
43744421 };
43754422
4376 try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs);
4423 try self.genIntMulDivOpMir(mir_tag, ty, lhs, rhs);
43774424
4378 return .{ .register = registerAlias(switch (tag) {
4425 if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {
43794426 .mul, .mulwrap, .div_trunc, .div_exact => .rax,
43804427 .rem => .rdx,
43814428 else => unreachable,
4382 }, abi_size) };
4429 }, dst_abi_size) };
4430
4431 const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false);
4432 try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{
4433 .base = .rbp,
4434 .disp = 0 - dst_mcv.stack_offset,
4435 }), .rax);
4436 try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{
4437 .base = .rbp,
4438 .disp = 8 - dst_mcv.stack_offset,
4439 }), .rdx);
4440 return dst_mcv;
43834441 },
43844442
43854443 .mod => {
......@@ -4402,7 +4460,7 @@ fn genMulDivBinOp(
44024460 return result;
44034461 },
44044462 .unsigned => {
4405 try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs);
4463 try self.genIntMulDivOpMir(.div, ty, lhs, rhs);
44064464 return .{ .register = registerAlias(.rdx, abi_size) };
44074465 },
44084466 }
......@@ -4441,18 +4499,13 @@ fn genMulDivBinOp(
44414499 };
44424500 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
44434501
4444 const result: MCValue = result: {
4445 switch (signedness) {
4446 .signed => break :result try self.genInlineIntDivFloor(ty, lhs, actual_rhs),
4447 .unsigned => {
4448 try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, actual_rhs);
4449 break :result MCValue{
4450 .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))),
4451 };
4452 },
4453 }
4454 };
4455 return result;
4502 switch (signedness) {
4503 .signed => return try self.genInlineIntDivFloor(ty, lhs, actual_rhs),
4504 .unsigned => {
4505 try self.genIntMulDivOpMir(.div, ty, lhs, actual_rhs);
4506 return .{ .register = registerAlias(.rax, abi_size) };
4507 },
4508 }
44564509 },
44574510
44584511 else => unreachable,
......@@ -6718,6 +6771,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
67186771}
67196772
67206773fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: InlineMemcpyOpts) InnerError!void {
6774 const base_reg = opts.dest_stack_base orelse .rbp;
67216775 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
67226776 switch (mcv) {
67236777 .dead => unreachable,
......@@ -6733,12 +6787,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
67336787 4 => 0xaaaaaaaa,
67346788 else => unreachable,
67356789 };
6736 return self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
6737 .base = opts.dest_stack_base orelse .rbp,
6738 .disp = -stack_offset,
6739 }), Immediate.u(value));
6790 return self.asmMemoryImmediate(.mov, Memory.sib(
6791 Memory.PtrSize.fromSize(abi_size),
6792 .{ .base = base_reg, .disp = -stack_offset },
6793 ), Immediate.u(value));
67406794 },
6741 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, opts),
6795 8 => return self.genSetStack(
6796 ty,
6797 stack_offset,
6798 .{ .immediate = 0xaaaaaaaaaaaaaaaa },
6799 opts,
6800 ),
67426801 else => |x| return self.genInlineMemset(
67436802 .{ .stack_offset = stack_offset },
67446803 .{ .immediate = 0xaa },
......@@ -6766,12 +6825,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
67666825 .{},
67676826 );
67686827 },
6769 .eflags => {
6770 const reg = try self.copyToTmpRegister(ty, mcv);
6771 return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts);
6772 },
6773 .immediate => |x_big| {
6774 const base_reg = opts.dest_stack_base orelse .rbp;
6828 .eflags => |cc| try self.asmSetccMemory(
6829 Memory.sib(.byte, .{ .base = base_reg, .disp = -stack_offset }),
6830 cc,
6831 ),
6832 .immediate => |imm| {
67756833 // TODO
67766834 switch (abi_size) {
67776835 0 => {
......@@ -6779,13 +6837,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
67796837 try self.asmMemoryImmediate(.mov, Memory.sib(.byte, .{
67806838 .base = base_reg,
67816839 .disp = -stack_offset,
6782 }), Immediate.u(@truncate(u8, x_big)));
6840 }), Immediate.u(@truncate(u8, imm)));
67836841 },
67846842 1, 2, 4 => {
67856843 const immediate = if (ty.isSignedInt())
6786 Immediate.s(@truncate(i32, @bitCast(i64, x_big)))
6844 Immediate.s(@truncate(i32, @bitCast(i64, imm)))
67876845 else
6788 Immediate.u(@intCast(u32, x_big));
6846 Immediate.u(@intCast(u32, imm));
67896847 try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
67906848 .base = base_reg,
67916849 .disp = -stack_offset,
......@@ -6795,27 +6853,32 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
67956853 else => {
67966854 // 64 bit write to memory would take two mov's anyways so we
67976855 // insted just use two 32 bit writes to avoid register allocation
6798 var offset: i32 = 0;
6799 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
6800 .mov,
6801 Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }),
6802 if (ty.isSignedInt())
6803 Immediate.s(@truncate(
6804 i32,
6805 @bitCast(i64, x_big) >> (math.cast(u6, offset * 8) orelse 63),
6806 ))
6807 else
6808 Immediate.u(@truncate(
6809 u32,
6810 if (math.cast(u6, offset * 8)) |shift| x_big >> shift else 0,
6811 )),
6812 );
6856 if (std.math.cast(i32, @bitCast(i64, imm))) |small| {
6857 try self.asmMemoryImmediate(.mov, Memory.sib(
6858 Memory.PtrSize.fromSize(abi_size),
6859 .{ .base = base_reg, .disp = -stack_offset },
6860 ), Immediate.s(small));
6861 } else {
6862 var offset: i32 = 0;
6863 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
6864 .mov,
6865 Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }),
6866 if (ty.isSignedInt())
6867 Immediate.s(@truncate(
6868 i32,
6869 @bitCast(i64, imm) >> (math.cast(u6, offset * 8) orelse 63),
6870 ))
6871 else
6872 Immediate.u(@truncate(
6873 u32,
6874 if (math.cast(u6, offset * 8)) |shift| imm >> shift else 0,
6875 )),
6876 );
6877 }
68136878 },
68146879 }
68156880 },
68166881 .register => |reg| {
6817 const base_reg = opts.dest_stack_base orelse .rbp;
6818
68196882 switch (ty.zigTypeTag()) {
68206883 .Float => {
68216884 if (intrinsicsAllowed(self.target.*, ty)) {