slang_rs_context.cpp revision fb40ee2a90f37967bf4a40a18dec7f60e5c580d8
1/*
2 * Copyright 2010-2012, 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_context.h"
18
19#include <string>
20
21#include "clang/AST/ASTContext.h"
22#include "clang/AST/Attr.h"
23#include "clang/AST/Decl.h"
24#include "clang/AST/DeclBase.h"
25#include "clang/AST/Mangle.h"
26#include "clang/AST/Type.h"
27
28#include "clang/Basic/Linkage.h"
29#include "clang/Basic/TargetInfo.h"
30
31#include "llvm/IR/LLVMContext.h"
32#include "llvm/IR/DataLayout.h"
33
34#include "slang.h"
35#include "slang_assert.h"
36#include "slang_rs_export_foreach.h"
37#include "slang_rs_export_func.h"
38#include "slang_rs_export_reduce.h"
39#include "slang_rs_export_type.h"
40#include "slang_rs_export_var.h"
41#include "slang_rs_exportable.h"
42#include "slang_rs_pragma_handler.h"
43#include "slang_rs_reflection.h"
44#include "slang_rs_special_func.h"
45
46namespace slang {
47
48RSContext::RSContext(clang::Preprocessor &PP,
49                     clang::ASTContext &Ctx,
50                     const clang::TargetInfo &Target,
51                     PragmaList *Pragmas,
52                     unsigned int TargetAPI,
53                     bool Verbose)
54    : mPP(PP),
55      mCtx(Ctx),
56      mPragmas(Pragmas),
57      mTargetAPI(TargetAPI),
58      mVerbose(Verbose),
59      mDataLayout(nullptr),
60      mLLVMContext(llvm::getGlobalContext()),
61      mLicenseNote(nullptr),
62      mRSPackageName("android.renderscript"),
63      version(0),
64      mMangleCtx(Ctx.createMangleContext()),
65      mIs64Bit(Target.getPointerWidth(0) == 64),
66      mNextSlot(1) {
67
68  AddPragmaHandlers(PP, this);
69
70  // Prepare target data
71  mDataLayout = new llvm::DataLayout(Target.getTargetDescription());
72
73  // Reserve slot 0 for the root kernel.
74  mExportForEach.push_back(nullptr);
75}
76
77bool RSContext::processExportVar(const clang::VarDecl *VD) {
78  slangAssert(!VD->getName().empty() && "Variable name should not be empty");
79
80  // TODO(zonr): some check on variable
81
82  RSExportType *ET = RSExportType::CreateFromDecl(this, VD);
83  if (!ET)
84    return false;
85
86  RSExportVar *EV = new RSExportVar(this, VD, ET);
87  if (EV == nullptr)
88    return false;
89  else
90    mExportVars.push_back(EV);
91
92  return true;
93}
94
95int RSContext::getForEachSlotNumber(const clang::FunctionDecl* FD) {
96  const clang::StringRef& funcName = FD->getName();
97  return getForEachSlotNumber(funcName);
98}
99
100int RSContext::getForEachSlotNumber(const clang::StringRef& funcName) {
101  auto it = mExportForEachMap.find(funcName);
102  if (it == mExportForEachMap.end()) {
103    return -1;
104  }
105  return it->second;
106}
107
108bool RSContext::processExportFunc(const clang::FunctionDecl *FD) {
109  slangAssert(!FD->getName().empty() && "Function name should not be empty");
110
111  if (!FD->isThisDeclarationADefinition()) {
112    return true;
113  }
114
115  if (FD->getStorageClass() != clang::SC_None) {
116    fprintf(stderr, "RSContext::processExportFunc : cannot export extern or "
117                    "static function '%s'\n", FD->getName().str().c_str());
118    return false;
119  }
120
121  // Specialized function
122  if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) {
123    // Do not reflect specialized functions like init, dtor, or graphics root.
124    return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD);
125  }
126
127  // Foreach kernel
128  if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) {
129    RSExportForEach *EFE = RSExportForEach::Create(this, FD);
130    if (EFE == nullptr) {
131      return false;
132    }
133    const llvm::StringRef& funcName = FD->getName();
134    if (funcName.equals("root")) {
135      mExportForEach[0] = EFE;
136    } else {
137      mExportForEach.push_back(EFE);
138    }
139    return true;
140  }
141
142  // Reduce kernel
143  if (RSExportReduce::isRSReduceFunc(mTargetAPI, FD)) {
144    if (auto *ER = RSExportReduce::Create(this, FD)) {
145      mExportReduce.push_back(ER);
146      return true;
147    }
148    return false;
149  }
150
151  // Invokable
152  if (auto *EF = RSExportFunc::Create(this, FD)) {
153    mExportFuncs.push_back(EF);
154    return true;
155  }
156
157  return false;
158}
159
160bool RSContext::addForEach(const clang::FunctionDecl* FD) {
161  const llvm::StringRef& funcName = FD->getName();
162
163  if (funcName.equals("root")) {
164    // The root kernel should always be in slot 0.
165    mExportForEachMap.insert(std::make_pair(funcName, 0));
166  } else {
167    mExportForEachMap.insert(std::make_pair(funcName, mNextSlot++));
168  }
169
170  return true;
171}
172
173bool RSContext::processExportType(const llvm::StringRef &Name) {
174  clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
175
176  slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level "
177                                   "declaration) is null object");
178
179  const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name);
180  if (II == nullptr)
181    // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
182    //             found
183    return false;
184
185  clang::DeclContext::lookup_result R = TUDecl->lookup(II);
186  RSExportType *ET = nullptr;
187
188  for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end();
189       I != E;
190       I++) {
191    clang::NamedDecl *const ND = *I;
192    const clang::Type *T = nullptr;
193
194    switch (ND->getKind()) {
195      case clang::Decl::Typedef: {
196        T = static_cast<const clang::TypedefDecl*>(
197            ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr();
198        break;
199      }
200      case clang::Decl::Record: {
201        T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl();
202        break;
203      }
204      default: {
205        // unsupported, skip
206        break;
207      }
208    }
209
210    if (T != nullptr)
211      ET = RSExportType::Create(this, T);
212  }
213
214  return (ET != nullptr);
215}
216
217void RSContext::addAllocationType(const clang::TypeDecl* TD) {
218  mAllocationType = mCtx.getTypeDeclType(TD);
219}
220
221bool RSContext::processExports() {
222  bool valid = true;
223
224  if (getDiagnostics()->hasErrorOccurred()) {
225    return false;
226  }
227
228  clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
229  for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) {
230    clang::Decl* D = *I;
231    switch (D->getKind()) {
232    case clang::Decl::Var: {
233      clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D);
234      if (VD->getFormalLinkage() == clang::ExternalLinkage) {
235        if (!processExportVar(VD)) {
236          valid = false;
237        }
238      }
239      break;
240    }
241    case clang::Decl::Function: {
242      clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D);
243      if (FD->getFormalLinkage() == clang::ExternalLinkage) {
244        if (!processExportFunc(FD)) {
245          valid = false;
246        }
247      }
248      break;
249    }
250    default:
251      break;
252    }
253  }
254
255  // Create a dummy root in slot 0 if a root kernel is not seen.
256  if (valid && mExportForEach[0] == nullptr) {
257    mExportForEach[0] = RSExportForEach::CreateDummyRoot(this);
258  }
259
260  // Finally, export type forcely set to be exported by user
261  for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
262           EE = mNeedExportTypes.end();
263       EI != EE;
264       EI++) {
265    if (!processExportType(EI->getKey())) {
266      valid = false;
267    }
268  }
269
270  return valid;
271}
272
273bool RSContext::insertExportType(const llvm::StringRef &TypeName,
274                                 RSExportType *ET) {
275  ExportTypeMap::value_type *NewItem =
276      ExportTypeMap::value_type::Create(TypeName,
277                                        mExportTypes.getAllocator(),
278                                        ET);
279
280  if (mExportTypes.insert(NewItem)) {
281    return true;
282  } else {
283    NewItem->Destroy(mExportTypes.getAllocator());
284    return false;
285  }
286}
287
288RSContext::~RSContext() {
289  delete mLicenseNote;
290  delete mDataLayout;
291  for (ExportableList::iterator I = mExportables.begin(),
292          E = mExportables.end();
293       I != E;
294       I++) {
295    if (!(*I)->isKeep())
296      delete *I;
297  }
298}
299
300}  // namespace slang
301