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 struct DataElementInfo {
35   const char *name;
36   DataType dataType;
37   bool normalized;
38   int vsize;
39 };
40 
41 static 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 
52 const int DataElementInfoTableCount = sizeof(DataElementInfoTable) / sizeof(DataElementInfoTable[0]);
53 
54 // TODO Rename RSExportElement to RSExportDataElement
Init()55 void 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 
Create(RSContext * Context,const clang::Type * T,const ElementInfo * EI)71 RSExportType *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 
CreateFromDecl(RSContext * Context,const clang::DeclaratorDecl * DD)131 RSExportType *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 
167 const RSExportElement::ElementInfo *
GetElementInfo(const llvm::StringRef & Name)168 RSExportElement::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