| author | |
| committer | |
| log | 0e1afb4d986c3316c6f024be50612b0a6c66777b |
| tree | 7b2bc69ae80604165ce4d11bf72ef104d4b51f86 |
| parent | fbc06f9c9151205896fb167b087506d6580946c4 |
| signature |
sample command:
/home/guw/github/zig/stage2/bin/zig build-obj cuda_kernel.zig -target nvptx64-cuda -O ReleaseSafe
this will create a kernel.ptx
expose PtxKernel call convention from LLVM
kernels are `export fn f() callconv(.PtxKernel)`12 files changed, 185 insertions(+), 8 deletions(-)
lib/std/builtin.zig+1| ... | @@ -147,6 +147,7 @@ pub const CallingConvention = enum { | ... | @@ -147,6 +147,7 @@ pub const CallingConvention = enum { |
| 147 | AAPCS, | 147 | AAPCS, |
| 148 | AAPCSVFP, | 148 | AAPCSVFP, |
| 149 | SysV, | 149 | SysV, |
| 150 | PtxKernel, | ||
| 150 | }; | 151 | }; |
| 151 | 152 | ||
| 152 | /// This data structure is used by the Zig language code generation and | 153 | /// This data structure is used by the Zig language code generation and |
lib/std/target.zig+4| ... | @@ -579,6 +579,8 @@ pub const Target = struct { | ... | @@ -579,6 +579,8 @@ pub const Target = struct { |
| 579 | raw, | 579 | raw, |
| 580 | /// Plan 9 from Bell Labs | 580 | /// Plan 9 from Bell Labs |
| 581 | plan9, | 581 | plan9, |
| 582 | /// Nvidia PTX format | ||
| 583 | nvptx, | ||
| 582 | 584 | ||
| 583 | pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 { | 585 | pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 { |
| 584 | return switch (of) { | 586 | return switch (of) { |
| ... | @@ -589,6 +591,7 @@ pub const Target = struct { | ... | @@ -589,6 +591,7 @@ pub const Target = struct { |
| 589 | .hex => ".ihex", | 591 | .hex => ".ihex", |
| 590 | .raw => ".bin", | 592 | .raw => ".bin", |
| 591 | .plan9 => plan9Ext(cpu_arch), | 593 | .plan9 => plan9Ext(cpu_arch), |
| 594 | .nvptx => ".ptx", | ||
| 592 | }; | 595 | }; |
| 593 | } | 596 | } |
| 594 | }; | 597 | }; |
| ... | @@ -1388,6 +1391,7 @@ pub const Target = struct { | ... | @@ -1388,6 +1391,7 @@ pub const Target = struct { |
| 1388 | else => return switch (cpu_arch) { | 1391 | else => return switch (cpu_arch) { |
| 1389 | .wasm32, .wasm64 => .wasm, | 1392 | .wasm32, .wasm64 => .wasm, |
| 1390 | .spirv32, .spirv64 => .spirv, | 1393 | .spirv32, .spirv64 => .spirv, |
| 1394 | .nvptx, .nvptx64 => .nvptx, | ||
| 1391 | else => .elf, | 1395 | else => .elf, |
| 1392 | }, | 1396 | }, |
| 1393 | }; | 1397 | }; |
lib/std/zig.zig+1| ... | @@ -181,6 +181,7 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error | ... | @@ -181,6 +181,7 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error |
| 181 | .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, ofmt.fileExt(target.cpu.arch) }), | 181 | .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, ofmt.fileExt(target.cpu.arch) }), |
| 182 | .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ target.libPrefix(), root_name }), | 182 | .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ target.libPrefix(), root_name }), |
| 183 | }, | 183 | }, |
| 184 | .nvptx => return std.fmt.allocPrint(allocator, "{s}", .{root_name}), | ||
| 184 | } | 185 | } |
| 185 | } | 186 | } |
| 186 | 187 |
src/Module.zig+5-1| ... | @@ -4242,7 +4242,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi | ... | @@ -4242,7 +4242,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi |
| 4242 | // in `Decl` to notice that the line number did not change. | 4242 | // in `Decl` to notice that the line number did not change. |
| 4243 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); | 4243 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); |
| 4244 | }, | 4244 | }, |
| 4245 | .c, .wasm, .spirv => {}, | 4245 | .c, .wasm, .spirv, .nvptx => {}, |
| 4246 | } | 4246 | } |
| 4247 | } | 4247 | } |
| 4248 | } | 4248 | } |
| ... | @@ -4316,6 +4316,7 @@ pub fn clearDecl( | ... | @@ -4316,6 +4316,7 @@ pub fn clearDecl( |
| 4316 | .c => .{ .c = {} }, | 4316 | .c => .{ .c = {} }, |
| 4317 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, | 4317 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, |
| 4318 | .spirv => .{ .spirv = {} }, | 4318 | .spirv => .{ .spirv = {} }, |
| 4319 | .nvptx => .{ .nvptx = {} }, | ||
| 4319 | }; | 4320 | }; |
| 4320 | decl.fn_link = switch (mod.comp.bin_file.tag) { | 4321 | decl.fn_link = switch (mod.comp.bin_file.tag) { |
| 4321 | .coff => .{ .coff = {} }, | 4322 | .coff => .{ .coff = {} }, |
| ... | @@ -4325,6 +4326,7 @@ pub fn clearDecl( | ... | @@ -4325,6 +4326,7 @@ pub fn clearDecl( |
| 4325 | .c => .{ .c = {} }, | 4326 | .c => .{ .c = {} }, |
| 4326 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, | 4327 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, |
| 4327 | .spirv => .{ .spirv = .{} }, | 4328 | .spirv => .{ .spirv = .{} }, |
| 4329 | .nvptx => .{ .nvptx = .{} }, | ||
| 4328 | }; | 4330 | }; |
| 4329 | } | 4331 | } |
| 4330 | if (decl.getInnerNamespace()) |namespace| { | 4332 | if (decl.getInnerNamespace()) |namespace| { |
| ... | @@ -4652,6 +4654,7 @@ pub fn allocateNewDecl( | ... | @@ -4652,6 +4654,7 @@ pub fn allocateNewDecl( |
| 4652 | .c => .{ .c = {} }, | 4654 | .c => .{ .c = {} }, |
| 4653 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, | 4655 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, |
| 4654 | .spirv => .{ .spirv = {} }, | 4656 | .spirv => .{ .spirv = {} }, |
| 4657 | .nvptx => .{ .nvptx = {} }, | ||
| 4655 | }, | 4658 | }, |
| 4656 | .fn_link = switch (mod.comp.bin_file.tag) { | 4659 | .fn_link = switch (mod.comp.bin_file.tag) { |
| 4657 | .coff => .{ .coff = {} }, | 4660 | .coff => .{ .coff = {} }, |
| ... | @@ -4661,6 +4664,7 @@ pub fn allocateNewDecl( | ... | @@ -4661,6 +4664,7 @@ pub fn allocateNewDecl( |
| 4661 | .c => .{ .c = {} }, | 4664 | .c => .{ .c = {} }, |
| 4662 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, | 4665 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, |
| 4663 | .spirv => .{ .spirv = .{} }, | 4666 | .spirv => .{ .spirv = .{} }, |
| 4667 | .nvptx => .{ .nvptx = .{} }, | ||
| 4664 | }, | 4668 | }, |
| 4665 | .generation = 0, | 4669 | .generation = 0, |
| 4666 | .is_pub = false, | 4670 | .is_pub = false, |
src/Sema.zig+1| ... | @@ -3724,6 +3724,7 @@ pub fn analyzeExport( | ... | @@ -3724,6 +3724,7 @@ pub fn analyzeExport( |
| 3724 | .c => .{ .c = {} }, | 3724 | .c => .{ .c = {} }, |
| 3725 | .wasm => .{ .wasm = {} }, | 3725 | .wasm => .{ .wasm = {} }, |
| 3726 | .spirv => .{ .spirv = {} }, | 3726 | .spirv => .{ .spirv = {} }, |
| 3727 | .nvptx => .{ .nvptx = {} }, | ||
| 3727 | }, | 3728 | }, |
| 3728 | .owner_decl = owner_decl, | 3729 | .owner_decl = owner_decl, |
| 3729 | .src_decl = src_decl, | 3730 | .src_decl = src_decl, |
src/codegen/llvm.zig+5-1| ... | @@ -378,7 +378,7 @@ pub const Object = struct { | ... | @@ -378,7 +378,7 @@ pub const Object = struct { |
| 378 | const mod = comp.bin_file.options.module.?; | 378 | const mod = comp.bin_file.options.module.?; |
| 379 | const cache_dir = mod.zig_cache_artifact_directory; | 379 | const cache_dir = mod.zig_cache_artifact_directory; |
| 380 | 380 | ||
| 381 | const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit| | 381 | var emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit| |
| 382 | try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?)) | 382 | try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?)) |
| 383 | else | 383 | else |
| 384 | null; | 384 | null; |
| ... | @@ -5078,6 +5078,10 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca | ... | @@ -5078,6 +5078,10 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca |
| 5078 | }, | 5078 | }, |
| 5079 | .Signal => .AVR_SIGNAL, | 5079 | .Signal => .AVR_SIGNAL, |
| 5080 | .SysV => .X86_64_SysV, | 5080 | .SysV => .X86_64_SysV, |
| 5081 | .PtxKernel => return switch (target.cpu.arch) { | ||
| 5082 | .nvptx, .nvptx64 => .PTX_Kernel, | ||
| 5083 | else => unreachable, | ||
| 5084 | }, | ||
| 5081 | }; | 5085 | }; |
| 5082 | } | 5086 | } |
| 5083 | 5087 |
src/link.zig+25-5| ... | @@ -215,6 +215,7 @@ pub const File = struct { | ... | @@ -215,6 +215,7 @@ pub const File = struct { |
| 215 | c: void, | 215 | c: void, |
| 216 | wasm: Wasm.DeclBlock, | 216 | wasm: Wasm.DeclBlock, |
| 217 | spirv: void, | 217 | spirv: void, |
| 218 | nvptx: void, | ||
| 218 | }; | 219 | }; |
| 219 | 220 | ||
| 220 | pub const LinkFn = union { | 221 | pub const LinkFn = union { |
| ... | @@ -225,6 +226,7 @@ pub const File = struct { | ... | @@ -225,6 +226,7 @@ pub const File = struct { |
| 225 | c: void, | 226 | c: void, |
| 226 | wasm: Wasm.FnData, | 227 | wasm: Wasm.FnData, |
| 227 | spirv: SpirV.FnData, | 228 | spirv: SpirV.FnData, |
| 229 | nvptx: void, | ||
| 228 | }; | 230 | }; |
| 229 | 231 | ||
| 230 | pub const Export = union { | 232 | pub const Export = union { |
| ... | @@ -235,6 +237,7 @@ pub const File = struct { | ... | @@ -235,6 +237,7 @@ pub const File = struct { |
| 235 | c: void, | 237 | c: void, |
| 236 | wasm: void, | 238 | wasm: void, |
| 237 | spirv: void, | 239 | spirv: void, |
| 240 | nvptx: void, | ||
| 238 | }; | 241 | }; |
| 239 | 242 | ||
| 240 | /// For DWARF .debug_info. | 243 | /// For DWARF .debug_info. |
| ... | @@ -274,6 +277,7 @@ pub const File = struct { | ... | @@ -274,6 +277,7 @@ pub const File = struct { |
| 274 | .plan9 => return &(try Plan9.createEmpty(allocator, options)).base, | 277 | .plan9 => return &(try Plan9.createEmpty(allocator, options)).base, |
| 275 | .c => unreachable, // Reported error earlier. | 278 | .c => unreachable, // Reported error earlier. |
| 276 | .spirv => &(try SpirV.createEmpty(allocator, options)).base, | 279 | .spirv => &(try SpirV.createEmpty(allocator, options)).base, |
| 280 | .nvptx => &(try NvPtx.createEmpty(allocator, options)).base, | ||
| 277 | .hex => return error.HexObjectFormatUnimplemented, | 281 | .hex => return error.HexObjectFormatUnimplemented, |
| 278 | .raw => return error.RawObjectFormatUnimplemented, | 282 | .raw => return error.RawObjectFormatUnimplemented, |
| 279 | }; | 283 | }; |
| ... | @@ -292,6 +296,7 @@ pub const File = struct { | ... | @@ -292,6 +296,7 @@ pub const File = struct { |
| 292 | .wasm => &(try Wasm.createEmpty(allocator, options)).base, | 296 | .wasm => &(try Wasm.createEmpty(allocator, options)).base, |
| 293 | .c => unreachable, // Reported error earlier. | 297 | .c => unreachable, // Reported error earlier. |
| 294 | .spirv => &(try SpirV.createEmpty(allocator, options)).base, | 298 | .spirv => &(try SpirV.createEmpty(allocator, options)).base, |
| 299 | .nvptx => &(try NvPtx.createEmpty(allocator, options)).base, | ||
| 295 | .hex => return error.HexObjectFormatUnimplemented, | 300 | .hex => return error.HexObjectFormatUnimplemented, |
| 296 | .raw => return error.RawObjectFormatUnimplemented, | 301 | .raw => return error.RawObjectFormatUnimplemented, |
| 297 | }; | 302 | }; |
| ... | @@ -312,6 +317,7 @@ pub const File = struct { | ... | @@ -312,6 +317,7 @@ pub const File = struct { |
| 312 | .wasm => &(try Wasm.openPath(allocator, sub_path, options)).base, | 317 | .wasm => &(try Wasm.openPath(allocator, sub_path, options)).base, |
| 313 | .c => &(try C.openPath(allocator, sub_path, options)).base, | 318 | .c => &(try C.openPath(allocator, sub_path, options)).base, |
| 314 | .spirv => &(try SpirV.openPath(allocator, sub_path, options)).base, | 319 | .spirv => &(try SpirV.openPath(allocator, sub_path, options)).base, |
| 320 | .nvptx => &(try NvPtx.openPath(allocator, sub_path, options)).base, | ||
| 315 | .hex => return error.HexObjectFormatUnimplemented, | 321 | .hex => return error.HexObjectFormatUnimplemented, |
| 316 | .raw => return error.RawObjectFormatUnimplemented, | 322 | .raw => return error.RawObjectFormatUnimplemented, |
| 317 | }; | 323 | }; |
| ... | @@ -344,7 +350,7 @@ pub const File = struct { | ... | @@ -344,7 +350,7 @@ pub const File = struct { |
| 344 | .mode = determineMode(base.options), | 350 | .mode = determineMode(base.options), |
| 345 | }); | 351 | }); |
| 346 | }, | 352 | }, |
| 347 | .c, .wasm, .spirv => {}, | 353 | .c, .wasm, .spirv, .nvptx => {}, |
| 348 | } | 354 | } |
| 349 | } | 355 | } |
| 350 | 356 | ||
| ... | @@ -389,7 +395,7 @@ pub const File = struct { | ... | @@ -389,7 +395,7 @@ pub const File = struct { |
| 389 | f.close(); | 395 | f.close(); |
| 390 | base.file = null; | 396 | base.file = null; |
| 391 | }, | 397 | }, |
| 392 | .c, .wasm, .spirv => {}, | 398 | .c, .wasm, .spirv, .nvptx => {}, |
| 393 | } | 399 | } |
| 394 | } | 400 | } |
| 395 | 401 | ||
| ... | @@ -437,6 +443,7 @@ pub const File = struct { | ... | @@ -437,6 +443,7 @@ pub const File = struct { |
| 437 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl), | 443 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl), |
| 438 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl), | 444 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl), |
| 439 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl), | 445 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl), |
| 446 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateDecl(module, decl), | ||
| 440 | // zig fmt: on | 447 | // zig fmt: on |
| 441 | } | 448 | } |
| 442 | } | 449 | } |
| ... | @@ -456,6 +463,7 @@ pub const File = struct { | ... | @@ -456,6 +463,7 @@ pub const File = struct { |
| 456 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness), | 463 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness), |
| 457 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness), | 464 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness), |
| 458 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness), | 465 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness), |
| 466 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func, air, liveness), | ||
| 459 | // zig fmt: on | 467 | // zig fmt: on |
| 460 | } | 468 | } |
| 461 | } | 469 | } |
| ... | @@ -471,7 +479,7 @@ pub const File = struct { | ... | @@ -471,7 +479,7 @@ pub const File = struct { |
| 471 | .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl), | 479 | .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl), |
| 472 | .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl), | 480 | .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl), |
| 473 | .plan9 => @panic("TODO: implement updateDeclLineNumber for plan9"), | 481 | .plan9 => @panic("TODO: implement updateDeclLineNumber for plan9"), |
| 474 | .wasm, .spirv => {}, | 482 | .wasm, .spirv, .nvptx => {}, |
| 475 | } | 483 | } |
| 476 | } | 484 | } |
| 477 | 485 | ||
| ... | @@ -493,7 +501,7 @@ pub const File = struct { | ... | @@ -493,7 +501,7 @@ pub const File = struct { |
| 493 | }, | 501 | }, |
| 494 | .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl), | 502 | .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl), |
| 495 | .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl), | 503 | .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl), |
| 496 | .c, .spirv => {}, | 504 | .c, .spirv, .nvptx => {}, |
| 497 | } | 505 | } |
| 498 | } | 506 | } |
| 499 | 507 | ||
| ... | @@ -551,6 +559,11 @@ pub const File = struct { | ... | @@ -551,6 +559,11 @@ pub const File = struct { |
| 551 | parent.deinit(); | 559 | parent.deinit(); |
| 552 | base.allocator.destroy(parent); | 560 | base.allocator.destroy(parent); |
| 553 | }, | 561 | }, |
| 562 | .nvptx => { | ||
| 563 | const parent = @fieldParentPtr(NvPtx, "base", base); | ||
| 564 | parent.deinit(); | ||
| 565 | base.allocator.destroy(parent); | ||
| 566 | }, | ||
| 554 | } | 567 | } |
| 555 | } | 568 | } |
| 556 | 569 | ||
| ... | @@ -584,6 +597,7 @@ pub const File = struct { | ... | @@ -584,6 +597,7 @@ pub const File = struct { |
| 584 | .wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp), | 597 | .wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp), |
| 585 | .spirv => return @fieldParentPtr(SpirV, "base", base).flush(comp), | 598 | .spirv => return @fieldParentPtr(SpirV, "base", base).flush(comp), |
| 586 | .plan9 => return @fieldParentPtr(Plan9, "base", base).flush(comp), | 599 | .plan9 => return @fieldParentPtr(Plan9, "base", base).flush(comp), |
| 600 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).flush(comp), | ||
| 587 | } | 601 | } |
| 588 | } | 602 | } |
| 589 | 603 | ||
| ... | @@ -598,6 +612,7 @@ pub const File = struct { | ... | @@ -598,6 +612,7 @@ pub const File = struct { |
| 598 | .wasm => return @fieldParentPtr(Wasm, "base", base).flushModule(comp), | 612 | .wasm => return @fieldParentPtr(Wasm, "base", base).flushModule(comp), |
| 599 | .spirv => return @fieldParentPtr(SpirV, "base", base).flushModule(comp), | 613 | .spirv => return @fieldParentPtr(SpirV, "base", base).flushModule(comp), |
| 600 | .plan9 => return @fieldParentPtr(Plan9, "base", base).flushModule(comp), | 614 | .plan9 => return @fieldParentPtr(Plan9, "base", base).flushModule(comp), |
| 615 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).flushModule(comp), | ||
| 601 | } | 616 | } |
| 602 | } | 617 | } |
| 603 | 618 | ||
| ... | @@ -612,6 +627,7 @@ pub const File = struct { | ... | @@ -612,6 +627,7 @@ pub const File = struct { |
| 612 | .wasm => @fieldParentPtr(Wasm, "base", base).freeDecl(decl), | 627 | .wasm => @fieldParentPtr(Wasm, "base", base).freeDecl(decl), |
| 613 | .spirv => @fieldParentPtr(SpirV, "base", base).freeDecl(decl), | 628 | .spirv => @fieldParentPtr(SpirV, "base", base).freeDecl(decl), |
| 614 | .plan9 => @fieldParentPtr(Plan9, "base", base).freeDecl(decl), | 629 | .plan9 => @fieldParentPtr(Plan9, "base", base).freeDecl(decl), |
| 630 | .nvptx => @fieldParentPtr(NvPtx, "base", base).freeDecl(decl), | ||
| 615 | } | 631 | } |
| 616 | } | 632 | } |
| 617 | 633 | ||
| ... | @@ -622,7 +638,7 @@ pub const File = struct { | ... | @@ -622,7 +638,7 @@ pub const File = struct { |
| 622 | .macho => return @fieldParentPtr(MachO, "base", base).error_flags, | 638 | .macho => return @fieldParentPtr(MachO, "base", base).error_flags, |
| 623 | .plan9 => return @fieldParentPtr(Plan9, "base", base).error_flags, | 639 | .plan9 => return @fieldParentPtr(Plan9, "base", base).error_flags, |
| 624 | .c => return .{ .no_entry_point_found = false }, | 640 | .c => return .{ .no_entry_point_found = false }, |
| 625 | .wasm, .spirv => return ErrorFlags{}, | 641 | .wasm, .spirv, .nvptx => return ErrorFlags{}, |
| 626 | } | 642 | } |
| 627 | } | 643 | } |
| 628 | 644 | ||
| ... | @@ -644,6 +660,7 @@ pub const File = struct { | ... | @@ -644,6 +660,7 @@ pub const File = struct { |
| 644 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclExports(module, decl, exports), | 660 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclExports(module, decl, exports), |
| 645 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateDeclExports(module, decl, exports), | 661 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateDeclExports(module, decl, exports), |
| 646 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclExports(module, decl, exports), | 662 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclExports(module, decl, exports), |
| 663 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateDeclExports(module, decl, exports), | ||
| 647 | } | 664 | } |
| 648 | } | 665 | } |
| 649 | 666 | ||
| ... | @@ -656,6 +673,7 @@ pub const File = struct { | ... | @@ -656,6 +673,7 @@ pub const File = struct { |
| 656 | .c => unreachable, | 673 | .c => unreachable, |
| 657 | .wasm => unreachable, | 674 | .wasm => unreachable, |
| 658 | .spirv => unreachable, | 675 | .spirv => unreachable, |
| 676 | .nvptx => unreachable, | ||
| 659 | } | 677 | } |
| 660 | } | 678 | } |
| 661 | 679 | ||
| ... | @@ -851,6 +869,7 @@ pub const File = struct { | ... | @@ -851,6 +869,7 @@ pub const File = struct { |
| 851 | wasm, | 869 | wasm, |
| 852 | spirv, | 870 | spirv, |
| 853 | plan9, | 871 | plan9, |
| 872 | nvptx, | ||
| 854 | }; | 873 | }; |
| 855 | 874 | ||
| 856 | pub const ErrorFlags = struct { | 875 | pub const ErrorFlags = struct { |
| ... | @@ -864,6 +883,7 @@ pub const File = struct { | ... | @@ -864,6 +883,7 @@ pub const File = struct { |
| 864 | pub const MachO = @import("link/MachO.zig"); | 883 | pub const MachO = @import("link/MachO.zig"); |
| 865 | pub const SpirV = @import("link/SpirV.zig"); | 884 | pub const SpirV = @import("link/SpirV.zig"); |
| 866 | pub const Wasm = @import("link/Wasm.zig"); | 885 | pub const Wasm = @import("link/Wasm.zig"); |
| 886 | pub const NvPtx = @import("link/NvPtx.zig"); | ||
| 867 | }; | 887 | }; |
| 868 | 888 | ||
| 869 | pub fn determineMode(options: Options) fs.File.Mode { | 889 | pub fn determineMode(options: Options) fs.File.Mode { |
src/link/NvPtx.zig created+122| ... | @@ -0,0 +1,122 @@ | ||
| 1 | //! NVidia PTX (Paralle Thread Execution) | ||
| 2 | //! https://docs.nvidia.com/cuda/parallel-thread-execution/index.html | ||
| 3 | //! For this we rely on the nvptx backend of LLVM | ||
| 4 | //! Kernel functions need to be marked both as "export" and "callconv(.PtxKernel)" | ||
| 5 | |||
| 6 | const NvPtx = @This(); | ||
| 7 | |||
| 8 | const std = @import("std"); | ||
| 9 | const builtin = @import("builtin"); | ||
| 10 | |||
| 11 | const Allocator = std.mem.Allocator; | ||
| 12 | const assert = std.debug.assert; | ||
| 13 | const log = std.log.scoped(.link); | ||
| 14 | |||
| 15 | const Module = @import("../Module.zig"); | ||
| 16 | const Compilation = @import("../Compilation.zig"); | ||
| 17 | const link = @import("../link.zig"); | ||
| 18 | const trace = @import("../tracy.zig").trace; | ||
| 19 | const build_options = @import("build_options"); | ||
| 20 | const Air = @import("../Air.zig"); | ||
| 21 | const Liveness = @import("../Liveness.zig"); | ||
| 22 | const LlvmObject = @import("../codegen/llvm.zig").Object; | ||
| 23 | |||
| 24 | base: link.File, | ||
| 25 | llvm_object: *LlvmObject, | ||
| 26 | |||
| 27 | pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx { | ||
| 28 | if (!build_options.have_llvm) return error.TODOArchNotSupported; | ||
| 29 | |||
| 30 | const nvptx = try gpa.create(NvPtx); | ||
| 31 | nvptx.* = .{ | ||
| 32 | .base = .{ | ||
| 33 | .tag = .nvptx, | ||
| 34 | .options = options, | ||
| 35 | .file = null, | ||
| 36 | .allocator = gpa, | ||
| 37 | }, | ||
| 38 | .llvm_object = undefined, | ||
| 39 | }; | ||
| 40 | |||
| 41 | switch (options.target.cpu.arch) { | ||
| 42 | .nvptx, .nvptx64 => {}, | ||
| 43 | else => return error.TODOArchNotSupported, | ||
| 44 | } | ||
| 45 | |||
| 46 | switch (options.target.os.tag) { | ||
| 47 | // TODO: does it also work with nvcl ? | ||
| 48 | .cuda => {}, | ||
| 49 | else => return error.TODOOsNotSupported, | ||
| 50 | } | ||
| 51 | |||
| 52 | return nvptx; | ||
| 53 | } | ||
| 54 | |||
| 55 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx { | ||
| 56 | if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled."); | ||
| 57 | if (!options.use_llvm) return error.TODOArchNotSupported; | ||
| 58 | assert(options.object_format == .nvptx); | ||
| 59 | |||
| 60 | const nvptx = try createEmpty(allocator, options); | ||
| 61 | errdefer nvptx.base.destroy(); | ||
| 62 | log.info("Opening .ptx target file {s}", .{sub_path}); | ||
| 63 | nvptx.llvm_object = try LlvmObject.create(allocator, options); | ||
| 64 | return nvptx; | ||
| 65 | } | ||
| 66 | |||
| 67 | pub fn deinit(self: *NvPtx) void { | ||
| 68 | if (!build_options.have_llvm) return; | ||
| 69 | self.llvm_object.destroy(self.base.allocator); | ||
| 70 | } | ||
| 71 | |||
| 72 | pub fn updateFunc(self: *NvPtx, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | ||
| 73 | if (!build_options.have_llvm) return; | ||
| 74 | try self.llvm_object.updateFunc(module, func, air, liveness); | ||
| 75 | } | ||
| 76 | |||
| 77 | pub fn updateDecl(self: *NvPtx, module: *Module, decl: *Module.Decl) !void { | ||
| 78 | if (!build_options.have_llvm) return; | ||
| 79 | return self.llvm_object.updateDecl(module, decl); | ||
| 80 | } | ||
| 81 | |||
| 82 | pub fn updateDeclExports( | ||
| 83 | self: *NvPtx, | ||
| 84 | module: *Module, | ||
| 85 | decl: *const Module.Decl, | ||
| 86 | exports: []const *Module.Export, | ||
| 87 | ) !void { | ||
| 88 | if (!build_options.have_llvm) return; | ||
| 89 | if (build_options.skip_non_native and builtin.object_format != .nvptx) { | ||
| 90 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 91 | } | ||
| 92 | return self.llvm_object.updateDeclExports(module, decl, exports); | ||
| 93 | } | ||
| 94 | |||
| 95 | pub fn freeDecl(self: *NvPtx, decl: *Module.Decl) void { | ||
| 96 | if (!build_options.have_llvm) return; | ||
| 97 | return self.llvm_object.freeDecl(decl); | ||
| 98 | } | ||
| 99 | |||
| 100 | pub fn flush(self: *NvPtx, comp: *Compilation) !void { | ||
| 101 | return self.flushModule(comp); | ||
| 102 | } | ||
| 103 | |||
| 104 | pub fn flushModule(self: *NvPtx, comp: *Compilation) !void { | ||
| 105 | if (!build_options.have_llvm) return; | ||
| 106 | if (build_options.skip_non_native) { | ||
| 107 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | ||
| 108 | } | ||
| 109 | const tracy = trace(@src()); | ||
| 110 | defer tracy.end(); | ||
| 111 | |||
| 112 | var hack_comp = comp; | ||
| 113 | if (comp.bin_file.options.emit) |emit| { | ||
| 114 | hack_comp.emit_asm = .{ | ||
| 115 | .directory = emit.directory, | ||
| 116 | .basename = comp.bin_file.intermediary_basename.?, | ||
| 117 | }; | ||
| 118 | hack_comp.bin_file.options.emit = null; | ||
| 119 | } | ||
| 120 | |||
| 121 | return try self.llvm_object.flushModule(hack_comp); | ||
| 122 | } | ||
src/stage1/all_types.hpp+2-1| ... | @@ -83,7 +83,8 @@ enum CallingConvention { | ... | @@ -83,7 +83,8 @@ enum CallingConvention { |
| 83 | CallingConventionAPCS, | 83 | CallingConventionAPCS, |
| 84 | CallingConventionAAPCS, | 84 | CallingConventionAAPCS, |
| 85 | CallingConventionAAPCSVFP, | 85 | CallingConventionAAPCSVFP, |
| 86 | CallingConventionSysV | 86 | CallingConventionSysV, |
| 87 | CallingConventionPtxKernel | ||
| 87 | }; | 88 | }; |
| 88 | 89 | ||
| 89 | // Stage 1 supports only the generic address space | 90 | // Stage 1 supports only the generic address space |
src/stage1/analyze.cpp+12| ... | @@ -991,6 +991,7 @@ const char *calling_convention_name(CallingConvention cc) { | ... | @@ -991,6 +991,7 @@ const char *calling_convention_name(CallingConvention cc) { |
| 991 | case CallingConventionAAPCSVFP: return "AAPCSVFP"; | 991 | case CallingConventionAAPCSVFP: return "AAPCSVFP"; |
| 992 | case CallingConventionInline: return "Inline"; | 992 | case CallingConventionInline: return "Inline"; |
| 993 | case CallingConventionSysV: return "SysV"; | 993 | case CallingConventionSysV: return "SysV"; |
| 994 | case CallingConventionPtxKernel: return "PtxKernel"; | ||
| 994 | } | 995 | } |
| 995 | zig_unreachable(); | 996 | zig_unreachable(); |
| 996 | } | 997 | } |
| ... | @@ -1000,6 +1001,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { | ... | @@ -1000,6 +1001,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { |
| 1000 | case CallingConventionUnspecified: | 1001 | case CallingConventionUnspecified: |
| 1001 | case CallingConventionAsync: | 1002 | case CallingConventionAsync: |
| 1002 | case CallingConventionInline: | 1003 | case CallingConventionInline: |
| 1004 | case CallingConventionPtxKernel: | ||
| 1003 | return true; | 1005 | return true; |
| 1004 | case CallingConventionC: | 1006 | case CallingConventionC: |
| 1005 | case CallingConventionNaked: | 1007 | case CallingConventionNaked: |
| ... | @@ -2006,6 +2008,15 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_ | ... | @@ -2006,6 +2008,15 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_ |
| 2006 | case CallingConventionSysV: | 2008 | case CallingConventionSysV: |
| 2007 | if (g->zig_target->arch != ZigLLVM_x86_64) | 2009 | if (g->zig_target->arch != ZigLLVM_x86_64) |
| 2008 | allowed_platforms = "x86_64"; | 2010 | allowed_platforms = "x86_64"; |
| 2011 | break; | ||
| 2012 | case CallingConventionPtxKernel: | ||
| 2013 | if (g->zig_target->arch != ZigLLVM_nvptx | ||
| 2014 | && g->zig_target->arch != ZigLLVM_nvptx64) | ||
| 2015 | { | ||
| 2016 | allowed_platforms = "nvptx and nvptx64"; | ||
| 2017 | } | ||
| 2018 | break; | ||
| 2019 | |||
| 2009 | } | 2020 | } |
| 2010 | if (allowed_platforms != nullptr) { | 2021 | if (allowed_platforms != nullptr) { |
| 2011 | add_node_error(g, source_node, buf_sprintf( | 2022 | add_node_error(g, source_node, buf_sprintf( |
| ... | @@ -3827,6 +3838,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -3827,6 +3838,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 3827 | case CallingConventionAAPCS: | 3838 | case CallingConventionAAPCS: |
| 3828 | case CallingConventionAAPCSVFP: | 3839 | case CallingConventionAAPCSVFP: |
| 3829 | case CallingConventionSysV: | 3840 | case CallingConventionSysV: |
| 3841 | case CallingConventionPtxKernel: | ||
| 3830 | add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), | 3842 | add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), |
| 3831 | GlobalLinkageIdStrong, fn_cc); | 3843 | GlobalLinkageIdStrong, fn_cc); |
| 3832 | break; | 3844 | break; |
src/stage1/codegen.cpp+6| ... | @@ -209,6 +209,11 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { | ... | @@ -209,6 +209,11 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { |
| 209 | case CallingConventionSysV: | 209 | case CallingConventionSysV: |
| 210 | assert(g->zig_target->arch == ZigLLVM_x86_64); | 210 | assert(g->zig_target->arch == ZigLLVM_x86_64); |
| 211 | return ZigLLVM_X86_64_SysV; | 211 | return ZigLLVM_X86_64_SysV; |
| 212 | case CallingConventionPtxKernel: | ||
| 213 | assert(g->zig_target->arch == ZigLLVM_nvptx || | ||
| 214 | g->zig_target->arch == ZigLLVM_nvptx64); | ||
| 215 | return ZigLLVM_PTX_Kernel; | ||
| 216 | |||
| 212 | } | 217 | } |
| 213 | zig_unreachable(); | 218 | zig_unreachable(); |
| 214 | } | 219 | } |
| ... | @@ -354,6 +359,7 @@ static bool cc_want_sret_attr(CallingConvention cc) { | ... | @@ -354,6 +359,7 @@ static bool cc_want_sret_attr(CallingConvention cc) { |
| 354 | case CallingConventionAAPCS: | 359 | case CallingConventionAAPCS: |
| 355 | case CallingConventionAAPCSVFP: | 360 | case CallingConventionAAPCSVFP: |
| 356 | case CallingConventionSysV: | 361 | case CallingConventionSysV: |
| 362 | case CallingConventionPtxKernel: | ||
| 357 | return true; | 363 | return true; |
| 358 | case CallingConventionAsync: | 364 | case CallingConventionAsync: |
| 359 | case CallingConventionUnspecified: | 365 | case CallingConventionUnspecified: |
src/stage1/ir.cpp+1| ... | @@ -11666,6 +11666,7 @@ static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirIns | ... | @@ -11666,6 +11666,7 @@ static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirIns |
| 11666 | case CallingConventionAAPCS: | 11666 | case CallingConventionAAPCS: |
| 11667 | case CallingConventionAAPCSVFP: | 11667 | case CallingConventionAAPCSVFP: |
| 11668 | case CallingConventionSysV: | 11668 | case CallingConventionSysV: |
| 11669 | case CallingConventionPtxKernel: | ||
| 11669 | add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc); | 11670 | add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc); |
| 11670 | fn_entry->section_name = section_name; | 11671 | fn_entry->section_name = section_name; |
| 11671 | break; | 11672 | break; |