authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-04-03 12:09:07-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-05 20:49:56-04:00
log9827ffe1ded884796aafe21cd6f6941f5ac3a279
tree2a4d390be7beaca88916ef4ac9c5dd34b4ae9f2a
parent95fdbc579fc1df3c575baded7ec5edc1c3ce6e6d

x86_64: fix incorrect handling of unreusable operands

Closes #23448

2 files changed, 55 insertions(+), 4 deletions(-)

src/arch/x86_64/CodeGen.zig+12-3
...@@ -104889,8 +104889,9 @@ const Temp = struct {...@@ -104889,8 +104889,9 @@ const Temp = struct {
104889 const result_temp: Temp = .{ .index = result_temp_index.toIndex() };104889 const result_temp: Temp = .{ .index = result_temp_index.toIndex() };
104890 assert(cg.reuseTemp(result_temp.index, first_temp.index, first_temp_tracking));104890 assert(cg.reuseTemp(result_temp.index, first_temp.index, first_temp_tracking));
104891 assert(cg.reuseTemp(result_temp.index, second_temp.index, second_temp_tracking));104891 assert(cg.reuseTemp(result_temp.index, second_temp.index, second_temp_tracking));
104892 cg.temp_type[@intFromEnum(result_temp_index)] = .slice_const_u8;
104893 result_temp_index.tracking(cg).* = .init(result);104892 result_temp_index.tracking(cg).* = .init(result);
104893 cg.temp_type[@intFromEnum(result_temp_index)] = .slice_const_u8;
104894 cg.next_temp_index = @enumFromInt(@intFromEnum(result_temp_index) + 1);
104894 first_temp.* = result_temp;104895 first_temp.* = result_temp;
104895 second_temp.* = result_temp;104896 second_temp.* = result_temp;
104896 }104897 }
...@@ -109598,7 +109599,8 @@ const Temp = struct {...@@ -109598,7 +109599,8 @@ const Temp = struct {
109598 ) InnerError!void {109599 ) InnerError!void {
109599 const tomb_bits = cg.liveness.getTombBits(inst);109600 const tomb_bits = cg.liveness.getTombBits(inst);
109600 for (0.., op_refs, op_temps) |op_index, op_ref, op_temp| {109601 for (0.., op_refs, op_temps) |op_index, op_ref, op_temp| {
109601 if (op_temp.index != temp.index and op_temp.tracking(cg).short != .dead) try op_temp.die(cg);109602 if (op_temp.index == temp.index) continue;
109603 if (op_temp.tracking(cg).short != .dead) try op_temp.die(cg);
109602 if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;109604 if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
109603 if (cg.reused_operands.isSet(op_index)) continue;109605 if (cg.reused_operands.isSet(op_index)) continue;
109604 try cg.processDeath(op_ref.toIndexAllowNone() orelse continue);109606 try cg.processDeath(op_ref.toIndexAllowNone() orelse continue);
...@@ -109617,6 +109619,12 @@ const Temp = struct {...@@ -109617,6 +109619,12 @@ const Temp = struct {
109617 assert(cg.reuseTemp(inst, temp_index.toIndex(), temp_tracking));109619 assert(cg.reuseTemp(inst, temp_index.toIndex(), temp_tracking));
109618 },109620 },
109619 }109621 }
109622 for (0.., op_refs, op_temps) |op_index, op_ref, op_temp| {
109623 if (op_temp.index != temp.index) continue;
109624 if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
109625 if (cg.reused_operands.isSet(op_index)) continue;
109626 try cg.processDeath(op_ref.toIndexAllowNone() orelse continue);
109627 }
109620 }109628 }
109621109629
109622 fn die(temp: Temp, cg: *CodeGen) InnerError!void {109630 fn die(temp: Temp, cg: *CodeGen) InnerError!void {
...@@ -109642,7 +109650,8 @@ const Temp = struct {...@@ -109642,7 +109650,8 @@ const Temp = struct {
109642 }109650 }
109643109651
109644 fn isValid(index: Index, cg: *CodeGen) bool {109652 fn isValid(index: Index, cg: *CodeGen) bool {
109645 return index.tracking(cg).short != .dead;109653 return @intFromEnum(index) < @intFromEnum(cg.next_temp_index) and
109654 index.tracking(cg).short != .dead;
109646 }109655 }
109647109656
109648 fn typeOf(index: Index, cg: *CodeGen) Type {109657 fn typeOf(index: Index, cg: *CodeGen) Type {
test/behavior/struct.zig+43-1
...@@ -1527,7 +1527,7 @@ test "optional generic function label struct field" {...@@ -1527,7 +1527,7 @@ test "optional generic function label struct field" {
1527}1527}
15281528
1529test "struct fields get automatically reordered" {1529test "struct fields get automatically reordered" {
1530 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO1530 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
15311531
1532 const S1 = struct {1532 const S1 = struct {
1533 a: u32,1533 a: u32,
...@@ -2137,3 +2137,45 @@ test "anonymous struct equivalence" {...@@ -2137,3 +2137,45 @@ test "anonymous struct equivalence" {
2137 comptime assert(A != C);2137 comptime assert(A != C);
2138 comptime assert(B != C);2138 comptime assert(B != C);
2139}2139}
2140
2141test "field access through mem ptr arg" {
2142 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2143
2144 const S = struct {
2145 fn nestedFieldAccess(
2146 _: usize,
2147 _: usize,
2148 _: usize,
2149 _: usize,
2150 _: usize,
2151 _: usize,
2152 _: usize,
2153 _: usize,
2154 ptr_struct: *const struct { field: u32 },
2155 ) u32 {
2156 return ptr_struct.field;
2157 }
2158 };
2159 try expect(S.nestedFieldAccess(
2160 undefined,
2161 undefined,
2162 undefined,
2163 undefined,
2164 undefined,
2165 undefined,
2166 undefined,
2167 undefined,
2168 &.{ .field = 0x6b00a2eb },
2169 ) == 0x6b00a2eb);
2170 comptime assert(S.nestedFieldAccess(
2171 undefined,
2172 undefined,
2173 undefined,
2174 undefined,
2175 undefined,
2176 undefined,
2177 undefined,
2178 undefined,
2179 &.{ .field = 0x0ced271f },
2180 ) == 0x0ced271f);
2181}