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 {
160160 AAPCSVFP,
161161 SysV,
162162 Win64,
163 PtxKernel,
164 AmdgpuKernel,
163 Kernel,
165164};
166165
167166/// This data structure is used by the Zig language code generation and
src/Sema.zig+15-17
......@@ -8883,7 +8883,7 @@ fn funcCommon(
88838883 };
88848884 return sema.failWithOwnedErrorMsg(msg);
88858885 }
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)) {
88878887 const msg = msg: {
88888888 const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{
88898889 return_type.fmt(sema.mod), @tagName(cc_resolved),
......@@ -8961,13 +8961,9 @@ fn funcCommon(
89618961 .x86_64 => null,
89628962 else => @as([]const u8, "x86_64"),
89638963 },
8964 .PtxKernel => switch (arch) {
8965 .nvptx, .nvptx64 => null,
8966 else => @as([]const u8, "nvptx and nvptx64"),
8967 },
8968 .AmdgpuKernel => switch (arch) {
8969 .amdgcn => null,
8970 else => @as([]const u8, "amdgcn"),
8964 .Kernel => switch (arch) {
8965 .nvptx, .nvptx64, .amdgcn, .spirv32, .spirv64 => null,
8966 else => @as([]const u8, "nvptx, amdgcn and SPIR-V"),
89718967 },
89728968 }) |allowed_platform| {
89738969 return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{
......@@ -9093,10 +9089,11 @@ fn analyzeParameter(
90939089 comptime_params[i] = param.is_comptime or requires_comptime;
90949090 const this_generic = param.ty.tag() == .generic_poison;
90959091 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)) {
90979094 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
90989095 }
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)) {
91009097 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
91019098 }
91029099 if (!param.ty.isValidParamType()) {
......@@ -9112,7 +9109,7 @@ fn analyzeParameter(
91129109 };
91139110 return sema.failWithOwnedErrorMsg(msg);
91149111 }
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)) {
91169113 const msg = msg: {
91179114 const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
91189115 param.ty.fmt(sema.mod), @tagName(cc),
......@@ -22786,12 +22783,13 @@ fn validateExternType(
2278622783 },
2278722784 .Fn => {
2278822785 if (position != .other) return false;
22789 return switch (ty.fnCallingConvention()) {
22790 // 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.
22792 .PtxKernel => true,
22793 else => !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()),
22794 };
22786 const target = sema.mod.getTarget();
22787 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
22788 // The goal is to experiment with more integrated CPU/GPU code.
22789 if (ty.fnCallingConvention() == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) {
22790 return true;
22791 }
22792 return !Type.fnCallingConventionAllowsZigTypes(target, ty.fnCallingConvention());
2279522793 },
2279622794 .Enum => {
2279722795 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
1035010350 .Signal => .AVR_SIGNAL,
1035110351 .SysV => .X86_64_SysV,
1035210352 .Win64 => .Win64,
10353 .PtxKernel => return switch (target.cpu.arch) {
10353 .Kernel => return switch (target.cpu.arch) {
1035410354 .nvptx, .nvptx64 => .PTX_Kernel,
10355 else => unreachable,
10356 },
10357 .AmdgpuKernel => return switch (target.cpu.arch) {
1035810355 .amdgcn => .AMDGPU_KERNEL,
1035910356 else => unreachable,
1036010357 },
src/link/NvPtx.zig+1-1
......@@ -1,7 +1,7 @@
11//! NVidia PTX (Paralle Thread Execution)
22//! https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
33//! 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
66const NvPtx = @This();
77
src/type.zig+5-2
......@@ -4796,9 +4796,12 @@ pub const Type = extern union {
47964796 }
47974797
47984798 /// 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 {
48004800 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,
48024805 else => false,
48034806 };
48044807 }
test/nvptx.zig+4-4
......@@ -10,7 +10,7 @@ pub fn addCases(ctx: *Cases) !void {
1010 \\ return a + b;
1111 \\}
1212 \\
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 {
1414 \\ const x = add(a, 7);
1515 \\ var y = add(2, 0);
1616 \\ y -= x;
......@@ -29,7 +29,7 @@ pub fn addCases(ctx: *Cases) !void {
2929 \\ );
3030 \\}
3131 \\
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 {
3333 \\ const i = threadIdX();
3434 \\ out[i] = a[i] + 7;
3535 \\}
......@@ -42,7 +42,7 @@ pub fn addCases(ctx: *Cases) !void {
4242 case.addCompile(
4343 \\var x: i32 addrspace(.global) = 0;
4444 \\
45 \\pub export fn increment(out: *i32) callconv(.PtxKernel) void {
45 \\pub export fn increment(out: *i32) callconv(.Kernel) void {
4646 \\ x += 1;
4747 \\ out.* = x;
4848 \\}
......@@ -59,7 +59,7 @@ pub fn addCases(ctx: *Cases) !void {
5959 \\}
6060 \\
6161 \\ 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 {
6363 \\ var sdata = @addrSpaceCast(.generic, &_sdata);
6464 \\ const tid: u32 = threadIdX();
6565 \\ var sum = d_x[tid];