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