| author | |
| committer | |
| log | feab1ebe1bfea3955320a6acba69f0c6c79c0730 |
| tree | 023f71b0c26e3a0ea63b607aedb97b132c9c114e |
| parent | 65f860bef7995a6120e49606d549bdf154bca150 |
| parent | c289794f0db3e06c568450cc6c646a0ba63a73ba |
| signature |
Update Nvptx backend for Zig 0.109 files changed, 91 insertions(+), 31 deletions(-)
lib/std/builtin.zig+1| ... | ... | @@ -833,6 +833,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr |
| 833 | 833 | // Didn't have boot_services, just fallback to whatever. |
| 834 | 834 | std.os.abort(); |
| 835 | 835 | }, |
| 836 | .cuda => std.os.abort(), | |
| 836 | 837 | else => { |
| 837 | 838 | const first_trace_addr = ret_addr orelse @returnAddress(); |
| 838 | 839 | std.debug.panicImpl(error_return_trace, first_trace_addr, msg); |
lib/std/os.zig+6| ... | ... | @@ -500,10 +500,16 @@ pub fn abort() noreturn { |
| 500 | 500 | @breakpoint(); |
| 501 | 501 | exit(1); |
| 502 | 502 | } |
| 503 | if (builtin.os.tag == .cuda) { | |
| 504 | // TODO: introduce `@trap` instead of abusing https://github.com/ziglang/zig/issues/2291 | |
| 505 | @"llvm.trap"(); | |
| 506 | } | |
| 503 | 507 | |
| 504 | 508 | system.abort(); |
| 505 | 509 | } |
| 506 | 510 | |
| 511 | extern fn @"llvm.trap"() noreturn; | |
| 512 | ||
| 507 | 513 | pub const RaiseError = UnexpectedError; |
| 508 | 514 | |
| 509 | 515 | pub fn raise(sig: u8) RaiseError!void { |
lib/std/target.zig+7| ... | ... | @@ -951,6 +951,13 @@ pub const Target = struct { |
| 951 | 951 | }; |
| 952 | 952 | } |
| 953 | 953 | |
| 954 | pub fn isNvptx(arch: Arch) bool { | |
| 955 | return switch (arch) { | |
| 956 | .nvptx, .nvptx64 => true, | |
| 957 | else => false, | |
| 958 | }; | |
| 959 | } | |
| 960 | ||
| 954 | 961 | pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { |
| 955 | 962 | for (arch.allCpuModels()) |cpu| { |
| 956 | 963 | if (mem.eql(u8, cpu_name, cpu.name)) { |
src/Module.zig+9| ... | ... | @@ -720,6 +720,15 @@ pub const Decl = struct { |
| 720 | 720 | var buffer = std.ArrayList(u8).init(mod.gpa); |
| 721 | 721 | defer buffer.deinit(); |
| 722 | 722 | try decl.renderFullyQualifiedName(mod, buffer.writer()); |
| 723 | ||
| 724 | // Sanitize the name for nvptx which is more restrictive. | |
| 725 | if (mod.comp.bin_file.options.target.cpu.arch.isNvptx()) { | |
| 726 | for (buffer.items) |*byte| switch (byte.*) { | |
| 727 | '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', | |
| 728 | else => {}, | |
| 729 | }; | |
| 730 | } | |
| 731 | ||
| 723 | 732 | return buffer.toOwnedSliceSentinel(0); |
| 724 | 733 | } |
| 725 | 734 |
src/Sema.zig+6-7| ... | ... | @@ -18202,12 +18202,6 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 18202 | 18202 | else |
| 18203 | 18203 | dest_ptr_ty; |
| 18204 | 18204 | |
| 18205 | if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |val| { | |
| 18206 | // Pointer value should compatible with both address spaces. | |
| 18207 | // TODO: Figure out why this generates an invalid bitcast. | |
| 18208 | return sema.addConstant(dest_ty, val); | |
| 18209 | } | |
| 18210 | ||
| 18211 | 18205 | try sema.requireRuntimeBlock(block, src, ptr_src); |
| 18212 | 18206 | // TODO: Address space cast safety? |
| 18213 | 18207 | |
| ... | ... | @@ -21397,7 +21391,12 @@ fn validateExternType( |
| 21397 | 21391 | }, |
| 21398 | 21392 | .Fn => { |
| 21399 | 21393 | if (position != .other) return false; |
| 21400 | return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()); | |
| 21394 | return switch (ty.fnCallingConvention()) { | |
| 21395 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. | |
| 21396 | // The goal is to experiment with more integrated CPU/GPU code. | |
| 21397 | .PtxKernel => true, | |
| 21398 | else => !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()), | |
| 21399 | }; | |
| 21401 | 21400 | }, |
| 21402 | 21401 | .Enum => { |
| 21403 | 21402 | var buf: Type.Payload.Bits = undefined; |
src/link/NvPtx.zig+17-15| ... | ... | @@ -28,10 +28,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx { |
| 28 | 28 | if (!build_options.have_llvm) return error.PtxArchNotSupported; |
| 29 | 29 | if (!options.use_llvm) return error.PtxArchNotSupported; |
| 30 | 30 | |
| 31 | switch (options.target.cpu.arch) { | |
| 32 | .nvptx, .nvptx64 => {}, | |
| 33 | else => return error.PtxArchNotSupported, | |
| 34 | } | |
| 31 | if (!options.target.cpu.arch.isNvptx()) return error.PtxArchNotSupported; | |
| 35 | 32 | |
| 36 | 33 | switch (options.target.os.tag) { |
| 37 | 34 | // TODO: does it also work with nvcl ? |
| ... | ... | @@ -59,9 +56,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 59 | 56 | if (!options.use_llvm) return error.PtxArchNotSupported; |
| 60 | 57 | assert(options.target.ofmt == .nvptx); |
| 61 | 58 | |
| 62 | const nvptx = try createEmpty(allocator, options); | |
| 63 | log.info("Opening .ptx target file {s}", .{sub_path}); | |
| 64 | return nvptx; | |
| 59 | log.debug("Opening .ptx target file {s}", .{sub_path}); | |
| 60 | return createEmpty(allocator, options); | |
| 65 | 61 | } |
| 66 | 62 | |
| 67 | 63 | pub fn deinit(self: *NvPtx) void { |
| ... | ... | @@ -109,13 +105,19 @@ pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.No |
| 109 | 105 | const tracy = trace(@src()); |
| 110 | 106 | defer tracy.end(); |
| 111 | 107 | |
| 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; | |
| 108 | const outfile = comp.bin_file.options.emit.?; | |
| 109 | // We modify 'comp' before passing it to LLVM, but restore value afterwards. | |
| 110 | // We tell LLVM to not try to build a .o, only an "assembly" file. | |
| 111 | // This is required by the LLVM PTX backend. | |
| 112 | comp.bin_file.options.emit = null; | |
| 113 | comp.emit_asm = .{ | |
| 114 | .directory = outfile.directory, | |
| 115 | .basename = comp.bin_file.intermediary_basename.?, | |
| 116 | }; | |
| 117 | defer { | |
| 118 | comp.bin_file.options.emit = outfile; | |
| 119 | comp.emit_asm = null; | |
| 119 | 120 | } |
| 120 | return try self.llvm_object.flushModule(hack_comp, prog_node); | |
| 121 | ||
| 122 | try self.llvm_object.flushModule(comp, prog_node); | |
| 121 | 123 | } |
src/target.zig+6-2| ... | ... | @@ -411,7 +411,11 @@ pub fn classifyCompilerRtLibName(target: std.Target, name: []const u8) CompilerR |
| 411 | 411 | } |
| 412 | 412 | |
| 413 | 413 | pub fn hasDebugInfo(target: std.Target) bool { |
| 414 | _ = target; | |
| 414 | if (target.cpu.arch.isNvptx()) { | |
| 415 | // TODO: not sure how to test "ptx >= 7.5" with featureset | |
| 416 | return std.Target.nvptx.featureSetHas(target.cpu.features, .ptx75); | |
| 417 | } | |
| 418 | ||
| 415 | 419 | return true; |
| 416 | 420 | } |
| 417 | 421 | |
| ... | ... | @@ -651,7 +655,7 @@ pub fn addrSpaceCastIsValid( |
| 651 | 655 | const arch = target.cpu.arch; |
| 652 | 656 | switch (arch) { |
| 653 | 657 | .x86_64, .i386 => return arch.supportsAddressSpace(from) and arch.supportsAddressSpace(to), |
| 654 | .amdgcn => { | |
| 658 | .nvptx64, .nvptx, .amdgcn => { | |
| 655 | 659 | const to_generic = arch.supportsAddressSpace(from) and to == .generic; |
| 656 | 660 | const from_generic = arch.supportsAddressSpace(to) and from == .generic; |
| 657 | 661 | return to_generic or from_generic; |
test/cases.zig+1-2| ... | ... | @@ -4,6 +4,5 @@ const TestContext = @import("../src/test.zig").TestContext; |
| 4 | 4 | pub fn addCases(ctx: *TestContext) !void { |
| 5 | 5 | try @import("compile_errors.zig").addCases(ctx); |
| 6 | 6 | try @import("stage2/cbe.zig").addCases(ctx); |
| 7 | // https://github.com/ziglang/zig/issues/10968 | |
| 8 | //try @import("stage2/nvptx.zig").addCases(ctx); | |
| 7 | try @import("stage2/nvptx.zig").addCases(ctx); | |
| 9 | 8 | } |
test/stage2/nvptx.zig+38-5| ... | ... | @@ -23,11 +23,10 @@ pub fn addCases(ctx: *TestContext) !void { |
| 23 | 23 | var case = addPtx(ctx, "nvptx: read special registers"); |
| 24 | 24 | |
| 25 | 25 | case.compiles( |
| 26 | \\fn threadIdX() usize { | |
| 27 | \\ var tid = asm volatile ("mov.u32 \t$0, %tid.x;" | |
| 28 | \\ : [ret] "=r" (-> u32), | |
| 29 | \\ ); | |
| 30 | \\ return @as(usize, tid); | |
| 26 | \\fn threadIdX() u32 { | |
| 27 | \\ return asm ("mov.u32 \t%[r], %tid.x;" | |
| 28 | \\ : [r] "=r" (-> u32), | |
| 29 | \\ ); | |
| 31 | 30 | \\} |
| 32 | 31 | \\ |
| 33 | 32 | \\pub export fn special_reg(a: []const i32, out: []i32) callconv(.PtxKernel) void { |
| ... | ... | @@ -49,6 +48,38 @@ pub fn addCases(ctx: *TestContext) !void { |
| 49 | 48 | \\} |
| 50 | 49 | ); |
| 51 | 50 | } |
| 51 | ||
| 52 | { | |
| 53 | var case = addPtx(ctx, "nvptx: reduce in shared mem"); | |
| 54 | case.compiles( | |
| 55 | \\fn threadIdX() u32 { | |
| 56 | \\ return asm ("mov.u32 \t%[r], %tid.x;" | |
| 57 | \\ : [r] "=r" (-> u32), | |
| 58 | \\ ); | |
| 59 | \\} | |
| 60 | \\ | |
| 61 | \\ var _sdata: [1024]f32 addrspace(.shared) = undefined; | |
| 62 | \\ pub export fn reduceSum(d_x: []const f32, out: *f32) callconv(.PtxKernel) void { | |
| 63 | \\ var sdata = @addrSpaceCast(.generic, &_sdata); | |
| 64 | \\ const tid: u32 = threadIdX(); | |
| 65 | \\ var sum = d_x[tid]; | |
| 66 | \\ sdata[tid] = sum; | |
| 67 | \\ asm volatile ("bar.sync \t0;"); | |
| 68 | \\ var s: u32 = 512; | |
| 69 | \\ while (s > 0) : (s = s >> 1) { | |
| 70 | \\ if (tid < s) { | |
| 71 | \\ sum += sdata[tid + s]; | |
| 72 | \\ sdata[tid] = sum; | |
| 73 | \\ } | |
| 74 | \\ asm volatile ("bar.sync \t0;"); | |
| 75 | \\ } | |
| 76 | \\ | |
| 77 | \\ if (tid == 0) { | |
| 78 | \\ out.* = sum; | |
| 79 | \\ } | |
| 80 | \\ } | |
| 81 | ); | |
| 82 | } | |
| 52 | 83 | } |
| 53 | 84 | |
| 54 | 85 | const nvptx_target = std.zig.CrossTarget{ |
| ... | ... | @@ -68,6 +99,8 @@ pub fn addPtx( |
| 68 | 99 | .files = std.ArrayList(TestContext.File).init(ctx.cases.allocator), |
| 69 | 100 | .link_libc = false, |
| 70 | 101 | .backend = .llvm, |
| 102 | // Bug in Debug mode | |
| 103 | .optimize_mode = .ReleaseSafe, | |
| 71 | 104 | }) catch @panic("out of memory"); |
| 72 | 105 | return &ctx.cases.items[ctx.cases.items.len - 1]; |
| 73 | 106 | } |