slang_rs_context.cpp revision 13fad85b3c99a37c17d8acfec72f46b8ee64e912
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
219bool RSContext::processExports() {
220  bool valid = true;
221
222  if (getDiagnostics()->hasErrorOccurred()) {
223    return false;
224  }
225
226  clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
227  for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) {
228    clang::Decl* D = *I;
229    switch (D->getKind()) {
230    case clang::Decl::Var: {
231      clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D);
232      bool ShouldExportVariable = true;
233      if (VD->getFormalLinkage() == clang::ExternalLinkage) {
234        clang::QualType QT = VD->getTypeSourceInfo()->getType();
235        if (QT.isConstQualified() && !VD->hasInit()) {
236          if (Slang::IsLocInRSHeaderFile(VD->getLocation(),
237                                         *getSourceManager())) {
238            // We don't export variables internal to the runtime's
239            // implementation.
240            ShouldExportVariable = false;
241          } else {
242            clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
243            DiagEngine->Report(VD->getLocation(), DiagEngine->getCustomDiagID(
244                clang::DiagnosticsEngine::Error,
245                "invalid declaration of uninitialized constant variable '%0'"))
246              << VD->getName();
247            valid = false;
248          }
249        }
250        if (valid && ShouldExportVariable && !processExportVar(VD)) {
251          valid = false;
252        }
253      }
254      break;
255    }
256    case clang::Decl::Function: {
257      clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D);
258      if (FD->getFormalLinkage() == clang::ExternalLinkage) {
259        if (!processExportFunc(FD)) {
260          valid = false;
261        }
262      }
263      break;
264    }
265    default:
266      break;
267    }
268  }
269
270  // Create a dummy root in slot 0 if a root kernel is not seen
271  // and there exists a non-root kernel.
272  if (valid && mExportForEach[0] == nullptr) {
273    const size_t numExportedForEach = mExportForEach.size();
274    if (numExportedForEach > 1) {
275      mExportForEach[0] = RSExportForEach::CreateDummyRoot(this);
276    } else {
277      slangAssert(numExportedForEach == 1);
278      mExportForEach.pop_back();
279    }
280  }
281
282  // Finally, export type forcely set to be exported by user
283  for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
284           EE = mNeedExportTypes.end();
285       EI != EE;
286       EI++) {
287    if (!processExportType(EI->getKey())) {
288      valid = false;
289    }
290  }
291
292  return valid;
293}
294
295bool RSContext::insertExportType(const llvm::StringRef &TypeName,
296                                 RSExportType *ET) {
297  ExportTypeMap::value_type *NewItem =
298      ExportTypeMap::value_type::Create(TypeName,
299                                        mExportTypes.getAllocator(),
300                                        ET);
301
302  if (mExportTypes.insert(NewItem)) {
303    return true;
304  } else {
305    NewItem->Destroy(mExportTypes.getAllocator());
306    return false;
307  }
308}
309
310RSContext::~RSContext() {
311  delete mLicenseNote;
312  delete mDataLayout;
313  for (ExportableList::iterator I = mExportables.begin(),
314          E = mExportables.end();
315       I != E;
316       I++) {
317    if (!(*I)->isKeep())
318      delete *I;
319  }
320}
321
322}  // namespace slang
323