From cc0ba28cf07fd696148d70eb454fbaeb9c0b30c2 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Tue, 20 Aug 2019 12:21:03 +0000 Subject: [PATCH] [OpenCL] Add const, volatile and pointer builtin handling Const, volatile, and pointer types were previously available, but not working. This patch adds handling for OpenCL builtin functions. Add TableGen definitions for some atomic and asynchronous builtins to make use of the new functionality. Patch by Pierre Gondois and Sven van Haastregt. Differential Revision: https://reviews.llvm.org/D63442 llvm-svn: 369373 --- clang/lib/Sema/OpenCLBuiltins.td | 98 ++++++++++++++++--- .../SemaOpenCL/fdeclare-opencl-builtins.cl | 10 ++ .../TableGen/ClangOpenCLBuiltinEmitter.cpp | 38 ++++++- 3 files changed, 131 insertions(+), 15 deletions(-) diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td index c99d5073ef25..ed925ce2fa4b 100644 --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -51,11 +51,6 @@ class QualType { bit IsAbstract = _IsAbstract; } -// Helper class to store type access qualifiers (volatile, const, ...). -class Qualifier { - string QualName = _QualName; -} - // List of integers. class IntList _List> { string Name = _Name; @@ -79,24 +74,59 @@ class Type { int VecWidth = 1; // Is a pointer. bit IsPointer = 0; - // List of qualifiers associated with the type (volatile, ...) - list QualList = []; + // "const" qualifier. + bit IsConst = 0; + // "volatile" qualifier. + bit IsVolatile = 0; // Access qualifier. Must be one of ("RO", "WO", "RW"). string AccessQualifier = ""; // Address space. - string AddrSpace = "clang::LangAS::Default"; + string AddrSpace = DefaultAS.Name; } -// OpenCL vector types (e.g. int2, int3, int16, float8, ...) +// OpenCL vector types (e.g. int2, int3, int16, float8, ...). class VectorType : Type<_Ty.Name, _Ty.QTName> { - int VecWidth = _VecWidth; + let VecWidth = _VecWidth; + // Inherited fields + let IsPointer = _Ty.IsPointer; + let IsConst = _Ty.IsConst; + let IsVolatile = _Ty.IsVolatile; + let AccessQualifier = _Ty.AccessQualifier; + let AddrSpace = _Ty.AddrSpace; } // OpenCL pointer types (e.g. int*, float*, ...). -class PointerType : +class PointerType : Type<_Ty.Name, _Ty.QTName> { - bit IsPointer = 1; - string AddrSpace = _AS.Name; + let AddrSpace = _AS.Name; + // Inherited fields + let VecWidth = _Ty.VecWidth; + let IsPointer = 1; + let IsConst = _Ty.IsConst; + let IsVolatile = _Ty.IsVolatile; + let AccessQualifier = _Ty.AccessQualifier; +} + +// OpenCL const types (e.g. const int). +class ConstType : Type<_Ty.Name, _Ty.QTName> { + let IsConst = 1; + // Inherited fields + let VecWidth = _Ty.VecWidth; + let IsPointer = _Ty.IsPointer; + let IsVolatile = _Ty.IsVolatile; + let AccessQualifier = _Ty.AccessQualifier; + let AddrSpace = _Ty.AddrSpace; +} + +// OpenCL volatile types (e.g. volatile int). +class VolatileType : Type<_Ty.Name, _Ty.QTName> { + let IsVolatile = 1; + // Inherited fields + let VecWidth = _Ty.VecWidth; + let IsPointer = _Ty.IsPointer; + let IsConst = _Ty.IsConst; + let AccessQualifier = _Ty.AccessQualifier; + let AddrSpace = _Ty.AddrSpace; } // OpenCL image types (e.g. image2d_t, ...) @@ -242,12 +272,16 @@ def VecNoScalar : IntList<"VecNoScalar", [2, 3, 4, 8, 16]>; def Vec1 : IntList<"Vec1", [1]>; // Type lists. +def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>; def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>; def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>; // GenType definitions for multiple base types (e.g. all floating point types, // or all integer types). +// All types +def AGenTypeN : GenericType<"AGenTypeN", TLAll, VecAndScalar>; +def AGenTypeNNoScalar : GenericType<"AGenTypeNNoScalar", TLAll, VecNoScalar>; // All integer def AIGenType1 : GenericType<"AIGenType1", TLAllInts, Vec1>; def AIGenTypeN : GenericType<"AIGenTypeN", TLAllInts, VecAndScalar>; @@ -294,6 +328,44 @@ foreach RType = [Float, Double, Half, Char, UChar, Short, } } +//-------------------------------------------------------------------- +// 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 +// --- Table 18 --- +foreach name = ["async_work_group_copy"] in { + def : Builtin, PointerType, GlobalAS>, Size, Event]>; + def : Builtin, PointerType, LocalAS>, Size, Event]>; +} +foreach name = ["async_work_group_strided_copy"] in { + def : Builtin, PointerType, GlobalAS>, Size, Size, Event]>; + def : Builtin, PointerType, LocalAS>, Size, Size, Event]>; +} +foreach name = ["wait_group_events"] in { + def : Builtin]>; +} +foreach name = ["prefetch"] in { + def : Builtin, GlobalAS>, Size]>; +} + +//-------------------------------------------------------------------- +// OpenCL v2.0 s6.13.11 - Atomics Functions. +// Functions that use memory_order and cl_mem_fence_flags enums are not +// declared here as the TableGen backend does not handle enums. + +// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers. +// --- Table 9.1 --- +foreach Type = [Int, UInt] in { + foreach name = ["atom_add", "atom_sub", "atom_xchg"] in { + def : Builtin, GlobalAS>, Type]>; + } + foreach name = ["atom_inc", "atom_dec"] in { + def : Builtin, GlobalAS>]>; + } + foreach name = ["atom_cmpxchg"] in { + def : Builtin, GlobalAS>, Type, Type]>; + } +} + // OpenCL v1.2 s6.12.1: Work-Item Functions def get_work_dim : Builtin<"get_work_dim", [UInt]>; foreach name = ["get_global_size", "get_global_id", "get_local_size", diff --git a/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl b/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl index 66afb630d7d7..13266bc7a058 100644 --- a/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl +++ b/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl @@ -16,6 +16,16 @@ typedef unsigned int uint; typedef __SIZE_TYPE__ size_t; #endif +kernel void test_pointers(volatile global void *global_p, global const int4 *a) { + int i; + unsigned int ui; + + prefetch(a, 2); + + atom_add((volatile __global int *)global_p, i); + atom_cmpxchg((volatile __global unsigned int *)global_p, ui, ui); +} + kernel void basic_conversion() { double d; float f; diff --git a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp index 89ba5e0d9739..4bf59c3a9231 100644 --- a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -236,10 +236,18 @@ void BuiltinNameEmitter::EmitDeclarations() { // Represents a return type or argument type. struct OpenCLTypeStruct { - // A type (e.g. float, int, ...) + // A type (e.g. float, int, ...). const OpenCLTypeID ID; // Vector size (if applicable; 0 for scalars and generic types). const unsigned VectorWidth; + // 0 if the type is not a pointer. + const bool IsPointer; + // 0 if the type is not const. + const bool IsConst; + // 0 if the type is not volatile. + const bool IsVolatile; + // Address space of the pointer (if applicable). + const LangAS AS; }; // One overload of an OpenCL builtin function. @@ -341,7 +349,11 @@ void BuiltinNameEmitter::EmitTypeTable() { for (const auto &T : TypeMap) { OS << " // " << T.second << "\n"; OS << " {OCLT_" << T.first->getValueAsString("Name") << ", " - << T.first->getValueAsInt("VecWidth") << "},\n"; + << T.first->getValueAsInt("VecWidth") << ", " + << T.first->getValueAsBit("IsPointer") << ", " + << T.first->getValueAsBit("IsConst") << ", " + << T.first->getValueAsBit("IsVolatile") << ", " + << T.first->getValueAsString("AddrSpace") << "},\n"; } OS << "};\n\n"; } @@ -525,6 +537,28 @@ static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty, QT[Index] = Context.getExtVectorType(QT[Index], Ty.VectorWidth); } } + + if (Ty.IsVolatile != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getVolatileType(QT[Index]); + } + } + + if (Ty.IsConst != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getConstType(QT[Index]); + } + } + + // Transform the type to a pointer as the last step, if necessary. + // Builtin functions only have pointers on [const|volatile], no + // [const|volatile] pointers, so this is ok to do it as a last step. + if (Ty.IsPointer != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getAddrSpaceQualType(QT[Index], Ty.AS); + QT[Index] = Context.getPointerType(QT[Index]); + } + } )"; // End of the "OCL2Qual" function.