compiler: add -flegalize-all option

This option is intended for compiler development and testing. It forces
all `Air.Legalize` passes to be enabled, so we can exhaustively test the
functionality of legalization passes even before any backend enables
them. The option is limited to the LLVM backend, because enabling
legalizations often requires some level of backend support (e.g. support
for the `legalize_compiler_rt_call` instruction tag), and it's usually
fairly simple to support these in the LLVM backend *and* gets us a lot
of test coverage (in particular, it lets us test on both big-endian and
little-endian targets).
This commit is contained in:
Matthew Lugg committed 2026-10-26 14:17:03 +00:00
1 parent 9ebba3b64d
commit 405cc93b89
5 files changed
+77 -2

No files matched your search

+17
View File
@@ -325,6 +325,23 @@ pub const Feature = enum {
pub const Features = std.enums.EnumSet(Feature);
/// The maximal set of `Features` which may be simultaneously enabled.
pub const all_features: Features = .complement(.initMany(&.{
// There are a few features that conflict with others, so we need to enable the more useful one.
.scalarize_add_safe, // conflicts with `.expand_add_safe`
.scalarize_sub_safe, // conflicts with `.expand_sub_safe`
.scalarize_mul_safe, // conflicts with `.expand_mul_safe`
.scalarize_int_cast_safe, // conflicts with `.expand_int_cast_safe`
.scalarize_div_ceil, // conflicts with `.expand_div_ceil`
.scalarize_div_ceil_optimized, // conflicts with `.expand_div_ceil_optimized`
.scalarize_int_from_float_safe, // conflicts with `.expand_int_from_float_safe`
.scalarize_int_from_float_optimized_safe, // conflicts with `.expand_int_from_float_optimized_safe`
// This feature introduces a new AIR form, and acts solely as an optimization (I'm not actually
// sure if it should be here at all), so is excluded from `-flegalize-all`.
.unsplat_shift_rhs,
}));
pub const Error = std.mem.Allocator.Error;
pub fn legalize(air: *Air, pt: Zcu.PerThread, features: *const Features) Error!void {
+8
View File
@@ -58,6 +58,7 @@ import_memory: bool,
export_memory: bool,
shared_memory: bool,
is_test: bool,
legalize_all: bool,
debug_format: DebugFormat,
root_optimize_mode: std.lang.Optimize,
root_strip: bool,
@@ -111,6 +112,7 @@ pub const Options = struct {
use_new_linker: ?bool = null,
pie: ?bool = null,
lto: ?std.zig.LtoMode = null,
legalize_all: bool = false,
incremental: bool = false,
/// WASI-only. Type of WASI execution model ("command" or "reactor").
wasi_exec_model: ?std.lang.WasiExecModel = null,
@@ -161,6 +163,7 @@ pub const ResolveError = error{
DllExportFnsRequiresWindows,
NewLinkerIncompatibleWithLld,
NewLinkerIncompatibleObjectFormat,
LegalizeAllRequiresLlvm,
};
pub fn resolve(options: Options) ResolveError!Config {
@@ -395,6 +398,10 @@ pub fn resolve(options: Options) ResolveError!Config {
// There is no compiler backend available for this target.
return error.ZigLacksTargetSupport;
}
if (options.legalize_all and !use_llvm) {
return error.LegalizeAllRequiresLlvm;
}
}
// Make a decision on whether to use LLD or our own linker.
@@ -613,6 +620,7 @@ pub fn resolve(options: Options) ResolveError!Config {
.output_mode = options.output_mode,
.have_zcu = options.have_zcu,
.is_test = options.is_test,
.legalize_all = options.legalize_all,
.link_mode = link_mode,
.link_libc = link_libc,
.link_libcpp = link_libcpp,
+3
View File
@@ -68,6 +68,9 @@ fn importBackend(comptime backend: std.lang.CompilerBackend) type {
pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*const Air.Legalize.Features {
const zcu = pt.zcu;
if (zcu.comp.config.legalize_all) {
return &Air.Legalize.all_features;
}
const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) {
else => unreachable,
+45 -2
View File
@@ -350,8 +350,9 @@ fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.Cov
.legalize_vec_elem_val => try self.airLegalizeVecElemVal(inst),
.legalize_vec_store_elem => try self.airLegalizeVecStoreElem(inst),
// No soft float legalizations are enabled.
.legalize_compiler_rt_call => unreachable,
// No soft float legalizations are requested, but for testing we sometimes enable *all*
// legalizations in this backend (`-flegalize-all`), so we still need to handle this.
.legalize_compiler_rt_call => try self.airLegalizeCompilerRtCall(inst),
.add => try self.airAdd(inst, .normal),
.add_optimized => try self.airAdd(inst, .fast),
@@ -2290,6 +2291,48 @@ fn airLegalizeVecStoreElem(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!B
return .none;
}
fn airLegalizeCompilerRtCall(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
const zcu = fg.object.zcu;
const comp = zcu.comp;
const gpa = comp.gpa;
const target = comp.getTarget();
const builder = &fg.object.builder;
const compiler_rt_call = fg.air.unwrapCompilerRtCall(inst);
const param_types = try gpa.alloc(InternPool.Index, compiler_rt_call.args.len);
defer gpa.free(param_types);
const llvm_args = try gpa.alloc(Builder.Value, compiler_rt_call.args.len);
defer gpa.free(llvm_args);
for (param_types, llvm_args, compiler_rt_call.args) |*param_ty, *llvm_arg, arg_ref| {
param_ty.* = fg.typeOf(arg_ref).toIntern();
llvm_arg.* = try fg.resolveInst(arg_ref);
}
const fn_info: Object.FuncInfo = .{
.cc = compiler_rt_call.func.@"callconv"(target),
.param_types = param_types,
.return_type = compiler_rt_call.func.returnType().toIntern(),
};
const llvm_fn = try fg.object.getLibcFunction(
fg.pt,
try builder.strtabString(compiler_rt_call.func.name(target)),
fn_info,
);
return fg.buildCall(
.{},
llvm_fn.typeOf(builder),
llvm_fn.toValue(builder),
fn_info,
fn_info.param_types,
llvm_args,
);
}
fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
const zcu = self.object.zcu;
const bin_op = self.air.instructions.items(.data)[@backingInt(inst)].bin_op;
+4
View File
@@ -793,6 +793,7 @@ const compile_usage =
\\Debug Options (Zig Compiler Development):
\\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes
\\ -fstack-report Print stack size diagnostics
\\ -flegalize-all Force-enable all codegen legalizations for testing
\\ --debug-log [scope] Enable printing debug/info log messages for scope
\\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
\\ --debug-link-snapshot Dump linker state and output file information for troubleshooting
@@ -1498,6 +1499,8 @@ fn buildOutputType(
test_execve = true;
} else if (mem.eql(u8, arg, "-fstack-report")) {
stack_report = true;
} else if (mem.eql(u8, arg, "-flegalize-all")) {
create_module.opts.legalize_all = true;
} else if (mem.eql(u8, arg, "-fPIC")) {
mod_opts.pic = true;
} else if (mem.eql(u8, arg, "-fno-PIC")) {
@@ -4328,6 +4331,7 @@ fn createModule(
error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}),
error.NewLinkerIncompatibleWithLld => fatal("using the new linker is incompatible with using lld", .{}),
error.NewLinkerIncompatibleObjectFormat => fatal("no new linker available for '{t}' files", .{target.ofmt}),
error.LegalizeAllRequiresLlvm => fatal("'-flegalize-all' requires the LLVM backend", .{}),
};
}