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