slang_rs_backend.cpp revision 4b32ffdfc1ac766f8932e7effbcdf7484e804a8e
1/* 2 * Copyright 2010, 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 <vector> 20#include <string> 21 22#include "llvm/Metadata.h" 23#include "llvm/Constant.h" 24#include "llvm/Constants.h" 25#include "llvm/Module.h" 26#include "llvm/Function.h" 27#include "llvm/DerivedTypes.h" 28 29#include "llvm/Support/IRBuilder.h" 30 31#include "llvm/ADT/Twine.h" 32#include "llvm/ADT/StringExtras.h" 33 34#include "slang_rs.h" 35#include "slang_rs_context.h" 36#include "slang_rs_metadata.h" 37#include "slang_rs_export_var.h" 38#include "slang_rs_export_func.h" 39#include "slang_rs_export_type.h" 40 41using namespace slang; 42 43RSBackend::RSBackend(RSContext *Context, 44 clang::Diagnostic &Diags, 45 const clang::CodeGenOptions &CodeGenOpts, 46 const clang::TargetOptions &TargetOpts, 47 const PragmaList &Pragmas, 48 llvm::raw_ostream *OS, 49 Slang::OutputType OT, 50 clang::SourceManager &SourceMgr, 51 bool AllowRSPrefix) 52 : Backend(Diags, 53 CodeGenOpts, 54 TargetOpts, 55 Pragmas, 56 OS, 57 OT), 58 mContext(Context), 59 mSourceMgr(SourceMgr), 60 mAllowRSPrefix(AllowRSPrefix), 61 mExportVarMetadata(NULL), 62 mExportFuncMetadata(NULL), 63 mExportTypeMetadata(NULL) { 64 return; 65} 66 67// 1) Add zero initialization of local RS object types 68void RSBackend::AnnotateFunction(clang::FunctionDecl *FD) { 69 if (FD && 70 FD->hasBody() && 71 !SlangRS::IsFunctionInRSHeaderFile(FD, mSourceMgr)) { 72 mRefCount.Visit(FD->getBody()); 73 } 74 return; 75} 76 77void RSBackend::HandleTopLevelDecl(clang::DeclGroupRef D) { 78 // Disallow user-defined functions with prefix "rs" 79 if (!mAllowRSPrefix) { 80 // Iterate all function declarations in the program. 81 for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); 82 I != E; I++) { 83 clang::FunctionDecl *FD = dyn_cast<clang::FunctionDecl>(*I); 84 if (FD == NULL) 85 continue; 86 if (!FD->getName().startswith("rs")) // Check prefix 87 continue; 88 if (!SlangRS::IsFunctionInRSHeaderFile(FD, mSourceMgr)) 89 mDiags.Report(clang::FullSourceLoc(FD->getLocation(), mSourceMgr), 90 mDiags.getCustomDiagID(clang::Diagnostic::Error, 91 "invalid function name prefix, " 92 "\"rs\" is reserved: '%0'")) 93 << FD->getName(); 94 } 95 } 96 97 // Process any non-static function declarations 98 for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; I++) { 99 AnnotateFunction(dyn_cast<clang::FunctionDecl>(*I)); 100 } 101 102 Backend::HandleTopLevelDecl(D); 103 return; 104} 105 106void RSBackend::HandleTranslationUnitPre(clang::ASTContext& C) { 107 clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl(); 108 109 // Process any static function declarations 110 for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(), 111 E = TUDecl->decls_end(); I != E; I++) { 112 if ((I->getKind() >= clang::Decl::firstFunction) && 113 (I->getKind() <= clang::Decl::lastFunction)) { 114 AnnotateFunction(static_cast<clang::FunctionDecl*>(*I)); 115 } 116 } 117 118 return; 119} 120 121/////////////////////////////////////////////////////////////////////////////// 122void RSBackend::HandleTranslationUnitPost(llvm::Module *M) { 123 mContext->processExport(); 124 125 // Dump export variable info 126 if (mContext->hasExportVar()) { 127 if (mExportVarMetadata == NULL) 128 mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN); 129 130 llvm::SmallVector<llvm::Value*, 2> ExportVarInfo; 131 132 for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(), 133 E = mContext->export_vars_end(); 134 I != E; 135 I++) { 136 const RSExportVar *EV = *I; 137 const RSExportType *ET = EV->getType(); 138 139 // Variable name 140 ExportVarInfo.push_back( 141 llvm::MDString::get(mLLVMContext, EV->getName().c_str())); 142 143 // Type name 144 switch (ET->getClass()) { 145 case RSExportType::ExportClassPrimitive: { 146 ExportVarInfo.push_back( 147 llvm::MDString::get( 148 mLLVMContext, llvm::utostr_32( 149 static_cast<const RSExportPrimitiveType*>(ET)->getType()))); 150 break; 151 } 152 case RSExportType::ExportClassPointer: { 153 ExportVarInfo.push_back( 154 llvm::MDString::get( 155 mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET) 156 ->getPointeeType()->getName()).c_str())); 157 break; 158 } 159 case RSExportType::ExportClassMatrix: { 160 ExportVarInfo.push_back( 161 llvm::MDString::get( 162 mLLVMContext, llvm::utostr_32( 163 RSExportPrimitiveType::DataTypeRSMatrix2x2 + 164 static_cast<const RSExportMatrixType*>(ET)->getDim() - 2))); 165 break; 166 } 167 case RSExportType::ExportClassVector: 168 case RSExportType::ExportClassConstantArray: 169 case RSExportType::ExportClassRecord: { 170 ExportVarInfo.push_back( 171 llvm::MDString::get(mLLVMContext, 172 EV->getType()->getName().c_str())); 173 break; 174 } 175 } 176 177 mExportVarMetadata->addOperand( 178 llvm::MDNode::get(mLLVMContext, 179 ExportVarInfo.data(), 180 ExportVarInfo.size()) ); 181 182 ExportVarInfo.clear(); 183 } 184 } 185 186 // Dump export function info 187 if (mContext->hasExportFunc()) { 188 if (mExportFuncMetadata == NULL) 189 mExportFuncMetadata = 190 M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN); 191 192 llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo; 193 194 for (RSContext::const_export_func_iterator 195 I = mContext->export_funcs_begin(), 196 E = mContext->export_funcs_end(); 197 I != E; 198 I++) { 199 const RSExportFunc *EF = *I; 200 201 // Function name 202 if (!EF->hasParam()) { 203 ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext, 204 EF->getName().c_str())); 205 } else { 206 llvm::Function *F = M->getFunction(EF->getName()); 207 llvm::Function *HelperFunction; 208 const std::string HelperFunctionName(".helper_" + EF->getName()); 209 210 assert(F && "Function marked as exported disappeared in Bitcode"); 211 212 // Create helper function 213 { 214 llvm::StructType *HelperFunctionParameterTy = NULL; 215 216 if (!F->getArgumentList().empty()) { 217 std::vector<const llvm::Type*> HelperFunctionParameterTys; 218 for (llvm::Function::arg_iterator AI = F->arg_begin(), 219 AE = F->arg_end(); AI != AE; AI++) 220 HelperFunctionParameterTys.push_back(AI->getType()); 221 222 HelperFunctionParameterTy = 223 llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys); 224 } 225 226 if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) { 227 fprintf(stderr, "Failed to export function %s: parameter type " 228 "mismatch during creation of helper function.\n", 229 EF->getName().c_str()); 230 231 const RSExportRecordType *Expected = EF->getParamPacketType(); 232 if (Expected) { 233 fprintf(stderr, "Expected:\n"); 234 Expected->getLLVMType()->dump(); 235 } 236 if (HelperFunctionParameterTy) { 237 fprintf(stderr, "Got:\n"); 238 HelperFunctionParameterTy->dump(); 239 } 240 } 241 242 std::vector<const llvm::Type*> Params; 243 if (HelperFunctionParameterTy) { 244 llvm::PointerType *HelperFunctionParameterTyP = 245 llvm::PointerType::getUnqual(HelperFunctionParameterTy); 246 Params.push_back(HelperFunctionParameterTyP); 247 } 248 249 llvm::FunctionType * HelperFunctionType = 250 llvm::FunctionType::get(F->getReturnType(), 251 Params, 252 /* IsVarArgs = */false); 253 254 HelperFunction = 255 llvm::Function::Create(HelperFunctionType, 256 llvm::GlobalValue::ExternalLinkage, 257 HelperFunctionName, 258 M); 259 260 HelperFunction->addFnAttr(llvm::Attribute::NoInline); 261 HelperFunction->setCallingConv(F->getCallingConv()); 262 263 // Create helper function body 264 { 265 llvm::Argument *HelperFunctionParameter = 266 &(*HelperFunction->arg_begin()); 267 llvm::BasicBlock *BB = 268 llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction); 269 llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB); 270 llvm::SmallVector<llvm::Value*, 6> Params; 271 llvm::Value *Idx[2]; 272 273 Idx[0] = 274 llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0); 275 276 // getelementptr and load instruction for all elements in 277 // parameter .p 278 for (size_t i = 0; i < EF->getNumParameters(); i++) { 279 // getelementptr 280 Idx[1] = 281 llvm::ConstantInt::get( 282 llvm::Type::getInt32Ty(mLLVMContext), i); 283 llvm::Value *Ptr = IB->CreateInBoundsGEP(HelperFunctionParameter, 284 Idx, 285 Idx + 2); 286 287 // load 288 llvm::Value *V = IB->CreateLoad(Ptr); 289 Params.push_back(V); 290 } 291 292 // Call and pass the all elements as paramter to F 293 llvm::CallInst *CI = IB->CreateCall(F, 294 Params.data(), 295 Params.data() + Params.size()); 296 297 CI->setCallingConv(F->getCallingConv()); 298 299 if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext)) 300 IB->CreateRetVoid(); 301 else 302 IB->CreateRet(CI); 303 304 delete IB; 305 } 306 } 307 308 ExportFuncInfo.push_back( 309 llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str())); 310 } 311 312 mExportFuncMetadata->addOperand( 313 llvm::MDNode::get(mLLVMContext, 314 ExportFuncInfo.data(), 315 ExportFuncInfo.size())); 316 317 ExportFuncInfo.clear(); 318 } 319 } 320 321 // Dump export type info 322 if (mContext->hasExportType()) { 323 llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo; 324 325 for (RSContext::const_export_type_iterator 326 I = mContext->export_types_begin(), 327 E = mContext->export_types_end(); 328 I != E; 329 I++) { 330 // First, dump type name list to export 331 const RSExportType *ET = I->getValue(); 332 333 ExportTypeInfo.clear(); 334 // Type name 335 ExportTypeInfo.push_back( 336 llvm::MDString::get(mLLVMContext, ET->getName().c_str())); 337 338 if (ET->getClass() == RSExportType::ExportClassRecord) { 339 const RSExportRecordType *ERT = 340 static_cast<const RSExportRecordType*>(ET); 341 342 if (mExportTypeMetadata == NULL) 343 mExportTypeMetadata = 344 M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN); 345 346 mExportTypeMetadata->addOperand( 347 llvm::MDNode::get(mLLVMContext, 348 ExportTypeInfo.data(), 349 ExportTypeInfo.size())); 350 351 // Now, export struct field information to %[struct name] 352 std::string StructInfoMetadataName("%"); 353 StructInfoMetadataName.append(ET->getName()); 354 llvm::NamedMDNode *StructInfoMetadata = 355 M->getOrInsertNamedMetadata(StructInfoMetadataName); 356 llvm::SmallVector<llvm::Value*, 3> FieldInfo; 357 358 assert(StructInfoMetadata->getNumOperands() == 0 && 359 "Metadata with same name was created before"); 360 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(), 361 FE = ERT->fields_end(); 362 FI != FE; 363 FI++) { 364 const RSExportRecordType::Field *F = *FI; 365 366 // 1. field name 367 FieldInfo.push_back(llvm::MDString::get(mLLVMContext, 368 F->getName().c_str())); 369 370 // 2. field type name 371 FieldInfo.push_back( 372 llvm::MDString::get(mLLVMContext, 373 F->getType()->getName().c_str())); 374 375 // 3. field kind 376 switch (F->getType()->getClass()) { 377 case RSExportType::ExportClassPrimitive: 378 case RSExportType::ExportClassVector: { 379 const RSExportPrimitiveType *EPT = 380 static_cast<const RSExportPrimitiveType*>(F->getType()); 381 FieldInfo.push_back( 382 llvm::MDString::get(mLLVMContext, 383 llvm::itostr(EPT->getKind()))); 384 break; 385 } 386 387 default: { 388 FieldInfo.push_back( 389 llvm::MDString::get(mLLVMContext, 390 llvm::itostr( 391 RSExportPrimitiveType::DataKindUser))); 392 break; 393 } 394 } 395 396 StructInfoMetadata->addOperand(llvm::MDNode::get(mLLVMContext, 397 FieldInfo.data(), 398 FieldInfo.size())); 399 400 FieldInfo.clear(); 401 } 402 } // ET->getClass() == RSExportType::ExportClassRecord 403 } 404 } 405 406 return; 407} 408 409RSBackend::~RSBackend() { 410 return; 411} 412