spirv: add -fstructured-cfg option

This enables the compiler to generate a structured cfg even in opencl,
even if it is not strictly required by the SPIR-V Kernel specification.
This commit is contained in:
Robin Voetter 2023-11-23 23:58:50 +01:00
parent cb026c5d59
commit b4b1c4df64
No known key found for this signature in database
4 changed files with 34 additions and 2 deletions

View File

@ -1002,6 +1002,8 @@ pub const InitOptions = struct {
/// (Windows) PDB output path
pdb_out_path: ?[]const u8 = null,
error_limit: ?Module.ErrorInt = null,
/// (SPIR-V) whether to generate a structured control flow graph or not
want_structured_cfg: ?bool = null,
};
fn addModuleTableToCacheHash(
@ -1447,6 +1449,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
};
const formatted_panics = options.formatted_panics orelse (options.optimize_mode == .Debug);
const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
// We put everything into the cache hash that *cannot be modified
// during an incremental update*. For example, one cannot change the
// target between updates, but one can change source files, so the
@ -1545,6 +1549,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
hash.add(options.skip_linker_dependencies);
hash.add(options.parent_compilation_link_libc);
hash.add(formatted_panics);
hash.add(options.emit_h != null);
hash.add(error_limit);
hash.addOptional(options.want_structured_cfg);
// In the case of incremental cache mode, this `zig_cache_artifact_directory`
// is computed based on a hash of non-linker inputs, and it is where all
@ -1699,7 +1706,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.local_zir_cache = local_zir_cache,
.emit_h = emit_h,
.tmp_hack_arena = std.heap.ArenaAllocator.init(gpa),
.error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1),
.error_limit = error_limit,
};
try module.init();
@ -1958,6 +1965,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.force_undefined_symbols = options.force_undefined_symbols,
.pdb_source_path = options.pdb_source_path,
.pdb_out_path = options.pdb_out_path,
.want_structured_cfg = options.want_structured_cfg,
});
errdefer bin_file.destroy();
comp.* = .{
@ -2732,6 +2740,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
man.hash.add(comp.bin_file.options.valgrind);
man.hash.add(comp.bin_file.options.single_threaded);
man.hash.add(comp.bin_file.options.use_llvm);
man.hash.add(comp.bin_file.options.use_lib_llvm);
man.hash.add(comp.bin_file.options.dll_export_fns);
man.hash.add(comp.bin_file.options.is_test);
man.hash.add(comp.test_evented_io);
@ -2739,8 +2748,10 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
man.hash.addOptionalBytes(comp.test_name_prefix);
man.hash.add(comp.bin_file.options.skip_linker_dependencies);
man.hash.add(comp.bin_file.options.parent_compilation_link_libc);
man.hash.add(comp.formatted_panics);
man.hash.add(mod.emit_h != null);
man.hash.add(mod.error_limit);
man.hash.addOptional(comp.bin_file.options.want_structured_cfg);
}
try man.addOptionalFile(comp.bin_file.options.linker_script);
@ -6823,6 +6834,7 @@ fn buildOutputFromZig(
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
.parent_compilation_link_libc = comp.bin_file.options.link_libc,
.want_structured_cfg = comp.bin_file.options.want_structured_cfg,
});
defer sub_compilation.destroy();
@ -6903,6 +6915,7 @@ pub fn build_crt_file(
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
.parent_compilation_link_libc = comp.bin_file.options.link_libc,
.want_structured_cfg = comp.bin_file.options.want_structured_cfg,
});
defer sub_compilation.destroy();

View File

@ -99,6 +99,15 @@ pub const Object = struct {
air: Air,
liveness: Liveness,
) !void {
const target = mod.getTarget();
// We always want a structured control flow in shaders. This option is only relevant
// for OpenCL kernels.
const want_structured_cfg = switch (target.os.tag) {
.opencl => mod.comp.bin_file.options.want_structured_cfg orelse false,
else => true,
};
_ = want_structured_cfg;
var decl_gen = DeclGen{
.gpa = self.gpa,
.object = self,

View File

@ -268,6 +268,9 @@ pub const Options = struct {
/// (Windows) .def file to specify when linking
module_definition_file: ?[]const u8 = null,
/// (SPIR-V) whether to generate a structured control flow graph or not
want_structured_cfg: ?bool = null,
pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
return if (options.use_lld) .Obj else options.output_mode;
}

View File

@ -493,6 +493,8 @@ const usage_build_generic =
\\ msvc Use msvc include paths (must be present on the system)
\\ gnu Use mingw include paths (distributed with Zig)
\\ none Do not use any autodetected include paths
\\ -fstructured-cfg (SPIR-V) force SPIR-V kernels to use structured control flow
\\ -fno-structured-cfg (SPIR-V) force SPIR-V kernels to not use structured control flow
\\
\\Link Options:
\\ -l[lib], --library [lib] Link against system library (only if actually used)
@ -913,7 +915,7 @@ fn buildOutputType(
var pdb_out_path: ?[]const u8 = null;
var dwarf_format: ?std.dwarf.Format = null;
var error_limit: ?Module.ErrorInt = null;
var want_structured_cfg: ?bool = null;
// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
// This array is populated by zig cc frontend and then has to be converted to zig-style
// CPU features.
@ -1070,6 +1072,10 @@ fn buildOutputType(
if (mem.eql(u8, next_arg, "--")) break;
try extra_rcflags.append(next_arg);
}
} else if (mem.startsWith(u8, arg, "-fstructured-cfg")) {
want_structured_cfg = true;
} else if (mem.startsWith(u8, arg, "-fno-structured-cfg")) {
want_structured_cfg = false;
} else if (mem.eql(u8, arg, "--color")) {
const next_arg = args_iter.next() orelse {
fatal("expected [auto|on|off] after --color", .{});
@ -3595,6 +3601,7 @@ fn buildOutputType(
.error_tracing = error_tracing,
.pdb_out_path = pdb_out_path,
.error_limit = error_limit,
.want_structured_cfg = want_structured_cfg,
}) catch |err| switch (err) {
error.LibCUnavailable => {
const target = target_info.target;