slang_rs_context.cpp revision 40a0911e5cbdf600bce5a390148865626ac7086c
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  RSExportType *ET = RSExportType::CreateFromDecl(this, VD);
81  if (!ET)
82    return false;
83
84  RSExportVar *EV = new RSExportVar(this, VD, ET);
85  if (EV == nullptr)
86    return false;
87  else
88    mExportVars.push_back(EV);
89
90  return true;
91}
92
93int RSContext::getForEachSlotNumber(const clang::FunctionDecl* FD) {
94  const clang::StringRef& funcName = FD->getName();
95  return getForEachSlotNumber(funcName);
96}
97
98int RSContext::getForEachSlotNumber(const clang::StringRef& funcName) {
99  auto it = mExportForEachMap.find(funcName);
100  if (it == mExportForEachMap.end()) {
101    return -1;
102  }
103  return it->second;
104}
105
106bool RSContext::processExportFunc(const clang::FunctionDecl *FD) {
107  slangAssert(!FD->getName().empty() && "Function name should not be empty");
108
109  if (!FD->isThisDeclarationADefinition()) {
110    return true;
111  }
112
113  if (FD->getStorageClass() != clang::SC_None) {
114    fprintf(stderr, "RSContext::processExportFunc : cannot export extern or "
115                    "static function '%s'\n", FD->getName().str().c_str());
116    return false;
117  }
118
119  // Specialized function
120  if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) {
121    // Do not reflect specialized functions like init, dtor, or graphics root.
122    return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD);
123  }
124
125  // Foreach kernel
126  if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) {
127    RSExportForEach *EFE = RSExportForEach::Create(this, FD);
128    if (EFE == nullptr) {
129      return false;
130    }
131    const llvm::StringRef& funcName = FD->getName();
132    if (funcName.equals("root")) {
133      mExportForEach[0] = EFE;
134    } else {
135      mExportForEach.push_back(EFE);
136    }
137    return true;
138  }
139
140  // Reduce kernel
141  if (RSExportReduce::isRSReduceFunc(mTargetAPI, FD)) {
142    if (auto *ER = RSExportReduce::Create(this, FD)) {
143      mExportReduce.push_back(ER);
144      return true;
145    }
146    return false;
147  }
148
149  // Invokable
150  if (auto *EF = RSExportFunc::Create(this, FD)) {
151    mExportFuncs.push_back(EF);
152    return true;
153  }
154
155  return false;
156}
157
158bool RSContext::addForEach(const clang::FunctionDecl* FD) {
159  const llvm::StringRef& funcName = FD->getName();
160
161  if (funcName.equals("root")) {
162    // The root kernel should always be in slot 0.
163    mExportForEachMap.insert(std::make_pair(funcName, 0));
164  } else {
165    mExportForEachMap.insert(std::make_pair(funcName, mNextSlot++));
166  }
167
168  return true;
169}
170
171bool RSContext::processExportType(const llvm::StringRef &Name) {
172  clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
173
174  slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level "
175                                   "declaration) is null object");
176
177  const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name);
178  if (II == nullptr)
179    // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
180    //             found
181    return false;
182
183  clang::DeclContext::lookup_result R = TUDecl->lookup(II);
184  RSExportType *ET = nullptr;
185
186  for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end();
187       I != E;
188       I++) {
189    clang::NamedDecl *const ND = *I;
190    const clang::Type *T = nullptr;
191
192    switch (ND->getKind()) {
193      case clang::Decl::Typedef: {
194        T = static_cast<const clang::TypedefDecl*>(
195            ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr();
196        break;
197      }
198      case clang::Decl::Record: {
199        T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl();
200        break;
201      }
202      default: {
203        // unsupported, skip
204        break;
205      }
206    }
207
208    if (T != nullptr)
209      ET = RSExportType::Create(this, T, NotLegacyKernelArgument);
210  }
211
212  return (ET != nullptr);
213}
214
215void RSContext::setAllocationType(const clang::TypeDecl* TD) {
216  mAllocationType = mCtx.getTypeDeclType(TD);
217}
218
219void RSContext::setScriptCallType(const clang::TypeDecl* TD) {
220  mScriptCallType = mCtx.getTypeDeclType(TD);
221}
222
223bool RSContext::processExports() {
224  bool valid = true;
225
226  if (getDiagnostics()->hasErrorOccurred()) {
227    return false;
228  }
229
230  clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
231  for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) {
232    clang::Decl* D = *I;
233    switch (D->getKind()) {
234    case clang::Decl::Var: {
235      clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D);
236      bool ShouldExportVariable = true;
237      if (VD->getFormalLinkage() == clang::ExternalLinkage) {
238        clang::QualType QT = VD->getTypeSourceInfo()->getType();
239        if (QT.isConstQualified() && !VD->hasInit()) {
240          if (Slang::IsLocInRSHeaderFile(VD->getLocation(),
241                                         *getSourceManager())) {
242            // We don't export variables internal to the runtime's
243            // implementation.
244            ShouldExportVariable = false;
245          } else {
246            clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
247            DiagEngine->Report(VD->getLocation(), DiagEngine->getCustomDiagID(
248                clang::DiagnosticsEngine::Error,
249                "invalid declaration of uninitialized constant variable '%0'"))
250              << VD->getName();
251            valid = false;
252          }
253        }
254        if (valid && ShouldExportVariable && !processExportVar(VD)) {
255          valid = false;
256        }
257      }
258      break;
259    }
260    case clang::Decl::Function: {
261      clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D);
262      if (FD->getFormalLinkage() == clang::ExternalLinkage) {
263        if (!processExportFunc(FD)) {
264          valid = false;
265        }
266      }
267      break;
268    }
269    default:
270      break;
271    }
272  }
273
274  // Create a dummy root in slot 0 if a root kernel is not seen
275  // and there exists a non-root kernel.
276  if (valid && mExportForEach[0] == nullptr) {
277    const size_t numExportedForEach = mExportForEach.size();
278    if (numExportedForEach > 1) {
279      mExportForEach[0] = RSExportForEach::CreateDummyRoot(this);
280    } else {
281      slangAssert(numExportedForEach == 1);
282      mExportForEach.pop_back();
283    }
284  }
285
286  // Finally, export type forcely set to be exported by user
287  for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
288           EE = mNeedExportTypes.end();
289       EI != EE;
290       EI++) {
291    if (!processExportType(EI->getKey())) {
292      valid = false;
293    }
294  }
295
296  return valid;
297}
298
299bool RSContext::insertExportType(const llvm::StringRef &TypeName,
300                                 RSExportType *ET) {
301  ExportTypeMap::value_type *NewItem =
302      ExportTypeMap::value_type::Create(TypeName,
303                                        mExportTypes.getAllocator(),
304                                        ET);
305
306  if (mExportTypes.insert(NewItem)) {
307    return true;
308  } else {
309    NewItem->Destroy(mExportTypes.getAllocator());
310    return false;
311  }
312}
313
314RSContext::~RSContext() {
315  delete mLicenseNote;
316  delete mDataLayout;
317  for (ExportableList::iterator I = mExportables.begin(),
318          E = mExportables.end();
319       I != E;
320       I++) {
321    if (!(*I)->isKeep())
322      delete *I;
323  }
324}
325
326}  // namespace slang
327