static std::unique_ptr<Module> getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, StringSet<> &Internalize, StringSet<> &Maybe) { ld_plugin_input_file File; if (get_input_file(F.handle, &File) != LDPS_OK) message(LDPL_FATAL, "Failed to get file information"); if (get_symbols(F.handle, F.syms.size(), &F.syms[0]) != LDPS_OK) message(LDPL_FATAL, "Failed to get symbol information"); const void *View; if (get_view(F.handle, &View) != LDPS_OK) message(LDPL_FATAL, "Failed to get a view of file"); llvm::ErrorOr<MemoryBufferRef> MBOrErr = object::IRObjectFile::findBitcodeInMemBuffer( MemoryBufferRef(StringRef((const char *)View, File.filesize), "")); if (std::error_code EC = MBOrErr.getError()) message(LDPL_FATAL, "Could not read bitcode from file : %s", EC.message().c_str()); std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(MBOrErr->getBuffer(), "", false); if (release_input_file(F.handle) != LDPS_OK) message(LDPL_FATAL, "Failed to release file information"); ErrorOr<Module *> MOrErr = getLazyBitcodeModule(std::move(Buffer), Context); if (std::error_code EC = MOrErr.getError()) message(LDPL_FATAL, "Could not read bitcode from file : %s", EC.message().c_str()); std::unique_ptr<Module> M(MOrErr.get()); SmallPtrSet<GlobalValue *, 8> Used; collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false); DenseSet<GlobalValue *> Drop; std::vector<GlobalAlias *> KeptAliases; for (ld_plugin_symbol &Sym : F.syms) { ld_plugin_symbol_resolution Resolution = (ld_plugin_symbol_resolution)Sym.resolution; if (options::generate_api_file) *ApiFile << Sym.name << ' ' << getResolutionName(Resolution) << '\n'; GlobalValue *GV = M->getNamedValue(Sym.name); if (!GV) continue; // Asm symbol. if (Resolution != LDPR_PREVAILING_DEF_IRONLY && GV->hasCommonLinkage()) { // Common linkage is special. There is no single symbol that wins the // resolution. Instead we have to collect the maximum alignment and size. // The IR linker does that for us if we just pass it every common GV. // We still have to keep track of LDPR_PREVAILING_DEF_IRONLY so we // internalize once the IR linker has done its job. continue; } switch (Resolution) { case LDPR_UNKNOWN: llvm_unreachable("Unexpected resolution"); case LDPR_RESOLVED_IR: case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: case LDPR_UNDEF: assert(GV->isDeclarationForLinker()); break; case LDPR_PREVAILING_DEF_IRONLY: { keepGlobalValue(*GV, KeptAliases); if (!Used.count(GV)) { // Since we use the regular lib/Linker, we cannot just internalize GV // now or it will not be copied to the merged module. Instead we force // it to be copied and then internalize it. Internalize.insert(Sym.name); } break; } case LDPR_PREVAILING_DEF: keepGlobalValue(*GV, KeptAliases); break; case LDPR_PREEMPTED_IR: // Gold might have selected a linkonce_odr and preempted a weak_odr. // In that case we have to make sure we don't end up internalizing it. if (!GV->isDiscardableIfUnused()) Maybe.erase(Sym.name); // fall-through case LDPR_PREEMPTED_REG: Drop.insert(GV); break; case LDPR_PREVAILING_DEF_IRONLY_EXP: { // We can only check for address uses after we merge the modules. The // reason is that this GV might have a copy in another module // and in that module the address might be significant, but that // copy will be LDPR_PREEMPTED_IR. if (GV->hasLinkOnceODRLinkage()) Maybe.insert(Sym.name); keepGlobalValue(*GV, KeptAliases); break; } } free(Sym.name); free(Sym.comdat_key); Sym.name = nullptr; Sym.comdat_key = nullptr; } ValueToValueMapTy VM; LocalValueMaterializer Materializer(Drop); for (GlobalAlias *GA : KeptAliases) { // Gold told us to keep GA. It is possible that a GV usied in the aliasee // expression is being dropped. If that is the case, that GV must be copied. Constant *Aliasee = GA->getAliasee(); Constant *Replacement = mapConstantToLocalCopy(Aliasee, VM, &Materializer); if (Aliasee != Replacement) GA->setAliasee(Replacement); } for (auto *GV : Drop) drop(*GV); return M; }
LTOModule *LTOModule::makeLTOModule(MemoryBufferRef Buffer, TargetOptions options, std::string &errMsg, LLVMContext *Context) { std::unique_ptr<LLVMContext> OwnedContext; if (!Context) { OwnedContext = llvm::make_unique<LLVMContext>(); Context = OwnedContext.get(); } ErrorOr<MemoryBufferRef> MBOrErr = IRObjectFile::findBitcodeInMemBuffer(Buffer); if (std::error_code EC = MBOrErr.getError()) { errMsg = EC.message(); return nullptr; } ErrorOr<Module *> MOrErr = parseBitcodeFile(*MBOrErr, *Context); if (std::error_code EC = MOrErr.getError()) { errMsg = EC.message(); return nullptr; } std::unique_ptr<Module> M(MOrErr.get()); std::string TripleStr = M->getTargetTriple(); if (TripleStr.empty()) TripleStr = sys::getDefaultTargetTriple(); llvm::Triple Triple(TripleStr); // find machine architecture for this module const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); if (!march) return nullptr; // construct LTOModule, hand over ownership of module and target SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(Triple); std::string FeatureStr = Features.getString(); // Set a default CPU for Darwin triples. std::string CPU; if (Triple.isOSDarwin()) { if (Triple.getArch() == llvm::Triple::x86_64) CPU = "core2"; else if (Triple.getArch() == llvm::Triple::x86) CPU = "yonah"; else if (Triple.getArch() == llvm::Triple::aarch64) CPU = "cyclone"; } TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr, options); M->setDataLayout(target->getSubtargetImpl()->getDataLayout()); std::unique_ptr<object::IRObjectFile> IRObj( new object::IRObjectFile(Buffer, std::move(M))); LTOModule *Ret; if (OwnedContext) Ret = new LTOModule(std::move(IRObj), target, std::move(OwnedContext)); else Ret = new LTOModule(std::move(IRObj), target); if (Ret->parseSymbols(errMsg)) { delete Ret; return nullptr; } Ret->parseMetadata(); return Ret; }
/// Called by gold to see whether this file is one that our plugin can handle. /// We'll try to open it and register all the symbols with add_symbol if /// possible. static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { LLVMContext Context; MemoryBufferRef BufferRef; std::unique_ptr<MemoryBuffer> Buffer; if (get_view) { const void *view; if (get_view(file->handle, &view) != LDPS_OK) { message(LDPL_ERROR, "Failed to get a view of %s", file->name); return LDPS_ERR; } BufferRef = MemoryBufferRef(StringRef((const char *)view, file->filesize), ""); } else { int64_t offset = 0; // Gold has found what might be IR part-way inside of a file, such as // an .a archive. if (file->offset) { offset = file->offset; } ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getOpenFileSlice(file->fd, file->name, file->filesize, offset); if (std::error_code EC = BufferOrErr.getError()) { message(LDPL_ERROR, EC.message().c_str()); return LDPS_ERR; } Buffer = std::move(BufferOrErr.get()); BufferRef = Buffer->getMemBufferRef(); } ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr = object::IRObjectFile::createIRObjectFile(BufferRef, Context); std::error_code EC = ObjOrErr.getError(); if (EC == BitcodeError::InvalidBitcodeSignature || EC == object::object_error::invalid_file_type || EC == object::object_error::bitcode_section_not_found) return LDPS_OK; *claimed = 1; if (EC) { message(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module: %s", EC.message().c_str()); return LDPS_ERR; } std::unique_ptr<object::IRObjectFile> Obj = std::move(*ObjOrErr); Modules.resize(Modules.size() + 1); claimed_file &cf = Modules.back(); cf.handle = file->handle; for (auto &Sym : Obj->symbols()) { uint32_t Symflags = Sym.getFlags(); if (!(Symflags & object::BasicSymbolRef::SF_Global)) continue; if (Symflags & object::BasicSymbolRef::SF_FormatSpecific) continue; cf.syms.push_back(ld_plugin_symbol()); ld_plugin_symbol &sym = cf.syms.back(); sym.version = nullptr; SmallString<64> Name; { raw_svector_ostream OS(Name); Sym.printName(OS); } sym.name = strdup(Name.c_str()); const GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); sym.visibility = LDPV_DEFAULT; if (GV) { switch (GV->getVisibility()) { case GlobalValue::DefaultVisibility: sym.visibility = LDPV_DEFAULT; break; case GlobalValue::HiddenVisibility: sym.visibility = LDPV_HIDDEN; break; case GlobalValue::ProtectedVisibility: sym.visibility = LDPV_PROTECTED; break; } } if (Symflags & object::BasicSymbolRef::SF_Undefined) { sym.def = LDPK_UNDEF; if (GV && GV->hasExternalWeakLinkage()) sym.def = LDPK_WEAKUNDEF; } else { sym.def = LDPK_DEF; if (GV) { assert(!GV->hasExternalWeakLinkage() && !GV->hasAvailableExternallyLinkage() && "Not a declaration!"); if (GV->hasCommonLinkage()) sym.def = LDPK_COMMON; else if (GV->isWeakForLinker()) sym.def = LDPK_WEAKDEF; } } sym.size = 0; sym.comdat_key = nullptr; if (GV) { const GlobalObject *Base = getBaseObject(*GV); if (!Base) message(LDPL_FATAL, "Unable to determine comdat of alias!"); const Comdat *C = Base->getComdat(); if (C) sym.comdat_key = strdup(C->getName().str().c_str()); else if (Base->hasWeakLinkage() || Base->hasLinkOnceLinkage()) sym.comdat_key = strdup(sym.name); } sym.resolution = LDPR_UNKNOWN; } if (!cf.syms.empty()) { if (add_symbols(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) { message(LDPL_ERROR, "Unable to add symbols!"); return LDPS_ERR; } } return LDPS_OK; }
/// ReadCheckFile - Read the check file, which specifies the sequence of /// expected strings. The strings are added to the CheckStrings vector. /// Returns true in case of an error, false otherwise. static bool ReadCheckFile(SourceMgr &SM, std::vector<CheckString> &CheckStrings) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFileOrSTDIN(CheckFilename); if (std::error_code EC = FileOrErr.getError()) { errs() << "Could not open check file '" << CheckFilename << "': " << EC.message() << '\n'; return true; } // If we want to canonicalize whitespace, strip excess whitespace from the // buffer containing the CHECK lines. Remove DOS style line endings. MemoryBuffer *F = CanonicalizeInputFile(FileOrErr.get().release(), NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); // Find all instances of CheckPrefix followed by : in the file. StringRef Buffer = F->getBuffer(); std::vector<Pattern> DagNotMatches; // LineNumber keeps track of the line on which CheckPrefix instances are // found. unsigned LineNumber = 1; while (1) { Check::CheckType CheckTy; size_t PrefixLoc; // See if a prefix occurs in the memory buffer. StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer, LineNumber, CheckTy, PrefixLoc); if (UsedPrefix.empty()) break; Buffer = Buffer.drop_front(PrefixLoc); // Location to use for error messages. const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); // PrefixLoc is to the start of the prefix. Skip to the end. Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy)); // Okay, we found the prefix, yay. Remember the rest of the line, but ignore // leading and trailing whitespace. Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); // Scan ahead to the end of line. size_t EOL = Buffer.find_first_of("\n\r"); // Remember the location of the start of the pattern, for diagnostics. SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. Pattern P(CheckTy); if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) return true; // Verify that CHECK-LABEL lines do not define or use variables if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, "found '" + UsedPrefix + "-LABEL:'" " with variable definition or use"); return true; } Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) { SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, "found '" + UsedPrefix + "-NEXT:' without previous '" + UsedPrefix + ": line"); return true; } // Handle CHECK-DAG/-NOT. if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { DagNotMatches.push_back(P); continue; } // Okay, add the string we captured to the output vector and move on. CheckStrings.push_back(CheckString(P, UsedPrefix, PatternLoc, CheckTy)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first // prefix as a filler for the error message. if (!DagNotMatches.empty()) { CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF), CheckPrefixes[0], SMLoc::getFromPointer(Buffer.data()), Check::CheckEOF)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } if (CheckStrings.empty()) { errs() << "error: no check strings found with prefix" << (CheckPrefixes.size() > 1 ? "es " : " "); for (size_t I = 0, N = CheckPrefixes.size(); I != N; ++I) { StringRef Prefix(CheckPrefixes[I]); errs() << '\'' << Prefix << ":'"; if (I != N - 1) errs() << ", "; } errs() << '\n'; return true; } return false; }
int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); if (!ValidateCheckPrefixes()) { errs() << "Supplied check-prefix is invalid! Prefixes must be unique and " "start with a letter and contain only alphanumeric characters, " "hyphens and underscores\n"; return 2; } AddCheckPrefixIfNeeded(); SourceMgr SM; // Read the expected strings from the check file. std::vector<CheckString> CheckStrings; if (ReadCheckFile(SM, CheckStrings)) return 2; // Open the file to check and add it to SourceMgr. ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFileOrSTDIN(InputFilename); if (std::error_code EC = FileOrErr.getError()) { errs() << "Could not open input file '" << InputFilename << "': " << EC.message() << '\n'; return 2; } std::unique_ptr<MemoryBuffer> File = std::move(FileOrErr.get()); if (File->getBufferSize() == 0) { errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; return 2; } // Remove duplicate spaces in the input file if requested. // Remove DOS style line endings. MemoryBuffer *F = CanonicalizeInputFile(File.release(), NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); /// VariableTable - This holds all the current filecheck variables. StringMap<StringRef> VariableTable; // Check that we have all of the expected strings, in order, in the input // file. StringRef Buffer = F->getBuffer(); bool hasError = false; unsigned i = 0, j = 0, e = CheckStrings.size(); while (true) { StringRef CheckRegion; if (j == e) { CheckRegion = Buffer; } else { const CheckString &CheckLabelStr = CheckStrings[j]; if (CheckLabelStr.CheckTy != Check::CheckLabel) { ++j; continue; } // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG size_t MatchLabelLen = 0; size_t MatchLabelPos = CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, VariableTable); if (MatchLabelPos == StringRef::npos) { hasError = true; break; } CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen); Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen); ++j; } for ( ; i != j; ++i) { const CheckString &CheckStr = CheckStrings[i]; // Check each string within the scanned region, including a second check // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) size_t MatchLen = 0; size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen, VariableTable); if (MatchPos == StringRef::npos) { hasError = true; i = j; break; } CheckRegion = CheckRegion.substr(MatchPos + MatchLen); } if (j == e) break; } return hasError ? 1 : 0; }
static void DumpSymbolNamesFromFile(std::string &Filename) { if (Filename != "-" && !sys::fs::exists(Filename)) { errs() << ToolName << ": '" << Filename << "': " << "No such file\n"; return; } OwningPtr<MemoryBuffer> Buffer; if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename)) return; sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer()); LLVMContext &Context = getGlobalContext(); if (magic == sys::fs::file_magic::bitcode) { ErrorOr<Module *> ModuleOrErr = parseBitcodeFile(Buffer.get(), Context); if (error(ModuleOrErr.getError(), Filename)) { return; } else { Module *Result = ModuleOrErr.get(); DumpSymbolNamesFromModule(Result); delete Result; } } else if (magic == sys::fs::file_magic::archive) { ErrorOr<Binary *> BinaryOrErr = object::createBinary(Buffer.take(), magic); if (error(BinaryOrErr.getError(), Filename)) return; OwningPtr<Binary> arch(BinaryOrErr.get()); if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { if (ArchiveMap) { object::Archive::symbol_iterator I = a->symbol_begin(); object::Archive::symbol_iterator E = a->symbol_end(); if (I !=E) { outs() << "Archive map" << "\n"; for (; I != E; ++I) { object::Archive::child_iterator c; StringRef symname; StringRef filename; if (error(I->getMember(c))) return; if (error(I->getName(symname))) return; if (error(c->getName(filename))) return; outs() << symname << " in " << filename << "\n"; } outs() << "\n"; } } for (object::Archive::child_iterator i = a->child_begin(), e = a->child_end(); i != e; ++i) { OwningPtr<Binary> child; if (i->getAsBinary(child)) { // Try opening it as a bitcode file. OwningPtr<MemoryBuffer> buff; if (error(i->getMemoryBuffer(buff))) return; ErrorOr<Module *> ModuleOrErr = parseBitcodeFile(buff.get(), Context); if (ModuleOrErr) { Module *Result = ModuleOrErr.get(); DumpSymbolNamesFromModule(Result); delete Result; } continue; } if (object::ObjectFile *o = dyn_cast<ObjectFile>(child.get())) { outs() << o->getFileName() << ":\n"; DumpSymbolNamesFromObject(o); } } } } else if (magic == sys::fs::file_magic::macho_universal_binary) { ErrorOr<Binary *> BinaryOrErr = object::createBinary(Buffer.take(), magic); if (error(BinaryOrErr.getError(), Filename)) return; OwningPtr<Binary> Bin(BinaryOrErr.get()); object::MachOUniversalBinary *UB = cast<object::MachOUniversalBinary>(Bin.get()); for (object::MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { OwningPtr<ObjectFile> Obj; if (!I->getAsObjectFile(Obj)) { outs() << Obj->getFileName() << ":\n"; DumpSymbolNamesFromObject(Obj.get()); } } } else if (magic.is_object()) { ErrorOr<Binary *> BinaryOrErr = object::createBinary(Buffer.take(), magic); if (error(BinaryOrErr.getError(), Filename)) return; OwningPtr<Binary> obj(BinaryOrErr.get()); if (object::ObjectFile *o = dyn_cast<ObjectFile>(obj.get())) DumpSymbolNamesFromObject(o); } else { errs() << ToolName << ": " << Filename << ": " << "unrecognizable file type\n"; HadError = true; return; } }
/// Called by gold to see whether this file is one that our plugin can handle. /// We'll try to open it and register all the symbols with add_symbol if /// possible. static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { const void *view; std::unique_ptr<MemoryBuffer> buffer; if (get_view) { if (get_view(file->handle, &view) != LDPS_OK) { message(LDPL_ERROR, "Failed to get a view of %s", file->name); return LDPS_ERR; } } else { int64_t offset = 0; // Gold has found what might be IR part-way inside of a file, such as // an .a archive. if (file->offset) { offset = file->offset; } ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getOpenFileSlice(file->fd, file->name, file->filesize, offset); if (std::error_code EC = BufferOrErr.getError()) { message(LDPL_ERROR, EC.message().c_str()); return LDPS_ERR; } buffer = std::move(BufferOrErr.get()); view = buffer->getBufferStart(); } if (!LTOModule::isBitcodeFile(view, file->filesize)) return LDPS_OK; *claimed = 1; std::string Error; LTOModule *M = LTOModule::createFromBuffer(view, file->filesize, TargetOpts, Error); if (!M) { message(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module: %s", Error.c_str()); return LDPS_ERR; } Modules.resize(Modules.size() + 1); claimed_file &cf = Modules.back(); if (!options::triple.empty()) M->setTargetTriple(options::triple.c_str()); cf.handle = file->handle; unsigned sym_count = M->getSymbolCount(); cf.syms.reserve(sym_count); for (unsigned i = 0; i != sym_count; ++i) { lto_symbol_attributes attrs = M->getSymbolAttributes(i); if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) continue; cf.syms.push_back(ld_plugin_symbol()); ld_plugin_symbol &sym = cf.syms.back(); sym.name = strdup(M->getSymbolName(i)); sym.version = nullptr; int scope = attrs & LTO_SYMBOL_SCOPE_MASK; bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; if (!CanBeHidden) CannotBeHidden.insert(sym.name); switch (scope) { case LTO_SYMBOL_SCOPE_HIDDEN: sym.visibility = LDPV_HIDDEN; break; case LTO_SYMBOL_SCOPE_PROTECTED: sym.visibility = LDPV_PROTECTED; break; case 0: // extern case LTO_SYMBOL_SCOPE_DEFAULT: case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: sym.visibility = LDPV_DEFAULT; break; default: message(LDPL_ERROR, "Unknown scope attribute: %d", scope); return LDPS_ERR; } int definition = attrs & LTO_SYMBOL_DEFINITION_MASK; sym.comdat_key = nullptr; switch (definition) { case LTO_SYMBOL_DEFINITION_REGULAR: sym.def = LDPK_DEF; break; case LTO_SYMBOL_DEFINITION_UNDEFINED: sym.def = LDPK_UNDEF; break; case LTO_SYMBOL_DEFINITION_TENTATIVE: sym.def = LDPK_COMMON; break; case LTO_SYMBOL_DEFINITION_WEAK: sym.comdat_key = sym.name; sym.def = LDPK_WEAKDEF; break; case LTO_SYMBOL_DEFINITION_WEAKUNDEF: sym.def = LDPK_WEAKUNDEF; break; default: message(LDPL_ERROR, "Unknown definition attribute: %d", definition); return LDPS_ERR; } sym.size = 0; sym.resolution = LDPR_UNKNOWN; } cf.syms.reserve(cf.syms.size()); if (!cf.syms.empty()) { if (add_symbols(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) { message(LDPL_ERROR, "Unable to add symbols!"); return LDPS_ERR; } } if (CodeGen) { std::string Error; if (!CodeGen->addModule(M, Error)) { message(LDPL_ERROR, "Error linking module: %s", Error.c_str()); return LDPS_ERR; } } delete M; return LDPS_OK; }
int main(int argc, char **argv) { InitLLVM X(argc, argv); // Initialize targets and assembly parsers. llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); // Enable printing of available targets when flag --version is specified. cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions}); // Parse flags and initialize target options. cl::ParseCommandLineOptions(argc, argv, "llvm machine code performance analyzer.\n"); MCTargetOptions MCOptions; MCOptions.PreserveAsmComments = false; // Get the target from the triple. If a triple is not specified, then select // the default triple for the host. If the triple doesn't correspond to any // registered target, then exit with an error message. const char *ProgName = argv[0]; const Target *TheTarget = getTarget(ProgName); if (!TheTarget) return 1; // GetTarget() may replaced TripleName with a default triple. // For safety, reconstruct the Triple object. Triple TheTriple(TripleName); ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = MemoryBuffer::getFileOrSTDIN(InputFilename); if (std::error_code EC = BufferPtr.getError()) { WithColor::error() << InputFilename << ": " << EC.message() << '\n'; return 1; } // Apply overrides to llvm-mca specific options. processViewOptions(); SourceMgr SrcMgr; // Tell SrcMgr about this buffer, which is what the parser will pick up. SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc()); std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); assert(MAI && "Unable to create target asm info!"); MCObjectFileInfo MOFI; MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx); std::unique_ptr<buffer_ostream> BOS; mca::CodeRegions Regions(SrcMgr); MCStreamerWrapper Str(Ctx, Regions); std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); std::unique_ptr<MCInstrAnalysis> MCIA( TheTarget->createMCInstrAnalysis(MCII.get())); if (!MCPU.compare("native")) MCPU = llvm::sys::getHostCPUName(); std::unique_ptr<MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TripleName, MCPU, /* FeaturesStr */ "")); if (!STI->isCPUStringValid(MCPU)) return 1; if (!PrintInstructionTables && !STI->getSchedModel().isOutOfOrder()) { WithColor::error() << "please specify an out-of-order cpu. '" << MCPU << "' is an in-order cpu.\n"; return 1; } if (!STI->getSchedModel().hasInstrSchedModel()) { WithColor::error() << "unable to find instruction-level scheduling information for" << " target triple '" << TheTriple.normalize() << "' and cpu '" << MCPU << "'.\n"; if (STI->getSchedModel().InstrItineraries) WithColor::note() << "cpu '" << MCPU << "' provides itineraries. However, " << "instruction itineraries are currently unsupported.\n"; return 1; } std::unique_ptr<MCAsmParser> P(createMCAsmParser(SrcMgr, Ctx, Str, *MAI)); MCAsmLexer &Lexer = P->getLexer(); MCACommentConsumer CC(Regions); Lexer.setCommentConsumer(&CC); if (AssembleInput(ProgName, *P, TheTarget, *STI, *MCII, MCOptions)) return 1; if (Regions.empty()) { WithColor::error() << "no assembly instructions found.\n"; return 1; } // Now initialize the output file. auto OF = getOutputStream(); if (std::error_code EC = OF.getError()) { WithColor::error() << EC.message() << '\n'; return 1; } unsigned AssemblerDialect = P->getAssemblerDialect(); if (OutputAsmVariant >= 0) AssemblerDialect = static_cast<unsigned>(OutputAsmVariant); std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( Triple(TripleName), AssemblerDialect, *MAI, *MCII, *MRI)); if (!IP) { WithColor::error() << "unable to create instruction printer for target triple '" << TheTriple.normalize() << "' with assembly variant " << AssemblerDialect << ".\n"; return 1; } std::unique_ptr<llvm::ToolOutputFile> TOF = std::move(*OF); const MCSchedModel &SM = STI->getSchedModel(); unsigned Width = SM.IssueWidth; if (DispatchWidth) Width = DispatchWidth; // Create an instruction builder. mca::InstrBuilder IB(*STI, *MCII, *MRI, *MCIA, *IP); // Create a context to control ownership of the pipeline hardware. mca::Context MCA(*MRI, *STI); mca::PipelineOptions PO(Width, RegisterFileSize, LoadQueueSize, StoreQueueSize, AssumeNoAlias); // Number each region in the sequence. unsigned RegionIdx = 0; for (const std::unique_ptr<mca::CodeRegion> &Region : Regions) { // Skip empty code regions. if (Region->empty()) continue; // Don't print the header of this region if it is the default region, and // it doesn't have an end location. if (Region->startLoc().isValid() || Region->endLoc().isValid()) { TOF->os() << "\n[" << RegionIdx++ << "] Code Region"; StringRef Desc = Region->getDescription(); if (!Desc.empty()) TOF->os() << " - " << Desc; TOF->os() << "\n\n"; } mca::SourceMgr S(Region->getInstructions(), PrintInstructionTables ? 1 : Iterations); if (PrintInstructionTables) { // Create a pipeline, stages, and a printer. auto P = llvm::make_unique<mca::Pipeline>(); P->appendStage(llvm::make_unique<mca::FetchStage>(IB, S)); P->appendStage(llvm::make_unique<mca::InstructionTables>(SM, IB)); mca::PipelinePrinter Printer(*P); // Create the views for this pipeline, execute, and emit a report. if (PrintInstructionInfoView) { Printer.addView( llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, S, *IP)); } Printer.addView( llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, S)); P->run(); Printer.printReport(TOF->os()); continue; } // Create a basic pipeline simulating an out-of-order backend. auto P = MCA.createDefaultPipeline(PO, IB, S); mca::PipelinePrinter Printer(*P); if (PrintSummaryView) Printer.addView(llvm::make_unique<mca::SummaryView>(SM, S, Width)); if (PrintInstructionInfoView) Printer.addView( llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, S, *IP)); if (PrintDispatchStats) Printer.addView(llvm::make_unique<mca::DispatchStatistics>()); if (PrintSchedulerStats) Printer.addView(llvm::make_unique<mca::SchedulerStatistics>(*STI)); if (PrintRetireStats) Printer.addView(llvm::make_unique<mca::RetireControlUnitStatistics>()); if (PrintRegisterFileStats) Printer.addView(llvm::make_unique<mca::RegisterFileStatistics>(*STI)); if (PrintResourcePressureView) Printer.addView( llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, S)); if (PrintTimelineView) { Printer.addView(llvm::make_unique<mca::TimelineView>( *STI, *IP, S, TimelineMaxIterations, TimelineMaxCycles)); } P->run(); Printer.printReport(TOF->os()); // Clear the InstrBuilder internal state in preparation for another round. IB.clear(); } TOF->keep(); return 0; }