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