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