Skip to content

Commit 18d3d51

Browse files
committed
x86_64: fix switch dispatch bug
Also closes #23902
1 parent dd5d4ea commit 18d3d51

File tree

6 files changed

+33
-18
lines changed

6 files changed

+33
-18
lines changed

src/Compilation.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ pub const Directories = struct {
774774
/// `comp.debug_incremental`. It is inline so that comptime-known `false` propagates to the caller,
775775
/// preventing debugging features from making it into release builds of the compiler.
776776
pub inline fn debugIncremental(comp: *const Compilation) bool {
777-
if (!build_options.enable_debug_extensions) return false;
777+
if (!build_options.enable_debug_extensions or builtin.single_threaded) return false;
778778
return comp.debug_incremental;
779779
}
780780

src/IncrementalDebugServer.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
comptime {
1212
// This file should only be referenced when debug extensions are enabled.
13-
std.debug.assert(@import("build_options").enable_debug_extensions);
13+
std.debug.assert(@import("build_options").enable_debug_extensions and !@import("builtin").single_threaded);
1414
}
1515

1616
zcu: *Zcu,

src/arch/x86_64/CodeGen.zig

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -161505,10 +161505,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
161505161505
for (elems, 0..) |elem_ref, field_index| {
161506161506
const elem_dies = bt.feed();
161507161507
if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
161508-
var elem = try cg.tempFromOperand(elem_ref, elem_dies);
161509-
try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);
161510-
try elem.die(cg);
161511-
try cg.resetTemps(reset_index);
161508+
if (!hack_around_sema_opv_bugs or Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]).hasRuntimeBitsIgnoreComptime(zcu)) {
161509+
var elem = try cg.tempFromOperand(elem_ref, elem_dies);
161510+
try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);
161511+
try elem.die(cg);
161512+
try cg.resetTemps(reset_index);
161513+
}
161512161514
}
161513161515
},
161514161516
.@"packed" => return cg.fail("failed to select {s} {}", .{
@@ -175015,8 +175017,7 @@ fn lowerSwitchBr(
175015175017
) !void {
175016175018
const zcu = cg.pt.zcu;
175017175019
const condition_ty = cg.typeOf(switch_br.operand);
175018-
const condition_int_info = cg.intInfo(condition_ty).?;
175019-
const condition_int_ty = try cg.pt.intType(condition_int_info.signedness, condition_int_info.bits);
175020+
const unsigned_condition_ty = try cg.pt.intType(.unsigned, cg.intInfo(condition_ty).?.bits);
175020175021

175021175022
const ExpectedContents = extern struct {
175022175023
liveness_deaths: [1 << 8 | 1]Air.Inst.Index,
@@ -175087,8 +175088,8 @@ fn lowerSwitchBr(
175087175088
.{ .air_ref = Air.internedToRef(min.?.toIntern()) },
175088175089
);
175089175090
const else_reloc = if (switch_br.else_body_len > 0) else_reloc: {
175090-
var cond_temp = try cg.tempInit(condition_ty, condition_index);
175091-
var table_max_temp = try cg.tempFromValue(try cg.pt.intValue(condition_int_ty, table_len - 1));
175091+
var cond_temp = try cg.tempInit(unsigned_condition_ty, condition_index);
175092+
var table_max_temp = try cg.tempFromValue(try cg.pt.intValue(unsigned_condition_ty, table_len - 1));
175092175093
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, cg) catch |err| switch (err) {
175093175094
error.SelectFailed => unreachable,
175094175095
else => |e| return e,
@@ -175416,8 +175417,7 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175416175417

175417175418
if (self.loop_switches.getPtr(br.block_inst)) |table| {
175418175419
const condition_ty = self.typeOf(br.operand);
175419-
const condition_int_info = self.intInfo(condition_ty).?;
175420-
const condition_int_ty = try self.pt.intType(condition_int_info.signedness, condition_int_info.bits);
175420+
const unsigned_condition_ty = try self.pt.intType(.unsigned, self.intInfo(condition_ty).?.bits);
175421175421
const condition_mcv = block_tracking.short;
175422175422
try self.spillEflagsIfOccupied();
175423175423
if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir(
@@ -175429,8 +175429,8 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175429175429
switch (table.else_relocs) {
175430175430
.@"unreachable" => {},
175431175431
.forward => |*else_relocs| {
175432-
var cond_temp = try self.tempInit(condition_ty, condition_mcv);
175433-
var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));
175432+
var cond_temp = try self.tempInit(unsigned_condition_ty, condition_mcv);
175433+
var table_max_temp = try self.tempFromValue(try self.pt.intValue(unsigned_condition_ty, table.len - 1));
175434175434
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
175435175435
error.SelectFailed => unreachable,
175436175436
else => |e| return e,
@@ -175441,8 +175441,8 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175441175441
try cc_temp.die(self);
175442175442
},
175443175443
.backward => |else_reloc| {
175444-
var cond_temp = try self.tempInit(condition_ty, condition_mcv);
175445-
var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));
175444+
var cond_temp = try self.tempInit(unsigned_condition_ty, condition_mcv);
175445+
var table_max_temp = try self.tempFromValue(try self.pt.intValue(unsigned_condition_ty, table.len - 1));
175446175446
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
175447175447
error.SelectFailed => unreachable,
175448175448
else => |e| return e,

src/main.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ test {
3939
_ = Package;
4040
}
4141

42-
const thread_stack_size = 50 << 20;
42+
const thread_stack_size = 60 << 20;
4343

4444
pub const std_options: std.Options = .{
4545
.wasiCwd = wasi_cwd,
@@ -4208,7 +4208,7 @@ fn serve(
42084208
const main_progress_node = std.Progress.start(.{});
42094209
const file_system_inputs = comp.file_system_inputs.?;
42104210

4211-
const IncrementalDebugServer = if (build_options.enable_debug_extensions)
4211+
const IncrementalDebugServer = if (build_options.enable_debug_extensions and !builtin.single_threaded)
42124212
@import("IncrementalDebugServer.zig")
42134213
else
42144214
void;

test/behavior/switch.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,3 +1056,12 @@ test "unlabeled break ignores switch" {
10561056
};
10571057
try expect(result == 123);
10581058
}
1059+
1060+
test "switch on a signed value smaller than the smallest prong value" {
1061+
var v: i32 = undefined;
1062+
v = -1;
1063+
switch (v) {
1064+
inline 0...10 => return error.TestFailed,
1065+
else => {},
1066+
}
1067+
}

test/standalone/stack_iterator/build.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ pub fn build(b: *std.Build) void {
5252
.unwind_tables = .@"async",
5353
.omit_frame_pointer = true,
5454
}),
55+
// self-hosted lacks omit_frame_pointer support
56+
.use_llvm = true,
5557
});
5658

5759
const run_cmd = b.addRunArtifact(exe);
@@ -97,6 +99,8 @@ pub fn build(b: *std.Build) void {
9799
.unwind_tables = if (target.result.os.tag.isDarwin()) .@"async" else null,
98100
.omit_frame_pointer = true,
99101
}),
102+
// zig objcopy doesn't support incremental binaries
103+
.use_llvm = true,
100104
});
101105

102106
exe.linkLibrary(c_shared_lib);
@@ -137,6 +141,8 @@ pub fn build(b: *std.Build) void {
137141
.unwind_tables = null,
138142
.omit_frame_pointer = false,
139143
}),
144+
// self-hosted lacks omit_frame_pointer support
145+
.use_llvm = true,
140146
});
141147

142148
// This "freestanding" binary is runnable because it invokes the

0 commit comments

Comments
 (0)