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