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