Commit b4b1c4df64

Robin Voetter <robin@voetter.nl>
2023-11-23 23:58:50
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.
1 parent cb026c5
Changed files (4)
src/codegen/spirv.zig
@@ -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,
src/Compilation.zig
@@ -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();
 
src/link.zig
@@ -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;
     }
src/main.zig
@@ -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;