slang_rs_export_type.cpp revision 6e6578a360497f78a181e63d7783422a9c9bfb15
1/*
2 * Copyright 2010, 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/RecordLayout.h"
23
24#include "llvm/ADT/StringExtras.h"
25
26#include "llvm/DerivedTypes.h"
27
28#include "llvm/Target/TargetData.h"
29
30#include "llvm/Type.h"
31
32#include "slang_assert.h"
33#include "slang_rs_context.h"
34#include "slang_rs_export_element.h"
35#include "slang_rs_type_spec.h"
36
37#define CHECK_PARENT_EQUALITY(ParentClass, E) \
38  if (!ParentClass::equals(E))                \
39    return false;
40
41namespace slang {
42
43namespace {
44
45static const clang::Type *TypeExportableHelper(
46    const clang::Type *T,
47    llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
48    clang::Diagnostic *Diags,
49    clang::SourceManager *SM,
50    const clang::VarDecl *VD,
51    const clang::RecordDecl *TopLevelRecord);
52
53static void ReportTypeError(clang::Diagnostic *Diags,
54                            const clang::SourceManager *SM,
55                            const clang::VarDecl *VD,
56                            const clang::RecordDecl *TopLevelRecord,
57                            const char *Message) {
58  if (!Diags || !SM) {
59    return;
60  }
61
62  // Attempt to use the type declaration first (if we have one).
63  // Fall back to the variable definition, if we are looking at something
64  // like an array declaration that can't be exported.
65  if (TopLevelRecord) {
66    Diags->Report(clang::FullSourceLoc(TopLevelRecord->getLocation(), *SM),
67                  Diags->getCustomDiagID(clang::Diagnostic::Error, Message))
68         << TopLevelRecord->getName();
69  } else if (VD) {
70    Diags->Report(clang::FullSourceLoc(VD->getLocation(), *SM),
71                  Diags->getCustomDiagID(clang::Diagnostic::Error, Message))
72         << VD->getName();
73  } else {
74    slangAssert(false && "Variables should be validated before exporting");
75  }
76
77  return;
78}
79
80static const clang::Type *ConstantArrayTypeExportableHelper(
81    const clang::ConstantArrayType *CAT,
82    llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
83    clang::Diagnostic *Diags,
84    clang::SourceManager *SM,
85    const clang::VarDecl *VD,
86    const clang::RecordDecl *TopLevelRecord) {
87  // Check element type
88  const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
89  if (ElementType->isArrayType()) {
90    ReportTypeError(Diags, SM, VD, TopLevelRecord,
91        "multidimensional arrays cannot be exported: '%0'");
92    return NULL;
93  } else if (ElementType->isExtVectorType()) {
94    const clang::ExtVectorType *EVT =
95        static_cast<const clang::ExtVectorType*>(ElementType);
96    unsigned numElements = EVT->getNumElements();
97
98    const clang::Type *BaseElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
99    if (!RSExportPrimitiveType::IsPrimitiveType(BaseElementType)) {
100      ReportTypeError(Diags, SM, VD, TopLevelRecord,
101          "vectors of non-primitive types cannot be exported: '%0'");
102      return NULL;
103    }
104
105    if (numElements == 3 && CAT->getSize() != 1) {
106      ReportTypeError(Diags, SM, VD, TopLevelRecord,
107          "arrays of width 3 vector types cannot be exported: '%0'");
108      return NULL;
109    }
110  }
111
112  if (TypeExportableHelper(ElementType, SPS, Diags, SM, VD,
113                           TopLevelRecord) == NULL)
114    return NULL;
115  else
116    return CAT;
117}
118
119static const clang::Type *TypeExportableHelper(
120    const clang::Type *T,
121    llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
122    clang::Diagnostic *Diags,
123    clang::SourceManager *SM,
124    const clang::VarDecl *VD,
125    const clang::RecordDecl *TopLevelRecord) {
126  // Normalize first
127  if ((T = GET_CANONICAL_TYPE(T)) == NULL)
128    return NULL;
129
130  if (SPS.count(T))
131    return T;
132
133  switch (T->getTypeClass()) {
134    case clang::Type::Builtin: {
135      const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T);
136
137      switch (BT->getKind()) {
138#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
139        case builtin_type:
140#include "RSClangBuiltinEnums.inc"
141          return T;
142        default: {
143          return NULL;
144        }
145      }
146    }
147    case clang::Type::Record: {
148      if (RSExportPrimitiveType::GetRSSpecificType(T) !=
149          RSExportPrimitiveType::DataTypeUnknown)
150        return T;  // RS object type, no further checks are needed
151
152      // Check internal struct
153      if (T->isUnionType()) {
154        ReportTypeError(Diags, SM, NULL, T->getAsUnionType()->getDecl(),
155            "unions cannot be exported: '%0'");
156        return NULL;
157      } else if (!T->isStructureType()) {
158        slangAssert(false && "Unknown type cannot be exported");
159        return NULL;
160      }
161
162      clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
163      if (RD != NULL) {
164        RD = RD->getDefinition();
165        if (RD == NULL) {
166          ReportTypeError(Diags, SM, NULL, T->getAsStructureType()->getDecl(),
167              "struct is not defined in this module");
168          return NULL;
169        }
170      }
171
172      if (!TopLevelRecord) {
173        TopLevelRecord = RD;
174      }
175      if (RD->getName().empty()) {
176        ReportTypeError(Diags, SM, NULL, RD,
177            "anonymous structures cannot be exported");
178        return NULL;
179      }
180
181      // Fast check
182      if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
183        return NULL;
184
185      // Insert myself into checking set
186      SPS.insert(T);
187
188      // Check all element
189      for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
190               FE = RD->field_end();
191           FI != FE;
192           FI++) {
193        const clang::FieldDecl *FD = *FI;
194        const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
195        FT = GET_CANONICAL_TYPE(FT);
196
197        if (!TypeExportableHelper(FT, SPS, Diags, SM, VD, TopLevelRecord)) {
198          return NULL;
199        }
200
201        // We don't support bit fields yet
202        //
203        // TODO(zonr/srhines): allow bit fields of size 8, 16, 32
204        if (FD->isBitField()) {
205          if (Diags && SM) {
206            Diags->Report(clang::FullSourceLoc(FD->getLocation(), *SM),
207                          Diags->getCustomDiagID(clang::Diagnostic::Error,
208                          "bit fields are not able to be exported: '%0.%1'"))
209                << RD->getName()
210                << FD->getName();
211          }
212          return NULL;
213        }
214      }
215
216      return T;
217    }
218    case clang::Type::Pointer: {
219      if (TopLevelRecord) {
220        ReportTypeError(Diags, SM, NULL, TopLevelRecord,
221            "structures containing pointers cannot be exported: '%0'");
222        return NULL;
223      }
224
225      const clang::PointerType *PT = UNSAFE_CAST_TYPE(clang::PointerType, T);
226      const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
227
228      if (PointeeType->getTypeClass() == clang::Type::Pointer)
229        return T;
230      // We don't support pointer with array-type pointee or unsupported pointee
231      // type
232      if (PointeeType->isArrayType() ||
233          (TypeExportableHelper(PointeeType, SPS, Diags, SM, VD,
234                                TopLevelRecord) == NULL))
235        return NULL;
236      else
237        return T;
238    }
239    case clang::Type::ExtVector: {
240      const clang::ExtVectorType *EVT =
241          UNSAFE_CAST_TYPE(clang::ExtVectorType, T);
242      // Only vector with size 2, 3 and 4 are supported.
243      if (EVT->getNumElements() < 2 || EVT->getNumElements() > 4)
244        return NULL;
245
246      // Check base element type
247      const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
248
249      if ((ElementType->getTypeClass() != clang::Type::Builtin) ||
250          (TypeExportableHelper(ElementType, SPS, Diags, SM, VD,
251                                TopLevelRecord) == NULL))
252        return NULL;
253      else
254        return T;
255    }
256    case clang::Type::ConstantArray: {
257      const clang::ConstantArrayType *CAT =
258          UNSAFE_CAST_TYPE(clang::ConstantArrayType, T);
259
260      return ConstantArrayTypeExportableHelper(CAT, SPS, Diags, SM, VD,
261                                               TopLevelRecord);
262    }
263    default: {
264      return NULL;
265    }
266  }
267}
268
269// Return the type that can be used to create RSExportType, will always return
270// the canonical type
271// If the Type T is not exportable, this function returns NULL. Diags and SM
272// are used to generate proper Clang diagnostic messages when a
273// non-exportable type is detected. TopLevelRecord is used to capture the
274// highest struct (in the case of a nested hierarchy) for detecting other
275// types that cannot be exported (mostly pointers within a struct).
276static const clang::Type *TypeExportable(const clang::Type *T,
277                                         clang::Diagnostic *Diags,
278                                         clang::SourceManager *SM,
279                                         const clang::VarDecl *VD) {
280  llvm::SmallPtrSet<const clang::Type*, 8> SPS =
281      llvm::SmallPtrSet<const clang::Type*, 8>();
282
283  return TypeExportableHelper(T, SPS, Diags, SM, VD, NULL);
284}
285
286}  // namespace
287
288/****************************** RSExportType ******************************/
289bool RSExportType::NormalizeType(const clang::Type *&T,
290                                 llvm::StringRef &TypeName,
291                                 clang::Diagnostic *Diags,
292                                 clang::SourceManager *SM,
293                                 const clang::VarDecl *VD) {
294  if ((T = TypeExportable(T, Diags, SM, VD)) == NULL) {
295    return false;
296  }
297  // Get type name
298  TypeName = RSExportType::GetTypeName(T);
299  if (TypeName.empty()) {
300    if (Diags && SM) {
301      if (VD) {
302        Diags->Report(clang::FullSourceLoc(VD->getLocation(), *SM),
303                      Diags->getCustomDiagID(clang::Diagnostic::Error,
304                                             "anonymous types cannot "
305                                             "be exported"));
306      } else {
307        Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
308                                             "anonymous types cannot "
309                                             "be exported"));
310      }
311    }
312    return false;
313  }
314
315  return true;
316}
317
318const clang::Type
319*RSExportType::GetTypeOfDecl(const clang::DeclaratorDecl *DD) {
320  if (DD) {
321    clang::QualType T;
322    if (DD->getTypeSourceInfo())
323      T = DD->getTypeSourceInfo()->getType();
324    else
325      T = DD->getType();
326
327    if (T.isNull())
328      return NULL;
329    else
330      return T.getTypePtr();
331  }
332  return NULL;
333}
334
335llvm::StringRef RSExportType::GetTypeName(const clang::Type* T) {
336  T = GET_CANONICAL_TYPE(T);
337  if (T == NULL)
338    return llvm::StringRef();
339
340  switch (T->getTypeClass()) {
341    case clang::Type::Builtin: {
342      const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T);
343
344      switch (BT->getKind()) {
345#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
346        case builtin_type:                                    \
347          return cname;                                       \
348        break;
349#include "RSClangBuiltinEnums.inc"
350        default: {
351          slangAssert(false && "Unknown data type of the builtin");
352          break;
353        }
354      }
355      break;
356    }
357    case clang::Type::Record: {
358      clang::RecordDecl *RD;
359      if (T->isStructureType()) {
360        RD = T->getAsStructureType()->getDecl();
361      } else {
362        break;
363      }
364
365      llvm::StringRef Name = RD->getName();
366      if (Name.empty()) {
367          if (RD->getTypedefForAnonDecl() != NULL)
368            Name = RD->getTypedefForAnonDecl()->getName();
369
370          if (Name.empty())
371            // Try to find a name from redeclaration (i.e. typedef)
372            for (clang::TagDecl::redecl_iterator RI = RD->redecls_begin(),
373                     RE = RD->redecls_end();
374                 RI != RE;
375                 RI++) {
376              slangAssert(*RI != NULL && "cannot be NULL object");
377
378              Name = (*RI)->getName();
379              if (!Name.empty())
380                break;
381            }
382      }
383      return Name;
384    }
385    case clang::Type::Pointer: {
386      // "*" plus pointee name
387      const clang::Type *PT = GET_POINTEE_TYPE(T);
388      llvm::StringRef PointeeName;
389      if (NormalizeType(PT, PointeeName, NULL, NULL, NULL)) {
390        char *Name = new char[ 1 /* * */ + PointeeName.size() + 1 ];
391        Name[0] = '*';
392        memcpy(Name + 1, PointeeName.data(), PointeeName.size());
393        Name[PointeeName.size() + 1] = '\0';
394        return Name;
395      }
396      break;
397    }
398    case clang::Type::ExtVector: {
399      const clang::ExtVectorType *EVT =
400          UNSAFE_CAST_TYPE(clang::ExtVectorType, T);
401      return RSExportVectorType::GetTypeName(EVT);
402      break;
403    }
404    case clang::Type::ConstantArray : {
405      // Construct name for a constant array is too complicated.
406      return DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE;
407    }
408    default: {
409      break;
410    }
411  }
412
413  return llvm::StringRef();
414}
415
416
417RSExportType *RSExportType::Create(RSContext *Context,
418                                   const clang::Type *T,
419                                   const llvm::StringRef &TypeName) {
420  // Lookup the context to see whether the type was processed before.
421  // Newly created RSExportType will insert into context
422  // in RSExportType::RSExportType()
423  RSContext::export_type_iterator ETI = Context->findExportType(TypeName);
424
425  if (ETI != Context->export_types_end())
426    return ETI->second;
427
428  RSExportType *ET = NULL;
429  switch (T->getTypeClass()) {
430    case clang::Type::Record: {
431      RSExportPrimitiveType::DataType dt =
432          RSExportPrimitiveType::GetRSSpecificType(TypeName);
433      switch (dt) {
434        case RSExportPrimitiveType::DataTypeUnknown: {
435          // User-defined types
436          ET = RSExportRecordType::Create(Context,
437                                          T->getAsStructureType(),
438                                          TypeName);
439          break;
440        }
441        case RSExportPrimitiveType::DataTypeRSMatrix2x2: {
442          // 2 x 2 Matrix type
443          ET = RSExportMatrixType::Create(Context,
444                                          T->getAsStructureType(),
445                                          TypeName,
446                                          2);
447          break;
448        }
449        case RSExportPrimitiveType::DataTypeRSMatrix3x3: {
450          // 3 x 3 Matrix type
451          ET = RSExportMatrixType::Create(Context,
452                                          T->getAsStructureType(),
453                                          TypeName,
454                                          3);
455          break;
456        }
457        case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
458          // 4 x 4 Matrix type
459          ET = RSExportMatrixType::Create(Context,
460                                          T->getAsStructureType(),
461                                          TypeName,
462                                          4);
463          break;
464        }
465        default: {
466          // Others are primitive types
467          ET = RSExportPrimitiveType::Create(Context, T, TypeName);
468          break;
469        }
470      }
471      break;
472    }
473    case clang::Type::Builtin: {
474      ET = RSExportPrimitiveType::Create(Context, T, TypeName);
475      break;
476    }
477    case clang::Type::Pointer: {
478      ET = RSExportPointerType::Create(Context,
479                                       UNSAFE_CAST_TYPE(clang::PointerType, T),
480                                       TypeName);
481      // FIXME: free the name (allocated in RSExportType::GetTypeName)
482      delete [] TypeName.data();
483      break;
484    }
485    case clang::Type::ExtVector: {
486      ET = RSExportVectorType::Create(Context,
487                                      UNSAFE_CAST_TYPE(clang::ExtVectorType, T),
488                                      TypeName);
489      break;
490    }
491    case clang::Type::ConstantArray: {
492      ET = RSExportConstantArrayType::Create(
493              Context,
494              UNSAFE_CAST_TYPE(clang::ConstantArrayType, T));
495      break;
496    }
497    default: {
498      clang::Diagnostic *Diags = Context->getDiagnostics();
499      Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
500                        "unknown type cannot be exported: '%0'"))
501          << T->getTypeClassName();
502      break;
503    }
504  }
505
506  return ET;
507}
508
509RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) {
510  llvm::StringRef TypeName;
511  if (NormalizeType(T, TypeName, NULL, NULL, NULL))
512    return Create(Context, T, TypeName);
513  else
514    return NULL;
515}
516
517RSExportType *RSExportType::CreateFromDecl(RSContext *Context,
518                                           const clang::VarDecl *VD) {
519  return RSExportType::Create(Context, GetTypeOfDecl(VD));
520}
521
522size_t RSExportType::GetTypeStoreSize(const RSExportType *ET) {
523  return ET->getRSContext()->getTargetData()->getTypeStoreSize(
524      ET->getLLVMType());
525}
526
527size_t RSExportType::GetTypeAllocSize(const RSExportType *ET) {
528  if (ET->getClass() == RSExportType::ExportClassRecord)
529    return static_cast<const RSExportRecordType*>(ET)->getAllocSize();
530  else
531    return ET->getRSContext()->getTargetData()->getTypeAllocSize(
532        ET->getLLVMType());
533}
534
535RSExportType::RSExportType(RSContext *Context,
536                           ExportClass Class,
537                           const llvm::StringRef &Name)
538    : RSExportable(Context, RSExportable::EX_TYPE),
539      mClass(Class),
540      // Make a copy on Name since memory stored @Name is either allocated in
541      // ASTContext or allocated in GetTypeName which will be destroyed later.
542      mName(Name.data(), Name.size()),
543      mLLVMType(NULL),
544      mSpecType(NULL) {
545  // Don't cache the type whose name start with '<'. Those type failed to
546  // get their name since constructing their name in GetTypeName() requiring
547  // complicated work.
548  if (!Name.startswith(DUMMY_RS_TYPE_NAME_PREFIX))
549    // TODO(zonr): Need to check whether the insertion is successful or not.
550    Context->insertExportType(llvm::StringRef(Name), this);
551  return;
552}
553
554bool RSExportType::keep() {
555  if (!RSExportable::keep())
556    return false;
557  // Invalidate converted LLVM type.
558  mLLVMType = NULL;
559  return true;
560}
561
562bool RSExportType::equals(const RSExportable *E) const {
563  CHECK_PARENT_EQUALITY(RSExportable, E);
564  return (static_cast<const RSExportType*>(E)->getClass() == getClass());
565}
566
567RSExportType::~RSExportType() {
568  delete mSpecType;
569}
570
571/************************** RSExportPrimitiveType **************************/
572llvm::ManagedStatic<RSExportPrimitiveType::RSSpecificTypeMapTy>
573RSExportPrimitiveType::RSSpecificTypeMap;
574
575llvm::Type *RSExportPrimitiveType::RSObjectLLVMType = NULL;
576
577bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) {
578  if ((T != NULL) && (T->getTypeClass() == clang::Type::Builtin))
579    return true;
580  else
581    return false;
582}
583
584RSExportPrimitiveType::DataType
585RSExportPrimitiveType::GetRSSpecificType(const llvm::StringRef &TypeName) {
586  if (TypeName.empty())
587    return DataTypeUnknown;
588
589  if (RSSpecificTypeMap->empty()) {
590#define ENUM_RS_MATRIX_TYPE(type, cname, dim)                       \
591    RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type);
592#include "RSMatrixTypeEnums.inc"
593#define ENUM_RS_OBJECT_TYPE(type, cname)                            \
594    RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type);
595#include "RSObjectTypeEnums.inc"
596  }
597
598  RSSpecificTypeMapTy::const_iterator I = RSSpecificTypeMap->find(TypeName);
599  if (I == RSSpecificTypeMap->end())
600    return DataTypeUnknown;
601  else
602    return I->getValue();
603}
604
605RSExportPrimitiveType::DataType
606RSExportPrimitiveType::GetRSSpecificType(const clang::Type *T) {
607  T = GET_CANONICAL_TYPE(T);
608  if ((T == NULL) || (T->getTypeClass() != clang::Type::Record))
609    return DataTypeUnknown;
610
611  return GetRSSpecificType( RSExportType::GetTypeName(T) );
612}
613
614bool RSExportPrimitiveType::IsRSMatrixType(DataType DT) {
615  return ((DT >= FirstRSMatrixType) && (DT <= LastRSMatrixType));
616}
617
618bool RSExportPrimitiveType::IsRSObjectType(DataType DT) {
619  return ((DT >= FirstRSObjectType) && (DT <= LastRSObjectType));
620}
621
622bool RSExportPrimitiveType::IsStructureTypeWithRSObject(const clang::Type *T) {
623  bool RSObjectTypeSeen = false;
624  while (T && T->isArrayType()) {
625    T = T->getArrayElementTypeNoTypeQual();
626  }
627
628  const clang::RecordType *RT = T->getAsStructureType();
629  if (!RT) {
630    return false;
631  }
632  const clang::RecordDecl *RD = RT->getDecl();
633  RD = RD->getDefinition();
634  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
635         FE = RD->field_end();
636       FI != FE;
637       FI++) {
638    // We just look through all field declarations to see if we find a
639    // declaration for an RS object type (or an array of one).
640    const clang::FieldDecl *FD = *FI;
641    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
642    while (FT && FT->isArrayType()) {
643      FT = FT->getArrayElementTypeNoTypeQual();
644    }
645
646    RSExportPrimitiveType::DataType DT = GetRSSpecificType(FT);
647    if (IsRSObjectType(DT)) {
648      // RS object types definitely need to be zero-initialized
649      RSObjectTypeSeen = true;
650    } else {
651      switch (DT) {
652        case RSExportPrimitiveType::DataTypeRSMatrix2x2:
653        case RSExportPrimitiveType::DataTypeRSMatrix3x3:
654        case RSExportPrimitiveType::DataTypeRSMatrix4x4:
655          // Matrix types should get zero-initialized as well
656          RSObjectTypeSeen = true;
657          break;
658        default:
659          // Ignore all other primitive types
660          break;
661      }
662      while (FT && FT->isArrayType()) {
663        FT = FT->getArrayElementTypeNoTypeQual();
664      }
665      if (FT->isStructureType()) {
666        // Recursively handle structs of structs (even though these can't
667        // be exported, it is possible for a user to have them internally).
668        RSObjectTypeSeen |= IsStructureTypeWithRSObject(FT);
669      }
670    }
671  }
672
673  return RSObjectTypeSeen;
674}
675
676const size_t RSExportPrimitiveType::SizeOfDataTypeInBits[] = {
677#define ENUM_RS_DATA_TYPE(type, cname, bits)  \
678  bits,
679#include "RSDataTypeEnums.inc"
680  0   // DataTypeMax
681};
682
683size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) {
684  slangAssert(((EPT->getType() > DataTypeUnknown) &&
685               (EPT->getType() < DataTypeMax)) &&
686              "RSExportPrimitiveType::GetSizeInBits : unknown data type");
687  return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ];
688}
689
690RSExportPrimitiveType::DataType
691RSExportPrimitiveType::GetDataType(RSContext *Context, const clang::Type *T) {
692  if (T == NULL)
693    return DataTypeUnknown;
694
695  switch (T->getTypeClass()) {
696    case clang::Type::Builtin: {
697      const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T);
698      switch (BT->getKind()) {
699#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
700        case builtin_type: {                                  \
701          return DataType ## type;                            \
702        }
703#include "RSClangBuiltinEnums.inc"
704        // The size of type WChar depend on platform so we abandon the support
705        // to them.
706        default: {
707          clang::Diagnostic *Diags = Context->getDiagnostics();
708          Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
709                            "built-in type cannot be exported: '%0'"))
710              << T->getTypeClassName();
711          break;
712        }
713      }
714      break;
715    }
716    case clang::Type::Record: {
717      // must be RS object type
718      return RSExportPrimitiveType::GetRSSpecificType(T);
719    }
720    default: {
721      clang::Diagnostic *Diags = Context->getDiagnostics();
722      Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
723                        "primitive type cannot be exported: '%0'"))
724          << T->getTypeClassName();
725      break;
726    }
727  }
728
729  return DataTypeUnknown;
730}
731
732RSExportPrimitiveType
733*RSExportPrimitiveType::Create(RSContext *Context,
734                               const clang::Type *T,
735                               const llvm::StringRef &TypeName,
736                               DataKind DK,
737                               bool Normalized) {
738  DataType DT = GetDataType(Context, T);
739
740  if ((DT == DataTypeUnknown) || TypeName.empty())
741    return NULL;
742  else
743    return new RSExportPrimitiveType(Context, ExportClassPrimitive, TypeName,
744                                     DT, DK, Normalized);
745}
746
747RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context,
748                                                     const clang::Type *T,
749                                                     DataKind DK) {
750  llvm::StringRef TypeName;
751  if (RSExportType::NormalizeType(T, TypeName, NULL, NULL, NULL) &&
752      IsPrimitiveType(T)) {
753    return Create(Context, T, TypeName, DK);
754  } else {
755    return NULL;
756  }
757}
758
759const llvm::Type *RSExportPrimitiveType::convertToLLVMType() const {
760  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
761
762  if (isRSObjectType()) {
763    // struct {
764    //   int *p;
765    // } __attribute__((packed, aligned(pointer_size)))
766    //
767    // which is
768    //
769    // <{ [1 x i32] }> in LLVM
770    //
771    if (RSObjectLLVMType == NULL) {
772      std::vector<const llvm::Type *> Elements;
773      Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1));
774      RSObjectLLVMType = llvm::StructType::get(C, Elements, true);
775    }
776    return RSObjectLLVMType;
777  }
778
779  switch (mType) {
780    case DataTypeFloat32: {
781      return llvm::Type::getFloatTy(C);
782      break;
783    }
784    case DataTypeFloat64: {
785      return llvm::Type::getDoubleTy(C);
786      break;
787    }
788    case DataTypeBoolean: {
789      return llvm::Type::getInt1Ty(C);
790      break;
791    }
792    case DataTypeSigned8:
793    case DataTypeUnsigned8: {
794      return llvm::Type::getInt8Ty(C);
795      break;
796    }
797    case DataTypeSigned16:
798    case DataTypeUnsigned16:
799    case DataTypeUnsigned565:
800    case DataTypeUnsigned5551:
801    case DataTypeUnsigned4444: {
802      return llvm::Type::getInt16Ty(C);
803      break;
804    }
805    case DataTypeSigned32:
806    case DataTypeUnsigned32: {
807      return llvm::Type::getInt32Ty(C);
808      break;
809    }
810    case DataTypeSigned64:
811    case DataTypeUnsigned64: {
812      return llvm::Type::getInt64Ty(C);
813      break;
814    }
815    default: {
816      slangAssert(false && "Unknown data type");
817    }
818  }
819
820  return NULL;
821}
822
823union RSType *RSExportPrimitiveType::convertToSpecType() const {
824  llvm::OwningPtr<union RSType> ST(new union RSType);
825  RS_TYPE_SET_CLASS(ST, RS_TC_Primitive);
826  // enum RSExportPrimitiveType::DataType is synced with enum RSDataType in
827  // slang_rs_type_spec.h
828  RS_PRIMITIVE_TYPE_SET_DATA_TYPE(ST, getType());
829  return ST.take();
830}
831
832bool RSExportPrimitiveType::equals(const RSExportable *E) const {
833  CHECK_PARENT_EQUALITY(RSExportType, E);
834  return (static_cast<const RSExportPrimitiveType*>(E)->getType() == getType());
835}
836
837/**************************** RSExportPointerType ****************************/
838
839RSExportPointerType
840*RSExportPointerType::Create(RSContext *Context,
841                             const clang::PointerType *PT,
842                             const llvm::StringRef &TypeName) {
843  const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
844  const RSExportType *PointeeET;
845
846  if (PointeeType->getTypeClass() != clang::Type::Pointer) {
847    PointeeET = RSExportType::Create(Context, PointeeType);
848  } else {
849    // Double or higher dimension of pointer, export as int*
850    PointeeET = RSExportPrimitiveType::Create(Context,
851                    Context->getASTContext().IntTy.getTypePtr());
852  }
853
854  if (PointeeET == NULL) {
855    // Error diagnostic is emitted for corresponding pointee type
856    return NULL;
857  }
858
859  return new RSExportPointerType(Context, TypeName, PointeeET);
860}
861
862const llvm::Type *RSExportPointerType::convertToLLVMType() const {
863  const llvm::Type *PointeeType = mPointeeType->getLLVMType();
864  return llvm::PointerType::getUnqual(PointeeType);
865}
866
867union RSType *RSExportPointerType::convertToSpecType() const {
868  llvm::OwningPtr<union RSType> ST(new union RSType);
869
870  RS_TYPE_SET_CLASS(ST, RS_TC_Pointer);
871  RS_POINTER_TYPE_SET_POINTEE_TYPE(ST, getPointeeType()->getSpecType());
872
873  if (RS_POINTER_TYPE_GET_POINTEE_TYPE(ST) != NULL)
874    return ST.take();
875  else
876    return NULL;
877}
878
879bool RSExportPointerType::keep() {
880  if (!RSExportType::keep())
881    return false;
882  const_cast<RSExportType*>(mPointeeType)->keep();
883  return true;
884}
885
886bool RSExportPointerType::equals(const RSExportable *E) const {
887  CHECK_PARENT_EQUALITY(RSExportType, E);
888  return (static_cast<const RSExportPointerType*>(E)
889              ->getPointeeType()->equals(getPointeeType()));
890}
891
892/***************************** RSExportVectorType *****************************/
893llvm::StringRef
894RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) {
895  const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
896
897  if ((ElementType->getTypeClass() != clang::Type::Builtin))
898    return llvm::StringRef();
899
900  const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType,
901                                                  ElementType);
902  if ((EVT->getNumElements() < 1) ||
903      (EVT->getNumElements() > 4))
904    return llvm::StringRef();
905
906  switch (BT->getKind()) {
907    // Compiler is smart enough to optimize following *big if branches* since
908    // they all become "constant comparison" after macro expansion
909#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
910    case builtin_type: {                                      \
911      const char *Name[] = { cname"2", cname"3", cname"4" };  \
912      return Name[EVT->getNumElements() - 2];                 \
913      break;                                                  \
914    }
915#include "RSClangBuiltinEnums.inc"
916    default: {
917      return llvm::StringRef();
918    }
919  }
920}
921
922RSExportVectorType *RSExportVectorType::Create(RSContext *Context,
923                                               const clang::ExtVectorType *EVT,
924                                               const llvm::StringRef &TypeName,
925                                               DataKind DK,
926                                               bool Normalized) {
927  slangAssert(EVT != NULL && EVT->getTypeClass() == clang::Type::ExtVector);
928
929  const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
930  RSExportPrimitiveType::DataType DT =
931      RSExportPrimitiveType::GetDataType(Context, ElementType);
932
933  if (DT != RSExportPrimitiveType::DataTypeUnknown)
934    return new RSExportVectorType(Context,
935                                  TypeName,
936                                  DT,
937                                  DK,
938                                  Normalized,
939                                  EVT->getNumElements());
940  else
941    return NULL;
942}
943
944const llvm::Type *RSExportVectorType::convertToLLVMType() const {
945  const llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType();
946  return llvm::VectorType::get(ElementType, getNumElement());
947}
948
949union RSType *RSExportVectorType::convertToSpecType() const {
950  llvm::OwningPtr<union RSType> ST(new union RSType);
951
952  RS_TYPE_SET_CLASS(ST, RS_TC_Vector);
953  RS_VECTOR_TYPE_SET_ELEMENT_TYPE(ST, getType());
954  RS_VECTOR_TYPE_SET_VECTOR_SIZE(ST, getNumElement());
955
956  return ST.take();
957}
958
959bool RSExportVectorType::equals(const RSExportable *E) const {
960  CHECK_PARENT_EQUALITY(RSExportPrimitiveType, E);
961  return (static_cast<const RSExportVectorType*>(E)->getNumElement()
962              == getNumElement());
963}
964
965/***************************** RSExportMatrixType *****************************/
966RSExportMatrixType *RSExportMatrixType::Create(RSContext *Context,
967                                               const clang::RecordType *RT,
968                                               const llvm::StringRef &TypeName,
969                                               unsigned Dim) {
970  slangAssert((RT != NULL) && (RT->getTypeClass() == clang::Type::Record));
971  slangAssert((Dim > 1) && "Invalid dimension of matrix");
972
973  // Check whether the struct rs_matrix is in our expected form (but assume it's
974  // correct if we're not sure whether it's correct or not)
975  const clang::RecordDecl* RD = RT->getDecl();
976  RD = RD->getDefinition();
977  if (RD != NULL) {
978    clang::Diagnostic *Diags = Context->getDiagnostics();
979    const clang::SourceManager *SM = Context->getSourceManager();
980    // Find definition, perform further examination
981    if (RD->field_empty()) {
982      Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
983                    Diags->getCustomDiagID(clang::Diagnostic::Error,
984                        "invalid matrix struct: must have 1 field for saving "
985                        "values: '%0'"))
986           << RD->getName();
987      return NULL;
988    }
989
990    clang::RecordDecl::field_iterator FIT = RD->field_begin();
991    const clang::FieldDecl *FD = *FIT;
992    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
993    if ((FT == NULL) || (FT->getTypeClass() != clang::Type::ConstantArray)) {
994      Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
995                    Diags->getCustomDiagID(clang::Diagnostic::Error,
996                        "invalid matrix struct: first field should be an "
997                        "array with constant size: '%0'"))
998           << RD->getName();
999      return NULL;
1000    }
1001    const clang::ConstantArrayType *CAT =
1002      static_cast<const clang::ConstantArrayType *>(FT);
1003    const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
1004    if ((ElementType == NULL) ||
1005        (ElementType->getTypeClass() != clang::Type::Builtin) ||
1006        (static_cast<const clang::BuiltinType *>(ElementType)->getKind()
1007          != clang::BuiltinType::Float)) {
1008      Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1009                    Diags->getCustomDiagID(clang::Diagnostic::Error,
1010                        "invalid matrix struct: first field should be a "
1011                        "float array: '%0'"))
1012           << RD->getName();
1013      return NULL;
1014    }
1015
1016    if (CAT->getSize() != Dim * Dim) {
1017      Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1018                    Diags->getCustomDiagID(clang::Diagnostic::Error,
1019                        "invalid matrix struct: first field should be an "
1020                        "array with size %0: '%1'"))
1021           << Dim * Dim
1022           << RD->getName();
1023      return NULL;
1024    }
1025
1026    FIT++;
1027    if (FIT != RD->field_end()) {
1028      Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1029                    Diags->getCustomDiagID(clang::Diagnostic::Error,
1030                        "invalid matrix struct: must have exactly 1 field: "
1031                        "'%0'"))
1032           << RD->getName();
1033      return NULL;
1034    }
1035  }
1036
1037  return new RSExportMatrixType(Context, TypeName, Dim);
1038}
1039
1040const llvm::Type *RSExportMatrixType::convertToLLVMType() const {
1041  // Construct LLVM type:
1042  // struct {
1043  //  float X[mDim * mDim];
1044  // }
1045
1046  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
1047  llvm::ArrayType *X = llvm::ArrayType::get(llvm::Type::getFloatTy(C),
1048                                            mDim * mDim);
1049  return llvm::StructType::get(C, X, NULL);
1050}
1051
1052union RSType *RSExportMatrixType::convertToSpecType() const {
1053  llvm::OwningPtr<union RSType> ST(new union RSType);
1054  RS_TYPE_SET_CLASS(ST, RS_TC_Matrix);
1055  switch (getDim()) {
1056    case 2: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix2x2); break;
1057    case 3: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix3x3); break;
1058    case 4: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix4x4); break;
1059    default: slangAssert(false && "Matrix type with unsupported dimension.");
1060  }
1061  return ST.take();
1062}
1063
1064bool RSExportMatrixType::equals(const RSExportable *E) const {
1065  CHECK_PARENT_EQUALITY(RSExportType, E);
1066  return (static_cast<const RSExportMatrixType*>(E)->getDim() == getDim());
1067}
1068
1069/************************* RSExportConstantArrayType *************************/
1070RSExportConstantArrayType
1071*RSExportConstantArrayType::Create(RSContext *Context,
1072                                   const clang::ConstantArrayType *CAT) {
1073  slangAssert(CAT != NULL && CAT->getTypeClass() == clang::Type::ConstantArray);
1074
1075  slangAssert((CAT->getSize().getActiveBits() < 32) && "array too large");
1076
1077  unsigned Size = static_cast<unsigned>(CAT->getSize().getZExtValue());
1078  slangAssert((Size > 0) && "Constant array should have size greater than 0");
1079
1080  const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
1081  RSExportType *ElementET = RSExportType::Create(Context, ElementType);
1082
1083  if (ElementET == NULL) {
1084    return NULL;
1085  }
1086
1087  return new RSExportConstantArrayType(Context,
1088                                       ElementET,
1089                                       Size);
1090}
1091
1092const llvm::Type *RSExportConstantArrayType::convertToLLVMType() const {
1093  return llvm::ArrayType::get(mElementType->getLLVMType(), getSize());
1094}
1095
1096union RSType *RSExportConstantArrayType::convertToSpecType() const {
1097  llvm::OwningPtr<union RSType> ST(new union RSType);
1098
1099  RS_TYPE_SET_CLASS(ST, RS_TC_ConstantArray);
1100  RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_TYPE(
1101      ST, getElementType()->getSpecType());
1102  RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_SIZE(ST, getSize());
1103
1104  if (RS_CONSTANT_ARRAY_TYPE_GET_ELEMENT_TYPE(ST) != NULL)
1105    return ST.take();
1106  else
1107    return NULL;
1108}
1109
1110bool RSExportConstantArrayType::keep() {
1111  if (!RSExportType::keep())
1112    return false;
1113  const_cast<RSExportType*>(mElementType)->keep();
1114  return true;
1115}
1116
1117bool RSExportConstantArrayType::equals(const RSExportable *E) const {
1118  CHECK_PARENT_EQUALITY(RSExportType, E);
1119  const RSExportConstantArrayType *RHS =
1120      static_cast<const RSExportConstantArrayType*>(E);
1121  return ((getSize() == RHS->getSize()) &&
1122          (getElementType()->equals(RHS->getElementType())));
1123}
1124
1125/**************************** RSExportRecordType ****************************/
1126RSExportRecordType *RSExportRecordType::Create(RSContext *Context,
1127                                               const clang::RecordType *RT,
1128                                               const llvm::StringRef &TypeName,
1129                                               bool mIsArtificial) {
1130  slangAssert(RT != NULL && RT->getTypeClass() == clang::Type::Record);
1131
1132  const clang::RecordDecl *RD = RT->getDecl();
1133  slangAssert(RD->isStruct());
1134
1135  RD = RD->getDefinition();
1136  if (RD == NULL) {
1137    slangAssert(false && "struct is not defined in this module");
1138    return NULL;
1139  }
1140
1141  // Struct layout construct by clang. We rely on this for obtaining the
1142  // alloc size of a struct and offset of every field in that struct.
1143  const clang::ASTRecordLayout *RL =
1144      &Context->getASTContext().getASTRecordLayout(RD);
1145  slangAssert((RL != NULL) && "Failed to retrieve the struct layout from Clang.");
1146
1147  RSExportRecordType *ERT =
1148      new RSExportRecordType(Context,
1149                             TypeName,
1150                             RD->hasAttr<clang::PackedAttr>(),
1151                             mIsArtificial,
1152                             (RL->getSize() >> 3));
1153  unsigned int Index = 0;
1154
1155  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1156           FE = RD->field_end();
1157       FI != FE;
1158       FI++, Index++) {
1159    clang::Diagnostic *Diags = Context->getDiagnostics();
1160    const clang::SourceManager *SM = Context->getSourceManager();
1161
1162    // FIXME: All fields should be primitive type
1163    slangAssert((*FI)->getKind() == clang::Decl::Field);
1164    clang::FieldDecl *FD = *FI;
1165
1166    if (FD->isBitField()) {
1167      delete ERT;
1168      return NULL;
1169    }
1170
1171    // Type
1172    RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD);
1173
1174    if (ET != NULL) {
1175      ERT->mFields.push_back(
1176          new Field(ET, FD->getName(), ERT,
1177                    static_cast<size_t>(RL->getFieldOffset(Index) >> 3)));
1178    } else {
1179      Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1180                    Diags->getCustomDiagID(clang::Diagnostic::Error,
1181                    "field type cannot be exported: '%0.%1'"))
1182          << RD->getName()
1183          << FD->getName();
1184      delete ERT;
1185      return NULL;
1186    }
1187  }
1188
1189  return ERT;
1190}
1191
1192const llvm::Type *RSExportRecordType::convertToLLVMType() const {
1193  // Create an opaque type since struct may reference itself recursively.
1194  llvm::PATypeHolder ResultHolder =
1195      llvm::OpaqueType::get(getRSContext()->getLLVMContext());
1196  setAbstractLLVMType(ResultHolder.get());
1197
1198  std::vector<const llvm::Type*> FieldTypes;
1199
1200  for (const_field_iterator FI = fields_begin(), FE = fields_end();
1201       FI != FE;
1202       FI++) {
1203    const Field *F = *FI;
1204    const RSExportType *FET = F->getType();
1205
1206    FieldTypes.push_back(FET->getLLVMType());
1207  }
1208
1209  llvm::StructType *ST = llvm::StructType::get(getRSContext()->getLLVMContext(),
1210                                               FieldTypes,
1211                                               mIsPacked);
1212  if (ST != NULL)
1213    static_cast<llvm::OpaqueType*>(ResultHolder.get())
1214        ->refineAbstractTypeTo(ST);
1215  else
1216    return NULL;
1217  return ResultHolder.get();
1218}
1219
1220union RSType *RSExportRecordType::convertToSpecType() const {
1221  unsigned NumFields = getFields().size();
1222  unsigned AllocSize = sizeof(union RSType) +
1223                       sizeof(struct RSRecordField) * NumFields;
1224  llvm::OwningPtr<union RSType> ST(
1225      reinterpret_cast<union RSType*>(operator new(AllocSize)));
1226
1227  ::memset(ST.get(), 0, AllocSize);
1228
1229  RS_TYPE_SET_CLASS(ST, RS_TC_Record);
1230  RS_RECORD_TYPE_SET_NAME(ST, getName().c_str());
1231  RS_RECORD_TYPE_SET_NUM_FIELDS(ST, NumFields);
1232
1233  setSpecTypeTemporarily(ST.get());
1234
1235  unsigned FieldIdx = 0;
1236  for (const_field_iterator FI = fields_begin(), FE = fields_end();
1237       FI != FE;
1238       FI++, FieldIdx++) {
1239    const Field *F = *FI;
1240
1241    RS_RECORD_TYPE_SET_FIELD_NAME(ST, FieldIdx, F->getName().c_str());
1242    RS_RECORD_TYPE_SET_FIELD_TYPE(ST, FieldIdx, F->getType()->getSpecType());
1243
1244    enum RSDataKind DK = RS_DK_User;
1245    if ((F->getType()->getClass() == ExportClassPrimitive) ||
1246        (F->getType()->getClass() == ExportClassVector)) {
1247      const RSExportPrimitiveType *EPT =
1248        static_cast<const RSExportPrimitiveType*>(F->getType());
1249      // enum RSExportPrimitiveType::DataKind is synced with enum RSDataKind in
1250      // slang_rs_type_spec.h
1251      DK = static_cast<enum RSDataKind>(EPT->getKind());
1252    }
1253    RS_RECORD_TYPE_SET_FIELD_DATA_KIND(ST, FieldIdx, DK);
1254  }
1255
1256  // TODO(slang): Check whether all fields were created normally.
1257
1258  return ST.take();
1259}
1260
1261bool RSExportRecordType::keep() {
1262  if (!RSExportType::keep())
1263    return false;
1264  for (std::list<const Field*>::iterator I = mFields.begin(),
1265          E = mFields.end();
1266       I != E;
1267       I++) {
1268    const_cast<RSExportType*>((*I)->getType())->keep();
1269  }
1270  return true;
1271}
1272
1273bool RSExportRecordType::equals(const RSExportable *E) const {
1274  CHECK_PARENT_EQUALITY(RSExportType, E);
1275
1276  const RSExportRecordType *ERT = static_cast<const RSExportRecordType*>(E);
1277
1278  if (ERT->getFields().size() != getFields().size())
1279    return false;
1280
1281  const_field_iterator AI = fields_begin(), BI = ERT->fields_begin();
1282
1283  for (unsigned i = 0, e = getFields().size(); i != e; i++) {
1284    if (!(*AI)->getType()->equals((*BI)->getType()))
1285      return false;
1286    AI++;
1287    BI++;
1288  }
1289
1290  return true;
1291}
1292
1293}  // namespace slang
1294