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