@@ -228,6 +228,64 @@ class BuiltinNameEmitter {
228
228
// same entry (<I1, I2, I3>).
229
229
MapVector<BuiltinIndexListTy *, BuiltinTableEntries> SignatureListMap;
230
230
};
231
+
232
+ // OpenCL builtin test generator. This class processes the same TableGen input
233
+ // as BuiltinNameEmitter, but generates a .cl file that contains a call to each
234
+ // builtin function described in the .td input.
235
+ class OpenCLBuiltinTestEmitter {
236
+ public:
237
+ OpenCLBuiltinTestEmitter (RecordKeeper &Records, raw_ostream &OS)
238
+ : Records(Records), OS(OS) {}
239
+
240
+ // Entrypoint to generate the functions for testing all OpenCL builtin
241
+ // functions.
242
+ void emit ();
243
+
244
+ private:
245
+ struct TypeFlags {
246
+ TypeFlags () : IsConst(false ), IsVolatile(false ), IsPointer(false ) {}
247
+ bool IsConst : 1 ;
248
+ bool IsVolatile : 1 ;
249
+ bool IsPointer : 1 ;
250
+ StringRef AddrSpace;
251
+ };
252
+
253
+ // Return a string representation of the given type, such that it can be
254
+ // used as a type in OpenCL C code.
255
+ std::string getTypeString (const Record *Type, TypeFlags Flags,
256
+ int VectorSize) const ;
257
+
258
+ // Return the type(s) and vector size(s) for the given type. For
259
+ // non-GenericTypes, the resulting vectors will contain 1 element. For
260
+ // GenericTypes, the resulting vectors typically contain multiple elements.
261
+ void getTypeLists (Record *Type, TypeFlags &Flags,
262
+ std::vector<Record *> &TypeList,
263
+ std::vector<int64_t > &VectorList) const ;
264
+
265
+ // Expand the TableGen Records representing a builtin function signature into
266
+ // one or more function signatures. Return them as a vector of a vector of
267
+ // strings, with each string containing an OpenCL C type and optional
268
+ // qualifiers.
269
+ //
270
+ // The Records may contain GenericTypes, which expand into multiple
271
+ // signatures. Repeated occurrences of GenericType in a signature expand to
272
+ // the same types. For example [char, FGenType, FGenType] expands to:
273
+ // [char, float, float]
274
+ // [char, float2, float2]
275
+ // [char, float3, float3]
276
+ // ...
277
+ void
278
+ expandTypesInSignature (const std::vector<Record *> &Signature,
279
+ SmallVectorImpl<SmallVector<std::string, 2 >> &Types);
280
+
281
+ // Contains OpenCL builtin functions and related information, stored as
282
+ // Record instances. They are coming from the associated TableGen file.
283
+ RecordKeeper &Records;
284
+
285
+ // The output file.
286
+ raw_ostream &OS;
287
+ };
288
+
231
289
} // namespace
232
290
233
291
void BuiltinNameEmitter::Emit () {
@@ -861,7 +919,230 @@ static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty,
861
919
OS << " \n } // OCL2Qual\n " ;
862
920
}
863
921
922
+ std::string OpenCLBuiltinTestEmitter::getTypeString (const Record *Type,
923
+ TypeFlags Flags,
924
+ int VectorSize) const {
925
+ std::string S;
926
+ if (Type->getValueAsBit (" IsConst" ) || Flags.IsConst ) {
927
+ S += " const " ;
928
+ }
929
+ if (Type->getValueAsBit (" IsVolatile" ) || Flags.IsVolatile ) {
930
+ S += " volatile " ;
931
+ }
932
+
933
+ auto PrintAddrSpace = [&S](StringRef AddrSpace) {
934
+ S += StringSwitch<const char *>(AddrSpace)
935
+ .Case (" clang::LangAS::opencl_private" , " __private" )
936
+ .Case (" clang::LangAS::opencl_global" , " __global" )
937
+ .Case (" clang::LangAS::opencl_constant" , " __constant" )
938
+ .Case (" clang::LangAS::opencl_local" , " __local" )
939
+ .Case (" clang::LangAS::opencl_generic" , " __generic" )
940
+ .Default (" __private" );
941
+ S += " " ;
942
+ };
943
+ if (Flags.IsPointer ) {
944
+ PrintAddrSpace (Flags.AddrSpace );
945
+ } else if (Type->getValueAsBit (" IsPointer" )) {
946
+ PrintAddrSpace (Type->getValueAsString (" AddrSpace" ));
947
+ }
948
+
949
+ StringRef Acc = Type->getValueAsString (" AccessQualifier" );
950
+ if (Acc != " " ) {
951
+ S += StringSwitch<const char *>(Acc)
952
+ .Case (" RO" , " __read_only " )
953
+ .Case (" WO" , " __write_only " )
954
+ .Case (" RW" , " __read_write " );
955
+ }
956
+
957
+ S += Type->getValueAsString (" Name" ).str ();
958
+ if (VectorSize > 1 ) {
959
+ S += std::to_string (VectorSize);
960
+ }
961
+
962
+ if (Type->getValueAsBit (" IsPointer" ) || Flags.IsPointer ) {
963
+ S += " *" ;
964
+ }
965
+
966
+ return S;
967
+ }
968
+
969
+ void OpenCLBuiltinTestEmitter::getTypeLists (
970
+ Record *Type, TypeFlags &Flags, std::vector<Record *> &TypeList,
971
+ std::vector<int64_t > &VectorList) const {
972
+ bool isGenType = Type->isSubClassOf (" GenericType" );
973
+ if (isGenType) {
974
+ TypeList = Type->getValueAsDef (" TypeList" )->getValueAsListOfDefs (" List" );
975
+ VectorList =
976
+ Type->getValueAsDef (" VectorList" )->getValueAsListOfInts (" List" );
977
+ return ;
978
+ }
979
+
980
+ if (Type->isSubClassOf (" PointerType" ) || Type->isSubClassOf (" ConstType" ) ||
981
+ Type->isSubClassOf (" VolatileType" )) {
982
+ StringRef SubTypeName = Type->getValueAsString (" Name" );
983
+ Record *PossibleGenType = Records.getDef (SubTypeName);
984
+ if (PossibleGenType && PossibleGenType->isSubClassOf (" GenericType" )) {
985
+ // When PointerType, ConstType, or VolatileType is applied to a
986
+ // GenericType, the flags need to be taken from the subtype, not from the
987
+ // GenericType.
988
+ Flags.IsPointer = Type->getValueAsBit (" IsPointer" );
989
+ Flags.IsConst = Type->getValueAsBit (" IsConst" );
990
+ Flags.IsVolatile = Type->getValueAsBit (" IsVolatile" );
991
+ Flags.AddrSpace = Type->getValueAsString (" AddrSpace" );
992
+ getTypeLists (PossibleGenType, Flags, TypeList, VectorList);
993
+ return ;
994
+ }
995
+ }
996
+
997
+ // Not a GenericType, so just insert the single type.
998
+ TypeList.push_back (Type);
999
+ VectorList.push_back (Type->getValueAsInt (" VecWidth" ));
1000
+ }
1001
+
1002
+ void OpenCLBuiltinTestEmitter::expandTypesInSignature (
1003
+ const std::vector<Record *> &Signature,
1004
+ SmallVectorImpl<SmallVector<std::string, 2 >> &Types) {
1005
+ // Find out if there are any GenTypes in this signature, and if so, calculate
1006
+ // into how many signatures they will expand.
1007
+ unsigned NumSignatures = 1 ;
1008
+ SmallVector<SmallVector<std::string, 4 >, 4 > ExpandedGenTypes;
1009
+ for (const auto &Arg : Signature) {
1010
+ SmallVector<std::string, 4 > ExpandedArg;
1011
+ std::vector<Record *> TypeList;
1012
+ std::vector<int64_t > VectorList;
1013
+ TypeFlags Flags;
1014
+
1015
+ getTypeLists (Arg, Flags, TypeList, VectorList);
1016
+
1017
+ // Insert the Cartesian product of the types and vector sizes.
1018
+ for (const auto &Vector : VectorList) {
1019
+ for (const auto &Type : TypeList) {
1020
+ ExpandedArg.push_back (getTypeString (Type, Flags, Vector));
1021
+ }
1022
+ }
1023
+ NumSignatures = std::max<unsigned >(NumSignatures, ExpandedArg.size ());
1024
+ ExpandedGenTypes.push_back (ExpandedArg);
1025
+ }
1026
+
1027
+ // Now the total number of signatures is known. Populate the return list with
1028
+ // all signatures.
1029
+ for (unsigned I = 0 ; I < NumSignatures; I++) {
1030
+ SmallVector<std::string, 2 > Args;
1031
+
1032
+ // Process a single signature.
1033
+ for (unsigned ArgNum = 0 ; ArgNum < Signature.size (); ArgNum++) {
1034
+ // For differently-sized GenTypes in a parameter list, the smaller
1035
+ // GenTypes just repeat, so index modulo the number of expanded types.
1036
+ size_t TypeIndex = I % ExpandedGenTypes[ArgNum].size ();
1037
+ Args.push_back (ExpandedGenTypes[ArgNum][TypeIndex]);
1038
+ }
1039
+ Types.push_back (Args);
1040
+ }
1041
+ }
1042
+
1043
+ void OpenCLBuiltinTestEmitter::emit () {
1044
+ emitSourceFileHeader (" OpenCL Builtin exhaustive testing" , OS);
1045
+
1046
+ // Enable some extensions for testing.
1047
+ OS << R"(
1048
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
1049
+ #pragma OPENCL EXTENSION cl_khr_fp64 : enable
1050
+ #pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
1051
+ #pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable
1052
+ #pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable
1053
+ #pragma OPENCL EXTENSION cl_khr_mipmap_image_writes : enable
1054
+ #pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable
1055
+
1056
+ )" ;
1057
+
1058
+ // Ensure each test has a unique name by numbering them.
1059
+ unsigned TestID = 0 ;
1060
+
1061
+ // Iterate over all builtins.
1062
+ std::vector<Record *> Builtins = Records.getAllDerivedDefinitions (" Builtin" );
1063
+ for (const auto *B : Builtins) {
1064
+ StringRef Name = B->getValueAsString (" Name" );
1065
+
1066
+ SmallVector<SmallVector<std::string, 2 >, 4 > FTypes;
1067
+ expandTypesInSignature (B->getValueAsListOfDefs (" Signature" ), FTypes);
1068
+
1069
+ OS << " // Test " << Name << " \n " ;
1070
+ std::string OptionalEndif;
1071
+ StringRef Extensions =
1072
+ B->getValueAsDef (" Extension" )->getValueAsString (" ExtName" );
1073
+ if (!Extensions.empty ()) {
1074
+ OS << " #if" ;
1075
+ OptionalEndif = " #endif // Extension\n " ;
1076
+
1077
+ SmallVector<StringRef, 2 > ExtVec;
1078
+ Extensions.split (ExtVec, " " );
1079
+ bool isFirst = true ;
1080
+ for (StringRef Ext : ExtVec) {
1081
+ if (!isFirst) {
1082
+ OS << " &&" ;
1083
+ }
1084
+ OS << " defined(" << Ext << " )" ;
1085
+ isFirst = false ;
1086
+ }
1087
+ OS << " \n " ;
1088
+ }
1089
+ auto PrintOpenCLVersion = [this ](int Version) {
1090
+ OS << " CL_VERSION_" << (Version / 100 ) << " _" << ((Version % 100 ) / 10 );
1091
+ };
1092
+ int MinVersion = B->getValueAsDef (" MinVersion" )->getValueAsInt (" ID" );
1093
+ if (MinVersion != 100 ) {
1094
+ // OpenCL 1.0 is the default minimum version.
1095
+ OS << " #if __OPENCL_C_VERSION__ >= " ;
1096
+ PrintOpenCLVersion (MinVersion);
1097
+ OS << " \n " ;
1098
+ OptionalEndif = " #endif // MinVersion\n " + OptionalEndif;
1099
+ }
1100
+ int MaxVersion = B->getValueAsDef (" MaxVersion" )->getValueAsInt (" ID" );
1101
+ if (MaxVersion) {
1102
+ OS << " #if __OPENCL_C_VERSION__ < " ;
1103
+ PrintOpenCLVersion (MaxVersion);
1104
+ OS << " \n " ;
1105
+ OptionalEndif = " #endif // MaxVersion\n " + OptionalEndif;
1106
+ }
1107
+ for (const auto &Signature : FTypes) {
1108
+ // Emit function declaration.
1109
+ OS << Signature[0 ] << " test" << TestID++ << " _" << Name << " (" ;
1110
+ if (Signature.size () > 1 ) {
1111
+ for (unsigned I = 1 ; I < Signature.size (); I++) {
1112
+ if (I != 1 )
1113
+ OS << " , " ;
1114
+ OS << Signature[I] << " arg" << I;
1115
+ }
1116
+ }
1117
+ OS << " ) {\n " ;
1118
+
1119
+ // Emit function body.
1120
+ OS << " " ;
1121
+ if (Signature[0 ] != " void" ) {
1122
+ OS << " return " ;
1123
+ }
1124
+ OS << Name << " (" ;
1125
+ for (unsigned I = 1 ; I < Signature.size (); I++) {
1126
+ if (I != 1 )
1127
+ OS << " , " ;
1128
+ OS << " arg" << I;
1129
+ }
1130
+ OS << " );\n " ;
1131
+
1132
+ // End of function body.
1133
+ OS << " }\n " ;
1134
+ }
1135
+ OS << OptionalEndif << " \n " ;
1136
+ }
1137
+ }
1138
+
864
1139
void clang::EmitClangOpenCLBuiltins (RecordKeeper &Records, raw_ostream &OS) {
865
1140
BuiltinNameEmitter NameChecker (Records, OS);
866
1141
NameChecker.Emit ();
867
1142
}
1143
+
1144
+ void clang::EmitClangOpenCLBuiltinTests (RecordKeeper &Records,
1145
+ raw_ostream &OS) {
1146
+ OpenCLBuiltinTestEmitter TestFileGenerator (Records, OS);
1147
+ TestFileGenerator.emit ();
1148
+ }
0 commit comments