| //===- bolt/Utils/Utils.cpp - Common helper functions ---------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Common helper functions. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "bolt/Utils/Utils.h" | |
| #include "llvm/ADT/SmallString.h" | |
| #include "llvm/BinaryFormat/Dwarf.h" | |
| #include "llvm/MC/MCDwarf.h" | |
| #include "llvm/Support/LEB128.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #if defined(__linux__) | |
| #include <fcntl.h> | |
| #include <sys/mman.h> | |
| #include <unistd.h> | |
| #endif | |
| namespace llvm { | |
| namespace bolt { | |
| void report_error(StringRef Message, std::error_code EC) { | |
| assert(EC); | |
| errs() << "BOLT-ERROR: '" << Message << "': " << EC.message() << ".\n"; | |
| exit(1); | |
| } | |
| void report_error(StringRef Message, Error E) { | |
| assert(E); | |
| errs() << "BOLT-ERROR: '" << Message << "': " << toString(std::move(E)) | |
| << ".\n"; | |
| exit(1); | |
| } | |
| void check_error(std::error_code EC, StringRef Message) { | |
| if (!EC) | |
| return; | |
| report_error(Message, EC); | |
| } | |
| void check_error(Error E, Twine Message) { | |
| if (!E) | |
| return; | |
| handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) { | |
| llvm::errs() << "BOLT-ERROR: '" << Message << "': " << EIB.message() | |
| << '\n'; | |
| exit(1); | |
| }); | |
| } | |
| std::string getEscapedName(const StringRef &Name) { | |
| std::string Output = Name.str(); | |
| for (size_t I = 0; I < Output.size(); ++I) | |
| if (Output[I] == ' ' || Output[I] == '\\') | |
| Output.insert(I++, 1, '\\'); | |
| return Output; | |
| } | |
| std::string getUnescapedName(const StringRef &Name) { | |
| std::string Output = Name.str(); | |
| for (size_t I = 0; I < Output.size(); ++I) | |
| if (Output[I] == '\\') | |
| Output.erase(I++, 1); | |
| return Output; | |
| } | |
| std::optional<StringRef> getCommonName(const StringRef Name, bool KeepSuffix, | |
| ArrayRef<StringRef> Suffixes) { | |
| for (StringRef Suffix : Suffixes) { | |
| size_t LTOSuffixPos = Name.find(Suffix); | |
| if (LTOSuffixPos != StringRef::npos) | |
| return Name.substr(0, LTOSuffixPos + (KeepSuffix ? Suffix.size() : 0)); | |
| } | |
| return std::nullopt; | |
| } | |
| std::optional<StringRef> getLTOCommonName(const StringRef Name) { | |
| return getCommonName(Name, true, | |
| {".__uniq.", ".lto_priv.", ".constprop.", ".llvm."}); | |
| } | |
| std::optional<uint8_t> readDWARFExpressionTargetReg(StringRef ExprBytes) { | |
| uint8_t Opcode = ExprBytes[0]; | |
| if (Opcode == dwarf::DW_CFA_def_cfa_expression) | |
| return std::nullopt; | |
| assert((Opcode == dwarf::DW_CFA_expression || | |
| Opcode == dwarf::DW_CFA_val_expression) && | |
| "invalid DWARF expression CFI"); | |
| assert(ExprBytes.size() > 1 && "DWARF expression CFI is too short"); | |
| const uint8_t *const Start = | |
| reinterpret_cast<const uint8_t *>(ExprBytes.drop_front(1).data()); | |
| const uint8_t *const End = | |
| reinterpret_cast<const uint8_t *>(Start + ExprBytes.size() - 1); | |
| uint8_t Reg = decodeULEB128(Start, nullptr, End); | |
| return Reg; | |
| } | |
| void safePWrite(raw_fd_ostream &OS, const char *Src, size_t Size, | |
| uint64_t Offset) { | |
| if (Size == 0) | |
| return; | |
| const uint64_t SavedPos = OS.tell(); | |
| const uint64_t RequiredPos = Offset + Size; | |
| const bool Extended = SavedPos < RequiredPos; | |
| // raw_pwrite_stream::pwrite() expects the stream to be large enough | |
| // to cover the write. If the target offset exceeds the current stream | |
| // position, we must extend the stream by seeking to the required position | |
| // first to avoid failures. | |
| if (Extended) | |
| OS.seek(RequiredPos); | |
| OS.pwrite(Src, Size, Offset); | |
| if (Extended) | |
| OS.seek(SavedPos); | |
| } | |
| void pageOutMemory(const void *Addr, size_t Size) { | |
| #if defined(__linux__) && defined(MADV_PAGEOUT) | |
| const uintptr_t Start = reinterpret_cast<uintptr_t>(Addr); | |
| const size_t PageSize = static_cast<size_t>(::getpagesize()); | |
| // madvise() requires a page-aligned start. | |
| if (PageSize == 0 || Start % PageSize != 0 || Size < PageSize) | |
| return; | |
| (void)::madvise(const_cast<void *>(Addr), Size & ~(PageSize - 1), | |
| MADV_PAGEOUT); | |
| #else | |
| (void)Addr; | |
| (void)Size; | |
| #endif | |
| } | |
| void dropFileFromPageCache(StringRef Path) { | |
| #if defined(__linux__) | |
| if (Path.empty()) | |
| return; | |
| SmallString<128> PathStorage(Path); | |
| const int FD = ::open(PathStorage.c_str(), O_RDONLY); | |
| if (FD < 0) | |
| return; | |
| (void)::posix_fadvise(FD, 0, 0, POSIX_FADV_DONTNEED); | |
| ::close(FD); | |
| #else | |
| (void)Path; | |
| #endif | |
| } | |
| } // namespace bolt | |
| bool operator==(const llvm::MCCFIInstruction &L, | |
| const llvm::MCCFIInstruction &R) { | |
| if (L.getOperation() != R.getOperation()) | |
| return false; | |
| switch (L.getOperation()) { | |
| case MCCFIInstruction::OpRestore: | |
| case MCCFIInstruction::OpSameValue: | |
| case MCCFIInstruction::OpUndefined: | |
| case MCCFIInstruction::OpDefCfaRegister: | |
| return L.getRegister() == R.getRegister(); | |
| case MCCFIInstruction::OpRegister: | |
| return L.getRegister() == R.getRegister() && | |
| L.getRegister2() == R.getRegister2(); | |
| case MCCFIInstruction::OpOffset: | |
| case MCCFIInstruction::OpRelOffset: | |
| case MCCFIInstruction::OpDefCfa: | |
| return L.getRegister() == R.getRegister() && L.getOffset() == R.getOffset(); | |
| case MCCFIInstruction::OpEscape: | |
| return L.getValues() == R.getValues(); | |
| case MCCFIInstruction::OpRememberState: | |
| case MCCFIInstruction::OpRestoreState: | |
| return true; | |
| case MCCFIInstruction::OpDefCfaOffset: | |
| case MCCFIInstruction::OpAdjustCfaOffset: | |
| return L.getOffset() == R.getOffset(); | |
| default: | |
| return false; | |
| } | |
| } | |
| } // namespace llvm |