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