slang_rs_export_type.cpp revision 43730fe3c839af391efe6bdf56b0479860121924
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::VarDecl *VD,
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 (VD) {
111    DiagEngine->Report(
112      clang::FullSourceLoc(VD->getLocation(), SM),
113      DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, Message))
114      << VD->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->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 ValidateVarDecl(). 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// VD - top-level variable declaration that we are validating.
365// T - sub-type of VD's type that we are validating.
366// SPS - set of types we have already seen/validated.
367// InCompositeType - true if we are within an outer composite type.
368// UnionDecl - set if we are in a sub-type of a union.
369// TargetAPI - target SDK API level.
370static bool ValidateVarDeclHelper(
371    clang::VarDecl *VD,
372    const clang::Type *&T,
373    llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
374    bool InCompositeType,
375    clang::RecordDecl *UnionDecl,
376    unsigned int TargetAPI) {
377  if ((T = GET_CANONICAL_TYPE(T)) == NULL)
378    return true;
379
380  if (SPS.count(T))
381    return true;
382
383  switch (T->getTypeClass()) {
384    case clang::Type::Record: {
385      if (RSExportPrimitiveType::IsRSObjectType(T)) {
386        if (!ValidateRSObjectInVarDecl(VD, InCompositeType, TargetAPI)) {
387          return false;
388        }
389      }
390
391      if (RSExportPrimitiveType::GetRSSpecificType(T) !=
392          RSExportPrimitiveType::DataTypeUnknown) {
393        if (!UnionDecl) {
394          return true;
395        } else if (RSExportPrimitiveType::IsRSObjectType(T)) {
396          clang::ASTContext &C = VD->getASTContext();
397          ReportTypeError(&C.getDiagnostics(), VD, UnionDecl,
398              "unions containing RS object types are not allowed");
399          return false;
400        }
401      }
402
403      clang::RecordDecl *RD = NULL;
404
405      // Check internal struct
406      if (T->isUnionType()) {
407        RD = T->getAsUnionType()->getDecl();
408        UnionDecl = RD;
409      } else if (T->isStructureType()) {
410        RD = T->getAsStructureType()->getDecl();
411      } else {
412        slangAssert(false && "Unknown type cannot be exported");
413        return false;
414      }
415
416      if (RD != NULL) {
417        RD = RD->getDefinition();
418        if (RD == NULL) {
419          // FIXME
420          return true;
421        }
422      }
423
424      // Fast check
425      if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
426        return false;
427
428      // Insert myself into checking set
429      SPS.insert(T);
430
431      // Check all elements
432      for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
433               FE = RD->field_end();
434           FI != FE;
435           FI++) {
436        const clang::FieldDecl *FD = *FI;
437        const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
438        FT = GET_CANONICAL_TYPE(FT);
439
440        if (!ValidateVarDeclHelper(VD, FT, SPS, true, UnionDecl, TargetAPI)) {
441          return false;
442        }
443      }
444
445      return true;
446    }
447
448    case clang::Type::Builtin: {
449      break;
450    }
451
452    case clang::Type::Pointer: {
453      const clang::PointerType *PT =
454        UNSAFE_CAST_TYPE(const clang::PointerType, T);
455      const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
456
457      return ValidateVarDeclHelper(VD, PointeeType, SPS, InCompositeType,
458                                   UnionDecl, TargetAPI);
459    }
460
461    case clang::Type::ExtVector: {
462      const clang::ExtVectorType *EVT =
463          UNSAFE_CAST_TYPE(const clang::ExtVectorType, T);
464      const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
465      return ValidateVarDeclHelper(VD, ElementType, SPS, true, UnionDecl,
466                                   TargetAPI);
467    }
468
469    case clang::Type::ConstantArray: {
470      const clang::ConstantArrayType *CAT =
471          UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T);
472      const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
473      return ValidateVarDeclHelper(VD, ElementType, SPS, true, UnionDecl,
474                                   TargetAPI);
475    }
476
477    default: {
478      break;
479    }
480  }
481
482  return true;
483}
484
485}  // namespace
486
487/****************************** RSExportType ******************************/
488bool RSExportType::NormalizeType(const clang::Type *&T,
489                                 llvm::StringRef &TypeName,
490                                 clang::DiagnosticsEngine *DiagEngine,
491                                 const clang::VarDecl *VD) {
492  if ((T = TypeExportable(T, DiagEngine, VD)) == NULL) {
493    return false;
494  }
495  // Get type name
496  TypeName = RSExportType::GetTypeName(T);
497  if (TypeName.empty()) {
498    if (DiagEngine) {
499      if (VD) {
500        DiagEngine->Report(
501          clang::FullSourceLoc(VD->getLocation(),
502                               DiagEngine->getSourceManager()),
503          DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
504                                      "anonymous types cannot be exported"));
505      } else {
506        DiagEngine->Report(
507          DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
508                                      "anonymous types cannot be exported"));
509      }
510    }
511    return false;
512  }
513
514  return true;
515}
516
517bool RSExportType::ValidateVarDecl(clang::VarDecl *VD, unsigned int TargetAPI) {
518  const clang::Type *T = VD->getType().getTypePtr();
519  llvm::SmallPtrSet<const clang::Type*, 8> SPS =
520      llvm::SmallPtrSet<const clang::Type*, 8>();
521
522  return ValidateVarDeclHelper(VD, T, SPS, false, NULL, TargetAPI);
523}
524
525const clang::Type
526*RSExportType::GetTypeOfDecl(const clang::DeclaratorDecl *DD) {
527  if (DD) {
528    clang::QualType T;
529    if (DD->getTypeSourceInfo())
530      T = DD->getTypeSourceInfo()->getType();
531    else
532      T = DD->getType();
533
534    if (T.isNull())
535      return NULL;
536    else
537      return T.getTypePtr();
538  }
539  return NULL;
540}
541
542llvm::StringRef RSExportType::GetTypeName(const clang::Type* T) {
543  T = GET_CANONICAL_TYPE(T);
544  if (T == NULL)
545    return llvm::StringRef();
546
547  switch (T->getTypeClass()) {
548    case clang::Type::Builtin: {
549      const clang::BuiltinType *BT =
550        UNSAFE_CAST_TYPE(const clang::BuiltinType, T);
551
552      switch (BT->getKind()) {
553#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
554        case builtin_type:                                    \
555          return cname;                                       \
556        break;
557#include "RSClangBuiltinEnums.inc"
558        default: {
559          slangAssert(false && "Unknown data type of the builtin");
560          break;
561        }
562      }
563      break;
564    }
565    case clang::Type::Record: {
566      clang::RecordDecl *RD;
567      if (T->isStructureType()) {
568        RD = T->getAsStructureType()->getDecl();
569      } else {
570        break;
571      }
572
573      llvm::StringRef Name = RD->getName();
574      if (Name.empty()) {
575        if (RD->getTypedefNameForAnonDecl() != NULL) {
576          Name = RD->getTypedefNameForAnonDecl()->getName();
577        }
578
579        if (Name.empty()) {
580          // Try to find a name from redeclaration (i.e. typedef)
581          for (clang::TagDecl::redecl_iterator RI = RD->redecls_begin(),
582                   RE = RD->redecls_end();
583               RI != RE;
584               RI++) {
585            slangAssert(*RI != NULL && "cannot be NULL object");
586
587            Name = (*RI)->getName();
588            if (!Name.empty())
589              break;
590          }
591        }
592      }
593      return Name;
594    }
595    case clang::Type::Pointer: {
596      // "*" plus pointee name
597      const clang::Type *PT = GET_POINTEE_TYPE(T);
598      llvm::StringRef PointeeName;
599      if (NormalizeType(PT, PointeeName, NULL, NULL)) {
600        char *Name = new char[ 1 /* * */ + PointeeName.size() + 1 ];
601        Name[0] = '*';
602        memcpy(Name + 1, PointeeName.data(), PointeeName.size());
603        Name[PointeeName.size() + 1] = '\0';
604        return Name;
605      }
606      break;
607    }
608    case clang::Type::ExtVector: {
609      const clang::ExtVectorType *EVT =
610          UNSAFE_CAST_TYPE(const clang::ExtVectorType, T);
611      return RSExportVectorType::GetTypeName(EVT);
612      break;
613    }
614    case clang::Type::ConstantArray : {
615      // Construct name for a constant array is too complicated.
616      return DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE;
617    }
618    default: {
619      break;
620    }
621  }
622
623  return llvm::StringRef();
624}
625
626
627RSExportType *RSExportType::Create(RSContext *Context,
628                                   const clang::Type *T,
629                                   const llvm::StringRef &TypeName) {
630  // Lookup the context to see whether the type was processed before.
631  // Newly created RSExportType will insert into context
632  // in RSExportType::RSExportType()
633  RSContext::export_type_iterator ETI = Context->findExportType(TypeName);
634
635  if (ETI != Context->export_types_end())
636    return ETI->second;
637
638  RSExportType *ET = NULL;
639  switch (T->getTypeClass()) {
640    case clang::Type::Record: {
641      RSExportPrimitiveType::DataType dt =
642          RSExportPrimitiveType::GetRSSpecificType(TypeName);
643      switch (dt) {
644        case RSExportPrimitiveType::DataTypeUnknown: {
645          // User-defined types
646          ET = RSExportRecordType::Create(Context,
647                                          T->getAsStructureType(),
648                                          TypeName);
649          break;
650        }
651        case RSExportPrimitiveType::DataTypeRSMatrix2x2: {
652          // 2 x 2 Matrix type
653          ET = RSExportMatrixType::Create(Context,
654                                          T->getAsStructureType(),
655                                          TypeName,
656                                          2);
657          break;
658        }
659        case RSExportPrimitiveType::DataTypeRSMatrix3x3: {
660          // 3 x 3 Matrix type
661          ET = RSExportMatrixType::Create(Context,
662                                          T->getAsStructureType(),
663                                          TypeName,
664                                          3);
665          break;
666        }
667        case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
668          // 4 x 4 Matrix type
669          ET = RSExportMatrixType::Create(Context,
670                                          T->getAsStructureType(),
671                                          TypeName,
672                                          4);
673          break;
674        }
675        default: {
676          // Others are primitive types
677          ET = RSExportPrimitiveType::Create(Context, T, TypeName);
678          break;
679        }
680      }
681      break;
682    }
683    case clang::Type::Builtin: {
684      ET = RSExportPrimitiveType::Create(Context, T, TypeName);
685      break;
686    }
687    case clang::Type::Pointer: {
688      ET = RSExportPointerType::Create(Context,
689               UNSAFE_CAST_TYPE(const clang::PointerType, T), TypeName);
690      // FIXME: free the name (allocated in RSExportType::GetTypeName)
691      delete [] TypeName.data();
692      break;
693    }
694    case clang::Type::ExtVector: {
695      ET = RSExportVectorType::Create(Context,
696               UNSAFE_CAST_TYPE(const clang::ExtVectorType, T), TypeName);
697      break;
698    }
699    case clang::Type::ConstantArray: {
700      ET = RSExportConstantArrayType::Create(
701              Context,
702              UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T));
703      break;
704    }
705    default: {
706      clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
707      DiagEngine->Report(
708        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
709                                    "unknown type cannot be exported: '%0'"))
710        << T->getTypeClassName();
711      break;
712    }
713  }
714
715  return ET;
716}
717
718RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) {
719  llvm::StringRef TypeName;
720  if (NormalizeType(T, TypeName, Context->getDiagnostics(), NULL)) {
721    return Create(Context, T, TypeName);
722  } else {
723    return NULL;
724  }
725}
726
727RSExportType *RSExportType::CreateFromDecl(RSContext *Context,
728                                           const clang::VarDecl *VD) {
729  return RSExportType::Create(Context, GetTypeOfDecl(VD));
730}
731
732size_t RSExportType::GetTypeStoreSize(const RSExportType *ET) {
733  return ET->getRSContext()->getTargetData()->getTypeStoreSize(
734      ET->getLLVMType());
735}
736
737size_t RSExportType::GetTypeAllocSize(const RSExportType *ET) {
738  if (ET->getClass() == RSExportType::ExportClassRecord)
739    return static_cast<const RSExportRecordType*>(ET)->getAllocSize();
740  else
741    return ET->getRSContext()->getTargetData()->getTypeAllocSize(
742        ET->getLLVMType());
743}
744
745RSExportType::RSExportType(RSContext *Context,
746                           ExportClass Class,
747                           const llvm::StringRef &Name)
748    : RSExportable(Context, RSExportable::EX_TYPE),
749      mClass(Class),
750      // Make a copy on Name since memory stored @Name is either allocated in
751      // ASTContext or allocated in GetTypeName which will be destroyed later.
752      mName(Name.data(), Name.size()),
753      mLLVMType(NULL),
754      mSpecType(NULL) {
755  // Don't cache the type whose name start with '<'. Those type failed to
756  // get their name since constructing their name in GetTypeName() requiring
757  // complicated work.
758  if (!Name.startswith(DUMMY_RS_TYPE_NAME_PREFIX))
759    // TODO(zonr): Need to check whether the insertion is successful or not.
760    Context->insertExportType(llvm::StringRef(Name), this);
761  return;
762}
763
764bool RSExportType::keep() {
765  if (!RSExportable::keep())
766    return false;
767  // Invalidate converted LLVM type.
768  mLLVMType = NULL;
769  return true;
770}
771
772bool RSExportType::equals(const RSExportable *E) const {
773  CHECK_PARENT_EQUALITY(RSExportable, E);
774  return (static_cast<const RSExportType*>(E)->getClass() == getClass());
775}
776
777RSExportType::~RSExportType() {
778  delete mSpecType;
779}
780
781/************************** RSExportPrimitiveType **************************/
782llvm::ManagedStatic<RSExportPrimitiveType::RSSpecificTypeMapTy>
783RSExportPrimitiveType::RSSpecificTypeMap;
784
785llvm::Type *RSExportPrimitiveType::RSObjectLLVMType = NULL;
786
787bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) {
788  if ((T != NULL) && (T->getTypeClass() == clang::Type::Builtin))
789    return true;
790  else
791    return false;
792}
793
794RSExportPrimitiveType::DataType
795RSExportPrimitiveType::GetRSSpecificType(const llvm::StringRef &TypeName) {
796  if (TypeName.empty())
797    return DataTypeUnknown;
798
799  if (RSSpecificTypeMap->empty()) {
800#define ENUM_RS_MATRIX_TYPE(type, cname, dim)                       \
801    RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type);
802#include "RSMatrixTypeEnums.inc"
803#define ENUM_RS_OBJECT_TYPE(type, cname)                            \
804    RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type);
805#include "RSObjectTypeEnums.inc"
806  }
807
808  RSSpecificTypeMapTy::const_iterator I = RSSpecificTypeMap->find(TypeName);
809  if (I == RSSpecificTypeMap->end())
810    return DataTypeUnknown;
811  else
812    return I->getValue();
813}
814
815RSExportPrimitiveType::DataType
816RSExportPrimitiveType::GetRSSpecificType(const clang::Type *T) {
817  T = GET_CANONICAL_TYPE(T);
818  if ((T == NULL) || (T->getTypeClass() != clang::Type::Record))
819    return DataTypeUnknown;
820
821  return GetRSSpecificType( RSExportType::GetTypeName(T) );
822}
823
824bool RSExportPrimitiveType::IsRSMatrixType(DataType DT) {
825  return ((DT >= FirstRSMatrixType) && (DT <= LastRSMatrixType));
826}
827
828bool RSExportPrimitiveType::IsRSObjectType(DataType DT) {
829  return ((DT >= FirstRSObjectType) && (DT <= LastRSObjectType));
830}
831
832bool RSExportPrimitiveType::IsStructureTypeWithRSObject(const clang::Type *T) {
833  bool RSObjectTypeSeen = false;
834  while (T && T->isArrayType()) {
835    T = T->getArrayElementTypeNoTypeQual();
836  }
837
838  const clang::RecordType *RT = T->getAsStructureType();
839  if (!RT) {
840    return false;
841  }
842  const clang::RecordDecl *RD = RT->getDecl();
843  RD = RD->getDefinition();
844  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
845         FE = RD->field_end();
846       FI != FE;
847       FI++) {
848    // We just look through all field declarations to see if we find a
849    // declaration for an RS object type (or an array of one).
850    const clang::FieldDecl *FD = *FI;
851    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
852    while (FT && FT->isArrayType()) {
853      FT = FT->getArrayElementTypeNoTypeQual();
854    }
855
856    RSExportPrimitiveType::DataType DT = GetRSSpecificType(FT);
857    if (IsRSObjectType(DT)) {
858      // RS object types definitely need to be zero-initialized
859      RSObjectTypeSeen = true;
860    } else {
861      switch (DT) {
862        case RSExportPrimitiveType::DataTypeRSMatrix2x2:
863        case RSExportPrimitiveType::DataTypeRSMatrix3x3:
864        case RSExportPrimitiveType::DataTypeRSMatrix4x4:
865          // Matrix types should get zero-initialized as well
866          RSObjectTypeSeen = true;
867          break;
868        default:
869          // Ignore all other primitive types
870          break;
871      }
872      while (FT && FT->isArrayType()) {
873        FT = FT->getArrayElementTypeNoTypeQual();
874      }
875      if (FT->isStructureType()) {
876        // Recursively handle structs of structs (even though these can't
877        // be exported, it is possible for a user to have them internally).
878        RSObjectTypeSeen |= IsStructureTypeWithRSObject(FT);
879      }
880    }
881  }
882
883  return RSObjectTypeSeen;
884}
885
886const size_t RSExportPrimitiveType::SizeOfDataTypeInBits[] = {
887#define ENUM_RS_DATA_TYPE(type, cname, bits)  \
888  bits,
889#include "RSDataTypeEnums.inc"
890  0   // DataTypeMax
891};
892
893size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) {
894  slangAssert(((EPT->getType() > DataTypeUnknown) &&
895               (EPT->getType() < DataTypeMax)) &&
896              "RSExportPrimitiveType::GetSizeInBits : unknown data type");
897  return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ];
898}
899
900RSExportPrimitiveType::DataType
901RSExportPrimitiveType::GetDataType(RSContext *Context, const clang::Type *T) {
902  if (T == NULL)
903    return DataTypeUnknown;
904
905  switch (T->getTypeClass()) {
906    case clang::Type::Builtin: {
907      const clang::BuiltinType *BT =
908        UNSAFE_CAST_TYPE(const clang::BuiltinType, T);
909      switch (BT->getKind()) {
910#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
911        case builtin_type: {                                  \
912          return DataType ## type;                            \
913        }
914#include "RSClangBuiltinEnums.inc"
915        // The size of type WChar depend on platform so we abandon the support
916        // to them.
917        default: {
918          clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
919          DiagEngine->Report(
920            DiagEngine->getCustomDiagID(
921              clang::DiagnosticsEngine::Error,
922              "built-in type cannot be exported: '%0'"))
923            << T->getTypeClassName();
924          break;
925        }
926      }
927      break;
928    }
929    case clang::Type::Record: {
930      // must be RS object type
931      return RSExportPrimitiveType::GetRSSpecificType(T);
932    }
933    default: {
934      clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
935      DiagEngine->Report(
936        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
937                                    "primitive type cannot be exported: '%0'"))
938          << T->getTypeClassName();
939      break;
940    }
941  }
942
943  return DataTypeUnknown;
944}
945
946RSExportPrimitiveType
947*RSExportPrimitiveType::Create(RSContext *Context,
948                               const clang::Type *T,
949                               const llvm::StringRef &TypeName,
950                               bool Normalized) {
951  DataType DT = GetDataType(Context, T);
952
953  if ((DT == DataTypeUnknown) || TypeName.empty())
954    return NULL;
955  else
956    return new RSExportPrimitiveType(Context, ExportClassPrimitive, TypeName,
957                                     DT, Normalized);
958}
959
960RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context,
961                                                     const clang::Type *T) {
962  llvm::StringRef TypeName;
963  if (RSExportType::NormalizeType(T, TypeName, Context->getDiagnostics(), NULL)
964      && IsPrimitiveType(T)) {
965    return Create(Context, T, TypeName);
966  } else {
967    return NULL;
968  }
969}
970
971llvm::Type *RSExportPrimitiveType::convertToLLVMType() const {
972  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
973
974  if (isRSObjectType()) {
975    // struct {
976    //   int *p;
977    // } __attribute__((packed, aligned(pointer_size)))
978    //
979    // which is
980    //
981    // <{ [1 x i32] }> in LLVM
982    //
983    if (RSObjectLLVMType == NULL) {
984      std::vector<llvm::Type *> Elements;
985      Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1));
986      RSObjectLLVMType = llvm::StructType::get(C, Elements, true);
987    }
988    return RSObjectLLVMType;
989  }
990
991  switch (mType) {
992    case DataTypeFloat32: {
993      return llvm::Type::getFloatTy(C);
994      break;
995    }
996    case DataTypeFloat64: {
997      return llvm::Type::getDoubleTy(C);
998      break;
999    }
1000    case DataTypeBoolean: {
1001      return llvm::Type::getInt1Ty(C);
1002      break;
1003    }
1004    case DataTypeSigned8:
1005    case DataTypeUnsigned8: {
1006      return llvm::Type::getInt8Ty(C);
1007      break;
1008    }
1009    case DataTypeSigned16:
1010    case DataTypeUnsigned16:
1011    case DataTypeUnsigned565:
1012    case DataTypeUnsigned5551:
1013    case DataTypeUnsigned4444: {
1014      return llvm::Type::getInt16Ty(C);
1015      break;
1016    }
1017    case DataTypeSigned32:
1018    case DataTypeUnsigned32: {
1019      return llvm::Type::getInt32Ty(C);
1020      break;
1021    }
1022    case DataTypeSigned64:
1023    case DataTypeUnsigned64: {
1024      return llvm::Type::getInt64Ty(C);
1025      break;
1026    }
1027    default: {
1028      slangAssert(false && "Unknown data type");
1029    }
1030  }
1031
1032  return NULL;
1033}
1034
1035union RSType *RSExportPrimitiveType::convertToSpecType() const {
1036  llvm::OwningPtr<union RSType> ST(new union RSType);
1037  RS_TYPE_SET_CLASS(ST, RS_TC_Primitive);
1038  // enum RSExportPrimitiveType::DataType is synced with enum RSDataType in
1039  // slang_rs_type_spec.h
1040  RS_PRIMITIVE_TYPE_SET_DATA_TYPE(ST, getType());
1041  return ST.take();
1042}
1043
1044bool RSExportPrimitiveType::equals(const RSExportable *E) const {
1045  CHECK_PARENT_EQUALITY(RSExportType, E);
1046  return (static_cast<const RSExportPrimitiveType*>(E)->getType() == getType());
1047}
1048
1049RSReflectionType *RSExportPrimitiveType::getRSReflectionType(DataType DT) {
1050  if (DT > DataTypeUnknown && DT < DataTypeMax) {
1051    return &gReflectionTypes[DT];
1052  } else {
1053    return NULL;
1054  }
1055}
1056
1057/**************************** RSExportPointerType ****************************/
1058
1059RSExportPointerType
1060*RSExportPointerType::Create(RSContext *Context,
1061                             const clang::PointerType *PT,
1062                             const llvm::StringRef &TypeName) {
1063  const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
1064  const RSExportType *PointeeET;
1065
1066  if (PointeeType->getTypeClass() != clang::Type::Pointer) {
1067    PointeeET = RSExportType::Create(Context, PointeeType);
1068  } else {
1069    // Double or higher dimension of pointer, export as int*
1070    PointeeET = RSExportPrimitiveType::Create(Context,
1071                    Context->getASTContext().IntTy.getTypePtr());
1072  }
1073
1074  if (PointeeET == NULL) {
1075    // Error diagnostic is emitted for corresponding pointee type
1076    return NULL;
1077  }
1078
1079  return new RSExportPointerType(Context, TypeName, PointeeET);
1080}
1081
1082llvm::Type *RSExportPointerType::convertToLLVMType() const {
1083  llvm::Type *PointeeType = mPointeeType->getLLVMType();
1084  return llvm::PointerType::getUnqual(PointeeType);
1085}
1086
1087union RSType *RSExportPointerType::convertToSpecType() const {
1088  llvm::OwningPtr<union RSType> ST(new union RSType);
1089
1090  RS_TYPE_SET_CLASS(ST, RS_TC_Pointer);
1091  RS_POINTER_TYPE_SET_POINTEE_TYPE(ST, getPointeeType()->getSpecType());
1092
1093  if (RS_POINTER_TYPE_GET_POINTEE_TYPE(ST) != NULL)
1094    return ST.take();
1095  else
1096    return NULL;
1097}
1098
1099bool RSExportPointerType::keep() {
1100  if (!RSExportType::keep())
1101    return false;
1102  const_cast<RSExportType*>(mPointeeType)->keep();
1103  return true;
1104}
1105
1106bool RSExportPointerType::equals(const RSExportable *E) const {
1107  CHECK_PARENT_EQUALITY(RSExportType, E);
1108  return (static_cast<const RSExportPointerType*>(E)
1109              ->getPointeeType()->equals(getPointeeType()));
1110}
1111
1112/***************************** RSExportVectorType *****************************/
1113llvm::StringRef
1114RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) {
1115  const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
1116
1117  if ((ElementType->getTypeClass() != clang::Type::Builtin))
1118    return llvm::StringRef();
1119
1120  const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(const clang::BuiltinType,
1121                                                  ElementType);
1122  if ((EVT->getNumElements() < 1) ||
1123      (EVT->getNumElements() > 4))
1124    return llvm::StringRef();
1125
1126  switch (BT->getKind()) {
1127    // Compiler is smart enough to optimize following *big if branches* since
1128    // they all become "constant comparison" after macro expansion
1129#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
1130    case builtin_type: {                                      \
1131      const char *Name[] = { cname"2", cname"3", cname"4" };  \
1132      return Name[EVT->getNumElements() - 2];                 \
1133      break;                                                  \
1134    }
1135#include "RSClangBuiltinEnums.inc"
1136    default: {
1137      return llvm::StringRef();
1138    }
1139  }
1140}
1141
1142RSExportVectorType *RSExportVectorType::Create(RSContext *Context,
1143                                               const clang::ExtVectorType *EVT,
1144                                               const llvm::StringRef &TypeName,
1145                                               bool Normalized) {
1146  slangAssert(EVT != NULL && EVT->getTypeClass() == clang::Type::ExtVector);
1147
1148  const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
1149  RSExportPrimitiveType::DataType DT =
1150      RSExportPrimitiveType::GetDataType(Context, ElementType);
1151
1152  if (DT != RSExportPrimitiveType::DataTypeUnknown)
1153    return new RSExportVectorType(Context,
1154                                  TypeName,
1155                                  DT,
1156                                  Normalized,
1157                                  EVT->getNumElements());
1158  else
1159    return NULL;
1160}
1161
1162llvm::Type *RSExportVectorType::convertToLLVMType() const {
1163  llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType();
1164  return llvm::VectorType::get(ElementType, getNumElement());
1165}
1166
1167union RSType *RSExportVectorType::convertToSpecType() const {
1168  llvm::OwningPtr<union RSType> ST(new union RSType);
1169
1170  RS_TYPE_SET_CLASS(ST, RS_TC_Vector);
1171  RS_VECTOR_TYPE_SET_ELEMENT_TYPE(ST, getType());
1172  RS_VECTOR_TYPE_SET_VECTOR_SIZE(ST, getNumElement());
1173
1174  return ST.take();
1175}
1176
1177bool RSExportVectorType::equals(const RSExportable *E) const {
1178  CHECK_PARENT_EQUALITY(RSExportPrimitiveType, E);
1179  return (static_cast<const RSExportVectorType*>(E)->getNumElement()
1180              == getNumElement());
1181}
1182
1183/***************************** RSExportMatrixType *****************************/
1184RSExportMatrixType *RSExportMatrixType::Create(RSContext *Context,
1185                                               const clang::RecordType *RT,
1186                                               const llvm::StringRef &TypeName,
1187                                               unsigned Dim) {
1188  slangAssert((RT != NULL) && (RT->getTypeClass() == clang::Type::Record));
1189  slangAssert((Dim > 1) && "Invalid dimension of matrix");
1190
1191  // Check whether the struct rs_matrix is in our expected form (but assume it's
1192  // correct if we're not sure whether it's correct or not)
1193  const clang::RecordDecl* RD = RT->getDecl();
1194  RD = RD->getDefinition();
1195  if (RD != NULL) {
1196    clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
1197    const clang::SourceManager *SM = Context->getSourceManager();
1198    // Find definition, perform further examination
1199    if (RD->field_empty()) {
1200      DiagEngine->Report(
1201        clang::FullSourceLoc(RD->getLocation(), *SM),
1202        DiagEngine->getCustomDiagID(
1203          clang::DiagnosticsEngine::Error,
1204          "invalid matrix struct: must have 1 field for saving values: '%0'"))
1205           << RD->getName();
1206      return NULL;
1207    }
1208
1209    clang::RecordDecl::field_iterator FIT = RD->field_begin();
1210    const clang::FieldDecl *FD = *FIT;
1211    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
1212    if ((FT == NULL) || (FT->getTypeClass() != clang::Type::ConstantArray)) {
1213      DiagEngine->Report(
1214        clang::FullSourceLoc(RD->getLocation(), *SM),
1215        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1216                                    "invalid matrix struct: first field should"
1217                                    " be an array with constant size: '%0'"))
1218        << RD->getName();
1219      return NULL;
1220    }
1221    const clang::ConstantArrayType *CAT =
1222      static_cast<const clang::ConstantArrayType *>(FT);
1223    const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
1224    if ((ElementType == NULL) ||
1225        (ElementType->getTypeClass() != clang::Type::Builtin) ||
1226        (static_cast<const clang::BuiltinType *>(ElementType)->getKind() !=
1227         clang::BuiltinType::Float)) {
1228      DiagEngine->Report(
1229        clang::FullSourceLoc(RD->getLocation(), *SM),
1230        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1231                                    "invalid matrix struct: first field "
1232                                    "should be a float array: '%0'"))
1233        << RD->getName();
1234      return NULL;
1235    }
1236
1237    if (CAT->getSize() != Dim * Dim) {
1238      DiagEngine->Report(
1239        clang::FullSourceLoc(RD->getLocation(), *SM),
1240        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1241                                    "invalid matrix struct: first field "
1242                                    "should be an array with size %0: '%1'"))
1243        << (Dim * Dim) << (RD->getName());
1244      return NULL;
1245    }
1246
1247    FIT++;
1248    if (FIT != RD->field_end()) {
1249      DiagEngine->Report(
1250        clang::FullSourceLoc(RD->getLocation(), *SM),
1251        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1252                                    "invalid matrix struct: must have "
1253                                    "exactly 1 field: '%0'"))
1254        << RD->getName();
1255      return NULL;
1256    }
1257  }
1258
1259  return new RSExportMatrixType(Context, TypeName, Dim);
1260}
1261
1262llvm::Type *RSExportMatrixType::convertToLLVMType() const {
1263  // Construct LLVM type:
1264  // struct {
1265  //  float X[mDim * mDim];
1266  // }
1267
1268  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
1269  llvm::ArrayType *X = llvm::ArrayType::get(llvm::Type::getFloatTy(C),
1270                                            mDim * mDim);
1271  return llvm::StructType::get(C, X, false);
1272}
1273
1274union RSType *RSExportMatrixType::convertToSpecType() const {
1275  llvm::OwningPtr<union RSType> ST(new union RSType);
1276  RS_TYPE_SET_CLASS(ST, RS_TC_Matrix);
1277  switch (getDim()) {
1278    case 2: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix2x2); break;
1279    case 3: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix3x3); break;
1280    case 4: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix4x4); break;
1281    default: slangAssert(false && "Matrix type with unsupported dimension.");
1282  }
1283  return ST.take();
1284}
1285
1286bool RSExportMatrixType::equals(const RSExportable *E) const {
1287  CHECK_PARENT_EQUALITY(RSExportType, E);
1288  return (static_cast<const RSExportMatrixType*>(E)->getDim() == getDim());
1289}
1290
1291/************************* RSExportConstantArrayType *************************/
1292RSExportConstantArrayType
1293*RSExportConstantArrayType::Create(RSContext *Context,
1294                                   const clang::ConstantArrayType *CAT) {
1295  slangAssert(CAT != NULL && CAT->getTypeClass() == clang::Type::ConstantArray);
1296
1297  slangAssert((CAT->getSize().getActiveBits() < 32) && "array too large");
1298
1299  unsigned Size = static_cast<unsigned>(CAT->getSize().getZExtValue());
1300  slangAssert((Size > 0) && "Constant array should have size greater than 0");
1301
1302  const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
1303  RSExportType *ElementET = RSExportType::Create(Context, ElementType);
1304
1305  if (ElementET == NULL) {
1306    return NULL;
1307  }
1308
1309  return new RSExportConstantArrayType(Context,
1310                                       ElementET,
1311                                       Size);
1312}
1313
1314llvm::Type *RSExportConstantArrayType::convertToLLVMType() const {
1315  return llvm::ArrayType::get(mElementType->getLLVMType(), getSize());
1316}
1317
1318union RSType *RSExportConstantArrayType::convertToSpecType() const {
1319  llvm::OwningPtr<union RSType> ST(new union RSType);
1320
1321  RS_TYPE_SET_CLASS(ST, RS_TC_ConstantArray);
1322  RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_TYPE(
1323      ST, getElementType()->getSpecType());
1324  RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_SIZE(ST, getSize());
1325
1326  if (RS_CONSTANT_ARRAY_TYPE_GET_ELEMENT_TYPE(ST) != NULL)
1327    return ST.take();
1328  else
1329    return NULL;
1330}
1331
1332bool RSExportConstantArrayType::keep() {
1333  if (!RSExportType::keep())
1334    return false;
1335  const_cast<RSExportType*>(mElementType)->keep();
1336  return true;
1337}
1338
1339bool RSExportConstantArrayType::equals(const RSExportable *E) const {
1340  CHECK_PARENT_EQUALITY(RSExportType, E);
1341  const RSExportConstantArrayType *RHS =
1342      static_cast<const RSExportConstantArrayType*>(E);
1343  return ((getSize() == RHS->getSize()) &&
1344          (getElementType()->equals(RHS->getElementType())));
1345}
1346
1347/**************************** RSExportRecordType ****************************/
1348RSExportRecordType *RSExportRecordType::Create(RSContext *Context,
1349                                               const clang::RecordType *RT,
1350                                               const llvm::StringRef &TypeName,
1351                                               bool mIsArtificial) {
1352  slangAssert(RT != NULL && RT->getTypeClass() == clang::Type::Record);
1353
1354  const clang::RecordDecl *RD = RT->getDecl();
1355  slangAssert(RD->isStruct());
1356
1357  RD = RD->getDefinition();
1358  if (RD == NULL) {
1359    slangAssert(false && "struct is not defined in this module");
1360    return NULL;
1361  }
1362
1363  // Struct layout construct by clang. We rely on this for obtaining the
1364  // alloc size of a struct and offset of every field in that struct.
1365  const clang::ASTRecordLayout *RL =
1366      &Context->getASTContext().getASTRecordLayout(RD);
1367  slangAssert((RL != NULL) &&
1368      "Failed to retrieve the struct layout from Clang.");
1369
1370  RSExportRecordType *ERT =
1371      new RSExportRecordType(Context,
1372                             TypeName,
1373                             RD->hasAttr<clang::PackedAttr>(),
1374                             mIsArtificial,
1375                             RL->getSize().getQuantity());
1376  unsigned int Index = 0;
1377
1378  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1379           FE = RD->field_end();
1380       FI != FE;
1381       FI++, Index++) {
1382    clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
1383
1384    // FIXME: All fields should be primitive type
1385    slangAssert(FI->getKind() == clang::Decl::Field);
1386    clang::FieldDecl *FD = *FI;
1387
1388    if (FD->isBitField()) {
1389      return NULL;
1390    }
1391
1392    // Type
1393    RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD);
1394
1395    if (ET != NULL) {
1396      ERT->mFields.push_back(
1397          new Field(ET, FD->getName(), ERT,
1398                    static_cast<size_t>(RL->getFieldOffset(Index) >> 3)));
1399    } else {
1400      DiagEngine->Report(
1401        clang::FullSourceLoc(RD->getLocation(), DiagEngine->getSourceManager()),
1402        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1403                                    "field type cannot be exported: '%0.%1'"))
1404        << RD->getName() << FD->getName();
1405      return NULL;
1406    }
1407  }
1408
1409  return ERT;
1410}
1411
1412llvm::Type *RSExportRecordType::convertToLLVMType() const {
1413  // Create an opaque type since struct may reference itself recursively.
1414
1415  // TODO(sliao): LLVM took out the OpaqueType. Any other to migrate to?
1416  std::vector<llvm::Type*> FieldTypes;
1417
1418  for (const_field_iterator FI = fields_begin(), FE = fields_end();
1419       FI != FE;
1420       FI++) {
1421    const Field *F = *FI;
1422    const RSExportType *FET = F->getType();
1423
1424    FieldTypes.push_back(FET->getLLVMType());
1425  }
1426
1427  llvm::StructType *ST = llvm::StructType::get(getRSContext()->getLLVMContext(),
1428                                               FieldTypes,
1429                                               mIsPacked);
1430  if (ST != NULL) {
1431    return ST;
1432  } else {
1433    return NULL;
1434  }
1435}
1436
1437union RSType *RSExportRecordType::convertToSpecType() const {
1438  unsigned NumFields = getFields().size();
1439  unsigned AllocSize = sizeof(union RSType) +
1440                       sizeof(struct RSRecordField) * NumFields;
1441  llvm::OwningPtr<union RSType> ST(
1442      reinterpret_cast<union RSType*>(operator new(AllocSize)));
1443
1444  ::memset(ST.get(), 0, AllocSize);
1445
1446  RS_TYPE_SET_CLASS(ST, RS_TC_Record);
1447  RS_RECORD_TYPE_SET_NAME(ST, getName().c_str());
1448  RS_RECORD_TYPE_SET_NUM_FIELDS(ST, NumFields);
1449
1450  setSpecTypeTemporarily(ST.get());
1451
1452  unsigned FieldIdx = 0;
1453  for (const_field_iterator FI = fields_begin(), FE = fields_end();
1454       FI != FE;
1455       FI++, FieldIdx++) {
1456    const Field *F = *FI;
1457
1458    RS_RECORD_TYPE_SET_FIELD_NAME(ST, FieldIdx, F->getName().c_str());
1459    RS_RECORD_TYPE_SET_FIELD_TYPE(ST, FieldIdx, F->getType()->getSpecType());
1460  }
1461
1462  // TODO(slang): Check whether all fields were created normally.
1463
1464  return ST.take();
1465}
1466
1467bool RSExportRecordType::keep() {
1468  if (!RSExportType::keep())
1469    return false;
1470  for (std::list<const Field*>::iterator I = mFields.begin(),
1471          E = mFields.end();
1472       I != E;
1473       I++) {
1474    const_cast<RSExportType*>((*I)->getType())->keep();
1475  }
1476  return true;
1477}
1478
1479bool RSExportRecordType::equals(const RSExportable *E) const {
1480  CHECK_PARENT_EQUALITY(RSExportType, E);
1481
1482  const RSExportRecordType *ERT = static_cast<const RSExportRecordType*>(E);
1483
1484  if (ERT->getFields().size() != getFields().size())
1485    return false;
1486
1487  const_field_iterator AI = fields_begin(), BI = ERT->fields_begin();
1488
1489  for (unsigned i = 0, e = getFields().size(); i != e; i++) {
1490    if (!(*AI)->getType()->equals((*BI)->getType()))
1491      return false;
1492    AI++;
1493    BI++;
1494  }
1495
1496  return true;
1497}
1498
1499void RSExportType::convertToRTD(RSReflectionTypeData *rtd) const {
1500    memset(rtd, 0, sizeof(*rtd));
1501    rtd->vecSize = 1;
1502
1503    switch(getClass()) {
1504    case RSExportType::ExportClassPrimitive: {
1505            const RSExportPrimitiveType *EPT = static_cast<const RSExportPrimitiveType*>(this);
1506            rtd->type = RSExportPrimitiveType::getRSReflectionType(EPT);
1507            return;
1508        }
1509    case RSExportType::ExportClassPointer: {
1510            const RSExportPointerType *EPT = static_cast<const RSExportPointerType*>(this);
1511            const RSExportType *PointeeType = EPT->getPointeeType();
1512            PointeeType->convertToRTD(rtd);
1513            rtd->isPointer = true;
1514            return;
1515        }
1516    case RSExportType::ExportClassVector: {
1517            const RSExportVectorType *EVT = static_cast<const RSExportVectorType*>(this);
1518            rtd->type = EVT->getRSReflectionType(EVT);
1519            rtd->vecSize = EVT->getNumElement();
1520            return;
1521        }
1522    case RSExportType::ExportClassMatrix: {
1523            const RSExportMatrixType *EMT = static_cast<const RSExportMatrixType*>(this);
1524            unsigned Dim = EMT->getDim();
1525            slangAssert((Dim >= 2) && (Dim <= 4));
1526            rtd->type = &gReflectionTypes[15 + Dim-2];
1527            return;
1528        }
1529    case RSExportType::ExportClassConstantArray: {
1530            const RSExportConstantArrayType* CAT =
1531              static_cast<const RSExportConstantArrayType*>(this);
1532            CAT->getElementType()->convertToRTD(rtd);
1533            rtd->arraySize = CAT->getSize();
1534            return;
1535        }
1536    case RSExportType::ExportClassRecord: {
1537            slangAssert(!"RSExportType::ExportClassRecord not implemented");
1538            return;// RS_TYPE_CLASS_NAME_PREFIX + ET->getName() + ".Item";
1539        }
1540    default: {
1541            slangAssert(false && "Unknown class of type");
1542        }
1543    }
1544}
1545
1546
1547}  // namespace slang
1548