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