Skip to content

Commit

Permalink
LLVM and SPIRV-LLVM-Translator pulldown (WW52)
Browse files Browse the repository at this point in the history
  • Loading branch information
bb-sycl committed Dec 29, 2023
2 parents 367166c + c99ffd5 commit 9bfc3ae
Show file tree
Hide file tree
Showing 884 changed files with 53,233 additions and 22,453 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/libcxx-build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ jobs:
std_modules: 'OFF'
# Use a larger machine for MSAN to avoid timeout and memory allocation issues.
- config: 'generic-msan'
machine: libcxx-runners-32-set
machine: libcxx-runners-8-set
std_modules: 'OFF'
runs-on: ${{ matrix.machine }}
steps:
Expand Down
16 changes: 9 additions & 7 deletions bolt/lib/Core/DIEBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,11 @@ void DIEBuilder::buildCompileUnits(const bool Init) {
}
void DIEBuilder::buildCompileUnits(const std::vector<DWARFUnit *> &CUs) {
BuilderState.reset(new State());
// Initializing to full size because there could be cross CU references with
// different abbrev offsets. LLVM happens to output CUs that have cross CU
// references with the same abbrev table. So destinations end up in the first
// set, even if they themselves don't have src cross cu ref. We could have
// cases where this is not the case. In which case this container needs to be
// big enough for all.
getState().CloneUnitCtxMap.resize(DwarfContext->getNumCompileUnits());
// Allocating enough for current batch being processed.
// In real use cases we either processing a batch of CUs with no cross
// references, or if they do have them it is due to LTO. With clang they will
// share the same abbrev table. In either case this vector will not grow.
getState().CloneUnitCtxMap.resize(CUs.size());
getState().Type = ProcessingType::CUs;
for (DWARFUnit *CU : CUs)
registerUnit(*CU, false);
Expand Down Expand Up @@ -897,6 +895,10 @@ void DIEBuilder::registerUnit(DWARFUnit &DU, bool NeedSort) {
});
}
getState().UnitIDMap[getHash(DU)] = getState().DUList.size();
// This handles the case where we do have cross cu references, but CUs do not
// share the same abbrev table.
if (getState().DUList.size() == getState().CloneUnitCtxMap.size())
getState().CloneUnitCtxMap.emplace_back();
getState().DUList.push_back(&DU);
}

Expand Down
100 changes: 64 additions & 36 deletions bolt/lib/Passes/SplitFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,12 @@ struct SplitCacheDirected final : public SplitStrategy {
void fragment(const BlockIt Start, const BlockIt End) override {
BasicBlockOrder BlockOrder(Start, End);
BinaryFunction &BF = *BlockOrder.front()->getFunction();
// No need to re-split small functions.
if (BlockOrder.size() <= 2)
return;

size_t BestSplitIndex = findSplitIndex(BF, BlockOrder);
assert(BestSplitIndex < BlockOrder.size());

// Assign fragments based on the computed best split index.
// All basic blocks with index up to the best split index become hot.
Expand All @@ -200,10 +204,12 @@ struct SplitCacheDirected final : public SplitStrategy {
};

struct SplitScore {
size_t SplitIndex;
size_t SplitIndex = size_t(-1);
size_t HotSizeReduction = 0;
double LocalScore = 0;
double CoverCallScore = 0;

double sum() const { return LocalScore + CoverCallScore; }
};

// Auxiliary variables used by the algorithm.
Expand Down Expand Up @@ -303,7 +309,7 @@ struct SplitCacheDirected final : public SplitStrategy {
const size_t SplitIndex) {
assert(SplitIndex < BlockOrder.size() && "Invalid split index");

// Update function layout assuming hot-warm splitting at SplitIndex
// Update function layout assuming hot-warm splitting at SplitIndex.
for (size_t Index = 0; Index < BlockOrder.size(); Index++) {
BinaryBasicBlock *BB = BlockOrder[Index];
if (BB->getFragmentNum() == FragmentNum::cold())
Expand All @@ -319,8 +325,8 @@ struct SplitCacheDirected final : public SplitStrategy {
// Populate BB.OutputAddressRange with estimated new start and end addresses
// and compute the old end address of the hot section and the new end
// address of the hot section.
size_t OldHotEndAddr;
size_t NewHotEndAddr;
size_t OldHotEndAddr{0};
size_t NewHotEndAddr{0};
size_t CurrentAddr = BBOffsets[BlockOrder[0]];
for (BinaryBasicBlock *BB : BlockOrder) {
// We only care about new addresses of blocks in hot/warm.
Expand Down Expand Up @@ -492,20 +498,15 @@ struct SplitCacheDirected final : public SplitStrategy {
}

/// Compute the split score of splitting a function at a given index.
/// The split score consists of local score and cover score. Cover call score
/// is expensive to compute. As a result, we pass in a \p ReferenceScore and
/// compute cover score only when the local score exceeds that in the
/// ReferenceScore or that the size reduction of the hot fragment is larger
/// than that achieved by the split index of the ReferenceScore. This function
/// returns \p Score of SplitScore type. It contains the local score and cover
/// score (if computed) of the current splitting index. For easier book
/// keeping and comparison, it also stores the split index and the resulting
/// reduction in hot fragment size.
/// The split score consists of local score and cover score. This function
/// returns \p Score of SplitScore type. It contains the local score and
/// cover score of the current splitting index. For easier book keeping and
/// comparison, it also stores the split index and the resulting reduction
/// in hot fragment size.
SplitScore computeSplitScore(const BinaryFunction &BF,
const BasicBlockOrder &BlockOrder,
const size_t SplitIndex,
const std::vector<CallInfo> &CoverCalls,
const SplitScore &ReferenceScore) {
const std::vector<CallInfo> &CoverCalls) {
// Populate BinaryBasicBlock::OutputAddressRange with estimated
// new start and end addresses after hot-warm splitting at SplitIndex.
size_t OldHotEnd;
Expand Down Expand Up @@ -533,47 +534,74 @@ struct SplitCacheDirected final : public SplitStrategy {
// increamented in place.
computeJumpScore(BlockOrder, SplitIndex, Score);

// There is no need to compute CoverCallScore if we have already found
// another split index with a bigger LocalScore and bigger HotSizeReduction.
if (Score.LocalScore <= ReferenceScore.LocalScore &&
Score.HotSizeReduction <= ReferenceScore.HotSizeReduction)
return Score;

// Compute CoverCallScore and store in Score in place.
computeCoverCallScore(BlockOrder, SplitIndex, CoverCalls, Score);
return Score;
}

/// Find the most likely successor of a basic block when it has one or two
/// successors. Return nullptr otherwise.
const BinaryBasicBlock *getMostLikelySuccessor(const BinaryBasicBlock *BB) {
if (BB->succ_size() == 1)
return BB->getSuccessor();
if (BB->succ_size() == 2) {
uint64_t TakenCount = BB->getTakenBranchInfo().Count;
assert(TakenCount != BinaryBasicBlock::COUNT_NO_PROFILE);
uint64_t NonTakenCount = BB->getFallthroughBranchInfo().Count;
assert(NonTakenCount != BinaryBasicBlock::COUNT_NO_PROFILE);
if (TakenCount > NonTakenCount)
return BB->getConditionalSuccessor(true);
else if (TakenCount < NonTakenCount)
return BB->getConditionalSuccessor(false);
}
return nullptr;
}

/// Find the best index for splitting. The returned value is the index of the
/// last hot basic block. Hence, "no splitting" is equivalent to returning the
/// value which is one less than the size of the function.
size_t findSplitIndex(const BinaryFunction &BF,
const BasicBlockOrder &BlockOrder) {
assert(BlockOrder.size() > 2);
// Find all function calls that can be shortened if we move blocks of the
// current function to warm/cold
const std::vector<CallInfo> CoverCalls = extractCoverCalls(BF);

// Try all possible split indices (blocks with Index <= SplitIndex are in
// hot) and find the one maximizing the splitting score.
// Find the existing hot-cold splitting index.
size_t HotColdIndex = 0;
while (HotColdIndex + 1 < BlockOrder.size()) {
if (BlockOrder[HotColdIndex + 1]->getFragmentNum() == FragmentNum::cold())
break;
HotColdIndex++;
}
assert(HotColdIndex + 1 == BlockOrder.size() ||
(BlockOrder[HotColdIndex]->getFragmentNum() == FragmentNum::main() &&
BlockOrder[HotColdIndex + 1]->getFragmentNum() ==
FragmentNum::cold()));

// Try all possible split indices up to HotColdIndex (blocks that have
// Index <= SplitIndex are in hot) and find the one maximizing the
// splitting score.
SplitScore BestScore;
double BestScoreSum = -1.0;
SplitScore ReferenceScore;
for (size_t Index = 0; Index < BlockOrder.size(); Index++) {
for (size_t Index = 0; Index <= HotColdIndex; Index++) {
const BinaryBasicBlock *LastHotBB = BlockOrder[Index];
// No need to keep cold blocks in the hot section.
if (LastHotBB->getFragmentNum() == FragmentNum::cold())
break;
assert(LastHotBB->getFragmentNum() != FragmentNum::cold());

// Do not break jump to the most likely successor.
if (Index + 1 < BlockOrder.size() &&
BlockOrder[Index + 1] == getMostLikelySuccessor(LastHotBB))
continue;

const SplitScore Score =
computeSplitScore(BF, BlockOrder, Index, CoverCalls, ReferenceScore);
double ScoreSum = Score.LocalScore + Score.CoverCallScore;
if (ScoreSum > BestScoreSum) {
BestScoreSum = ScoreSum;
computeSplitScore(BF, BlockOrder, Index, CoverCalls);
if (Score.sum() > BestScore.sum())
BestScore = Score;
}
if (Score.LocalScore > ReferenceScore.LocalScore)
ReferenceScore = Score;
}

// If we don't find a good splitting point, fallback to the original one.
if (BestScore.SplitIndex == size_t(-1))
return HotColdIndex;

return BestScore.SplitIndex;
}
};
Expand Down
9 changes: 4 additions & 5 deletions bolt/test/X86/cdsplit-call-scale.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
# When -call-scale=0.0, the tested function is 2-way splitted.
# When -call-scale=1.0, the tested function is 3-way splitted with 5 blocks
# in warm because of the increased benefit of shortening the call edges.
# When -call-scale=1000.0, the tested function is 3-way splitted with 7 blocks
# in warm because of the strong benefit of shortening the call edges.
# When -call-scale=1000.0, the tested function is still 3-way splitted with
# 5 blocks in warm because cdsplit does not allow hot-warm splitting to break
# a fall through branch from a basic block to its most likely successor.

# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o
# RUN: link_fdata %s %t.o %t.fdata
Expand Down Expand Up @@ -39,12 +40,10 @@
# MEDINCENTIVE: {{^\.Ltmp5}}

# HIGHINCENTIVE: Binary Function "chain" after split-functions
# HIGHINCENTIVE: {{^\.LBB00}}
# HIGHINCENTIVE: {{^\.Ltmp1}}
# HIGHINCENTIVE: ------- HOT-COLD SPLIT POINT -------
# HIGHINCENTIVE: {{^\.LFT1}}
# HIGHINCENTIVE: ------- HOT-COLD SPLIT POINT -------
# HIGHINCENTIVE: {{^\.LFT0}}
# HIGHINCENTIVE: {{^\.Ltmp1}}
# HIGHINCENTIVE: {{^\.Ltmp0}}
# HIGHINCENTIVE: {{^\.Ltmp2}}
# HIGHINCENTIVE: {{^\.Ltmp3}}
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
#include "UnhandledSelfAssignmentCheck.h"
#include "UniquePtrArrayMismatchCheck.h"
#include "UnsafeFunctionsCheck.h"
#include "UnusedLocalNonTrivialVariableCheck.h"
#include "UnusedRaiiCheck.h"
#include "UnusedReturnValueCheck.h"
#include "UseAfterMoveCheck.h"
Expand Down Expand Up @@ -235,6 +236,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-unique-ptr-array-mismatch");
CheckFactories.registerCheck<UnsafeFunctionsCheck>(
"bugprone-unsafe-functions");
CheckFactories.registerCheck<UnusedLocalNonTrivialVariableCheck>(
"bugprone-unused-local-non-trivial-variable");
CheckFactories.registerCheck<UnusedRaiiCheck>("bugprone-unused-raii");
CheckFactories.registerCheck<UnusedReturnValueCheck>(
"bugprone-unused-return-value");
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ add_clang_library(clangTidyBugproneModule
UnhandledSelfAssignmentCheck.cpp
UniquePtrArrayMismatchCheck.cpp
UnsafeFunctionsCheck.cpp
UnusedLocalNonTrivialVariableCheck.cpp
UnusedRaiiCheck.cpp
UnusedReturnValueCheck.cpp
UseAfterMoveCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//===--- UnusedLocalNonTrivialVariableCheck.cpp - clang-tidy --------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "UnusedLocalNonTrivialVariableCheck.h"
#include "../utils/Matchers.h"
#include "../utils/OptionsUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersMacros.h"

using namespace clang::ast_matchers;
using namespace clang::tidy::matchers;

namespace clang::tidy::bugprone {

namespace {
static constexpr StringRef DefaultIncludeTypeRegex =
"::std::.*mutex;::std::future;::std::basic_string;::std::basic_regex;"
"::std::basic_istringstream;::std::basic_stringstream;::std::bitset;"
"::std::filesystem::path";

AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); }
AST_MATCHER(VarDecl, isReferenced) { return Node.isReferenced(); }
AST_MATCHER(Type, isReferenceType) { return Node.isReferenceType(); }
AST_MATCHER(QualType, isTrivial) {
return Node.isTrivialType(Finder->getASTContext()) ||
Node.isTriviallyCopyableType(Finder->getASTContext());
}
} // namespace

UnusedLocalNonTrivialVariableCheck::UnusedLocalNonTrivialVariableCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IncludeTypes(utils::options::parseStringList(
Options.get("IncludeTypes", DefaultIncludeTypeRegex))),
ExcludeTypes(
utils::options::parseStringList(Options.get("ExcludeTypes", ""))) {}

void UnusedLocalNonTrivialVariableCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IncludeTypes",
utils::options::serializeStringList(IncludeTypes));
Options.store(Opts, "ExcludeTypes",
utils::options::serializeStringList(ExcludeTypes));
}

void UnusedLocalNonTrivialVariableCheck::registerMatchers(MatchFinder *Finder) {
if (IncludeTypes.empty())
return;

Finder->addMatcher(
varDecl(isLocalVarDecl(), unless(isReferenced()),
unless(isExceptionVariable()), hasLocalStorage(), isDefinition(),
unless(hasType(isReferenceType())), unless(hasType(isTrivial())),
hasType(hasUnqualifiedDesugaredType(
anyOf(recordType(hasDeclaration(namedDecl(
matchesAnyListedName(IncludeTypes),
unless(matchesAnyListedName(ExcludeTypes))))),
templateSpecializationType(hasDeclaration(namedDecl(
matchesAnyListedName(IncludeTypes),
unless(matchesAnyListedName(ExcludeTypes)))))))))
.bind("var"),
this);
}

void UnusedLocalNonTrivialVariableCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("var");
diag(MatchedDecl->getLocation(), "unused local variable %0 of type %1")
<< MatchedDecl << MatchedDecl->getType();
}

bool UnusedLocalNonTrivialVariableCheck::isLanguageVersionSupported(
const LangOptions &LangOpts) const {
return LangOpts.CPlusPlus;
}

std::optional<TraversalKind>
UnusedLocalNonTrivialVariableCheck::getCheckTraversalKind() const {
return TK_IgnoreUnlessSpelledInSource;
}

} // namespace clang::tidy::bugprone
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//===--- UnusedLocalNonTrivialVariableCheck.h - clang-tidy ------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDLOCALNONTRIVIALVARIABLECHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDLOCALNONTRIVIALVARIABLECHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::bugprone {

/// Warns when a local non trivial variable is unused within a function. By
/// default std::.*mutex and std::future are included.
///
/// The check supports these options:
/// - 'IncludeTypes': a semicolon-separated list of regular expressions
/// matching types to ensure must be used.
/// - 'ExcludeTypes': a semicolon-separated list of regular expressions
/// matching types that are excluded from the
/// 'IncludeTypes' matches.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/unused-local-non-trivial-variable.html
class UnusedLocalNonTrivialVariableCheck : public ClangTidyCheck {
public:
UnusedLocalNonTrivialVariableCheck(StringRef Name, ClangTidyContext *Context);
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
std::optional<TraversalKind> getCheckTraversalKind() const override;

private:
const std::vector<StringRef> IncludeTypes;
const std::vector<StringRef> ExcludeTypes;
};

} // namespace clang::tidy::bugprone

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDLOCALNONTRIVIALVARIABLECHECK_H
Loading

0 comments on commit 9bfc3ae

Please sign in to comment.