Skip to content

Commit 7f5a28a

Browse files
authored
GPU: Metal branches in the common definition macros (#15772)
Defines the GPUd()/GPUshared()/GPU*ref() family for __METAL__ and __METAL_HOST__, and teaches GPUCommonDef.h about the Metal host and device compilation passes. The Metal backend targets MSL 4.1 and later only. That is what lets GPUdDefault() expand to nothing: up to MSL 4.0 a member function's implicit this is thread, which is wrong for objects living in device memory, and pinning defaulted constructors to device made the same type unusable in thread or threadgroup. MSL 4.1 makes an unannotated this generic, which is the C++ semantics this codebase already assumes. The *ref() macros stay explicit regardless: they are correct from the OpenCL port, explicit is never slower than generic, and constant is not covered by generic pointers at all. Inert unless __METAL__ or __METAL_HOST__ is defined.
1 parent 23fb5bd commit 7f5a28a

2 files changed

Lines changed: 53 additions & 4 deletions

File tree

GPU/Common/GPUCommonDef.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
#include "GPUCommonDefSettings.h"
3232

3333
#if !defined(__CLING__) && !defined(G__ROOT) // No GPU code for ROOT
34-
#if defined(__CUDACC__) || defined(__OPENCL__) || defined(__HIPCC__) || defined(__OPENCL_HOST__)
34+
#if defined(__CUDACC__) || defined(__OPENCL__) || defined(__HIPCC__) || defined(__OPENCL_HOST__) || defined(__METAL_HOST__)
3535
#define GPUCA_GPUCODE // Compiled by GPU compiler
3636
#endif
3737

3838
#if defined(GPUCA_GPUCODE)
39-
#if defined(__CUDA_ARCH__) || defined(__OPENCL__) || defined(__HIP_DEVICE_COMPILE__)
39+
#if defined(__CUDA_ARCH__) || defined(__OPENCL__) || defined(__HIP_DEVICE_COMPILE__) || defined(__METAL_VERSION__)
4040
#define GPUCA_GPUCODE_DEVICE // Executed on device
4141
#endif
4242
#if defined(__CUDACC__)
@@ -45,6 +45,8 @@
4545
#define GPUCA_GPUTYPE HIP
4646
#elif defined(__OPENCL__) || defined(__OPENCL_HOST__)
4747
#define GPUCA_GPUTYPE OCL
48+
#elif defined(__METAL__) || defined(__METAL_HOST__)
49+
#define GPUCA_GPUTYPE METAL
4850
#endif
4951
#endif
5052
#endif

GPU/Common/GPUCommonDefAPI.h

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
//Define macros for GPU keywords. i-version defines inline functions.
2828
//All host-functions in GPU code are automatically inlined, to avoid duplicate symbols.
2929
//For non-inline host only functions, use no keyword at all!
30-
#if !defined(GPUCA_GPUCODE) || defined(__OPENCL_HOST__) // For host / ROOT dictionary
30+
#if !defined(GPUCA_GPUCODE) || defined(__OPENCL_HOST__) || defined(__METAL_HOST__) // For host / ROOT dictionary
3131
#define GPUd() // device function
3232
#define GPUdDefault() // default (constructor / operator) device function
3333
#define GPUhdDefault() // default (constructor / operator) host device function
@@ -124,6 +124,53 @@
124124
#if (!defined(__OPENCL__) || !defined(GPUCA_NO_CONSTANT_MEMORY))
125125
#define GPUconstantref() GPUconstant()
126126
#endif
127+
#elif defined(__METAL__) //Defines for Metal Shading Language
128+
// ADDRESS SPACES. This backend targets MSL 4.1 (macOS 27) and later only --
129+
// see -std=metal4.1 in the CMakeLists, which fails the build on anything
130+
// older rather than miscompiling quietly.
131+
//
132+
// That version is what makes the port tractable: up to MSL 4.0 a member
133+
// function's implicit `this` is `thread`, which is wrong for us, since most
134+
// objects the kernels touch live in `device` memory. Pinning defaulted
135+
// constructors and operators to `device` was the 4.0 workaround, and it made
136+
// the same type unusable in `thread` or `threadgroup`. In 4.1 an unannotated
137+
// `this` is GENERIC and resolves to whichever address space the object is in
138+
// -- the C++ semantics this codebase already assumes -- so GPUdDefault()
139+
// needs nothing at all. The compiler resolves it statically in almost every
140+
// case; it only falls back to a runtime branch where it cannot see through,
141+
// such as argument buffers or dynamic libraries.
142+
//
143+
// The *ref() macros below stay explicit even so. They are already correct
144+
// from the OpenCL port, an explicit annotation is never slower than a generic
145+
// one, and `constant` is not covered by generic pointers at all.
146+
#define GPUdDefault() // generic `this` (MSL 4.1+)
147+
#define GPUd()
148+
#define GPUhdDefault()
149+
#define GPUdi() inline
150+
#define GPUdii() inline
151+
#define GPUdni()
152+
#define GPUdnii()
153+
#define GPUh() inline
154+
#define GPUhi() inline
155+
#define GPUhd() inline
156+
#define GPUhdi() inline
157+
#define GPUhdni()
158+
#define GPUg() kernel
159+
#define GPUshared() threadgroup
160+
#define GPUglobal() device
161+
#define GPUconstant() constant // TODO: possibly add const __restrict where possible later!
162+
#define GPUconstexpr() constant
163+
#define GPUprivate() thread
164+
#define GPUgeneric()
165+
#define GPUglobalref() device
166+
#define GPUsharedref() threadgroup
167+
#define GPUprivateref() thread
168+
#define GPUconstantref() constant
169+
#define GPUconstexprref() GPUconstexpr()
170+
#define GPUdouble() float
171+
#define GPUbarrier() threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup)
172+
#define GPUbarrierWarp() simdgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup)
173+
#define GPUAtomic(type) atomic<type> // atomic variable type
127174
#elif defined(__HIPCC__) //Defines for HIP
128175
#define GPUd() __device__
129176
#define GPUdDefault() __device__
@@ -230,5 +277,5 @@
230277
#define get_group_id(dim) iBlock
231278
#endif
232279

233-
// clang-format on
280+
// clang-format on
234281
#endif

0 commit comments

Comments
 (0)