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