authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-04-08 14:17:34+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-04-09 01:51:54+02:00
logf12beb857ad7868396a4246b8f62f83f625c0978
treeee82e5c5b60c48db8122adaa6f74763ea756c2a4
parent3f2025f59e4488bff9e046cabbbff047fa1db508
signaturelock-open Commit is signed but in an unrecognized format.

amdgpu,nvptx: unify kernel calling conventions

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};
166165
167/// This data structure is used by the Zig language code generation and166/// 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.html2//! https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
3//! For this we rely on the nvptx backend of LLVM3//! 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)"
55
6const NvPtx = @This();6const NvPtx = @This();
77
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 }
47974797
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];