41 changes: 15 additions & 26 deletions bolt/include/bolt/Passes/MCF.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,14 @@
#ifndef BOLT_PASSES_MCF_H
#define BOLT_PASSES_MCF_H

#include "bolt/Passes/BinaryPasses.h"
#include "llvm/Support/CommandLine.h"

namespace llvm {
namespace bolt {

class BinaryFunction;
class DataflowInfoManager;

enum MCFCostFunction : char {
MCF_DISABLE = 0,
MCF_LINEAR,
MCF_QUADRATIC,
MCF_LOG,
MCF_BLAMEFTS
};

/// Implement the idea in "SamplePGO - The Power of Profile Guided Optimizations
/// without the Usability Burden" by Diego Novillo to make basic block counts
/// equal if we show that A dominates B, B post-dominates A and they are in the
Expand All @@ -31,23 +25,18 @@ void equalizeBBCounts(DataflowInfoManager &Info, BinaryFunction &BF);

/// Fill edge counts based on the basic block count. Used in nonLBR mode when
/// we only have bb count.
void estimateEdgeCounts(BinaryFunction &BF);

/// Entry point for computing a min-cost flow for the CFG with the goal
/// of fixing the flow of the CFG edges, that is, making sure it obeys the
/// flow-conservation equation SumInEdges = SumOutEdges.
///
/// To do this, we create an instance of the min-cost flow problem in a
/// similar way as the one discussed in the work of Roy Levin "Completing
/// Incomplete Edge Profile by Applying Minimum Cost Circulation Algorithms".
/// We do a few things differently, though. We don't populate edge counts using
/// weights coming from a static branch prediction technique and we don't
/// use the same cost function.
///
/// If cost function BlameFTs is used, assign all remaining flow to
/// fall-throughs. This is used when the sampling is based on taken branches
/// that do not account for them.
void solveMCF(BinaryFunction &BF, MCFCostFunction CostFunction);
class EstimateEdgeCounts : public BinaryFunctionPass {
void runOnFunction(BinaryFunction &BF);

public:
explicit EstimateEdgeCounts(const cl::opt<bool> &PrintPass)
: BinaryFunctionPass(PrintPass) {}

const char *getName() const override { return "estimate-edge-counts"; }

/// Pass entry point
Error runOnFunctions(BinaryContext &BC) override;
};

} // end namespace bolt
} // end namespace llvm
Expand Down
4 changes: 2 additions & 2 deletions bolt/include/bolt/Passes/StokeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ struct StokeFuncInfo {
<< "," << NumBlocks << "," << IsLoopFree << "," << NumLoops << ","
<< MaxLoopDepth << "," << HotSize << "," << TotalSize << ","
<< Score << "," << HasCall << ",\"{ ";
for (std::string S : DefIn)
for (const std::string &S : DefIn)
Outfile << "%" << S << " ";
Outfile << "}\",\"{ ";
for (std::string S : LiveOut)
for (const std::string &S : LiveOut)
Outfile << "%" << S << " ";
Outfile << "}\"," << HeapOut << "," << StackOut << "," << HasRipAddr
<< "," << Omitted << "\n";
Expand Down
49 changes: 24 additions & 25 deletions bolt/include/bolt/Profile/BoltAddressTranslation.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class BinaryFunction;
class BoltAddressTranslation {
public:
// In-memory representation of the address translation table
using MapTy = std::map<uint32_t, uint32_t>;
using MapTy = std::multimap<uint32_t, uint32_t>;

// List of taken fall-throughs
using FallthroughListTy = SmallVector<std::pair<uint64_t, uint64_t>, 16>;
Expand All @@ -90,7 +90,7 @@ class BoltAddressTranslation {
std::error_code parse(raw_ostream &OS, StringRef Buf);

/// Dump the parsed address translation tables
void dump(raw_ostream &OS);
void dump(raw_ostream &OS) const;

/// If the maps are loaded in memory, perform the lookup to translate LBR
/// addresses in function located at \p FuncAddress.
Expand All @@ -107,7 +107,12 @@ class BoltAddressTranslation {

/// If available, fetch the address of the hot part linked to the cold part
/// at \p Address. Return 0 otherwise.
uint64_t fetchParentAddress(uint64_t Address) const;
uint64_t fetchParentAddress(uint64_t Address) const {
auto Iter = ColdPartSource.find(Address);
if (Iter == ColdPartSource.end())
return 0;
return Iter->second;
}

/// True if the input binary has a translation table we can use to convert
/// addresses when aggregating profile
Expand All @@ -132,7 +137,8 @@ class BoltAddressTranslation {
/// emitted for the start of the BB. More entries may be emitted to cover
/// the location of calls or any instruction that may change control flow.
void writeEntriesForBB(MapTy &Map, const BinaryBasicBlock &BB,
uint64_t FuncInputAddress, uint64_t FuncOutputAddress);
uint64_t FuncInputAddress,
uint64_t FuncOutputAddress) const;

/// Write the serialized address translation table for a function.
template <bool Cold>
Expand All @@ -147,7 +153,7 @@ class BoltAddressTranslation {

/// Returns the bitmask with set bits corresponding to indices of BRANCHENTRY
/// entries in function address translation map.
APInt calculateBranchEntriesBitMask(MapTy &Map, size_t EqualElems);
APInt calculateBranchEntriesBitMask(MapTy &Map, size_t EqualElems) const;

/// Calculate the number of equal offsets (output = input - skew) in the
/// beginning of the function.
Expand Down Expand Up @@ -178,14 +184,9 @@ class BoltAddressTranslation {
public:
/// Map basic block input offset to a basic block index and hash pair.
class BBHashMapTy {
class EntryTy {
struct EntryTy {
unsigned Index;
size_t Hash;

public:
unsigned getBBIndex() const { return Index; }
size_t getBBHash() const { return Hash; }
EntryTy(unsigned Index, size_t Hash) : Index(Index), Hash(Hash) {}
};

std::map<uint32_t, EntryTy> Map;
Expand All @@ -201,34 +202,30 @@ class BoltAddressTranslation {
}

unsigned getBBIndex(uint32_t BBInputOffset) const {
return getEntry(BBInputOffset).getBBIndex();
return getEntry(BBInputOffset).Index;
}

size_t getBBHash(uint32_t BBInputOffset) const {
return getEntry(BBInputOffset).getBBHash();
return getEntry(BBInputOffset).Hash;
}

void addEntry(uint32_t BBInputOffset, unsigned BBIndex, size_t BBHash) {
Map.emplace(BBInputOffset, EntryTy(BBIndex, BBHash));
Map.emplace(BBInputOffset, EntryTy{BBIndex, BBHash});
}

size_t getNumBasicBlocks() const { return Map.size(); }

auto begin() const { return Map.begin(); }
auto end() const { return Map.end(); }
auto upper_bound(uint32_t Offset) const { return Map.upper_bound(Offset); }
auto size() const { return Map.size(); }
};

/// Map function output address to its hash and basic blocks hash map.
class FuncHashesTy {
class EntryTy {
struct EntryTy {
size_t Hash;
BBHashMapTy BBHashMap;

public:
size_t getBFHash() const { return Hash; }
const BBHashMapTy &getBBHashMap() const { return BBHashMap; }
EntryTy(size_t Hash) : Hash(Hash) {}
};

std::unordered_map<uint64_t, EntryTy> Map;
Expand All @@ -240,23 +237,23 @@ class BoltAddressTranslation {

public:
size_t getBFHash(uint64_t FuncOutputAddress) const {
return getEntry(FuncOutputAddress).getBFHash();
return getEntry(FuncOutputAddress).Hash;
}

const BBHashMapTy &getBBHashMap(uint64_t FuncOutputAddress) const {
return getEntry(FuncOutputAddress).getBBHashMap();
return getEntry(FuncOutputAddress).BBHashMap;
}

void addEntry(uint64_t FuncOutputAddress, size_t BFHash) {
Map.emplace(FuncOutputAddress, EntryTy(BFHash));
Map.emplace(FuncOutputAddress, EntryTy{BFHash, BBHashMapTy()});
}

size_t getNumFunctions() const { return Map.size(); };

size_t getNumBasicBlocks() const {
size_t NumBasicBlocks{0};
for (auto &I : Map)
NumBasicBlocks += I.second.getBBHashMap().getNumBasicBlocks();
NumBasicBlocks += I.second.BBHashMap.getNumBasicBlocks();
return NumBasicBlocks;
}
};
Expand All @@ -278,7 +275,9 @@ class BoltAddressTranslation {

/// Returns the number of basic blocks in a function.
size_t getNumBasicBlocks(uint64_t OutputAddress) const {
return NumBasicBlocksMap.at(OutputAddress);
auto It = NumBasicBlocksMap.find(OutputAddress);
assert(It != NumBasicBlocksMap.end());
return It->second;
}

private:
Expand Down
5 changes: 4 additions & 1 deletion bolt/include/bolt/Profile/DataAggregator.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define BOLT_PROFILE_DATA_AGGREGATOR_H

#include "bolt/Profile/DataReader.h"
#include "bolt/Profile/YAMLProfileWriter.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Program.h"
Expand Down Expand Up @@ -248,7 +249,7 @@ class DataAggregator : public DataReader {
BinaryFunction *getBATParentFunction(const BinaryFunction &Func) const;

/// Retrieve the location name to be used for samples recorded in \p Func.
StringRef getLocationName(const BinaryFunction &Func) const;
static StringRef getLocationName(const BinaryFunction &Func, bool BAT);

/// Semantic actions - parser hooks to interpret parsed perf samples
/// Register a sample (non-LBR mode), i.e. a new hit at \p Address
Expand Down Expand Up @@ -490,6 +491,8 @@ class DataAggregator : public DataReader {
/// Parse the output generated by "perf buildid-list" to extract build-ids
/// and return a file name matching a given \p FileBuildID.
std::optional<StringRef> getFileNameForBuildID(StringRef FileBuildID);

friend class YAMLProfileWriter;
};
} // namespace bolt
} // namespace llvm
Expand Down
21 changes: 13 additions & 8 deletions bolt/lib/Core/BinaryContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ BinaryContext::BinaryContext(std::unique_ptr<MCContext> Ctx,
AsmInfo(std::move(AsmInfo)), MII(std::move(MII)), STI(std::move(STI)),
InstPrinter(std::move(InstPrinter)), MIA(std::move(MIA)),
MIB(std::move(MIB)), MRI(std::move(MRI)), DisAsm(std::move(DisAsm)),
Logger(Logger) {
Logger(Logger), InitialDynoStats(isAArch64()) {
Relocation::Arch = this->TheTriple->getArch();
RegularPageSize = isAArch64() ? RegularPageSizeAArch64 : RegularPageSizeX86;
PageAlign = opts::NoHugePages ? RegularPageSize : HugePageSize;
Expand Down Expand Up @@ -934,10 +934,13 @@ std::string BinaryContext::generateJumpTableName(const BinaryFunction &BF,
uint64_t Offset = 0;
if (const JumpTable *JT = BF.getJumpTableContainingAddress(Address)) {
Offset = Address - JT->getAddress();
auto Itr = JT->Labels.find(Offset);
if (Itr != JT->Labels.end())
return std::string(Itr->second->getName());
Id = JumpTableIds.at(JT->getAddress());
auto JTLabelsIt = JT->Labels.find(Offset);
if (JTLabelsIt != JT->Labels.end())
return std::string(JTLabelsIt->second->getName());

auto JTIdsIt = JumpTableIds.find(JT->getAddress());
assert(JTIdsIt != JumpTableIds.end());
Id = JTIdsIt->second;
} else {
Id = JumpTableIds[Address] = BF.JumpTables.size();
}
Expand Down Expand Up @@ -1322,7 +1325,9 @@ void BinaryContext::processInterproceduralReferences() {
InterproceduralReferences) {
BinaryFunction &Function = *It.first;
uint64_t Address = It.second;
if (!Address || Function.isIgnored())
// Process interprocedural references from ignored functions in BAT mode
// (non-simple in non-relocation mode) to properly register entry points
if (!Address || (Function.isIgnored() && !HasBATSection))
continue;

BinaryFunction *TargetFunction =
Expand Down Expand Up @@ -2212,8 +2217,8 @@ ErrorOr<uint64_t> BinaryContext::getUnsignedValueAtAddress(uint64_t Address,
return DE.getUnsigned(&ValueOffset, Size);
}

ErrorOr<uint64_t> BinaryContext::getSignedValueAtAddress(uint64_t Address,
size_t Size) const {
ErrorOr<int64_t> BinaryContext::getSignedValueAtAddress(uint64_t Address,
size_t Size) const {
const ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);
if (!Section)
return std::make_error_code(std::errc::bad_address);
Expand Down
4 changes: 3 additions & 1 deletion bolt/lib/Core/BinaryEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,9 @@ void BinaryEmitter::emitJumpTable(const JumpTable &JT, MCSection *HotSection,
// determining its destination.
std::map<MCSymbol *, uint64_t> LabelCounts;
if (opts::JumpTables > JTS_SPLIT && !JT.Counts.empty()) {
MCSymbol *CurrentLabel = JT.Labels.at(0);
auto It = JT.Labels.find(0);
assert(It != JT.Labels.end());
MCSymbol *CurrentLabel = It->second;
uint64_t CurrentLabelCount = 0;
for (unsigned Index = 0; Index < JT.Entries.size(); ++Index) {
auto LI = JT.Labels.find(Index * JT.EntrySize);
Expand Down
26 changes: 19 additions & 7 deletions bolt/lib/Core/BinaryFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,15 +851,19 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
return IndirectBranchType::UNKNOWN;
}

// RIP-relative addressing should be converted to symbol form by now
// in processed instructions (but not in jump).
if (DispExpr) {
auto getExprValue = [&](const MCExpr *Expr) {
const MCSymbol *TargetSym;
uint64_t TargetOffset;
std::tie(TargetSym, TargetOffset) = BC.MIB->getTargetSymbolInfo(DispExpr);
std::tie(TargetSym, TargetOffset) = BC.MIB->getTargetSymbolInfo(Expr);
ErrorOr<uint64_t> SymValueOrError = BC.getSymbolValue(*TargetSym);
assert(SymValueOrError && "global symbol needs a value");
ArrayStart = *SymValueOrError + TargetOffset;
assert(SymValueOrError && "Global symbol needs a value");
return *SymValueOrError + TargetOffset;
};

// RIP-relative addressing should be converted to symbol form by now
// in processed instructions (but not in jump).
if (DispExpr) {
ArrayStart = getExprValue(DispExpr);
BaseRegNum = BC.MIB->getNoRegister();
if (BC.isAArch64()) {
ArrayStart &= ~0xFFFULL;
Expand Down Expand Up @@ -1666,7 +1670,8 @@ void BinaryFunction::postProcessEntryPoints() {
// In non-relocation mode there's potentially an external undetectable
// reference to the entry point and hence we cannot move this entry
// point. Optimizing without moving could be difficult.
if (!BC.HasRelocations)
// In BAT mode, register any known entry points for CFG construction.
if (!BC.HasRelocations && !BC.HasBATSection)
setSimple(false);

const uint32_t Offset = KV.first;
Expand Down Expand Up @@ -3697,6 +3702,13 @@ BinaryFunction::BasicBlockListType BinaryFunction::dfs() const {

size_t BinaryFunction::computeHash(bool UseDFS, HashFunction HashFunction,
OperandHashFuncTy OperandHashFunc) const {
LLVM_DEBUG({
dbgs() << "BOLT-DEBUG: computeHash " << getPrintName() << ' '
<< (UseDFS ? "dfs" : "bin") << " order "
<< (HashFunction == HashFunction::StdHash ? "std::hash" : "xxh3")
<< '\n';
});

if (size() == 0)
return 0;

Expand Down
4 changes: 2 additions & 2 deletions bolt/lib/Core/DebugNames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ void DWARF5AcceleratorTable::addUnit(DWARFUnit &Unit,
// Returns true if DW_TAG_variable should be included in .debug-names based on
// section 6.1.1.1 for DWARF5 spec.
static bool shouldIncludeVariable(const DWARFUnit &Unit, const DIE &Die) {
if (Die.findAttribute(dwarf::Attribute::DW_AT_declaration))
return false;
const DIEValue LocAttrInfo =
Die.findAttribute(dwarf::Attribute::DW_AT_location);
if (!LocAttrInfo)
Expand Down Expand Up @@ -148,6 +146,8 @@ static bool shouldIncludeVariable(const DWARFUnit &Unit, const DIE &Die) {

bool static canProcess(const DWARFUnit &Unit, const DIE &Die,
std::string &NameToUse, const bool TagsOnly) {
if (Die.findAttribute(dwarf::Attribute::DW_AT_declaration))
return false;
switch (Die.getTag()) {
case dwarf::DW_TAG_base_type:
case dwarf::DW_TAG_class_type:
Expand Down
5 changes: 3 additions & 2 deletions bolt/lib/Core/DynoStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ void DynoStats::print(raw_ostream &OS, const DynoStats *Other,
for (auto &Stat : llvm::reverse(SortedHistogram)) {
OS << format("%20s,%'18lld", Printer->getOpcodeName(Stat.second).data(),
Stat.first * opts::DynoStatsScale);

MaxOpcodeHistogramTy MaxMultiMap = OpcodeHistogram.at(Stat.second).second;
auto It = OpcodeHistogram.find(Stat.second);
assert(It != OpcodeHistogram.end());
MaxOpcodeHistogramTy MaxMultiMap = It->second.second;
// Start with function name:BB offset with highest execution count.
for (auto &Max : llvm::reverse(MaxMultiMap)) {
OS << format(", %'18lld, ", Max.first * opts::DynoStatsScale)
Expand Down
4 changes: 3 additions & 1 deletion bolt/lib/Passes/BinaryFunctionCallGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ std::deque<BinaryFunction *> BinaryFunctionCallGraph::buildTraversalOrder() {
std::stack<NodeId> Worklist;

for (BinaryFunction *Func : Funcs) {
const NodeId Id = FuncToNodeId.at(Func);
auto It = FuncToNodeId.find(Func);
assert(It != FuncToNodeId.end());
const NodeId Id = It->second;
Worklist.push(Id);
NodeStatus[Id] = NEW;
}
Expand Down
65 changes: 42 additions & 23 deletions bolt/lib/Passes/BinaryPasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,8 @@ static uint64_t fixDoubleJumps(BinaryFunction &Function, bool MarkInvalid) {
MCPlusBuilder *MIB = Function.getBinaryContext().MIB.get();
for (BinaryBasicBlock &BB : Function) {
auto checkAndPatch = [&](BinaryBasicBlock *Pred, BinaryBasicBlock *Succ,
const MCSymbol *SuccSym) {
const MCSymbol *SuccSym,
std::optional<uint32_t> Offset) {
// Ignore infinite loop jumps or fallthrough tail jumps.
if (Pred == Succ || Succ == &BB)
return false;
Expand Down Expand Up @@ -715,9 +716,11 @@ static uint64_t fixDoubleJumps(BinaryFunction &Function, bool MarkInvalid) {
Pred->removeSuccessor(&BB);
Pred->eraseInstruction(Pred->findInstruction(Branch));
Pred->addTailCallInstruction(SuccSym);
MCInst *TailCall = Pred->getLastNonPseudoInstr();
assert(TailCall);
MIB->setOffset(*TailCall, BB.getOffset());
if (Offset) {
MCInst *TailCall = Pred->getLastNonPseudoInstr();
assert(TailCall);
MIB->setOffset(*TailCall, *Offset);
}
} else {
return false;
}
Expand Down Expand Up @@ -760,7 +763,8 @@ static uint64_t fixDoubleJumps(BinaryFunction &Function, bool MarkInvalid) {
if (Pred->getSuccessor() == &BB ||
(Pred->getConditionalSuccessor(true) == &BB && !IsTailCall) ||
Pred->getConditionalSuccessor(false) == &BB)
if (checkAndPatch(Pred, Succ, SuccSym) && MarkInvalid)
if (checkAndPatch(Pred, Succ, SuccSym, MIB->getOffset(*Inst)) &&
MarkInvalid)
BB.markValid(BB.pred_size() != 0 || BB.isLandingPad() ||
BB.isEntryPoint());
}
Expand Down Expand Up @@ -1386,9 +1390,19 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) {
if (Function.isPLTFunction())
continue;

// Adjustment for BAT mode: the profile for BOLT split fragments is combined
// so only count the hot fragment.
const uint64_t Address = Function.getAddress();
bool IsHotParentOfBOLTSplitFunction = !Function.getFragments().empty() &&
BAT && BAT->isBATFunction(Address) &&
!BAT->fetchParentAddress(Address);

++NumRegularFunctions;

if (!Function.isSimple()) {
// In BOLTed binaries split functions are non-simple (due to non-relocation
// mode), but the original function is known to be simple and we have a
// valid profile for it.
if (!Function.isSimple() && !IsHotParentOfBOLTSplitFunction) {
if (Function.hasProfile())
++NumNonSimpleProfiledFunctions;
continue;
Expand Down Expand Up @@ -1549,23 +1563,28 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) {
const bool Ascending =
opts::DynoStatsSortOrderOpt == opts::DynoStatsSortOrder::Ascending;

if (SortAll) {
llvm::stable_sort(Functions,
[Ascending, &Stats](const BinaryFunction *A,
const BinaryFunction *B) {
return Ascending ? Stats.at(A) < Stats.at(B)
: Stats.at(B) < Stats.at(A);
});
} else {
llvm::stable_sort(
Functions, [Ascending, &Stats](const BinaryFunction *A,
const BinaryFunction *B) {
const DynoStats &StatsA = Stats.at(A);
const DynoStats &StatsB = Stats.at(B);
return Ascending ? StatsA.lessThan(StatsB, opts::PrintSortedBy)
: StatsB.lessThan(StatsA, opts::PrintSortedBy);
});
}
std::function<bool(const DynoStats &, const DynoStats &)>
DynoStatsComparator =
SortAll ? [](const DynoStats &StatsA,
const DynoStats &StatsB) { return StatsA < StatsB; }
: [](const DynoStats &StatsA, const DynoStats &StatsB) {
return StatsA.lessThan(StatsB, opts::PrintSortedBy);
};

llvm::stable_sort(Functions,
[Ascending, &Stats, DynoStatsComparator](
const BinaryFunction *A, const BinaryFunction *B) {
auto StatsItr = Stats.find(A);
assert(StatsItr != Stats.end());
const DynoStats &StatsA = StatsItr->second;

StatsItr = Stats.find(B);
assert(StatsItr != Stats.end());
const DynoStats &StatsB = StatsItr->second;

return Ascending ? DynoStatsComparator(StatsA, StatsB)
: DynoStatsComparator(StatsB, StatsA);
});

BC.outs() << "BOLT-INFO: top functions sorted by ";
if (SortAll) {
Expand Down
43 changes: 33 additions & 10 deletions bolt/lib/Passes/CacheMetrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,20 @@ calcTSPScore(const std::vector<BinaryFunction *> &BinaryFunctions,
for (BinaryBasicBlock *DstBB : SrcBB->successors()) {
if (SrcBB != DstBB && BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE) {
JumpCount += BI->Count;
if (BBAddr.at(SrcBB) + BBSize.at(SrcBB) == BBAddr.at(DstBB))

auto BBAddrIt = BBAddr.find(SrcBB);
assert(BBAddrIt != BBAddr.end());
uint64_t SrcBBAddr = BBAddrIt->second;

auto BBSizeIt = BBSize.find(SrcBB);
assert(BBSizeIt != BBSize.end());
uint64_t SrcBBSize = BBSizeIt->second;

BBAddrIt = BBAddr.find(DstBB);
assert(BBAddrIt != BBAddr.end());
uint64_t DstBBAddr = BBAddrIt->second;

if (SrcBBAddr + SrcBBSize == DstBBAddr)
Score += BI->Count;
}
++BI;
Expand Down Expand Up @@ -149,29 +162,39 @@ double expectedCacheHitRatio(
for (BinaryFunction *BF : BinaryFunctions) {
if (BF->getLayout().block_empty())
continue;
const uint64_t Page =
BBAddr.at(BF->getLayout().block_front()) / ITLBPageSize;
PageSamples[Page] += FunctionSamples.at(BF);
auto BBAddrIt = BBAddr.find(BF->getLayout().block_front());
assert(BBAddrIt != BBAddr.end());
const uint64_t Page = BBAddrIt->second / ITLBPageSize;

auto FunctionSamplesIt = FunctionSamples.find(BF);
assert(FunctionSamplesIt != FunctionSamples.end());
PageSamples[Page] += FunctionSamplesIt->second;
}

// Computing the expected number of misses for every function
double Misses = 0;
for (BinaryFunction *BF : BinaryFunctions) {
// Skip the function if it has no samples
if (BF->getLayout().block_empty() || FunctionSamples.at(BF) == 0.0)
auto FunctionSamplesIt = FunctionSamples.find(BF);
assert(FunctionSamplesIt != FunctionSamples.end());
double Samples = FunctionSamplesIt->second;
if (BF->getLayout().block_empty() || Samples == 0.0)
continue;
double Samples = FunctionSamples.at(BF);
const uint64_t Page =
BBAddr.at(BF->getLayout().block_front()) / ITLBPageSize;

auto BBAddrIt = BBAddr.find(BF->getLayout().block_front());
assert(BBAddrIt != BBAddr.end());
const uint64_t Page = BBAddrIt->second / ITLBPageSize;
// The probability that the page is not present in the cache
const double MissProb =
pow(1.0 - PageSamples[Page] / TotalSamples, ITLBEntries);

// Processing all callers of the function
for (std::pair<BinaryFunction *, uint64_t> Pair : Calls[BF]) {
BinaryFunction *SrcFunction = Pair.first;
const uint64_t SrcPage =
BBAddr.at(SrcFunction->getLayout().block_front()) / ITLBPageSize;

BBAddrIt = BBAddr.find(SrcFunction->getLayout().block_front());
assert(BBAddrIt != BBAddr.end());
const uint64_t SrcPage = BBAddrIt->second / ITLBPageSize;
// Is this a 'long' or a 'short' call?
if (Page != SrcPage) {
// This is a miss
Expand Down
4 changes: 3 additions & 1 deletion bolt/lib/Passes/Inliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,9 @@ Inliner::inlineCall(BinaryBasicBlock &CallerBB,
std::vector<BinaryBasicBlock *> Successors(BB.succ_size());
llvm::transform(BB.successors(), Successors.begin(),
[&InlinedBBMap](const BinaryBasicBlock *BB) {
return InlinedBBMap.at(BB);
auto It = InlinedBBMap.find(BB);
assert(It != InlinedBBMap.end());
return It->second;
});

if (CallerFunction.hasValidProfile() && Callee.hasValidProfile())
Expand Down
33 changes: 21 additions & 12 deletions bolt/lib/Passes/MCF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@

#include "bolt/Passes/MCF.h"
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Core/ParallelUtilities.h"
#include "bolt/Passes/DataflowInfoManager.h"
#include "bolt/Utils/CommandLineOpts.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
#include <algorithm>
#include <vector>
Expand All @@ -29,19 +31,10 @@ namespace opts {

extern cl::OptionCategory BoltOptCategory;

extern cl::opt<bool> TimeOpts;

static cl::opt<bool> IterativeGuess(
"iterative-guess",
cl::desc("in non-LBR mode, guess edge counts using iterative technique"),
cl::Hidden, cl::cat(BoltOptCategory));

static cl::opt<bool> UseRArcs(
"mcf-use-rarcs",
cl::desc("in MCF, consider the possibility of cancelling flow to balance "
"edges"),
cl::Hidden, cl::cat(BoltOptCategory));

} // namespace opts

namespace llvm {
Expand Down Expand Up @@ -441,7 +434,7 @@ void equalizeBBCounts(DataflowInfoManager &Info, BinaryFunction &BF) {
}
}

void estimateEdgeCounts(BinaryFunction &BF) {
void EstimateEdgeCounts::runOnFunction(BinaryFunction &BF) {
EdgeWeightMap PredEdgeWeights;
EdgeWeightMap SuccEdgeWeights;
if (!opts::IterativeGuess) {
Expand All @@ -462,8 +455,24 @@ void estimateEdgeCounts(BinaryFunction &BF) {
recalculateBBCounts(BF, /*AllEdges=*/false);
}

void solveMCF(BinaryFunction &BF, MCFCostFunction CostFunction) {
llvm_unreachable("not implemented");
Error EstimateEdgeCounts::runOnFunctions(BinaryContext &BC) {
if (llvm::none_of(llvm::make_second_range(BC.getBinaryFunctions()),
[](const BinaryFunction &BF) {
return BF.getProfileFlags() == BinaryFunction::PF_SAMPLE;
}))
return Error::success();

ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
runOnFunction(BF);
};
ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) {
return BF.getProfileFlags() != BinaryFunction::PF_SAMPLE;
};

ParallelUtilities::runOnEachFunction(
BC, ParallelUtilities::SchedulingPolicy::SP_BB_QUADRATIC, WorkFun,
SkipFunc, "EstimateEdgeCounts");
return Error::success();
}

} // namespace bolt
Expand Down
50 changes: 29 additions & 21 deletions bolt/lib/Profile/BoltAddressTranslation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ namespace bolt {

const char *BoltAddressTranslation::SECTION_NAME = ".note.bolt_bat";

void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
const BinaryBasicBlock &BB,
uint64_t FuncInputAddress,
uint64_t FuncOutputAddress) {
void BoltAddressTranslation::writeEntriesForBB(
MapTy &Map, const BinaryBasicBlock &BB, uint64_t FuncInputAddress,
uint64_t FuncOutputAddress) const {
const uint64_t BBOutputOffset =
BB.getOutputAddressRange().first - FuncOutputAddress;
const uint32_t BBInputOffset = BB.getInputOffset();
Expand Down Expand Up @@ -55,7 +54,7 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
// and this deleted block will both share the same output address (the same
// key), and we need to map back. We choose here to privilege the successor by
// allowing it to overwrite the previously inserted key in the map.
Map[BBOutputOffset] = BBInputOffset << 1;
Map.emplace(BBOutputOffset, BBInputOffset << 1);

const auto &IOAddressMap =
BB.getFunction()->getBinaryContext().getIOAddressMap();
Expand All @@ -72,8 +71,7 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,

LLVM_DEBUG(dbgs() << " Key: " << Twine::utohexstr(OutputOffset) << " Val: "
<< Twine::utohexstr(InputOffset) << " (branch)\n");
Map.insert(std::pair<uint32_t, uint32_t>(OutputOffset,
(InputOffset << 1) | BRANCHENTRY));
Map.emplace(OutputOffset, (InputOffset << 1) | BRANCHENTRY);
}
}

Expand Down Expand Up @@ -108,6 +106,19 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
for (const BinaryBasicBlock *const BB :
Function.getLayout().getMainFragment())
writeEntriesForBB(Map, *BB, InputAddress, OutputAddress);
// Add entries for deleted blocks. They are still required for correct BB
// mapping of branches modified by SCTC. By convention, they would have the
// end of the function as output address.
const BBHashMapTy &BBHashMap = getBBHashMap(InputAddress);
if (BBHashMap.size() != Function.size()) {
const uint64_t EndOffset = Function.getOutputSize();
std::unordered_set<uint32_t> MappedInputOffsets;
for (const BinaryBasicBlock &BB : Function)
MappedInputOffsets.emplace(BB.getInputOffset());
for (const auto &[InputOffset, _] : BBHashMap)
if (!llvm::is_contained(MappedInputOffsets, InputOffset))
Map.emplace(EndOffset, InputOffset << 1);
}
Maps.emplace(Function.getOutputAddress(), std::move(Map));
ReverseMap.emplace(OutputAddress, InputAddress);

Expand Down Expand Up @@ -138,8 +149,8 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
<< " basic block hashes\n";
}

APInt BoltAddressTranslation::calculateBranchEntriesBitMask(MapTy &Map,
size_t EqualElems) {
APInt BoltAddressTranslation::calculateBranchEntriesBitMask(
MapTy &Map, size_t EqualElems) const {
APInt BitMask(alignTo(EqualElems, 8), 0);
size_t Index = 0;
for (std::pair<const uint32_t, uint32_t> &KeyVal : Map) {
Expand Down Expand Up @@ -422,7 +433,7 @@ void BoltAddressTranslation::parseMaps(std::vector<uint64_t> &HotFuncs,
}
}

void BoltAddressTranslation::dump(raw_ostream &OS) {
void BoltAddressTranslation::dump(raw_ostream &OS) const {
const size_t NumTables = Maps.size();
OS << "BAT tables for " << NumTables << " functions:\n";
for (const auto &MapEntry : Maps) {
Expand All @@ -447,11 +458,15 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
OS << formatv(" hash: {0:x}", BBHashMap.getBBHash(Val));
OS << "\n";
}
if (IsHotFunction)
OS << "NumBlocks: " << NumBasicBlocksMap[Address] << '\n';
if (SecondaryEntryPointsMap.count(Address)) {
if (IsHotFunction) {
auto NumBasicBlocksIt = NumBasicBlocksMap.find(Address);
assert(NumBasicBlocksIt != NumBasicBlocksMap.end());
OS << "NumBlocks: " << NumBasicBlocksIt->second << '\n';
}
auto SecondaryEntryPointsIt = SecondaryEntryPointsMap.find(Address);
if (SecondaryEntryPointsIt != SecondaryEntryPointsMap.end()) {
const std::vector<uint32_t> &SecondaryEntryPoints =
SecondaryEntryPointsMap[Address];
SecondaryEntryPointsIt->second;
OS << SecondaryEntryPoints.size() << " secondary entry points:\n";
for (uint32_t EntryPointOffset : SecondaryEntryPoints)
OS << formatv("{0:x}\n", EntryPointOffset);
Expand Down Expand Up @@ -547,13 +562,6 @@ BoltAddressTranslation::getFallthroughsInTrace(uint64_t FuncAddress,
return Res;
}

uint64_t BoltAddressTranslation::fetchParentAddress(uint64_t Address) const {
auto Iter = ColdPartSource.find(Address);
if (Iter == ColdPartSource.end())
return 0;
return Iter->second;
}

bool BoltAddressTranslation::enabledFor(
llvm::object::ELFObjectFileBase *InputFile) const {
for (const SectionRef &Section : InputFile->sections()) {
Expand Down
1 change: 0 additions & 1 deletion bolt/lib/Profile/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,5 @@ add_llvm_library(LLVMBOLTProfile
target_link_libraries(LLVMBOLTProfile
PRIVATE
LLVMBOLTCore
LLVMBOLTPasses
LLVMBOLTUtils
)
28 changes: 14 additions & 14 deletions bolt/lib/Profile/DataAggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,6 @@ Error DataAggregator::readProfile(BinaryContext &BC) {
if (std::error_code EC = writeBATYAML(BC, opts::SaveProfile))
report_error("cannot create output data file", EC);
}
BC.logBOLTErrorsAndQuitOnFatal(PrintProgramStats().runOnFunctions(BC));
}

return Error::success();
Expand Down Expand Up @@ -673,7 +672,8 @@ DataAggregator::getBATParentFunction(const BinaryFunction &Func) const {
return nullptr;
}

StringRef DataAggregator::getLocationName(const BinaryFunction &Func) const {
StringRef DataAggregator::getLocationName(const BinaryFunction &Func,
bool BAT) {
if (!BAT)
return Func.getOneName();

Expand Down Expand Up @@ -702,7 +702,7 @@ bool DataAggregator::doSample(BinaryFunction &OrigFunc, uint64_t Address,
auto I = NamesToSamples.find(Func.getOneName());
if (I == NamesToSamples.end()) {
bool Success;
StringRef LocName = getLocationName(Func);
StringRef LocName = getLocationName(Func, BAT);
std::tie(I, Success) = NamesToSamples.insert(
std::make_pair(Func.getOneName(),
FuncSampleData(LocName, FuncSampleData::ContainerTy())));
Expand All @@ -722,7 +722,7 @@ bool DataAggregator::doIntraBranch(BinaryFunction &Func, uint64_t From,
FuncBranchData *AggrData = getBranchData(Func);
if (!AggrData) {
AggrData = &NamesToBranches[Func.getOneName()];
AggrData->Name = getLocationName(Func);
AggrData->Name = getLocationName(Func, BAT);
setBranchData(Func, AggrData);
}

Expand All @@ -741,7 +741,7 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,
StringRef SrcFunc;
StringRef DstFunc;
if (FromFunc) {
SrcFunc = getLocationName(*FromFunc);
SrcFunc = getLocationName(*FromFunc, BAT);
FromAggrData = getBranchData(*FromFunc);
if (!FromAggrData) {
FromAggrData = &NamesToBranches[FromFunc->getOneName()];
Expand All @@ -752,7 +752,7 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,
recordExit(*FromFunc, From, Mispreds, Count);
}
if (ToFunc) {
DstFunc = getLocationName(*ToFunc);
DstFunc = getLocationName(*ToFunc, BAT);
ToAggrData = getBranchData(*ToFunc);
if (!ToAggrData) {
ToAggrData = &NamesToBranches[ToFunc->getOneName()];
Expand Down Expand Up @@ -1227,7 +1227,7 @@ ErrorOr<Location> DataAggregator::parseLocationOrOffset() {
if (Sep == StringRef::npos)
return parseOffset();
StringRef LookAhead = ParsingBuf.substr(0, Sep);
if (LookAhead.find_first_of(":") == StringRef::npos)
if (!LookAhead.contains(':'))
return parseOffset();

ErrorOr<StringRef> BuildID = parseString(':');
Expand Down Expand Up @@ -2340,7 +2340,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
continue;
BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncAddress);
assert(BF);
YamlBF.Name = getLocationName(*BF);
YamlBF.Name = getLocationName(*BF, BAT);
YamlBF.Id = BF->getFunctionNumber();
YamlBF.Hash = BAT->getBFHash(FuncAddress);
YamlBF.ExecCount = BF->getKnownExecutionCount();
Expand All @@ -2349,11 +2349,11 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
BAT->getBBHashMap(FuncAddress);
YamlBF.Blocks.resize(YamlBF.NumBasicBlocks);

for (auto &&[Idx, YamlBB] : llvm::enumerate(YamlBF.Blocks))
YamlBB.Index = Idx;

for (auto BI = BlockMap.begin(), BE = BlockMap.end(); BI != BE; ++BI)
YamlBF.Blocks[BI->second.getBBIndex()].Hash = BI->second.getBBHash();
for (auto &&[Entry, YamlBB] : llvm::zip(BlockMap, YamlBF.Blocks)) {
const auto &Block = Entry.second;
YamlBB.Hash = Block.Hash;
YamlBB.Index = Block.Index;
}

// Lookup containing basic block offset and index
auto getBlock = [&BlockMap](uint32_t Offset) {
Expand All @@ -2363,7 +2363,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
exit(1);
}
--BlockIt;
return std::pair(BlockIt->first, BlockIt->second.getBBIndex());
return std::pair(BlockIt->first, BlockIt->second.Index);
};

for (const BranchInfo &BI : Branches.Data) {
Expand Down
2 changes: 0 additions & 2 deletions bolt/lib/Profile/DataReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,6 @@ void DataReader::readSampleData(BinaryFunction &BF) {
}

BF.ExecutionCount = TotalEntryCount;

estimateEdgeCounts(BF);
}

void DataReader::convertBranchData(BinaryFunction &BF) const {
Expand Down
12 changes: 10 additions & 2 deletions bolt/lib/Profile/StaleProfileMatching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "llvm/ADT/Bitfields.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/xxhash.h"
#include "llvm/Transforms/Utils/SampleProfileInference.h"

Expand All @@ -42,6 +43,7 @@ using namespace llvm;

namespace opts {

extern cl::opt<bool> TimeRewrite;
extern cl::OptionCategory BoltOptCategory;

cl::opt<bool>
Expand Down Expand Up @@ -372,8 +374,10 @@ createFlowFunction(const BinaryFunction::BasicBlockOrderType &BlockOrder) {

// Create necessary metadata for the flow function
for (FlowJump &Jump : Func.Jumps) {
Func.Blocks.at(Jump.Source).SuccJumps.push_back(&Jump);
Func.Blocks.at(Jump.Target).PredJumps.push_back(&Jump);
assert(Jump.Source < Func.Blocks.size());
Func.Blocks[Jump.Source].SuccJumps.push_back(&Jump);
assert(Jump.Target < Func.Blocks.size());
Func.Blocks[Jump.Target].PredJumps.push_back(&Jump);
}
return Func;
}
Expand Down Expand Up @@ -705,6 +709,10 @@ void assignProfile(BinaryFunction &BF,

bool YAMLProfileReader::inferStaleProfile(
BinaryFunction &BF, const yaml::bolt::BinaryFunctionProfile &YamlBF) {

NamedRegionTimer T("inferStaleProfile", "stale profile inference", "rewrite",
"Rewrite passes", opts::TimeRewrite);

if (!BF.hasCFG())
return false;

Expand Down
20 changes: 12 additions & 8 deletions bolt/lib/Profile/YAMLProfileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,17 @@ bool YAMLProfileReader::parseFunctionProfile(
FuncRawBranchCount += YamlSI.Count;
BF.setRawBranchCount(FuncRawBranchCount);

if (!opts::IgnoreHash &&
YamlBF.Hash != BF.computeHash(IsDFSOrder, HashFunction)) {
if (opts::Verbosity >= 1)
errs() << "BOLT-WARNING: function hash mismatch\n";
ProfileMatched = false;
if (BF.empty())
return true;

if (!opts::IgnoreHash) {
if (!BF.getHash())
BF.computeHash(IsDFSOrder, HashFunction);
if (YamlBF.Hash != BF.getHash()) {
if (opts::Verbosity >= 1)
errs() << "BOLT-WARNING: function hash mismatch\n";
ProfileMatched = false;
}
}

if (YamlBF.NumBasicBlocks != BF.size()) {
Expand Down Expand Up @@ -250,10 +256,8 @@ bool YAMLProfileReader::parseFunctionProfile(
if (BB.getExecutionCount() == BinaryBasicBlock::COUNT_NO_PROFILE)
BB.setExecutionCount(0);

if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE) {
if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE)
BF.setExecutionCount(FunctionExecutionCount);
estimateEdgeCounts(BF);
}

ProfileMatched &= !MismatchedBlocks && !MismatchedCalls && !MismatchedEdges;

Expand Down
7 changes: 6 additions & 1 deletion bolt/lib/Profile/YAMLProfileWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "bolt/Core/BinaryBasicBlock.h"
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Profile/BoltAddressTranslation.h"
#include "bolt/Profile/DataAggregator.h"
#include "bolt/Profile/ProfileReaderBase.h"
#include "bolt/Rewrite/RewriteInstance.h"
#include "llvm/Support/CommandLine.h"
Expand Down Expand Up @@ -39,6 +40,10 @@ const BinaryFunction *YAMLProfileWriter::setCSIDestination(
BC.getFunctionForSymbol(Symbol, &EntryID)) {
if (BAT && BAT->isBATFunction(Callee->getAddress()))
std::tie(Callee, EntryID) = BAT->translateSymbol(BC, *Symbol, Offset);
else if (const BinaryBasicBlock *BB =
Callee->getBasicBlockContainingOffset(Offset))
BC.getFunctionForSymbol(Callee->getSecondaryEntryPointSymbol(*BB),
&EntryID);
CSI.DestId = Callee->getFunctionNumber();
CSI.EntryDiscriminator = EntryID;
return Callee;
Expand All @@ -59,7 +64,7 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS,
BF.computeHash(UseDFS);
BF.computeBlockHashes();

YamlBF.Name = BF.getPrintName();
YamlBF.Name = DataAggregator::getLocationName(BF, BAT);
YamlBF.Id = BF.getFunctionNumber();
YamlBF.Hash = BF.getHash();
YamlBF.NumBasicBlocks = BF.size();
Expand Down
19 changes: 13 additions & 6 deletions bolt/lib/Rewrite/BinaryPassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "bolt/Passes/JTFootprintReduction.h"
#include "bolt/Passes/LongJmp.h"
#include "bolt/Passes/LoopInversionPass.h"
#include "bolt/Passes/MCF.h"
#include "bolt/Passes/PLTCall.h"
#include "bolt/Passes/PatchEntries.h"
#include "bolt/Passes/RegReAssign.h"
Expand Down Expand Up @@ -90,6 +91,11 @@ PrintAfterLowering("print-after-lowering",
cl::desc("print function after instruction lowering"),
cl::Hidden, cl::cat(BoltOptCategory));

static cl::opt<bool> PrintEstimateEdgeCounts(
"print-estimate-edge-counts",
cl::desc("print function after edge counts are set for no-LBR profile"),
cl::Hidden, cl::cat(BoltOptCategory));

cl::opt<bool>
PrintFinalized("print-finalized",
cl::desc("print function after CFG is finalized"),
Expand Down Expand Up @@ -334,8 +340,10 @@ Error BinaryFunctionPassManager::runPasses() {
Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
BinaryFunctionPassManager Manager(BC);

const DynoStats InitialDynoStats =
getDynoStats(BC.getBinaryFunctions(), BC.isAArch64());
Manager.registerPass(
std::make_unique<EstimateEdgeCounts>(PrintEstimateEdgeCounts));

Manager.registerPass(std::make_unique<DynoStatsSetPass>());

Manager.registerPass(std::make_unique<AsmDumpPass>(),
opts::AsmDump.getNumOccurrences());
Expand Down Expand Up @@ -447,10 +455,9 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
Manager.registerPass(std::make_unique<SplitFunctions>(PrintSplit));

// Print final dyno stats right while CFG and instruction analysis are intact.
Manager.registerPass(
std::make_unique<DynoStatsPrintPass>(
InitialDynoStats, "after all optimizations before SCTC and FOP"),
opts::PrintDynoStats || opts::DynoStatsAll);
Manager.registerPass(std::make_unique<DynoStatsPrintPass>(
"after all optimizations before SCTC and FOP"),
opts::PrintDynoStats || opts::DynoStatsAll);

// Add the StokeInfo pass, which extract functions for stoke optimization and
// get the liveness information for them
Expand Down
3 changes: 1 addition & 2 deletions bolt/lib/Rewrite/DWARFRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ static void printDie(DWARFUnit &DU, uint64_t DIEOffset) {
DWARFDataExtractor DebugInfoData = DU.getDebugInfoExtractor();
DWARFDebugInfoEntry DIEEntry;
if (DIEEntry.extractFast(DU, &DIEOffset, DebugInfoData, NextCUOffset, 0)) {
if (const DWARFAbbreviationDeclaration *AbbrDecl =
DIEEntry.getAbbreviationDeclarationPtr()) {
if (DIEEntry.getAbbreviationDeclarationPtr()) {
DWARFDie DDie(&DU, &DIEEntry);
printDie(DDie);
} else {
Expand Down
2 changes: 1 addition & 1 deletion bolt/lib/Rewrite/LinuxKernelRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ void LinuxKernelRewriter::processLKKSymtab(bool IsGPL) {

for (uint64_t I = 0; I < SectionSize; I += 4) {
const uint64_t EntryAddress = SectionAddress + I;
ErrorOr<uint64_t> Offset = BC.getSignedValueAtAddress(EntryAddress, 4);
ErrorOr<int64_t> Offset = BC.getSignedValueAtAddress(EntryAddress, 4);
assert(Offset && "Reading valid PC-relative offset for a ksymtab entry");
const int32_t SignedOffset = *Offset;
const uint64_t RefAddress = EntryAddress + SignedOffset;
Expand Down
83 changes: 47 additions & 36 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "bolt/Core/MCPlusBuilder.h"
#include "bolt/Core/ParallelUtilities.h"
#include "bolt/Core/Relocation.h"
#include "bolt/Passes/BinaryPasses.h"
#include "bolt/Passes/CacheMetrics.h"
#include "bolt/Passes/ReorderFunctions.h"
#include "bolt/Profile/BoltAddressTranslation.h"
Expand Down Expand Up @@ -86,6 +87,7 @@ extern cl::list<std::string> ReorderData;
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
extern cl::opt<bool> TerminalTrap;
extern cl::opt<bool> TimeBuild;
extern cl::opt<bool> TimeRewrite;

cl::opt<bool> AllowStripped("allow-stripped",
cl::desc("allow processing of stripped binaries"),
Expand Down Expand Up @@ -235,11 +237,6 @@ UseGnuStack("use-gnu-stack",
cl::ZeroOrMore,
cl::cat(BoltCategory));

static cl::opt<bool>
TimeRewrite("time-rewrite",
cl::desc("print time spent in rewriting passes"), cl::Hidden,
cl::cat(BoltCategory));

static cl::opt<bool>
SequentialDisassembly("sequential-disassembly",
cl::desc("performs disassembly sequentially"),
Expand Down Expand Up @@ -1500,7 +1497,7 @@ void RewriteInstance::registerFragments() {
if (!BC->hasSymbolsWithFileName()) {
BC->errs() << "BOLT-ERROR: input file has split functions but does not "
"have FILE symbols. If the binary was stripped, preserve "
"FILE symbols with --keep-file-symbols strip option";
"FILE symbols with --keep-file-symbols strip option\n";
exit(1);
}

Expand Down Expand Up @@ -1988,6 +1985,7 @@ Error RewriteInstance::readSpecialSections() {

if (ErrorOr<BinarySection &> BATSec =
BC->getUniqueSectionByName(BoltAddressTranslation::SECTION_NAME)) {
BC->HasBATSection = true;
// Do not read BAT when plotting a heatmap
if (!opts::HeatmapMode) {
if (std::error_code EC = BAT->parse(BC->outs(), BATSec->getContents())) {
Expand Down Expand Up @@ -3208,12 +3206,14 @@ void RewriteInstance::preprocessProfileData() {
if (Error E = ProfileReader->preprocessProfile(*BC.get()))
report_error("cannot pre-process profile", std::move(E));

if (!BC->hasSymbolsWithFileName() && ProfileReader->hasLocalsWithFileName()) {
if (!BC->hasSymbolsWithFileName() && ProfileReader->hasLocalsWithFileName() &&
!opts::AllowStripped) {
BC->errs()
<< "BOLT-ERROR: input binary does not have local file symbols "
"but profile data includes function names with embedded file "
"names. It appears that the input binary was stripped while a "
"profiled binary was not\n";
"profiled binary was not. If you know what you are doing and "
"wish to proceed, use -allow-stripped option.\n";
exit(1);
}
}
Expand Down Expand Up @@ -3284,8 +3284,11 @@ void RewriteInstance::processProfileData() {
// Release memory used by profile reader.
ProfileReader.reset();

if (opts::AggregateOnly)
if (opts::AggregateOnly) {
PrintProgramStats PPS(&*BAT);
BC->logBOLTErrorsAndQuitOnFatal(PPS.runOnFunctions(*BC));
exit(0);
}
}

void RewriteInstance::disassembleFunctions() {
Expand Down Expand Up @@ -4808,6 +4811,40 @@ void RewriteInstance::updateELFSymbolTable(
// Create a new symbol based on the existing symbol.
ELFSymTy NewSymbol = Symbol;

// Handle special symbols based on their name.
Expected<StringRef> SymbolName = Symbol.getName(StringSection);
assert(SymbolName && "cannot get symbol name");

auto updateSymbolValue = [&](const StringRef Name,
std::optional<uint64_t> Value = std::nullopt) {
NewSymbol.st_value = Value ? *Value : getNewValueForSymbol(Name);
NewSymbol.st_shndx = ELF::SHN_ABS;
BC->outs() << "BOLT-INFO: setting " << Name << " to 0x"
<< Twine::utohexstr(NewSymbol.st_value) << '\n';
};

if (*SymbolName == "__hot_start" || *SymbolName == "__hot_end") {
if (opts::HotText) {
updateSymbolValue(*SymbolName);
++NumHotTextSymsUpdated;
}
goto registerSymbol;
}

if (*SymbolName == "__hot_data_start" || *SymbolName == "__hot_data_end") {
if (opts::HotData) {
updateSymbolValue(*SymbolName);
++NumHotDataSymsUpdated;
}
goto registerSymbol;
}

if (*SymbolName == "_end") {
if (NextAvailableAddress > Symbol.st_value)
updateSymbolValue(*SymbolName, NextAvailableAddress);
goto registerSymbol;
}

if (Function) {
// If the symbol matched a function that was not emitted, update the
// corresponding section index but otherwise leave it unchanged.
Expand Down Expand Up @@ -4904,33 +4941,7 @@ void RewriteInstance::updateELFSymbolTable(
}
}

// Handle special symbols based on their name.
Expected<StringRef> SymbolName = Symbol.getName(StringSection);
assert(SymbolName && "cannot get symbol name");

auto updateSymbolValue = [&](const StringRef Name,
std::optional<uint64_t> Value = std::nullopt) {
NewSymbol.st_value = Value ? *Value : getNewValueForSymbol(Name);
NewSymbol.st_shndx = ELF::SHN_ABS;
BC->outs() << "BOLT-INFO: setting " << Name << " to 0x"
<< Twine::utohexstr(NewSymbol.st_value) << '\n';
};

if (opts::HotText &&
(*SymbolName == "__hot_start" || *SymbolName == "__hot_end")) {
updateSymbolValue(*SymbolName);
++NumHotTextSymsUpdated;
}

if (opts::HotData && (*SymbolName == "__hot_data_start" ||
*SymbolName == "__hot_data_end")) {
updateSymbolValue(*SymbolName);
++NumHotDataSymsUpdated;
}

if (*SymbolName == "_end" && NextAvailableAddress > Symbol.st_value)
updateSymbolValue(*SymbolName, NextAvailableAddress);

registerSymbol:
if (IsDynSym)
Write((&Symbol - cantFail(Obj.symbols(&SymTabSection)).begin()) *
sizeof(ELFSymTy),
Expand Down
38 changes: 25 additions & 13 deletions bolt/lib/Target/X86/X86MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1932,6 +1932,19 @@ class X86MCPlusBuilder : public MCPlusBuilder {
// = R_X86_64_PC32(Ln) + En - JT
// = R_X86_64_PC32(Ln + offsetof(En))
//
auto isRIPRel = [&](X86MemOperand &MO) {
// NB: DispExpr should be set
return MO.DispExpr != nullptr &&
MO.BaseRegNum == RegInfo->getProgramCounter() &&
MO.IndexRegNum == X86::NoRegister &&
MO.SegRegNum == X86::NoRegister;
};
auto isIndexed = [](X86MemOperand &MO, MCPhysReg R) {
// NB: IndexRegNum should be set.
return MO.IndexRegNum != X86::NoRegister && MO.BaseRegNum == R &&
MO.ScaleImm == 4 && MO.DispImm == 0 &&
MO.SegRegNum == X86::NoRegister;
};
LLVM_DEBUG(dbgs() << "Checking for PIC jump table\n");
MCInst *MemLocInstr = nullptr;
const MCInst *MovInstr = nullptr;
Expand Down Expand Up @@ -1965,9 +1978,8 @@ class X86MCPlusBuilder : public MCPlusBuilder {
std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Instr);
if (!MO)
break;
if (MO->BaseRegNum != R1 || MO->ScaleImm != 4 ||
MO->IndexRegNum == X86::NoRegister || MO->DispImm != 0 ||
MO->SegRegNum != X86::NoRegister)
if (!isIndexed(*MO, R1))
// POSSIBLE_PIC_JUMP_TABLE
break;
MovInstr = &Instr;
} else {
Expand All @@ -1986,9 +1998,7 @@ class X86MCPlusBuilder : public MCPlusBuilder {
std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Instr);
if (!MO)
break;
if (MO->BaseRegNum != RegInfo->getProgramCounter() ||
MO->IndexRegNum != X86::NoRegister ||
MO->SegRegNum != X86::NoRegister || MO->DispExpr == nullptr)
if (!isRIPRel(*MO))
break;
MemLocInstr = &Instr;
break;
Expand Down Expand Up @@ -2105,13 +2115,15 @@ class X86MCPlusBuilder : public MCPlusBuilder {
return IndirectBranchType::POSSIBLE_FIXED_BRANCH;
}

if (Type == IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE &&
(MO->ScaleImm != 1 || MO->BaseRegNum != RIPRegister))
return IndirectBranchType::UNKNOWN;

if (Type != IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE &&
MO->ScaleImm != PtrSize)
return IndirectBranchType::UNKNOWN;
switch (Type) {
case IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE:
if (MO->ScaleImm != 1 || MO->BaseRegNum != RIPRegister)
return IndirectBranchType::UNKNOWN;
break;
default:
if (MO->ScaleImm != PtrSize)
return IndirectBranchType::UNKNOWN;
}

MemLocInstrOut = MemLocInstr;

Expand Down
4 changes: 4 additions & 0 deletions bolt/lib/Utils/CommandLineOpts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ cl::opt<bool> TimeOpts("time-opts",
cl::desc("print time spent in each optimization"),
cl::cat(BoltOptCategory));

cl::opt<bool> TimeRewrite("time-rewrite",
cl::desc("print time spent in rewriting passes"),
cl::Hidden, cl::cat(BoltCategory));

cl::opt<bool> UseOldText(
"use-old-text",
cl::desc("re-use space in old .text if possible (relocation mode)"),
Expand Down
4 changes: 1 addition & 3 deletions bolt/runtime/instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,6 @@ void Graph::computeEdgeFrequencies(const uint64_t *Counters,
continue;

assert(SpanningTreeNodes[Cur].NumInEdges == 1, "must have 1 parent");
const uint32_t Parent = SpanningTreeNodes[Cur].InEdges[0].Node;
const uint32_t ParentEdge = SpanningTreeNodes[Cur].InEdges[0].ID;

// Calculate parent edge freq.
Expand Down Expand Up @@ -1464,9 +1463,8 @@ void visitCallFlowEntry(CallFlowHashTable::MapEntry &Entry, int FD,
int openProfile() {
// Build the profile name string by appending our PID
char Buf[BufSize];
char *Ptr = Buf;
uint64_t PID = __getpid();
Ptr = strCopy(Buf, __bolt_instr_filename, BufSize);
char *Ptr = strCopy(Buf, __bolt_instr_filename, BufSize);
if (__bolt_instr_use_pid) {
Ptr = strCopy(Ptr, ".", BufSize - (Ptr - Buf + 1));
Ptr = intToStr(Ptr, PID, 10);
Expand Down
3 changes: 1 addition & 2 deletions bolt/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,14 @@ list(APPEND BOLT_TEST_DEPS
)

add_custom_target(bolt-test-depends DEPENDS ${BOLT_TEST_DEPS})
set_target_properties(bolt-test-depends PROPERTIES FOLDER "BOLT")
set_target_properties(bolt-test-depends PROPERTIES FOLDER "BOLT/Tests")

add_lit_testsuite(check-bolt "Running the BOLT regression tests"
${CMAKE_CURRENT_BINARY_DIR}
PARAMS ${BOLT_TEST_PARAMS}
DEPENDS ${BOLT_TEST_DEPS}
ARGS ${BOLT_TEST_EXTRA_ARGS}
)
set_target_properties(check-bolt PROPERTIES FOLDER "BOLT")

add_lit_testsuites(BOLT ${CMAKE_CURRENT_SOURCE_DIR}
PARAMS ${BOLT_TEST_PARAMS}
Expand Down
18 changes: 14 additions & 4 deletions bolt/test/X86/bb-with-two-tail-calls.s
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
# This reproduces a bug with dynostats when trying to compute branch stats
# at a block with two tails calls (one conditional and one unconditional).

# REQUIRES: system-linux

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
# RUN: %s -o %t.o
# RUN: link_fdata %s %t.o %t.fdata
# RUN: llvm-strip --strip-unneeded %t.o
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib
# RUN: llvm-bolt %t.exe -o %t.out --data %t.fdata --lite=0 --dyno-stats \
# RUN: --print-sctc --print-only=_start -enable-bat 2>&1 | FileCheck %s
# RUN: llvm-objdump --syms %t.out > %t.log
# RUN: llvm-bat-dump %t.out --dump-all >> %t.log
# RUN: FileCheck %s --input-file %t.log --check-prefix=CHECK-BAT

# CHECK-NOT: Assertion `BranchInfo.size() == 2 && "could only be called for blocks with 2 successors"' failed.
# Two tail calls in the same basic block after SCTC:
# CHECK: {{.*}}: ja {{.*}} # TAILCALL # Offset: 7 # CTCTakenCount: 4
# CHECK-NEXT: {{.*}}: jmp {{.*}} # TAILCALL # Offset: 12
# CHECK-NEXT: {{.*}}: jmp {{.*}} # TAILCALL # Offset: 13

# Confirm that a deleted basic block is emitted at function end offset (0xe)
# CHECK-BAT: [[#%x,ADDR:]] g .text [[#%x,SIZE:]] _start
# CHECK-BAT: Function Address: 0x[[#%x,ADDR]]
# CHECK-BAT: 0x[[#%x,SIZE]]
# CHECK-BAT: NumBlocks: 5

.globl _start
_start:
Expand All @@ -23,7 +31,9 @@ a: ja b
x: ret
# FDATA: 1 _start #a# 1 _start #b# 2 4
b: jmp e
c: jmp f
c:
.nops 1
jmp f

.globl e
e:
Expand Down
7 changes: 5 additions & 2 deletions bolt/test/X86/bolt-address-translation-yaml.test
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat.preagg.txt -w %t.yaml -o
RUN: 2>&1 | FileCheck --check-prefix READ-BAT-CHECK %s
RUN: FileCheck --input-file %t.yaml --check-prefix YAML-BAT-CHECK %s
# Check that YAML converted from fdata matches YAML created directly with BAT.
RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o /dev/null
RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o /dev/null \
RUN: 2>&1 | FileCheck --check-prefix READ-BAT-FDATA-CHECK %s
RUN: FileCheck --input-file %t.yaml-fdata --check-prefix YAML-BAT-CHECK %s

# Test resulting YAML profile with the original binary (no-stale mode)
Expand All @@ -40,11 +41,13 @@ RUN: | FileCheck --check-prefix CHECK-BOLT-YAML %s

WRITE-BAT-CHECK: BOLT-INFO: Wrote 5 BAT maps
WRITE-BAT-CHECK: BOLT-INFO: Wrote 4 function and 22 basic block hashes
WRITE-BAT-CHECK: BOLT-INFO: BAT section size (bytes): 384
WRITE-BAT-CHECK: BOLT-INFO: BAT section size (bytes): 404

READ-BAT-CHECK-NOT: BOLT-ERROR: unable to save profile in YAML format for input file processed by BOLT
READ-BAT-CHECK: BOLT-INFO: Parsed 5 BAT entries
READ-BAT-CHECK: PERF2BOLT: read 79 aggregated LBR entries
READ-BAT-CHECK: BOLT-INFO: 5 out of 21 functions in the binary (23.8%) have non-empty execution profile
READ-BAT-FDATA-CHECK: BOLT-INFO: 5 out of 16 functions in the binary (31.2%) have non-empty execution profile

YAML-BAT-CHECK: functions:
# Function not covered by BAT - has insns in basic block
Expand Down
2 changes: 1 addition & 1 deletion bolt/test/X86/bolt-address-translation.test
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
# CHECK: BOLT: 3 out of 7 functions were overwritten.
# CHECK: BOLT-INFO: Wrote 6 BAT maps
# CHECK: BOLT-INFO: Wrote 3 function and 58 basic block hashes
# CHECK: BOLT-INFO: BAT section size (bytes): 928
# CHECK: BOLT-INFO: BAT section size (bytes): 940
#
# usqrt mappings (hot part). We match against any key (left side containing
# the bolted binary offsets) because BOLT may change where it puts instructions
Expand Down
670 changes: 670 additions & 0 deletions bolt/test/X86/dwarf5-debug-names-class-type-decl.s

Large diffs are not rendered by default.

485 changes: 485 additions & 0 deletions bolt/test/X86/dwarf5-debug-names-enumeration-type-decl.s

Large diffs are not rendered by default.

671 changes: 671 additions & 0 deletions bolt/test/X86/dwarf5-debug-names-structure-type-decl.s

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions bolt/test/X86/ignored-interprocedural-reference.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# This reproduces a bug with not processing interprocedural references from
# ignored functions.

# REQUIRES: system-linux

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags %t.o -o %t.exe -nostdlib -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.out --enable-bat -funcs=main
# RUN: link_fdata %s %t.out %t.preagg PREAGG
# RUN: perf2bolt %t.out -p %t.preagg --pa -o %t.fdata -w %t.yaml
# RUN: FileCheck %s --input-file=%t.fdata --check-prefix=CHECK-FDATA
# RUN: FileCheck %s --input-file=%t.yaml --check-prefix=CHECK-YAML

# CHECK-FDATA: 1 main 0 1 foo a 1 1
# CHECK-YAML: name: main
# CHECK-YAML: calls: {{.*}} disc: 1

# PREAGG: B #main# #foo_secondary# 1 1
# main calls foo at valid instruction offset past nops that are to be stripped.
.globl main
main:
.cfi_startproc
call foo_secondary
ret
.cfi_endproc
.size main,.-main

# Placeholder cold fragment to force main to be ignored in non-relocation mode.
.globl main.cold
main.cold:
.cfi_startproc
ud2
.cfi_endproc
.size main.cold,.-main.cold

# foo is set up to contain a valid instruction at called offset, and trapping
# instructions past that.
.globl foo
foo:
.cfi_startproc
.nops 10
.globl foo_secondary
foo_secondary:
ret
.rept 20
int3
.endr
.cfi_endproc
.size foo,.-foo
8 changes: 8 additions & 0 deletions bolt/test/X86/register-fragments-bolt-symbols.s
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
# RUN: FileCheck --input-file %t.bat.fdata --check-prefix=CHECK-FDATA %s
# RUN: FileCheck --input-file %t.bat.yaml --check-prefix=CHECK-YAML %s

# RUN: link_fdata --no-redefine %s %t.bolt %t.preagg2 PREAGG2
# PREAGG2: B X:0 #chain# 1 0
# RUN: perf2bolt %t.bolt -p %t.preagg2 --pa -o %t.bat2.fdata -w %t.bat2.yaml
# RUN: FileCheck %s --input-file %t.bat2.yaml --check-prefix=CHECK-YAML2

# CHECK-SYMS: l df *ABS* [[#]] chain.s
# CHECK-SYMS: l F .bolt.org.text [[#]] chain
# CHECK-SYMS: l F .text.cold [[#]] chain.cold.0
Expand All @@ -28,6 +33,9 @@

# CHECK-FDATA: 0 [unknown] 0 1 chain/chain.s/2 10 0 1
# CHECK-YAML: - name: 'chain/chain.s/2'
# CHECK-YAML2: - name: 'chain/chain.s/1'
## non-BAT function has non-zero insns:
# CHECK-YAML2: insns: 1

.file "chain.s"
.text
Expand Down
71 changes: 71 additions & 0 deletions bolt/test/X86/yaml-non-simple.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
## Check that YAML profile for non-simple function is not reported as stale.

# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o
# RUN: %clang %cflags %t.o -o %t.exe -nostdlib
# RUN: llvm-bolt %t.exe -o %t.out --data %t/yaml --profile-ignore-hash -v=1 \
# RUN: --report-stale 2>&1 | FileCheck %s

# CHECK: BOLT-INFO: could not disassemble function main. Will ignore.
# CHECK: BOLT-INFO: could not disassemble function main.cold. Will ignore.
# CHECK: BOLT-INFO: 0 out of 2 functions in the binary (0.0%) have non-empty execution profile
# CHECK: BOLT-INFO: 1 function with profile could not be optimized

#--- main.s
.globl main
.type main, @function
main:
.cfi_startproc
.LBB00:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
testq %rax, %rax
js .LBB03
.LBB01:
jne .LBB04
.LBB02:
nop
.LBB03:
xorl %eax, %eax
addq $16, %rsp
popq %rbp
retq
.LBB04:
xorl %eax, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
.size main, .-main

.globl main.cold
.type main.cold, @function
main.cold:
.cfi_startproc
nop
.cfi_endproc
.size main.cold, .-main.cold

#--- yaml
---
header:
profile-version: 1
binary-name: 'yaml-non-simple.s.tmp.exe'
binary-build-id: '<unknown>'
profile-flags: [ lbr ]
profile-origin: branch profile reader
profile-events: ''
dfs-order: false
hash-func: xxh3
functions:
- name: main
fid: 0
hash: 0x0000000000000000
exec: 1
nblocks: 5
blocks:
- bid: 1
insns: 1
succ: [ { bid: 3, cnt: 1} ]
...
3 changes: 3 additions & 0 deletions bolt/test/link_fdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
parser.add_argument("prefix", nargs="?", default="FDATA", help="Custom FDATA prefix")
parser.add_argument("--nmtool", default="nm", help="Path to nm tool")
parser.add_argument("--no-lbr", action="store_true")
parser.add_argument("--no-redefine", action="store_true")

args = parser.parse_args()

Expand Down Expand Up @@ -90,6 +91,8 @@
symbols = {}
for symline in nm_output.splitlines():
symval, _, symname = symline.split(maxsplit=2)
if symname in symbols and args.no_redefine:
continue
symbols[symname] = symval


Expand Down
3 changes: 2 additions & 1 deletion bolt/test/runtime/X86/hot-end-symbol.s
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q

# RUN: llvm-bolt %t.exe --relocs=1 --hot-text --reorder-functions=hfsort \
# RUN: --split-functions --split-strategy=all \
# RUN: --data %t.fdata -o %t.out | FileCheck %s

# RUN: %t.out 1
Expand All @@ -30,12 +31,12 @@
# CHECK-OUTPUT: __hot_start
# CHECK-OUTPUT-NEXT: main
# CHECK-OUTPUT-NEXT: __hot_end
# CHECK-OUTPUT-NOT: __hot_start.cold

.text
.globl main
.type main, %function
.globl __hot_start
.type __hot_start, %object
.p2align 4
main:
__hot_start:
Expand Down
2 changes: 1 addition & 1 deletion bolt/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
add_custom_target(BoltUnitTests)
set_target_properties(BoltUnitTests PROPERTIES FOLDER "BOLT tests")
set_target_properties(BoltUnitTests PROPERTIES FOLDER "BOLT/Tests")

function(add_bolt_unittest test_dirname)
add_unittest(BoltUnitTests ${test_dirname} ${ARGN})
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
set(LLVM_SUBPROJECT_TITLE "Clang Tools Extra")

include(CMakeDependentOption)
include(GNUInstallDirs)

Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
PATTERN "*.h"
)
add_custom_target(clang-tidy-headers)
set_target_properties(clang-tidy-headers PROPERTIES FOLDER "Misc")
set_target_properties(clang-tidy-headers PROPERTIES FOLDER "Clang Tools Extra/Resources")
if(NOT LLVM_ENABLE_IDE)
add_llvm_install_targets(install-clang-tidy-headers
DEPENDS clang-tidy-headers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ AST_MATCHER(QualType, isEnableIf) {
AST_MATCHER_P(TemplateTypeParmDecl, hasDefaultArgument,
clang::ast_matchers::internal::Matcher<QualType>, TypeMatcher) {
return Node.hasDefaultArgument() &&
TypeMatcher.matches(Node.getDefaultArgument(), Finder, Builder);
TypeMatcher.matches(
Node.getDefaultArgument().getArgument().getAsType(), Finder,
Builder);
}
AST_MATCHER(TemplateDecl, hasAssociatedConstraints) {
return Node.hasAssociatedConstraints();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ namespace {
AST_MATCHER_P(TemplateTypeParmDecl, hasUnnamedDefaultArgument,
ast_matchers::internal::Matcher<TypeLoc>, InnerMatcher) {
if (Node.getIdentifier() != nullptr || !Node.hasDefaultArgument() ||
Node.getDefaultArgumentInfo() == nullptr)
Node.getDefaultArgument().getArgument().isNull())
return false;

TypeLoc DefaultArgTypeLoc = Node.getDefaultArgumentInfo()->getTypeLoc();
TypeLoc DefaultArgTypeLoc =
Node.getDefaultArgument().getTypeSourceInfo()->getTypeLoc();
return InnerMatcher.matches(DefaultArgTypeLoc, Finder, Builder);
}

Expand Down
32 changes: 15 additions & 17 deletions clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,13 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
unaryOperator(hasUnaryOperand(ArrayExpr), unless(hasOperatorName("*"))),
binaryOperator(hasEitherOperand(ArrayExpr)),
castExpr(hasSourceExpression(ArrayExpr))));
const auto PointerToArrayExpr = ignoringParenImpCasts(
hasType(hasCanonicalType(pointerType(pointee(arrayType())))));
const auto PointerToArrayExpr =
hasType(hasCanonicalType(pointerType(pointee(arrayType()))));

const auto StructAddrOfExpr = unaryOperator(
hasOperatorName("&"), hasUnaryOperand(ignoringParenImpCasts(
hasType(hasCanonicalType(recordType())))));
const auto PointerToStructType =
hasUnqualifiedDesugaredType(pointerType(pointee(recordType())));
const auto PointerToStructExpr = ignoringParenImpCasts(expr(
hasType(hasCanonicalType(PointerToStructType)), unless(cxxThisExpr())));
const auto PointerToStructExpr = expr(
hasType(hasCanonicalType(PointerToStructType)), unless(cxxThisExpr()));

const auto ArrayOfPointersExpr = ignoringParenImpCasts(
hasType(hasCanonicalType(arrayType(hasElementType(pointerType()))
Expand All @@ -166,18 +163,19 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
ignoringParenImpCasts(arraySubscriptExpr(
hasBase(ArrayOfSamePointersExpr), hasIndex(ZeroLiteral)));
const auto ArrayLengthExprDenom =
expr(hasParent(expr(ignoringParenImpCasts(binaryOperator(
hasOperatorName("/"), hasLHS(ignoringParenImpCasts(sizeOfExpr(
has(ArrayOfPointersExpr)))))))),
expr(hasParent(binaryOperator(hasOperatorName("/"),
hasLHS(ignoringParenImpCasts(sizeOfExpr(
has(ArrayOfPointersExpr)))))),
sizeOfExpr(has(ArrayOfSamePointersZeroSubscriptExpr)));

Finder->addMatcher(expr(anyOf(sizeOfExpr(has(ignoringParenImpCasts(anyOf(
ArrayCastExpr, PointerToArrayExpr,
StructAddrOfExpr, PointerToStructExpr)))),
sizeOfExpr(has(PointerToStructType))),
unless(ArrayLengthExprDenom))
.bind("sizeof-pointer-to-aggregate"),
this);
Finder->addMatcher(
expr(sizeOfExpr(anyOf(
has(ignoringParenImpCasts(anyOf(
ArrayCastExpr, PointerToArrayExpr, PointerToStructExpr))),
has(PointerToStructType))),
unless(ArrayLengthExprDenom))
.bind("sizeof-pointer-to-aggregate"),
this);
}

// Detect expression like: sizeof(expr) <= k for a suspicious constant 'k'.
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_custom_command(
DEPENDS ${clang_tidy_confusable_chars_gen_target} ConfusableTable/confusables.txt)

add_custom_target(genconfusable DEPENDS Confusables.inc)
set_target_properties(genconfusable PROPERTIES FOLDER "Clang Tools Extra/Sourcegenning")

add_clang_library(clangTidyMiscModule
ConstCorrectnessCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,11 @@ matchTrailingTemplateParam(const FunctionTemplateDecl *FunctionTemplate) {
dyn_cast<TemplateTypeParmDecl>(LastParam)) {
if (LastTemplateParam->hasDefaultArgument() &&
LastTemplateParam->getIdentifier() == nullptr) {
return {matchEnableIfSpecialization(
LastTemplateParam->getDefaultArgumentInfo()->getTypeLoc()),
LastTemplateParam};
return {
matchEnableIfSpecialization(LastTemplateParam->getDefaultArgument()
.getTypeSourceInfo()
->getTypeLoc()),
LastTemplateParam};
}
}
return {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,

case CK_PointerToBoolean:
case CK_MemberPointerToBoolean: // Fall-through on purpose.
return Context.getLangOpts().CPlusPlus11 ? "nullptr" : "0";
return (Context.getLangOpts().CPlusPlus11 || Context.getLangOpts().C23)
? "nullptr"
: "0";

default:
llvm_unreachable("Unexpected cast kind");
Expand Down Expand Up @@ -165,6 +167,12 @@ bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
const ImplicitCastExpr *Cast,
ASTContext &Context, StringRef OtherType) {
if (!Context.getLangOpts().CPlusPlus) {
Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(),
(Twine("(") + OtherType + ")").str());
return;
}

const Expr *SubExpr = Cast->getSubExpr();
const bool NeedParens = !isa<ParenExpr>(SubExpr->IgnoreImplicit());
const bool NeedSpace = needsSpacePrefix(Cast->getBeginLoc(), Context);
Expand Down Expand Up @@ -267,6 +275,10 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
auto BoolXor =
binaryOperator(hasOperatorName("^"), hasLHS(ImplicitCastFromBool),
hasRHS(ImplicitCastFromBool));
auto ComparisonInCall = allOf(
hasParent(callExpr()),
hasSourceExpression(binaryOperator(hasAnyOperatorName("==", "!="))));

Finder->addMatcher(
traverse(TK_AsIs,
implicitCastExpr(
Expand All @@ -281,6 +293,8 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))),
// Exclude cases common to implicit cast to and from bool.
unless(ExceptionCases), unless(has(BoolXor)),
// Exclude C23 cases common to implicit cast to bool.
unless(ComparisonInCall),
// Retrieve also parent statement, to check if we need
// additional parens in replacement.
optionally(hasParent(stmt().bind("parentStmt"))),
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ static const NamedDecl *getFailureForNamedDecl(const NamedDecl *ND) {
if (const auto *Method = dyn_cast<CXXMethodDecl>(ND)) {
if (const CXXMethodDecl *Overridden = getOverrideMethod(Method))
Canonical = cast<NamedDecl>(Overridden->getCanonicalDecl());
else if (const FunctionTemplateDecl *Primary = Method->getPrimaryTemplate())
if (const FunctionDecl *TemplatedDecl = Primary->getTemplatedDecl())
Canonical = cast<NamedDecl>(TemplatedDecl->getCanonicalDecl());

if (Canonical != ND)
return Canonical;
Expand Down
11 changes: 8 additions & 3 deletions clang-tools-extra/clangd/Hover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,12 @@ fetchTemplateParameters(const TemplateParameterList *Params,
if (!TTP->getName().empty())
P.Name = TTP->getNameAsString();

if (TTP->hasDefaultArgument())
P.Default = TTP->getDefaultArgument().getAsString(PP);
if (TTP->hasDefaultArgument()) {
P.Default.emplace();
llvm::raw_string_ostream Out(*P.Default);
TTP->getDefaultArgument().getArgument().print(PP, Out,
/*IncludeType=*/false);
}
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
P.Type = printType(NTTP, PP);

Expand All @@ -258,7 +262,8 @@ fetchTemplateParameters(const TemplateParameterList *Params,
if (NTTP->hasDefaultArgument()) {
P.Default.emplace();
llvm::raw_string_ostream Out(*P.Default);
NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
NTTP->getDefaultArgument().getArgument().print(PP, Out,
/*IncludeType=*/false);
}
} else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
P.Type = printType(TTPD, PP);
Expand Down
5 changes: 3 additions & 2 deletions clang-tools-extra/clangd/test/infinite-instantiation.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: cp %s %t.cpp
// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
// RUN: rm -rf %t.dir && mkdir -p %t.dir
// RUN: echo '[{"directory": "%/t.dir", "command": "clang -ftemplate-depth=100 -x c++ %/s", "file": "%/s"}]' > %t.dir/compile_commands.json
// RUN: not clangd --compile-commands-dir=%t.dir -check=%s 2>&1 | FileCheck -strict-whitespace %s

// CHECK: [template_recursion_depth_exceeded]

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../quality/CompletionModel.cmake)
gen_decision_forest(${CMAKE_CURRENT_SOURCE_DIR}/decision_forest_model DecisionForestRuntimeTest ::ns1::ns2::test::Example)

add_custom_target(ClangdUnitTests)
set_target_properties(ClangdUnitTests PROPERTIES FOLDER "Clang Tools Extra/Tests")
add_unittest(ClangdUnitTests ClangdTests
Annotations.cpp
ASTTests.cpp
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/unittests/ClangdTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ TEST(ClangdServerTest, SearchLibDir) {
ErrorCheckingCallbacks DiagConsumer;
MockCompilationDatabase CDB;
CDB.ExtraClangFlags.insert(CDB.ExtraClangFlags.end(),
{"-xc++", "-target", "x86_64-linux-unknown",
{"-xc++", "--target=x86_64-unknown-linux-gnu",
"-m64", "--gcc-toolchain=/randomusr",
"-stdlib=libstdc++"});
ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
Expand Down
4 changes: 3 additions & 1 deletion clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,9 @@ TEST_F(TargetDeclTest, OverloadExpr) {
[[delete]] x;
}
)cpp";
EXPECT_DECLS("CXXDeleteExpr", "void operator delete(void *) noexcept");
// Sized deallocation is enabled by default in C++14 onwards.
EXPECT_DECLS("CXXDeleteExpr",
"void operator delete(void *, unsigned long) noexcept");
}

TEST_F(TargetDeclTest, DependentExprs) {
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ if (DOXYGEN_FOUND)
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating clang doxygen documentation." VERBATIM)
set_target_properties(doxygen-clang-tools PROPERTIES FOLDER "Clang Tools Extra/Docs")

if (LLVM_BUILD_DOCS)
add_dependencies(doxygen doxygen-clang-tools)
Expand Down
7 changes: 5 additions & 2 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,15 @@ Changes in existing checks
<clang-tidy/checks/readability/identifier-naming>` check in `GetConfigPerFile`
mode by resolving symbolic links to header files. Fixed handling of Hungarian
Prefix when configured to `LowerCase`. Added support for renaming designated
initializers. Added support for renaming macro arguments.
initializers. Added support for renaming macro arguments. Fixed renaming
conflicts arising from out-of-line member function template definitions.

- Improved :doc:`readability-implicit-bool-conversion
<clang-tidy/checks/readability/implicit-bool-conversion>` check to provide
valid fix suggestions for ``static_cast`` without a preceding space and
fixed problem with duplicate parentheses in double implicit casts.
fixed problem with duplicate parentheses in double implicit casts. Corrected
the fix suggestions for C23 and later by using C-style casts instead of
``static_cast``.

- Improved :doc:`readability-redundant-inline-specifier
<clang-tidy/checks/readability/redundant-inline-specifier>` check to properly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ The rules for generating fix-it hints are:
- ``if (!pointer)`` is changed to ``if (pointer == nullptr)``,

- in case of conversions from bool to other built-in types, an explicit
``static_cast`` is proposed to make it clear that a conversion is taking
place:
``static_cast`` (or a C-style cast since C23) is proposed to make it clear
that a conversion is taking place:

- ``int integer = boolean;`` is changed to
``int integer = static_cast<int>(boolean);``,
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
)

add_custom_target(ClangIncludeCleanerUnitTests)
set_target_properties(ClangIncludeCleanerUnitTests PROPERTIES FOLDER "Clang Tools Extra/Tests")
add_unittest(ClangIncludeCleanerUnitTests ClangIncludeCleanerTests
AnalysisTest.cpp
FindHeadersTest.cpp
Expand Down
6 changes: 2 additions & 4 deletions clang-tools-extra/modularize/ModularizeUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,9 @@ static std::string replaceDotDot(StringRef Path) {
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)
if (*B == "..")
llvm::sys::path::remove_filename(Buffer);
else
else if (*B != ".")
llvm::sys::path::append(Buffer, *B);
++B;
}
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/pseudo/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ add_custom_command(OUTPUT ${cxx_bnf_inc}
add_custom_target(cxx_gen
DEPENDS ${cxx_symbols_inc} ${cxx_bnf_inc}
VERBATIM)
set_target_properties(cxx_gen PROPERTIES FOLDER "Clang Tools Extra/Sourcegenning")
1 change: 1 addition & 0 deletions clang-tools-extra/pseudo/tool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ add_custom_command(OUTPUT HTMLForestResources.inc
DEPENDS ${CLANG_SOURCE_DIR}/utils/bundle_resources.py HTMLForest.css HTMLForest.js HTMLForest.html
VERBATIM)
add_custom_target(clang-pseudo-resources DEPENDS HTMLForestResources.inc)
set_target_properties(clang-pseudo-resources PROPERTIES FOLDER "Clang Tools Extra/Resources")
add_dependencies(clang-pseudo clang-pseudo-resources)
1 change: 1 addition & 0 deletions clang-tools-extra/pseudo/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
)

add_custom_target(ClangPseudoUnitTests)
set_target_properties(ClangPseudoUnitTests PROPERTIES FOLDER "Clang Tools Extra/Tests")
add_unittest(ClangPseudoUnitTests ClangPseudoTests
BracketTest.cpp
CXXTest.cpp
Expand Down
1 change: 0 additions & 1 deletion clang-tools-extra/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ add_lit_testsuite(check-clang-extra "Running clang-tools-extra/test"
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${CLANG_TOOLS_TEST_DEPS}
)
set_target_properties(check-clang-extra PROPERTIES FOLDER "Clang extra tools' tests")

add_lit_testsuites(CLANG-EXTRA ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${CLANG_TOOLS_TEST_DEPS}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ struct X {
// CHECK-MESSAGES: :[[@LINE-1]]:5: error: field has incomplete type 'X' [clang-diagnostic-error]
int a = 10;
};

template <typename T> class NoCrash {
// CHECK-MESSAGES: :[[@LINE+2]]:20: error: base class has incomplete type
// CHECK-MESSAGES: :[[@LINE-2]]:29: note: definition of 'NoCrash<T>' is not complete until the closing '}'
class B : public NoCrash {
template <typename U> B(U u) {}
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -463,12 +463,6 @@ struct NegativeIncompleteArrayMember {
char e[];
};

template <typename T> class NoCrash {
class B : public NoCrash {
template <typename U> B(U u) {}
};
};

struct PositiveBitfieldMember {
PositiveBitfieldMember() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,6 @@ struct S {
// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
void *operator new(size_t size) noexcept(false);

struct T {
// Sized deallocations are not enabled by default, and so this new/delete pair
// does not match. However, we expect only one warning, for the new, because
// the operator delete is a placement delete and we do not warn on mismatching
// placement operations.
// CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
void *operator new(size_t size) noexcept;
void operator delete(void *ptr, size_t) noexcept; // ok only if sized deallocation is enabled
};

struct U {
void *operator new(size_t size) noexcept;
void operator delete(void *ptr) noexcept;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %check_clang_tidy %s readability-identifier-naming %t -std=c++20 \
// RUN: --config='{CheckOptions: { \
// RUN: readability-identifier-naming.MethodCase: CamelCase, \
// RUN: }}'

namespace SomeNamespace {
namespace Inner {

class SomeClass {
public:
template <typename T>
int someMethod();
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for method 'someMethod' [readability-identifier-naming]
// CHECK-FIXES: {{^}} int SomeMethod();
};
template <typename T>
int SomeClass::someMethod() {
// CHECK-FIXES: {{^}}int SomeClass::SomeMethod() {
return 5;
}

} // namespace Inner

void someFunc() {
Inner::SomeClass S;
S.someMethod<int>();
// CHECK-FIXES: {{^}} S.SomeMethod<int>();
}

} // namespace SomeNamespace
Original file line number Diff line number Diff line change
@@ -0,0 +1,354 @@
// RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t -- -- -std=c23

#undef NULL
#define NULL 0L

void functionTakingBool(bool);
void functionTakingInt(int);
void functionTakingUnsignedLong(unsigned long);
void functionTakingChar(char);
void functionTakingFloat(float);
void functionTakingDouble(double);
void functionTakingSignedChar(signed char);


////////// Implicit conversion from bool.

void implicitConversionFromBoolSimpleCases() {
bool boolean = true;

functionTakingBool(boolean);

functionTakingInt(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int' [readability-implicit-bool-conversion]
// CHECK-FIXES: functionTakingInt((int)boolean);

functionTakingUnsignedLong(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'bool' -> 'unsigned long'
// CHECK-FIXES: functionTakingUnsignedLong((unsigned long)boolean);

functionTakingChar(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'bool' -> 'char'
// CHECK-FIXES: functionTakingChar((char)boolean);

functionTakingFloat(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'bool' -> 'float'
// CHECK-FIXES: functionTakingFloat((float)boolean);

functionTakingDouble(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'double'
// CHECK-FIXES: functionTakingDouble((double)boolean);
}

float implicitConversionFromBoolInReturnValue() {
bool boolean = false;
return boolean;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'bool' -> 'float'
// CHECK-FIXES: return (float)boolean;
}

void implicitConversionFromBoolInSingleBoolExpressions(bool b1, bool b2) {
bool boolean = true;
boolean = b1 ^ b2;
boolean |= !b1 || !b2;
boolean &= b1;

int integer = boolean - 3;
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: int integer = (int)boolean - 3;

float floating = boolean / 0.3f;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion 'bool' -> 'float'
// CHECK-FIXES: float floating = (float)boolean / 0.3f;

char character = boolean;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion 'bool' -> 'char'
// CHECK-FIXES: char character = (char)boolean;
}

void implicitConversionFromBoolInComplexBoolExpressions() {
bool boolean = true;
bool anotherBoolean = false;

int integer = boolean && anotherBoolean;
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion 'bool' -> 'int'
// CHECK-MESSAGES: :[[@LINE-2]]:28: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: int integer = (int)boolean && (int)anotherBoolean;

float floating = (boolean || anotherBoolean) * 0.3f;
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int'
// CHECK-MESSAGES: :[[@LINE-2]]:32: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: float floating = ((int)boolean || (int)anotherBoolean) * 0.3f;

double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3;
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'bool' -> 'int'
// CHECK-MESSAGES: :[[@LINE-2]]:40: warning: implicit conversion 'bool' -> 'int'
// CHECK-MESSAGES: :[[@LINE-3]]:58: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: double doubleFloating = ((int)boolean && ((int)anotherBoolean || (int)boolean)) * 0.3;
}

void implicitConversionFromBoolLiterals() {
functionTakingInt(true);
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: functionTakingInt(1);

functionTakingUnsignedLong(false);
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'bool' -> 'unsigned long'
// CHECK-FIXES: functionTakingUnsignedLong(0u);

functionTakingSignedChar(true);
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'bool' -> 'signed char'
// CHECK-FIXES: functionTakingSignedChar(1);

functionTakingFloat(false);
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'bool' -> 'float'
// CHECK-FIXES: functionTakingFloat(0.0f);

functionTakingDouble(true);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'double'
// CHECK-FIXES: functionTakingDouble(1.0);
}

void implicitConversionFromBoolInComparisons() {
bool boolean = true;
int integer = 0;

functionTakingBool(boolean == integer);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: functionTakingBool((int)boolean == integer);

functionTakingBool(integer != boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: functionTakingBool(integer != (int)boolean);
}

void ignoreBoolComparisons() {
bool boolean = true;
bool anotherBoolean = false;

functionTakingBool(boolean == anotherBoolean);
functionTakingBool(boolean != anotherBoolean);
}

void ignoreExplicitCastsFromBool() {
bool boolean = true;

int integer = (int)boolean + 3;
float floating = (float)boolean * 0.3f;
char character = (char)boolean;
}

void ignoreImplicitConversionFromBoolInMacroExpansions() {
bool boolean = true;

#define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3
int integerFromMacroBody = CAST_FROM_BOOL_IN_MACRO_BODY;

#define CAST_FROM_BOOL_IN_MACRO_ARGUMENT(x) x + 3
int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean);
}

////////// Implicit conversions to bool.

void implicitConversionToBoolSimpleCases() {
int integer = 10;
functionTakingBool(integer);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: functionTakingBool(integer != 0);

unsigned long unsignedLong = 10;
functionTakingBool(unsignedLong);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'unsigned long' -> 'bool'
// CHECK-FIXES: functionTakingBool(unsignedLong != 0u);

float floating = 0.0f;
functionTakingBool(floating);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: functionTakingBool(floating != 0.0f);

double doubleFloating = 1.0f;
functionTakingBool(doubleFloating);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool'
// CHECK-FIXES: functionTakingBool(doubleFloating != 0.0);

signed char character = 'a';
functionTakingBool(character);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'signed char' -> 'bool'
// CHECK-FIXES: functionTakingBool(character != 0);

int* pointer = nullptr;
functionTakingBool(pointer);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int *' -> 'bool'
// CHECK-FIXES: functionTakingBool(pointer != nullptr);
}

void implicitConversionToBoolInSingleExpressions() {
int integer = 10;
bool boolComingFromInt;
boolComingFromInt = integer;
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: boolComingFromInt = (integer != 0);

float floating = 10.0f;
bool boolComingFromFloat;
boolComingFromFloat = floating;
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: boolComingFromFloat = (floating != 0.0f);

signed char character = 'a';
bool boolComingFromChar;
boolComingFromChar = character;
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'signed char' -> 'bool'
// CHECK-FIXES: boolComingFromChar = (character != 0);

int* pointer = nullptr;
bool boolComingFromPointer;
boolComingFromPointer = pointer;
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion 'int *' -> 'bool'
// CHECK-FIXES: boolComingFromPointer = (pointer != nullptr);
}

void implicitConversionToBoolInComplexExpressions() {
bool boolean = true;

int integer = 10;
int anotherInteger = 20;
bool boolComingFromInteger;
boolComingFromInteger = integer + anotherInteger;
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: boolComingFromInteger = ((integer + anotherInteger) != 0);
}

void implicitConversionInNegationExpressions() {
int integer = 10;
bool boolComingFromNegatedInt;
boolComingFromNegatedInt = !integer;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: boolComingFromNegatedInt = ((!integer) != 0);
}

bool implicitConversionToBoolInReturnValue() {
float floating = 1.0f;
return floating;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: return floating != 0.0f;
}

void implicitConversionToBoolFromLiterals() {
functionTakingBool(0);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: functionTakingBool(false);

functionTakingBool(1);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: functionTakingBool(true);

functionTakingBool(2ul);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'unsigned long' -> 'bool'
// CHECK-FIXES: functionTakingBool(true);

functionTakingBool(0.0f);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: functionTakingBool(false);

functionTakingBool(1.0f);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: functionTakingBool(true);

functionTakingBool(2.0);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool'
// CHECK-FIXES: functionTakingBool(true);

functionTakingBool('\0');
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: functionTakingBool(false);

functionTakingBool('a');
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: functionTakingBool(true);

functionTakingBool("");
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'char *' -> 'bool'
// CHECK-FIXES: functionTakingBool(true);

functionTakingBool("abc");
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'char *' -> 'bool'
// CHECK-FIXES: functionTakingBool(true);

functionTakingBool(NULL);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'long' -> 'bool'
// CHECK-FIXES: functionTakingBool(false);
}

void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() {
functionTakingBool(-0);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: functionTakingBool((-0) != 0);

functionTakingBool(-0.0f);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: functionTakingBool((-0.0f) != 0.0f);

functionTakingBool(-0.0);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool'
// CHECK-FIXES: functionTakingBool((-0.0) != 0.0);
}

void ignoreExplicitCastsToBool() {
int integer = 10;
bool boolComingFromInt = (bool)integer;

float floating = 10.0f;
bool boolComingFromFloat = (bool)floating;

char character = 'a';
bool boolComingFromChar = (bool)character;

int* pointer = nullptr;
bool booleanComingFromPointer = (bool)pointer;
}

void ignoreImplicitConversionToBoolInMacroExpansions() {
int integer = 3;

#define CAST_TO_BOOL_IN_MACRO_BODY integer && false
bool boolFromMacroBody = CAST_TO_BOOL_IN_MACRO_BODY;

#define CAST_TO_BOOL_IN_MACRO_ARGUMENT(x) x || true
bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer);
}

int implicitConversionReturnInt()
{
return true;
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: return 1
}

int implicitConversionReturnIntWithParens()
{
return (true);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'bool' -> 'int'
// CHECK-FIXES: return 1
}

bool implicitConversionReturnBool()
{
return 1;
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: return true
}

bool implicitConversionReturnBoolWithParens()
{
return (1);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'int' -> 'bool'
// CHECK-FIXES: return true
}

int keepCompactReturnInC_PR71848() {
bool foo = false;
return( foo );
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'bool' -> 'int' [readability-implicit-bool-conversion]
// CHECK-FIXES: return(int)( foo );
}
2 changes: 1 addition & 1 deletion clang-tools-extra/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
add_custom_target(ExtraToolsUnitTests)
set_target_properties(ExtraToolsUnitTests PROPERTIES FOLDER "Extra Tools Unit Tests")
set_target_properties(ExtraToolsUnitTests PROPERTIES FOLDER "Clang Tools Extra/Tests")

function(add_extra_unittest test_dirname)
add_unittest(ExtraToolsUnitTests ${test_dirname} ${ARGN})
Expand Down
13 changes: 6 additions & 7 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.20.0)
set(LLVM_SUBPROJECT_TITLE "Clang")

if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS)
set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
Expand Down Expand Up @@ -349,10 +350,7 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wno-long-long")
endif ()

check_cxx_compiler_flag("-Werror -Wnested-anon-types" CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG)
if( CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" )
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" )
endif ()

# Determine HOST_LINK_VERSION on Darwin.
Expand Down Expand Up @@ -394,14 +392,15 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
# Installing the headers needs to depend on generating any public
# tablegen'd headers.
add_custom_target(clang-headers DEPENDS clang-tablegen-targets)
set_target_properties(clang-headers PROPERTIES FOLDER "Misc")
set_target_properties(clang-headers PROPERTIES FOLDER "Clang/Resources")
if(NOT LLVM_ENABLE_IDE)
add_llvm_install_targets(install-clang-headers
DEPENDS clang-headers
COMPONENT clang-headers)
endif()

add_custom_target(bash-autocomplete DEPENDS utils/bash-autocomplete.sh)
set_target_properties(bash-autocomplete PROPERTIES FOLDER "Clang/Misc")
install(FILES utils/bash-autocomplete.sh
DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT bash-autocomplete)
Expand Down Expand Up @@ -482,7 +481,7 @@ add_custom_target(clang-tablegen-targets
omp_gen
ClangDriverOptions
${CLANG_TABLEGEN_TARGETS})
set_target_properties(clang-tablegen-targets PROPERTIES FOLDER "Misc")
set_target_properties(clang-tablegen-targets PROPERTIES FOLDER "Clang/Tablegenning/Targets")
list(APPEND LLVM_COMMON_DEPENDS clang-tablegen-targets)

# Force target to be built as soon as possible. Clang modules builds depend
Expand Down Expand Up @@ -547,7 +546,7 @@ endif()

# Custom target to install all clang libraries.
add_custom_target(clang-libraries)
set_target_properties(clang-libraries PROPERTIES FOLDER "Misc")
set_target_properties(clang-libraries PROPERTIES FOLDER "Clang/Install")

if(NOT LLVM_ENABLE_IDE)
add_llvm_install_targets(install-clang-libraries
Expand Down
2 changes: 1 addition & 1 deletion clang/bindings/python/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ add_custom_target(check-clang-python
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..)

set(RUN_PYTHON_TESTS TRUE)
set_target_properties(check-clang-python PROPERTIES FOLDER "Clang tests")
set_target_properties(check-clang-python PROPERTIES FOLDER "Clang/Tests")

# Tests require libclang.so which is only built with LLVM_ENABLE_PIC=ON
if(NOT LLVM_ENABLE_PIC)
Expand Down
38 changes: 35 additions & 3 deletions clang/cmake/caches/CrossWinToARMLinux.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ endif()

message(STATUS "Toolchain target to build: ${LLVM_TARGETS_TO_BUILD}")

# Allow to override libc++ ABI version. Use 2 by default.
if (NOT DEFINED LIBCXX_ABI_VERSION)
set(LIBCXX_ABI_VERSION 2)
endif()

message(STATUS "Toolchain's Libc++ ABI version: ${LIBCXX_ABI_VERSION}")

if (NOT DEFINED CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "")
endif()
Expand All @@ -109,8 +116,15 @@ set(CLANG_DEFAULT_OBJCOPY "llvm-objcopy" CACHE STRING "")
set(CLANG_DEFAULT_RTLIB "compiler-rt" CACHE STRING "")
set(CLANG_DEFAULT_UNWINDLIB "libunwind" CACHE STRING "")

if(WIN32)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded" CACHE STRING "")
if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY AND WIN32)
#Note: Always specify MT DLL for the LLDB build configurations on Windows host.
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebugDLL" CACHE STRING "")
else()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL" CACHE STRING "")
endif()
# Grab all ucrt/vcruntime related DLLs into the binary installation folder.
set(CMAKE_INSTALL_UCRT_LIBRARIES ON CACHE BOOL "")
endif()

# Set up RPATH for the target runtime/builtin libraries.
Expand All @@ -127,6 +141,15 @@ set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_INSTALL_RPATH
set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "")
set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_LLVM_CMAKE_DIR "${LLVM_PROJECT_DIR}/llvm/cmake/modules" CACHE PATH "")

if (DEFINED TOOLCHAIN_TARGET_COMPILER_FLAGS)
foreach(lang C;CXX;ASM)
set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_${lang}_FLAGS "${TOOLCHAIN_TARGET_COMPILER_FLAGS}" CACHE STRING "")
endforeach()
endif()
foreach(type SHARED;MODULE;EXE)
set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
endforeach()

set(LLVM_RUNTIME_TARGETS "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "")
set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "")

Expand All @@ -137,6 +160,15 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSROOT
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_INSTALL_RPATH "${RUNTIMES_INSTALL_RPATH}" CACHE STRING "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "")

if (DEFINED TOOLCHAIN_TARGET_COMPILER_FLAGS)
foreach(lang C;CXX;ASM)
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_${lang}_FLAGS "${TOOLCHAIN_TARGET_COMPILER_FLAGS}" CACHE STRING "")
endforeach()
endif()
foreach(type SHARED;MODULE;EXE)
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
endforeach()

set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_BUILTINS ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "")
Expand Down Expand Up @@ -164,7 +196,7 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_SHARED

set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION ${LIBCXX_ABI_VERSION} CACHE STRING "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "") #!!!
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "")

Expand Down
1 change: 0 additions & 1 deletion clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ set(LLVM_ENABLE_LLD ON CACHE BOOL "")
set(LLVM_ENABLE_LTO ON CACHE BOOL "")
set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "")
set(LLVM_ENABLE_PLUGINS OFF CACHE BOOL "")
set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "")
set(LLVM_ENABLE_UNWIND_TABLES OFF CACHE BOOL "")
set(LLVM_ENABLE_Z3_SOLVER OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
Expand Down
7 changes: 0 additions & 7 deletions clang/cmake/caches/Fuchsia.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ set(LLVM_ENABLE_DIA_SDK OFF CACHE BOOL "")
set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "")
set(LLVM_ENABLE_LIBXML2 OFF CACHE BOOL "")
set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "")
set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "")
set(LLVM_ENABLE_UNWIND_TABLES OFF CACHE BOOL "")
set(LLVM_ENABLE_Z3_SOLVER OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "")
Expand All @@ -34,7 +33,6 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH
LibXml2_ROOT
LLVM_ENABLE_CURL
LLVM_ENABLE_HTTPLIB
LLVM_ENABLE_TERMINFO
LLVM_ENABLE_LIBEDIT
CURL_ROOT
OpenSSL_ROOT
Expand All @@ -47,11 +45,6 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH
CURSES_LIBRARIES
PANEL_LIBRARIES

# Deprecated
Terminfo_ROOT

Terminfo_LIBRARIES

# Deprecated
LibEdit_ROOT

Expand Down
Loading