slang_rs_export_type.h revision c808a99831115928b4648f4c8b86dc682594217a
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#ifndef _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_EXPORT_TYPE_H_  // NOLINT
18#define _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_EXPORT_TYPE_H_
19
20#include <list>
21#include <set>
22#include <string>
23
24#include "clang/AST/Decl.h"
25#include "clang/AST/Type.h"
26
27#include "llvm/ADT/SmallPtrSet.h"
28#include "llvm/ADT/StringMap.h"
29#include "llvm/ADT/StringRef.h"
30
31#include "llvm/Support/ManagedStatic.h"
32
33#include "slang_rs_exportable.h"
34
35#define GET_CANONICAL_TYPE(T) \
36    (((T) == NULL) ? NULL : (T)->getCanonicalTypeInternal().getTypePtr())
37#define UNSAFE_CAST_TYPE(TT, T) \
38    static_cast<TT*>(T->getCanonicalTypeInternal().getTypePtr())
39#define GET_EXT_VECTOR_ELEMENT_TYPE(T) \
40    (((T) == NULL) ? NULL : \
41                     GET_CANONICAL_TYPE((T)->getElementType().getTypePtr()))
42#define GET_POINTEE_TYPE(T) \
43    (((T) == NULL) ? NULL : \
44                     GET_CANONICAL_TYPE((T)->getPointeeType().getTypePtr()))
45#define GET_CONSTANT_ARRAY_ELEMENT_TYPE(T)  \
46    (((T) == NULL) ? NULL : \
47                     GET_CANONICAL_TYPE((T)->getElementType().getTypePtr()))
48#define DUMMY_RS_TYPE_NAME_PREFIX   "<"
49#define DUMMY_RS_TYPE_NAME_POSTFIX  ">"
50#define DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE  \
51    DUMMY_RS_TYPE_NAME_PREFIX"ConstantArray"DUMMY_RS_TYPE_NAME_POSTFIX
52
53union RSType;
54
55namespace llvm {
56  class Type;
57}   // namespace llvm
58
59namespace slang {
60
61  class RSContext;
62
63class RSExportType : public RSExportable {
64  friend class RSExportElement;
65 public:
66  typedef enum {
67    ExportClassPrimitive,
68    ExportClassPointer,
69    ExportClassVector,
70    ExportClassMatrix,
71    ExportClassConstantArray,
72    ExportClassRecord
73  } ExportClass;
74
75 private:
76  ExportClass mClass;
77  std::string mName;
78
79  // Cache the result after calling convertToLLVMType() at the first time
80  mutable const llvm::Type *mLLVMType;
81  // Cache the result after calling convertToSpecType() at the first time
82  mutable union RSType *mSpecType;
83
84 protected:
85  RSExportType(RSContext *Context,
86               ExportClass Class,
87               const llvm::StringRef &Name);
88
89  // Let's make it private since there're some prerequisites to call this
90  // function.
91  //
92  // @T was normalized by calling RSExportType::TypeExportable().
93  // @TypeName was retrieve from RSExportType::GetTypeName() before calling
94  //           this.
95  //
96  static RSExportType *Create(RSContext *Context,
97                              const clang::Type *T,
98                              const llvm::StringRef &TypeName);
99
100  static llvm::StringRef GetTypeName(const clang::Type *T);
101  // Return the type that can be used to create RSExportType, will always return
102  // the canonical type
103  static const clang::Type
104  *TypeExportable(const clang::Type *T,
105                  // Contain the checked type for recursion
106                  llvm::SmallPtrSet<const clang::Type*, 8> &SPS,
107                  bool InRecord);
108
109  // This function convert the RSExportType to LLVM type. Actually, it should be
110  // "convert Clang type to LLVM type." However, clang doesn't make this API
111  // (lib/CodeGen/CodeGenTypes.h) public, we need to do by ourselves.
112  //
113  // Once we can get LLVM type, we can use LLVM to get alignment information,
114  // allocation size of a given type and structure layout that LLVM used
115  // (all of these information are target dependent) without dealing with these
116  // by ourselves.
117  virtual const llvm::Type *convertToLLVMType() const = 0;
118  // Record type may recursively reference its type definition. We need a
119  // temporary type setup before the type construction gets done.
120  inline void setAbstractLLVMType(const llvm::Type *LLVMType) const {
121    mLLVMType = LLVMType;
122  }
123
124  virtual union RSType *convertToSpecType() const = 0;
125  inline void setSpecTypeTemporarily(union RSType *SpecType) const {
126    mSpecType = SpecType;
127  }
128
129  virtual ~RSExportType();
130 public:
131  static bool NormalizeType(const clang::Type *&T, llvm::StringRef &TypeName);
132  // @T may not be normalized
133  static RSExportType *Create(RSContext *Context, const clang::Type *T);
134  static RSExportType *CreateFromDecl(RSContext *Context,
135                                      const clang::VarDecl *VD);
136
137  static const clang::Type *GetTypeOfDecl(const clang::DeclaratorDecl *DD);
138
139  inline ExportClass getClass() const { return mClass; }
140
141  inline const llvm::Type *getLLVMType() const {
142    if (mLLVMType == NULL)
143      mLLVMType = convertToLLVMType();
144    return mLLVMType;
145  }
146
147  inline const union RSType *getSpecType() const {
148    if (mSpecType == NULL)
149      mSpecType = convertToSpecType();
150    return mSpecType;
151  }
152
153  // Return the number of bits necessary to hold the specified RSExportType
154  static size_t GetTypeStoreSize(const RSExportType *ET);
155
156  // The size of allocation of specified RSExportType (alignment considered)
157  static size_t GetTypeAllocSize(const RSExportType *ET);
158
159  inline const std::string &getName() const { return mName; }
160
161  virtual bool keep();
162  virtual bool equals(const RSExportable *E) const;
163};  // RSExportType
164
165// Primitive types
166class RSExportPrimitiveType : public RSExportType {
167  friend class RSExportType;
168  friend class RSExportElement;
169 public:
170  // From graphics/java/android/renderscript/Element.java: Element.DataType
171  typedef enum {
172    DataTypeUnknown = -1,
173
174#define ENUM_PRIMITIVE_DATA_TYPE_RANGE(begin_type, end_type)  \
175    FirstPrimitiveType = DataType ## begin_type,  \
176    LastPrimitiveType = DataType ## end_type,
177
178#define ENUM_RS_MATRIX_DATA_TYPE_RANGE(begin_type, end_type)  \
179    FirstRSMatrixType = DataType ## begin_type,  \
180    LastRSMatrixType = DataType ## end_type,
181
182#define ENUM_RS_OBJECT_DATA_TYPE_RANGE(begin_type, end_type)  \
183    FirstRSObjectType = DataType ## begin_type,  \
184    LastRSObjectType = DataType ## end_type,
185
186#define ENUM_RS_DATA_TYPE(type, cname, bits)  \
187    DataType ## type,
188
189#include "RSDataTypeEnums.inc"
190
191    DataTypeMax
192  } DataType;
193
194  // From graphics/java/android/renderscript/Element.java: Element.DataKind
195  typedef enum {
196    DataKindUnknown = -1
197#define ENUM_RS_DATA_KIND(kind) \
198    , DataKind ## kind
199#include "RSDataKindEnums.inc"
200  } DataKind;
201
202 private:
203  // NOTE: There's no any instance of RSExportPrimitiveType which mType
204  // is of the value DataTypeRSMatrix*. DataTypeRSMatrix* enumeration here is
205  // only for RSExportPrimitiveType::GetRSObjectType to *recognize* the struct
206  // rs_matrix{2x2, 3x3, 4x4}. These matrix type are represented as
207  // RSExportMatrixType.
208  DataType mType;
209  DataKind mKind;
210  bool mNormalized;
211
212  typedef llvm::StringMap<DataType> RSSpecificTypeMapTy;
213  static llvm::ManagedStatic<RSSpecificTypeMapTy> RSSpecificTypeMap;
214
215  static llvm::Type *RSObjectLLVMType;
216
217  static const size_t SizeOfDataTypeInBits[];
218  // @T was normalized by calling RSExportType::TypeExportable() before calling
219  // this.
220  // @TypeName was retrieved from RSExportType::GetTypeName() before calling
221  // this
222  static RSExportPrimitiveType *Create(RSContext *Context,
223                                       const clang::Type *T,
224                                       const llvm::StringRef &TypeName,
225                                       DataKind DK = DataKindUser,
226                                       bool Normalized = false);
227
228 protected:
229  // T is normalized by calling RSExportType::TypeExportable() before
230  // calling this
231  static bool IsPrimitiveType(const clang::Type *T);
232
233  static DataType GetDataType(const clang::Type *T);
234
235  RSExportPrimitiveType(RSContext *Context,
236                        // for derived class to set their type class
237                        ExportClass Class,
238                        const llvm::StringRef &Name,
239                        DataType DT,
240                        DataKind DK,
241                        bool Normalized)
242      : RSExportType(Context, Class, Name),
243        mType(DT),
244        mKind(DK),
245        mNormalized(Normalized) {
246    return;
247  }
248
249  virtual const llvm::Type *convertToLLVMType() const;
250  virtual union RSType *convertToSpecType() const;
251 public:
252  // @T may not be normalized
253  static RSExportPrimitiveType *Create(RSContext *Context,
254                                       const clang::Type *T,
255                                       DataKind DK = DataKindUser);
256
257  static DataType GetRSSpecificType(const llvm::StringRef &TypeName);
258  static DataType GetRSSpecificType(const clang::Type *T);
259
260  static bool IsRSMatrixType(DataType DT);
261  static bool IsRSObjectType(DataType DT);
262
263  static size_t GetSizeInBits(const RSExportPrimitiveType *EPT);
264
265  inline DataType getType() const { return mType; }
266  inline DataKind getKind() const { return mKind; }
267  inline bool isRSObjectType() const {
268    return ((mType >= DataTypeRSElement) && (mType < DataTypeMax));
269  }
270
271  virtual bool equals(const RSExportable *E) const;
272};  // RSExportPrimitiveType
273
274
275class RSExportPointerType : public RSExportType {
276  friend class RSExportType;
277  friend class RSExportFunc;
278 private:
279  const RSExportType *mPointeeType;
280
281  RSExportPointerType(RSContext *Context,
282                      const llvm::StringRef &Name,
283                      const RSExportType *PointeeType)
284      : RSExportType(Context, ExportClassPointer, Name),
285        mPointeeType(PointeeType) {
286    return;
287  }
288
289  // @PT was normalized by calling RSExportType::TypeExportable() before calling
290  // this.
291  static RSExportPointerType *Create(RSContext *Context,
292                                     const clang::PointerType *PT,
293                                     const llvm::StringRef &TypeName);
294
295  virtual const llvm::Type *convertToLLVMType() const;
296  virtual union RSType *convertToSpecType() const;
297 public:
298  static const clang::Type *IntegerType;
299
300  virtual bool keep();
301
302  inline const RSExportType *getPointeeType() const { return mPointeeType; }
303
304  virtual bool equals(const RSExportable *E) const;
305};  // RSExportPointerType
306
307
308class RSExportVectorType : public RSExportPrimitiveType {
309  friend class RSExportType;
310  friend class RSExportElement;
311 private:
312  unsigned mNumElement;   // number of element
313
314  RSExportVectorType(RSContext *Context,
315                     const llvm::StringRef &Name,
316                     DataType DT,
317                     DataKind DK,
318                     bool Normalized,
319                     unsigned NumElement)
320      : RSExportPrimitiveType(Context, ExportClassVector, Name,
321                              DT, DK, Normalized),
322        mNumElement(NumElement) {
323    return;
324  }
325
326  // @EVT was normalized by calling RSExportType::TypeExportable() before
327  // calling this.
328  static RSExportVectorType *Create(RSContext *Context,
329                                    const clang::ExtVectorType *EVT,
330                                    const llvm::StringRef &TypeName,
331                                    DataKind DK = DataKindUser,
332                                    bool Normalized = false);
333
334  virtual const llvm::Type *convertToLLVMType() const;
335  virtual union RSType *convertToSpecType() const;
336 public:
337  static llvm::StringRef GetTypeName(const clang::ExtVectorType *EVT);
338
339  inline unsigned getNumElement() const { return mNumElement; }
340
341  virtual bool equals(const RSExportable *E) const;
342};
343
344// Only *square* *float* matrix is supported by now.
345//
346// struct rs_matrix{2x2,3x3,4x4, ..., NxN} should be defined as the following
347// form *exactly*:
348//  typedef struct {
349//    float m[{NxN}];
350//  } rs_matrixNxN;
351//
352//  where mDim will be N.
353class RSExportMatrixType : public RSExportType {
354  friend class RSExportType;
355 private:
356  unsigned mDim;  // dimension
357
358  RSExportMatrixType(RSContext *Context,
359                     const llvm::StringRef &Name,
360                     unsigned Dim)
361    : RSExportType(Context, ExportClassMatrix, Name),
362      mDim(Dim) {
363    return;
364  }
365
366  virtual const llvm::Type *convertToLLVMType() const;
367  virtual union RSType *convertToSpecType() const;
368 public:
369  // @RT was normalized by calling RSExportType::TypeExportable() before
370  // calling this.
371  static RSExportMatrixType *Create(RSContext *Context,
372                                    const clang::RecordType *RT,
373                                    const llvm::StringRef &TypeName,
374                                    unsigned Dim);
375
376  inline unsigned getDim() const { return mDim; }
377
378  virtual bool equals(const RSExportable *E) const;
379};
380
381class RSExportConstantArrayType : public RSExportType {
382  friend class RSExportType;
383 private:
384  const RSExportType *mElementType;  // Array element type
385  unsigned mSize;  // Array size
386
387  RSExportConstantArrayType(RSContext *Context,
388                            const RSExportType *ElementType,
389                            unsigned Size)
390    : RSExportType(Context,
391                   ExportClassConstantArray,
392                   DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE),
393      mElementType(ElementType),
394      mSize(Size) {
395    return;
396  }
397
398  // @CAT was normalized by calling RSExportType::TypeExportable() before
399  // calling this.
400  static RSExportConstantArrayType *Create(RSContext *Context,
401                                           const clang::ConstantArrayType *CAT);
402
403  virtual const llvm::Type *convertToLLVMType() const;
404  virtual union RSType *convertToSpecType() const;
405 public:
406  inline unsigned getSize() const { return mSize; }
407  inline const RSExportType *getElementType() const { return mElementType; }
408
409  virtual bool keep();
410  virtual bool equals(const RSExportable *E) const;
411};
412
413class RSExportRecordType : public RSExportType {
414  friend class RSExportType;
415 public:
416  class Field {
417   private:
418    const RSExportType *mType;
419    // Field name
420    std::string mName;
421    // Link to the struct that contain this field
422    const RSExportRecordType *mParent;
423    // Offset in the container
424    size_t mOffset;
425
426   public:
427    Field(const RSExportType *T,
428          const llvm::StringRef &Name,
429          const RSExportRecordType *Parent,
430          size_t Offset)
431        : mType(T),
432          mName(Name.data(), Name.size()),
433          mParent(Parent),
434          mOffset(Offset) {
435      return;
436    }
437
438    inline const RSExportRecordType *getParent() const { return mParent; }
439    inline const RSExportType *getType() const { return mType; }
440    inline const std::string &getName() const { return mName; }
441    inline size_t getOffsetInParent() const { return mOffset; }
442  };
443
444  typedef std::list<const Field*>::const_iterator const_field_iterator;
445
446  inline const_field_iterator fields_begin() const {
447    return this->mFields.begin();
448  }
449  inline const_field_iterator fields_end() const {
450    return this->mFields.end();
451  }
452
453 private:
454  std::list<const Field*> mFields;
455  bool mIsPacked;
456  // Artificial export struct type is not exported by user (and thus it won't
457  // get reflected)
458  bool mIsArtificial;
459  size_t mAllocSize;
460
461  RSExportRecordType(RSContext *Context,
462                     const llvm::StringRef &Name,
463                     bool IsPacked,
464                     bool IsArtificial,
465                     size_t AllocSize)
466      : RSExportType(Context, ExportClassRecord, Name),
467        mIsPacked(IsPacked),
468        mIsArtificial(IsArtificial),
469        mAllocSize(AllocSize) {
470    return;
471  }
472
473  // @RT was normalized by calling RSExportType::TypeExportable() before calling
474  // this.
475  // @TypeName was retrieved from RSExportType::GetTypeName() before calling
476  // this.
477  static RSExportRecordType *Create(RSContext *Context,
478                                    const clang::RecordType *RT,
479                                    const llvm::StringRef &TypeName,
480                                    bool mIsArtificial = false);
481
482  virtual const llvm::Type *convertToLLVMType() const;
483  virtual union RSType *convertToSpecType() const;
484 public:
485  inline const std::list<const Field*>& getFields() const { return mFields; }
486  inline bool isPacked() const { return mIsPacked; }
487  inline bool isArtificial() const { return mIsArtificial; }
488  inline size_t getAllocSize() const { return mAllocSize; }
489
490  virtual bool keep();
491  virtual bool equals(const RSExportable *E) const;
492
493  ~RSExportRecordType() {
494    for (std::list<const Field*>::iterator I = mFields.begin(),
495             E = mFields.end();
496         I != E;
497         I++)
498      if (*I != NULL)
499        delete *I;
500    return;
501  }
502};  // RSExportRecordType
503
504}   // namespace slang
505
506#endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_EXPORT_TYPE_H_  NOLINT
507