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