Home | History | Annotate | Download | only in slang
      1 /*
      2  * Copyright 2010-2012, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #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 #include <sstream>
     24 
     25 #include "clang/AST/Decl.h"
     26 #include "clang/AST/Type.h"
     27 
     28 #include "llvm/ADT/SmallPtrSet.h"
     29 #include "llvm/ADT/StringMap.h"
     30 #include "llvm/ADT/StringRef.h"
     31 
     32 #include "llvm/Support/ManagedStatic.h"
     33 
     34 #include "slang_rs_exportable.h"
     35 
     36 #define GET_CANONICAL_TYPE(T) \
     37     (((T) == NULL) ? NULL : (T)->getCanonicalTypeInternal().getTypePtr())
     38 #define UNSAFE_CAST_TYPE(TT, T) \
     39     static_cast<TT*>(T->getCanonicalTypeInternal().getTypePtr())
     40 #define GET_EXT_VECTOR_ELEMENT_TYPE(T) \
     41     (((T) == NULL) ? NULL : \
     42                      GET_CANONICAL_TYPE((T)->getElementType().getTypePtr()))
     43 #define GET_POINTEE_TYPE(T) \
     44     (((T) == NULL) ? NULL : \
     45                      GET_CANONICAL_TYPE((T)->getPointeeType().getTypePtr()))
     46 #define GET_CONSTANT_ARRAY_ELEMENT_TYPE(T)  \
     47     (((T) == NULL) ? NULL : \
     48                      GET_CANONICAL_TYPE((T)->getElementType().getTypePtr()))
     49 #define DUMMY_RS_TYPE_NAME_PREFIX   "<"
     50 #define DUMMY_RS_TYPE_NAME_POSTFIX  ">"
     51 #define DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE  \
     52     DUMMY_RS_TYPE_NAME_PREFIX"ConstantArray"DUMMY_RS_TYPE_NAME_POSTFIX
     53 
     54 union RSType;
     55 
     56 namespace llvm {
     57   class Type;
     58 }   // namespace llvm
     59 
     60 namespace slang {
     61 
     62   class RSContext;
     63 
     64 typedef struct {
     65     const char * rs_type;
     66     const char * rs_short_type;
     67     uint32_t size_in_bits;
     68     const char * c_name;
     69     const char * java_name;
     70     const char * rs_c_vector_prefix;
     71     const char * rs_java_vector_prefix;
     72     bool java_promotion;
     73 } RSReflectionType;
     74 
     75 
     76 typedef struct RSReflectionTypeData_rec {
     77     const RSReflectionType *type;
     78     uint32_t vecSize;
     79     bool isPointer;
     80     uint32_t arraySize;
     81 
     82     // Subelements
     83     //std::vector<const struct RSReflectionTypeData_rec *> fields;
     84     //std::vector< std::string > fieldNames;
     85     //std::vector< uint32_t> fieldOffsetBytes;
     86 } RSReflectionTypeData;
     87 
     88 
     89 class RSExportType : public RSExportable {
     90   friend class RSExportElement;
     91  public:
     92   typedef enum {
     93     ExportClassPrimitive,
     94     ExportClassPointer,
     95     ExportClassVector,
     96     ExportClassMatrix,
     97     ExportClassConstantArray,
     98     ExportClassRecord
     99   } ExportClass;
    100 
    101   void convertToRTD(RSReflectionTypeData *rtd) const;
    102 
    103  private:
    104   ExportClass mClass;
    105   std::string mName;
    106 
    107   // Cache the result after calling convertToLLVMType() at the first time
    108   mutable llvm::Type *mLLVMType;
    109   // Cache the result after calling convertToSpecType() at the first time
    110   mutable union RSType *mSpecType;
    111 
    112  protected:
    113   RSExportType(RSContext *Context,
    114                ExportClass Class,
    115                const llvm::StringRef &Name);
    116 
    117   // Let's make it private since there're some prerequisites to call this
    118   // function.
    119   //
    120   // @T was normalized by calling RSExportType::NormalizeType().
    121   // @TypeName was retrieve from RSExportType::GetTypeName() before calling
    122   //           this.
    123   //
    124   static RSExportType *Create(RSContext *Context,
    125                               const clang::Type *T,
    126                               const llvm::StringRef &TypeName);
    127 
    128   static llvm::StringRef GetTypeName(const clang::Type *T);
    129 
    130   // This function convert the RSExportType to LLVM type. Actually, it should be
    131   // "convert Clang type to LLVM type." However, clang doesn't make this API
    132   // (lib/CodeGen/CodeGenTypes.h) public, we need to do by ourselves.
    133   //
    134   // Once we can get LLVM type, we can use LLVM to get alignment information,
    135   // allocation size of a given type and structure layout that LLVM used
    136   // (all of these information are target dependent) without dealing with these
    137   // by ourselves.
    138   virtual llvm::Type *convertToLLVMType() const = 0;
    139   // Record type may recursively reference its type definition. We need a
    140   // temporary type setup before the type construction gets done.
    141   inline void setAbstractLLVMType(llvm::Type *LLVMType) const {
    142     mLLVMType = LLVMType;
    143   }
    144 
    145   virtual union RSType *convertToSpecType() const = 0;
    146   inline void setSpecTypeTemporarily(union RSType *SpecType) const {
    147     mSpecType = SpecType;
    148   }
    149 
    150   virtual ~RSExportType();
    151 
    152  public:
    153   // This function additionally verifies that the Type T is exportable.
    154   // If it is not, this function returns false. Otherwise it returns true.
    155   static bool NormalizeType(const clang::Type *&T,
    156                             llvm::StringRef &TypeName,
    157                             clang::DiagnosticsEngine *Diags,
    158                             const clang::VarDecl *VD);
    159 
    160   // This function checks whether the specified type can be handled by RS/FS.
    161   // If it cannot, this function returns false. Otherwise it returns true.
    162   // Filterscript has additional restrictions on supported types.
    163   static bool ValidateType(clang::ASTContext &C, clang::QualType QT,
    164                            clang::NamedDecl *ND, clang::SourceLocation Loc,
    165                            unsigned int TargetAPI, bool IsFilterscript);
    166 
    167   // This function ensures that the VarDecl can be properly handled by RS.
    168   // If it cannot, this function returns false. Otherwise it returns true.
    169   // Filterscript has additional restrictions on supported types.
    170   static bool ValidateVarDecl(clang::VarDecl *VD, unsigned int TargetAPI,
    171                               bool IsFilterscript);
    172 
    173   // @T may not be normalized
    174   static RSExportType *Create(RSContext *Context, const clang::Type *T);
    175   static RSExportType *CreateFromDecl(RSContext *Context,
    176                                       const clang::VarDecl *VD);
    177 
    178   static const clang::Type *GetTypeOfDecl(const clang::DeclaratorDecl *DD);
    179 
    180   inline ExportClass getClass() const { return mClass; }
    181 
    182   virtual unsigned getSize() const { return 1; }
    183 
    184   inline llvm::Type *getLLVMType() const {
    185     if (mLLVMType == NULL)
    186       mLLVMType = convertToLLVMType();
    187     return mLLVMType;
    188   }
    189 
    190   inline const union RSType *getSpecType() const {
    191     if (mSpecType == NULL)
    192       mSpecType = convertToSpecType();
    193     return mSpecType;
    194   }
    195 
    196   // Return the number of bits necessary to hold the specified RSExportType
    197   static size_t GetTypeStoreSize(const RSExportType *ET);
    198 
    199   // The size of allocation of specified RSExportType (alignment considered)
    200   static size_t GetTypeAllocSize(const RSExportType *ET);
    201 
    202   inline const std::string &getName() const { return mName; }
    203 
    204   virtual std::string getElementName() const {
    205     // Base case is actually an invalid C/Java identifier.
    206     return "@@INVALID@@";
    207   }
    208 
    209   virtual bool keep();
    210   virtual bool equals(const RSExportable *E) const;
    211 };  // RSExportType
    212 
    213 // Primitive types
    214 class RSExportPrimitiveType : public RSExportType {
    215   friend class RSExportType;
    216   friend class RSExportElement;
    217  public:
    218   // From graphics/java/android/renderscript/Element.java: Element.DataType
    219   typedef enum {
    220     DataTypeIsStruct = -2,
    221     DataTypeUnknown = -1,
    222 
    223 #define ENUM_PRIMITIVE_DATA_TYPE_RANGE(begin_type, end_type)  \
    224     FirstPrimitiveType = DataType ## begin_type,  \
    225     LastPrimitiveType = DataType ## end_type,
    226 
    227 #define ENUM_RS_MATRIX_DATA_TYPE_RANGE(begin_type, end_type)  \
    228     FirstRSMatrixType = DataType ## begin_type,  \
    229     LastRSMatrixType = DataType ## end_type,
    230 
    231 #define ENUM_RS_OBJECT_DATA_TYPE_RANGE(begin_type, end_type)  \
    232     FirstRSObjectType = DataType ## begin_type,  \
    233     LastRSObjectType = DataType ## end_type,
    234 
    235 #define ENUM_RS_DATA_TYPE(type, cname, bits)  \
    236     DataType ## type,
    237 
    238 #include "RSDataTypeEnums.inc"
    239 
    240     DataTypeMax
    241   } DataType;
    242 
    243  private:
    244   // NOTE: There's no any instance of RSExportPrimitiveType which mType
    245   // is of the value DataTypeRSMatrix*. DataTypeRSMatrix* enumeration here is
    246   // only for RSExportPrimitiveType::GetRSObjectType to *recognize* the struct
    247   // rs_matrix{2x2, 3x3, 4x4}. These matrix type are represented as
    248   // RSExportMatrixType.
    249   DataType mType;
    250   bool mNormalized;
    251 
    252   typedef llvm::StringMap<DataType> RSSpecificTypeMapTy;
    253   static llvm::ManagedStatic<RSSpecificTypeMapTy> RSSpecificTypeMap;
    254 
    255   static llvm::Type *RSObjectLLVMType;
    256 
    257   static const size_t SizeOfDataTypeInBits[];
    258   // @T was normalized by calling RSExportType::NormalizeType() before calling
    259   // this.
    260   // @TypeName was retrieved from RSExportType::GetTypeName() before calling
    261   // this
    262   static RSExportPrimitiveType *Create(RSContext *Context,
    263                                        const clang::Type *T,
    264                                        const llvm::StringRef &TypeName,
    265                                        bool Normalized = false);
    266 
    267  protected:
    268   RSExportPrimitiveType(RSContext *Context,
    269                         // for derived class to set their type class
    270                         ExportClass Class,
    271                         const llvm::StringRef &Name,
    272                         DataType DT,
    273                         bool Normalized)
    274       : RSExportType(Context, Class, Name),
    275         mType(DT),
    276         mNormalized(Normalized) {
    277     return;
    278   }
    279 
    280   virtual llvm::Type *convertToLLVMType() const;
    281   virtual union RSType *convertToSpecType() const;
    282 
    283   static DataType GetDataType(RSContext *Context, const clang::Type *T);
    284 
    285  public:
    286   // T is normalized by calling RSExportType::NormalizeType() before
    287   // calling this
    288   static bool IsPrimitiveType(const clang::Type *T);
    289 
    290   // @T may not be normalized
    291   static RSExportPrimitiveType *Create(RSContext *Context,
    292                                        const clang::Type *T);
    293 
    294   static DataType GetRSSpecificType(const llvm::StringRef &TypeName);
    295   static DataType GetRSSpecificType(const clang::Type *T);
    296 
    297   static bool IsRSMatrixType(DataType DT);
    298   static bool IsRSObjectType(DataType DT);
    299   static bool IsRSObjectType(const clang::Type *T) {
    300     return IsRSObjectType(GetRSSpecificType(T));
    301   }
    302 
    303   // Determines whether T is [an array of] struct that contains at least one
    304   // RS object type within it.
    305   static bool IsStructureTypeWithRSObject(const clang::Type *T);
    306 
    307   static size_t GetSizeInBits(const RSExportPrimitiveType *EPT);
    308 
    309   inline DataType getType() const { return mType; }
    310   inline bool isRSObjectType() const {
    311     return ((mType >= FirstRSObjectType) && (mType <= LastRSObjectType));
    312   }
    313 
    314   virtual bool equals(const RSExportable *E) const;
    315 
    316   static RSReflectionType *getRSReflectionType(DataType DT);
    317   static RSReflectionType *getRSReflectionType(
    318       const RSExportPrimitiveType *EPT) {
    319     return getRSReflectionType(EPT->getType());
    320   }
    321 
    322   virtual unsigned getSize() const { return (GetSizeInBits(this) >> 3); }
    323 
    324   std::string getElementName() const {
    325     return getRSReflectionType(this)->rs_short_type;
    326   }
    327 };  // RSExportPrimitiveType
    328 
    329 
    330 class RSExportPointerType : public RSExportType {
    331   friend class RSExportType;
    332   friend class RSExportFunc;
    333  private:
    334   const RSExportType *mPointeeType;
    335 
    336   RSExportPointerType(RSContext *Context,
    337                       const llvm::StringRef &Name,
    338                       const RSExportType *PointeeType)
    339       : RSExportType(Context, ExportClassPointer, Name),
    340         mPointeeType(PointeeType) {
    341     return;
    342   }
    343 
    344   // @PT was normalized by calling RSExportType::NormalizeType() before calling
    345   // this.
    346   static RSExportPointerType *Create(RSContext *Context,
    347                                      const clang::PointerType *PT,
    348                                      const llvm::StringRef &TypeName);
    349 
    350   virtual llvm::Type *convertToLLVMType() const;
    351   virtual union RSType *convertToSpecType() const;
    352 
    353  public:
    354   virtual bool keep();
    355 
    356   inline const RSExportType *getPointeeType() const { return mPointeeType; }
    357 
    358   virtual bool equals(const RSExportable *E) const;
    359 };  // RSExportPointerType
    360 
    361 
    362 class RSExportVectorType : public RSExportPrimitiveType {
    363   friend class RSExportType;
    364   friend class RSExportElement;
    365  private:
    366   unsigned mNumElement;   // number of element
    367 
    368   RSExportVectorType(RSContext *Context,
    369                      const llvm::StringRef &Name,
    370                      DataType DT,
    371                      bool Normalized,
    372                      unsigned NumElement)
    373       : RSExportPrimitiveType(Context, ExportClassVector, Name,
    374                               DT, Normalized),
    375         mNumElement(NumElement) {
    376     return;
    377   }
    378 
    379   // @EVT was normalized by calling RSExportType::NormalizeType() before
    380   // calling this.
    381   static RSExportVectorType *Create(RSContext *Context,
    382                                     const clang::ExtVectorType *EVT,
    383                                     const llvm::StringRef &TypeName,
    384                                     bool Normalized = false);
    385 
    386   virtual llvm::Type *convertToLLVMType() const;
    387   virtual union RSType *convertToSpecType() const;
    388 
    389  public:
    390   static llvm::StringRef GetTypeName(const clang::ExtVectorType *EVT);
    391 
    392   inline unsigned getNumElement() const { return mNumElement; }
    393 
    394   std::string getElementName() const {
    395     std::stringstream Name;
    396     Name << RSExportPrimitiveType::getRSReflectionType(this)->rs_short_type
    397          << "_" << getNumElement();
    398     return Name.str();
    399   }
    400 
    401   virtual bool equals(const RSExportable *E) const;
    402 };
    403 
    404 // Only *square* *float* matrix is supported by now.
    405 //
    406 // struct rs_matrix{2x2,3x3,4x4, ..., NxN} should be defined as the following
    407 // form *exactly*:
    408 //  typedef struct {
    409 //    float m[{NxN}];
    410 //  } rs_matrixNxN;
    411 //
    412 //  where mDim will be N.
    413 class RSExportMatrixType : public RSExportType {
    414   friend class RSExportType;
    415  private:
    416   unsigned mDim;  // dimension
    417 
    418   RSExportMatrixType(RSContext *Context,
    419                      const llvm::StringRef &Name,
    420                      unsigned Dim)
    421     : RSExportType(Context, ExportClassMatrix, Name),
    422       mDim(Dim) {
    423     return;
    424   }
    425 
    426   virtual llvm::Type *convertToLLVMType() const;
    427   virtual union RSType *convertToSpecType() const;
    428 
    429  public:
    430   // @RT was normalized by calling RSExportType::NormalizeType() before
    431   // calling this.
    432   static RSExportMatrixType *Create(RSContext *Context,
    433                                     const clang::RecordType *RT,
    434                                     const llvm::StringRef &TypeName,
    435                                     unsigned Dim);
    436 
    437   inline unsigned getDim() const { return mDim; }
    438 
    439   virtual bool equals(const RSExportable *E) const;
    440 };
    441 
    442 class RSExportConstantArrayType : public RSExportType {
    443   friend class RSExportType;
    444  private:
    445   const RSExportType *mElementType;  // Array element type
    446   unsigned mSize;  // Array size
    447 
    448   RSExportConstantArrayType(RSContext *Context,
    449                             const RSExportType *ElementType,
    450                             unsigned Size)
    451     : RSExportType(Context,
    452                    ExportClassConstantArray,
    453                    DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE),
    454       mElementType(ElementType),
    455       mSize(Size) {
    456     return;
    457   }
    458 
    459   // @CAT was normalized by calling RSExportType::NormalizeType() before
    460   // calling this.
    461   static RSExportConstantArrayType *Create(RSContext *Context,
    462                                            const clang::ConstantArrayType *CAT);
    463 
    464   virtual llvm::Type *convertToLLVMType() const;
    465   virtual union RSType *convertToSpecType() const;
    466 
    467  public:
    468   virtual unsigned getSize() const { return mSize; }
    469   inline const RSExportType *getElementType() const { return mElementType; }
    470 
    471   std::string getElementName() const {
    472     return mElementType->getElementName();
    473   }
    474 
    475   virtual bool keep();
    476   virtual bool equals(const RSExportable *E) const;
    477 };
    478 
    479 class RSExportRecordType : public RSExportType {
    480   friend class RSExportType;
    481  public:
    482   class Field {
    483    private:
    484     const RSExportType *mType;
    485     // Field name
    486     std::string mName;
    487     // Link to the struct that contain this field
    488     const RSExportRecordType *mParent;
    489     // Offset in the container
    490     size_t mOffset;
    491 
    492    public:
    493     Field(const RSExportType *T,
    494           const llvm::StringRef &Name,
    495           const RSExportRecordType *Parent,
    496           size_t Offset)
    497         : mType(T),
    498           mName(Name.data(), Name.size()),
    499           mParent(Parent),
    500           mOffset(Offset) {
    501       return;
    502     }
    503 
    504     inline const RSExportRecordType *getParent() const { return mParent; }
    505     inline const RSExportType *getType() const { return mType; }
    506     inline const std::string &getName() const { return mName; }
    507     inline size_t getOffsetInParent() const { return mOffset; }
    508   };
    509 
    510   typedef std::list<const Field*>::const_iterator const_field_iterator;
    511 
    512   inline const_field_iterator fields_begin() const {
    513     return this->mFields.begin();
    514   }
    515   inline const_field_iterator fields_end() const {
    516     return this->mFields.end();
    517   }
    518 
    519  private:
    520   std::list<const Field*> mFields;
    521   bool mIsPacked;
    522   // Artificial export struct type is not exported by user (and thus it won't
    523   // get reflected)
    524   bool mIsArtificial;
    525   size_t mAllocSize;
    526 
    527   RSExportRecordType(RSContext *Context,
    528                      const llvm::StringRef &Name,
    529                      bool IsPacked,
    530                      bool IsArtificial,
    531                      size_t AllocSize)
    532       : RSExportType(Context, ExportClassRecord, Name),
    533         mIsPacked(IsPacked),
    534         mIsArtificial(IsArtificial),
    535         mAllocSize(AllocSize) {
    536     return;
    537   }
    538 
    539   // @RT was normalized by calling RSExportType::NormalizeType() before calling
    540   // this.
    541   // @TypeName was retrieved from RSExportType::GetTypeName() before calling
    542   // this.
    543   static RSExportRecordType *Create(RSContext *Context,
    544                                     const clang::RecordType *RT,
    545                                     const llvm::StringRef &TypeName,
    546                                     bool mIsArtificial = false);
    547 
    548   virtual llvm::Type *convertToLLVMType() const;
    549   virtual union RSType *convertToSpecType() const;
    550 
    551  public:
    552   inline const std::list<const Field*>& getFields() const { return mFields; }
    553   inline bool isPacked() const { return mIsPacked; }
    554   inline bool isArtificial() const { return mIsArtificial; }
    555   inline size_t getAllocSize() const { return mAllocSize; }
    556 
    557   virtual std::string getElementName() const {
    558     return "ScriptField_" + getName();
    559   }
    560 
    561   virtual bool keep();
    562   virtual bool equals(const RSExportable *E) const;
    563 
    564   ~RSExportRecordType() {
    565     for (std::list<const Field*>::iterator I = mFields.begin(),
    566              E = mFields.end();
    567          I != E;
    568          I++)
    569       if (*I != NULL)
    570         delete *I;
    571     return;
    572   }
    573 };  // RSExportRecordType
    574 
    575 }   // namespace slang
    576 
    577 #endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_EXPORT_TYPE_H_  NOLINT
    578