slang_rs_backend.cpp revision 48d893dc7794b3cfb74f35955ca763ee4170f9ad
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_backend.h"
18
19#include <string>
20#include <vector>
21
22#include "clang/AST/ASTContext.h"
23#include "clang/Frontend/CodeGenOptions.h"
24
25#include "llvm/ADT/Twine.h"
26#include "llvm/ADT/StringExtras.h"
27
28#include "llvm/IR/Constant.h"
29#include "llvm/IR/Constants.h"
30#include "llvm/IR/DerivedTypes.h"
31#include "llvm/IR/Function.h"
32#include "llvm/IR/IRBuilder.h"
33#include "llvm/IR/Metadata.h"
34#include "llvm/IR/Module.h"
35
36#include "llvm/Support/DebugLoc.h"
37
38#include "slang_assert.h"
39#include "slang_rs.h"
40#include "slang_rs_context.h"
41#include "slang_rs_export_foreach.h"
42#include "slang_rs_export_func.h"
43#include "slang_rs_export_type.h"
44#include "slang_rs_export_var.h"
45#include "slang_rs_metadata.h"
46
47namespace slang {
48
49RSBackend::RSBackend(RSContext *Context,
50                     clang::DiagnosticsEngine *DiagEngine,
51                     const clang::CodeGenOptions &CodeGenOpts,
52                     const clang::TargetOptions &TargetOpts,
53                     PragmaList *Pragmas,
54                     llvm::raw_ostream *OS,
55                     Slang::OutputType OT,
56                     clang::SourceManager &SourceMgr,
57                     bool AllowRSPrefix,
58                     bool IsFilterscript)
59  : Backend(DiagEngine, CodeGenOpts, TargetOpts, Pragmas, OS, OT),
60    mContext(Context),
61    mSourceMgr(SourceMgr),
62    mAllowRSPrefix(AllowRSPrefix),
63    mIsFilterscript(IsFilterscript),
64    mExportVarMetadata(NULL),
65    mExportFuncMetadata(NULL),
66    mExportForEachNameMetadata(NULL),
67    mExportForEachSignatureMetadata(NULL),
68    mExportTypeMetadata(NULL),
69    mRSObjectSlotsMetadata(NULL),
70    mRefCount(mContext->getASTContext()),
71    mASTChecker(Context, Context->getTargetAPI(), IsFilterscript) {
72}
73
74// 1) Add zero initialization of local RS object types
75void RSBackend::AnnotateFunction(clang::FunctionDecl *FD) {
76  if (FD &&
77      FD->hasBody() &&
78      !SlangRS::IsLocInRSHeaderFile(FD->getLocation(), mSourceMgr)) {
79    mRefCount.Init();
80    mRefCount.Visit(FD->getBody());
81  }
82  return;
83}
84
85bool RSBackend::HandleTopLevelDecl(clang::DeclGroupRef D) {
86  // Disallow user-defined functions with prefix "rs"
87  if (!mAllowRSPrefix) {
88    // Iterate all function declarations in the program.
89    for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end();
90         I != E; I++) {
91      clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
92      if (FD == NULL)
93        continue;
94      if (!FD->getName().startswith("rs"))  // Check prefix
95        continue;
96      if (!SlangRS::IsLocInRSHeaderFile(FD->getLocation(), mSourceMgr))
97        mDiagEngine.Report(
98          clang::FullSourceLoc(FD->getLocation(), mSourceMgr),
99          mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
100                                      "invalid function name prefix, "
101                                      "\"rs\" is reserved: '%0'"))
102          << FD->getName();
103    }
104  }
105
106  // Process any non-static function declarations
107  for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; I++) {
108    clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
109    if (FD && FD->isGlobal()) {
110      // Check that we don't have any array parameters being misintrepeted as
111      // kernel pointers due to the C type system's array to pointer decay.
112      size_t numParams = FD->getNumParams();
113      for (size_t i = 0; i < numParams; i++) {
114        const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
115        clang::QualType QT = PVD->getOriginalType();
116        if (QT->isArrayType()) {
117          mDiagEngine.Report(
118            clang::FullSourceLoc(PVD->getTypeSpecStartLoc(), mSourceMgr),
119            mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
120                                        "exported function parameters may "
121                                        "not have array type: %0")) << QT;
122        }
123      }
124      AnnotateFunction(FD);
125    }
126  }
127
128  return Backend::HandleTopLevelDecl(D);
129}
130
131
132void RSBackend::HandleTranslationUnitPre(clang::ASTContext &C) {
133  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
134
135  // If we have an invalid RS/FS AST, don't check further.
136  if (!mASTChecker.Validate()) {
137    return;
138  }
139
140  if (mIsFilterscript) {
141    mContext->addPragma("rs_fp_relaxed", "");
142  }
143
144  int version = mContext->getVersion();
145  if (version == 0) {
146    // Not setting a version is an error
147    mDiagEngine.Report(
148        mSourceMgr.getLocForEndOfFile(mSourceMgr.getMainFileID()),
149        mDiagEngine.getCustomDiagID(
150            clang::DiagnosticsEngine::Error,
151            "missing pragma for version in source file"));
152  } else {
153    slangAssert(version == 1);
154  }
155
156  if (mContext->getReflectJavaPackageName().empty()) {
157    mDiagEngine.Report(
158        mSourceMgr.getLocForEndOfFile(mSourceMgr.getMainFileID()),
159        mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
160                                    "missing \"#pragma rs "
161                                    "java_package_name(com.foo.bar)\" "
162                                    "in source file"));
163    return;
164  }
165
166  // Create a static global destructor if necessary (to handle RS object
167  // runtime cleanup).
168  clang::FunctionDecl *FD = mRefCount.CreateStaticGlobalDtor();
169  if (FD) {
170    HandleTopLevelDecl(clang::DeclGroupRef(FD));
171  }
172
173  // Process any static function declarations
174  for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
175          E = TUDecl->decls_end(); I != E; I++) {
176    if ((I->getKind() >= clang::Decl::firstFunction) &&
177        (I->getKind() <= clang::Decl::lastFunction)) {
178      clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
179      if (FD && !FD->isGlobal()) {
180        AnnotateFunction(FD);
181      }
182    }
183  }
184
185  return;
186}
187
188///////////////////////////////////////////////////////////////////////////////
189void RSBackend::dumpExportVarInfo(llvm::Module *M) {
190  int slotCount = 0;
191  if (mExportVarMetadata == NULL)
192    mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
193
194  llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
195
196  // We emit slot information (#rs_object_slots) for any reference counted
197  // RS type or pointer (which can also be bound).
198
199  for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(),
200          E = mContext->export_vars_end();
201       I != E;
202       I++) {
203    const RSExportVar *EV = *I;
204    const RSExportType *ET = EV->getType();
205    bool countsAsRSObject = false;
206
207    // Variable name
208    ExportVarInfo.push_back(
209        llvm::MDString::get(mLLVMContext, EV->getName().c_str()));
210
211    // Type name
212    switch (ET->getClass()) {
213      case RSExportType::ExportClassPrimitive: {
214        const RSExportPrimitiveType *PT =
215            static_cast<const RSExportPrimitiveType*>(ET);
216        ExportVarInfo.push_back(
217            llvm::MDString::get(
218              mLLVMContext, llvm::utostr_32(PT->getType())));
219        if (PT->isRSObjectType()) {
220          countsAsRSObject = true;
221        }
222        break;
223      }
224      case RSExportType::ExportClassPointer: {
225        ExportVarInfo.push_back(
226            llvm::MDString::get(
227              mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET)
228                ->getPointeeType()->getName()).c_str()));
229        break;
230      }
231      case RSExportType::ExportClassMatrix: {
232        ExportVarInfo.push_back(
233            llvm::MDString::get(
234              mLLVMContext, llvm::utostr_32(
235                RSExportPrimitiveType::DataTypeRSMatrix2x2 +
236                static_cast<const RSExportMatrixType*>(ET)->getDim() - 2)));
237        break;
238      }
239      case RSExportType::ExportClassVector:
240      case RSExportType::ExportClassConstantArray:
241      case RSExportType::ExportClassRecord: {
242        ExportVarInfo.push_back(
243            llvm::MDString::get(mLLVMContext,
244              EV->getType()->getName().c_str()));
245        break;
246      }
247    }
248
249    mExportVarMetadata->addOperand(
250        llvm::MDNode::get(mLLVMContext, ExportVarInfo));
251    ExportVarInfo.clear();
252
253    if (mRSObjectSlotsMetadata == NULL) {
254      mRSObjectSlotsMetadata =
255          M->getOrInsertNamedMetadata(RS_OBJECT_SLOTS_MN);
256    }
257
258    if (countsAsRSObject) {
259      mRSObjectSlotsMetadata->addOperand(llvm::MDNode::get(mLLVMContext,
260          llvm::MDString::get(mLLVMContext, llvm::utostr_32(slotCount))));
261    }
262
263    slotCount++;
264  }
265}
266
267void RSBackend::dumpExportFunctionInfo(llvm::Module *M) {
268  if (mExportFuncMetadata == NULL)
269    mExportFuncMetadata =
270        M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
271
272  llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo;
273
274  for (RSContext::const_export_func_iterator
275          I = mContext->export_funcs_begin(),
276          E = mContext->export_funcs_end();
277       I != E;
278       I++) {
279    const RSExportFunc *EF = *I;
280
281    // Function name
282    if (!EF->hasParam()) {
283      ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext,
284                                                   EF->getName().c_str()));
285    } else {
286      llvm::Function *F = M->getFunction(EF->getName());
287      llvm::Function *HelperFunction;
288      const std::string HelperFunctionName(".helper_" + EF->getName());
289
290      slangAssert(F && "Function marked as exported disappeared in Bitcode");
291
292      // Create helper function
293      {
294        llvm::StructType *HelperFunctionParameterTy = NULL;
295
296        if (!F->getArgumentList().empty()) {
297          std::vector<llvm::Type*> HelperFunctionParameterTys;
298          for (llvm::Function::arg_iterator AI = F->arg_begin(),
299               AE = F->arg_end(); AI != AE; AI++)
300            HelperFunctionParameterTys.push_back(AI->getType());
301
302          HelperFunctionParameterTy =
303              llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
304        }
305
306        if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
307          fprintf(stderr, "Failed to export function %s: parameter type "
308                          "mismatch during creation of helper function.\n",
309                  EF->getName().c_str());
310
311          const RSExportRecordType *Expected = EF->getParamPacketType();
312          if (Expected) {
313            fprintf(stderr, "Expected:\n");
314            Expected->getLLVMType()->dump();
315          }
316          if (HelperFunctionParameterTy) {
317            fprintf(stderr, "Got:\n");
318            HelperFunctionParameterTy->dump();
319          }
320        }
321
322        std::vector<llvm::Type*> Params;
323        if (HelperFunctionParameterTy) {
324          llvm::PointerType *HelperFunctionParameterTyP =
325              llvm::PointerType::getUnqual(HelperFunctionParameterTy);
326          Params.push_back(HelperFunctionParameterTyP);
327        }
328
329        llvm::FunctionType * HelperFunctionType =
330            llvm::FunctionType::get(F->getReturnType(),
331                                    Params,
332                                    /* IsVarArgs = */false);
333
334        HelperFunction =
335            llvm::Function::Create(HelperFunctionType,
336                                   llvm::GlobalValue::ExternalLinkage,
337                                   HelperFunctionName,
338                                   M);
339
340        HelperFunction->addFnAttr(llvm::Attribute::NoInline);
341        HelperFunction->setCallingConv(F->getCallingConv());
342
343        // Create helper function body
344        {
345          llvm::Argument *HelperFunctionParameter =
346              &(*HelperFunction->arg_begin());
347          llvm::BasicBlock *BB =
348              llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
349          llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
350          llvm::SmallVector<llvm::Value*, 6> Params;
351          llvm::Value *Idx[2];
352
353          Idx[0] =
354              llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
355
356          // getelementptr and load instruction for all elements in
357          // parameter .p
358          for (size_t i = 0; i < EF->getNumParameters(); i++) {
359            // getelementptr
360            Idx[1] = llvm::ConstantInt::get(
361              llvm::Type::getInt32Ty(mLLVMContext), i);
362
363            llvm::Value *Ptr =
364              IB->CreateInBoundsGEP(HelperFunctionParameter, Idx);
365
366            // load
367            llvm::Value *V = IB->CreateLoad(Ptr);
368            Params.push_back(V);
369          }
370
371          // Call and pass the all elements as parameter to F
372          llvm::CallInst *CI = IB->CreateCall(F, Params);
373
374          CI->setCallingConv(F->getCallingConv());
375
376          if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
377            IB->CreateRetVoid();
378          else
379            IB->CreateRet(CI);
380
381          delete IB;
382        }
383      }
384
385      ExportFuncInfo.push_back(
386          llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
387    }
388
389    mExportFuncMetadata->addOperand(
390        llvm::MDNode::get(mLLVMContext, ExportFuncInfo));
391    ExportFuncInfo.clear();
392  }
393}
394
395void RSBackend::dumpExportForEachInfo(llvm::Module *M) {
396  if (mExportForEachNameMetadata == NULL) {
397    mExportForEachNameMetadata =
398        M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_NAME_MN);
399  }
400  if (mExportForEachSignatureMetadata == NULL) {
401    mExportForEachSignatureMetadata =
402        M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
403  }
404
405  llvm::SmallVector<llvm::Value*, 1> ExportForEachName;
406  llvm::SmallVector<llvm::Value*, 1> ExportForEachInfo;
407
408  for (RSContext::const_export_foreach_iterator
409          I = mContext->export_foreach_begin(),
410          E = mContext->export_foreach_end();
411       I != E;
412       I++) {
413    const RSExportForEach *EFE = *I;
414
415    ExportForEachName.push_back(
416        llvm::MDString::get(mLLVMContext, EFE->getName().c_str()));
417
418    mExportForEachNameMetadata->addOperand(
419        llvm::MDNode::get(mLLVMContext, ExportForEachName));
420    ExportForEachName.clear();
421
422    ExportForEachInfo.push_back(
423        llvm::MDString::get(mLLVMContext,
424                            llvm::utostr_32(EFE->getSignatureMetadata())));
425
426    mExportForEachSignatureMetadata->addOperand(
427        llvm::MDNode::get(mLLVMContext, ExportForEachInfo));
428    ExportForEachInfo.clear();
429  }
430}
431
432void RSBackend::dumpExportTypeInfo(llvm::Module *M) {
433  llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
434
435  for (RSContext::const_export_type_iterator
436          I = mContext->export_types_begin(),
437          E = mContext->export_types_end();
438       I != E;
439       I++) {
440    // First, dump type name list to export
441    const RSExportType *ET = I->getValue();
442
443    ExportTypeInfo.clear();
444    // Type name
445    ExportTypeInfo.push_back(
446        llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
447
448    if (ET->getClass() == RSExportType::ExportClassRecord) {
449      const RSExportRecordType *ERT =
450          static_cast<const RSExportRecordType*>(ET);
451
452      if (mExportTypeMetadata == NULL)
453        mExportTypeMetadata =
454            M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
455
456      mExportTypeMetadata->addOperand(
457          llvm::MDNode::get(mLLVMContext, ExportTypeInfo));
458
459      // Now, export struct field information to %[struct name]
460      std::string StructInfoMetadataName("%");
461      StructInfoMetadataName.append(ET->getName());
462      llvm::NamedMDNode *StructInfoMetadata =
463          M->getOrInsertNamedMetadata(StructInfoMetadataName);
464      llvm::SmallVector<llvm::Value*, 3> FieldInfo;
465
466      slangAssert(StructInfoMetadata->getNumOperands() == 0 &&
467                  "Metadata with same name was created before");
468      for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
469              FE = ERT->fields_end();
470           FI != FE;
471           FI++) {
472        const RSExportRecordType::Field *F = *FI;
473
474        // 1. field name
475        FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
476                                                F->getName().c_str()));
477
478        // 2. field type name
479        FieldInfo.push_back(
480            llvm::MDString::get(mLLVMContext,
481                                F->getType()->getName().c_str()));
482
483        StructInfoMetadata->addOperand(
484            llvm::MDNode::get(mLLVMContext, FieldInfo));
485        FieldInfo.clear();
486      }
487    }   // ET->getClass() == RSExportType::ExportClassRecord
488  }
489}
490
491void RSBackend::HandleTranslationUnitPost(llvm::Module *M) {
492  if (!mContext->processExport()) {
493    return;
494  }
495
496  if (mContext->hasExportVar())
497    dumpExportVarInfo(M);
498
499  if (mContext->hasExportFunc())
500    dumpExportFunctionInfo(M);
501
502  if (mContext->hasExportForEach())
503    dumpExportForEachInfo(M);
504
505  if (mContext->hasExportType())
506    dumpExportTypeInfo(M);
507
508  return;
509}
510
511RSBackend::~RSBackend() {
512  return;
513}
514
515}  // namespace slang
516