[OpenCL] Support enum and typedef args in TableGen BIFs

Add enum and typedef argument support to `-fdeclare-opencl-builtins`,
which was the last major missing feature.

Adding the remaining missing builtins is left as future work.

Differential Revision: https://reviews.llvm.org/D96051
This commit is contained in:
Sven van Haastregt 2021-02-17 14:17:43 +00:00
parent c72a63b4b0
commit 23d65aa446
5 changed files with 101 additions and 10 deletions

View File

@ -9893,6 +9893,8 @@ def err_opencl_pointer_to_type : Error<
"pointer to type %0 is invalid in OpenCL">;
def err_opencl_type_can_only_be_used_as_function_parameter : Error <
"type %0 can only be used as a function parameter in OpenCL">;
def err_opencl_type_not_found : Error<
"%0 type %1 not found; include the base header with -finclude-default-header">;
def warn_opencl_attr_deprecated_ignored : Warning <
"%0 attribute is deprecated and ignored in OpenCL version %1">,
InGroup<IgnoredAttributes>;

View File

@ -178,6 +178,16 @@ class ImageType<Type _Ty, string _AccessQualifier> :
let AddrSpace = _Ty.AddrSpace;
}
// OpenCL enum type (e.g. memory_scope).
class EnumType<string _Name> :
Type<_Name, QualType<"getOpenCLEnumType(S, \"" # _Name # "\")", 0>> {
}
// OpenCL typedef type (e.g. cl_mem_fence_flags).
class TypedefType<string _Name> :
Type<_Name, QualType<"getOpenCLTypedefType(S, \"" # _Name # "\")", 0>> {
}
// List of Types.
class TypeList<list<Type> _Type> {
list<Type> List = _Type;
@ -299,6 +309,7 @@ def ClkEvent : Type<"clk_event_t", QualType<"Context.OCLClkEventTy"
def Event : Type<"event_t", QualType<"Context.OCLEventTy">>;
def Queue : Type<"queue_t", QualType<"Context.OCLQueueTy">>;
def ReserveId : Type<"reserve_id_t", QualType<"Context.OCLReserveIDTy">>;
def MemFenceFlags : TypedefType<"cl_mem_fence_flags">;
// OpenCL v2.0 s6.13.11: Atomic integer and floating-point types.
def AtomicInt : Type<"atomic_int", QualType<"Context.getAtomicType(Context.IntTy)">>;
@ -312,6 +323,9 @@ def AtomicUIntPtr : Type<"atomic_uintptr_t", QualType<"Context.getAtomic
def AtomicSize : Type<"atomic_size_t", QualType<"Context.getAtomicType(Context.getSizeType())">>;
def AtomicPtrDiff : Type<"atomic_ptrdiff_t", QualType<"Context.getAtomicType(Context.getPointerDiffType())">>;
def MemoryOrder : EnumType<"memory_order">;
def MemoryScope : EnumType<"memory_scope">;
//===----------------------------------------------------------------------===//
// Definitions of OpenCL gentype variants
//===----------------------------------------------------------------------===//
@ -897,6 +911,9 @@ foreach AS = [ConstantAS] in {
}
}
// OpenCL v3.0 s6.15.8 - Synchronization Functions.
def : Builtin<"barrier", [Void, MemFenceFlags], Attr.Convergent>;
//--------------------------------------------------------------------
// OpenCL v1.1 s6.11.10, v1.2 s6.12.10, v2.0 s6.13.10: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
// OpenCL Extension v2.0 s5.1.7 and s6.1.7: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
@ -1028,6 +1045,12 @@ let MinVersion = CL20 in {
def : Builtin<"atomic_compare_exchange_" # Variant,
[Bool, PointerType<VolatileType<TypePair[0]>, GenericAS>,
PointerType<TypePair[1], GenericAS>, TypePair[1]]>;
def : Builtin<"atomic_compare_exchange_" # Variant # "_explicit",
[Bool, PointerType<VolatileType<TypePair[0]>, GenericAS>,
PointerType<TypePair[1], GenericAS>, TypePair[1], MemoryOrder, MemoryOrder]>;
def : Builtin<"atomic_compare_exchange_" # Variant # "_explicit",
[Bool, PointerType<VolatileType<TypePair[0]>, GenericAS>,
PointerType<TypePair[1], GenericAS>, TypePair[1], MemoryOrder, MemoryOrder, MemoryScope]>;
}
}

View File

@ -677,9 +677,43 @@ LLVM_DUMP_METHOD void LookupResult::dump() {
D->dump();
}
/// Diagnose a missing builtin type.
static QualType diagOpenCLBuiltinTypeError(Sema &S, llvm::StringRef TypeClass,
llvm::StringRef Name) {
S.Diag(SourceLocation(), diag::err_opencl_type_not_found)
<< TypeClass << Name;
return S.Context.VoidTy;
}
/// Lookup an OpenCL enum type.
static QualType getOpenCLEnumType(Sema &S, llvm::StringRef Name) {
LookupResult Result(S, &S.Context.Idents.get(Name), SourceLocation(),
Sema::LookupTagName);
S.LookupName(Result, S.TUScope);
if (Result.empty())
return diagOpenCLBuiltinTypeError(S, "enum", Name);
EnumDecl *Decl = Result.getAsSingle<EnumDecl>();
if (!Decl)
return diagOpenCLBuiltinTypeError(S, "enum", Name);
return S.Context.getEnumType(Decl);
}
/// Lookup an OpenCL typedef type.
static QualType getOpenCLTypedefType(Sema &S, llvm::StringRef Name) {
LookupResult Result(S, &S.Context.Idents.get(Name), SourceLocation(),
Sema::LookupOrdinaryName);
S.LookupName(Result, S.TUScope);
if (Result.empty())
return diagOpenCLBuiltinTypeError(S, "typedef", Name);
TypedefNameDecl *Decl = Result.getAsSingle<TypedefNameDecl>();
if (!Decl)
return diagOpenCLBuiltinTypeError(S, "typedef", Name);
return S.Context.getTypedefType(Decl);
}
/// Get the QualType instances of the return type and arguments for an OpenCL
/// builtin function signature.
/// \param Context (in) The Context instance.
/// \param S (in) The Sema instance.
/// \param OpenCLBuiltin (in) The signature currently handled.
/// \param GenTypeMaxCnt (out) Maximum number of types contained in a generic
/// type used as return type or as argument.
@ -689,20 +723,20 @@ LLVM_DUMP_METHOD void LookupResult::dump() {
/// argument, ArgTypes contains QualTypes for the Cartesian product
/// of (vector sizes) x (types) .
static void GetQualTypesForOpenCLBuiltin(
ASTContext &Context, const OpenCLBuiltinStruct &OpenCLBuiltin,
unsigned &GenTypeMaxCnt, SmallVector<QualType, 1> &RetTypes,
Sema &S, const OpenCLBuiltinStruct &OpenCLBuiltin, unsigned &GenTypeMaxCnt,
SmallVector<QualType, 1> &RetTypes,
SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) {
// Get the QualType instances of the return types.
unsigned Sig = SignatureTable[OpenCLBuiltin.SigTableIndex];
OCL2Qual(Context, TypeTable[Sig], RetTypes);
OCL2Qual(S, TypeTable[Sig], RetTypes);
GenTypeMaxCnt = RetTypes.size();
// Get the QualType instances of the arguments.
// First type is the return type, skip it.
for (unsigned Index = 1; Index < OpenCLBuiltin.NumTypes; Index++) {
SmallVector<QualType, 1> Ty;
OCL2Qual(Context,
TypeTable[SignatureTable[OpenCLBuiltin.SigTableIndex + Index]], Ty);
OCL2Qual(S, TypeTable[SignatureTable[OpenCLBuiltin.SigTableIndex + Index]],
Ty);
GenTypeMaxCnt = (Ty.size() > GenTypeMaxCnt) ? Ty.size() : GenTypeMaxCnt;
ArgTypes.push_back(std::move(Ty));
}
@ -789,8 +823,8 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
SmallVector<SmallVector<QualType, 1>, 5> ArgTypes;
// Obtain QualType lists for the function signature.
GetQualTypesForOpenCLBuiltin(Context, OpenCLBuiltin, GenTypeMaxCnt,
RetTypes, ArgTypes);
GetQualTypesForOpenCLBuiltin(S, OpenCLBuiltin, GenTypeMaxCnt, RetTypes,
ArgTypes);
if (GenTypeMaxCnt > 1) {
HasGenType = true;
}

View File

@ -17,6 +17,17 @@
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#endif
// First, test that Clang gracefully handles missing types.
#ifdef NO_HEADER
void test_without_header() {
barrier(0);
// expected-note@-1 0+{{candidate function not viable}}
// expected-error@-2 0+{{argument type 'void' is incomplete}}
// expected-error@-3 0+{{no matching function for call to 'barrier'}}
// expected-error@* {{typedef type cl_mem_fence_flags not found; include the base header with -finclude-default-header}}
}
#endif
// Provide typedefs when invoking clang without -finclude-default-header.
#ifdef NO_HEADER
typedef unsigned char uchar;
@ -34,6 +45,9 @@ typedef int int4 __attribute__((ext_vector_type(4)));
typedef uint uint4 __attribute__((ext_vector_type(4)));
typedef long long2 __attribute__((ext_vector_type(2)));
typedef uint cl_mem_fence_flags;
#define CLK_GLOBAL_MEM_FENCE 0x02
// Enable extensions that are enabled in opencl-c-base.h.
#if (defined(__OPENCL_CPP_VERSION__) || __OPENCL_C_VERSION__ >= 200)
#define cl_khr_subgroup_extended_types 1
@ -53,6 +67,18 @@ kernel void test_pointers(volatile global void *global_p, global const int4 *a)
atom_cmpxchg((volatile __global unsigned int *)global_p, ui, ui);
}
// Only test enum arguments when the base header is included, because we need
// the enum declarations.
#if !defined(NO_HEADER) && (defined(__OPENCL_CPP_VERSION__) || __OPENCL_C_VERSION__ >= 200)
kernel void test_enum_args(volatile global atomic_int *global_p, global int *expected) {
int desired;
atomic_compare_exchange_strong_explicit(global_p, expected, desired,
memory_order_acq_rel,
memory_order_relaxed,
memory_scope_work_group);
}
#endif
kernel void basic_conversion() {
double d;
float f;
@ -184,6 +210,8 @@ kernel void basic_vector_data() {
kernel void basic_work_item() {
uint ui;
barrier(CLK_GLOBAL_MEM_FENCE);
get_enqueued_local_size(ui);
#if !defined(__OPENCL_CPP_VERSION__) && __OPENCL_C_VERSION__ < CL_VERSION_2_0
// expected-error@-2{{implicit declaration of function 'get_enqueued_local_size' is invalid in OpenCL}}

View File

@ -48,7 +48,7 @@
// Find out whether a string matches an existing OpenCL builtin function
// name and return an index into BuiltinTable and the number of overloads.
//
// * void OCL2Qual(ASTContext&, OpenCLTypeStruct, std::vector<QualType>&)
// * void OCL2Qual(Sema&, OpenCLTypeStruct, std::vector<QualType>&)
// Convert an OpenCLTypeStruct type to a list of QualType instances.
// One OpenCLTypeStruct can represent multiple types, primarily when using
// GenTypes.
@ -628,6 +628,9 @@ static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) {
void BuiltinNameEmitter::EmitQualTypeFinder() {
OS << R"(
static QualType getOpenCLEnumType(Sema &S, llvm::StringRef Name);
static QualType getOpenCLTypedefType(Sema &S, llvm::StringRef Name);
// Convert an OpenCLTypeStruct type to a list of QualTypes.
// Generic types represent multiple types and vector sizes, thus a vector
// is returned. The conversion is done in two steps:
@ -636,8 +639,9 @@ void BuiltinNameEmitter::EmitQualTypeFinder() {
// or a single scalar type for non generic types.
// Step 2: Qualifiers and other type properties such as vector size are
// applied.
static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty,
static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty,
llvm::SmallVectorImpl<QualType> &QT) {
ASTContext &Context = S.Context;
// Number of scalar types in the GenType.
unsigned GenTypeNumTypes;
// Pointer to the list of vector sizes for the GenType.