Skip to content

Commit 12d6901

Browse files
authored
[SYCL][SPIR-V] Make clang lookup for SPIR-V builtins (#1345)
* [SPIR-V] Make the OpenCL Builtin lookup agnostic to programming models Rename the OpenCL Builtin lookup system to make it agnostic. The Builtin emitter is now outputting the builtin information into a class so that different programming models can be produced and used. * [SPIR-V] Enable SPIR-V builtin lookup Add flag -fdeclare-spirv-builtins to enable lookup of SPIR-V builtins. If -fdeclare-spirv-builtins is passed to clang, the compiler will try to lookup for the builtin described in SPIRVBuiltins.td for any match. If a match is found, overloads are build for the match. This will enforce a stable way to express SPIR-V builtins and make them closer to how the translator mangles them. This will help ensuring builtin for CUDA does not break easily. This will also support any changes suggested by the SPIRV-LLVM people on how to represent builtins. Signed-off-by: Victor Lomuller <victor@codeplay.com>
1 parent ade5218 commit 12d6901

15 files changed

+586
-134
lines changed

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ LANGOPT(SYCLAllowFuncPtr , 1, 0, "Allow function pointers in SYCL device code")
237237
LANGOPT(SYCLStdLayoutKernelParams, 1, 0, "Enable standard layout requirement for SYCL kernel parameters")
238238
LANGOPT(SYCLUnnamedLambda , 1, 0, "Allow unnamed lambda SYCL kernels")
239239
LANGOPT(SYCLVersion , 32, 0, "Version of the SYCL standard used")
240+
LANGOPT(DeclareSPIRVBuiltins, 1, 0, "Declare SPIR-V builtin functions")
240241

241242
LANGOPT(HIPUseNewLaunchAPI, 1, 0, "Use new kernel launching API for HIP")
242243

clang/include/clang/Driver/CC1Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,8 @@ def finclude_default_header : Flag<["-"], "finclude-default-header">,
807807
HelpText<"Include default header file for OpenCL">;
808808
def fdeclare_opencl_builtins : Flag<["-"], "fdeclare-opencl-builtins">,
809809
HelpText<"Add OpenCL builtin function declarations (experimental)">;
810+
def fdeclare_spirv_builtins : Flag<["-"], "fdeclare-spirv-builtins">,
811+
HelpText<"Add SPIR-V builtin function declarations (experimental)">;
810812
def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">,
811813
HelpText<"Preserve 3-component vector type">;
812814
def fwchar_type_EQ : Joined<["-"], "fwchar-type=">,

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2577,6 +2577,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
25772577

25782578
Opts.IncludeDefaultHeader = Args.hasArg(OPT_finclude_default_header);
25792579
Opts.DeclareOpenCLBuiltins = Args.hasArg(OPT_fdeclare_opencl_builtins);
2580+
Opts.DeclareSPIRVBuiltins = Args.hasArg(OPT_fdeclare_spirv_builtins);
25802581

25812582
llvm::Triple T(TargetOpts.Triple);
25822583
CompilerInvocation::setLangDefaults(Opts, IK, T, PPOpts, LangStd);

clang/lib/Sema/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ clang_tablegen(OpenCLBuiltins.inc -gen-clang-opencl-builtins
1717
TARGET ClangOpenCLBuiltinsImpl
1818
)
1919

20+
clang_tablegen(SPIRVBuiltins.inc -gen-clang-spirv-builtins
21+
SOURCE SPIRVBuiltins.td
22+
TARGET ClangSPIRVBuiltinsImpl
23+
)
24+
2025
add_clang_library(clangSema
2126
AnalysisBasedWarnings.cpp
2227
CodeCompleteConsumer.cpp
@@ -72,6 +77,7 @@ add_clang_library(clangSema
7277

7378
DEPENDS
7479
ClangOpenCLBuiltinsImpl
80+
ClangSPIRVBuiltinsImpl
7581

7682
LINK_LIBS
7783
clangAST

clang/lib/Sema/OpenCLBuiltins.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ class Builtin<string _Name, list<Type> _Signature, list<bit> _Attributes = Attr.
234234
bit IsConst = _Attributes[1];
235235
// Function attribute __attribute__((convergent))
236236
bit IsConv = _Attributes[2];
237+
// Is function a variadic one
238+
bit IsVariadic = 0;
237239
// OpenCL extensions to which the function belongs.
238240
FunctionExtension Extension = FuncExtNone;
239241
// Version of OpenCL from which the function is available (e.g.: CL10).

clang/lib/Sema/SPIRVBuiltins.td

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
//==--- SPIRVBuiltins.td - SPIRV builtin declarations -------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6+
// See https://llvm.org/LICENSE.txt for license information.
7+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8+
//
9+
//===----------------------------------------------------------------------===//
10+
//
11+
// This file contains TableGen definitions for SPIR-V builtin function
12+
// declarations. In case of an unresolved function name, Clang will check for
13+
// a function described in this file when -fdeclare-spirv-builtins is specified.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
//===----------------------------------------------------------------------===//
18+
// Definitions of miscellaneous basic entities.
19+
//===----------------------------------------------------------------------===//
20+
// TODO: basic entities declaration with OpenCLBuiltins.td
21+
22+
// TODO: Manage version using the JSON grammar. Unused for now.
23+
class Version<int _Version> {
24+
int ID = _Version;
25+
}
26+
def SPIRVAll : Version< 0>;
27+
28+
// Address spaces
29+
// Pointer types need to be assigned an address space.
30+
class AddressSpace<string _AS> {
31+
string Name = _AS;
32+
}
33+
def DefaultAS : AddressSpace<"clang::LangAS::Default">;
34+
def PrivateAS : AddressSpace<"clang::LangAS::sycl_private">;
35+
def GlobalAS : AddressSpace<"clang::LangAS::sycl_global">;
36+
def ConstantAS : AddressSpace<"clang::LangAS::sycl_constant">;
37+
def LocalAS : AddressSpace<"clang::LangAS::sycl_local">;
38+
def GenericAS : AddressSpace<"clang::LangAS::sycl_generic">;
39+
40+
// TODO: Manage capabilities. Unused for now.
41+
class AbstractExtension<string _Ext> {
42+
string ExtName = _Ext;
43+
}
44+
45+
// Extension associated to a builtin function.
46+
class FunctionExtension<string _Ext> : AbstractExtension<_Ext>;
47+
48+
// FunctionExtension definitions.
49+
def FuncExtNone : FunctionExtension<"">;
50+
51+
// Qualified Type. These map to ASTContext::QualType.
52+
class QualType<string _Name, bit _IsAbstract=0, bit _IsSigned=0> {
53+
// Name of the field or function in a clang::ASTContext
54+
// E.g. Name="IntTy" for the int type, and "getIntPtrType()" for an intptr_t
55+
string Name = _Name;
56+
// Some QualTypes in this file represent an abstract type for which there is
57+
// no corresponding AST QualType, e.g. a GenType or an `image2d_t` type
58+
// without access qualifiers.
59+
bit IsAbstract = _IsAbstract;
60+
bit IsSigned = _IsSigned;
61+
}
62+
63+
// List of integers.
64+
class IntList<string _Name, list<int> _List> {
65+
string Name = _Name;
66+
list<int> List = _List;
67+
}
68+
69+
// Basic data types (int, float, image2d_t, ...).
70+
// Its child classes can represent concrete types (e.g. VectorType) or
71+
// abstract types (e.g. GenType).
72+
class Type<string _Name, QualType _QTName> {
73+
// Name of the Type.
74+
string Name = _Name;
75+
// QualType associated with this type.
76+
QualType QTName = _QTName;
77+
// Size of the vector (if applicable).
78+
int VecWidth = 1;
79+
// Size of the element in bits.
80+
int ElementSize = 1;
81+
// Is a integer.
82+
bit IsInteger = 0;
83+
// Is a signed integer.
84+
bit IsSigned = 1;
85+
// Is a float.
86+
bit IsFloat = 0;
87+
// Is a pointer.
88+
bit IsPointer = 0;
89+
// "const" qualifier.
90+
bit IsConst = 0;
91+
// "volatile" qualifier.
92+
bit IsVolatile = 0;
93+
// Access qualifier. Must be one of ("RO", "WO", "RW").
94+
string AccessQualifier = "";
95+
// Address space.
96+
string AddrSpace = DefaultAS.Name;
97+
}
98+
99+
class FundamentalType<string _Name, QualType _QTName, int _Size> : Type<_Name, _QTName> {
100+
// Inherited fields
101+
let ElementSize = _Size;
102+
}
103+
104+
// Integer Type.
105+
class IntType<string _Name, QualType _QTName, int _Size> : FundamentalType<_Name, _QTName, _Size> {
106+
// Inherited fields
107+
let IsInteger = 1;
108+
let IsSigned = 1;
109+
}
110+
111+
// Unsigned integer Type.
112+
class UIntType<string _Name, QualType _QTName, int _Size> : FundamentalType<_Name, _QTName, _Size> {
113+
// Inherited fields
114+
let IsInteger = 1;
115+
let IsSigned = 0;
116+
}
117+
118+
// Floating Type.
119+
class FPType<string _Name, QualType _QTName, int _Size> : FundamentalType<_Name, _QTName, _Size> {
120+
// Inherited fields
121+
let IsFloat = 1;
122+
}
123+
124+
class CompoundType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> {
125+
// Inherited fields
126+
let VecWidth = _Ty.VecWidth;
127+
let ElementSize = _Ty.ElementSize;
128+
let IsInteger = _Ty.IsInteger;
129+
let IsSigned = _Ty.IsSigned;
130+
let IsFloat = _Ty.IsFloat;
131+
let IsPointer = _Ty.IsPointer;
132+
let IsConst = _Ty.IsConst;
133+
let IsVolatile = _Ty.IsVolatile;
134+
let AccessQualifier = _Ty.AccessQualifier;
135+
let AddrSpace = _Ty.AddrSpace;
136+
137+
Type ElementType = _Ty;
138+
}
139+
140+
// Vector types (e.g. int2, int3, int16, float8, ...).
141+
class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> {
142+
let VecWidth = _VecWidth;
143+
let AccessQualifier = "";
144+
// Inherited fields
145+
let ElementSize = _Ty.ElementSize;
146+
let IsInteger = _Ty.IsInteger;
147+
let IsSigned = _Ty.IsSigned;
148+
let IsFloat = _Ty.IsFloat;
149+
let IsPointer = _Ty.IsPointer;
150+
let IsConst = _Ty.IsConst;
151+
let IsVolatile = _Ty.IsVolatile;
152+
let AccessQualifier = _Ty.AccessQualifier;
153+
let AddrSpace = _Ty.AddrSpace;
154+
}
155+
156+
// Pointer types (e.g. int*, float*, ...).
157+
class PointerType<Type _Ty, AddressSpace _AS = DefaultAS> :
158+
CompoundType<_Ty> {
159+
// Inherited fields
160+
let IsPointer = 1;
161+
let AddrSpace = _AS.Name;
162+
}
163+
164+
// Const types (e.g. const int).
165+
class ConstType<Type _Ty> : CompoundType<_Ty> {
166+
// Inherited fields
167+
let IsConst = 1;
168+
}
169+
170+
// Volatile types (e.g. volatile int).
171+
class VolatileType<Type _Ty> : CompoundType<_Ty> {
172+
// Inherited fields
173+
let IsVolatile = 1;
174+
}
175+
176+
// Image types (e.g. image2d).
177+
class ImageType<Type _Ty, string _AccessQualifier> :
178+
Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> {
179+
let VecWidth = 0;
180+
let AccessQualifier = _AccessQualifier;
181+
// Inherited fields
182+
let ElementSize = _Ty.ElementSize;
183+
let IsInteger = _Ty.IsInteger;
184+
let IsSigned = _Ty.IsSigned;
185+
let IsFloat = _Ty.IsFloat;
186+
let IsPointer = _Ty.IsPointer;
187+
let IsConst = _Ty.IsConst;
188+
let IsVolatile = _Ty.IsVolatile;
189+
let AddrSpace = _Ty.AddrSpace;
190+
}
191+
192+
// List of Types.
193+
class TypeList<list<Type> _Type> {
194+
list<Type> List = _Type;
195+
}
196+
197+
// A GenericType is an abstract type that defines a set of types as a
198+
// combination of Types and vector sizes.
199+
//
200+
// For example, if TypeList = <int, float> and VectorList = <1, 2, 4>, then it
201+
// represents <int, int2, int4, float, float2, float4>.
202+
//
203+
// Some rules apply when using multiple GenericType arguments in a declaration:
204+
// 1. The number of vector sizes must be equal or 1 for all gentypes in a
205+
// declaration.
206+
// 2. The number of Types must be equal or 1 for all gentypes in a
207+
// declaration.
208+
// 3. Generic types are combined by iterating over all generic types at once.
209+
// For example, for the following GenericTypes
210+
// GenT1 = GenericType<half, [1, 2]> and
211+
// GenT2 = GenericType<float, int, [1, 2]>
212+
// A declaration f(GenT1, GenT2) results in the combinations
213+
// f(half, float), f(half2, float2), f(half, int), f(half2, int2) .
214+
// 4. "sgentype" from the OpenCL specification is supported by specifying
215+
// a single vector size.
216+
// For example, for the following GenericTypes
217+
// GenT = GenericType<half, int, [1, 2]> and
218+
// SGenT = GenericType<half, int, [1]>
219+
// A declaration f(GenT, SGenT) results in the combinations
220+
// f(half, half), f(half2, half), f(int, int), f(int2, int) .
221+
class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> :
222+
Type<_Ty, QualType<"null", 1>> {
223+
// Possible element types of the generic type.
224+
TypeList TypeList = _TypeList;
225+
// Possible vector sizes of the types in the TypeList.
226+
IntList VectorList = _VectorList;
227+
// The VecWidth field is ignored for GenericTypes. Use VectorList instead.
228+
let VecWidth = 0;
229+
}
230+
231+
// Builtin function attributes.
232+
def Attr {
233+
list<bit> None = [0, 0, 0];
234+
list<bit> Pure = [1, 0, 0];
235+
list<bit> Const = [0, 1, 0];
236+
list<bit> Convergent = [0, 0, 1];
237+
}
238+
239+
//===----------------------------------------------------------------------===//
240+
// Class for builtin functions
241+
//===----------------------------------------------------------------------===//
242+
class Builtin<string _Name, list<Type> _Signature, list<bit> _Attributes = Attr.None> {
243+
// Name of the builtin function
244+
string Name = _Name;
245+
// List of types used by the function. The first one is the return type and
246+
// the following are the arguments. The list must have at least one element
247+
// (the return type).
248+
list<Type> Signature = _Signature;
249+
// Function attribute __attribute__((pure))
250+
bit IsPure = _Attributes[0];
251+
// Function attribute __attribute__((const))
252+
bit IsConst = _Attributes[1];
253+
// Function attribute __attribute__((convergent))
254+
bit IsConv = _Attributes[2];
255+
// Is function a variadic one
256+
bit IsVariadic = 0;
257+
// OpenCL extensions to which the function belongs.
258+
FunctionExtension Extension = FuncExtNone;
259+
// Version from which the function is available.
260+
// MinVersion is inclusive.
261+
Version MinVersion = SPIRVAll;
262+
// Version from which the function is not supported anymore.
263+
// MaxVersion is exclusive.
264+
// SPIRVAll makes the function available for all versions.
265+
Version MaxVersion = SPIRVAll;
266+
}
267+
268+
// Helper to declare SPIR-V Core builtins.
269+
class SPVBuiltin<string _Name, list<Type> _Signature, list<bit> _Attributes = Attr.None> :
270+
Builtin<"__spirv_" # _Name, _Signature, _Attributes> {}
271+
272+
// Helper to declare OpenCL SPIR-V extended set builtins.
273+
class OCLSPVBuiltin<string _Name, list<Type> _Signature, list<bit> _Attributes = Attr.None> :
274+
SPVBuiltin<"ocl_" # _Name, _Signature, _Attributes> {}
275+
276+
//===----------------------------------------------------------------------===//
277+
// Definitions of types
278+
//===----------------------------------------------------------------------===//
279+
280+
def Float : FPType<"float", QualType<"FloatTy">, 32>;
281+
def Double : FPType<"double", QualType<"DoubleTy">, 64>;
282+
def Half : FPType<"half", QualType<"Float16Ty">, 16>;
283+
284+
//===----------------------------------------------------------------------===//
285+
// Definitions of gentype variants
286+
//===----------------------------------------------------------------------===//
287+
288+
// Vector width lists.
289+
def VecAndScalar: IntList<"VecAndScalar", [1, 2, 3, 4, 8, 16]>;
290+
291+
// Type lists.
292+
def TLFloat : TypeList<[Float, Double, Half]>;
293+
294+
// Float
295+
def FGenTypeN : GenericType<"FGenTypeN", TLFloat, VecAndScalar>;
296+
297+
298+
299+
//===----------------------------------------------------------------------===//
300+
// Definitions of builtins
301+
// extinst.opencl.std.100.grammar.json
302+
//===----------------------------------------------------------------------===//
303+
304+
// 2.1. Math extended instructions
305+
306+
def : OCLSPVBuiltin<"acos", [FGenTypeN, FGenTypeN], Attr.Const>;
307+

0 commit comments

Comments
 (0)