blob: 81152bc79135a92146675fe1632bf23c67d0db6a [file] [edit]
//===- 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