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