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