slang_rs_export_type.cpp revision 5f3da4bf52b327dbf5b6a33f340196f43d542159
1/*
2 * Copyright 2010-2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "slang_rs_export_type.h"
18
19#include <list>
20#include <vector>
21
22#include "clang/AST/ASTContext.h"
23#include "clang/AST/Attr.h"
24#include "clang/AST/RecordLayout.h"
25
26#include "llvm/ADT/StringExtras.h"
27#include "llvm/IR/DataLayout.h"
28#include "llvm/IR/DerivedTypes.h"
29#include "llvm/IR/Type.h"
30
31#include "slang_assert.h"
32#include "slang_rs_context.h"
33#include "slang_rs_export_element.h"
34#include "slang_version.h"
35
36#define CHECK_PARENT_EQUALITY(ParentClass, E) \
37  if (!ParentClass::equals(E))                \
38    return false;
39
40namespace slang {
41
42namespace {
43
44// For the data types we support:
45//  Category      - data type category
46//  RsType        - element name in RenderScript
47//  RsShortType   - short element name in RenderScript
48//  SizeInBits    - size in bits
49//  CName         - reflected C name
50//  JavaName      - reflected Java name
51//  JavaArrayElementName - reflected name in Java arrays
52//  CVecName      - prefix for C vector types
53//  JavaVecName   - prefix for Java vector type
54//  JavaPromotion - unsigned type undergoing Java promotion
55//
56// IMPORTANT: The data types in this table should be at the same index as
57// specified by the corresponding DataType enum.
58//
59// TODO: Pull this information out into a separate file.
60static RSReflectionType gReflectionTypes[] = {
61#define _ nullptr
62{PrimitiveDataType,         "FLOAT_16",     "F16", 16,     "half",   "short",        _,   "Half",   "Half", false},
63{PrimitiveDataType,         "FLOAT_32",     "F32", 32,    "float",   "float",  "float",  "Float",  "Float", false},
64{PrimitiveDataType,         "FLOAT_64",     "F64", 64,   "double",  "double", "double", "Double", "Double", false},
65{PrimitiveDataType,         "SIGNED_8",      "I8",  8,   "int8_t",    "byte",   "byte",   "Byte",   "Byte", false},
66{PrimitiveDataType,        "SIGNED_16",     "I16", 16,  "int16_t",   "short",  "short",  "Short",  "Short", false},
67{PrimitiveDataType,        "SIGNED_32",     "I32", 32,  "int32_t",     "int",    "int",    "Int",    "Int", false},
68{PrimitiveDataType,        "SIGNED_64",     "I64", 64,  "int64_t",    "long",   "long",   "Long",   "Long", false},
69{PrimitiveDataType,       "UNSIGNED_8",      "U8",  8,  "uint8_t",   "short",   "byte",  "UByte",  "Short",  true},
70{PrimitiveDataType,      "UNSIGNED_16",     "U16", 16, "uint16_t",     "int",  "short", "UShort",    "Int",  true},
71{PrimitiveDataType,      "UNSIGNED_32",     "U32", 32, "uint32_t",    "long",    "int",   "UInt",   "Long",  true},
72{PrimitiveDataType,      "UNSIGNED_64",     "U64", 64, "uint64_t",    "long",   "long",  "ULong",   "Long", false},
73{PrimitiveDataType,          "BOOLEAN", "BOOLEAN",  8,     "bool", "boolean",   "byte",        _,        _, false},
74{PrimitiveDataType,   "UNSIGNED_5_6_5",         _, 16,          _,         _,        _,        _,        _, false},
75{PrimitiveDataType, "UNSIGNED_5_5_5_1",         _, 16,          _,         _,        _,        _,        _, false},
76{PrimitiveDataType, "UNSIGNED_4_4_4_4",         _, 16,          _,         _,        _,        _,        _, false},
77
78{MatrixDataType, "MATRIX_2X2", _,  4*32, "rs_matrix2x2", "Matrix2f", _, _, _, false},
79{MatrixDataType, "MATRIX_3X3", _,  9*32, "rs_matrix3x3", "Matrix3f", _, _, _, false},
80{MatrixDataType, "MATRIX_4X4", _, 16*32, "rs_matrix4x4", "Matrix4f", _, _, _, false},
81
82// RS object types are 32 bits in 32-bit RS, but 256 bits in 64-bit RS.
83// This is handled specially by the GetSizeInBits(}, method.
84{ObjectDataType,          "RS_ELEMENT",          "ELEMENT", 32,         "Element",         "Element", _, _, _, false},
85{ObjectDataType,             "RS_TYPE",             "TYPE", 32,            "Type",            "Type", _, _, _, false},
86{ObjectDataType,       "RS_ALLOCATION",       "ALLOCATION", 32,      "Allocation",      "Allocation", _, _, _, false},
87{ObjectDataType,          "RS_SAMPLER",          "SAMPLER", 32,         "Sampler",         "Sampler", _, _, _, false},
88{ObjectDataType,           "RS_SCRIPT",           "SCRIPT", 32,          "Script",          "Script", _, _, _, false},
89{ObjectDataType,             "RS_MESH",             "MESH", 32,            "Mesh",            "Mesh", _, _, _, false},
90{ObjectDataType,             "RS_PATH",             "PATH", 32,            "Path",            "Path", _, _, _, false},
91{ObjectDataType, "RS_PROGRAM_FRAGMENT", "PROGRAM_FRAGMENT", 32, "ProgramFragment", "ProgramFragment", _, _, _, false},
92{ObjectDataType,   "RS_PROGRAM_VERTEX",   "PROGRAM_VERTEX", 32,   "ProgramVertex",   "ProgramVertex", _, _, _, false},
93{ObjectDataType,   "RS_PROGRAM_RASTER",   "PROGRAM_RASTER", 32,   "ProgramRaster",   "ProgramRaster", _, _, _, false},
94{ObjectDataType,    "RS_PROGRAM_STORE",    "PROGRAM_STORE", 32,    "ProgramStore",    "ProgramStore", _, _, _, false},
95{ObjectDataType,             "RS_FONT",             "FONT", 32,            "Font",            "Font", _, _, _, false},
96#undef _
97};
98
99const int kMaxVectorSize = 4;
100
101struct BuiltinInfo {
102  clang::BuiltinType::Kind builtinTypeKind;
103  DataType type;
104  /* TODO If we return std::string instead of llvm::StringRef, we could build
105   * the name instead of duplicating the entries.
106   */
107  const char *cname[kMaxVectorSize];
108};
109
110
111BuiltinInfo BuiltinInfoTable[] = {
112    {clang::BuiltinType::Bool, DataTypeBoolean,
113     {"bool", "bool2", "bool3", "bool4"}},
114    {clang::BuiltinType::Char_U, DataTypeUnsigned8,
115     {"uchar", "uchar2", "uchar3", "uchar4"}},
116    {clang::BuiltinType::UChar, DataTypeUnsigned8,
117     {"uchar", "uchar2", "uchar3", "uchar4"}},
118    {clang::BuiltinType::Char16, DataTypeSigned16,
119     {"short", "short2", "short3", "short4"}},
120    {clang::BuiltinType::Char32, DataTypeSigned32,
121     {"int", "int2", "int3", "int4"}},
122    {clang::BuiltinType::UShort, DataTypeUnsigned16,
123     {"ushort", "ushort2", "ushort3", "ushort4"}},
124    {clang::BuiltinType::UInt, DataTypeUnsigned32,
125     {"uint", "uint2", "uint3", "uint4"}},
126    {clang::BuiltinType::ULong, DataTypeUnsigned64,
127     {"ulong", "ulong2", "ulong3", "ulong4"}},
128    {clang::BuiltinType::ULongLong, DataTypeUnsigned64,
129     {"ulong", "ulong2", "ulong3", "ulong4"}},
130
131    {clang::BuiltinType::Char_S, DataTypeSigned8,
132     {"char", "char2", "char3", "char4"}},
133    {clang::BuiltinType::SChar, DataTypeSigned8,
134     {"char", "char2", "char3", "char4"}},
135    {clang::BuiltinType::Short, DataTypeSigned16,
136     {"short", "short2", "short3", "short4"}},
137    {clang::BuiltinType::Int, DataTypeSigned32,
138     {"int", "int2", "int3", "int4"}},
139    {clang::BuiltinType::Long, DataTypeSigned64,
140     {"long", "long2", "long3", "long4"}},
141    {clang::BuiltinType::LongLong, DataTypeSigned64,
142     {"long", "long2", "long3", "long4"}},
143    {clang::BuiltinType::Half, DataTypeFloat16,
144     {"half", "half2", "half3", "half4"}},
145    {clang::BuiltinType::Float, DataTypeFloat32,
146     {"float", "float2", "float3", "float4"}},
147    {clang::BuiltinType::Double, DataTypeFloat64,
148     {"double", "double2", "double3", "double4"}},
149};
150const int BuiltinInfoTableCount = sizeof(BuiltinInfoTable) / sizeof(BuiltinInfoTable[0]);
151
152struct NameAndPrimitiveType {
153  const char *name;
154  DataType dataType;
155};
156
157static NameAndPrimitiveType MatrixAndObjectDataTypes[] = {
158    {"rs_matrix2x2", DataTypeRSMatrix2x2},
159    {"rs_matrix3x3", DataTypeRSMatrix3x3},
160    {"rs_matrix4x4", DataTypeRSMatrix4x4},
161    {"rs_element", DataTypeRSElement},
162    {"rs_type", DataTypeRSType},
163    {"rs_allocation", DataTypeRSAllocation},
164    {"rs_sampler", DataTypeRSSampler},
165    {"rs_script", DataTypeRSScript},
166    {"rs_mesh", DataTypeRSMesh},
167    {"rs_path", DataTypeRSPath},
168    {"rs_program_fragment", DataTypeRSProgramFragment},
169    {"rs_program_vertex", DataTypeRSProgramVertex},
170    {"rs_program_raster", DataTypeRSProgramRaster},
171    {"rs_program_store", DataTypeRSProgramStore},
172    {"rs_font", DataTypeRSFont},
173};
174
175const int MatrixAndObjectDataTypesCount =
176    sizeof(MatrixAndObjectDataTypes) / sizeof(MatrixAndObjectDataTypes[0]);
177
178static const clang::Type *TypeExportableHelper(
179    const clang::Type *T,
180    llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
181    slang::RSContext *Context,
182    const clang::VarDecl *VD,
183    const clang::RecordDecl *TopLevelRecord);
184
185template <unsigned N>
186static void ReportTypeError(slang::RSContext *Context,
187                            const clang::NamedDecl *ND,
188                            const clang::RecordDecl *TopLevelRecord,
189                            const char (&Message)[N],
190                            unsigned int TargetAPI = 0) {
191  // Attempt to use the type declaration first (if we have one).
192  // Fall back to the variable definition, if we are looking at something
193  // like an array declaration that can't be exported.
194  if (TopLevelRecord) {
195    Context->ReportError(TopLevelRecord->getLocation(), Message)
196        << TopLevelRecord->getName() << TargetAPI;
197  } else if (ND) {
198    Context->ReportError(ND->getLocation(), Message) << ND->getName()
199                                                     << TargetAPI;
200  } else {
201    slangAssert(false && "Variables should be validated before exporting");
202  }
203}
204
205static const clang::Type *ConstantArrayTypeExportableHelper(
206    const clang::ConstantArrayType *CAT,
207    llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
208    slang::RSContext *Context,
209    const clang::VarDecl *VD,
210    const clang::RecordDecl *TopLevelRecord) {
211  // Check element type
212  const clang::Type *ElementType = GetConstantArrayElementType(CAT);
213  if (ElementType->isArrayType()) {
214    ReportTypeError(Context, VD, TopLevelRecord,
215                    "multidimensional arrays cannot be exported: '%0'");
216    return nullptr;
217  } else if (ElementType->isExtVectorType()) {
218    const clang::ExtVectorType *EVT =
219        static_cast<const clang::ExtVectorType*>(ElementType);
220    unsigned numElements = EVT->getNumElements();
221
222    const clang::Type *BaseElementType = GetExtVectorElementType(EVT);
223    if (!RSExportPrimitiveType::IsPrimitiveType(BaseElementType)) {
224      ReportTypeError(Context, VD, TopLevelRecord,
225        "vectors of non-primitive types cannot be exported: '%0'");
226      return nullptr;
227    }
228
229    if (numElements == 3 && CAT->getSize() != 1) {
230      ReportTypeError(Context, VD, TopLevelRecord,
231        "arrays of width 3 vector types cannot be exported: '%0'");
232      return nullptr;
233    }
234  }
235
236  if (TypeExportableHelper(ElementType, SPS, Context, VD,
237                           TopLevelRecord) == nullptr) {
238    return nullptr;
239  } else {
240    return CAT;
241  }
242}
243
244BuiltinInfo *FindBuiltinType(clang::BuiltinType::Kind builtinTypeKind) {
245  for (int i = 0; i < BuiltinInfoTableCount; i++) {
246    if (builtinTypeKind == BuiltinInfoTable[i].builtinTypeKind) {
247      return &BuiltinInfoTable[i];
248    }
249  }
250  return nullptr;
251}
252
253static const clang::Type *TypeExportableHelper(
254    clang::Type const *T,
255    llvm::SmallPtrSet<clang::Type const *, 8> &SPS,
256    slang::RSContext *Context,
257    clang::VarDecl const *VD,
258    clang::RecordDecl const *TopLevelRecord) {
259  // Normalize first
260  if ((T = GetCanonicalType(T)) == nullptr)
261    return nullptr;
262
263  if (SPS.count(T))
264    return T;
265
266  const clang::Type *CTI = T->getCanonicalTypeInternal().getTypePtr();
267
268  switch (T->getTypeClass()) {
269    case clang::Type::Builtin: {
270      const clang::BuiltinType *BT = static_cast<const clang::BuiltinType*>(CTI);
271      return FindBuiltinType(BT->getKind()) == nullptr ? nullptr : T;
272    }
273    case clang::Type::Record: {
274      if (RSExportPrimitiveType::GetRSSpecificType(T) != DataTypeUnknown) {
275        return T;  // RS object type, no further checks are needed
276      }
277
278      // Check internal struct
279      if (T->isUnionType()) {
280        ReportTypeError(Context, VD, T->getAsUnionType()->getDecl(),
281                        "unions cannot be exported: '%0'");
282        return nullptr;
283      } else if (!T->isStructureType()) {
284        slangAssert(false && "Unknown type cannot be exported");
285        return nullptr;
286      }
287
288      clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
289      if (RD != nullptr) {
290        RD = RD->getDefinition();
291        if (RD == nullptr) {
292          ReportTypeError(Context, nullptr, T->getAsStructureType()->getDecl(),
293                          "struct is not defined in this module");
294          return nullptr;
295        }
296      }
297
298      if (!TopLevelRecord) {
299        TopLevelRecord = RD;
300      }
301      if (RD->getName().empty()) {
302        ReportTypeError(Context, nullptr, RD,
303                        "anonymous structures cannot be exported");
304        return nullptr;
305      }
306
307      // Fast check
308      if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
309        return nullptr;
310
311      // Insert myself into checking set
312      SPS.insert(T);
313
314      // Check all element
315      for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
316               FE = RD->field_end();
317           FI != FE;
318           FI++) {
319        const clang::FieldDecl *FD = *FI;
320        const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
321        FT = GetCanonicalType(FT);
322
323        if (!TypeExportableHelper(FT, SPS, Context, VD, TopLevelRecord)) {
324          return nullptr;
325        }
326
327        // We don't support bit fields yet
328        //
329        // TODO(zonr/srhines): allow bit fields of size 8, 16, 32
330        if (FD->isBitField()) {
331          Context->ReportError(
332              FD->getLocation(),
333              "bit fields are not able to be exported: '%0.%1'")
334              << RD->getName() << FD->getName();
335          return nullptr;
336        }
337      }
338
339      return T;
340    }
341    case clang::Type::Pointer: {
342      if (TopLevelRecord) {
343        ReportTypeError(Context, VD, TopLevelRecord,
344            "structures containing pointers cannot be used as the type of "
345            "an exported global variable or the parameter to an exported "
346            "function: '%0'");
347        return nullptr;
348      }
349
350      const clang::PointerType *PT = static_cast<const clang::PointerType*>(CTI);
351      const clang::Type *PointeeType = GetPointeeType(PT);
352
353      if (PointeeType->getTypeClass() == clang::Type::Pointer) {
354        ReportTypeError(Context, VD, TopLevelRecord,
355            "multiple levels of pointers cannot be exported: '%0'");
356        return nullptr;
357      }
358      // We don't support pointer with array-type pointee or unsupported pointee
359      // type
360      if (PointeeType->isArrayType() ||
361          (TypeExportableHelper(PointeeType, SPS, Context, VD,
362                                TopLevelRecord) == nullptr))
363        return nullptr;
364      else
365        return T;
366    }
367    case clang::Type::ExtVector: {
368      const clang::ExtVectorType *EVT =
369              static_cast<const clang::ExtVectorType*>(CTI);
370      // Only vector with size 2, 3 and 4 are supported.
371      if (EVT->getNumElements() < 2 || EVT->getNumElements() > 4)
372        return nullptr;
373
374      // Check base element type
375      const clang::Type *ElementType = GetExtVectorElementType(EVT);
376
377      if ((ElementType->getTypeClass() != clang::Type::Builtin) ||
378          (TypeExportableHelper(ElementType, SPS, Context, VD,
379                                TopLevelRecord) == nullptr))
380        return nullptr;
381      else
382        return T;
383    }
384    case clang::Type::ConstantArray: {
385      const clang::ConstantArrayType *CAT =
386              static_cast<const clang::ConstantArrayType*>(CTI);
387
388      return ConstantArrayTypeExportableHelper(CAT, SPS, Context, VD,
389                                               TopLevelRecord);
390    }
391    case clang::Type::Enum: {
392      // FIXME: We currently convert enums to integers, rather than reflecting
393      // a more complete (and nicer type-safe Java version).
394      return Context->getASTContext().IntTy.getTypePtr();
395    }
396    default: {
397      slangAssert(false && "Unknown type cannot be validated");
398      return nullptr;
399    }
400  }
401}
402
403// Return the type that can be used to create RSExportType, will always return
404// the canonical type.
405//
406// If the Type T is not exportable, this function returns nullptr. DiagEngine is
407// used to generate proper Clang diagnostic messages when a non-exportable type
408// is detected. TopLevelRecord is used to capture the highest struct (in the
409// case of a nested hierarchy) for detecting other types that cannot be exported
410// (mostly pointers within a struct).
411static const clang::Type *TypeExportable(const clang::Type *T,
412                                         slang::RSContext *Context,
413                                         const clang::VarDecl *VD) {
414  llvm::SmallPtrSet<const clang::Type*, 8> SPS =
415      llvm::SmallPtrSet<const clang::Type*, 8>();
416
417  return TypeExportableHelper(T, SPS, Context, VD, nullptr);
418}
419
420static bool ValidateRSObjectInVarDecl(slang::RSContext *Context,
421                                      clang::VarDecl *VD, bool InCompositeType,
422                                      unsigned int TargetAPI) {
423  if (TargetAPI < SLANG_JB_TARGET_API) {
424    // Only if we are already in a composite type (like an array or structure).
425    if (InCompositeType) {
426      // Only if we are actually exported (i.e. non-static).
427      if (VD->hasLinkage() &&
428          (VD->getFormalLinkage() == clang::ExternalLinkage)) {
429        // Only if we are not a pointer to an object.
430        const clang::Type *T = GetCanonicalType(VD->getType().getTypePtr());
431        if (T->getTypeClass() != clang::Type::Pointer) {
432          ReportTypeError(Context, VD, nullptr,
433                          "arrays/structures containing RS object types "
434                          "cannot be exported in target API < %1: '%0'",
435                          SLANG_JB_TARGET_API);
436          return false;
437        }
438      }
439    }
440  }
441
442  return true;
443}
444
445// Helper function for ValidateType(). We do a recursive descent on the
446// type hierarchy to ensure that we can properly export/handle the
447// declaration.
448// \return true if the variable declaration is valid,
449//         false if it is invalid (along with proper diagnostics).
450//
451// C - ASTContext (for diagnostics + builtin types).
452// T - sub-type that we are validating.
453// ND - (optional) top-level named declaration that we are validating.
454// SPS - set of types we have already seen/validated.
455// InCompositeType - true if we are within an outer composite type.
456// UnionDecl - set if we are in a sub-type of a union.
457// TargetAPI - target SDK API level.
458// IsFilterscript - whether or not we are compiling for Filterscript
459// IsExtern - is this type externally visible (i.e. extern global or parameter
460//                                             to an extern function)
461static bool ValidateTypeHelper(
462    slang::RSContext *Context,
463    clang::ASTContext &C,
464    const clang::Type *&T,
465    clang::NamedDecl *ND,
466    clang::SourceLocation Loc,
467    llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
468    bool InCompositeType,
469    clang::RecordDecl *UnionDecl,
470    unsigned int TargetAPI,
471    bool IsFilterscript,
472    bool IsExtern) {
473  if ((T = GetCanonicalType(T)) == nullptr)
474    return true;
475
476  if (SPS.count(T))
477    return true;
478
479  const clang::Type *CTI = T->getCanonicalTypeInternal().getTypePtr();
480
481  switch (T->getTypeClass()) {
482    case clang::Type::Record: {
483      if (RSExportPrimitiveType::IsRSObjectType(T)) {
484        clang::VarDecl *VD = (ND ? llvm::dyn_cast<clang::VarDecl>(ND) : nullptr);
485        if (VD && !ValidateRSObjectInVarDecl(Context, VD, InCompositeType,
486                                             TargetAPI)) {
487          return false;
488        }
489      }
490
491      if (RSExportPrimitiveType::GetRSSpecificType(T) != DataTypeUnknown) {
492        if (!UnionDecl) {
493          return true;
494        } else if (RSExportPrimitiveType::IsRSObjectType(T)) {
495          ReportTypeError(Context, nullptr, UnionDecl,
496              "unions containing RS object types are not allowed");
497          return false;
498        }
499      }
500
501      clang::RecordDecl *RD = nullptr;
502
503      // Check internal struct
504      if (T->isUnionType()) {
505        RD = T->getAsUnionType()->getDecl();
506        UnionDecl = RD;
507      } else if (T->isStructureType()) {
508        RD = T->getAsStructureType()->getDecl();
509      } else {
510        slangAssert(false && "Unknown type cannot be exported");
511        return false;
512      }
513
514      if (RD != nullptr) {
515        RD = RD->getDefinition();
516        if (RD == nullptr) {
517          // FIXME
518          return true;
519        }
520      }
521
522      // Fast check
523      if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
524        return false;
525
526      // Insert myself into checking set
527      SPS.insert(T);
528
529      // Check all elements
530      for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
531               FE = RD->field_end();
532           FI != FE;
533           FI++) {
534        const clang::FieldDecl *FD = *FI;
535        const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
536        FT = GetCanonicalType(FT);
537
538        if (!ValidateTypeHelper(Context, C, FT, ND, Loc, SPS, true, UnionDecl,
539                                TargetAPI, IsFilterscript, IsExtern)) {
540          return false;
541        }
542      }
543
544      return true;
545    }
546
547    case clang::Type::Builtin: {
548      if (IsFilterscript) {
549        clang::QualType QT = T->getCanonicalTypeInternal();
550        if (QT == C.DoubleTy ||
551            QT == C.LongDoubleTy ||
552            QT == C.LongTy ||
553            QT == C.LongLongTy) {
554          if (ND) {
555            Context->ReportError(
556                Loc,
557                "Builtin types > 32 bits in size are forbidden in "
558                "Filterscript: '%0'")
559                << ND->getName();
560          } else {
561            Context->ReportError(
562                Loc,
563                "Builtin types > 32 bits in size are forbidden in "
564                "Filterscript");
565          }
566          return false;
567        }
568      }
569      break;
570    }
571
572    case clang::Type::Pointer: {
573      if (IsFilterscript) {
574        if (ND) {
575          Context->ReportError(Loc,
576                               "Pointers are forbidden in Filterscript: '%0'")
577              << ND->getName();
578          return false;
579        } else {
580          // TODO(srhines): Find a better way to handle expressions (i.e. no
581          // NamedDecl) involving pointers in FS that should be allowed.
582          // An example would be calls to library functions like
583          // rsMatrixMultiply() that take rs_matrixNxN * types.
584        }
585      }
586
587      // Forbid pointers in structures that are externally visible.
588      if (InCompositeType && IsExtern) {
589        if (ND) {
590          Context->ReportError(Loc,
591              "structures containing pointers cannot be used as the type of "
592              "an exported global variable or the parameter to an exported "
593              "function: '%0'")
594            << ND->getName();
595        } else {
596          Context->ReportError(Loc,
597              "structures containing pointers cannot be used as the type of "
598              "an exported global variable or the parameter to an exported "
599              "function");
600        }
601        return false;
602      }
603
604      const clang::PointerType *PT = static_cast<const clang::PointerType*>(CTI);
605      const clang::Type *PointeeType = GetPointeeType(PT);
606
607      return ValidateTypeHelper(Context, C, PointeeType, ND, Loc, SPS,
608                                InCompositeType, UnionDecl, TargetAPI,
609                                IsFilterscript, IsExtern);
610    }
611
612    case clang::Type::ExtVector: {
613      const clang::ExtVectorType *EVT =
614              static_cast<const clang::ExtVectorType*>(CTI);
615      const clang::Type *ElementType = GetExtVectorElementType(EVT);
616      if (TargetAPI < SLANG_ICS_TARGET_API &&
617          InCompositeType &&
618          EVT->getNumElements() == 3 &&
619          ND &&
620          ND->getFormalLinkage() == clang::ExternalLinkage) {
621        ReportTypeError(Context, ND, nullptr,
622                        "structs containing vectors of dimension 3 cannot "
623                        "be exported at this API level: '%0'");
624        return false;
625      }
626      return ValidateTypeHelper(Context, C, ElementType, ND, Loc, SPS, true,
627                                UnionDecl, TargetAPI, IsFilterscript, IsExtern);
628    }
629
630    case clang::Type::ConstantArray: {
631      const clang::ConstantArrayType *CAT = static_cast<const clang::ConstantArrayType*>(CTI);
632      const clang::Type *ElementType = GetConstantArrayElementType(CAT);
633      return ValidateTypeHelper(Context, C, ElementType, ND, Loc, SPS, true,
634                                UnionDecl, TargetAPI, IsFilterscript, IsExtern);
635    }
636
637    default: {
638      break;
639    }
640  }
641
642  return true;
643}
644
645}  // namespace
646
647std::string CreateDummyName(const char *type, const std::string &name) {
648  std::stringstream S;
649  S << "<" << type;
650  if (!name.empty()) {
651    S << ":" << name;
652  }
653  S << ">";
654  return S.str();
655}
656
657/****************************** RSExportType ******************************/
658bool RSExportType::NormalizeType(const clang::Type *&T,
659                                 llvm::StringRef &TypeName,
660                                 RSContext *Context,
661                                 const clang::VarDecl *VD) {
662  if ((T = TypeExportable(T, Context, VD)) == nullptr) {
663    return false;
664  }
665  // Get type name
666  TypeName = RSExportType::GetTypeName(T);
667  if (Context && TypeName.empty()) {
668    if (VD) {
669      Context->ReportError(VD->getLocation(),
670                           "anonymous types cannot be exported");
671    } else {
672      Context->ReportError("anonymous types cannot be exported");
673    }
674    return false;
675  }
676
677  return true;
678}
679
680bool RSExportType::ValidateType(slang::RSContext *Context, clang::ASTContext &C,
681                                clang::QualType QT, clang::NamedDecl *ND,
682                                clang::SourceLocation Loc,
683                                unsigned int TargetAPI, bool IsFilterscript,
684                                bool IsExtern) {
685  const clang::Type *T = QT.getTypePtr();
686  llvm::SmallPtrSet<const clang::Type*, 8> SPS =
687      llvm::SmallPtrSet<const clang::Type*, 8>();
688
689  // If this is an externally visible variable declaration, we check if the
690  // type is able to be exported first.
691  if (auto VD = llvm::dyn_cast_or_null<clang::VarDecl>(ND)) {
692    if (VD->getFormalLinkage() == clang::ExternalLinkage) {
693      if (!TypeExportable(T, Context, VD)) {
694        return false;
695      }
696    }
697  }
698  return ValidateTypeHelper(Context, C, T, ND, Loc, SPS, false, nullptr, TargetAPI,
699                            IsFilterscript, IsExtern);
700}
701
702bool RSExportType::ValidateVarDecl(slang::RSContext *Context,
703                                   clang::VarDecl *VD, unsigned int TargetAPI,
704                                   bool IsFilterscript) {
705  return ValidateType(Context, VD->getASTContext(), VD->getType(), VD,
706                      VD->getLocation(), TargetAPI, IsFilterscript,
707                      (VD->getFormalLinkage() == clang::ExternalLinkage));
708}
709
710const clang::Type
711*RSExportType::GetTypeOfDecl(const clang::DeclaratorDecl *DD) {
712  if (DD) {
713    clang::QualType T = DD->getType();
714
715    if (T.isNull())
716      return nullptr;
717    else
718      return T.getTypePtr();
719  }
720  return nullptr;
721}
722
723llvm::StringRef RSExportType::GetTypeName(const clang::Type* T) {
724  T = GetCanonicalType(T);
725  if (T == nullptr)
726    return llvm::StringRef();
727
728  const clang::Type *CTI = T->getCanonicalTypeInternal().getTypePtr();
729
730  switch (T->getTypeClass()) {
731    case clang::Type::Builtin: {
732      const clang::BuiltinType *BT = static_cast<const clang::BuiltinType*>(CTI);
733      BuiltinInfo *info = FindBuiltinType(BT->getKind());
734      if (info != nullptr) {
735        return info->cname[0];
736      }
737      slangAssert(false && "Unknown data type of the builtin");
738      break;
739    }
740    case clang::Type::Record: {
741      clang::RecordDecl *RD;
742      if (T->isStructureType()) {
743        RD = T->getAsStructureType()->getDecl();
744      } else {
745        break;
746      }
747
748      llvm::StringRef Name = RD->getName();
749      if (Name.empty()) {
750        if (RD->getTypedefNameForAnonDecl() != nullptr) {
751          Name = RD->getTypedefNameForAnonDecl()->getName();
752        }
753
754        if (Name.empty()) {
755          // Try to find a name from redeclaration (i.e. typedef)
756          for (clang::TagDecl::redecl_iterator RI = RD->redecls_begin(),
757                   RE = RD->redecls_end();
758               RI != RE;
759               RI++) {
760            slangAssert(*RI != nullptr && "cannot be NULL object");
761
762            Name = (*RI)->getName();
763            if (!Name.empty())
764              break;
765          }
766        }
767      }
768      return Name;
769    }
770    case clang::Type::Pointer: {
771      // "*" plus pointee name
772      const clang::PointerType *P = static_cast<const clang::PointerType*>(CTI);
773      const clang::Type *PT = GetPointeeType(P);
774      llvm::StringRef PointeeName;
775      if (NormalizeType(PT, PointeeName, nullptr, nullptr)) {
776        char *Name = new char[ 1 /* * */ + PointeeName.size() + 1 ];
777        Name[0] = '*';
778        memcpy(Name + 1, PointeeName.data(), PointeeName.size());
779        Name[PointeeName.size() + 1] = '\0';
780        return Name;
781      }
782      break;
783    }
784    case clang::Type::ExtVector: {
785      const clang::ExtVectorType *EVT =
786              static_cast<const clang::ExtVectorType*>(CTI);
787      return RSExportVectorType::GetTypeName(EVT);
788      break;
789    }
790    case clang::Type::ConstantArray : {
791      // Construct name for a constant array is too complicated.
792      return "<ConstantArray>";
793    }
794    default: {
795      break;
796    }
797  }
798
799  return llvm::StringRef();
800}
801
802
803RSExportType *RSExportType::Create(RSContext *Context,
804                                   const clang::Type *T,
805                                   const llvm::StringRef &TypeName) {
806  // Lookup the context to see whether the type was processed before.
807  // Newly created RSExportType will insert into context
808  // in RSExportType::RSExportType()
809  RSContext::export_type_iterator ETI = Context->findExportType(TypeName);
810
811  if (ETI != Context->export_types_end())
812    return ETI->second;
813
814  const clang::Type *CTI = T->getCanonicalTypeInternal().getTypePtr();
815
816  RSExportType *ET = nullptr;
817  switch (T->getTypeClass()) {
818    case clang::Type::Record: {
819      DataType dt = RSExportPrimitiveType::GetRSSpecificType(TypeName);
820      switch (dt) {
821        case DataTypeUnknown: {
822          // User-defined types
823          ET = RSExportRecordType::Create(Context,
824                                          T->getAsStructureType(),
825                                          TypeName);
826          break;
827        }
828        case DataTypeRSMatrix2x2: {
829          // 2 x 2 Matrix type
830          ET = RSExportMatrixType::Create(Context,
831                                          T->getAsStructureType(),
832                                          TypeName,
833                                          2);
834          break;
835        }
836        case DataTypeRSMatrix3x3: {
837          // 3 x 3 Matrix type
838          ET = RSExportMatrixType::Create(Context,
839                                          T->getAsStructureType(),
840                                          TypeName,
841                                          3);
842          break;
843        }
844        case DataTypeRSMatrix4x4: {
845          // 4 x 4 Matrix type
846          ET = RSExportMatrixType::Create(Context,
847                                          T->getAsStructureType(),
848                                          TypeName,
849                                          4);
850          break;
851        }
852        default: {
853          // Others are primitive types
854          ET = RSExportPrimitiveType::Create(Context, T, TypeName);
855          break;
856        }
857      }
858      break;
859    }
860    case clang::Type::Builtin: {
861      ET = RSExportPrimitiveType::Create(Context, T, TypeName);
862      break;
863    }
864    case clang::Type::Pointer: {
865      ET = RSExportPointerType::Create(Context,
866                                       static_cast<const clang::PointerType*>(CTI),
867                                       TypeName);
868      // FIXME: free the name (allocated in RSExportType::GetTypeName)
869      delete [] TypeName.data();
870      break;
871    }
872    case clang::Type::ExtVector: {
873      ET = RSExportVectorType::Create(Context,
874                                      static_cast<const clang::ExtVectorType*>(CTI),
875                                      TypeName);
876      break;
877    }
878    case clang::Type::ConstantArray: {
879      ET = RSExportConstantArrayType::Create(
880              Context,
881              static_cast<const clang::ConstantArrayType*>(CTI));
882      break;
883    }
884    default: {
885      Context->ReportError("unknown type cannot be exported: '%0'")
886          << T->getTypeClassName();
887      break;
888    }
889  }
890
891  return ET;
892}
893
894RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) {
895  llvm::StringRef TypeName;
896  if (NormalizeType(T, TypeName, Context, nullptr)) {
897    return Create(Context, T, TypeName);
898  } else {
899    return nullptr;
900  }
901}
902
903RSExportType *RSExportType::CreateFromDecl(RSContext *Context,
904                                           const clang::VarDecl *VD) {
905  return RSExportType::Create(Context, GetTypeOfDecl(VD));
906}
907
908size_t RSExportType::getStoreSize() const {
909  return getRSContext()->getDataLayout()->getTypeStoreSize(getLLVMType());
910}
911
912size_t RSExportType::getAllocSize() const {
913    return getRSContext()->getDataLayout()->getTypeAllocSize(getLLVMType());
914}
915
916RSExportType::RSExportType(RSContext *Context,
917                           ExportClass Class,
918                           const llvm::StringRef &Name)
919    : RSExportable(Context, RSExportable::EX_TYPE),
920      mClass(Class),
921      // Make a copy on Name since memory stored @Name is either allocated in
922      // ASTContext or allocated in GetTypeName which will be destroyed later.
923      mName(Name.data(), Name.size()),
924      mLLVMType(nullptr) {
925  // Don't cache the type whose name start with '<'. Those type failed to
926  // get their name since constructing their name in GetTypeName() requiring
927  // complicated work.
928  if (!IsDummyName(Name)) {
929    // TODO(zonr): Need to check whether the insertion is successful or not.
930    Context->insertExportType(llvm::StringRef(Name), this);
931  }
932
933}
934
935bool RSExportType::keep() {
936  if (!RSExportable::keep())
937    return false;
938  // Invalidate converted LLVM type.
939  mLLVMType = nullptr;
940  return true;
941}
942
943bool RSExportType::equals(const RSExportable *E) const {
944  CHECK_PARENT_EQUALITY(RSExportable, E);
945  return (static_cast<const RSExportType*>(E)->getClass() == getClass());
946}
947
948RSExportType::~RSExportType() {
949}
950
951/************************** RSExportPrimitiveType **************************/
952llvm::ManagedStatic<RSExportPrimitiveType::RSSpecificTypeMapTy>
953RSExportPrimitiveType::RSSpecificTypeMap;
954
955bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) {
956  if ((T != nullptr) && (T->getTypeClass() == clang::Type::Builtin))
957    return true;
958  else
959    return false;
960}
961
962DataType
963RSExportPrimitiveType::GetRSSpecificType(const llvm::StringRef &TypeName) {
964  if (TypeName.empty())
965    return DataTypeUnknown;
966
967  if (RSSpecificTypeMap->empty()) {
968    for (int i = 0; i < MatrixAndObjectDataTypesCount; i++) {
969      (*RSSpecificTypeMap)[MatrixAndObjectDataTypes[i].name] =
970          MatrixAndObjectDataTypes[i].dataType;
971    }
972  }
973
974  RSSpecificTypeMapTy::const_iterator I = RSSpecificTypeMap->find(TypeName);
975  if (I == RSSpecificTypeMap->end())
976    return DataTypeUnknown;
977  else
978    return I->getValue();
979}
980
981DataType RSExportPrimitiveType::GetRSSpecificType(const clang::Type *T) {
982  T = GetCanonicalType(T);
983  if ((T == nullptr) || (T->getTypeClass() != clang::Type::Record))
984    return DataTypeUnknown;
985
986  return GetRSSpecificType( RSExportType::GetTypeName(T) );
987}
988
989bool RSExportPrimitiveType::IsRSMatrixType(DataType DT) {
990    if (DT < 0 || DT >= DataTypeMax) {
991        return false;
992    }
993    return gReflectionTypes[DT].category == MatrixDataType;
994}
995
996bool RSExportPrimitiveType::IsRSObjectType(DataType DT) {
997    if (DT < 0 || DT >= DataTypeMax) {
998        return false;
999    }
1000    return gReflectionTypes[DT].category == ObjectDataType;
1001}
1002
1003bool RSExportPrimitiveType::IsStructureTypeWithRSObject(const clang::Type *T) {
1004  bool RSObjectTypeSeen = false;
1005  while (T && T->isArrayType()) {
1006    T = T->getArrayElementTypeNoTypeQual();
1007  }
1008
1009  const clang::RecordType *RT = T->getAsStructureType();
1010  if (!RT) {
1011    return false;
1012  }
1013
1014  const clang::RecordDecl *RD = RT->getDecl();
1015  if (RD) {
1016    RD = RD->getDefinition();
1017  }
1018  if (!RD) {
1019    return false;
1020  }
1021
1022  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1023         FE = RD->field_end();
1024       FI != FE;
1025       FI++) {
1026    // We just look through all field declarations to see if we find a
1027    // declaration for an RS object type (or an array of one).
1028    const clang::FieldDecl *FD = *FI;
1029    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
1030    while (FT && FT->isArrayType()) {
1031      FT = FT->getArrayElementTypeNoTypeQual();
1032    }
1033
1034    DataType DT = GetRSSpecificType(FT);
1035    if (IsRSObjectType(DT)) {
1036      // RS object types definitely need to be zero-initialized
1037      RSObjectTypeSeen = true;
1038    } else {
1039      switch (DT) {
1040        case DataTypeRSMatrix2x2:
1041        case DataTypeRSMatrix3x3:
1042        case DataTypeRSMatrix4x4:
1043          // Matrix types should get zero-initialized as well
1044          RSObjectTypeSeen = true;
1045          break;
1046        default:
1047          // Ignore all other primitive types
1048          break;
1049      }
1050      while (FT && FT->isArrayType()) {
1051        FT = FT->getArrayElementTypeNoTypeQual();
1052      }
1053      if (FT->isStructureType()) {
1054        // Recursively handle structs of structs (even though these can't
1055        // be exported, it is possible for a user to have them internally).
1056        RSObjectTypeSeen |= IsStructureTypeWithRSObject(FT);
1057      }
1058    }
1059  }
1060
1061  return RSObjectTypeSeen;
1062}
1063
1064size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) {
1065  int type = EPT->getType();
1066  slangAssert((type > DataTypeUnknown && type < DataTypeMax) &&
1067              "RSExportPrimitiveType::GetSizeInBits : unknown data type");
1068  // All RS object types are 256 bits in 64-bit RS.
1069  if (EPT->isRSObjectType() && EPT->getRSContext()->is64Bit()) {
1070    return 256;
1071  }
1072  return gReflectionTypes[type].size_in_bits;
1073}
1074
1075DataType
1076RSExportPrimitiveType::GetDataType(RSContext *Context, const clang::Type *T) {
1077  if (T == nullptr)
1078    return DataTypeUnknown;
1079
1080  switch (T->getTypeClass()) {
1081    case clang::Type::Builtin: {
1082      const clang::BuiltinType *BT =
1083              static_cast<const clang::BuiltinType*>(T->getCanonicalTypeInternal().getTypePtr());
1084      BuiltinInfo *info = FindBuiltinType(BT->getKind());
1085      if (info != nullptr) {
1086        return info->type;
1087      }
1088      // The size of type WChar depend on platform so we abandon the support
1089      // to them.
1090      Context->ReportError("built-in type cannot be exported: '%0'")
1091          << T->getTypeClassName();
1092      break;
1093    }
1094    case clang::Type::Record: {
1095      // must be RS object type
1096      return RSExportPrimitiveType::GetRSSpecificType(T);
1097    }
1098    default: {
1099      Context->ReportError("primitive type cannot be exported: '%0'")
1100          << T->getTypeClassName();
1101      break;
1102    }
1103  }
1104
1105  return DataTypeUnknown;
1106}
1107
1108RSExportPrimitiveType
1109*RSExportPrimitiveType::Create(RSContext *Context,
1110                               const clang::Type *T,
1111                               const llvm::StringRef &TypeName,
1112                               bool Normalized) {
1113  DataType DT = GetDataType(Context, T);
1114
1115  if ((DT == DataTypeUnknown) || TypeName.empty())
1116    return nullptr;
1117  else
1118    return new RSExportPrimitiveType(Context, ExportClassPrimitive, TypeName,
1119                                     DT, Normalized);
1120}
1121
1122RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context,
1123                                                     const clang::Type *T) {
1124  llvm::StringRef TypeName;
1125  if (RSExportType::NormalizeType(T, TypeName, Context, nullptr)
1126      && IsPrimitiveType(T)) {
1127    return Create(Context, T, TypeName);
1128  } else {
1129    return nullptr;
1130  }
1131}
1132
1133llvm::Type *RSExportPrimitiveType::convertToLLVMType() const {
1134  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
1135
1136  if (isRSObjectType()) {
1137    // struct {
1138    //   int *p;
1139    // } __attribute__((packed, aligned(pointer_size)))
1140    //
1141    // which is
1142    //
1143    // <{ [1 x i32] }> in LLVM
1144    //
1145    std::vector<llvm::Type *> Elements;
1146    if (getRSContext()->is64Bit()) {
1147      // 64-bit path
1148      Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt64Ty(C), 4));
1149      return llvm::StructType::get(C, Elements, true);
1150    } else {
1151      // 32-bit legacy path
1152      Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1));
1153      return llvm::StructType::get(C, Elements, true);
1154    }
1155  }
1156
1157  switch (mType) {
1158    case DataTypeFloat16: {
1159      return llvm::Type::getHalfTy(C);
1160      break;
1161    }
1162    case DataTypeFloat32: {
1163      return llvm::Type::getFloatTy(C);
1164      break;
1165    }
1166    case DataTypeFloat64: {
1167      return llvm::Type::getDoubleTy(C);
1168      break;
1169    }
1170    case DataTypeBoolean: {
1171      return llvm::Type::getInt1Ty(C);
1172      break;
1173    }
1174    case DataTypeSigned8:
1175    case DataTypeUnsigned8: {
1176      return llvm::Type::getInt8Ty(C);
1177      break;
1178    }
1179    case DataTypeSigned16:
1180    case DataTypeUnsigned16:
1181    case DataTypeUnsigned565:
1182    case DataTypeUnsigned5551:
1183    case DataTypeUnsigned4444: {
1184      return llvm::Type::getInt16Ty(C);
1185      break;
1186    }
1187    case DataTypeSigned32:
1188    case DataTypeUnsigned32: {
1189      return llvm::Type::getInt32Ty(C);
1190      break;
1191    }
1192    case DataTypeSigned64:
1193    case DataTypeUnsigned64: {
1194      return llvm::Type::getInt64Ty(C);
1195      break;
1196    }
1197    default: {
1198      slangAssert(false && "Unknown data type");
1199    }
1200  }
1201
1202  return nullptr;
1203}
1204
1205bool RSExportPrimitiveType::equals(const RSExportable *E) const {
1206  CHECK_PARENT_EQUALITY(RSExportType, E);
1207  return (static_cast<const RSExportPrimitiveType*>(E)->getType() == getType());
1208}
1209
1210RSReflectionType *RSExportPrimitiveType::getRSReflectionType(DataType DT) {
1211  if (DT > DataTypeUnknown && DT < DataTypeMax) {
1212    return &gReflectionTypes[DT];
1213  } else {
1214    return nullptr;
1215  }
1216}
1217
1218/**************************** RSExportPointerType ****************************/
1219
1220RSExportPointerType
1221*RSExportPointerType::Create(RSContext *Context,
1222                             const clang::PointerType *PT,
1223                             const llvm::StringRef &TypeName) {
1224  const clang::Type *PointeeType = GetPointeeType(PT);
1225  const RSExportType *PointeeET;
1226
1227  if (PointeeType->getTypeClass() != clang::Type::Pointer) {
1228    PointeeET = RSExportType::Create(Context, PointeeType);
1229  } else {
1230    // Double or higher dimension of pointer, export as int*
1231    PointeeET = RSExportPrimitiveType::Create(Context,
1232                    Context->getASTContext().IntTy.getTypePtr());
1233  }
1234
1235  if (PointeeET == nullptr) {
1236    // Error diagnostic is emitted for corresponding pointee type
1237    return nullptr;
1238  }
1239
1240  return new RSExportPointerType(Context, TypeName, PointeeET);
1241}
1242
1243llvm::Type *RSExportPointerType::convertToLLVMType() const {
1244  llvm::Type *PointeeType = mPointeeType->getLLVMType();
1245  return llvm::PointerType::getUnqual(PointeeType);
1246}
1247
1248bool RSExportPointerType::keep() {
1249  if (!RSExportType::keep())
1250    return false;
1251  const_cast<RSExportType*>(mPointeeType)->keep();
1252  return true;
1253}
1254
1255bool RSExportPointerType::equals(const RSExportable *E) const {
1256  CHECK_PARENT_EQUALITY(RSExportType, E);
1257  return (static_cast<const RSExportPointerType*>(E)
1258              ->getPointeeType()->equals(getPointeeType()));
1259}
1260
1261/***************************** RSExportVectorType *****************************/
1262llvm::StringRef
1263RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) {
1264  const clang::Type *ElementType = GetExtVectorElementType(EVT);
1265  llvm::StringRef name;
1266
1267  if ((ElementType->getTypeClass() != clang::Type::Builtin))
1268    return name;
1269
1270  const clang::BuiltinType *BT =
1271          static_cast<const clang::BuiltinType*>(
1272              ElementType->getCanonicalTypeInternal().getTypePtr());
1273
1274  if ((EVT->getNumElements() < 1) ||
1275      (EVT->getNumElements() > 4))
1276    return name;
1277
1278  BuiltinInfo *info = FindBuiltinType(BT->getKind());
1279  if (info != nullptr) {
1280    int I = EVT->getNumElements() - 1;
1281    if (I < kMaxVectorSize) {
1282      name = info->cname[I];
1283    } else {
1284      slangAssert(false && "Max vector is 4");
1285    }
1286  }
1287  return name;
1288}
1289
1290RSExportVectorType *RSExportVectorType::Create(RSContext *Context,
1291                                               const clang::ExtVectorType *EVT,
1292                                               const llvm::StringRef &TypeName,
1293                                               bool Normalized) {
1294  slangAssert(EVT != nullptr && EVT->getTypeClass() == clang::Type::ExtVector);
1295
1296  const clang::Type *ElementType = GetExtVectorElementType(EVT);
1297  DataType DT = RSExportPrimitiveType::GetDataType(Context, ElementType);
1298
1299  if (DT != DataTypeUnknown)
1300    return new RSExportVectorType(Context,
1301                                  TypeName,
1302                                  DT,
1303                                  Normalized,
1304                                  EVT->getNumElements());
1305  else
1306    return nullptr;
1307}
1308
1309llvm::Type *RSExportVectorType::convertToLLVMType() const {
1310  llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType();
1311  return llvm::VectorType::get(ElementType, getNumElement());
1312}
1313
1314bool RSExportVectorType::equals(const RSExportable *E) const {
1315  CHECK_PARENT_EQUALITY(RSExportPrimitiveType, E);
1316  return (static_cast<const RSExportVectorType*>(E)->getNumElement()
1317              == getNumElement());
1318}
1319
1320/***************************** RSExportMatrixType *****************************/
1321RSExportMatrixType *RSExportMatrixType::Create(RSContext *Context,
1322                                               const clang::RecordType *RT,
1323                                               const llvm::StringRef &TypeName,
1324                                               unsigned Dim) {
1325  slangAssert((RT != nullptr) && (RT->getTypeClass() == clang::Type::Record));
1326  slangAssert((Dim > 1) && "Invalid dimension of matrix");
1327
1328  // Check whether the struct rs_matrix is in our expected form (but assume it's
1329  // correct if we're not sure whether it's correct or not)
1330  const clang::RecordDecl* RD = RT->getDecl();
1331  RD = RD->getDefinition();
1332  if (RD != nullptr) {
1333    // Find definition, perform further examination
1334    if (RD->field_empty()) {
1335      Context->ReportError(
1336          RD->getLocation(),
1337          "invalid matrix struct: must have 1 field for saving values: '%0'")
1338          << RD->getName();
1339      return nullptr;
1340    }
1341
1342    clang::RecordDecl::field_iterator FIT = RD->field_begin();
1343    const clang::FieldDecl *FD = *FIT;
1344    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
1345    if ((FT == nullptr) || (FT->getTypeClass() != clang::Type::ConstantArray)) {
1346      Context->ReportError(RD->getLocation(),
1347                           "invalid matrix struct: first field should"
1348                           " be an array with constant size: '%0'")
1349          << RD->getName();
1350      return nullptr;
1351    }
1352    const clang::ConstantArrayType *CAT =
1353      static_cast<const clang::ConstantArrayType *>(FT);
1354    const clang::Type *ElementType = GetConstantArrayElementType(CAT);
1355    if ((ElementType == nullptr) ||
1356        (ElementType->getTypeClass() != clang::Type::Builtin) ||
1357        (static_cast<const clang::BuiltinType *>(ElementType)->getKind() !=
1358         clang::BuiltinType::Float)) {
1359      Context->ReportError(RD->getLocation(),
1360                           "invalid matrix struct: first field "
1361                           "should be a float array: '%0'")
1362          << RD->getName();
1363      return nullptr;
1364    }
1365
1366    if (CAT->getSize() != Dim * Dim) {
1367      Context->ReportError(RD->getLocation(),
1368                           "invalid matrix struct: first field "
1369                           "should be an array with size %0: '%1'")
1370          << (Dim * Dim) << (RD->getName());
1371      return nullptr;
1372    }
1373
1374    FIT++;
1375    if (FIT != RD->field_end()) {
1376      Context->ReportError(RD->getLocation(),
1377                           "invalid matrix struct: must have "
1378                           "exactly 1 field: '%0'")
1379          << RD->getName();
1380      return nullptr;
1381    }
1382  }
1383
1384  return new RSExportMatrixType(Context, TypeName, Dim);
1385}
1386
1387llvm::Type *RSExportMatrixType::convertToLLVMType() const {
1388  // Construct LLVM type:
1389  // struct {
1390  //  float X[mDim * mDim];
1391  // }
1392
1393  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
1394  llvm::ArrayType *X = llvm::ArrayType::get(llvm::Type::getFloatTy(C),
1395                                            mDim * mDim);
1396  return llvm::StructType::get(C, X, false);
1397}
1398
1399bool RSExportMatrixType::equals(const RSExportable *E) const {
1400  CHECK_PARENT_EQUALITY(RSExportType, E);
1401  return (static_cast<const RSExportMatrixType*>(E)->getDim() == getDim());
1402}
1403
1404/************************* RSExportConstantArrayType *************************/
1405RSExportConstantArrayType
1406*RSExportConstantArrayType::Create(RSContext *Context,
1407                                   const clang::ConstantArrayType *CAT) {
1408  slangAssert(CAT != nullptr && CAT->getTypeClass() == clang::Type::ConstantArray);
1409
1410  slangAssert((CAT->getSize().getActiveBits() < 32) && "array too large");
1411
1412  unsigned Size = static_cast<unsigned>(CAT->getSize().getZExtValue());
1413  slangAssert((Size > 0) && "Constant array should have size greater than 0");
1414
1415  const clang::Type *ElementType = GetConstantArrayElementType(CAT);
1416  RSExportType *ElementET = RSExportType::Create(Context, ElementType);
1417
1418  if (ElementET == nullptr) {
1419    return nullptr;
1420  }
1421
1422  return new RSExportConstantArrayType(Context,
1423                                       ElementET,
1424                                       Size);
1425}
1426
1427llvm::Type *RSExportConstantArrayType::convertToLLVMType() const {
1428  return llvm::ArrayType::get(mElementType->getLLVMType(), getSize());
1429}
1430
1431bool RSExportConstantArrayType::keep() {
1432  if (!RSExportType::keep())
1433    return false;
1434  const_cast<RSExportType*>(mElementType)->keep();
1435  return true;
1436}
1437
1438bool RSExportConstantArrayType::equals(const RSExportable *E) const {
1439  CHECK_PARENT_EQUALITY(RSExportType, E);
1440  const RSExportConstantArrayType *RHS =
1441      static_cast<const RSExportConstantArrayType*>(E);
1442  return ((getSize() == RHS->getSize()) &&
1443          (getElementType()->equals(RHS->getElementType())));
1444}
1445
1446/**************************** RSExportRecordType ****************************/
1447RSExportRecordType *RSExportRecordType::Create(RSContext *Context,
1448                                               const clang::RecordType *RT,
1449                                               const llvm::StringRef &TypeName,
1450                                               bool mIsArtificial) {
1451  slangAssert(RT != nullptr && RT->getTypeClass() == clang::Type::Record);
1452
1453  const clang::RecordDecl *RD = RT->getDecl();
1454  slangAssert(RD->isStruct());
1455
1456  RD = RD->getDefinition();
1457  if (RD == nullptr) {
1458    slangAssert(false && "struct is not defined in this module");
1459    return nullptr;
1460  }
1461
1462  // Struct layout construct by clang. We rely on this for obtaining the
1463  // alloc size of a struct and offset of every field in that struct.
1464  const clang::ASTRecordLayout *RL =
1465      &Context->getASTContext().getASTRecordLayout(RD);
1466  slangAssert((RL != nullptr) &&
1467      "Failed to retrieve the struct layout from Clang.");
1468
1469  RSExportRecordType *ERT =
1470      new RSExportRecordType(Context,
1471                             TypeName,
1472                             RD->hasAttr<clang::PackedAttr>(),
1473                             mIsArtificial,
1474                             RL->getDataSize().getQuantity(),
1475                             RL->getSize().getQuantity());
1476  unsigned int Index = 0;
1477
1478  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1479           FE = RD->field_end();
1480       FI != FE;
1481       FI++, Index++) {
1482
1483    // FIXME: All fields should be primitive type
1484    slangAssert(FI->getKind() == clang::Decl::Field);
1485    clang::FieldDecl *FD = *FI;
1486
1487    if (FD->isBitField()) {
1488      return nullptr;
1489    }
1490
1491    // Type
1492    RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD);
1493
1494    if (ET != nullptr) {
1495      ERT->mFields.push_back(
1496          new Field(ET, FD->getName(), ERT,
1497                    static_cast<size_t>(RL->getFieldOffset(Index) >> 3)));
1498    } else {
1499      Context->ReportError(RD->getLocation(),
1500                           "field type cannot be exported: '%0.%1'")
1501          << RD->getName() << FD->getName();
1502      return nullptr;
1503    }
1504  }
1505
1506  return ERT;
1507}
1508
1509llvm::Type *RSExportRecordType::convertToLLVMType() const {
1510  // Create an opaque type since struct may reference itself recursively.
1511
1512  // TODO(sliao): LLVM took out the OpaqueType. Any other to migrate to?
1513  std::vector<llvm::Type*> FieldTypes;
1514
1515  for (const_field_iterator FI = fields_begin(), FE = fields_end();
1516       FI != FE;
1517       FI++) {
1518    const Field *F = *FI;
1519    const RSExportType *FET = F->getType();
1520
1521    FieldTypes.push_back(FET->getLLVMType());
1522  }
1523
1524  llvm::StructType *ST = llvm::StructType::get(getRSContext()->getLLVMContext(),
1525                                               FieldTypes,
1526                                               mIsPacked);
1527  if (ST != nullptr) {
1528    return ST;
1529  } else {
1530    return nullptr;
1531  }
1532}
1533
1534bool RSExportRecordType::keep() {
1535  if (!RSExportType::keep())
1536    return false;
1537  for (std::list<const Field*>::iterator I = mFields.begin(),
1538          E = mFields.end();
1539       I != E;
1540       I++) {
1541    const_cast<RSExportType*>((*I)->getType())->keep();
1542  }
1543  return true;
1544}
1545
1546bool RSExportRecordType::equals(const RSExportable *E) const {
1547  CHECK_PARENT_EQUALITY(RSExportType, E);
1548
1549  const RSExportRecordType *ERT = static_cast<const RSExportRecordType*>(E);
1550
1551  if (ERT->getFields().size() != getFields().size())
1552    return false;
1553
1554  const_field_iterator AI = fields_begin(), BI = ERT->fields_begin();
1555
1556  for (unsigned i = 0, e = getFields().size(); i != e; i++) {
1557    if (!(*AI)->getType()->equals((*BI)->getType()))
1558      return false;
1559    AI++;
1560    BI++;
1561  }
1562
1563  return true;
1564}
1565
1566void RSExportType::convertToRTD(RSReflectionTypeData *rtd) const {
1567    memset(rtd, 0, sizeof(*rtd));
1568    rtd->vecSize = 1;
1569
1570    switch(getClass()) {
1571    case RSExportType::ExportClassPrimitive: {
1572            const RSExportPrimitiveType *EPT = static_cast<const RSExportPrimitiveType*>(this);
1573            rtd->type = RSExportPrimitiveType::getRSReflectionType(EPT);
1574            return;
1575        }
1576    case RSExportType::ExportClassPointer: {
1577            const RSExportPointerType *EPT = static_cast<const RSExportPointerType*>(this);
1578            const RSExportType *PointeeType = EPT->getPointeeType();
1579            PointeeType->convertToRTD(rtd);
1580            rtd->isPointer = true;
1581            return;
1582        }
1583    case RSExportType::ExportClassVector: {
1584            const RSExportVectorType *EVT = static_cast<const RSExportVectorType*>(this);
1585            rtd->type = EVT->getRSReflectionType(EVT);
1586            rtd->vecSize = EVT->getNumElement();
1587            return;
1588        }
1589    case RSExportType::ExportClassMatrix: {
1590            const RSExportMatrixType *EMT = static_cast<const RSExportMatrixType*>(this);
1591            unsigned Dim = EMT->getDim();
1592            slangAssert((Dim >= 2) && (Dim <= 4));
1593            rtd->type = &gReflectionTypes[15 + Dim-2];
1594            return;
1595        }
1596    case RSExportType::ExportClassConstantArray: {
1597            const RSExportConstantArrayType* CAT =
1598              static_cast<const RSExportConstantArrayType*>(this);
1599            CAT->getElementType()->convertToRTD(rtd);
1600            rtd->arraySize = CAT->getSize();
1601            return;
1602        }
1603    case RSExportType::ExportClassRecord: {
1604            slangAssert(!"RSExportType::ExportClassRecord not implemented");
1605            return;// RS_TYPE_CLASS_NAME_PREFIX + ET->getName() + ".Item";
1606        }
1607    default: {
1608            slangAssert(false && "Unknown class of type");
1609        }
1610    }
1611}
1612
1613
1614}  // namespace slang
1615