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