slang_rs_context.cpp revision 40bac5d72af8fe32ab3d0bb38aafb5c65d8d9dfa
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_backend.h"
37#include "slang_rs_export_foreach.h"
38#include "slang_rs_export_func.h"
39#include "slang_rs_export_reduce.h"
40#include "slang_rs_export_type.h"
41#include "slang_rs_export_var.h"
42#include "slang_rs_exportable.h"
43#include "slang_rs_pragma_handler.h"
44#include "slang_rs_reflection.h"
45#include "slang_rs_special_func.h"
46
47namespace slang {
48
49RSContext::RSContext(clang::Preprocessor &PP,
50                     clang::ASTContext &Ctx,
51                     const clang::TargetInfo &Target,
52                     PragmaList *Pragmas,
53                     unsigned int TargetAPI,
54                     bool Verbose)
55    : mPP(PP),
56      mCtx(Ctx),
57      mPragmas(Pragmas),
58      mTargetAPI(TargetAPI),
59      mVerbose(Verbose),
60      mDataLayout(nullptr),
61      mLLVMContext(llvm::getGlobalContext()),
62      mLicenseNote(nullptr),
63      mRSPackageName("android.renderscript"),
64      version(0),
65      mMangleCtx(Ctx.createMangleContext()),
66      mIs64Bit(Target.getPointerWidth(0) == 64),
67      mNextSlot(1) {
68
69  AddPragmaHandlers(PP, this);
70
71  // Prepare target data
72  mDataLayout = new llvm::DataLayout(Target.getDataLayoutString());
73
74  // Reserve slot 0 for the root kernel.
75  mExportForEach.push_back(nullptr);
76  mFirstOldStyleKernel = mExportForEach.end();
77}
78
79bool RSContext::processExportVar(const clang::VarDecl *VD) {
80  slangAssert(!VD->getName().empty() && "Variable name should not be empty");
81
82  RSExportType *ET = RSExportType::CreateFromDecl(this, VD);
83  if (!ET)
84    return false;
85
86  RSExportVar *EV = new RSExportVar(this, VD, ET);
87  if (EV == nullptr)
88    return false;
89  else
90    mExportVars.push_back(EV);
91
92  return true;
93}
94
95int RSContext::getForEachSlotNumber(const clang::FunctionDecl* FD) {
96  const clang::StringRef& funcName = FD->getName();
97  return getForEachSlotNumber(funcName);
98}
99
100int RSContext::getForEachSlotNumber(const clang::StringRef& funcName) {
101  auto it = mExportForEachMap.find(funcName);
102  if (it == mExportForEachMap.end()) {
103    return -1;
104  }
105  return it->second;
106}
107
108bool RSContext::processExportFunc(const clang::FunctionDecl *FD) {
109  slangAssert(!FD->getName().empty() && "Function name should not be empty");
110
111  if (!FD->isThisDeclarationADefinition()) {
112    return true;
113  }
114
115  slangAssert(FD->getStorageClass() == clang::SC_None);
116
117  // Specialized function
118  if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) {
119    // Do not reflect specialized functions like init, dtor, or graphics root.
120    return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD);
121  }
122
123  // Foreach kernel
124  if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) {
125    RSExportForEach *EFE = RSExportForEach::Create(this, FD);
126    if (EFE == nullptr) {
127      return false;
128    }
129
130    // The root function should be at index 0 in the list
131    if (FD->getName().equals("root")) {
132      mExportForEach[0] = EFE;
133      return true;
134    }
135
136    // New-style kernels with attribute "kernel" should come first in the list
137    if (FD->hasAttr<clang::KernelAttr>()) {
138      mFirstOldStyleKernel = mExportForEach.insert(mFirstOldStyleKernel, EFE) + 1;
139      slangAssert((mTargetAPI < SLANG_FEATURE_SINGLE_SOURCE_API ||
140                   getForEachSlotNumber(FD->getName()) ==
141                   mFirstOldStyleKernel - mExportForEach.begin() - 1) &&
142                  "Inconsistent slot number assignment");
143      return true;
144    }
145
146    // Old-style kernels should appear in the end of the list
147    mFirstOldStyleKernel = mExportForEach.insert(mFirstOldStyleKernel, EFE);
148    return true;
149  }
150
151  // Reduce kernel
152  if (RSExportReduce::isRSReduceFunc(mTargetAPI, FD)) {
153    if (auto *ER = RSExportReduce::Create(this, FD)) {
154      mExportReduce.push_back(ER);
155      return true;
156    }
157    return false;
158  }
159
160  // Invokable
161  if (auto *EF = RSExportFunc::Create(this, FD)) {
162    mExportFuncs.push_back(EF);
163    return true;
164  }
165
166  return false;
167}
168
169bool RSContext::addForEach(const clang::FunctionDecl* FD) {
170  const llvm::StringRef& funcName = FD->getName();
171
172  if (funcName.equals("root")) {
173    // The root kernel should always be in slot 0.
174    mExportForEachMap.insert(std::make_pair(funcName, 0));
175  } else {
176    mExportForEachMap.insert(std::make_pair(funcName, mNextSlot++));
177  }
178
179  return true;
180}
181
182bool RSContext::processExportType(const llvm::StringRef &Name) {
183  clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
184
185  slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level "
186                                   "declaration) is null object");
187
188  const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name);
189  if (II == nullptr)
190    // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
191    //             found
192    return false;
193
194  clang::DeclContext::lookup_result R = TUDecl->lookup(II);
195  RSExportType *ET = nullptr;
196
197  for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end();
198       I != E;
199       I++) {
200    clang::NamedDecl *const ND = *I;
201    const clang::Type *T = nullptr;
202
203    switch (ND->getKind()) {
204      case clang::Decl::Typedef: {
205        T = static_cast<const clang::TypedefDecl*>(
206            ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr();
207        break;
208      }
209      case clang::Decl::Record: {
210        T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl();
211        break;
212      }
213      default: {
214        // unsupported, skip
215        break;
216      }
217    }
218
219    if (T != nullptr)
220      ET = RSExportType::Create(this, T, NotLegacyKernelArgument);
221  }
222
223  return (ET != nullptr);
224}
225
226void RSContext::setAllocationType(const clang::TypeDecl* TD) {
227  mAllocationType = mCtx.getTypeDeclType(TD);
228}
229
230void RSContext::setScriptCallType(const clang::TypeDecl* TD) {
231  mScriptCallType = mCtx.getTypeDeclType(TD);
232}
233
234bool RSContext::processExports() {
235  bool valid = true;
236
237  if (getDiagnostics()->hasErrorOccurred()) {
238    return false;
239  }
240
241  clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
242  for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) {
243    clang::Decl* D = *I;
244    switch (D->getKind()) {
245    case clang::Decl::Var: {
246      clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D);
247      bool ShouldExportVariable = true;
248      if (VD->getFormalLinkage() == clang::ExternalLinkage) {
249        clang::QualType QT = VD->getTypeSourceInfo()->getType();
250        if (QT.isConstQualified() && !VD->hasInit()) {
251          if (Slang::IsLocInRSHeaderFile(VD->getLocation(),
252                                         *getSourceManager())) {
253            // We don't export variables internal to the runtime's
254            // implementation.
255            ShouldExportVariable = false;
256          } else {
257            clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
258            DiagEngine->Report(VD->getLocation(), DiagEngine->getCustomDiagID(
259                clang::DiagnosticsEngine::Error,
260                "invalid declaration of uninitialized constant variable '%0'"))
261              << VD->getName();
262            valid = false;
263          }
264        }
265        if (valid && ShouldExportVariable && isSyntheticName(VD->getName()))
266          ShouldExportVariable = false;
267        if (valid && ShouldExportVariable && !processExportVar(VD)) {
268          valid = false;
269        }
270      }
271      break;
272    }
273    case clang::Decl::Function: {
274      clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D);
275      if (FD->getFormalLinkage() == clang::ExternalLinkage) {
276        if (!processExportFunc(FD)) {
277          valid = false;
278        }
279      }
280      break;
281    }
282    default:
283      break;
284    }
285  }
286
287  // Create a dummy root in slot 0 if a root kernel is not seen
288  // and there exists a non-root kernel.
289  if (valid && mExportForEach[0] == nullptr) {
290    const size_t numExportedForEach = mExportForEach.size();
291    if (numExportedForEach > 1) {
292      mExportForEach[0] = RSExportForEach::CreateDummyRoot(this);
293    } else {
294      slangAssert(numExportedForEach == 1);
295      mExportForEach.pop_back();
296    }
297  }
298
299  // Finally, export type forcely set to be exported by user
300  for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
301           EE = mNeedExportTypes.end();
302       EI != EE;
303       EI++) {
304    if (!processExportType(EI->getKey())) {
305      valid = false;
306    }
307  }
308
309  return valid;
310}
311
312bool RSContext::processReducePragmas(Backend *BE) {
313  // This is needed to ensure that the dummy variable is emitted into
314  // the bitcode -- which in turn forces the function to be emitted
315  // into the bitcode.  We couldn't do this at
316  // markUsedByReducePragma() time because we had to wait until the
317  // Backend is available.
318  for (auto DummyVar : mUsedByReducePragmaDummyVars)
319    BE->HandleTopLevelDecl(clang::DeclGroupRef(DummyVar));
320
321  bool valid = true;
322  for (auto I = export_reduce_new_begin(), E = export_reduce_new_end(); I != E; ++I) {
323    if (! (*I)->analyzeTranslationUnit())
324      valid = false;
325  }
326  return valid;
327}
328
329void RSContext::markUsedByReducePragma(clang::FunctionDecl *FD, CheckName Check) {
330  if (mUsedByReducePragmaFns.find(FD) != mUsedByReducePragmaFns.end())
331    return;  // already marked used
332
333  if (Check == CheckNameYes) {
334    // This is an inefficient linear search.  If this turns out to be a
335    // problem in practice, then processReducePragmas() could build a
336    // set or hash table or something similar containing all function
337    // names mentioned in a reduce pragma and searchable in O(c) or
338    // O(log(n)) time rather than the currently-implemented O(n) search.
339    auto NameMatches = [this, FD]() {
340      for (auto I = export_reduce_new_begin(), E = export_reduce_new_end(); I != E; ++I) {
341        if ((*I)->matchName(FD->getName()))
342          return true;
343      }
344      return false;
345    };
346    if (!NameMatches())
347      return;
348  }
349
350  mUsedByReducePragmaFns.insert(FD);
351
352  // This is needed to prevent clang from warning that the function is
353  // unused (in the case where it is only referenced by #pragma rs
354  // reduce).
355  FD->setIsUsed();
356
357  // Each constituent function "f" of a reduction kernel gets a dummy variable generated for it:
358  //   void *.rs.reduce_fn.f = (void*)&f;
359  // This is a trick to ensure that clang will not delete "f" as unused.
360
361  // `-VarDecl 0x87cb558 <line:3:1, col:30> col:7 var 'void *' cinit
362  //     `-CStyleCastExpr 0x87cb630 <col:19, col:26> 'void *' <BitCast>
363  //       `-ImplicitCastExpr 0x87cb618 <col:26> 'void (*)(int *, float, double)' <FunctionToPointerDecay>
364  //         `-DeclRefExpr 0x87cb5b8 <col:26> 'void (int *, float, double)' Function 0x8784e10 'foo' 'void (int *, float, double)
365
366  const clang::QualType VoidPtrType = mCtx.getPointerType(mCtx.VoidTy);
367
368  clang::DeclContext *const DC = FD->getDeclContext();
369  const clang::SourceLocation Loc = FD->getLocation();
370
371  clang::VarDecl *const VD = clang::VarDecl::Create(
372      mCtx, DC, Loc, Loc,
373      &mCtx.Idents.get(std::string(".rs.reduce_fn.") + FD->getNameAsString()),
374      VoidPtrType,
375      mCtx.getTrivialTypeSourceInfo(VoidPtrType),
376      clang::SC_None);
377  VD->setLexicalDeclContext(DC);
378  DC->addDecl(VD);
379
380  clang::DeclRefExpr *const DRE = clang::DeclRefExpr::Create(mCtx,
381                                                             clang::NestedNameSpecifierLoc(),
382                                                             Loc,
383                                                             FD, false, Loc, FD->getType(),
384                                                             clang::VK_RValue);
385  clang::ImplicitCastExpr *const ICE = clang::ImplicitCastExpr::Create(mCtx, mCtx.getPointerType(FD->getType()),
386                                                                       clang::CK_FunctionToPointerDecay, DRE,
387                                                                       nullptr, clang::VK_RValue);
388  clang::CStyleCastExpr *const CSCE = clang::CStyleCastExpr::Create(mCtx, VoidPtrType, clang::VK_RValue, clang::CK_BitCast,
389                                                                    ICE, nullptr, nullptr,
390                                                                    Loc, Loc);
391  VD->setInit(CSCE);
392
393  mUsedByReducePragmaDummyVars.push_back(VD);
394}
395
396bool RSContext::insertExportType(const llvm::StringRef &TypeName,
397                                 RSExportType *ET) {
398  ExportTypeMap::value_type *NewItem =
399      ExportTypeMap::value_type::Create(TypeName,
400                                        mExportTypes.getAllocator(),
401                                        ET);
402
403  if (mExportTypes.insert(NewItem)) {
404    return true;
405  } else {
406    NewItem->Destroy(mExportTypes.getAllocator());
407    return false;
408  }
409}
410
411RSContext::~RSContext() {
412  delete mLicenseNote;
413  delete mDataLayout;
414  for (ExportableList::iterator I = mExportables.begin(),
415          E = mExportables.end();
416       I != E;
417       I++) {
418    if (!(*I)->isKeep())
419      delete *I;
420  }
421}
422
423}  // namespace slang
424