/// \brief Get the FunctionSamples for an instruction. /// /// The FunctionSamples of an instruction \p Inst is the inlined instance /// in which that instruction is coming from. We traverse the inline stack /// of that instruction, and match it with the tree nodes in the profile. /// /// \param Inst Instruction to query. /// /// \returns the FunctionSamples pointer to the inlined instance. const FunctionSamples * SampleProfileLoader::findFunctionSamples(const Instruction &Inst) const { SmallVector<CallsiteLocation, 10> S; const DILocation *DIL = Inst.getDebugLoc(); if (!DIL) { return Samples; } StringRef CalleeName; for (const DILocation *DIL = Inst.getDebugLoc(); DIL; DIL = DIL->getInlinedAt()) { DISubprogram *SP = DIL->getScope()->getSubprogram(); if (!SP) return nullptr; if (!CalleeName.empty()) { S.push_back(CallsiteLocation(getOffset(DIL->getLine(), SP->getLine()), DIL->getDiscriminator(), CalleeName)); } CalleeName = SP->getLinkageName(); } if (S.size() == 0) return Samples; const FunctionSamples *FS = Samples; for (int i = S.size() - 1; i >= 0 && FS != nullptr; i--) { FS = FS->findFunctionSamplesAt(S[i]); } return FS; }
int ReplaceFunctionVariables( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "function variable..."); return TCL_ERROR; } DISubprogram *function; if (GetMetadataFromObj(interp, objv[1], "function", function) != TCL_OK) return TCL_ERROR; std::vector<Metadata*> variables; for (int i=2 ; i<objc ; i++) { DILocalVariable *var; if (GetMetadataFromObj(interp, objv[i], "variable", var) != TCL_OK) return TCL_ERROR; variables.push_back(var); } auto vars = function->getVariables(); if (!vars->isTemporary()) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "can only replace variable list when temporary", -1)); return TCL_ERROR; } vars->replaceAllUsesWith(MDNode::get(vars->getContext(), variables)); function->resolveCycles(); return TCL_OK; }
/// processSubprogram - Process DISubprogram. void DebugInfoFinder::processSubprogram(DISubprogram SP) { if (!addSubprogram(SP)) return; if (SP.getVersion() <= LLVMDebugVersion10) addCompileUnit(SP.getCompileUnit()); processType(SP.getType()); }
DebugLoc DebugLoc::getFnDebugLoc(const LLVMContext &Ctx) const { const MDNode *Scope = getScopeNode(Ctx); DISubprogram SP = getDISubprogram(Scope); if (SP.isSubprogram()) return DebugLoc::get(SP.getScopeLineNumber(), 0, SP); return DebugLoc(); }
/// processSubprogram - Process DISubprogram. void DebugInfoFinder::processSubprogram(DISubprogram SP) { if (SP.isNull()) return; if (!addSubprogram(SP)) return; addCompileUnit(SP.getCompileUnit()); processType(SP.getType()); }
DebugLoc DebugLoc::getFnDebugLoc() const { // FIXME: Add a method on \a MDLocation that does this work. const MDNode *Scope = getInlinedAtScope(); DISubprogram SP = getDISubprogram(Scope); if (SP.isSubprogram()) return DebugLoc::get(SP.getScopeLineNumber(), 0, SP); return DebugLoc(); }
bool DIVariable::isInlinedFnArgument(const Function *CurFn) { assert(CurFn && "Invalid function"); DISubprogram SP = dyn_cast<MDSubprogram>(getContext()); if (!SP) return false; // This variable is not inlined function argument if its scope // does not describe current function. return !SP.describes(CurFn); }
// addSubprogram - Add subprgoram into SPs. bool DebugInfoFinder::addSubprogram(DISubprogram SP) { if (SP.isNull()) return false; if (!NodesSeen.insert(SP.getNode())) return false; SPs.push_back(SP.getNode()); return true; }
void DebugDatabase::addFunction(MDNode *subprogram, GenerateRTL *hw) { string name; DISubprogram s; assert(subprogram || hw); if (subprogram) { s = DISubprogram(subprogram); name = s.getName().str(); } if (hw) { // dbgs() << "Adding function " << // hw->getFunction()->getName().str() << "\n"; if (hwToFunctionIds.find(hw) != hwToFunctionIds.end()) { // This function has already been added // This can happen since we add functions with metadata first, then // add all functions with hardware next. Those with metadata will // have // already been added // dbgs() << "exiting\n"; return; } else { // dbgs() << "not exiting\n"; } if (subprogram) { assert(name == hw->getFunction()->getName().str()); } else { name = hw->getFunction()->getName().str(); } } std::string query = "INSERT INTO Function (designId, name, inlined, " "hasMetadata, startLineNumber) "; query += "VALUES (" + std::to_string(designId); query += "," + addQuotesToStr(name); query += "," + std::to_string(hw ? false : true); query += "," + std::to_string(subprogram ? true : false); query += "," + (subprogram ? std::to_string(s.getLineNumber()) : "NULL"); query += ");"; runQuery(query); int functionId = mysql_insert_id(connection); if (subprogram) { subprogramsToFunctionIds[subprogram] = functionId; } if (hw) { hwToFunctionIds[hw] = functionId; } }
DebugLoc DebugLoc::getFnDebugLoc(const LLVMContext &Ctx) { const MDNode *Scope = getScopeNode(Ctx); DISubprogram SP = getDISubprogram(Scope); if (SP.isSubprogram()) { // Check for number of operands since the compatibility is // cheap here. FIXME: Name the magic constant. if (SP->getNumOperands() > 19) return DebugLoc::get(SP.getScopeLineNumber(), 0, SP); else return DebugLoc::get(SP.getLineNumber(), 0, SP); } return DebugLoc(); }
void getFunctionInfo(const char **name, int *line, const char **filename, size_t pointer) { std::map<size_t, FuncInfo> info = jl_jit_events->getMap(); *name = NULL; *line = -1; *filename = "no file"; for (std::map<size_t, FuncInfo>::iterator it= info.begin(); it!= info.end(); it++) { if ((*it).first <= pointer) { if ((size_t)(*it).first + (*it).second.lengthAdr >= pointer) { #if LLVM_VERSION_MAJOR == 3 #if LLVM_VERSION_MINOR == 0 *name = &(*(*it).second.func).getNameStr()[0]; #elif LLVM_VERSION_MINOR >= 1 *name = (((*(*it).second.func).getName()).data()); #endif #endif if ((*it).second.lines.size() == 0) { continue; } std::vector<JITEvent_EmittedFunctionDetails::LineStart>::iterator vit = (*it).second.lines.begin(); JITEvent_EmittedFunctionDetails::LineStart prev = *vit; DISubprogram debugscope = DISubprogram(prev.Loc.getScope((*it).second.func->getContext())); *filename = debugscope.getFilename().data(); // the DISubprogram has the un-mangled name, so use that if // available. *name = debugscope.getName().data(); vit++; while (vit != (*it).second.lines.end()) { if (pointer <= (*vit).Address) { *line = prev.Loc.getLine(); break; } prev = *vit; vit++; } if (*line == -1) { *line = prev.Loc.getLine(); } break; } } } }
void DebugInfoFinder::processSubprogram(DISubprogram SP) { if (!addSubprogram(SP)) return; processScope(SP.getContext().resolve(TypeIdentifierMap)); processType(SP.getType()); for (auto *Element : SP.getTemplateParams()) { if (DITemplateTypeParameter TType = dyn_cast<MDTemplateTypeParameter>(Element)) { processType(TType.getType().resolve(TypeIdentifierMap)); } else if (DITemplateValueParameter TVal = dyn_cast<MDTemplateValueParameter>(Element)) { processType(TVal.getType().resolve(TypeIdentifierMap)); } } }
DISubprogram llvm::getDISubprogram(const Function *F) { // We look for the first instr that has a debug annotation leading back to F. for (auto &BB : *F) { auto Inst = std::find_if(BB.begin(), BB.end(), [](const Instruction &Inst) { return !Inst.getDebugLoc().isUnknown(); }); if (Inst == BB.end()) continue; DebugLoc DLoc = Inst->getDebugLoc(); const MDNode *Scope = DLoc.getScopeNode(); DISubprogram Subprogram = getDISubprogram(Scope); return Subprogram.describes(F) ? Subprogram : DISubprogram(); } return DISubprogram(); }
void DebugInfoFinder::processSubprogram(DISubprogram SP) { if (!addSubprogram(SP)) return; processScope(SP.getContext().resolve(TypeIdentifierMap)); processType(SP.getType()); DIArray TParams = SP.getTemplateParams(); for (unsigned I = 0, E = TParams.getNumElements(); I != E; ++I) { DIDescriptor Element = TParams.getElement(I); if (Element.isTemplateTypeParameter()) { DITemplateTypeParameter TType(Element); processType(TType.getType().resolve(TypeIdentifierMap)); } else if (Element.isTemplateValueParameter()) { DITemplateValueParameter TVal(Element); processType(TVal.getType().resolve(TypeIdentifierMap)); } } }
void LineNumberAnnotatedWriter::emitFunctionAnnot( const Function *F, formatted_raw_ostream &Out) { InstrLoc = nullptr; DISubprogram *FuncLoc = F->getSubprogram(); if (!FuncLoc) { auto SP = Subprogram.find(F); if (SP != Subprogram.end()) FuncLoc = SP->second; } if (!FuncLoc) return; std::vector<DILineInfo> DIvec(1); DILineInfo &DI = DIvec.back(); DI.FunctionName = FuncLoc->getName(); DI.FileName = FuncLoc->getFilename(); DI.Line = FuncLoc->getLine(); LinePrinter.emit_lineinfo(Out, DIvec); }
/// fixupSubprogramName - Replace contains special characters used /// in a typical Objective-C names with '.' in a given string. static void fixupSubprogramName(DISubprogram Fn, SmallVectorImpl<char> &Out) { StringRef FName = Fn.getFunction() ? Fn.getFunction()->getName() : Fn.getName(); FName = Function::getRealLinkageName(FName); StringRef Prefix("llvm.dbg.lv."); Out.reserve(FName.size() + Prefix.size()); Out.append(Prefix.begin(), Prefix.end()); bool isObjCLike = false; for (size_t i = 0, e = FName.size(); i < e; ++i) { char C = FName[i]; if (C == '[') isObjCLike = true; if (isObjCLike && (C == '[' || C == ']' || C == ' ' || C == ':' || C == '+' || C == '(' || C == ')')) Out.push_back('.'); else Out.push_back(C); } }
/// \brief Get the FunctionSamples for a call instruction. /// /// The FunctionSamples of a call instruction \p Inst is the inlined /// instance in which that call instruction is calling to. It contains /// all samples that resides in the inlined instance. We first find the /// inlined instance in which the call instruction is from, then we /// traverse its children to find the callsite with the matching /// location and callee function name. /// /// \param Inst Call instruction to query. /// /// \returns The FunctionSamples pointer to the inlined instance. const FunctionSamples * SampleProfileLoader::findCalleeFunctionSamples(const CallInst &Inst) const { const DILocation *DIL = Inst.getDebugLoc(); if (!DIL) { return nullptr; } DISubprogram *SP = DIL->getScope()->getSubprogram(); if (!SP || DIL->getLine() < SP->getLine()) return nullptr; Function *CalleeFunc = Inst.getCalledFunction(); if (!CalleeFunc) { return nullptr; } StringRef CalleeName = CalleeFunc->getName(); const FunctionSamples *FS = findFunctionSamples(Inst); if (FS == nullptr) return nullptr; return FS->findFunctionSamplesAt(CallsiteLocation( DIL->getLine() - SP->getLine(), DIL->getDiscriminator(), CalleeName)); }
/// addPubTypes - Add type for pubtypes section. void CompileUnit::addPubTypes(DISubprogram SP) { DICompositeType SPTy = SP.getType(); unsigned SPTag = SPTy.getTag(); if (SPTag != dwarf::DW_TAG_subroutine_type) return; DIArray Args = SPTy.getTypeArray(); for (unsigned i = 0, e = Args.getNumElements(); i != e; ++i) { DIType ATy(Args.getElement(i)); if (!ATy.Verify()) continue; addGlobalType(ATy); } }
bool cmpDISP(const DISubprogram & SP1, const DISubprogram & SP2) { int cmp = SP1.getDirectory().compare(SP2.getDirectory()); if (cmp == 0) { cmp = SP1.getFilename().compare(SP2.getFilename()); if (cmp == 0) { cmp = SP1.getLineNumber() - SP2.getLineNumber(); } } return cmp >= 0 ? false : true; }
/// addSourceLine - Add location information to specified debug information /// entry. void CompileUnit::addSourceLine(DIE *Die, DISubprogram SP) { // Verify subprogram. if (!SP.Verify()) return; // If the line number is 0, don't add it. if (SP.getLineNumber() == 0) return; unsigned Line = SP.getLineNumber(); if (!SP.getContext().Verify()) return; unsigned FileID = DD->GetOrCreateSourceID(SP.getFilename(), SP.getDirectory()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); }
void GCOVProfiler::emitProfileNotes() { NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); if (!CU_Nodes) return; for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { // Each compile unit gets its own .gcno file. This means that whether we run // this pass over the original .o's as they're produced, or run it after // LTO, we'll generate the same .gcno files. auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i)); // Skip module skeleton (and module) CUs. if (CU->getDWOId()) continue; std::error_code EC; raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, sys::fs::F_None); if (EC) { Ctx->emitError(Twine("failed to open coverage notes file for writing: ") + EC.message()); continue; } std::string EdgeDestinations; unsigned FunctionIdent = 0; for (auto &F : M->functions()) { DISubprogram *SP = F.getSubprogram(); if (!SP) continue; if (!functionHasLines(F)) continue; // TODO: Functions using scope-based EH are currently not supported. if (isUsingScopeBasedEH(F)) continue; // gcov expects every function to start with an entry block that has a // single successor, so split the entry block to make sure of that. BasicBlock &EntryBlock = F.getEntryBlock(); BasicBlock::iterator It = EntryBlock.begin(); while (shouldKeepInEntry(It)) ++It; EntryBlock.splitBasicBlock(It); Funcs.push_back(make_unique<GCOVFunction>(SP, &F, &out, FunctionIdent++, Options.UseCfgChecksum, Options.ExitBlockBeforeBody)); GCOVFunction &Func = *Funcs.back(); for (auto &BB : F) { GCOVBlock &Block = Func.getBlock(&BB); TerminatorInst *TI = BB.getTerminator(); if (int successors = TI->getNumSuccessors()) { for (int i = 0; i != successors; ++i) { Block.addEdge(Func.getBlock(TI->getSuccessor(i))); } } else if (isa<ReturnInst>(TI)) { Block.addEdge(Func.getReturnBlock()); } uint32_t Line = 0; for (auto &I : BB) { // Debug intrinsic locations correspond to the location of the // declaration, not necessarily any statements or expressions. if (isa<DbgInfoIntrinsic>(&I)) continue; const DebugLoc &Loc = I.getDebugLoc(); if (!Loc) continue; // Artificial lines such as calls to the global constructors. if (Loc.getLine() == 0) continue; if (Line == Loc.getLine()) continue; Line = Loc.getLine(); if (SP != getDISubprogram(Loc.getScope())) continue; GCOVLines &Lines = Block.getFile(SP->getFilename()); Lines.addLine(Loc.getLine()); } } EdgeDestinations += Func.getEdgeDestinations(); } FileChecksums.push_back(hash_value(EdgeDestinations)); out.write("oncg", 4); out.write(ReversedVersion, 4); out.write(reinterpret_cast<char*>(&FileChecksums.back()), 4); for (auto &Func : Funcs) { Func->setCfgChecksum(FileChecksums.back()); Func->writeOut(); } out.write("\0\0\0\0\0\0\0\0", 8); // EOF out.close(); } }
void jl_getFunctionInfo(const char **name, int *line, const char **filename, size_t pointer, int skipC) { *name = NULL; *line = -1; *filename = "no file"; #if USE_MCJIT // With MCJIT we can get function information directly from the ObjectFile std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events->getObjectMap(); std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(pointer); if (it == objmap.end()) return jl_getDylibFunctionInfo(name,line,filename,pointer,skipC); if ((pointer - it->first) > it->second.size) return jl_getDylibFunctionInfo(name,line,filename,pointer,skipC); DIContext *context = DIContext::getDWARFContext(it->second.object); lookup_pointer(context, name, line, filename, pointer, 1); #else // !USE_MCJIT // Without MCJIT we use the FuncInfo structure containing address maps std::map<size_t, FuncInfo, revcomp> &info = jl_jit_events->getMap(); std::map<size_t, FuncInfo, revcomp>::iterator it = info.lower_bound(pointer); if (it != info.end() && (size_t)(*it).first + (*it).second.lengthAdr >= pointer) { // commenting these lines out skips functions that don't // have explicit debug info. this is useful for hiding // the jlcall wrapper functions we generate. #if LLVM_VERSION_MAJOR == 3 #if LLVM_VERSION_MINOR == 0 //*name = &(*(*it).second.func).getNameStr()[0]; #elif LLVM_VERSION_MINOR >= 1 //*name = (((*(*it).second.func).getName()).data()); #endif #endif std::vector<JITEvent_EmittedFunctionDetails::LineStart>::iterator vit = (*it).second.lines.begin(); JITEvent_EmittedFunctionDetails::LineStart prev = *vit; if ((*it).second.func) { DISubprogram debugscope = DISubprogram(prev.Loc.getScope((*it).second.func->getContext())); *filename = debugscope.getFilename().data(); // the DISubprogram has the un-mangled name, so use that if // available. *name = debugscope.getName().data(); } else { *name = (*it).second.name.c_str(); *filename = (*it).second.filename.c_str(); } vit++; while (vit != (*it).second.lines.end()) { if (pointer <= (*vit).Address) { *line = prev.Loc.getLine(); break; } prev = *vit; vit++; } if (*line == -1) { *line = prev.Loc.getLine(); } } else { jl_getDylibFunctionInfo(name,line,filename,pointer,skipC); } #endif // USE_MCJIT }
bool DevirtModule::run() { Function *TypeTestFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_test)); Function *TypeCheckedLoadFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load)); Function *AssumeFunc = M.getFunction(Intrinsic::getName(Intrinsic::assume)); if ((!TypeTestFunc || TypeTestFunc->use_empty() || !AssumeFunc || AssumeFunc->use_empty()) && (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty())) return false; if (TypeTestFunc && AssumeFunc) scanTypeTestUsers(TypeTestFunc, AssumeFunc); if (TypeCheckedLoadFunc) scanTypeCheckedLoadUsers(TypeCheckedLoadFunc); // Rebuild type metadata into a map for easy lookup. std::vector<VTableBits> Bits; DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap; buildTypeIdentifierMap(Bits, TypeIdMap); if (TypeIdMap.empty()) return true; // For each (type, offset) pair: bool DidVirtualConstProp = false; std::map<std::string, Function*> DevirtTargets; for (auto &S : CallSlots) { // Search each of the members of the type identifier for the virtual // function implementation at offset S.first.ByteOffset, and add to // TargetsForSlot. std::vector<VirtualCallTarget> TargetsForSlot; if (!tryFindVirtualCallTargets(TargetsForSlot, TypeIdMap[S.first.TypeID], S.first.ByteOffset)) continue; if (!trySingleImplDevirt(TargetsForSlot, S.second) && tryVirtualConstProp(TargetsForSlot, S.second)) DidVirtualConstProp = true; // Collect functions devirtualized at least for one call site for stats. if (RemarksEnabled) for (const auto &T : TargetsForSlot) if (T.WasDevirt) DevirtTargets[T.Fn->getName()] = T.Fn; } if (RemarksEnabled) { // Generate remarks for each devirtualized function. for (const auto &DT : DevirtTargets) { Function *F = DT.second; DISubprogram *SP = F->getSubprogram(); DebugLoc DL = SP ? DebugLoc::get(SP->getScopeLine(), 0, SP) : DebugLoc(); emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F, DL, Twine("devirtualized ") + F->getName()); } } // If we were able to eliminate all unsafe uses for a type checked load, // eliminate the type test by replacing it with true. if (TypeCheckedLoadFunc) { auto True = ConstantInt::getTrue(M.getContext()); for (auto &&U : NumUnsafeUsesForTypeTest) { if (U.second == 0) { U.first->replaceAllUsesWith(True); U.first->eraseFromParent(); } } } // Rebuild each global we touched as part of virtual constant propagation to // include the before and after bytes. if (DidVirtualConstProp) for (VTableBits &B : Bits) rebuildGlobal(B); return true; }
void jl_dump_function_asm(const char *Fptr, size_t Fsize, #ifndef USE_MCJIT std::vector<JITEvent_EmittedFunctionDetails::LineStart> lineinfo, #else const object::ObjectFile *objectfile, #endif formatted_raw_ostream &stream) { // Initialize targets and assembly printers/parsers. // Avoids hard-coded targets - will generally be only host CPU anyway. llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetDisassembler(); // Get the host information std::string TripleName; if (TripleName.empty()) TripleName = sys::getDefaultTargetTriple(); Triple TheTriple(Triple::normalize(TripleName)); std::string MCPU = sys::getHostCPUName(); SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(TheTriple); std::string err; const Target* TheTarget = TargetRegistry::lookupTarget(TripleName, err); // Set up required helpers and streamer #ifdef LLVM35 std::unique_ptr<MCStreamer> Streamer; #else OwningPtr<MCStreamer> Streamer; #endif SourceMgr SrcMgr; #ifdef LLVM35 std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TripleName),TripleName)); #elif defined(LLVM34) llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TripleName),TripleName)); #else llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName)); #endif assert(MAI && "Unable to create target asm info!"); #ifdef LLVM35 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); #else llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); #endif assert(MRI && "Unable to create target register info!"); #ifdef LLVM35 std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); #else OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); #endif #ifdef LLVM34 MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); #else MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); #endif MOFI->InitMCObjectFileInfo(TripleName, Reloc::Default, CodeModel::Default, Ctx); // Set up Subtarget and Disassembler #ifdef LLVM35 std::unique_ptr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); std::unique_ptr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI, Ctx)); #else OwningPtr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); OwningPtr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); #endif if (!DisAsm) { JL_PRINTF(JL_STDERR, "error: no disassembler for target", TripleName.c_str(), "\n"); return; } unsigned OutputAsmVariant = 1; bool ShowEncoding = false; bool ShowInst = false; #ifdef LLVM35 std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); std::unique_ptr<MCInstrAnalysis> MCIA(TheTarget->createMCInstrAnalysis(MCII.get())); #else OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); OwningPtr<MCInstrAnalysis> MCIA(TheTarget->createMCInstrAnalysis(MCII.get())); #endif MCInstPrinter* IP = TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MCII, *MRI, *STI); MCCodeEmitter *CE = 0; MCAsmBackend *MAB = 0; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); #ifdef LLVM34 MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); #else MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); #endif } Streamer.reset(TheTarget->createAsmStreamer(Ctx, stream, /*asmverbose*/true, #ifndef LLVM35 /*useLoc*/ true, /*useCFI*/ true, #endif /*useDwarfDirectory*/ true, IP, CE, MAB, ShowInst)); #ifdef LLVM36 Streamer->InitSections(true); #else Streamer->InitSections(); #endif // Make the MemoryObject wrapper #ifdef LLVM36 ArrayRef<uint8_t> memoryObject(const_cast<uint8_t*>((const uint8_t*)Fptr),Fsize); #else FuncMCView memoryObject(Fptr, Fsize); #endif SymbolTable DisInfo(Ctx, memoryObject); #ifdef USE_MCJIT if (!objectfile) return; #ifdef LLVM36 DIContext *di_ctx = DIContext::getDWARFContext(*objectfile); #else DIContext *di_ctx = DIContext::getDWARFContext(const_cast<object::ObjectFile*>(objectfile)); #endif if (di_ctx == NULL) return; DILineInfoTable lineinfo = di_ctx->getLineInfoForAddressRange((size_t)Fptr, Fsize); #else typedef std::vector<JITEvent_EmittedFunctionDetails::LineStart> LInfoVec; #endif // Take two passes: In the first pass we record all branch labels, // in the second we actually perform the output for (int pass = 0; pass < 2; ++ pass) { DisInfo.setPass(pass); if (pass != 0) { // Switch to symbolic disassembly. We cannot do this // before the first pass, because this changes branch // targets from immediate values (constants) to // expressions, which are not handled correctly by // MCIA->evaluateBranch. (It should be possible to rewrite // this routine to handle this case correctly as well.) // Could add OpInfoLookup here #ifdef LLVM35 DisAsm->setSymbolizer(std::unique_ptr<MCSymbolizer>(new MCExternalSymbolizer( Ctx, std::unique_ptr<MCRelocationInfo>(new MCRelocationInfo(Ctx)), OpInfoLookup, SymbolLookup, &DisInfo))); #else DisAsm->setupForSymbolicDisassembly( OpInfoLookup, SymbolLookup, &DisInfo, &Ctx); #endif } uint64_t nextLineAddr = -1; #ifdef USE_MCJIT // Set up the line info DILineInfoTable::iterator lineIter = lineinfo.begin(); DILineInfoTable::iterator lineEnd = lineinfo.end(); if (lineIter != lineEnd) { nextLineAddr = lineIter->first; if (pass != 0) { #ifdef LLVM35 stream << "Filename: " << lineIter->second.FileName << "\n"; #else stream << "Filename: " << lineIter->second.getFileName() << "\n"; #endif } } #else // Set up the line info LInfoVec::iterator lineIter = lineinfo.begin(); LInfoVec::iterator lineEnd = lineinfo.end(); if (lineIter != lineEnd) { nextLineAddr = (*lineIter).Address; DISubprogram debugscope = DISubprogram((*lineIter).Loc.getScope(jl_LLVMContext)); if (pass != 0) { stream << "Filename: " << debugscope.getFilename() << "\n"; stream << "Source line: " << (*lineIter).Loc.getLine() << "\n"; } } #endif uint64_t Index = 0; uint64_t absAddr = 0; uint64_t insSize = 0; // Do the disassembly for (Index = 0, absAddr = (uint64_t)Fptr; Index < Fsize; Index += insSize, absAddr += insSize) { if (nextLineAddr != (uint64_t)-1 && absAddr == nextLineAddr) { #ifdef USE_MCJIT #ifdef LLVM35 if (pass != 0) stream << "Source line: " << lineIter->second.Line << "\n"; #else if (pass != 0) stream << "Source line: " << lineIter->second.getLine() << "\n"; #endif nextLineAddr = (++lineIter)->first; #else if (pass != 0) stream << "Source line: " << (*lineIter).Loc.getLine() << "\n"; nextLineAddr = (*++lineIter).Address; #endif } if (pass != 0) { // Uncomment this to output addresses for all instructions // stream << Index << ": "; const char *symbolName = DisInfo.lookupSymbol(Index); if (symbolName) stream << symbolName << ":"; } MCInst Inst; MCDisassembler::DecodeStatus S; S = DisAsm->getInstruction(Inst, insSize, memoryObject, Index, /*REMOVE*/ nulls(), nulls()); switch (S) { case MCDisassembler::Fail: if (pass != 0) SrcMgr.PrintMessage(SMLoc::getFromPointer(Fptr + Index), SourceMgr::DK_Warning, "invalid instruction encoding"); if (insSize == 0) insSize = 1; // skip illegible bytes break; case MCDisassembler::SoftFail: if (pass != 0) SrcMgr.PrintMessage(SMLoc::getFromPointer(Fptr + Index), SourceMgr::DK_Warning, "potentially undefined instruction encoding"); // Fall through case MCDisassembler::Success: if (pass == 0) { // Pass 0: Record all branch targets if (MCIA->isBranch(Inst)) { uint64_t addr; #ifdef LLVM35 if (MCIA->evaluateBranch(Inst, Index, insSize, addr)) #else if ((addr = MCIA->evaluateBranch(Inst, Index, insSize)) != (uint64_t)-1) #endif DisInfo.insertAddress(addr); } } else { // Pass 1: Output instruction #ifdef LLVM35 Streamer->EmitInstruction(Inst, *STI); #else Streamer->EmitInstruction(Inst); #endif } break; } } if (pass == 0) DisInfo.createSymbols(); } }
void jl_dump_function_asm(void* Fptr, size_t Fsize, std::vector<JITEvent_EmittedFunctionDetails::LineStart> lineinfo, formatted_raw_ostream &stream) { // Initialize targets and assembly printers/parsers. // Avoids hard-coded targets - will generally be only host CPU anyway. llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetDisassembler(); // Get the host information std::string TripleName; if (TripleName.empty()) TripleName = sys::getDefaultTargetTriple(); Triple TheTriple(Triple::normalize(TripleName)); std::string MCPU = sys::getHostCPUName(); SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(TheTriple); std::string err; const Target* TheTarget = TargetRegistry::lookupTarget(TripleName, err); // Set up required helpers and streamer OwningPtr<MCStreamer> Streamer; SourceMgr SrcMgr; #ifdef LLVM34 llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TripleName),TripleName)); #else llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName)); #endif assert(MAI && "Unable to create target asm info!"); llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); #ifdef LLVM34 MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); #else MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); #endif MOFI->InitMCObjectFileInfo(TripleName, Reloc::Default, CodeModel::Default, Ctx); // Set up Subtarget and Disassembler OwningPtr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); #ifdef LLVM35 OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI, Ctx)); #else OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); #endif if (!DisAsm) { JL_PRINTF(JL_STDERR, "error: no disassembler for target", TripleName.c_str(), "\n"); return; } unsigned OutputAsmVariant = 1; bool ShowEncoding = false; bool ShowInst = false; OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); MCInstPrinter* IP = TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MCII, *MRI, *STI); MCCodeEmitter *CE = 0; MCAsmBackend *MAB = 0; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); #ifdef LLVM34 MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); #else MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); #endif } Streamer.reset(TheTarget->createAsmStreamer(Ctx, stream, /*asmverbose*/true, #ifndef LLVM35 /*useLoc*/ true, /*useCFI*/ true, #endif /*useDwarfDirectory*/ true, IP, CE, MAB, ShowInst)); Streamer->InitSections(); // Make the MemoryObject wrapper FuncMCView memoryObject(Fptr, Fsize); uint64_t Size; uint64_t Index; uint64_t absAddr; // Set up the line info typedef std::vector<JITEvent_EmittedFunctionDetails::LineStart> LInfoVec; LInfoVec::iterator lineIter = lineinfo.begin(); lineIter = lineinfo.begin(); uint64_t nextLineAddr = -1; DISubprogram debugscope; if (lineIter != lineinfo.end()) { nextLineAddr = (*lineIter).Address; debugscope = DISubprogram((*lineIter).Loc.getScope(jl_LLVMContext)); stream << "Filename: " << debugscope.getFilename().data() << "\n"; stream << "Source line: " << (*lineIter).Loc.getLine() << "\n"; } // Do the disassembly for (Index = 0, absAddr = (uint64_t)Fptr; Index < memoryObject.getExtent(); Index += Size, absAddr += Size) { if (nextLineAddr != (uint64_t)-1 && absAddr == nextLineAddr) { stream << "Source line: " << (*lineIter).Loc.getLine() << "\n"; nextLineAddr = (*++lineIter).Address; } MCInst Inst; MCDisassembler::DecodeStatus S; S = DisAsm->getInstruction(Inst, Size, memoryObject, Index, /*REMOVE*/ nulls(), nulls()); switch (S) { case MCDisassembler::Fail: SrcMgr.PrintMessage(SMLoc::getFromPointer(memoryObject[Index]), SourceMgr::DK_Warning, "invalid instruction encoding"); if (Size == 0) Size = 1; // skip illegible bytes break; case MCDisassembler::SoftFail: SrcMgr.PrintMessage(SMLoc::getFromPointer(memoryObject[Index]), SourceMgr::DK_Warning, "potentially undefined instruction encoding"); // Fall through case MCDisassembler::Success: #ifdef LLVM35 Streamer->EmitInstruction(Inst, *STI); #else Streamer->EmitInstruction(Inst); #endif break; } } }
/// DoPromotion - This method actually performs the promotion of the specified /// arguments, and returns the new function. At this point, we know that it's /// safe to do so. CallGraphNode *ArgPromotion::DoPromotion(Function *F, SmallPtrSetImpl<Argument*> &ArgsToPromote, SmallPtrSetImpl<Argument*> &ByValArgsToTransform) { // Start by computing a new prototype for the function, which is the same as // the old function, but has modified arguments. FunctionType *FTy = F->getFunctionType(); std::vector<Type*> Params; typedef std::set<IndicesVector> ScalarizeTable; // ScalarizedElements - If we are promoting a pointer that has elements // accessed out of it, keep track of which elements are accessed so that we // can add one argument for each. // // Arguments that are directly loaded will have a zero element value here, to // handle cases where there are both a direct load and GEP accesses. // std::map<Argument*, ScalarizeTable> ScalarizedElements; // OriginalLoads - Keep track of a representative load instruction from the // original function so that we can tell the alias analysis implementation // what the new GEP/Load instructions we are inserting look like. // We need to keep the original loads for each argument and the elements // of the argument that are accessed. std::map<std::pair<Argument*, IndicesVector>, LoadInst*> OriginalLoads; // Attribute - Keep track of the parameter attributes for the arguments // that we are *not* promoting. For the ones that we do promote, the parameter // attributes are lost SmallVector<AttributeSet, 8> AttributesVec; const AttributeSet &PAL = F->getAttributes(); // Add any return attributes. if (PAL.hasAttributes(AttributeSet::ReturnIndex)) AttributesVec.push_back(AttributeSet::get(F->getContext(), PAL.getRetAttributes())); // First, determine the new argument list unsigned ArgIndex = 1; for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I, ++ArgIndex) { if (ByValArgsToTransform.count(I)) { // Simple byval argument? Just add all the struct element types. Type *AgTy = cast<PointerType>(I->getType())->getElementType(); StructType *STy = cast<StructType>(AgTy); for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) Params.push_back(STy->getElementType(i)); ++NumByValArgsPromoted; } else if (!ArgsToPromote.count(I)) { // Unchanged argument Params.push_back(I->getType()); AttributeSet attrs = PAL.getParamAttributes(ArgIndex); if (attrs.hasAttributes(ArgIndex)) { AttrBuilder B(attrs, ArgIndex); AttributesVec. push_back(AttributeSet::get(F->getContext(), Params.size(), B)); } } else if (I->use_empty()) { // Dead argument (which are always marked as promotable) ++NumArgumentsDead; } else { // Okay, this is being promoted. This means that the only uses are loads // or GEPs which are only used by loads // In this table, we will track which indices are loaded from the argument // (where direct loads are tracked as no indices). ScalarizeTable &ArgIndices = ScalarizedElements[I]; for (User *U : I->users()) { Instruction *UI = cast<Instruction>(U); assert(isa<LoadInst>(UI) || isa<GetElementPtrInst>(UI)); IndicesVector Indices; Indices.reserve(UI->getNumOperands() - 1); // Since loads will only have a single operand, and GEPs only a single // non-index operand, this will record direct loads without any indices, // and gep+loads with the GEP indices. for (User::op_iterator II = UI->op_begin() + 1, IE = UI->op_end(); II != IE; ++II) Indices.push_back(cast<ConstantInt>(*II)->getSExtValue()); // GEPs with a single 0 index can be merged with direct loads if (Indices.size() == 1 && Indices.front() == 0) Indices.clear(); ArgIndices.insert(Indices); LoadInst *OrigLoad; if (LoadInst *L = dyn_cast<LoadInst>(UI)) OrigLoad = L; else // Take any load, we will use it only to update Alias Analysis OrigLoad = cast<LoadInst>(UI->user_back()); OriginalLoads[std::make_pair(I, Indices)] = OrigLoad; } // Add a parameter to the function for each element passed in. for (ScalarizeTable::iterator SI = ArgIndices.begin(), E = ArgIndices.end(); SI != E; ++SI) { // not allowed to dereference ->begin() if size() is 0 Params.push_back(GetElementPtrInst::getIndexedType(I->getType(), *SI)); assert(Params.back()); } if (ArgIndices.size() == 1 && ArgIndices.begin()->empty()) ++NumArgumentsPromoted; else ++NumAggregatesPromoted; } } // Add any function attributes. if (PAL.hasAttributes(AttributeSet::FunctionIndex)) AttributesVec.push_back(AttributeSet::get(FTy->getContext(), PAL.getFnAttributes())); Type *RetTy = FTy->getReturnType(); // Construct the new function type using the new arguments. FunctionType *NFTy = FunctionType::get(RetTy, Params, FTy->isVarArg()); // Create the new function body and insert it into the module. Function *NF = Function::Create(NFTy, F->getLinkage(), F->getName()); NF->copyAttributesFrom(F); // Patch the pointer to LLVM function in debug info descriptor. auto DI = FunctionDIs.find(F); if (DI != FunctionDIs.end()) { DISubprogram SP = DI->second; SP.replaceFunction(NF); // Ensure the map is updated so it can be reused on subsequent argument // promotions of the same function. FunctionDIs.erase(DI); FunctionDIs[NF] = SP; } DEBUG(dbgs() << "ARG PROMOTION: Promoting to:" << *NF << "\n" << "From: " << *F); // Recompute the parameter attributes list based on the new arguments for // the function. NF->setAttributes(AttributeSet::get(F->getContext(), AttributesVec)); AttributesVec.clear(); F->getParent()->getFunctionList().insert(F, NF); NF->takeName(F); // Get the alias analysis information that we need to update to reflect our // changes. AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); // Get the callgraph information that we need to update to reflect our // changes. CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); // Get a new callgraph node for NF. CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF); // Loop over all of the callers of the function, transforming the call sites // to pass in the loaded pointers. // SmallVector<Value*, 16> Args; while (!F->use_empty()) { CallSite CS(F->user_back()); assert(CS.getCalledFunction() == F); Instruction *Call = CS.getInstruction(); const AttributeSet &CallPAL = CS.getAttributes(); // Add any return attributes. if (CallPAL.hasAttributes(AttributeSet::ReturnIndex)) AttributesVec.push_back(AttributeSet::get(F->getContext(), CallPAL.getRetAttributes())); // Loop over the operands, inserting GEP and loads in the caller as // appropriate. CallSite::arg_iterator AI = CS.arg_begin(); ArgIndex = 1; for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I, ++AI, ++ArgIndex) if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) { Args.push_back(*AI); // Unmodified argument if (CallPAL.hasAttributes(ArgIndex)) { AttrBuilder B(CallPAL, ArgIndex); AttributesVec. push_back(AttributeSet::get(F->getContext(), Args.size(), B)); } } else if (ByValArgsToTransform.count(I)) { // Emit a GEP and load for each element of the struct. Type *AgTy = cast<PointerType>(I->getType())->getElementType(); StructType *STy = cast<StructType>(AgTy); Value *Idxs[2] = { ConstantInt::get(Type::getInt32Ty(F->getContext()), 0), nullptr }; for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { Idxs[1] = ConstantInt::get(Type::getInt32Ty(F->getContext()), i); Value *Idx = GetElementPtrInst::Create(*AI, Idxs, (*AI)->getName()+"."+utostr(i), Call); // TODO: Tell AA about the new values? Args.push_back(new LoadInst(Idx, Idx->getName()+".val", Call)); } } else if (!I->use_empty()) { // Non-dead argument: insert GEPs and loads as appropriate. ScalarizeTable &ArgIndices = ScalarizedElements[I]; // Store the Value* version of the indices in here, but declare it now // for reuse. std::vector<Value*> Ops; for (ScalarizeTable::iterator SI = ArgIndices.begin(), E = ArgIndices.end(); SI != E; ++SI) { Value *V = *AI; LoadInst *OrigLoad = OriginalLoads[std::make_pair(I, *SI)]; if (!SI->empty()) { Ops.reserve(SI->size()); Type *ElTy = V->getType(); for (IndicesVector::const_iterator II = SI->begin(), IE = SI->end(); II != IE; ++II) { // Use i32 to index structs, and i64 for others (pointers/arrays). // This satisfies GEP constraints. Type *IdxTy = (ElTy->isStructTy() ? Type::getInt32Ty(F->getContext()) : Type::getInt64Ty(F->getContext())); Ops.push_back(ConstantInt::get(IdxTy, *II)); // Keep track of the type we're currently indexing. ElTy = cast<CompositeType>(ElTy)->getTypeAtIndex(*II); } // And create a GEP to extract those indices. V = GetElementPtrInst::Create(V, Ops, V->getName()+".idx", Call); Ops.clear(); AA.copyValue(OrigLoad->getOperand(0), V); } // Since we're replacing a load make sure we take the alignment // of the previous load. LoadInst *newLoad = new LoadInst(V, V->getName()+".val", Call); newLoad->setAlignment(OrigLoad->getAlignment()); // Transfer the AA info too. AAMDNodes AAInfo; OrigLoad->getAAMetadata(AAInfo); newLoad->setAAMetadata(AAInfo); Args.push_back(newLoad); AA.copyValue(OrigLoad, Args.back()); } } // Push any varargs arguments on the list. for (; AI != CS.arg_end(); ++AI, ++ArgIndex) { Args.push_back(*AI); if (CallPAL.hasAttributes(ArgIndex)) { AttrBuilder B(CallPAL, ArgIndex); AttributesVec. push_back(AttributeSet::get(F->getContext(), Args.size(), B)); } } // Add any function attributes. if (CallPAL.hasAttributes(AttributeSet::FunctionIndex)) AttributesVec.push_back(AttributeSet::get(Call->getContext(), CallPAL.getFnAttributes())); Instruction *New; if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) { New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(), Args, "", Call); cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv()); cast<InvokeInst>(New)->setAttributes(AttributeSet::get(II->getContext(), AttributesVec)); } else { New = CallInst::Create(NF, Args, "", Call); cast<CallInst>(New)->setCallingConv(CS.getCallingConv()); cast<CallInst>(New)->setAttributes(AttributeSet::get(New->getContext(), AttributesVec)); if (cast<CallInst>(Call)->isTailCall()) cast<CallInst>(New)->setTailCall(); } New->setDebugLoc(Call->getDebugLoc()); Args.clear(); AttributesVec.clear(); // Update the alias analysis implementation to know that we are replacing // the old call with a new one. AA.replaceWithNewValue(Call, New); // Update the callgraph to know that the callsite has been transformed. CallGraphNode *CalleeNode = CG[Call->getParent()->getParent()]; CalleeNode->replaceCallEdge(Call, New, NF_CGN); if (!Call->use_empty()) { Call->replaceAllUsesWith(New); New->takeName(Call); } // Finally, remove the old call from the program, reducing the use-count of // F. Call->eraseFromParent(); } // Since we have now created the new function, splice the body of the old // function right into the new function, leaving the old rotting hulk of the // function empty. NF->getBasicBlockList().splice(NF->begin(), F->getBasicBlockList()); // Loop over the argument list, transferring uses of the old arguments over to // the new arguments, also transferring over the names as well. // for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(), I2 = NF->arg_begin(); I != E; ++I) { if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) { // If this is an unmodified argument, move the name and users over to the // new version. I->replaceAllUsesWith(I2); I2->takeName(I); AA.replaceWithNewValue(I, I2); ++I2; continue; } if (ByValArgsToTransform.count(I)) { // In the callee, we create an alloca, and store each of the new incoming // arguments into the alloca. Instruction *InsertPt = NF->begin()->begin(); // Just add all the struct element types. Type *AgTy = cast<PointerType>(I->getType())->getElementType(); Value *TheAlloca = new AllocaInst(AgTy, nullptr, "", InsertPt); StructType *STy = cast<StructType>(AgTy); Value *Idxs[2] = { ConstantInt::get(Type::getInt32Ty(F->getContext()), 0), nullptr }; for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { Idxs[1] = ConstantInt::get(Type::getInt32Ty(F->getContext()), i); Value *Idx = GetElementPtrInst::Create(TheAlloca, Idxs, TheAlloca->getName()+"."+Twine(i), InsertPt); I2->setName(I->getName()+"."+Twine(i)); new StoreInst(I2++, Idx, InsertPt); } // Anything that used the arg should now use the alloca. I->replaceAllUsesWith(TheAlloca); TheAlloca->takeName(I); AA.replaceWithNewValue(I, TheAlloca); // If the alloca is used in a call, we must clear the tail flag since // the callee now uses an alloca from the caller. for (User *U : TheAlloca->users()) { CallInst *Call = dyn_cast<CallInst>(U); if (!Call) continue; Call->setTailCall(false); } continue; } if (I->use_empty()) { AA.deleteValue(I); continue; } // Otherwise, if we promoted this argument, then all users are load // instructions (or GEPs with only load users), and all loads should be // using the new argument that we added. ScalarizeTable &ArgIndices = ScalarizedElements[I]; while (!I->use_empty()) { if (LoadInst *LI = dyn_cast<LoadInst>(I->user_back())) { assert(ArgIndices.begin()->empty() && "Load element should sort to front!"); I2->setName(I->getName()+".val"); LI->replaceAllUsesWith(I2); AA.replaceWithNewValue(LI, I2); LI->eraseFromParent(); DEBUG(dbgs() << "*** Promoted load of argument '" << I->getName() << "' in function '" << F->getName() << "'\n"); } else { GetElementPtrInst *GEP = cast<GetElementPtrInst>(I->user_back()); IndicesVector Operands; Operands.reserve(GEP->getNumIndices()); for (User::op_iterator II = GEP->idx_begin(), IE = GEP->idx_end(); II != IE; ++II) Operands.push_back(cast<ConstantInt>(*II)->getSExtValue()); // GEPs with a single 0 index can be merged with direct loads if (Operands.size() == 1 && Operands.front() == 0) Operands.clear(); Function::arg_iterator TheArg = I2; for (ScalarizeTable::iterator It = ArgIndices.begin(); *It != Operands; ++It, ++TheArg) { assert(It != ArgIndices.end() && "GEP not handled??"); } std::string NewName = I->getName(); for (unsigned i = 0, e = Operands.size(); i != e; ++i) { NewName += "." + utostr(Operands[i]); } NewName += ".val"; TheArg->setName(NewName); DEBUG(dbgs() << "*** Promoted agg argument '" << TheArg->getName() << "' of function '" << NF->getName() << "'\n"); // All of the uses must be load instructions. Replace them all with // the argument specified by ArgNo. while (!GEP->use_empty()) { LoadInst *L = cast<LoadInst>(GEP->user_back()); L->replaceAllUsesWith(TheArg); AA.replaceWithNewValue(L, TheArg); L->eraseFromParent(); } AA.deleteValue(GEP); GEP->eraseFromParent(); } } // Increment I2 past all of the arguments added for this promoted pointer. std::advance(I2, ArgIndices.size()); } // Tell the alias analysis that the old function is about to disappear. AA.replaceWithNewValue(F, NF); NF_CGN->stealCalledFunctionsFrom(CG[F]); // Now that the old function is dead, delete it. If there is a dangling // reference to the CallgraphNode, just leave the dead function around for // someone else to nuke. CallGraphNode *CGN = CG[F]; if (CGN->getNumReferences() == 0) delete CG.removeFunctionFromModule(CGN); else F->setLinkage(Function::ExternalLinkage); return NF_CGN; }
static StringRef getFunctionName(DISubprogram SP) { if (!SP.getLinkageName().empty()) return SP.getLinkageName(); return SP.getName(); }
void jl_getDylibFunctionInfo(const char **name, size_t *line, const char **filename, size_t pointer, int *fromC, int skipC) { #ifdef _OS_WINDOWS_ DWORD fbase = SymGetModuleBase64(GetCurrentProcess(),(DWORD)pointer); char *fname = 0; if (fbase != 0) { #else Dl_info dlinfo; const char *fname = 0; if ((dladdr((void*)pointer, &dlinfo) != 0) && dlinfo.dli_fname) { *fromC = !jl_is_sysimg(dlinfo.dli_fname); if (skipC && *fromC) return; // In case we fail with the debug info lookup, we at least still // have the function name, even if we don't have line numbers *name = dlinfo.dli_sname; *filename = dlinfo.dli_fname; uint64_t fbase = (uint64_t)dlinfo.dli_fbase; #endif obfiletype::iterator it = objfilemap.find(fbase); llvm::object::ObjectFile *obj = NULL; DIContext *context = NULL; int64_t slide = 0; #ifndef _OS_WINDOWS_ fname = dlinfo.dli_fname; #else IMAGEHLP_MODULE64 ModuleInfo; ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)pointer, &ModuleInfo); fname = ModuleInfo.LoadedImageName; *fromC = !jl_is_sysimg(fname); if (skipC && *fromC) return; #endif if (it == objfilemap.end()) { #ifdef _OS_DARWIN_ // First find the uuid of the object file (we'll use this to make sure we find the // correct debug symbol file). uint8_t uuid[16], uuid2[16]; #ifdef LLVM36 std::unique_ptr<MemoryBuffer> membuf = MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false); auto origerrorobj = llvm::object::ObjectFile::createObjectFile( membuf->getMemBufferRef(), sys::fs::file_magic::unknown); #elif LLVM35 MemoryBuffer *membuf = MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false); std::unique_ptr<MemoryBuffer> buf(membuf); auto origerrorobj = llvm::object::ObjectFile::createObjectFile( buf, sys::fs::file_magic::unknown); #else MemoryBuffer *membuf = MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false); llvm::object::ObjectFile *origerrorobj = llvm::object::ObjectFile::createObjectFile( membuf); #endif if (!origerrorobj) { objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; goto lookup; } #ifdef LLVM36 llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj.get().release(); #elif LLVM35 llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj.get(); #else llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj; #endif if (!getObjUUID(morigobj,uuid)) { objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; goto lookup; } // On OS X debug symbols are not contained in the dynamic library and that's why // we can't have nice things (easily). For now we only support .dSYM files in the same directory // as the shared library. In the future we may use DBGCopyFullDSYMURLForUUID from CoreFoundation to make // use of spotlight to find the .dSYM file. char dsympath[PATH_MAX]; strlcpy(dsympath, dlinfo.dli_fname, sizeof(dsympath)); strlcat(dsympath, ".dSYM/Contents/Resources/DWARF/", sizeof(dsympath)); strlcat(dsympath, strrchr(dlinfo.dli_fname,'/')+1, sizeof(dsympath)); #ifdef LLVM35 auto errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); #else llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); #endif #else // On non OS X systems we need to mmap another copy because of the permissions on the mmaped // shared library. #ifdef LLVM35 auto errorobj = llvm::object::ObjectFile::createObjectFile(fname); #else llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(fname); #endif #endif #ifdef LLVM36 if (errorobj) { obj = errorobj.get().getBinary().release(); errorobj.get().getBuffer().release(); #elif LLVM35 if (errorobj) { obj = errorobj.get(); #else if (errorobj != NULL) { obj = errorobj; #endif #ifdef _OS_DARWIN_ if (getObjUUID(morigobj,uuid2) && memcmp(uuid,uuid2,sizeof(uuid)) == 0) { #endif #ifdef LLVM36 context = DIContext::getDWARFContext(*obj); #else context = DIContext::getDWARFContext(obj); #endif slide = -(uint64_t)fbase; #ifdef _OS_DARWIN_ } #endif #ifdef _OS_WINDOWS_ assert(obj->isCOFF()); llvm::object::COFFObjectFile *coffobj = (llvm::object::COFFObjectFile *)obj; const llvm::object::pe32plus_header *pe32plus; coffobj->getPE32PlusHeader(pe32plus); if (pe32plus != NULL) { slide = pe32plus->ImageBase-fbase; } else { const llvm::object::pe32_header *pe32; coffobj->getPE32Header(pe32); if (pe32 == NULL) { obj = NULL; context = NULL; } else { slide = pe32->ImageBase-fbase; } } #endif } objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; } else { obj = it->second.obj; context = it->second.ctx; slide = it->second.slide; } #ifdef _OS_DARWIN_ lookup: #endif lookup_pointer(context, name, line, filename, pointer+slide, jl_is_sysimg(fname), fromC); return; } *fromC = 1; return; } #endif void jl_getFunctionInfo(const char **name, size_t *line, const char **filename, size_t pointer, int *fromC, int skipC) { *name = NULL; *line = -1; *filename = "no file"; *fromC = 0; #if USE_MCJIT // With MCJIT we can get function information directly from the ObjectFile std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events->getObjectMap(); std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(pointer); if (it == objmap.end()) return jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC); if ((pointer - it->first) > it->second.size) return jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC); #ifdef LLVM36 DIContext *context = DIContext::getDWARFContext(*it->second.object); #else DIContext *context = DIContext::getDWARFContext(it->second.object); #endif lookup_pointer(context, name, line, filename, pointer, 1, fromC); #else // !USE_MCJIT // Without MCJIT we use the FuncInfo structure containing address maps std::map<size_t, FuncInfo, revcomp> &info = jl_jit_events->getMap(); std::map<size_t, FuncInfo, revcomp>::iterator it = info.lower_bound(pointer); if (it != info.end() && (size_t)(*it).first + (*it).second.lengthAdr >= pointer) { // We do this to hide the jlcall wrappers when getting julia backtraces, // but it is still good to have them for regular lookup of C frames. if (skipC && (*it).second.lines.empty()) { // Technically not true, but we don't want them // in julia backtraces, so close enough *fromC = 1; return; } *name = (*it).second.name.c_str(); *filename = (*it).second.filename.c_str(); if ((*it).second.lines.empty()) { *fromC = 1; return; } std::vector<JITEvent_EmittedFunctionDetails::LineStart>::iterator vit = (*it).second.lines.begin(); JITEvent_EmittedFunctionDetails::LineStart prev = *vit; if ((*it).second.func) { DISubprogram debugscope = DISubprogram(prev.Loc.getScope((*it).second.func->getContext())); *filename = debugscope.getFilename().data(); // the DISubprogram has the un-mangled name, so use that if // available. However, if the scope need not be the current // subprogram. if (debugscope.getName().data() != NULL) *name = debugscope.getName().data(); else *name = jl_demangle(*name); } vit++; while (vit != (*it).second.lines.end()) { if (pointer <= (*vit).Address) { *line = prev.Loc.getLine(); break; } prev = *vit; vit++; } if (*line == (size_t) -1) { *line = prev.Loc.getLine(); } } else { jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC); } #endif // USE_MCJIT }
/// processSubprogram - Process DISubprogram. void DebugInfoFinder::processSubprogram(DISubprogram SP) { if (!addSubprogram(SP)) return; processType(SP.getType()); }
/// DeleteDeadVarargs - If this is an function that takes a ... list, and if /// llvm.vastart is never called, the varargs list is dead for the function. bool DAE::DeleteDeadVarargs(Function &Fn) { assert(Fn.getFunctionType()->isVarArg() && "Function isn't varargs!"); if (Fn.isDeclaration() || !Fn.hasLocalLinkage()) return false; // Ensure that the function is only directly called. if (Fn.hasAddressTaken()) return false; // Okay, we know we can transform this function if safe. Scan its body // looking for calls marked musttail or calls to llvm.vastart. for (Function::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) { for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { CallInst *CI = dyn_cast<CallInst>(I); if (!CI) continue; if (CI->isMustTailCall()) return false; if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI)) { if (II->getIntrinsicID() == Intrinsic::vastart) return false; } } } // If we get here, there are no calls to llvm.vastart in the function body, // remove the "..." and adjust all the calls. // Start by computing a new prototype for the function, which is the same as // the old function, but doesn't have isVarArg set. FunctionType *FTy = Fn.getFunctionType(); std::vector<Type*> Params(FTy->param_begin(), FTy->param_end()); FunctionType *NFTy = FunctionType::get(FTy->getReturnType(), Params, false); unsigned NumArgs = Params.size(); // Create the new function body and insert it into the module... Function *NF = Function::Create(NFTy, Fn.getLinkage()); NF->copyAttributesFrom(&Fn); Fn.getParent()->getFunctionList().insert(&Fn, NF); NF->takeName(&Fn); // Loop over all of the callers of the function, transforming the call sites // to pass in a smaller number of arguments into the new function. // std::vector<Value*> Args; for (Value::user_iterator I = Fn.user_begin(), E = Fn.user_end(); I != E; ) { CallSite CS(*I++); if (!CS) continue; Instruction *Call = CS.getInstruction(); // Pass all the same arguments. Args.assign(CS.arg_begin(), CS.arg_begin() + NumArgs); // Drop any attributes that were on the vararg arguments. AttributeSet PAL = CS.getAttributes(); if (!PAL.isEmpty() && PAL.getSlotIndex(PAL.getNumSlots() - 1) > NumArgs) { SmallVector<AttributeSet, 8> AttributesVec; for (unsigned i = 0; PAL.getSlotIndex(i) <= NumArgs; ++i) AttributesVec.push_back(PAL.getSlotAttributes(i)); if (PAL.hasAttributes(AttributeSet::FunctionIndex)) AttributesVec.push_back(AttributeSet::get(Fn.getContext(), PAL.getFnAttributes())); PAL = AttributeSet::get(Fn.getContext(), AttributesVec); } Instruction *New; if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) { New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(), Args, "", Call); cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv()); cast<InvokeInst>(New)->setAttributes(PAL); } else { New = CallInst::Create(NF, Args, "", Call); cast<CallInst>(New)->setCallingConv(CS.getCallingConv()); cast<CallInst>(New)->setAttributes(PAL); if (cast<CallInst>(Call)->isTailCall()) cast<CallInst>(New)->setTailCall(); } New->setDebugLoc(Call->getDebugLoc()); Args.clear(); if (!Call->use_empty()) Call->replaceAllUsesWith(New); New->takeName(Call); // Finally, remove the old call from the program, reducing the use-count of // F. Call->eraseFromParent(); } // Since we have now created the new function, splice the body of the old // function right into the new function, leaving the old rotting hulk of the // function empty. NF->getBasicBlockList().splice(NF->begin(), Fn.getBasicBlockList()); // Loop over the argument list, transferring uses of the old arguments over to // the new arguments, also transferring over the names as well. While we're at // it, remove the dead arguments from the DeadArguments list. // for (Function::arg_iterator I = Fn.arg_begin(), E = Fn.arg_end(), I2 = NF->arg_begin(); I != E; ++I, ++I2) { // Move the name and users over to the new version. I->replaceAllUsesWith(I2); I2->takeName(I); } // Patch the pointer to LLVM function in debug info descriptor. auto DI = FunctionDIs.find(&Fn); if (DI != FunctionDIs.end()) { DISubprogram SP = DI->second; SP.replaceFunction(NF); // Ensure the map is updated so it can be reused on non-varargs argument // eliminations of the same function. FunctionDIs.erase(DI); FunctionDIs[NF] = SP; } // Fix up any BlockAddresses that refer to the function. Fn.replaceAllUsesWith(ConstantExpr::getBitCast(NF, Fn.getType())); // Delete the bitcast that we just created, so that NF does not // appear to be address-taken. NF->removeDeadConstantUsers(); // Finally, nuke the old function. Fn.eraseFromParent(); return true; }