| author | |
| committer | |
| log | f12beb857ad7868396a4246b8f62f83f625c0978 |
| tree | ee82e5c5b60c48db8122adaa6f74763ea756c2a4 |
| parent | 3f2025f59e4488bff9e046cabbbff047fa1db508 |
| signature |
AmdgpuKernel and NvptxKernel are unified into a Kernel calling convention.
There is really no reason for these to be separate; no backend is allowed to
emit the calling convention of the other. This is in the same spirit as the
.Interrupt calling convention lowering to different LLVM calling conventions,
and opens the way for SPIR-V kernels to be exported using the Kernel calling
convention.6 files changed, 27 insertions(+), 30 deletions(-)
lib/std/builtin.zig+1-2| ... | @@ -160,8 +160,7 @@ pub const CallingConvention = enum { | ... | @@ -160,8 +160,7 @@ pub const CallingConvention = enum { |
| 160 | AAPCSVFP, | 160 | AAPCSVFP, |
| 161 | SysV, | 161 | SysV, |
| 162 | Win64, | 162 | Win64, |
| 163 | PtxKernel, | 163 | Kernel, |
| 164 | AmdgpuKernel, | ||
| 165 | }; | 164 | }; |
| 166 | 165 | ||
| 167 | /// This data structure is used by the Zig language code generation and | 166 | /// This data structure is used by the Zig language code generation and |
src/Sema.zig+15-17| ... | @@ -8883,7 +8883,7 @@ fn funcCommon( | ... | @@ -8883,7 +8883,7 @@ fn funcCommon( |
| 8883 | }; | 8883 | }; |
| 8884 | return sema.failWithOwnedErrorMsg(msg); | 8884 | return sema.failWithOwnedErrorMsg(msg); |
| 8885 | } | 8885 | } |
| 8886 | if (!ret_poison and !Type.fnCallingConventionAllowsZigTypes(cc_resolved) and !try sema.validateExternType(return_type, .ret_ty)) { | 8886 | if (!ret_poison and !Type.fnCallingConventionAllowsZigTypes(target, cc_resolved) and !try sema.validateExternType(return_type, .ret_ty)) { |
| 8887 | const msg = msg: { | 8887 | const msg = msg: { |
| 8888 | const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ | 8888 | const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ |
| 8889 | return_type.fmt(sema.mod), @tagName(cc_resolved), | 8889 | return_type.fmt(sema.mod), @tagName(cc_resolved), |
| ... | @@ -8961,13 +8961,9 @@ fn funcCommon( | ... | @@ -8961,13 +8961,9 @@ fn funcCommon( |
| 8961 | .x86_64 => null, | 8961 | .x86_64 => null, |
| 8962 | else => @as([]const u8, "x86_64"), | 8962 | else => @as([]const u8, "x86_64"), |
| 8963 | }, | 8963 | }, |
| 8964 | .PtxKernel => switch (arch) { | 8964 | .Kernel => switch (arch) { |
| 8965 | .nvptx, .nvptx64 => null, | 8965 | .nvptx, .nvptx64, .amdgcn, .spirv32, .spirv64 => null, |
| 8966 | else => @as([]const u8, "nvptx and nvptx64"), | 8966 | else => @as([]const u8, "nvptx, amdgcn and SPIR-V"), |
| 8967 | }, | ||
| 8968 | .AmdgpuKernel => switch (arch) { | ||
| 8969 | .amdgcn => null, | ||
| 8970 | else => @as([]const u8, "amdgcn"), | ||
| 8971 | }, | 8967 | }, |
| 8972 | }) |allowed_platform| { | 8968 | }) |allowed_platform| { |
| 8973 | return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{ | 8969 | return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{ |
| ... | @@ -9093,10 +9089,11 @@ fn analyzeParameter( | ... | @@ -9093,10 +9089,11 @@ fn analyzeParameter( |
| 9093 | comptime_params[i] = param.is_comptime or requires_comptime; | 9089 | comptime_params[i] = param.is_comptime or requires_comptime; |
| 9094 | const this_generic = param.ty.tag() == .generic_poison; | 9090 | const this_generic = param.ty.tag() == .generic_poison; |
| 9095 | is_generic.* = is_generic.* or this_generic; | 9091 | is_generic.* = is_generic.* or this_generic; |
| 9096 | if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) { | 9092 | const target = sema.mod.getTarget(); |
| 9093 | if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(target, cc)) { | ||
| 9097 | return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); | 9094 | return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); |
| 9098 | } | 9095 | } |
| 9099 | if (this_generic and !sema.no_partial_func_ty and !Type.fnCallingConventionAllowsZigTypes(cc)) { | 9096 | if (this_generic and !sema.no_partial_func_ty and !Type.fnCallingConventionAllowsZigTypes(target, cc)) { |
| 9100 | return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); | 9097 | return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); |
| 9101 | } | 9098 | } |
| 9102 | if (!param.ty.isValidParamType()) { | 9099 | if (!param.ty.isValidParamType()) { |
| ... | @@ -9112,7 +9109,7 @@ fn analyzeParameter( | ... | @@ -9112,7 +9109,7 @@ fn analyzeParameter( |
| 9112 | }; | 9109 | }; |
| 9113 | return sema.failWithOwnedErrorMsg(msg); | 9110 | return sema.failWithOwnedErrorMsg(msg); |
| 9114 | } | 9111 | } |
| 9115 | if (!this_generic and !Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(param.ty, .param_ty)) { | 9112 | if (!this_generic and !Type.fnCallingConventionAllowsZigTypes(target, cc) and !try sema.validateExternType(param.ty, .param_ty)) { |
| 9116 | const msg = msg: { | 9113 | const msg = msg: { |
| 9117 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ | 9114 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ |
| 9118 | param.ty.fmt(sema.mod), @tagName(cc), | 9115 | param.ty.fmt(sema.mod), @tagName(cc), |
| ... | @@ -22786,12 +22783,13 @@ fn validateExternType( | ... | @@ -22786,12 +22783,13 @@ fn validateExternType( |
| 22786 | }, | 22783 | }, |
| 22787 | .Fn => { | 22784 | .Fn => { |
| 22788 | if (position != .other) return false; | 22785 | if (position != .other) return false; |
| 22789 | return switch (ty.fnCallingConvention()) { | 22786 | const target = sema.mod.getTarget(); |
| 22790 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. | 22787 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. |
| 22791 | // The goal is to experiment with more integrated CPU/GPU code. | 22788 | // The goal is to experiment with more integrated CPU/GPU code. |
| 22792 | .PtxKernel => true, | 22789 | if (ty.fnCallingConvention() == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) { |
| 22793 | else => !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()), | 22790 | return true; |
| 22794 | }; | 22791 | } |
| 22792 | return !Type.fnCallingConventionAllowsZigTypes(target, ty.fnCallingConvention()); | ||
| 22795 | }, | 22793 | }, |
| 22796 | .Enum => { | 22794 | .Enum => { |
| 22797 | var buf: Type.Payload.Bits = undefined; | 22795 | var buf: Type.Payload.Bits = undefined; |
src/codegen/llvm.zig+1-4| ... | @@ -10350,11 +10350,8 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca | ... | @@ -10350,11 +10350,8 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca |
| 10350 | .Signal => .AVR_SIGNAL, | 10350 | .Signal => .AVR_SIGNAL, |
| 10351 | .SysV => .X86_64_SysV, | 10351 | .SysV => .X86_64_SysV, |
| 10352 | .Win64 => .Win64, | 10352 | .Win64 => .Win64, |
| 10353 | .PtxKernel => return switch (target.cpu.arch) { | 10353 | .Kernel => return switch (target.cpu.arch) { |
| 10354 | .nvptx, .nvptx64 => .PTX_Kernel, | 10354 | .nvptx, .nvptx64 => .PTX_Kernel, |
| 10355 | else => unreachable, | ||
| 10356 | }, | ||
| 10357 | .AmdgpuKernel => return switch (target.cpu.arch) { | ||
| 10358 | .amdgcn => .AMDGPU_KERNEL, | 10355 | .amdgcn => .AMDGPU_KERNEL, |
| 10359 | else => unreachable, | 10356 | else => unreachable, |
| 10360 | }, | 10357 | }, |
src/link/NvPtx.zig+1-1| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | //! NVidia PTX (Paralle Thread Execution) | 1 | //! NVidia PTX (Paralle Thread Execution) |
| 2 | //! https://docs.nvidia.com/cuda/parallel-thread-execution/index.html | 2 | //! https://docs.nvidia.com/cuda/parallel-thread-execution/index.html |
| 3 | //! For this we rely on the nvptx backend of LLVM | 3 | //! For this we rely on the nvptx backend of LLVM |
| 4 | //! Kernel functions need to be marked both as "export" and "callconv(.PtxKernel)" | 4 | //! Kernel functions need to be marked both as "export" and "callconv(.Kernel)" |
| 5 | 5 | ||
| 6 | const NvPtx = @This(); | 6 | const NvPtx = @This(); |
| 7 | 7 |
src/type.zig+5-2| ... | @@ -4796,9 +4796,12 @@ pub const Type = extern union { | ... | @@ -4796,9 +4796,12 @@ pub const Type = extern union { |
| 4796 | } | 4796 | } |
| 4797 | 4797 | ||
| 4798 | /// Asserts the type is a function. | 4798 | /// Asserts the type is a function. |
| 4799 | pub fn fnCallingConventionAllowsZigTypes(cc: std.builtin.CallingConvention) bool { | 4799 | pub fn fnCallingConventionAllowsZigTypes(target: Target, cc: std.builtin.CallingConvention) bool { |
| 4800 | return switch (cc) { | 4800 | return switch (cc) { |
| 4801 | .Unspecified, .Async, .Inline, .PtxKernel => true, | 4801 | .Unspecified, .Async, .Inline => true, |
| 4802 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. | ||
| 4803 | // The goal is to experiment with more integrated CPU/GPU code. | ||
| 4804 | .Kernel => target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64, | ||
| 4802 | else => false, | 4805 | else => false, |
| 4803 | }; | 4806 | }; |
| 4804 | } | 4807 | } |
test/nvptx.zig+4-4| ... | @@ -10,7 +10,7 @@ pub fn addCases(ctx: *Cases) !void { | ... | @@ -10,7 +10,7 @@ pub fn addCases(ctx: *Cases) !void { |
| 10 | \\ return a + b; | 10 | \\ return a + b; |
| 11 | \\} | 11 | \\} |
| 12 | \\ | 12 | \\ |
| 13 | \\pub export fn add_and_substract(a: i32, out: *i32) callconv(.PtxKernel) void { | 13 | \\pub export fn add_and_substract(a: i32, out: *i32) callconv(.Kernel) void { |
| 14 | \\ const x = add(a, 7); | 14 | \\ const x = add(a, 7); |
| 15 | \\ var y = add(2, 0); | 15 | \\ var y = add(2, 0); |
| 16 | \\ y -= x; | 16 | \\ y -= x; |
| ... | @@ -29,7 +29,7 @@ pub fn addCases(ctx: *Cases) !void { | ... | @@ -29,7 +29,7 @@ pub fn addCases(ctx: *Cases) !void { |
| 29 | \\ ); | 29 | \\ ); |
| 30 | \\} | 30 | \\} |
| 31 | \\ | 31 | \\ |
| 32 | \\pub export fn special_reg(a: []const i32, out: []i32) callconv(.PtxKernel) void { | 32 | \\pub export fn special_reg(a: []const i32, out: []i32) callconv(.Kernel) void { |
| 33 | \\ const i = threadIdX(); | 33 | \\ const i = threadIdX(); |
| 34 | \\ out[i] = a[i] + 7; | 34 | \\ out[i] = a[i] + 7; |
| 35 | \\} | 35 | \\} |
| ... | @@ -42,7 +42,7 @@ pub fn addCases(ctx: *Cases) !void { | ... | @@ -42,7 +42,7 @@ pub fn addCases(ctx: *Cases) !void { |
| 42 | case.addCompile( | 42 | case.addCompile( |
| 43 | \\var x: i32 addrspace(.global) = 0; | 43 | \\var x: i32 addrspace(.global) = 0; |
| 44 | \\ | 44 | \\ |
| 45 | \\pub export fn increment(out: *i32) callconv(.PtxKernel) void { | 45 | \\pub export fn increment(out: *i32) callconv(.Kernel) void { |
| 46 | \\ x += 1; | 46 | \\ x += 1; |
| 47 | \\ out.* = x; | 47 | \\ out.* = x; |
| 48 | \\} | 48 | \\} |
| ... | @@ -59,7 +59,7 @@ pub fn addCases(ctx: *Cases) !void { | ... | @@ -59,7 +59,7 @@ pub fn addCases(ctx: *Cases) !void { |
| 59 | \\} | 59 | \\} |
| 60 | \\ | 60 | \\ |
| 61 | \\ var _sdata: [1024]f32 addrspace(.shared) = undefined; | 61 | \\ var _sdata: [1024]f32 addrspace(.shared) = undefined; |
| 62 | \\ pub export fn reduceSum(d_x: []const f32, out: *f32) callconv(.PtxKernel) void { | 62 | \\ pub export fn reduceSum(d_x: []const f32, out: *f32) callconv(.Kernel) void { |
| 63 | \\ var sdata = @addrSpaceCast(.generic, &_sdata); | 63 | \\ var sdata = @addrSpaceCast(.generic, &_sdata); |
| 64 | \\ const tid: u32 = threadIdX(); | 64 | \\ const tid: u32 = threadIdX(); |
| 65 | \\ var sum = d_x[tid]; | 65 | \\ var sum = d_x[tid]; |