Function *GCOVProfiler::insertCounterWriteout( ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); if (!WriteoutF) WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage, "__llvm_gcov_writeout", M); WriteoutF->setUnnamedAddr(true); WriteoutF->addFnAttr(Attribute::NoInline); if (Options.NoRedZone) WriteoutF->addFnAttr(Attribute::NoRedZone); BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); IRBuilder<> Builder(BB); Constant *StartFile = getStartFileFunc(); Constant *EmitFunction = getEmitFunctionFunc(); Constant *EmitArcs = getEmitArcsFunc(); Constant *SummaryInfo = getSummaryInfoFunc(); Constant *EndFile = getEndFileFunc(); NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); if (CU_Nodes) { for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i)); std::string FilenameGcda = mangleName(CU, "gcda"); uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; Builder.CreateCall(StartFile, {Builder.CreateGlobalStringPtr(FilenameGcda), Builder.CreateGlobalStringPtr(ReversedVersion), Builder.getInt32(CfgChecksum)}); for (unsigned j = 0, e = CountersBySP.size(); j != e; ++j) { auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second); uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); Builder.CreateCall( EmitFunction, {Builder.getInt32(j), Options.FunctionNamesInData ? Builder.CreateGlobalStringPtr(getFunctionName(SP)) : Constant::getNullValue(Builder.getInt8PtrTy()), Builder.getInt32(FuncChecksum), Builder.getInt8(Options.UseCfgChecksum), Builder.getInt32(CfgChecksum)}); GlobalVariable *GV = CountersBySP[j].first; unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements(); Builder.CreateCall(EmitArcs, {Builder.getInt32(Arcs), Builder.CreateConstGEP2_64(GV, 0, 0)}); } Builder.CreateCall(SummaryInfo, {}); Builder.CreateCall(EndFile, {}); } } Builder.CreateRetVoid(); return WriteoutF; }
bool XCoreLowerThreadLocal::lowerGlobal(GlobalVariable *GV) { Module *M = GV->getParent(); LLVMContext &Ctx = M->getContext(); if (!GV->isThreadLocal()) return false; // Skip globals that we can't lower and leave it for the backend to error. if (!rewriteNonInstructionUses(GV, this) || !GV->getType()->isSized() || isZeroLengthArray(GV->getType())) return false; // Create replacement global. ArrayType *NewType = createLoweredType(GV->getType()->getElementType()); Constant *NewInitializer = nullptr; if (GV->hasInitializer()) NewInitializer = createLoweredInitializer(NewType, GV->getInitializer()); GlobalVariable *NewGV = new GlobalVariable(*M, NewType, GV->isConstant(), GV->getLinkage(), NewInitializer, "", nullptr, GlobalVariable::NotThreadLocal, GV->getType()->getAddressSpace(), GV->isExternallyInitialized()); // Update uses. SmallVector<User *, 16> Users(GV->user_begin(), GV->user_end()); for (unsigned I = 0, E = Users.size(); I != E; ++I) { User *U = Users[I]; Instruction *Inst = cast<Instruction>(U); IRBuilder<> Builder(Inst); Function *GetID = Intrinsic::getDeclaration(GV->getParent(), Intrinsic::xcore_getid); Value *ThreadID = Builder.CreateCall(GetID); SmallVector<Value *, 2> Indices; Indices.push_back(Constant::getNullValue(Type::getInt64Ty(Ctx))); Indices.push_back(ThreadID); Value *Addr = Builder.CreateInBoundsGEP(NewGV->getValueType(), NewGV, Indices); U->replaceUsesOfWith(GV, Addr); } // Remove old global. NewGV->takeName(GV); GV->eraseFromParent(); return true; }
Function *GCOVProfiler:: insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) { FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); Function *FlushF = M->getFunction("__llvm_gcov_flush"); if (!FlushF) FlushF = Function::Create(FTy, GlobalValue::InternalLinkage, "__llvm_gcov_flush", M); else FlushF->setLinkage(GlobalValue::InternalLinkage); FlushF->setUnnamedAddr(true); FlushF->addFnAttr(Attribute::NoInline); if (Options.NoRedZone) FlushF->addFnAttr(Attribute::NoRedZone); BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF); // Write out the current counters. Constant *WriteoutF = M->getFunction("__llvm_gcov_writeout"); assert(WriteoutF && "Need to create the writeout function first!"); IRBuilder<> Builder(Entry); Builder.CreateCall(WriteoutF, {}); // Zero out the counters. for (ArrayRef<std::pair<GlobalVariable *, MDNode *> >::iterator I = CountersBySP.begin(), E = CountersBySP.end(); I != E; ++I) { GlobalVariable *GV = I->first; Constant *Null = Constant::getNullValue(GV->getValueType()); Builder.CreateStore(Null, GV); } Type *RetTy = FlushF->getReturnType(); if (RetTy == Type::getVoidTy(*Ctx)) Builder.CreateRetVoid(); else if (RetTy->isIntegerTy()) // Used if __llvm_gcov_flush was implicitly declared. Builder.CreateRet(ConstantInt::get(RetTy, 0)); else report_fatal_error("invalid return type for __llvm_gcov_flush"); return FlushF; }
void BrainF::header(LLVMContext& C) { module = new Module("BrainF", C); //Function prototypes //declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i32, i1) Type *Tys[] = { Type::getInt8PtrTy(C), Type::getInt32Ty(C) }; Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset, Tys); //declare i32 @getchar() getchar_func = cast<Function>(module-> getOrInsertFunction("getchar", IntegerType::getInt32Ty(C), NULL)); //declare i32 @putchar(i32) putchar_func = cast<Function>(module-> getOrInsertFunction("putchar", IntegerType::getInt32Ty(C), IntegerType::getInt32Ty(C), NULL)); //Function header //define void @brainf() brainf_func = cast<Function>(module-> getOrInsertFunction("brainf", Type::getVoidTy(C), NULL)); builder = new IRBuilder<>(BasicBlock::Create(C, label, brainf_func)); //%arr = malloc i8, i32 %d ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal)); BasicBlock* BB = builder->GetInsertBlock(); Type* IntPtrTy = IntegerType::getInt32Ty(C); Type* Int8Ty = IntegerType::getInt8Ty(C); Constant* allocsize = ConstantExpr::getSizeOf(Int8Ty); allocsize = ConstantExpr::getTruncOrBitCast(allocsize, IntPtrTy); ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, Int8Ty, allocsize, val_mem, nullptr, "arr"); BB->getInstList().push_back(cast<Instruction>(ptr_arr)); //call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i32 1, i1 0) { Value *memset_params[] = { ptr_arr, ConstantInt::get(C, APInt(8, 0)), val_mem, ConstantInt::get(C, APInt(32, 1)), ConstantInt::get(C, APInt(1, 0)) }; CallInst *memset_call = builder-> CreateCall(memset_func, memset_params); memset_call->setTailCall(false); } //%arrmax = getelementptr i8 *%arr, i32 %d if (comflag & flag_arraybounds) { ptr_arrmax = builder-> CreateGEP(ptr_arr, ConstantInt::get(C, APInt(32, memtotal)), "arrmax"); } //%head.%d = getelementptr i8 *%arr, i32 %d curhead = builder->CreateGEP(ptr_arr, ConstantInt::get(C, APInt(32, memtotal/2)), headreg); //Function footer //brainf.end: endbb = BasicBlock::Create(C, label, brainf_func); //call free(i8 *%arr) endbb->getInstList().push_back(CallInst::CreateFree(ptr_arr, endbb)); //ret void ReturnInst::Create(C, endbb); //Error block for array out of bounds if (comflag & flag_arraybounds) { //@aberrormsg = internal constant [%d x i8] c"\00" Constant *msg_0 = ConstantDataArray::getString(C, "Error: The head has left the tape.", true); GlobalVariable *aberrormsg = new GlobalVariable( *module, msg_0->getType(), true, GlobalValue::InternalLinkage, msg_0, "aberrormsg"); //declare i32 @puts(i8 *) Function *puts_func = cast<Function>(module-> getOrInsertFunction("puts", IntegerType::getInt32Ty(C), PointerType::getUnqual(IntegerType::getInt8Ty(C)), NULL)); //brainf.aberror: aberrorbb = BasicBlock::Create(C, label, brainf_func); //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0)) { Constant *zero_32 = Constant::getNullValue(IntegerType::getInt32Ty(C)); Constant *gep_params[] = { zero_32, zero_32 }; Constant *msgptr = ConstantExpr:: getGetElementPtr(aberrormsg->getValueType(), aberrormsg, gep_params); Value *puts_params[] = { msgptr }; CallInst *puts_call = CallInst::Create(puts_func, puts_params, "", aberrorbb); puts_call->setTailCall(false); } //br label %brainf.end BranchInst::Create(endbb, aberrorbb); } }
bool GCOVProfiler::emitProfileArcs() { NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); if (!CU_Nodes) return false; bool Result = false; bool InsertIndCounterIncrCode = false; for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i)); SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; for (auto *SP : CU->getSubprograms()) { Function *F = FnMap[SP]; if (!F) continue; if (!functionHasLines(F)) continue; if (!Result) Result = true; unsigned Edges = 0; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { TerminatorInst *TI = BB->getTerminator(); if (isa<ReturnInst>(TI)) ++Edges; else Edges += TI->getNumSuccessors(); } ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Edges); GlobalVariable *Counters = new GlobalVariable(*M, CounterTy, false, GlobalValue::InternalLinkage, Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); CountersBySP.push_back(std::make_pair(Counters, SP)); UniqueVector<BasicBlock *> ComplexEdgePreds; UniqueVector<BasicBlock *> ComplexEdgeSuccs; unsigned Edge = 0; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { TerminatorInst *TI = BB->getTerminator(); int Successors = isa<ReturnInst>(TI) ? 1 : TI->getNumSuccessors(); if (Successors) { if (Successors == 1) { IRBuilder<> Builder(&*BB->getFirstInsertionPt()); Value *Counter = Builder.CreateConstInBoundsGEP2_64(Counters, 0, Edge); Value *Count = Builder.CreateLoad(Counter); Count = Builder.CreateAdd(Count, Builder.getInt64(1)); Builder.CreateStore(Count, Counter); } else if (BranchInst *BI = dyn_cast<BranchInst>(TI)) { IRBuilder<> Builder(BI); Value *Sel = Builder.CreateSelect(BI->getCondition(), Builder.getInt64(Edge), Builder.getInt64(Edge + 1)); SmallVector<Value *, 2> Idx; Idx.push_back(Builder.getInt64(0)); Idx.push_back(Sel); Value *Counter = Builder.CreateInBoundsGEP(Counters->getValueType(), Counters, Idx); Value *Count = Builder.CreateLoad(Counter); Count = Builder.CreateAdd(Count, Builder.getInt64(1)); Builder.CreateStore(Count, Counter); } else { ComplexEdgePreds.insert(&*BB); for (int i = 0; i != Successors; ++i) ComplexEdgeSuccs.insert(TI->getSuccessor(i)); } Edge += Successors; } } if (!ComplexEdgePreds.empty()) { GlobalVariable *EdgeTable = buildEdgeLookupTable(F, Counters, ComplexEdgePreds, ComplexEdgeSuccs); GlobalVariable *EdgeState = getEdgeStateValue(); for (int i = 0, e = ComplexEdgePreds.size(); i != e; ++i) { IRBuilder<> Builder(&*ComplexEdgePreds[i + 1]->getFirstInsertionPt()); Builder.CreateStore(Builder.getInt32(i), EdgeState); } for (int i = 0, e = ComplexEdgeSuccs.size(); i != e; ++i) { // Call runtime to perform increment. IRBuilder<> Builder(&*ComplexEdgeSuccs[i + 1]->getFirstInsertionPt()); Value *CounterPtrArray = Builder.CreateConstInBoundsGEP2_64(EdgeTable, 0, i * ComplexEdgePreds.size()); // Build code to increment the counter. InsertIndCounterIncrCode = true; Builder.CreateCall(getIncrementIndirectCounterFunc(), {EdgeState, CounterPtrArray}); } } } Function *WriteoutF = insertCounterWriteout(CountersBySP); Function *FlushF = insertFlush(CountersBySP); // Create a small bit of code that registers the "__llvm_gcov_writeout" to // be executed at exit and the "__llvm_gcov_flush" function to be executed // when "__gcov_flush" is called. FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, "__llvm_gcov_init", M); F->setUnnamedAddr(true); F->setLinkage(GlobalValue::InternalLinkage); F->addFnAttr(Attribute::NoInline); if (Options.NoRedZone) F->addFnAttr(Attribute::NoRedZone); BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); IRBuilder<> Builder(BB); FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); Type *Params[] = { PointerType::get(FTy, 0), PointerType::get(FTy, 0) }; FTy = FunctionType::get(Builder.getVoidTy(), Params, false); // Initialize the environment and register the local writeout and flush // functions. Constant *GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); Builder.CreateCall(GCOVInit, {WriteoutF, FlushF}); Builder.CreateRetVoid(); appendToGlobalCtors(*M, F, 0); } if (InsertIndCounterIncrCode) insertIndirectCounterIncrement(); return Result; }
Function *GCOVProfiler::insertCounterWriteout( ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); if (!WriteoutF) WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage, "__llvm_gcov_writeout", M); WriteoutF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); WriteoutF->addFnAttr(Attribute::NoInline); if (Options.NoRedZone) WriteoutF->addFnAttr(Attribute::NoRedZone); BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); IRBuilder<> Builder(BB); Constant *StartFile = getStartFileFunc(); Constant *EmitFunction = getEmitFunctionFunc(); Constant *EmitArcs = getEmitArcsFunc(); Constant *SummaryInfo = getSummaryInfoFunc(); Constant *EndFile = getEndFileFunc(); NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu"); if (!CUNodes) { Builder.CreateRetVoid(); return WriteoutF; } // Collect the relevant data into a large constant data structure that we can // walk to write out everything. StructType *StartFileCallArgsTy = StructType::create( {Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()}); StructType *EmitFunctionCallArgsTy = StructType::create( {Builder.getInt32Ty(), Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt8Ty(), Builder.getInt32Ty()}); StructType *EmitArcsCallArgsTy = StructType::create( {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}); StructType *FileInfoTy = StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(), EmitFunctionCallArgsTy->getPointerTo(), EmitArcsCallArgsTy->getPointerTo()}); Constant *Zero32 = Builder.getInt32(0); // Build an explicit array of two zeros for use in ConstantExpr GEP building. Constant *TwoZero32s[] = {Zero32, Zero32}; SmallVector<Constant *, 8> FileInfos; for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) { auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i)); // Skip module skeleton (and module) CUs. if (CU->getDWOId()) continue; std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA); uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; auto *StartFileCallArgs = ConstantStruct::get( StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda), Builder.CreateGlobalStringPtr(ReversedVersion), Builder.getInt32(CfgChecksum)}); SmallVector<Constant *, 8> EmitFunctionCallArgsArray; SmallVector<Constant *, 8> EmitArcsCallArgsArray; for (int j : llvm::seq<int>(0, CountersBySP.size())) { auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second); uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); EmitFunctionCallArgsArray.push_back(ConstantStruct::get( EmitFunctionCallArgsTy, {Builder.getInt32(j), Options.FunctionNamesInData ? Builder.CreateGlobalStringPtr(getFunctionName(SP)) : Constant::getNullValue(Builder.getInt8PtrTy()), Builder.getInt32(FuncChecksum), Builder.getInt8(Options.UseCfgChecksum), Builder.getInt32(CfgChecksum)})); GlobalVariable *GV = CountersBySP[j].first; unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements(); EmitArcsCallArgsArray.push_back(ConstantStruct::get( EmitArcsCallArgsTy, {Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr( GV->getValueType(), GV, TwoZero32s)})); } // Create global arrays for the two emit calls. int CountersSize = CountersBySP.size(); assert(CountersSize == (int)EmitFunctionCallArgsArray.size() && "Mismatched array size!"); assert(CountersSize == (int)EmitArcsCallArgsArray.size() && "Mismatched array size!"); auto *EmitFunctionCallArgsArrayTy = ArrayType::get(EmitFunctionCallArgsTy, CountersSize); auto *EmitFunctionCallArgsArrayGV = new GlobalVariable( *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, ConstantArray::get(EmitFunctionCallArgsArrayTy, EmitFunctionCallArgsArray), Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i)); auto *EmitArcsCallArgsArrayTy = ArrayType::get(EmitArcsCallArgsTy, CountersSize); EmitFunctionCallArgsArrayGV->setUnnamedAddr( GlobalValue::UnnamedAddr::Global); auto *EmitArcsCallArgsArrayGV = new GlobalVariable( *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray), Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i)); EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); FileInfos.push_back(ConstantStruct::get( FileInfoTy, {StartFileCallArgs, Builder.getInt32(CountersSize), ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy, EmitFunctionCallArgsArrayGV, TwoZero32s), ConstantExpr::getInBoundsGetElementPtr( EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)})); } // If we didn't find anything to actually emit, bail on out. if (FileInfos.empty()) { Builder.CreateRetVoid(); return WriteoutF; } // To simplify code, we cap the number of file infos we write out to fit // easily in a 32-bit signed integer. This gives consistent behavior between // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit // operations on 32-bit systems. It also seems unreasonable to try to handle // more than 2 billion files. if ((int64_t)FileInfos.size() > (int64_t)INT_MAX) FileInfos.resize(INT_MAX); // Create a global for the entire data structure so we can walk it more // easily. auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size()); auto *FileInfoArrayGV = new GlobalVariable( *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, ConstantArray::get(FileInfoArrayTy, FileInfos), "__llvm_internal_gcov_emit_file_info"); FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); // Create the CFG for walking this data structure. auto *FileLoopHeader = BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF); auto *CounterLoopHeader = BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF); auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF); auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF); // We always have at least one file, so just branch to the header. Builder.CreateBr(FileLoopHeader); // The index into the files structure is our loop induction variable. Builder.SetInsertPoint(FileLoopHeader); PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); IV->addIncoming(Builder.getInt32(0), BB); auto *FileInfoPtr = Builder.CreateInBoundsGEP(FileInfoArrayGV, {Builder.getInt32(0), IV}); auto *StartFileCallArgsPtr = Builder.CreateStructGEP(FileInfoPtr, 0); Builder.CreateCall( StartFile, {Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 0)), Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 1)), Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 2))}); auto *NumCounters = Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 1)); auto *EmitFunctionCallArgsArray = Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 2)); auto *EmitArcsCallArgsArray = Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 3)); auto *EnterCounterLoopCond = Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); Builder.SetInsertPoint(CounterLoopHeader); auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); JV->addIncoming(Builder.getInt32(0), FileLoopHeader); auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP(EmitFunctionCallArgsArray, {JV}); Builder.CreateCall( EmitFunction, {Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 0)), Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 1)), Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 2)), Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 3)), Builder.CreateLoad( Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 4))}); auto *EmitArcsCallArgsPtr = Builder.CreateInBoundsGEP(EmitArcsCallArgsArray, {JV}); Builder.CreateCall( EmitArcs, {Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 0)), Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 1))}); auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters); Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch); JV->addIncoming(NextJV, CounterLoopHeader); Builder.SetInsertPoint(FileLoopLatch); Builder.CreateCall(SummaryInfo, {}); Builder.CreateCall(EndFile, {}); auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1)); auto *FileLoopCond = Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); IV->addIncoming(NextIV, FileLoopLatch); Builder.SetInsertPoint(ExitBB); Builder.CreateRetVoid(); return WriteoutF; }
bool GenericToNVVM::runOnModule(Module &M) { // Create a clone of each global variable that has the default address space. // The clone is created with the global address space specifier, and the pair // of original global variable and its clone is placed in the GVMap for later // use. for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E;) { GlobalVariable *GV = &*I++; if (GV->getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC && !llvm::isTexture(*GV) && !llvm::isSurface(*GV) && !llvm::isSampler(*GV) && !GV->getName().startswith("llvm.")) { GlobalVariable *NewGV = new GlobalVariable( M, GV->getValueType(), GV->isConstant(), GV->getLinkage(), GV->hasInitializer() ? GV->getInitializer() : nullptr, "", GV, GV->getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL); NewGV->copyAttributesFrom(GV); GVMap[GV] = NewGV; } } // Return immediately, if every global variable has a specific address space // specifier. if (GVMap.empty()) { return false; } // Walk through the instructions in function defitinions, and replace any use // of original global variables in GVMap with a use of the corresponding // copies in GVMap. If necessary, promote constants to instructions. for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { if (I->isDeclaration()) { continue; } IRBuilder<> Builder(I->getEntryBlock().getFirstNonPHIOrDbg()); for (Function::iterator BBI = I->begin(), BBE = I->end(); BBI != BBE; ++BBI) { for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE; ++II) { for (unsigned i = 0, e = II->getNumOperands(); i < e; ++i) { Value *Operand = II->getOperand(i); if (isa<Constant>(Operand)) { II->setOperand( i, remapConstant(&M, &*I, cast<Constant>(Operand), Builder)); } } } } ConstantToValueMap.clear(); } // Copy GVMap over to a standard value map. ValueToValueMapTy VM; for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I) VM[I->first] = I->second; // Walk through the metadata section and update the debug information // associated with the global variables in the default address space. for (NamedMDNode &I : M.named_metadata()) { remapNamedMDNode(VM, &I); } // Walk through the global variable initializers, and replace any use of // original global variables in GVMap with a use of the corresponding copies // in GVMap. The copies need to be bitcast to the original global variable // types, as we cannot use cvta in global variable initializers. for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) { GlobalVariable *GV = I->first; GlobalVariable *NewGV = I->second; // Remove GV from the map so that it can be RAUWed. Note that // DenseMap::erase() won't invalidate any iterators but this one. auto Next = std::next(I); GVMap.erase(I); I = Next; Constant *BitCastNewGV = ConstantExpr::getPointerCast(NewGV, GV->getType()); // At this point, the remaining uses of GV should be found only in global // variable initializers, as other uses have been already been removed // while walking through the instructions in function definitions. GV->replaceAllUsesWith(BitCastNewGV); std::string Name = GV->getName(); GV->eraseFromParent(); NewGV->setName(Name); } assert(GVMap.empty() && "Expected it to be empty by now"); return true; }