forked from OSchip/llvm-project
[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:
parent
c72a63b4b0
commit
23d65aa446
|
@ -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>;
|
||||
|
|
|
@ -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]>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue