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