slang_rs_export_element.cpp revision 48d893dc7794b3cfb74f35955ca763ee4170f9ad
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
29namespace slang {
30
31bool RSExportElement::Initialized = false;
32RSExportElement::ElementInfoMapTy RSExportElement::ElementInfoMap;
33
34void 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
59RSExportType *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, NULL))
73    return NULL;
74
75  switch (T->getTypeClass()) {
76    case clang::Type::Builtin:
77    case clang::Type::Pointer: {
78      slangAssert(EI->vsize == 1 && "Element not a primitive class (please "
79                                    "check your macro)");
80      RSExportPrimitiveType *EPT =
81          RSExportPrimitiveType::Create(Context,
82                                        T,
83                                        TypeName,
84                                        EI->normalized);
85      // Verify
86      slangAssert(EI->type == EPT->getType() && "Element has unexpected type");
87      ET = EPT;
88      break;
89    }
90    case clang::Type::ExtVector: {
91      slangAssert(EI->vsize > 1 && "Element not a vector class (please check "
92                                   "your macro)");
93      RSExportVectorType *EVT =
94          RSExportVectorType::Create(Context,
95                                     static_cast<const clang::ExtVectorType*>(
96                                         T->getCanonicalTypeInternal()
97                                             .getTypePtr()),
98                                     TypeName,
99                                     EI->normalized);
100      // Verify
101      slangAssert(EI->type == EVT->getType() && "Element has unexpected type");
102      slangAssert(EI->vsize == EVT->getNumElement() && "Element has unexpected "
103                                                       "size of vector");
104      ET = EVT;
105      break;
106    }
107    default: {
108      // TODO(zonr): warn that type is not exportable
109      fprintf(stderr, "RSExportElement::Create : type '%s' is not exportable\n",
110              T->getTypeClassName());
111      break;
112    }
113  }
114
115  return ET;
116}
117
118RSExportType *RSExportElement::CreateFromDecl(RSContext *Context,
119                                              const clang::DeclaratorDecl *DD) {
120  const clang::Type* T = RSExportType::GetTypeOfDecl(DD);
121  const clang::Type* CT = GET_CANONICAL_TYPE(T);
122  const ElementInfo* EI = NULL;
123
124  // Note: RS element like rs_pixel_rgb elements are either in the type of
125  // primitive or vector.
126  if ((CT->getTypeClass() != clang::Type::Builtin) &&
127      (CT->getTypeClass() != clang::Type::ExtVector)) {
128    return RSExportType::Create(Context, T);
129  }
130
131  // Following the typedef chain to see whether it's an element name like
132  // rs_pixel_rgb or its alias (via typedef).
133  while (T != CT) {
134    if (T->getTypeClass() != clang::Type::Typedef) {
135      break;
136    } else {
137      const clang::TypedefType *TT = static_cast<const clang::TypedefType*>(T);
138      const clang::TypedefNameDecl *TD = TT->getDecl();
139      EI = GetElementInfo(TD->getName());
140      if (EI != NULL)
141        break;
142
143      T = TD->getUnderlyingType().getTypePtr();
144    }
145  }
146
147  if (EI == NULL) {
148    return RSExportType::Create(Context, T);
149  } else {
150    return RSExportElement::Create(Context, T, EI);
151  }
152}
153
154const RSExportElement::ElementInfo *
155RSExportElement::GetElementInfo(const llvm::StringRef &Name) {
156  if (!Initialized)
157    Init();
158
159  ElementInfoMapTy::const_iterator I = ElementInfoMap.find(Name);
160  if (I == ElementInfoMap.end())
161    return NULL;
162  else
163    return I->getValue();
164}
165
166}  // namespace slang
167