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