slang_rs_export_type.h revision ef1707027a18ed0d91a3854476db71024ae0e6da
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
37inline const clang::Type* GetCanonicalType(const clang::Type* T) {
38  if (T == nullptr) {
39    return  nullptr;
40  }
41  return T->getCanonicalTypeInternal().getTypePtr();
42}
43
44inline const clang::Type* GetCanonicalType(clang::QualType QT) {
45  return GetCanonicalType(QT.getTypePtr());
46}
47
48inline const clang::Type* GetExtVectorElementType(const clang::ExtVectorType *T) {
49  if (T == nullptr) {
50    return nullptr;
51  }
52  return GetCanonicalType(T->getElementType());
53}
54
55inline const clang::Type* GetPointeeType(const clang::PointerType *T) {
56  if (T == nullptr) {
57    return nullptr;
58  }
59  return GetCanonicalType(T->getPointeeType());
60}
61
62inline const clang::Type* GetConstantArrayElementType(const clang::ConstantArrayType *T) {
63  if (T == nullptr) {
64    return nullptr;
65  }
66  return GetCanonicalType(T->getElementType());
67}
68
69
70namespace llvm {
71  class Type;
72}   // namespace llvm
73
74namespace slang {
75
76class RSContext;
77
78// Broad grouping of the data types
79enum DataTypeCategory {
80    PrimitiveDataType,
81    MatrixDataType,
82    ObjectDataType
83};
84
85// Denote whether a particular export is intended for a legacy kernel argument.
86// NotLegacyKernelArgument - not a legacy kernel argument (might not even be a
87//                           kernel argument).
88// LegacyKernelArgument    - legacy pass-by-reference kernel argument using
89//                           pointers and no kernel attribute.
90enum ExportKind {
91   NotLegacyKernelArgument,
92   LegacyKernelArgument
93 };
94
95
96// From graphics/java/android/renderscript/Element.java: Element.DataType
97/* NOTE: The values of the enums are found compiled in the bit code (i.e. as
98 * values, not symbolic.  When adding new types, you must add them to the end.
99 * If removing types, you can't re-use the integer value.
100 *
101 * TODO: but if you do this, you won't be able to keep using First* & Last*
102 * for validation.
103 *
104 * IMPORTANT: This enum should correspond one-for-one to the entries found in the
105 * gReflectionsTypes table (except for the two negative numbers).  Don't edit one without
106 * the other.
107 */
108enum DataType {
109    DataTypeIsStruct = -2,
110    DataTypeUnknown = -1,
111
112    DataTypeFloat16 = 0,
113    DataTypeFloat32 = 1,
114    DataTypeFloat64 = 2,
115    DataTypeSigned8 = 3,
116    DataTypeSigned16 = 4,
117    DataTypeSigned32 = 5,
118    DataTypeSigned64 = 6,
119    DataTypeUnsigned8 = 7,
120    DataTypeUnsigned16 = 8,
121    DataTypeUnsigned32 = 9,
122    DataTypeUnsigned64 = 10,
123    DataTypeBoolean = 11,
124    DataTypeUnsigned565 = 12,
125    DataTypeUnsigned5551 = 13,
126    DataTypeUnsigned4444 = 14,
127
128    DataTypeRSMatrix2x2 = 15,
129    DataTypeRSMatrix3x3 = 16,
130    DataTypeRSMatrix4x4 = 17,
131
132    DataTypeRSElement = 18,
133    DataTypeRSType = 19,
134    DataTypeRSAllocation = 20,
135    DataTypeRSSampler = 21,
136    DataTypeRSScript = 22,
137    DataTypeRSMesh = 23,
138    DataTypeRSPath = 24,
139    DataTypeRSProgramFragment = 25,
140    DataTypeRSProgramVertex = 26,
141    DataTypeRSProgramRaster = 27,
142    DataTypeRSProgramStore = 28,
143    DataTypeRSFont = 29,
144
145    // This should always be last and correspond to the size of the gReflectionTypes table.
146    DataTypeMax
147};
148
149typedef struct {
150    // The data type category
151    DataTypeCategory category;
152    // "Common name" in script (C99)
153    const char * s_name;
154    // The element name in RenderScript
155    const char * rs_type;
156    // The short element name in RenderScript
157    const char * rs_short_type;
158    // The size of the type in bits
159    uint32_t size_in_bits;
160    // The reflected name in C code
161    const char * c_name;
162    // The reflected name in Java code
163    const char * java_name;
164    // The array type that is compatible with Allocations of our type,
165    // for use with copyTo(), copyFrom()
166    const char * java_array_element_name;
167    // The prefix for C vector types
168    const char * rs_c_vector_prefix;
169    // The prefix for Java vector types
170    const char * rs_java_vector_prefix;
171    // Indicates an unsigned type undergoing Java promotion
172    bool java_promotion;
173} RSReflectionType;
174
175
176typedef struct RSReflectionTypeData_rec {
177    const RSReflectionType *type;
178    uint32_t vecSize;   // number of elements; one if not a vector
179    bool isPointer;
180    uint32_t arraySize; // number of elements; zero if not an array
181
182    // Subelements
183    //std::vector<const struct RSReflectionTypeData_rec *> fields;
184    //std::vector< std::string > fieldNames;
185    //std::vector< uint32_t> fieldOffsetBytes;
186} RSReflectionTypeData;
187
188// Make a name for types that are too complicated to create the real names.
189std::string CreateDummyName(const char *type, const std::string &name);
190
191inline bool IsDummyName(const llvm::StringRef &Name) {
192  return Name.startswith("<");
193}
194
195class RSExportType : public RSExportable {
196  friend class RSExportElement;
197 public:
198  typedef enum {
199    ExportClassPrimitive,
200    ExportClassPointer,
201    ExportClassVector,
202    ExportClassMatrix,
203    ExportClassConstantArray,
204    ExportClassRecord
205  } ExportClass;
206
207  void convertToRTD(RSReflectionTypeData *rtd) const;
208
209 private:
210  ExportClass mClass;
211  std::string mName;
212
213  // Cache the result after calling convertToLLVMType() at the first time
214  mutable llvm::Type *mLLVMType;
215
216 protected:
217  RSExportType(RSContext *Context,
218               ExportClass Class,
219               const llvm::StringRef &Name);
220
221  // Let's make it private since there're some prerequisites to call this
222  // function.
223  //
224  // @T was normalized by calling RSExportType::NormalizeType().
225  // @TypeName was retrieved from RSExportType::GetTypeName() before calling
226  //           this.
227  // @EK denotes whether this @T is being used for a legacy kernel argument or
228  //     something else.
229  //
230  static RSExportType *Create(RSContext *Context,
231                              const clang::Type *T,
232                              const llvm::StringRef &TypeName,
233                              ExportKind EK);
234
235  static llvm::StringRef GetTypeName(const clang::Type *T);
236
237  // This function convert the RSExportType to LLVM type. Actually, it should be
238  // "convert Clang type to LLVM type." However, clang doesn't make this API
239  // (lib/CodeGen/CodeGenTypes.h) public, we need to do by ourselves.
240  //
241  // Once we can get LLVM type, we can use LLVM to get alignment information,
242  // allocation size of a given type and structure layout that LLVM used
243  // (all of these information are target dependent) without dealing with these
244  // by ourselves.
245  virtual llvm::Type *convertToLLVMType() const = 0;
246  // Record type may recursively reference its type definition. We need a
247  // temporary type setup before the type construction gets done.
248  inline void setAbstractLLVMType(llvm::Type *LLVMType) const {
249    mLLVMType = LLVMType;
250  }
251
252  virtual ~RSExportType();
253
254 public:
255  // This function additionally verifies that the Type T is exportable.
256  // If it is not, this function returns false. Otherwise it returns true.
257  static bool NormalizeType(const clang::Type *&T,
258                            llvm::StringRef &TypeName,
259                            RSContext *Context,
260                            const clang::VarDecl *VD,
261                            ExportKind EK);
262
263  // This function checks whether the specified type can be handled by RS/FS.
264  // If it cannot, this function returns false. Otherwise it returns true.
265  // Filterscript has additional restrictions on supported types.
266  static bool ValidateType(slang::RSContext *Context, clang::ASTContext &C,
267                           clang::QualType QT, const clang::NamedDecl *ND,
268                           clang::SourceLocation Loc, unsigned int TargetAPI,
269                           bool IsFilterscript, bool IsExtern);
270
271  // This function ensures that the VarDecl can be properly handled by RS.
272  // If it cannot, this function returns false. Otherwise it returns true.
273  // Filterscript has additional restrictions on supported types.
274  static bool ValidateVarDecl(slang::RSContext *Context, clang::VarDecl *VD,
275                              unsigned int TargetAPI, bool IsFilterscript);
276
277  // @T may not be normalized
278  static RSExportType *Create(RSContext *Context, const clang::Type *T,
279                              ExportKind EK,
280                              // T is type of VD or of subobject within VD
281                              const clang::VarDecl *VD = nullptr);
282  static RSExportType *CreateFromDecl(RSContext *Context,
283                                      const clang::VarDecl *VD);
284
285  static const clang::Type *GetTypeOfDecl(const clang::DeclaratorDecl *DD);
286
287  inline ExportClass getClass() const { return mClass; }
288
289  inline llvm::Type *getLLVMType() const {
290    if (mLLVMType == nullptr)
291      mLLVMType = convertToLLVMType();
292    return mLLVMType;
293  }
294
295  // Return the maximum number of bytes that may be written when this type is stored.
296  virtual size_t getStoreSize() const;
297
298  // Return the distance in bytes between successive elements of this type; it includes padding.
299  virtual size_t getAllocSize() const;
300
301  inline const std::string &getName() const { return mName; }
302
303  virtual std::string getElementName() const {
304    // Base case is actually an invalid C/Java identifier.
305    return "@@INVALID@@";
306  }
307
308  virtual bool keep();
309  // matchODR(): a helper function for Slang::checkODR() on ODR validation
310  //
311  // The LookInto parameter dictates whether to recursively validate member
312  // types of given compound types. This currently only affects struct
313  // (RSExportRecordType); it has no effect on primitive types, vector types,
314  // or matrix types.
315  //
316  // Consider the following pseudo code of nested struct types:
317  //
318  // Translation unit #1:     Translation unit #2:
319  //
320  // struct Name(AA) {        struct Name(BB) {
321  //   Type(aa) aa;             Type(bb) bb;
322  // };                       };
323  //
324  // struct Name(A)  {        struct Name(B) {
325  //   struct Name(AA) a;       struct Name(BB) b;
326  // };                       };
327  //
328  // Case 1:
329  // Assuming aa and bb do not match (say mismatching just in field name), but
330  // the rest does, then the desirable behavior is to report an ODR violation
331  // on struct BB (vs. struct AA) but not on struct B (vs. struct A), because
332  // BB is the tightest enclosing declaration of the violation, not B.
333  //
334  // For this case, RSExportRecordType::matchODR() has the following behavior:
335  //
336  // A.matchODR(B, true) should NOT report an ODR violation;
337  // AA.matchODR(BB, true) should report an ODR violation w.r.t. struct BB;
338  // A.matchODR(B, false) should not report an error;
339  // AA.matchODR(BB, false) should not report an error.
340  //
341  // Slang::checkODR() acts as a driver for this validation case. It calls
342  // A.matchODR() and AA.matchODR() comparing against B and BB respectively.
343  //
344  // By setting LookInto true when Slang::checkODR() calls matchODR() with
345  // the outermost compound type, and false with any recursively discovered
346  // types, we can ensure the desirable ODR violation reporting behavior.
347  //
348  // Case 2:
349  // Assuming Name(AA) != Name(BB), but the rest of the declarations match,
350  // then the desirable behavior is to report an ODR violation on struct B
351  // (vs. struct A).
352  //
353  // In this case, RSExportRecordType::matchODR() has the following behavior:
354  //
355  // A.matchODR(B, true) should report an ODR violation w.r.t. struct B;
356  // because AA and BB are two different types, AA.matchODR(BB) won't be
357  // called.
358  //
359  // A.matchODR(B, false) should not report an error; this happens, should
360  // there be any more additional enclosing types for A subject to ODR check.
361  virtual bool matchODR(const RSExportType *E, bool LookInto) const;
362};  // RSExportType
363
364// Primitive types
365class RSExportPrimitiveType : public RSExportType {
366  friend class RSExportType;
367  friend class RSExportElement;
368 private:
369  DataType mType;
370  bool mNormalized;
371
372  typedef llvm::StringMap<DataType> RSSpecificTypeMapTy;
373  static llvm::ManagedStatic<RSSpecificTypeMapTy> RSSpecificTypeMap;
374
375  static const size_t SizeOfDataTypeInBits[];
376  // @T was normalized by calling RSExportType::NormalizeType() before calling
377  // this.
378  // @TypeName was retrieved from RSExportType::GetTypeName() before calling
379  // this
380  static RSExportPrimitiveType *Create(RSContext *Context,
381                                       const clang::Type *T,
382                                       const llvm::StringRef &TypeName,
383                                       bool Normalized = false);
384
385 protected:
386  RSExportPrimitiveType(RSContext *Context,
387                        // for derived class to set their type class
388                        ExportClass Class,
389                        const llvm::StringRef &Name,
390                        DataType DT,
391                        bool Normalized)
392      : RSExportType(Context, Class, Name),
393        mType(DT),
394        mNormalized(Normalized) {
395  }
396
397  virtual llvm::Type *convertToLLVMType() const;
398
399  static DataType GetDataType(RSContext *Context, const clang::Type *T);
400
401 public:
402  // T is normalized by calling RSExportType::NormalizeType() before
403  // calling this
404  static bool IsPrimitiveType(const clang::Type *T);
405
406  // @T may not be normalized
407  static RSExportPrimitiveType *Create(RSContext *Context,
408                                       const clang::Type *T);
409
410  static DataType GetRSSpecificType(const llvm::StringRef &TypeName);
411  static DataType GetRSSpecificType(const clang::Type *T);
412
413  static bool IsRSMatrixType(DataType DT);
414  static bool IsRSObjectType(DataType DT);
415  static bool IsRSObjectType(const clang::Type *T) {
416    return IsRSObjectType(GetRSSpecificType(T));
417  }
418
419  // Determines whether T is [an array of] struct that contains at least one
420  // RS object type within it.
421  static bool IsStructureTypeWithRSObject(const clang::Type *T);
422
423  // For a primitive type, this is the size of the type.
424  // For a vector type (RSExportVectorType is derived from RSExportPrimitiveType),
425  // this is the size of a single vector element (component).
426  static size_t GetElementSizeInBits(const RSExportPrimitiveType *EPT);
427
428  inline DataType getType() const { return mType; }
429  inline bool isRSObjectType() const {
430      return IsRSObjectType(mType);
431  }
432
433  bool matchODR(const RSExportType *E, bool LookInto) const override;
434
435  static RSReflectionType *getRSReflectionType(DataType DT);
436  static RSReflectionType *getRSReflectionType(
437      const RSExportPrimitiveType *EPT) {
438    return getRSReflectionType(EPT->getType());
439  }
440
441  // For a vector type, this is the size of a single element.
442  unsigned getElementSizeInBytes() const { return (GetElementSizeInBits(this) >> 3); }
443
444  std::string getElementName() const {
445    return getRSReflectionType(this)->rs_short_type;
446  }
447};  // RSExportPrimitiveType
448
449
450class RSExportPointerType : public RSExportType {
451  friend class RSExportType;
452  friend class RSExportFunc;
453 private:
454  const RSExportType *mPointeeType;
455
456  RSExportPointerType(RSContext *Context,
457                      const llvm::StringRef &Name,
458                      const RSExportType *PointeeType)
459      : RSExportType(Context, ExportClassPointer, Name),
460        mPointeeType(PointeeType) {
461  }
462
463  // @PT was normalized by calling RSExportType::NormalizeType() before calling
464  // this.
465  static RSExportPointerType *Create(RSContext *Context,
466                                     const clang::PointerType *PT,
467                                     const llvm::StringRef &TypeName);
468
469  virtual llvm::Type *convertToLLVMType() const;
470
471 public:
472  virtual bool keep();
473
474  inline const RSExportType *getPointeeType() const { return mPointeeType; }
475
476  bool matchODR(const RSExportType *E, bool LookInto) const override;
477};  // RSExportPointerType
478
479
480class RSExportVectorType : public RSExportPrimitiveType {
481  friend class RSExportType;
482  friend class RSExportElement;
483 private:
484  unsigned mNumElement;   // number of elements (components)
485
486  RSExportVectorType(RSContext *Context,
487                     const llvm::StringRef &Name,
488                     DataType DT,
489                     bool Normalized,
490                     unsigned NumElement)
491      : RSExportPrimitiveType(Context, ExportClassVector, Name,
492                              DT, Normalized),
493        mNumElement(NumElement) {
494  }
495
496  // @EVT was normalized by calling RSExportType::NormalizeType() before
497  // calling this.
498  static RSExportVectorType *Create(RSContext *Context,
499                                    const clang::ExtVectorType *EVT,
500                                    const llvm::StringRef &TypeName,
501                                    bool Normalized = false);
502
503  virtual llvm::Type *convertToLLVMType() const;
504
505 public:
506  static llvm::StringRef GetTypeName(const clang::ExtVectorType *EVT);
507
508  inline unsigned getNumElement() const { return mNumElement; }
509
510  std::string getElementName() const {
511    std::stringstream Name;
512    Name << RSExportPrimitiveType::getRSReflectionType(this)->rs_short_type
513         << "_" << getNumElement();
514    return Name.str();
515  }
516
517  bool matchODR(const RSExportType *E, bool LookInto) const override;
518};
519
520// Only *square* *float* matrix is supported by now.
521//
522// struct rs_matrix{2x2,3x3,4x4, ..., NxN} should be defined as the following
523// form *exactly*:
524//  typedef struct {
525//    float m[{NxN}];
526//  } rs_matrixNxN;
527//
528//  where mDim will be N.
529class RSExportMatrixType : public RSExportType {
530  friend class RSExportType;
531 private:
532  unsigned mDim;  // dimension
533
534  RSExportMatrixType(RSContext *Context,
535                     const llvm::StringRef &Name,
536                     unsigned Dim)
537    : RSExportType(Context, ExportClassMatrix, Name),
538      mDim(Dim) {
539  }
540
541  virtual llvm::Type *convertToLLVMType() const;
542
543 public:
544  // @RT was normalized by calling RSExportType::NormalizeType() before
545  // calling this.
546  static RSExportMatrixType *Create(RSContext *Context,
547                                    const clang::RecordType *RT,
548                                    const llvm::StringRef &TypeName,
549                                    unsigned Dim);
550
551  inline unsigned getDim() const { return mDim; }
552
553  bool matchODR(const RSExportType *E, bool LookInto) const override;
554
555};
556
557class RSExportConstantArrayType : public RSExportType {
558  friend class RSExportType;
559 private:
560  const RSExportType *mElementType;  // Array element type
561  unsigned mNumElement;              // Array element count
562
563  RSExportConstantArrayType(RSContext *Context,
564                            const RSExportType *ElementType,
565                            unsigned NumElement)
566    : RSExportType(Context, ExportClassConstantArray, "<ConstantArray>"),
567      mElementType(ElementType),
568      mNumElement(NumElement) {
569  }
570
571  // @CAT was normalized by calling RSExportType::NormalizeType() before
572  // calling this.
573  static RSExportConstantArrayType *Create(RSContext *Context,
574                                           const clang::ConstantArrayType *CAT);
575
576  virtual llvm::Type *convertToLLVMType() const;
577
578 public:
579  unsigned getNumElement() const { return mNumElement; }
580  const RSExportType *getElementType() const { return mElementType; }
581
582  std::string getElementName() const {
583    return mElementType->getElementName();
584  }
585
586  virtual bool keep();
587  bool matchODR(const RSExportType *E, bool LookInto) const override;
588};
589
590class RSExportRecordType : public RSExportType {
591  friend class RSExportType;
592 public:
593  class Field {
594   private:
595    const RSExportType *mType;
596    // Field name
597    std::string mName;
598    // Link to the struct that contain this field
599    const RSExportRecordType *mParent;
600    // Offset in the container
601    size_t mOffset;
602
603   public:
604    Field(const RSExportType *T,
605          const llvm::StringRef &Name,
606          const RSExportRecordType *Parent,
607          size_t Offset)
608        : mType(T),
609          mName(Name.data(), Name.size()),
610          mParent(Parent),
611          mOffset(Offset) {
612    }
613
614    inline const RSExportRecordType *getParent() const { return mParent; }
615    inline const RSExportType *getType() const { return mType; }
616    inline const std::string &getName() const { return mName; }
617    inline size_t getOffsetInParent() const { return mOffset; }
618  };
619
620  typedef std::list<const Field*>::const_iterator const_field_iterator;
621
622  inline const_field_iterator fields_begin() const {
623    return this->mFields.begin();
624  }
625  inline const_field_iterator fields_end() const {
626    return this->mFields.end();
627  }
628
629 private:
630  std::list<const Field*> mFields;
631  bool mIsPacked;
632  // Artificial export struct type is not exported by user (and thus it won't
633  // get reflected)
634  bool mIsArtificial;
635  size_t mStoreSize;
636  size_t mAllocSize;
637
638  RSExportRecordType(RSContext *Context,
639                     const llvm::StringRef &Name,
640                     bool IsPacked,
641                     bool IsArtificial,
642                     size_t StoreSize,
643                     size_t AllocSize)
644      : RSExportType(Context, ExportClassRecord, Name),
645        mIsPacked(IsPacked),
646        mIsArtificial(IsArtificial),
647        mStoreSize(StoreSize),
648        mAllocSize(AllocSize) {
649  }
650
651  // @RT was normalized by calling RSExportType::NormalizeType() before calling
652  // this.
653  // @TypeName was retrieved from RSExportType::GetTypeName() before calling
654  // this.
655  static RSExportRecordType *Create(RSContext *Context,
656                                    const clang::RecordType *RT,
657                                    const llvm::StringRef &TypeName,
658                                    bool mIsArtificial = false);
659
660  virtual llvm::Type *convertToLLVMType() const;
661
662 public:
663  inline const std::list<const Field*>& getFields() const { return mFields; }
664  inline bool isPacked() const { return mIsPacked; }
665  inline bool isArtificial() const { return mIsArtificial; }
666  virtual size_t getStoreSize() const { return mStoreSize; }
667  virtual size_t getAllocSize() const { return mAllocSize; }
668
669  virtual std::string getElementName() const {
670    return "ScriptField_" + getName();
671  }
672
673  virtual bool keep();
674  bool matchODR(const RSExportType *E, bool LookInto) const override;
675
676  ~RSExportRecordType() {
677    for (std::list<const Field*>::iterator I = mFields.begin(),
678             E = mFields.end();
679         I != E;
680         I++)
681      if (*I != nullptr)
682        delete *I;
683  }
684};  // RSExportRecordType
685
686}   // namespace slang
687
688#endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_EXPORT_TYPE_H_  NOLINT
689