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/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 
     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(Context, Context->getTargetAPI(), IsFilterscript) {
     72 }
     73 
     74 // 1) Add zero initialization of local RS object types
     75 void 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 
     84 bool 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 
    128 void 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 ///////////////////////////////////////////////////////////////////////////////
    183 void 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 
    268 void 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         std::vector<bool> isStructInput;
    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               if (AI->getType()->isPointerTy() && AI->getType()->getPointerElementType()->isStructTy()) {
    302                   HelperFunctionParameterTys.push_back(AI->getType()->getPointerElementType());
    303                   isStructInput.push_back(true);
    304               } else {
    305                   HelperFunctionParameterTys.push_back(AI->getType());
    306                   isStructInput.push_back(false);
    307               }
    308           }
    309           HelperFunctionParameterTy =
    310               llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
    311         }
    312 
    313         if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
    314           fprintf(stderr, "Failed to export function %s: parameter type "
    315                           "mismatch during creation of helper function.\n",
    316                   EF->getName().c_str());
    317 
    318           const RSExportRecordType *Expected = EF->getParamPacketType();
    319           if (Expected) {
    320             fprintf(stderr, "Expected:\n");
    321             Expected->getLLVMType()->dump();
    322           }
    323           if (HelperFunctionParameterTy) {
    324             fprintf(stderr, "Got:\n");
    325             HelperFunctionParameterTy->dump();
    326           }
    327         }
    328 
    329         std::vector<llvm::Type*> Params;
    330         if (HelperFunctionParameterTy) {
    331           llvm::PointerType *HelperFunctionParameterTyP =
    332               llvm::PointerType::getUnqual(HelperFunctionParameterTy);
    333           Params.push_back(HelperFunctionParameterTyP);
    334         }
    335 
    336         llvm::FunctionType * HelperFunctionType =
    337             llvm::FunctionType::get(F->getReturnType(),
    338                                     Params,
    339                                     /* IsVarArgs = */false);
    340 
    341         HelperFunction =
    342             llvm::Function::Create(HelperFunctionType,
    343                                    llvm::GlobalValue::ExternalLinkage,
    344                                    HelperFunctionName,
    345                                    M);
    346 
    347         HelperFunction->addFnAttr(llvm::Attribute::NoInline);
    348         HelperFunction->setCallingConv(F->getCallingConv());
    349 
    350         // Create helper function body
    351         {
    352           llvm::Argument *HelperFunctionParameter =
    353               &(*HelperFunction->arg_begin());
    354           llvm::BasicBlock *BB =
    355               llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
    356           llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
    357           llvm::SmallVector<llvm::Value*, 6> Params;
    358           llvm::Value *Idx[2];
    359 
    360           Idx[0] =
    361               llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
    362 
    363           // getelementptr and load instruction for all elements in
    364           // parameter .p
    365           for (size_t i = 0; i < EF->getNumParameters(); i++) {
    366             // getelementptr
    367             Idx[1] = llvm::ConstantInt::get(
    368               llvm::Type::getInt32Ty(mLLVMContext), i);
    369 
    370             llvm::Value *Ptr = NULL;
    371 
    372             Ptr = IB->CreateInBoundsGEP(HelperFunctionParameter, Idx);
    373 
    374             // Load is only required for non-struct ptrs
    375             if (isStructInput[i]) {
    376                 Params.push_back(Ptr);
    377             } else {
    378                 llvm::Value *V = IB->CreateLoad(Ptr);
    379                 Params.push_back(V);
    380             }
    381           }
    382 
    383           // Call and pass the all elements as parameter to F
    384           llvm::CallInst *CI = IB->CreateCall(F, Params);
    385 
    386           CI->setCallingConv(F->getCallingConv());
    387 
    388           if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
    389             IB->CreateRetVoid();
    390           else
    391             IB->CreateRet(CI);
    392 
    393           delete IB;
    394         }
    395       }
    396 
    397       ExportFuncInfo.push_back(
    398           llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
    399     }
    400 
    401     mExportFuncMetadata->addOperand(
    402         llvm::MDNode::get(mLLVMContext, ExportFuncInfo));
    403     ExportFuncInfo.clear();
    404   }
    405 }
    406 
    407 void RSBackend::dumpExportForEachInfo(llvm::Module *M) {
    408   if (mExportForEachNameMetadata == NULL) {
    409     mExportForEachNameMetadata =
    410         M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_NAME_MN);
    411   }
    412   if (mExportForEachSignatureMetadata == NULL) {
    413     mExportForEachSignatureMetadata =
    414         M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
    415   }
    416 
    417   llvm::SmallVector<llvm::Value*, 1> ExportForEachName;
    418   llvm::SmallVector<llvm::Value*, 1> ExportForEachInfo;
    419 
    420   for (RSContext::const_export_foreach_iterator
    421           I = mContext->export_foreach_begin(),
    422           E = mContext->export_foreach_end();
    423        I != E;
    424        I++) {
    425     const RSExportForEach *EFE = *I;
    426 
    427     ExportForEachName.push_back(
    428         llvm::MDString::get(mLLVMContext, EFE->getName().c_str()));
    429 
    430     mExportForEachNameMetadata->addOperand(
    431         llvm::MDNode::get(mLLVMContext, ExportForEachName));
    432     ExportForEachName.clear();
    433 
    434     ExportForEachInfo.push_back(
    435         llvm::MDString::get(mLLVMContext,
    436                             llvm::utostr_32(EFE->getSignatureMetadata())));
    437 
    438     mExportForEachSignatureMetadata->addOperand(
    439         llvm::MDNode::get(mLLVMContext, ExportForEachInfo));
    440     ExportForEachInfo.clear();
    441   }
    442 }
    443 
    444 void RSBackend::dumpExportTypeInfo(llvm::Module *M) {
    445   llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
    446 
    447   for (RSContext::const_export_type_iterator
    448           I = mContext->export_types_begin(),
    449           E = mContext->export_types_end();
    450        I != E;
    451        I++) {
    452     // First, dump type name list to export
    453     const RSExportType *ET = I->getValue();
    454 
    455     ExportTypeInfo.clear();
    456     // Type name
    457     ExportTypeInfo.push_back(
    458         llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
    459 
    460     if (ET->getClass() == RSExportType::ExportClassRecord) {
    461       const RSExportRecordType *ERT =
    462           static_cast<const RSExportRecordType*>(ET);
    463 
    464       if (mExportTypeMetadata == NULL)
    465         mExportTypeMetadata =
    466             M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
    467 
    468       mExportTypeMetadata->addOperand(
    469           llvm::MDNode::get(mLLVMContext, ExportTypeInfo));
    470 
    471       // Now, export struct field information to %[struct name]
    472       std::string StructInfoMetadataName("%");
    473       StructInfoMetadataName.append(ET->getName());
    474       llvm::NamedMDNode *StructInfoMetadata =
    475           M->getOrInsertNamedMetadata(StructInfoMetadataName);
    476       llvm::SmallVector<llvm::Value*, 3> FieldInfo;
    477 
    478       slangAssert(StructInfoMetadata->getNumOperands() == 0 &&
    479                   "Metadata with same name was created before");
    480       for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
    481               FE = ERT->fields_end();
    482            FI != FE;
    483            FI++) {
    484         const RSExportRecordType::Field *F = *FI;
    485 
    486         // 1. field name
    487         FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
    488                                                 F->getName().c_str()));
    489 
    490         // 2. field type name
    491         FieldInfo.push_back(
    492             llvm::MDString::get(mLLVMContext,
    493                                 F->getType()->getName().c_str()));
    494 
    495         StructInfoMetadata->addOperand(
    496             llvm::MDNode::get(mLLVMContext, FieldInfo));
    497         FieldInfo.clear();
    498       }
    499     }   // ET->getClass() == RSExportType::ExportClassRecord
    500   }
    501 }
    502 
    503 void RSBackend::HandleTranslationUnitPost(llvm::Module *M) {
    504   if (!mContext->processExport()) {
    505     return;
    506   }
    507 
    508   if (mContext->hasExportVar())
    509     dumpExportVarInfo(M);
    510 
    511   if (mContext->hasExportFunc())
    512     dumpExportFunctionInfo(M);
    513 
    514   if (mContext->hasExportForEach())
    515     dumpExportForEachInfo(M);
    516 
    517   if (mContext->hasExportType())
    518     dumpExportTypeInfo(M);
    519 }
    520 
    521 RSBackend::~RSBackend() {
    522 }
    523 
    524 }  // namespace slang
    525