static std::string ProcessFailure(StringRef ProgPath, const char** Args, unsigned Timeout = 0, unsigned MemoryLimit = 0) { std::ostringstream OS; OS << "\nError running tool:\n "; for (const char **Arg = Args; *Arg; ++Arg) OS << " " << *Arg; OS << "\n"; // Rerun the compiler, capturing any error messages to print them. SmallString<128> ErrorFilename; int ErrorFD; error_code EC = sys::fs::createTemporaryFile( "bugpoint.program_error_messages", "", ErrorFD, ErrorFilename); if (EC) { errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(), ErrorFilename.str(), Timeout, MemoryLimit); // FIXME: check return code ? // Print out the error messages generated by GCC if possible... std::ifstream ErrorFile(ErrorFilename.c_str()); if (ErrorFile) { std::copy(std::istreambuf_iterator<char>(ErrorFile), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(OS)); ErrorFile.close(); } sys::fs::remove(ErrorFilename.c_str()); return OS.str(); }
// Implement the 'x' operation. This function extracts files back to the file // system. static void doExtract(StringRef Name, object::Archive::child_iterator I) { // Retain the original mode. sys::fs::perms Mode = I->getAccessMode(); SmallString<128> Storage = Name; int FD; failIfError( sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_None, Mode), Storage.c_str()); { raw_fd_ostream file(FD, false); // Get the data and its length StringRef Data = I->getBuffer(); // Write the data. file.write(Data.data(), Data.size()); } // If we're supposed to retain the original modification times, etc. do so // now. if (OriginalDates) failIfError( sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified())); if (close(FD)) fail("Could not close the file"); }
bool LTOCodeGenerator::compileOptimizedToFile(const char **name, std::string &errMsg) { // make unique temp .o file to put generated object file SmallString<128> Filename; int FD; std::error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); if (EC) { errMsg = EC.message(); return false; } // generate object file tool_output_file objFile(Filename.c_str(), FD); bool genResult = compileOptimized(objFile.os(), errMsg); objFile.os().close(); if (objFile.os().has_error()) { objFile.os().clear_error(); sys::fs::remove(Twine(Filename)); return false; } objFile.keep(); if (!genResult) { sys::fs::remove(Twine(Filename)); return false; } NativeObjectPath = Filename.c_str(); *name = NativeObjectPath.c_str(); return true; }
std::unique_ptr<Module> BugDriver::extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs, Module *M) { SmallString<128> Filename; int FD; std::error_code EC = sys::fs::createUniqueFile( OutputPrefix + "-extractblocks%%%%%%%", FD, Filename); if (EC) { outs() << "*** Basic Block extraction failed!\n"; errs() << "Error creating temporary file: " << EC.message() << "\n"; EmitProgressBitcode(M, "basicblockextractfail", true); return nullptr; } sys::RemoveFileOnSignal(Filename); tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD); for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end(); I != E; ++I) { BasicBlock *BB = *I; // If the BB doesn't have a name, give it one so we have something to key // off of. if (!BB->hasName()) BB->setName("tmpbb"); BlocksToNotExtractFile.os() << BB->getParent()->getName() << " " << BB->getName() << "\n"; } BlocksToNotExtractFile.os().close(); if (BlocksToNotExtractFile.os().has_error()) { errs() << "Error writing list of blocks to not extract\n"; EmitProgressBitcode(M, "basicblockextractfail", true); BlocksToNotExtractFile.os().clear_error(); return nullptr; } BlocksToNotExtractFile.keep(); std::string uniqueFN = "--extract-blocks-file="; uniqueFN += Filename.str(); const char *ExtraArg = uniqueFN.c_str(); std::vector<std::string> PI; PI.push_back("extract-blocks"); std::unique_ptr<Module> Ret = runPassesOn(M, PI, false, 1, &ExtraArg); sys::fs::remove(Filename.c_str()); if (!Ret) { outs() << "*** Basic Block extraction failed, please report a bug!\n"; EmitProgressBitcode(M, "basicblockextractfail", true); } return Ret; }
bool ReplacementHandling::serializeReplacements( const TUReplacementsMap &Replacements) { assert(!DestinationDir.empty() && "Destination directory not set"); bool Errors = false; for (TUReplacementsMap::const_iterator I = Replacements.begin(), E = Replacements.end(); I != E; ++I) { SmallString<128> ReplacementsFileName; SmallString<64> Error; bool Result = generateReplacementsFileName(DestinationDir, I->getValue().MainSourceFile, ReplacementsFileName, Error); if (!Result) { errs() << "Failed to generate replacements filename:" << Error << "\n"; Errors = true; continue; } std::string ErrorInfo; raw_fd_ostream ReplacementsFile(ReplacementsFileName.c_str(), ErrorInfo, fs::F_None); if (!ErrorInfo.empty()) { errs() << "Error opening file: " << ErrorInfo << "\n"; Errors = true; continue; } yaml::Output YAML(ReplacementsFile); YAML << const_cast<TranslationUnitReplacements &>(I->getValue()); } return !Errors; }
llvm::GlobalVariable * MSRTTIBuilder::getBaseClassArray(SmallVectorImpl<MSRTTIClass> &Classes) { SmallString<256> MangledName; { llvm::raw_svector_ostream Out(MangledName); Mangler.mangleCXXRTTIBaseClassArray(RD, Out); } // Forward-declare the base class array. // cl.exe pads the base class array with 1 (in 32 bit mode) or 4 (in 64 bit // mode) bytes of padding. We provide a pointer sized amount of padding by // adding +1 to Classes.size(). The sections have pointer alignment and are // marked pick-any so it shouldn't matter. auto PtrType = getBaseClassDescriptorType(CGM)->getPointerTo(); auto ArrayType = llvm::ArrayType::get(PtrType, Classes.size() + 1); auto BCA = new llvm::GlobalVariable(Module, ArrayType, /*Constant=*/true, Linkage, /*Initializer=*/0, MangledName.c_str()); // Initialize the BaseClassArray. SmallVector<llvm::Constant *, 8> BaseClassArrayData; for (MSRTTIClass &Class : Classes) BaseClassArrayData.push_back(getBaseClassDescriptor(Class)); BaseClassArrayData.push_back(llvm::ConstantPointerNull::get(PtrType)); BCA->setInitializer(llvm::ConstantArray::get(ArrayType, BaseClassArrayData)); return BCA; }
// This method allows an ArchiveMember to be replaced with the data for a // different file, presumably as an update to the member. It also makes sure // the flags are reset correctly. bool ArchiveMember::replaceWith(StringRef newFile, std::string* ErrMsg) { bool Exists; if (sys::fs::exists(newFile.str(), Exists) || !Exists) { if (ErrMsg) *ErrMsg = "Can not replace an archive member with a non-existent file"; return true; } data = 0; path = newFile.str(); // SVR4 symbol tables have an empty name if (path == ARFILE_SVR4_SYMTAB_NAME) flags |= SVR4SymbolTableFlag; else flags &= ~SVR4SymbolTableFlag; // BSD4.4 symbol tables have a special name if (path == ARFILE_BSD4_SYMTAB_NAME) flags |= BSD4SymbolTableFlag; else flags &= ~BSD4SymbolTableFlag; // String table name if (path == ARFILE_STRTAB_NAME) flags |= StringTableFlag; else flags &= ~StringTableFlag; // If it has a slash or its over 15 chars then its a long filename format if (path.length() > 15) flags |= HasLongFilenameFlag; else flags &= ~HasLongFilenameFlag; // Get the signature and status info const char* signature = (const char*) data; SmallString<4> magic; if (!signature) { sys::fs::get_magic(path, magic.capacity(), magic); signature = magic.c_str(); sys::fs::file_status Status; error_code EC = sys::fs::status(path, Status); if (EC) return true; User = Status.getUser(); Group = Status.getGroup(); Mode = Status.permissions(); ModTime = Status.getLastModificationTime(); // FIXME: On posix this is a second stat. EC = sys::fs::file_size(path, Size); if (EC) return true; } return false; }
/// Add a symbol which isn't defined just yet to a list to be resolved later. void LTOModule::addPotentialUndefinedSymbol(ModuleSymbolTable::Symbol Sym, bool isFunc) { SmallString<64> name; { raw_svector_ostream OS(name); SymTab.printSymbolName(OS, Sym); name.c_str(); } auto IterBool = _undefines.insert(std::make_pair(name, NameAndAttributes())); // we already have the symbol if (!IterBool.second) return; NameAndAttributes &info = IterBool.first->second; info.name = IterBool.first->first(); const GlobalValue *decl = Sym.dyn_cast<GlobalValue *>(); if (decl->hasExternalWeakLinkage()) info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; else info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; info.isFunction = isFunc; info.symbol = decl; }
/// parseSymbols - Parse the symbols from the module and model-level ASM and add /// them to either the defined or undefined lists. bool LTOModule::parseSymbols(std::string &errMsg) { for (auto &Sym : IRFile->symbols()) { const GlobalValue *GV = IRFile->getSymbolGV(Sym.getRawDataRefImpl()); uint32_t Flags = Sym.getFlags(); if (Flags & object::BasicSymbolRef::SF_FormatSpecific) continue; bool IsUndefined = Flags & object::BasicSymbolRef::SF_Undefined; if (!GV) { SmallString<64> Buffer; { raw_svector_ostream OS(Buffer); Sym.printName(OS); } const char *Name = Buffer.c_str(); if (IsUndefined) addAsmGlobalSymbolUndef(Name); else if (Flags & object::BasicSymbolRef::SF_Global) addAsmGlobalSymbol(Name, LTO_SYMBOL_SCOPE_DEFAULT); else addAsmGlobalSymbol(Name, LTO_SYMBOL_SCOPE_INTERNAL); continue; } auto *F = dyn_cast<Function>(GV); if (IsUndefined) { addPotentialUndefinedSymbol(Sym, F != nullptr); continue; } if (F) { addDefinedFunctionSymbol(Sym); continue; } if (isa<GlobalVariable>(GV)) { addDefinedDataSymbol(Sym); continue; } assert(isa<GlobalAlias>(GV)); addDefinedDataSymbol(Sym); } // make symbols for all undefines for (StringMap<NameAndAttributes>::iterator u =_undefines.begin(), e = _undefines.end(); u != e; ++u) { // If this symbol also has a definition, then don't make an undefine because // it is a tentative definition. if (_defines.count(u->getKey())) continue; NameAndAttributes info = u->getValue(); _symbols.push_back(info); } return false; }
/// Launch each module's backend pipeline in a separate task in a thread pool. static void thinLTOBackends(raw_fd_ostream *ApiFile, const ModuleSummaryIndex &CombinedIndex) { unsigned TaskCount = 0; std::vector<ThinLTOTaskInfo> Tasks; Tasks.reserve(Modules.size()); unsigned int MaxThreads = options::Parallelism ? options::Parallelism : thread::hardware_concurrency(); // Create ThreadPool in nested scope so that threads will be joined // on destruction. { ThreadPool ThinLTOThreadPool(MaxThreads); for (claimed_file &F : Modules) { // Do all the gold callbacks in the main thread, since gold is not thread // safe by default. PluginInputFile InputFile(F.handle); const void *View = getSymbolsAndView(F); if (!View) continue; SmallString<128> Filename; if (!options::obj_path.empty()) // Note that openOutputFile will append a unique ID for each task Filename = options::obj_path; else if (options::TheOutputType == options::OT_SAVE_TEMPS) { // Use the input file name so that we get a unique and identifiable // output file for each ThinLTO backend task. Filename = InputFile.file().name; Filename += ".thinlto.o"; } bool TempOutFile = Filename.empty(); SmallString<128> NewFilename; int FD = openOutputFile(Filename, TempOutFile, NewFilename, // Only append the TaskID if we will use the // non-unique obj_path. !options::obj_path.empty() ? TaskCount : -1); TaskCount++; std::unique_ptr<raw_fd_ostream> OS = llvm::make_unique<raw_fd_ostream>(FD, true); // Enqueue the task ThinLTOThreadPool.async(thinLTOBackendTask, std::ref(F), View, std::ref(InputFile.file()), ApiFile, std::ref(CombinedIndex), OS.get(), TaskCount); // Record the information needed by the task or during its cleanup // to a ThinLTOTaskInfo instance. For information needed by the task // the unique_ptr ownership is transferred to the ThinLTOTaskInfo. Tasks.emplace_back(std::move(InputFile), std::move(OS), NewFilename.c_str(), TempOutFile); } } for (auto &Task : Tasks) Task.cleanup(); }
void CodeGen::runSplitCodeGen(const SmallString<128> &BCFilename) { const std::string &TripleStr = M->getTargetTriple(); Triple TheTriple(TripleStr); SubtargetFeatures Features = getFeatures(TheTriple); TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); CodeGenOpt::Level CGOptLevel = getCGOptLevel(); SmallString<128> Filename; // Note that openOutputFile will append a unique ID for each task if (!options::obj_path.empty()) Filename = options::obj_path; else if (options::TheOutputType == options::OT_SAVE_TEMPS) Filename = output_name + ".o"; // Note that the default parallelism is 1 instead of the // hardware_concurrency, as there are behavioral differences between // parallelism levels (e.g. symbol ordering will be different, and some uses // of inline asm currently have issues with parallelism >1). unsigned int MaxThreads = options::Parallelism ? options::Parallelism : 1; std::vector<SmallString<128>> Filenames(MaxThreads); std::vector<SmallString<128>> BCFilenames(MaxThreads); bool TempOutFile = Filename.empty(); { // Open a file descriptor for each backend task. This is done in a block // so that the output file descriptors are closed before gold opens them. std::list<llvm::raw_fd_ostream> OSs; std::vector<llvm::raw_pwrite_stream *> OSPtrs(MaxThreads); for (unsigned I = 0; I != MaxThreads; ++I) { int FD = openOutputFile(Filename, TempOutFile, Filenames[I], // Only append ID if there are multiple tasks. MaxThreads > 1 ? I : -1); OSs.emplace_back(FD, true); OSPtrs[I] = &OSs.back(); } std::list<llvm::raw_fd_ostream> BCOSs; std::vector<llvm::raw_pwrite_stream *> BCOSPtrs; if (!BCFilename.empty() && MaxThreads > 1) { for (unsigned I = 0; I != MaxThreads; ++I) { int FD = openOutputFile(BCFilename, false, BCFilenames[I], I); BCOSs.emplace_back(FD, true); BCOSPtrs.push_back(&BCOSs.back()); } } // Run backend tasks. splitCodeGen(std::move(M), OSPtrs, BCOSPtrs, options::mcpu, Features.getString(), Options, RelocationModel, CodeModel::Default, CGOptLevel); } for (auto &Filename : Filenames) recordFile(Filename.c_str(), TempOutFile); }
void LTOModule::addDefinedDataSymbol(const object::BasicSymbolRef &Sym) { SmallString<64> Buffer; { raw_svector_ostream OS(Buffer); Sym.printName(OS); } const GlobalValue *V = IRFile->getSymbolGV(Sym.getRawDataRefImpl()); addDefinedDataSymbol(Buffer.c_str(), V); }
void LTOModule::addDefinedFunctionSymbol(ModuleSymbolTable::Symbol Sym) { SmallString<64> Buffer; { raw_svector_ostream OS(Buffer); SymTab.printSymbolName(OS, Sym); Buffer.c_str(); } const Function *F = cast<Function>(Sym.get<GlobalValue *>()); addDefinedFunctionSymbol(Buffer, F); }
void LTOModule::addDefinedDataSymbol(ModuleSymbolTable::Symbol Sym) { SmallString<64> Buffer; { raw_svector_ostream OS(Buffer); SymTab.printSymbolName(OS, Sym); Buffer.c_str(); } const GlobalValue *V = Sym.get<GlobalValue *>(); addDefinedDataSymbol(Buffer, V); }
void LTOModule::addDefinedFunctionSymbol(const object::BasicSymbolRef &Sym) { SmallString<64> Buffer; { raw_svector_ostream OS(Buffer); Sym.printName(OS); } const Function *F = cast<Function>(IRFile->getSymbolGV(Sym.getRawDataRefImpl())); addDefinedFunctionSymbol(Buffer.c_str(), F); }
TEST(TBDv2, WriteFile) { static const char tbd_v2_file3[] = "--- !tapi-tbd-v2\n" "archs: [ i386, x86_64 ]\n" "platform: macosx\n" "install-name: '/usr/lib/libfoo.dylib'\n" "current-version: 1.2.3\n" "compatibility-version: 0\n" "swift-version: 5\n" "exports: \n" " - archs: [ i386 ]\n" " symbols: [ _sym1 ]\n" " weak-def-symbols: [ _sym2 ]\n" " thread-local-symbols: [ _sym3 ]\n" " - archs: [ x86_64 ]\n" " allowable-clients: [ clientA ]\n" " re-exports: [ '/usr/lib/libfoo.dylib' ]\n" " symbols: [ '_OBJC_EHTYPE_$_Class1' ]\n" " objc-classes: [ _Class1 ]\n" " objc-ivars: [ _Class1._ivar1 ]\n" "...\n"; InterfaceFile File; File.setPath("libfoo.dylib"); File.setInstallName("/usr/lib/libfoo.dylib"); File.setFileType(FileType::TBD_V2); File.setArchitectures(AK_i386 | AK_x86_64); File.setPlatform(PlatformKind::macOS); File.setCurrentVersion(PackedVersion(1, 2, 3)); File.setTwoLevelNamespace(); File.setApplicationExtensionSafe(); File.setSwiftABIVersion(5); File.setObjCConstraint(ObjCConstraintType::Retain_Release); File.addAllowableClient("clientA", AK_x86_64); File.addReexportedLibrary("/usr/lib/libfoo.dylib", AK_x86_64); File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", AK_i386); File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", AK_i386, SymbolFlags::WeakDefined); File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", AK_i386, SymbolFlags::ThreadLocalValue); File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", AK_x86_64); File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", AK_x86_64); File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1", AK_x86_64); SmallString<4096> Buffer; raw_svector_ostream OS(Buffer); auto Result = TextAPIWriter::writeToStream(OS, File); EXPECT_FALSE(Result); EXPECT_STREQ(tbd_v2_file3, Buffer.c_str()); }
bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) { // make unique temp output file to put generated code SmallString<128> Filename; int FD; const char *Extension = (FileType == TargetMachine::CGFT_AssemblyFile ? "s" : "o"); std::error_code EC = sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename); if (EC) { emitError(EC.message()); return false; } // generate object file tool_output_file objFile(Filename.c_str(), FD); bool genResult = compileOptimized(&objFile.os()); objFile.os().close(); if (objFile.os().has_error()) { objFile.os().clear_error(); sys::fs::remove(Twine(Filename)); return false; } objFile.keep(); if (!genResult) { sys::fs::remove(Twine(Filename)); return false; } NativeObjectPath = Filename.c_str(); *Name = NativeObjectPath.c_str(); return true; }
llvm::GlobalVariable *MSRTTIBuilder::getClassHierarchyDescriptor() { SmallString<256> MangledName; { llvm::raw_svector_ostream Out(MangledName); Mangler.mangleCXXRTTIClassHierarchyDescriptor(RD, Out); } // Check to see if we've already declared this ClassHierarchyDescriptor. if (auto CHD = Module.getNamedGlobal(MangledName)) return CHD; // Serialize the class hierarchy and initialize the CHD Fields. SmallVector<MSRTTIClass, 8> Classes; serializeClassHierarchy(Classes, RD); Classes.front().initialize(/*Parent=*/0, /*Specifier=*/0); detectAmbiguousBases(Classes); int Flags = 0; for (auto Class : Classes) { if (Class.RD->getNumBases() > 1) Flags |= HasBranchingHierarchy; // Note: cl.exe does not calculate "HasAmbiguousBases" correctly. We // believe the field isn't actually used. if (Class.Flags & MSRTTIClass::IsAmbiguous) Flags |= HasAmbiguousBases; } if ((Flags & HasBranchingHierarchy) && RD->getNumVBases() != 0) Flags |= HasVirtualBranchingHierarchy; // These gep indices are used to get the address of the first element of the // base class array. llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0), llvm::ConstantInt::get(CGM.IntTy, 0)}; // Forward-declare the class hierarchy descriptor auto Type = getClassHierarchyDescriptorType(CGM); auto CHD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage, /*Initializer=*/0, MangledName.c_str()); // Initialize the base class ClassHierarchyDescriptor. llvm::Constant *Fields[] = { llvm::ConstantInt::get(CGM.IntTy, 0), // Unknown llvm::ConstantInt::get(CGM.IntTy, Flags), llvm::ConstantInt::get(CGM.IntTy, Classes.size()), llvm::ConstantExpr::getInBoundsGetElementPtr( getBaseClassArray(Classes), llvm::ArrayRef<llvm::Value *>(GEPIndices))}; CHD->setInitializer(llvm::ConstantStruct::get(Type, Fields)); return CHD; }
// Replace .. embedded in path for purposes of having // a canonical path. static std::string replaceDotDot(StringRef Path) { SmallString<128> Buffer; llvm::sys::path::const_iterator B = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path); while (B != E) { if (B->compare(".") == 0) { } else if (B->compare("..") == 0) llvm::sys::path::remove_filename(Buffer); else llvm::sys::path::append(Buffer, *B); ++B; } if (Path.endswith("/") || Path.endswith("\\")) Buffer.append(1, Path.back()); return Buffer.c_str(); }
std::string KleeHandler::getRunTimeLibraryPath(const char *argv0) { // allow specifying the path to the runtime library const char *env = getenv("KLEE_RUNTIME_LIBRARY_PATH"); if (env) return std::string(env); // Take any function from the execution binary but not main (as not allowed by // C++ standard) void *MainExecAddr = (void *)(intptr_t)getRunTimeLibraryPath; SmallString<128> toolRoot( #if LLVM_VERSION_CODE >= LLVM_VERSION(3,4) llvm::sys::fs::getMainExecutable(argv0, MainExecAddr) #else llvm::sys::Path::GetMainExecutable(argv0, MainExecAddr).str() #endif ); // Strip off executable so we have a directory path llvm::sys::path::remove_filename(toolRoot); SmallString<128> libDir; if ( strcmp(toolRoot.c_str(), KLEE_INSTALL_BIN_DIR ) == 0) { KLEE_DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() << "Using installed KLEE library runtime: "); libDir = KLEE_INSTALL_RUNTIME_DIR ; } else { KLEE_DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() << "Using build directory KLEE library runtime :"); libDir = KLEE_DIR; llvm::sys::path::append(libDir,RUNTIME_CONFIGURATION); llvm::sys::path::append(libDir,"lib"); } KLEE_DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() << libDir.c_str() << "\n"); return libDir.str(); }
llvm::GlobalVariable * MSRTTIBuilder::getBaseClassDescriptor(const MSRTTIClass &Class) { // Compute the fields for the BaseClassDescriptor. They are computed up front // because they are mangled into the name of the object. uint32_t OffsetInVBTable = 0; int32_t VBPtrOffset = -1; if (Class.VirtualRoot) { auto &VTableContext = CGM.getMicrosoftVTableContext(); OffsetInVBTable = VTableContext.getVBTableIndex(RD, Class.VirtualRoot) * 4; VBPtrOffset = Context.getASTRecordLayout(RD).getVBPtrOffset().getQuantity(); } SmallString<256> MangledName; { llvm::raw_svector_ostream Out(MangledName); Mangler.mangleCXXRTTIBaseClassDescriptor(Class.RD, Class.OffsetInVBase, VBPtrOffset, OffsetInVBTable, Class.Flags, Out); } // Check to see if we've already declared declared this object. if (auto BCD = Module.getNamedGlobal(MangledName)) return BCD; // Forward-declare the base class descriptor. auto Type = getBaseClassDescriptorType(CGM); auto BCD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage, /*Initializer=*/0, MangledName.c_str()); // Initialize the BaseClassDescriptor. llvm::Constant *Fields[] = { CGM.getMSTypeDescriptor(Context.getTypeDeclType(Class.RD)), llvm::ConstantInt::get(CGM.IntTy, Class.NumBases), llvm::ConstantInt::get(CGM.IntTy, Class.OffsetInVBase), llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset), llvm::ConstantInt::get(CGM.IntTy, OffsetInVBTable), llvm::ConstantInt::get(CGM.IntTy, Class.Flags), MSRTTIBuilder(CGM, Class.RD).getClassHierarchyDescriptor()}; BCD->setInitializer(llvm::ConstantStruct::get(Type, Fields)); return BCD; }
/// @brief Find program using shell lookup rules. /// @param Program This is either an absolute path, relative path, or simple a /// program name. Look in PATH for any programs that match. If no /// extension is present, try all extensions in PATHEXT. /// @return If ec == errc::success, The absolute path to the program. Otherwise /// the return value is undefined. static std::string FindProgram(const std::string &Program, std::error_code &ec) { char PathName[MAX_PATH + 1]; typedef SmallVector<StringRef, 12> pathext_t; pathext_t pathext; // Check for the program without an extension (in case it already has one). pathext.push_back(""); SplitString(std::getenv("PATHEXT"), pathext, ";"); for (pathext_t::iterator i = pathext.begin(), e = pathext.end(); i != e; ++i){ SmallString<5> ext; for (std::size_t ii = 0, e = i->size(); ii != e; ++ii) ext.push_back(::tolower((*i)[ii])); LPCSTR Extension = NULL; if (ext.size() && ext[0] == '.') Extension = ext.c_str(); DWORD length = ::SearchPathA(NULL, Program.c_str(), Extension, array_lengthof(PathName), PathName, NULL); if (length == 0) ec = windows_error(::GetLastError()); else if (length > array_lengthof(PathName)) { // This may have been the file, return with error. ec = windows_error(ERROR_BUFFER_OVERFLOW); break; } else { // We found the path! Return it. ec = std::error_code(); break; } } // Make sure PathName is valid. PathName[MAX_PATH] = 0; return PathName; }
llvm::GlobalVariable * MSRTTIBuilder::getCompleteObjectLocator(const VPtrInfo *Info) { SmallString<256> MangledName; { llvm::raw_svector_ostream Out(MangledName); Mangler.mangleCXXRTTICompleteObjectLocator(RD, Info->MangledPath, Out); } // Check to see if we've already computed this complete object locator. if (auto COL = Module.getNamedGlobal(MangledName)) return COL; // Compute the fields of the complete object locator. int OffsetToTop = Info->FullOffsetInMDC.getQuantity(); int VFPtrOffset = 0; // The offset includes the vtordisp if one exists. if (const CXXRecordDecl *VBase = Info->getVBaseWithVPtr()) if (Context.getASTRecordLayout(RD) .getVBaseOffsetsMap() .find(VBase) ->second.hasVtorDisp()) VFPtrOffset = Info->NonVirtualOffset.getQuantity() + 4; // Forward-declare the complete object locator. llvm::StructType *Type = getCompleteObjectLocatorType(CGM); auto COL = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage, /*Initializer=*/0, MangledName.c_str()); // Initialize the CompleteObjectLocator. llvm::Constant *Fields[] = { llvm::ConstantInt::get(CGM.IntTy, 0), // IsDeltaEncoded llvm::ConstantInt::get(CGM.IntTy, OffsetToTop), llvm::ConstantInt::get(CGM.IntTy, VFPtrOffset), CGM.getMSTypeDescriptor(Context.getTypeDeclType(RD)), getClassHierarchyDescriptor()}; COL->setInitializer(llvm::ConstantStruct::get(Type, Fields)); return COL; }
void BuildSystemFrontendDelegate::commandStarted(Command* command) { // Don't report status if opted out by the command. if (!command->shouldShowStatus()) { return; } // Log the command. // // FIXME: Design the logging and status output APIs. SmallString<64> description; if (getFrontend().getInvocation().showVerboseStatus) { command->getVerboseDescription(description); } else { command->getShortDescription(description); // If the short description is empty, always show the verbose one. if (description.empty()) { command->getVerboseDescription(description); } } fprintf(stdout, "%s\n", description.c_str()); fflush(stdout); }
Logger::~Logger() { llvm::sys::ScopedLock L(LoggingMutex); static llvm::TimeRecord sBeginTR = llvm::TimeRecord::getCurrentTime(); SmallString<64> LogMsg; llvm::raw_svector_ostream LogMsgOS(LogMsg); raw_ostream &OS = LogMsgOS; OS << '[' << int(CurrLevel) << ':' << Name << ':'; // FIXME: Portability. #if HAVE_PTHREAD_H && __APPLE__ mach_port_t tid = pthread_mach_thread_np(pthread_self()); OS << tid << ':'; #endif llvm::TimeRecord TR = llvm::TimeRecord::getCurrentTime(); OS << llvm::format("%7.4f] ", TR.getWallTime() - sBeginTR.getWallTime()); OS << Msg.str(); llvm::errs() << LoggerName << ": " << LogMsg.str() << '\n'; #if __APPLE__ // Use the Apple System Log facility. aslclient asl = asl_open(LoggerName.c_str(), "com.apple.console", ASL_OPT_NO_DELAY); aslmsg msg = asl_new(ASL_TYPE_MSG); static const char *levstr[] = {"0", "1", "2", "3", "4", "5", "6", "7"}; asl_set(msg, ASL_KEY_LEVEL, levstr[int(CurrLevel)]); asl_set(msg, ASL_KEY_MSG, LogMsg.c_str()); asl_send(asl, msg); asl_free(msg); asl_close(asl); #endif }
// MCJIT will call this function before compiling any module // MCJIT takes ownership of both the MemoryBuffer object and the memory // to which it refers. virtual MemoryBuffer* getObject(const Module* M) { // Get the ModuleID const std::string ModuleID = M->getModuleIdentifier(); // If we've flagged this as an IR file, cache it if (0 == ModuleID.compare(0, 3, "IR:")) { std::string IRFileName = ModuleID.substr(3); SmallString<128> IRCacheFile = CacheDir; sys::path::append(IRCacheFile, IRFileName); if (!sys::fs::exists(IRCacheFile.str())) { // This file isn't in our cache return NULL; } std::unique_ptr<MemoryBuffer> IRObjectBuffer; MemoryBuffer::getFile(IRCacheFile.c_str(), IRObjectBuffer, -1, false); // MCJIT will want to write into this buffer, and we don't want that // because the file has probably just been mmapped. Instead we make // a copy. The filed-based buffer will be released when it goes // out of scope. return MemoryBuffer::getMemBufferCopy(IRObjectBuffer->getBuffer()); } return NULL; }
void wpi::write_double(raw_ostream &S, double N, FloatStyle Style, optional<size_t> Precision) { size_t Prec = Precision.value_or(getDefaultPrecision(Style)); if (std::isnan(N)) { S << "nan"; return; } else if (std::isinf(N)) { S << "INF"; return; } char Letter; if (Style == FloatStyle::Exponent) Letter = 'e'; else if (Style == FloatStyle::ExponentUpper) Letter = 'E'; else Letter = 'f'; SmallString<8> Spec; wpi::raw_svector_ostream Out(Spec); Out << "%." << Prec << Letter; if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) { #ifdef _WIN32 // On MSVCRT and compatible, output of %e is incompatible to Posix // by default. Number of exponent digits should be at least 2. "%+03d" // FIXME: Implement our formatter to here or Support/Format.h! #if defined(__MINGW32__) // FIXME: It should be generic to C++11. if (N == 0.0 && std::signbit(N)) { char NegativeZero[] = "-0.000000e+00"; if (Style == FloatStyle::ExponentUpper) NegativeZero[strlen(NegativeZero) - 4] = 'E'; S << NegativeZero; return; } #else int fpcl = _fpclass(N); // negative zero if (fpcl == _FPCLASS_NZ) { char NegativeZero[] = "-0.000000e+00"; if (Style == FloatStyle::ExponentUpper) NegativeZero[strlen(NegativeZero) - 4] = 'E'; S << NegativeZero; return; } #endif char buf[32]; unsigned len; len = format(Spec.c_str(), N).snprint(buf, sizeof(buf)); if (len <= sizeof(buf) - 2) { if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') && buf[len - 3] == '0') { int cs = buf[len - 4]; if (cs == '+' || cs == '-') { int c1 = buf[len - 2]; int c0 = buf[len - 1]; if (isdigit(static_cast<unsigned char>(c1)) && isdigit(static_cast<unsigned char>(c0))) { // Trim leading '0': "...e+012" -> "...e+12\0" buf[len - 3] = c1; buf[len - 2] = c0; buf[--len] = 0; } } } S << buf; return; } #endif } if (Style == FloatStyle::Percent) N *= 100.0; char Buf[32]; format(Spec.c_str(), N).snprint(Buf, sizeof(Buf)); S << Buf; if (Style == FloatStyle::Percent) S << '%'; }
static void performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, std::vector<NewArchiveIterator> &NewMembers) { SmallString<128> TmpArchive; failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", TmpArchiveFD, TmpArchive)); TemporaryOutput = TmpArchive.c_str(); tool_output_file Output(TemporaryOutput, TmpArchiveFD); raw_fd_ostream &Out = Output.os(); Out << "!<arch>\n"; std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs; std::vector<std::unique_ptr<MemoryBuffer>> Buffers; std::vector<MemoryBufferRef> Members; for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { NewArchiveIterator &Member = NewMembers[I]; MemoryBufferRef MemberRef; if (Member.isNewMember()) { StringRef Filename = Member.getNew(); int FD = Member.getFD(); const sys::fs::file_status &Status = Member.getStatus(); ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr = MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false); failIfError(MemberBufferOrErr.getError(), Filename); Buffers.push_back(std::move(MemberBufferOrErr.get())); MemberRef = Buffers.back()->getMemBufferRef(); } else { object::Archive::child_iterator OldMember = Member.getOld(); ErrorOr<MemoryBufferRef> MemberBufferOrErr = OldMember->getMemoryBufferRef(); failIfError(MemberBufferOrErr.getError()); MemberRef = MemberBufferOrErr.get(); } Members.push_back(MemberRef); } if (Symtab) { writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs); } std::vector<unsigned> StringMapIndexes; writeStringTable(Out, NewMembers, StringMapIndexes); std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI = MemberOffsetRefs.begin(); unsigned MemberNum = 0; unsigned LongNameMemberNum = 0; for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(), E = NewMembers.end(); I != E; ++I, ++MemberNum) { unsigned Pos = Out.tell(); while (MemberRefsI != MemberOffsetRefs.end() && MemberRefsI->second == MemberNum) { Out.seek(MemberRefsI->first); print32BE(Out, Pos); ++MemberRefsI; } Out.seek(Pos); MemoryBufferRef File = Members[MemberNum]; if (I->isNewMember()) { StringRef FileName = I->getNew(); const sys::fs::file_status &Status = I->getStatus(); StringRef Name = sys::path::filename(FileName); if (Name.size() < 16) printMemberHeader(Out, Name, Status.getLastModificationTime(), Status.getUser(), Status.getGroup(), Status.permissions(), Status.getSize()); else printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], Status.getLastModificationTime(), Status.getUser(), Status.getGroup(), Status.permissions(), Status.getSize()); } else { object::Archive::child_iterator OldMember = I->getOld(); StringRef Name = I->getName(); if (Name.size() < 16) printMemberHeader(Out, Name, OldMember->getLastModified(), OldMember->getUID(), OldMember->getGID(), OldMember->getAccessMode(), OldMember->getSize()); else printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], OldMember->getLastModified(), OldMember->getUID(), OldMember->getGID(), OldMember->getAccessMode(), OldMember->getSize()); } Out << File.getBuffer(); if (Out.tell() % 2) Out << '\n'; } Output.keep(); Out.close(); sys::fs::rename(TemporaryOutput, ArchiveName); TemporaryOutput = nullptr; }
static void codegen(std::unique_ptr<Module> M) { const std::string &TripleStr = M->getTargetTriple(); Triple TheTriple(TripleStr); std::string ErrMsg; const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg); if (!TheTarget) message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str()); if (unsigned NumOpts = options::extra.size()) cl::ParseCommandLineOptions(NumOpts, &options::extra[0]); SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(TheTriple); for (const std::string &A : MAttrs) Features.AddFeature(A); TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); CodeGenOpt::Level CGOptLevel; switch (options::OptLevel) { case 0: CGOptLevel = CodeGenOpt::None; break; case 1: CGOptLevel = CodeGenOpt::Less; break; case 2: CGOptLevel = CodeGenOpt::Default; break; case 3: CGOptLevel = CodeGenOpt::Aggressive; break; } std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine( TripleStr, options::mcpu, Features.getString(), Options, RelocationModel, CodeModel::Default, CGOptLevel)); runLTOPasses(*M, *TM); if (options::TheOutputType == options::OT_SAVE_TEMPS) saveBCFile(output_name + ".opt.bc", *M); SmallString<128> Filename; if (!options::obj_path.empty()) Filename = options::obj_path; else if (options::TheOutputType == options::OT_SAVE_TEMPS) Filename = output_name + ".o"; std::vector<SmallString<128>> Filenames(options::Parallelism); bool TempOutFile = Filename.empty(); { // Open a file descriptor for each backend thread. This is done in a block // so that the output file descriptors are closed before gold opens them. std::list<llvm::raw_fd_ostream> OSs; std::vector<llvm::raw_pwrite_stream *> OSPtrs(options::Parallelism); for (unsigned I = 0; I != options::Parallelism; ++I) { int FD; if (TempOutFile) { std::error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filenames[I]); if (EC) message(LDPL_FATAL, "Could not create temporary file: %s", EC.message().c_str()); } else { Filenames[I] = Filename; if (options::Parallelism != 1) Filenames[I] += utostr(I); std::error_code EC = sys::fs::openFileForWrite(Filenames[I], FD, sys::fs::F_None); if (EC) message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str()); } OSs.emplace_back(FD, true); OSPtrs[I] = &OSs.back(); } // Run backend threads. splitCodeGen(std::move(M), OSPtrs, options::mcpu, Features.getString(), Options, RelocationModel, CodeModel::Default, CGOptLevel); } for (auto &Filename : Filenames) { if (add_input_file(Filename.c_str()) != LDPS_OK) message(LDPL_FATAL, "Unable to add .o file to the link. File left behind in: %s", Filename.c_str()); if (TempOutFile) Cleanup.push_back(Filename.c_str()); } }
/// 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(); } Context.setDiagnosticHandler(diagnosticHandler); ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr = object::IRObjectFile::create(BufferRef, Context); std::error_code EC = ObjOrErr.getError(); if (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; // If we are doing ThinLTO compilation, don't need to process the symbols. // Later we simply build a combined index file after all files are claimed. if (options::thinlto) return LDPS_OK; for (auto &Sym : Obj->symbols()) { uint32_t Symflags = Sym.getFlags(); if (shouldSkip(Symflags)) 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.data()) != LDPS_OK) { message(LDPL_ERROR, "Unable to add symbols!"); return LDPS_ERR; } } return LDPS_OK; }