Home | History | Annotate | Download | only in slang
      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_element.h"
     18 
     19 #include "clang/AST/Decl.h"
     20 #include "clang/AST/Type.h"
     21 
     22 #include "clang/Basic/SourceLocation.h"
     23 #include "clang/Basic/IdentifierTable.h"
     24 
     25 #include "slang_assert.h"
     26 #include "slang_rs_context.h"
     27 #include "slang_rs_export_type.h"
     28 
     29 namespace slang {
     30 
     31 bool RSExportElement::Initialized = false;
     32 RSExportElement::ElementInfoMapTy RSExportElement::ElementInfoMap;
     33 
     34 void RSExportElement::Init() {
     35   if (!Initialized) {
     36     // Initialize ElementInfoMap
     37 #define ENUM_RS_DATA_ELEMENT(_name, _dt, _norm, _vsize)  \
     38     {                                                         \
     39       ElementInfo *EI = new ElementInfo;                      \
     40       EI->type = RSExportPrimitiveType::DataType ## _dt;      \
     41       EI->normalized = _norm;                                 \
     42       EI->vsize = _vsize;                                     \
     43                                                               \
     44       llvm::StringRef Name(_name);                            \
     45       ElementInfoMap.insert(                                  \
     46           ElementInfoMapTy::value_type::Create(               \
     47               Name.begin(),                                   \
     48               Name.end(),                                     \
     49               ElementInfoMap.getAllocator(),                  \
     50               EI));                                           \
     51     }
     52 #include "RSDataElementEnums.inc"
     53 
     54     Initialized = true;
     55   }
     56   return;
     57 }
     58 
     59 RSExportType *RSExportElement::Create(RSContext *Context,
     60                                       const clang::Type *T,
     61                                       const ElementInfo *EI) {
     62   // Create RSExportType corresponded to the @T first and then verify
     63 
     64   llvm::StringRef TypeName;
     65   RSExportType *ET = NULL;
     66 
     67   if (!Initialized)
     68     Init();
     69 
     70   slangAssert(EI != NULL && "Element info not found");
     71 
     72   if (!RSExportType::NormalizeType(T, TypeName, Context->getDiagnostics(),
     73                                    NULL))
     74     return NULL;
     75 
     76   switch (T->getTypeClass()) {
     77     case clang::Type::Builtin:
     78     case clang::Type::Pointer: {
     79       slangAssert(EI->vsize == 1 && "Element not a primitive class (please "
     80                                     "check your macro)");
     81       RSExportPrimitiveType *EPT =
     82           RSExportPrimitiveType::Create(Context,
     83                                         T,
     84                                         TypeName,
     85                                         EI->normalized);
     86       // Verify
     87       slangAssert(EI->type == EPT->getType() && "Element has unexpected type");
     88       ET = EPT;
     89       break;
     90     }
     91     case clang::Type::ExtVector: {
     92       slangAssert(EI->vsize > 1 && "Element not a vector class (please check "
     93                                    "your macro)");
     94       RSExportVectorType *EVT =
     95           RSExportVectorType::Create(Context,
     96                                      static_cast<const clang::ExtVectorType*>(
     97                                          T->getCanonicalTypeInternal()
     98                                              .getTypePtr()),
     99                                      TypeName,
    100                                      EI->normalized);
    101       // Verify
    102       slangAssert(EI->type == EVT->getType() && "Element has unexpected type");
    103       slangAssert(EI->vsize == EVT->getNumElement() && "Element has unexpected "
    104                                                        "size of vector");
    105       ET = EVT;
    106       break;
    107     }
    108     default: {
    109       // TODO(zonr): warn that type is not exportable
    110       fprintf(stderr, "RSExportElement::Create : type '%s' is not exportable\n",
    111               T->getTypeClassName());
    112       break;
    113     }
    114   }
    115 
    116   return ET;
    117 }
    118 
    119 RSExportType *RSExportElement::CreateFromDecl(RSContext *Context,
    120                                               const clang::DeclaratorDecl *DD) {
    121   const clang::Type* T = RSExportType::GetTypeOfDecl(DD);
    122   const clang::Type* CT = GET_CANONICAL_TYPE(T);
    123   const ElementInfo* EI = NULL;
    124 
    125   // Note: RS element like rs_pixel_rgb elements are either in the type of
    126   // primitive or vector.
    127   if ((CT->getTypeClass() != clang::Type::Builtin) &&
    128       (CT->getTypeClass() != clang::Type::ExtVector)) {
    129     return RSExportType::Create(Context, T);
    130   }
    131 
    132   // Following the typedef chain to see whether it's an element name like
    133   // rs_pixel_rgb or its alias (via typedef).
    134   while (T != CT) {
    135     if (T->getTypeClass() != clang::Type::Typedef) {
    136       break;
    137     } else {
    138       const clang::TypedefType *TT = static_cast<const clang::TypedefType*>(T);
    139       const clang::TypedefNameDecl *TD = TT->getDecl();
    140       EI = GetElementInfo(TD->getName());
    141       if (EI != NULL)
    142         break;
    143 
    144       T = TD->getUnderlyingType().getTypePtr();
    145     }
    146   }
    147 
    148   if (EI == NULL) {
    149     return RSExportType::Create(Context, T);
    150   } else {
    151     return RSExportElement::Create(Context, T, EI);
    152   }
    153 }
    154 
    155 const RSExportElement::ElementInfo *
    156 RSExportElement::GetElementInfo(const llvm::StringRef &Name) {
    157   if (!Initialized)
    158     Init();
    159 
    160   ElementInfoMapTy::const_iterator I = ElementInfoMap.find(Name);
    161   if (I == ElementInfoMap.end())
    162     return NULL;
    163   else
    164     return I->getValue();
    165 }
    166 
    167 }  // namespace slang
    168