authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-10-15 01:35:56+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-10-23 09:18:03+03:30
logf51d2cf02ab5593f8e0e7923b34d8a68048bc0d8
tree25f735886a63492662bab9b5a166b22a7b2becf7
parent94ba9ff797fdc59f4f5b7e927245c3fe613c2f73

llvm: pass extensions and enable debug info


8 files changed, 155 insertions(+), 74 deletions(-)

src/Compilation.zig+2-1
...@@ -1300,7 +1300,7 @@ pub const cache_helpers = struct {...@@ -1300,7 +1300,7 @@ pub const cache_helpers = struct {
1300 const tag: @typeInfo(Config.DebugFormat).@"union".tag_type.? = x;1300 const tag: @typeInfo(Config.DebugFormat).@"union".tag_type.? = x;
1301 hh.add(tag);1301 hh.add(tag);
1302 switch (x) {1302 switch (x) {
1303 .strip, .code_view => {},1303 .strip, .code_view, .nsdi => {},
1304 .dwarf => |f| hh.add(f),1304 .dwarf => |f| hh.add(f),
1305 }1305 }
1306 }1306 }
...@@ -6303,6 +6303,7 @@ fn addCommonCCArgs(...@@ -6303,6 +6303,7 @@ fn addCommonCCArgs(
6303 try argv.ensureUnusedCapacity(2);6303 try argv.ensureUnusedCapacity(2);
6304 switch (comp.config.debug_format) {6304 switch (comp.config.debug_format) {
6305 .strip => {},6305 .strip => {},
6306 .nsdi => argv.appendAssumeCapacity("-g"),
6306 .code_view => {6307 .code_view => {
6307 // -g is required here because -gcodeview doesn't trigger debug info6308 // -g is required here because -gcodeview doesn't trigger debug info
6308 // generation, it only changes the type of information generated.6309 // generation, it only changes the type of information generated.
src/Compilation/Config.zig+4-1
...@@ -72,6 +72,8 @@ pub const DebugFormat = union(enum) {...@@ -72,6 +72,8 @@ pub const DebugFormat = union(enum) {
72 strip,72 strip,
73 dwarf: std.dwarf.Format,73 dwarf: std.dwarf.Format,
74 code_view,74 code_view,
75 /// Non-semantic Shader Debug Info
76 nsdi,
75};77};
7678
77pub const Options = struct {79pub const Options = struct {
...@@ -517,7 +519,8 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -517,7 +519,8 @@ pub fn resolve(options: Options) ResolveError!Config {
517 .windows, .uefi => .code_view,519 .windows, .uefi => .code_view,
518 else => .{ .dwarf = .@"32" },520 else => .{ .dwarf = .@"32" },
519 },521 },
520 .spirv, .hex, .raw, .plan9 => .strip,522 .spirv => .nsdi,
523 .hex, .raw, .plan9 => .strip,
521 };524 };
522 };525 };
523526
src/codegen/llvm.zig+1
...@@ -455,6 +455,7 @@ pub const Object = struct {...@@ -455,6 +455,7 @@ pub const Object = struct {
455455
456 switch (comp.config.debug_format) {456 switch (comp.config.debug_format) {
457 .strip => unreachable,457 .strip => unreachable,
458 .nsdi => {},
458 .dwarf => |f| {459 .dwarf => |f| {
459 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{460 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
460 behavior_max,461 behavior_max,
src/link/Elf/ZigObject.zig+1-1
...@@ -224,7 +224,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -224,7 +224,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
224 try dwarf.initMetadata();224 try dwarf.initMetadata();
225 self.dwarf = dwarf;225 self.dwarf = dwarf;
226 },226 },
227 .code_view => unreachable,227 .code_view, .nsdi => unreachable,
228 }228 }
229}229}
230230
src/link/Elf2.zig+8-8
...@@ -5146,7 +5146,7 @@ fn create(...@@ -5146,7 +5146,7 @@ fn create(
5146 .dwarf = .init(&elf.base, switch (comp.config.debug_format) {5146 .dwarf = .init(&elf.base, switch (comp.config.debug_format) {
5147 .strip => .@"32", // for .eh_frame5147 .strip => .@"32", // for .eh_frame
5148 .dwarf => |v| v,5148 .dwarf => |v| v,
5149 .code_view => unreachable,5149 .code_view, .nsdi => unreachable,
5150 }),5150 }),
5151 .dwarf_shared = comptime .initFill(.{5151 .dwarf_shared = comptime .initFill(.{
5152 .first_target_reloc = .none,5152 .first_target_reloc = .none,
...@@ -5261,7 +5261,7 @@ fn initHeaders(...@@ -5261,7 +5261,7 @@ fn initHeaders(
5261 const have_debug_frame = machine == .X86_64 and switch (comp.config.debug_format) {5261 const have_debug_frame = machine == .X86_64 and switch (comp.config.debug_format) {
5262 .strip => false,5262 .strip => false,
5263 .dwarf => !comp.config.any_unwind_tables,5263 .dwarf => !comp.config.any_unwind_tables,
5264 .code_view => unreachable,5264 .code_view, .nsdi => unreachable,
5265 };5265 };
5266 const addr_align: Alignment = switch (class) {5266 const addr_align: Alignment = switch (class) {
5267 .NONE, _ => unreachable,5267 .NONE, _ => unreachable,
...@@ -5322,7 +5322,7 @@ fn initHeaders(...@@ -5322,7 +5322,7 @@ fn initHeaders(
5322 shnum += 1; // .debug_str5322 shnum += 1; // .debug_str
5323 shnum += 1; // .debug_str_offsets5323 shnum += 1; // .debug_str_offsets
5324 },5324 },
5325 .code_view => unreachable,5325 .code_view, .nsdi => unreachable,
5326 }5326 }
5327 if (@"type" != .REL) {5327 if (@"type" != .REL) {
5328 shnum += 1; // .got5328 shnum += 1; // .got
...@@ -6548,7 +6548,7 @@ fn initHeaders(...@@ -6548,7 +6548,7 @@ fn initHeaders(
6548 .node_align = elf.mf.flags.block_size,6548 .node_align = elf.mf.flags.block_size,
6549 });6549 });
6550 },6550 },
6551 .code_view => unreachable,6551 .code_view, .nsdi => unreachable,
6552 }6552 }
65536553
6554 // If we have an entry point symbol, create the undefined reference now.6554 // If we have an entry point symbol, create the undefined reference now.
...@@ -10400,7 +10400,7 @@ fn updateContainerTypeInner(...@@ -10400,7 +10400,7 @@ fn updateContainerTypeInner(
10400 try elf.dwarf.const_pool.updateContainerType(pt, .{ .elf2 = elf }, ty, success);10400 try elf.dwarf.const_pool.updateContainerType(pt, .{ .elf2 = elf }, ty, success);
10401 try elf.dwarf.const_pool.flushPending(pt, .{ .elf2 = elf });10401 try elf.dwarf.const_pool.flushPending(pt, .{ .elf2 = elf });
10402 },10402 },
10403 .code_view => unreachable,10403 .code_view, .nsdi => unreachable,
10404 }10404 }
10405 if (!success) return;10405 if (!success) return;
10406 var lazy_it = elf.lazy.iterator();10406 var lazy_it = elf.lazy.iterator();
...@@ -10426,7 +10426,7 @@ pub fn addConst(...@@ -10426,7 +10426,7 @@ pub fn addConst(
10426 try elf.dwarf_consts.ensureUnusedCapacity(gpa, 1);10426 try elf.dwarf_consts.ensureUnusedCapacity(gpa, 1);
10427 try elf.dwarf.addConst(cpi, val, &addConstNode);10427 try elf.dwarf.addConst(cpi, val, &addConstNode);
10428 },10428 },
10429 .code_view => unreachable,10429 .code_view, .nsdi => unreachable,
10430 }10430 }
10431}10431}
10432fn addConstNode(10432fn addConstNode(
...@@ -10502,7 +10502,7 @@ fn updateConstInner(...@@ -10502,7 +10502,7 @@ fn updateConstInner(
10502 }10502 }
10503 try elf.genPending(pt);10503 try elf.genPending(pt);
10504 },10504 },
10505 .code_view => unreachable,10505 .code_view, .nsdi => unreachable,
10506 }10506 }
10507}10507}
1050810508
...@@ -11259,7 +11259,7 @@ fn genPending(elf: *Elf, pt: Zcu.PerThread) link.Error!void {...@@ -11259,7 +11259,7 @@ fn genPending(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
11259 elf.resetNodeRelocs(debug_info_ni);11259 elf.resetNodeRelocs(debug_info_ni);
11260 try elf.dwarf.genDecl(pt, &di_nw, pending.instance);11260 try elf.dwarf.genDecl(pt, &di_nw, pending.instance);
11261 },11261 },
11262 .code_view => unreachable,11262 .code_view, .nsdi => unreachable,
11263 }11263 }
11264 try elf.genPendingDebug(gpa);11264 try elf.genPendingDebug(gpa);
11265 assert(elf.pending_uavs.items.len == 0); // no UAVs added by lazy code/data or by debug info11265 assert(elf.pending_uavs.items.len == 0); // no UAVs added by lazy code/data or by debug info
src/link/MachO/ZigObject.zig+1-1
...@@ -62,7 +62,7 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void {...@@ -62,7 +62,7 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void {
62 self.debug_info_header_dirty = true;62 self.debug_info_header_dirty = true;
63 self.debug_line_header_dirty = true;63 self.debug_line_header_dirty = true;
64 },64 },
65 .code_view => unreachable,65 .code_view, .nsdi => unreachable,
66 }66 }
67}67}
6868
src/link/Spirv/Flush.zig+109-62
...@@ -2,6 +2,7 @@ const std = @import("std");...@@ -2,6 +2,7 @@ const std = @import("std");
2const Allocator = std.mem.Allocator;2const Allocator = std.mem.Allocator;
3const Path = std.Build.Cache.Path;3const Path = std.Build.Cache.Path;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const stringToEnum = std.meta.stringToEnum;
5const InternPool = @import("../../InternPool.zig");6const InternPool = @import("../../InternPool.zig");
6const link = @import("../../link.zig");7const link = @import("../../link.zig");
7const Type = @import("../../Type.zig");8const Type = @import("../../Type.zig");
...@@ -34,6 +35,7 @@ decorations: Section,...@@ -34,6 +35,7 @@ decorations: Section,
34globals: Section,35globals: Section,
35declarations: Section,36declarations: Section,
36functions: Section,37functions: Section,
38nonsemantic_info: bool = false,
3739
38const Symbol = struct {40const Symbol = struct {
39 id: Id,41 id: Id,
...@@ -42,7 +44,7 @@ const Symbol = struct {...@@ -42,7 +44,7 @@ const Symbol = struct {
42};44};
4345
44const Annotation = struct {46const Annotation = struct {
45 target: Word,47 target_id: Word,
46 class: spec.Class,48 class: spec.Class,
47 start: usize,49 start: usize,
48 end: usize,50 end: usize,
...@@ -224,6 +226,7 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -224,6 +226,7 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
224 const gpa = comp.gpa;226 const gpa = comp.gpa;
225 const arena = flush.arena;227 const arena = flush.arena;
226 const diags = &comp.link_diags;228 const diags = &comp.link_diags;
229 const target = &comp.root_mod.resolved_target.result;
227230
228 const ids = try gpa.alloc(Id, mir.id_bound);231 const ids = try gpa.alloc(Id, mir.id_bound);
229 defer gpa.free(ids);232 defer gpa.free(ids);
...@@ -264,7 +267,7 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -264,7 +267,7 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
264 offset += inst.len;267 offset += inst.len;
265268
266 if (header.opcode == .OpDecorate) {269 if (header.opcode == .OpDecorate) {
267 const target = inst[1];270 const target_id = inst[1];
268 const decoration: spec.Decoration = @fromBackingInt(inst[2]);271 const decoration: spec.Decoration = @fromBackingInt(inst[2]);
269 if (decoration == .linkage_attributes) {272 if (decoration == .linkage_attributes) {
270 const parameters = inst[3..];273 const parameters = inst[3..];
...@@ -273,7 +276,7 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -273,7 +276,7 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
273 const linkage: spec.LinkageType = @fromBackingInt(parameters[parameters.len - 1]);276 const linkage: spec.LinkageType = @fromBackingInt(parameters[parameters.len - 1]);
274 const gop = try flush.symbols.getOrPut(arena, name);277 const gop = try flush.symbols.getOrPut(arena, name);
275 if (!gop.found_existing) gop.value_ptr.* = .{278 if (!gop.found_existing) gop.value_ptr.* = .{
276 .id = ids[target],279 .id = ids[target_id],
277 .defined = false,280 .defined = false,
278 .declaration = &.{},281 .declaration = &.{},
279 };282 };
...@@ -285,19 +288,19 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -285,19 +288,19 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
285 }288 }
286 gop.value_ptr.defined = true;289 gop.value_ptr.defined = true;
287 },290 },
288 .import => try imports.put(gpa, target, @intCast(gop.index)),291 .import => try imports.put(gpa, target_id, @intCast(gop.index)),
289 .link_once_odr => {292 .link_once_odr => {
290 return diags.failParse(path.?, "unsupported linkage '{t}'", .{linkage});293 return diags.failParse(path.?, "unsupported linkage '{t}'", .{linkage});
291 },294 },
292 }295 }
293296
294 ids[target] = gop.value_ptr.id;297 ids[target_id] = gop.value_ptr.id;
295 continue;298 continue;
296 }299 }
297 }300 }
298301
299 const class = header.opcode.class();302 const class = header.opcode.class();
300 const target: Word = switch (header.opcode) {303 const target_id: Word = switch (header.opcode) {
301 .OpName, .OpMemberName => inst[1],304 .OpName, .OpMemberName => inst[1],
302 .OpDecorationGroup, .OpGroupDecorate, .OpGroupMemberDecorate => {305 .OpDecorationGroup, .OpGroupDecorate, .OpGroupMemberDecorate => {
303 return diags.failParse(path.?, "decoration groups are not supported", .{});306 return diags.failParse(path.?, "decoration groups are not supported", .{});
...@@ -305,32 +308,34 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -305,32 +308,34 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
305 else => if (class == .annotation) inst[1] else continue,308 else => if (class == .annotation) inst[1] else continue,
306 };309 };
307 try annotations.append(gpa, .{310 try annotations.append(gpa, .{
308 .target = target,311 .target_id = target_id,
309 .class = class,312 .class = class,
310 .start = start,313 .start = start,
311 .end = offset,314 .end = offset,
312 });315 });
313 }316 }
314317
318 var result_ids: std.ArrayList(Word) = .empty;
319 defer result_ids.deinit(gpa);
320
315 const starts = try gpa.alloc(u32, mir.id_bound + 1);321 const starts = try gpa.alloc(u32, mir.id_bound + 1);
316 defer gpa.free(starts);322 defer gpa.free(starts);
317 @memset(starts, 0);323 @memset(starts, 0);
318324
319 for (annotations.items) |annotation| starts[annotation.target + 1] += 1;325 for (annotations.items) |annotation| starts[annotation.target_id + 1] += 1;
320 for (1..starts.len) |i| starts[i] += starts[i - 1];326 for (1..starts.len) |i| starts[i] += starts[i - 1];
321327
322 const cursors = try gpa.dupe(u32, starts);328 const grouped_indices = try gpa.alloc(u32, annotations.items.len);
323 defer gpa.free(cursors);329 defer gpa.free(grouped_indices);
324 const by_target = try gpa.alloc(u32, annotations.items.len);330 {
325 defer gpa.free(by_target);331 const next_slot = try gpa.dupe(u32, starts);
326 for (annotations.items, 0..) |annotation, i| {332 defer gpa.free(next_slot);
327 by_target[cursors[annotation.target]] = @intCast(i);333 for (annotations.items, 0..) |annotation, i| {
328 cursors[annotation.target] += 1;334 grouped_indices[next_slot[annotation.target_id]] = @intCast(i);
335 next_slot[annotation.target_id] += 1;
336 }
329 }337 }
330338
331 var results: std.ArrayList(Word) = .empty;
332 defer results.deinit(gpa);
333
334 offset = 0;339 offset = 0;
335 while (offset < words.len) {340 while (offset < words.len) {
336 const start = offset;341 const start = offset;
...@@ -340,25 +345,67 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -340,25 +345,67 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
340 input.mark += 1;345 input.mark += 1;
341 flush.deps.clearRetainingCapacity();346 flush.deps.clearRetainingCapacity();
342347
343 const result_index = header.opcode.resultIndex() orelse {348 const result_index = header.opcode.resultIndex() orelse switch (header.opcode) {
344 switch (header.opcode) {349 .OpCapability => {
345 .OpEntryPoint => {350 const capability = std.enums.fromInt(spec.Capability, inst[1]) orelse {
346 try input.copy(flush, &flush.object_entry_points, start, offset, null);351 return diags.failParse(path.?, "unknown capability '{d}'", .{inst[1]});
347 },352 };
348 .OpExecutionMode, .OpExecutionModeId => {353
349 try input.copy(flush, &flush.object_execution_modes, start, offset, null);354 // TODO: this isn't a full validation. we probably have to automate this
350 },355 // based on some generated info from SPIRV-Headers/SPIRV-Registry
351 .OpTypeForwardPointer => {356 const allowed = switch (capability) {
352 forward_pointers.set(inst[1]);357 .linkage => true,
353 try input.copy(flush, &flush.globals, start, offset, null);358 .shader => target.os.tag == .vulkan or target.os.tag == .opengl,
354 },359 .kernel, .addresses => target.os.tag == .opencl,
355 else => {},360 .physical_storage_buffer_addresses => target.os.tag == .vulkan and target.cpu.arch == .spirv64,
356 }361 else => if (stringToEnum(std.Target.spirv.Feature, @tagName(capability))) |f| target.cpu.has(.spirv, f) else false,
357 continue;362 };
363 if (!allowed) return diags.failParse(
364 path.?,
365 "SPIR-V capability '{t}' is not enabled by the target feature set",
366 .{capability},
367 );
368 continue;
369 },
370 .OpExtension => {
371 const name = std.mem.sliceTo(std.mem.sliceAsBytes(inst[1..]), 0);
372 if (std.mem.eql(u8, name, "SPV_KHR_non_semantic_info")) {
373 flush.nonsemantic_info = true;
374 continue;
375 }
376
377 const allowed = allowed: {
378 if (stringToEnum(std.Target.spirv.Feature, name)) |f| {
379 break :allowed target.cpu.has(.spirv, f);
380 }
381 break :allowed true;
382 };
383 if (!allowed) return diags.failParse(
384 path.?,
385 "SPIR-V extension '{s}' is not enabled by the target feature set",
386 .{name},
387 );
388 continue;
389 },
390 .OpEntryPoint => {
391 try input.copy(flush, &flush.object_entry_points, start, offset, null);
392 continue;
393 },
394 .OpExecutionMode, .OpExecutionModeId => {
395 try input.copy(flush, &flush.object_execution_modes, start, offset, null);
396 continue;
397 },
398 .OpTypeForwardPointer => {
399 forward_pointers.set(inst[1]);
400 try input.copy(flush, &flush.globals, start, offset, null);
401 continue;
402 },
403 else => continue,
358 };404 };
359 const result = inst[result_index];405
360 results.clearRetainingCapacity();406 const result_id = inst[result_index];
361 try results.append(gpa, result);407 result_ids.clearRetainingCapacity();
408 try result_ids.append(gpa, result_id);
362409
363 var has_body = false;410 var has_body = false;
364 if (header.opcode == .OpFunction) {411 if (header.opcode == .OpFunction) {
...@@ -366,16 +413,16 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -366,16 +413,16 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
366 const body: spec.InstructionHeader = @bitCast(words[offset]);413 const body: spec.InstructionHeader = @bitCast(words[offset]);
367 if (body.opcode == .OpLabel) has_body = true;414 if (body.opcode == .OpLabel) has_body = true;
368 if (body.opcode.resultIndex()) |index| {415 if (body.opcode.resultIndex()) |index| {
369 try results.append(gpa, words[offset + index]);416 try result_ids.append(gpa, words[offset + index]);
370 }417 }
371 offset += body.word_count;418 offset += body.word_count;
372 if (body.opcode == .OpFunctionEnd) break;419 if (body.opcode == .OpFunctionEnd) break;
373 }420 }
374 }421 }
375422
376 for (results.items) |own| input.marks[own] = input.mark;423 for (result_ids.items) |own| input.marks[own] = input.mark;
377424
378 if (imports.get(result)) |symbol_index| {425 if (imports.get(result_id)) |symbol_index| {
379 flush.scratch.reset();426 flush.scratch.reset();
380 try input.copy(flush, &flush.scratch, start, offset, null);427 try input.copy(flush, &flush.scratch, start, offset, null);
381 const declaration = try arena.dupe(Word, flush.scratch.instructions.items);428 const declaration = try arena.dupe(Word, flush.scratch.instructions.items);
...@@ -385,30 +432,30 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -385,30 +432,30 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
385432
386 switch (header.opcode) {433 switch (header.opcode) {
387 .OpFunction => if (!has_body) return diags.failParse(path.?, "function declaration without linkage", .{}),434 .OpFunction => if (!has_body) return diags.failParse(path.?, "function declaration without linkage", .{}),
388 .OpVariable => try flush.variables.put(arena, ids[result], @fromBackingInt(inst[3])),435 .OpVariable => try flush.variables.put(arena, ids[result_id], @fromBackingInt(inst[3])),
389 else => if (!forward_pointers.isSet(result)) {436 else => if (!forward_pointers.isSet(result_id)) {
390 flush.scratch.reset();437 flush.scratch.reset();
391 try input.copy(flush, &flush.scratch, start, offset, start + result_index);438 try input.copy(flush, &flush.scratch, start, offset, start + result_index);
392 for (by_target[starts[result]..starts[result + 1]]) |index| {439 for (grouped_indices[starts[result_id]..starts[result_id + 1]]) |index| {
393 const annotation = annotations.items[index];440 const annotation = annotations.items[index];
394 if (annotation.class != .annotation) continue;441 if (annotation.class != .annotation) continue;
395 const target = annotation.start + 1;442 const target_id = annotation.start + 1;
396 try input.copy(flush, &flush.scratch, annotation.start, annotation.end, target);443 try input.copy(flush, &flush.scratch, annotation.start, annotation.end, target_id);
397 }444 }
398445
399 const key = std.mem.sliceAsBytes(flush.scratch.instructions.items);446 const key = std.mem.sliceAsBytes(flush.scratch.instructions.items);
400 const gop = try flush.interned.getOrPut(arena, key);447 const gop = try flush.interned.getOrPut(arena, key);
401 if (gop.found_existing) {448 if (gop.found_existing) {
402 ids[result] = gop.value_ptr.*;449 ids[result_id] = gop.value_ptr.*;
403 continue;450 continue;
404 }451 }
405 gop.key_ptr.* = try arena.dupe(u8, key);452 gop.key_ptr.* = try arena.dupe(u8, key);
406 gop.value_ptr.* = ids[result];453 gop.value_ptr.* = ids[result_id];
407 },454 },
408 }455 }
409456
410 for (results.items) |target| {457 for (result_ids.items) |target_id| {
411 for (by_target[starts[target]..starts[target + 1]]) |index| {458 for (grouped_indices[starts[target_id]..starts[target_id + 1]]) |index| {
412 const annotation = annotations.items[index];459 const annotation = annotations.items[index];
413 const section = switch (annotation.class) {460 const section = switch (annotation.class) {
414 .debug => &flush.names,461 .debug => &flush.names,
...@@ -428,7 +475,7 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {...@@ -428,7 +475,7 @@ fn load(flush: *Flush, mir: *const Mir, path: ?Path) link.Error!void {
428 try input.copy(flush, section, start, offset, null);475 try input.copy(flush, section, start, offset, null);
429 if (header.opcode == .OpFunction) {476 if (header.opcode == .OpFunction) {
430 const references = try arena.dupe(Id, flush.deps.items);477 const references = try arena.dupe(Id, flush.deps.items);
431 try flush.function_references.put(arena, ids[result], references);478 try flush.function_references.put(arena, ids[result_id], references);
432 }479 }
433 }480 }
434481
...@@ -468,25 +515,25 @@ fn emitCapabilities(flush: *Flush, out: *Section) link.Error!void {...@@ -468,25 +515,25 @@ fn emitCapabilities(flush: *Flush, out: *Section) link.Error!void {
468 try out.emit(gpa, .OpCapability, .{ .capability = .linkage });515 try out.emit(gpa, .OpCapability, .{ .capability = .linkage });
469 }516 }
470517
471 inline for (@typeInfo(spec.Capability).@"enum".field_names) |name| {518 for (std.enums.values(spec.Capability)) |capability| {
472 if (@hasField(std.Target.spirv.Feature, name)) {519 const feature = stringToEnum(std.Target.spirv.Feature, @tagName(capability)) orelse continue;
473 const feature = @field(std.Target.spirv.Feature, name);520 if (!target.cpu.has(.spirv, feature)) continue;
474 if (target.cpu.has(.spirv, feature)) {521 try out.emit(gpa, .OpCapability, .{ .capability = capability });
475 try out.emit(gpa, .OpCapability, .{ .capability = @field(spec.Capability, name) });
476 }
477 }
478 }522 }
479523
480 if (target.cpu.arch == .spirv64 and target.os.tag == .vulkan) {524 if (target.cpu.arch == .spirv64 and target.os.tag == .vulkan) {
481 try out.emit(gpa, .OpExtension, .{ .name = "SPV_KHR_physical_storage_buffer" });525 try out.emit(gpa, .OpExtension, .{ .name = "SPV_KHR_physical_storage_buffer" });
482 }526 }
483527
484 inline for (@typeInfo(spec.Extension).@"enum".field_names) |name| {528 for (std.enums.values(spec.Extension)) |extension| {
485 if (comptime std.mem.startsWith(u8, name, "v1_")) continue;529 const name = @tagName(extension);
486 if (@hasField(std.Target.spirv.Feature, name)) {530 if (std.mem.startsWith(u8, name, "v1_")) continue;
487 const feature = @field(std.Target.spirv.Feature, name);531 const feature = stringToEnum(std.Target.spirv.Feature, name) orelse continue;
488 if (target.cpu.has(.spirv, feature)) try out.emit(gpa, .OpExtension, .{ .name = name });532 if (!target.cpu.has(.spirv, feature)) continue;
489 }533 try out.emit(gpa, .OpExtension, .{ .name = name });
534 }
535 if (flush.nonsemantic_info) {
536 try out.emit(gpa, .OpExtension, .{ .name = "SPV_KHR_non_semantic_info" });
490 }537 }
491}538}
492539
src/main.zig+29
...@@ -3582,6 +3582,35 @@ fn buildOutputType(...@@ -3582,6 +3582,35 @@ fn buildOutputType(
3582 @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv);3582 @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv);
3583 }3583 }
35843584
3585 if (build_options.have_llvm and create_module.resolved_options.use_llvm and target.cpu.arch.isSpirV()) {
3586 // LLVM has no way to set this non-globally other
3587 // than SPIRVTranslate() but it cannot emits assembly.
3588 var extensions: std.ArrayList(u8) = .empty;
3589 defer extensions.deinit(gpa);
3590 try extensions.appendSlice(gpa, "--spirv-ext=");
3591
3592 var has_extension = false;
3593 if (!root_mod.strip) {
3594 try extensions.appendSlice(gpa, "+SPV_KHR_non_semantic_info");
3595 has_extension = true;
3596 }
3597
3598 for (std.enums.values(std.Target.spirv.Feature)) |feature| {
3599 const name = @tagName(feature);
3600 if (!mem.startsWith(u8, name, "SPV_")) continue;
3601 if (!target.cpu.has(.spirv, feature)) continue;
3602 if (mem.eql(u8, name, "SPV_KHR_variable_pointers") and target.cpu.has(.spirv, .v1_3)) continue;
3603
3604 if (has_extension) try extensions.append(gpa, ',');
3605 try extensions.append(gpa, '+');
3606 try extensions.appendSlice(gpa, name);
3607 has_extension = true;
3608 }
3609
3610 const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", try extensions.toOwnedSliceSentinel(gpa, 0) };
3611 @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv);
3612 }
3613
3585 const clang_passthrough_mode = switch (arg_mode) {3614 const clang_passthrough_mode = switch (arg_mode) {
3586 .cc, .cpp, .translate_c => true,3615 .cc, .cpp, .translate_c => true,
3587 else => false,3616 else => false,