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