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