diff options
author | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
---|---|---|
committer | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/libs/llvm12/tools/llvm-reduce/deltas | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) | |
download | ydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz |
fix ya.make
Diffstat (limited to 'contrib/libs/llvm12/tools/llvm-reduce/deltas')
26 files changed, 1696 insertions, 0 deletions
diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/Delta.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/Delta.cpp new file mode 100644 index 0000000000..9b0969e936 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/Delta.cpp @@ -0,0 +1,180 @@ +//===- Delta.cpp - Delta Debugging Algorithm Implementation ---------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation for the Delta Debugging Algorithm: +// it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.) +// into chunks and tries to reduce the number chunks that are interesting. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include <fstream> +#include <set> + +using namespace llvm; + +void writeOutput(llvm::Module *M, llvm::StringRef Message); + +bool IsReduced(Module &M, TestRunner &Test, SmallString<128> &CurrentFilepath) { + // Write Module to tmp file + int FD; + std::error_code EC = + sys::fs::createTemporaryFile("llvm-reduce", "ll", FD, CurrentFilepath); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "!\n"; + exit(1); + } + + ToolOutputFile Out(CurrentFilepath, FD); + M.print(Out.os(), /*AnnotationWriter=*/nullptr); + Out.os().close(); + if (Out.os().has_error()) { + errs() << "Error emitting bitcode to file '" << CurrentFilepath << "'!\n"; + exit(1); + } + + // Current Chunks aren't interesting + return Test.run(CurrentFilepath); +} + +/// Counts the amount of lines for a given file +static int getLines(StringRef Filepath) { + int Lines = 0; + std::string CurrLine; + std::ifstream FileStream{std::string(Filepath)}; + + while (std::getline(FileStream, CurrLine)) + ++Lines; + + return Lines; +} + +/// Splits Chunks in half and prints them. +/// If unable to split (when chunk size is 1) returns false. +static bool increaseGranularity(std::vector<Chunk> &Chunks) { + errs() << "Increasing granularity..."; + std::vector<Chunk> NewChunks; + bool SplitOne = false; + + for (auto &C : Chunks) { + if (C.end - C.begin == 0) + NewChunks.push_back(C); + else { + int Half = (C.begin + C.end) / 2; + NewChunks.push_back({C.begin, Half}); + NewChunks.push_back({Half + 1, C.end}); + SplitOne = true; + } + } + if (SplitOne) { + Chunks = NewChunks; + errs() << "Success! New Chunks:\n"; + for (auto C : Chunks) { + errs() << '\t'; + C.print(); + errs() << '\n'; + } + } + return SplitOne; +} + +/// Runs the Delta Debugging algorithm, splits the code into chunks and +/// reduces the amount of chunks that are considered interesting by the +/// given test. +void llvm::runDeltaPass( + TestRunner &Test, int Targets, + std::function<void(const std::vector<Chunk> &, Module *)> + ExtractChunksFromModule) { + assert(Targets >= 0); + if (!Targets) { + errs() << "\nNothing to reduce\n"; + return; + } + + if (Module *Program = Test.getProgram()) { + SmallString<128> CurrentFilepath; + if (!IsReduced(*Program, Test, CurrentFilepath)) { + errs() << "\nInput isn't interesting! Verify interesting-ness test\n"; + exit(1); + } + + assert(!verifyModule(*Program, &errs()) && + "input module is broken before making changes"); + } + + std::vector<Chunk> ChunksStillConsideredInteresting = {{1, Targets}}; + std::unique_ptr<Module> ReducedProgram; + + bool FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity; + do { + FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity = false; + + std::set<Chunk> UninterestingChunks; + for (Chunk &ChunkToCheckForUninterestingness : + reverse(ChunksStillConsideredInteresting)) { + // Take all of ChunksStillConsideredInteresting chunks, except those we've + // already deemed uninteresting (UninterestingChunks) but didn't remove + // from ChunksStillConsideredInteresting yet, and additionally ignore + // ChunkToCheckForUninterestingness chunk. + std::vector<Chunk> CurrentChunks; + CurrentChunks.reserve(ChunksStillConsideredInteresting.size() - + UninterestingChunks.size() - 1); + copy_if(ChunksStillConsideredInteresting, + std::back_inserter(CurrentChunks), [&](const Chunk &C) { + return !UninterestingChunks.count(C) && + C != ChunkToCheckForUninterestingness; + }); + + // Clone module before hacking it up.. + std::unique_ptr<Module> Clone = CloneModule(*Test.getProgram()); + // Generate Module with only Targets inside Current Chunks + ExtractChunksFromModule(CurrentChunks, Clone.get()); + + // Some reductions may result in invalid IR. Skip such reductions. + if (verifyModule(*Clone.get(), &errs())) { + errs() << " **** WARNING | reduction resulted in invalid module, " + "skipping\n"; + continue; + } + + errs() << "Ignoring: "; + ChunkToCheckForUninterestingness.print(); + for (const Chunk &C : UninterestingChunks) + C.print(); + + SmallString<128> CurrentFilepath; + if (!IsReduced(*Clone, Test, CurrentFilepath)) { + // Program became non-reduced, so this chunk appears to be interesting. + errs() << "\n"; + continue; + } + + FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity = true; + UninterestingChunks.insert(ChunkToCheckForUninterestingness); + ReducedProgram = std::move(Clone); + errs() << " **** SUCCESS | lines: " << getLines(CurrentFilepath) << "\n"; + writeOutput(ReducedProgram.get(), "Saved new best reduction to "); + } + // Delete uninteresting chunks + erase_if(ChunksStillConsideredInteresting, + [&UninterestingChunks](const Chunk &C) { + return UninterestingChunks.count(C); + }); + } while (!ChunksStillConsideredInteresting.empty() && + (FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity || + increaseGranularity(ChunksStillConsideredInteresting))); + + // If we reduced the testcase replace it + if (ReducedProgram) + Test.setProgram(std::move(ReducedProgram)); + errs() << "Couldn't increase anymore.\n"; +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/Delta.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/Delta.h new file mode 100644 index 0000000000..7da3c79c95 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/Delta.h @@ -0,0 +1,110 @@ +//===- Delta.h - Delta Debugging Algorithm Implementation -----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation for the Delta Debugging Algorithm: +// it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.) +// into chunks and tries to reduce the number chunks that are interesting. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMREDUCE_LLVMREDUCE_DELTA_H +#define LLVM_TOOLS_LLVMREDUCE_LLVMREDUCE_DELTA_H + +#include "TestRunner.h" +#include "llvm/ADT/ScopeExit.h" +#include <functional> +#include <utility> +#include <vector> + +namespace llvm { + +struct Chunk { + int begin; + int end; + + /// Helper function to verify if a given Target-index is inside the Chunk + bool contains(int Index) const { return Index >= begin && Index <= end; } + + void print() const { + errs() << "[" << begin; + if (end - begin != 0) + errs() << "," << end; + errs() << "]"; + } + + /// Operator when populating CurrentChunks in Generic Delta Pass + friend bool operator!=(const Chunk &C1, const Chunk &C2) { + return C1.begin != C2.begin || C1.end != C2.end; + } + + /// Operator used for sets + friend bool operator<(const Chunk &C1, const Chunk &C2) { + return std::tie(C1.begin, C1.end) < std::tie(C2.begin, C2.end); + } +}; + +/// Provides opaque interface for querying into ChunksToKeep without having to +/// actually understand what is going on. +class Oracle { + /// Out of all the features that we promised to be, + /// how many have we already processed? 1-based! + int Index = 1; + + /// The actual workhorse, contains the knowledge whether or not + /// some particular feature should be preserved this time. + ArrayRef<Chunk> ChunksToKeep; + +public: + explicit Oracle(ArrayRef<Chunk> ChunksToKeep_) + : ChunksToKeep(ChunksToKeep_) {} + + /// Should be called for each feature on which we are operating. + /// Name is self-explanatory - if returns true, then it should be preserved. + bool shouldKeep() { + if (ChunksToKeep.empty()) + return false; // All further features are to be discarded. + + // Does the current (front) chunk contain such a feature? + bool ShouldKeep = ChunksToKeep.front().contains(Index); + auto _ = make_scope_exit([&]() { ++Index; }); // Next time - next feature. + + // Is this the last feature in the chunk? + if (ChunksToKeep.front().end == Index) + ChunksToKeep = ChunksToKeep.drop_front(); // Onto next chunk. + + return ShouldKeep; + } +}; + +/// This function implements the Delta Debugging algorithm, it receives a +/// number of Targets (e.g. Functions, Instructions, Basic Blocks, etc.) and +/// splits them in half; these chunks of targets are then tested while ignoring +/// one chunk, if a chunk is proven to be uninteresting (i.e. fails the test) +/// it is removed from consideration. The algorithm will attempt to split the +/// Chunks in half and start the process again until it can't split chunks +/// anymore. +/// +/// This function is intended to be called by each specialized delta pass (e.g. +/// RemoveFunctions) and receives three key parameters: +/// * Test: The main TestRunner instance which is used to run the provided +/// interesting-ness test, as well as to store and access the reduced Program. +/// * Targets: The amount of Targets that are going to be reduced by the +/// algorithm, for example, the RemoveGlobalVars pass would send the amount of +/// initialized GVs. +/// * ExtractChunksFromModule: A function used to tailor the main program so it +/// only contains Targets that are inside Chunks of the given iteration. +/// Note: This function is implemented by each specialized Delta pass +/// +/// Other implementations of the Delta Debugging algorithm can also be found in +/// the CReduce, Delta, and Lithium projects. +void runDeltaPass(TestRunner &Test, int Targets, + std::function<void(const std::vector<Chunk> &, Module *)> + ExtractChunksFromModule); +} // namespace llvm + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAliases.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAliases.cpp new file mode 100644 index 0000000000..41be4baa98 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAliases.cpp @@ -0,0 +1,53 @@ +//===- ReduceAliases.cpp - Specialized Delta Pass -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce aliases in the provided Module. +// +//===----------------------------------------------------------------------===// + +#include "ReduceAliases.h" +#include "Delta.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalValue.h" + +using namespace llvm; + +/// Removes all aliases aren't inside any of the +/// desired Chunks. +static void extractAliasesFromModule(const std::vector<Chunk> &ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + for (auto &GA : make_early_inc_range(Program->aliases())) { + if (!O.shouldKeep()) { + GA.replaceAllUsesWith(GA.getAliasee()); + GA.eraseFromParent(); + } + } +} + +/// Counts the amount of aliases and prints their respective name & index. +static int countAliases(Module *Program) { + // TODO: Silence index with --quiet flag + errs() << "----------------------------\n"; + errs() << "Aliases Index Reference:\n"; + int Count = 0; + for (auto &GA : Program->aliases()) + errs() << "\t" << ++Count << ": " << GA.getName() << "\n"; + + errs() << "----------------------------\n"; + return Count; +} + +void llvm::reduceAliasesDeltaPass(TestRunner &Test) { + errs() << "*** Reducing Aliases ...\n"; + int Functions = countAliases(Test.getProgram()); + runDeltaPass(Test, Functions, extractAliasesFromModule); + errs() << "----------------------------\n"; +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAliases.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAliases.h new file mode 100644 index 0000000000..0c2886e0c2 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAliases.h @@ -0,0 +1,18 @@ +//===- ReduceAliases.h - Specialized Delta Pass ---------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce aliases in the provided Module. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" + +namespace llvm { +void reduceAliasesDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceArguments.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceArguments.cpp new file mode 100644 index 0000000000..c3c7dee83d --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceArguments.cpp @@ -0,0 +1,126 @@ +//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting Arguments from defined functions. +// +//===----------------------------------------------------------------------===// + +#include "ReduceArguments.h" +#include "Delta.h" +#include "llvm/ADT/SmallVector.h" +#include <set> +#include <vector> + +using namespace llvm; + +/// Goes over OldF calls and replaces them with a call to NewF +static void replaceFunctionCalls(Function &OldF, Function &NewF, + const std::set<int> &ArgIndexesToKeep) { + const auto &Users = OldF.users(); + for (auto I = Users.begin(), E = Users.end(); I != E; ) + if (auto *CI = dyn_cast<CallInst>(*I++)) { + SmallVector<Value *, 8> Args; + for (auto ArgI = CI->arg_begin(), E = CI->arg_end(); ArgI != E; ++ArgI) + if (ArgIndexesToKeep.count(ArgI - CI->arg_begin())) + Args.push_back(*ArgI); + + CallInst *NewCI = CallInst::Create(&NewF, Args); + NewCI->setCallingConv(NewF.getCallingConv()); + if (!CI->use_empty()) + CI->replaceAllUsesWith(NewCI); + ReplaceInstWithInst(CI, NewCI); + } +} + +/// Removes out-of-chunk arguments from functions, and modifies their calls +/// accordingly. It also removes allocations of out-of-chunk arguments. +static void extractArgumentsFromModule(std::vector<Chunk> ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + std::set<Argument *> ArgsToKeep; + std::vector<Function *> Funcs; + // Get inside-chunk arguments, as well as their parent function + for (auto &F : *Program) + if (!F.arg_empty()) { + Funcs.push_back(&F); + for (auto &A : F.args()) + if (O.shouldKeep()) + ArgsToKeep.insert(&A); + } + + for (auto *F : Funcs) { + ValueToValueMapTy VMap; + std::vector<WeakVH> InstToDelete; + for (auto &A : F->args()) + if (!ArgsToKeep.count(&A)) { + // By adding undesired arguments to the VMap, CloneFunction will remove + // them from the resulting Function + VMap[&A] = UndefValue::get(A.getType()); + for (auto *U : A.users()) + if (auto *I = dyn_cast<Instruction>(*&U)) + InstToDelete.push_back(I); + } + // Delete any (unique) instruction that uses the argument + for (Value *V : InstToDelete) { + if (!V) + continue; + auto *I = cast<Instruction>(V); + I->replaceAllUsesWith(UndefValue::get(I->getType())); + if (!I->isTerminator()) + I->eraseFromParent(); + } + + // No arguments to reduce + if (VMap.empty()) + continue; + + std::set<int> ArgIndexesToKeep; + for (auto &Arg : enumerate(F->args())) + if (ArgsToKeep.count(&Arg.value())) + ArgIndexesToKeep.insert(Arg.index()); + + auto *ClonedFunc = CloneFunction(F, VMap); + // In order to preserve function order, we move Clone after old Function + ClonedFunc->removeFromParent(); + Program->getFunctionList().insertAfter(F->getIterator(), ClonedFunc); + + replaceFunctionCalls(*F, *ClonedFunc, ArgIndexesToKeep); + // Rename Cloned Function to Old's name + std::string FName = std::string(F->getName()); + F->replaceAllUsesWith(ConstantExpr::getBitCast(ClonedFunc, F->getType())); + F->eraseFromParent(); + ClonedFunc->setName(FName); + } +} + +/// Counts the amount of arguments in non-declaration functions and prints their +/// respective name, index, and parent function name +static int countArguments(Module *Program) { + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + outs() << "Param Index Reference:\n"; + int ArgsCount = 0; + for (auto &F : *Program) + if (!F.arg_empty()) { + outs() << " " << F.getName() << "\n"; + for (auto &A : F.args()) + outs() << "\t" << ++ArgsCount << ": " << A.getName() << "\n"; + + outs() << "----------------------------\n"; + } + + return ArgsCount; +} + +void llvm::reduceArgumentsDeltaPass(TestRunner &Test) { + outs() << "*** Reducing Arguments...\n"; + int ArgCount = countArguments(Test.getProgram()); + runDeltaPass(Test, ArgCount, extractArgumentsFromModule); +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceArguments.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceArguments.h new file mode 100644 index 0000000000..d9682b44f7 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceArguments.h @@ -0,0 +1,21 @@ +//===- ReduceArguments.h - Specialized Delta Pass -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting Arguments from defined functions. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" +#include "llvm/IR/Argument.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" + +namespace llvm { +void reduceArgumentsDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAttributes.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAttributes.cpp new file mode 100644 index 0000000000..cbaf5d5efd --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAttributes.cpp @@ -0,0 +1,200 @@ +//===- ReduceAttributes.cpp - Specialized Delta Pass -------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting attributes. +// +//===----------------------------------------------------------------------===// + +#include "ReduceAttributes.h" +#include "Delta.h" +#include "TestRunner.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <iterator> +#include <utility> +#include <vector> + +namespace llvm { +class LLVMContext; +} // namespace llvm + +using namespace llvm; + +namespace { + +using AttrPtrVecTy = std::vector<const Attribute *>; +using AttrPtrIdxVecVecTy = std::pair<unsigned, AttrPtrVecTy>; +using AttrPtrVecVecTy = SmallVector<AttrPtrIdxVecVecTy, 3>; + +/// Given ChunksToKeep, produce a map of global variables/functions/calls +/// and indexes of attributes to be preserved for each of them. +class AttributeRemapper : public InstVisitor<AttributeRemapper> { + Oracle O; + +public: + DenseMap<GlobalVariable *, AttrPtrVecTy> GlobalVariablesToRefine; + DenseMap<Function *, AttrPtrVecVecTy> FunctionsToRefine; + DenseMap<CallBase *, AttrPtrVecVecTy> CallsToRefine; + + explicit AttributeRemapper(ArrayRef<Chunk> ChunksToKeep) : O(ChunksToKeep) {} + + void visitModule(Module &M) { + for (GlobalVariable &GV : M.getGlobalList()) + visitGlobalVariable(GV); + } + + void visitGlobalVariable(GlobalVariable &GV) { + // Global variables only have one attribute set. + const AttributeSet &AS = GV.getAttributes(); + if (AS.hasAttributes()) + visitAttributeSet(AS, GlobalVariablesToRefine[&GV]); + } + + void visitFunction(Function &F) { + if (F.getIntrinsicID() != Intrinsic::not_intrinsic) + return; // We can neither add nor remove attributes from intrinsics. + visitAttributeList(F.getAttributes(), FunctionsToRefine[&F]); + } + + void visitCallBase(CallBase &I) { + visitAttributeList(I.getAttributes(), CallsToRefine[&I]); + } + + void visitAttributeList(const AttributeList &AL, + AttrPtrVecVecTy &AttributeSetsToPreserve) { + assert(AttributeSetsToPreserve.empty() && "Should not be sharing vectors."); + AttributeSetsToPreserve.reserve(AL.getNumAttrSets()); + for (unsigned SetIdx : seq(AL.index_begin(), AL.index_end())) { + AttrPtrIdxVecVecTy AttributesToPreserve; + AttributesToPreserve.first = SetIdx; + visitAttributeSet(AL.getAttributes(AttributesToPreserve.first), + AttributesToPreserve.second); + if (!AttributesToPreserve.second.empty()) + AttributeSetsToPreserve.emplace_back(std::move(AttributesToPreserve)); + } + } + + void visitAttributeSet(const AttributeSet &AS, + AttrPtrVecTy &AttrsToPreserve) { + assert(AttrsToPreserve.empty() && "Should not be sharing vectors."); + AttrsToPreserve.reserve(AS.getNumAttributes()); + for (const Attribute &A : AS) + if (O.shouldKeep()) + AttrsToPreserve.emplace_back(&A); + } +}; + +struct AttributeCounter : public InstVisitor<AttributeCounter> { + /// How many features (in this case, attributes) did we count, total? + int AttributeCount = 0; + + void visitModule(Module &M) { + for (GlobalVariable &GV : M.getGlobalList()) + visitGlobalVariable(GV); + } + + void visitGlobalVariable(GlobalVariable &GV) { + // Global variables only have one attribute set. + visitAttributeSet(GV.getAttributes()); + } + + void visitFunction(Function &F) { + if (F.getIntrinsicID() != Intrinsic::not_intrinsic) + return; // We can neither add nor remove attributes from intrinsics. + visitAttributeList(F.getAttributes()); + } + + void visitCallBase(CallBase &I) { visitAttributeList(I.getAttributes()); } + + void visitAttributeList(const AttributeList &AL) { + for (const AttributeSet &AS : AL) + visitAttributeSet(AS); + } + + void visitAttributeSet(const AttributeSet &AS) { + AttributeCount += AS.getNumAttributes(); + } +}; + +} // namespace + +AttributeSet +convertAttributeRefToAttributeSet(LLVMContext &C, + ArrayRef<const Attribute *> Attributes) { + AttrBuilder B; + for (const Attribute *A : Attributes) + B.addAttribute(*A); + return AttributeSet::get(C, B); +} + +AttributeList convertAttributeRefVecToAttributeList( + LLVMContext &C, ArrayRef<AttrPtrIdxVecVecTy> AttributeSets) { + std::vector<std::pair<unsigned, AttributeSet>> SetVec; + SetVec.reserve(AttributeSets.size()); + + transform(AttributeSets, std::back_inserter(SetVec), + [&C](const AttrPtrIdxVecVecTy &V) { + return std::make_pair( + V.first, convertAttributeRefToAttributeSet(C, V.second)); + }); + + sort(SetVec, [](const std::pair<unsigned, AttributeSet> &LHS, + const std::pair<unsigned, AttributeSet> &RHS) { + return LHS.first < RHS.first; // All values are unique. + }); + + return AttributeList::get(C, SetVec); +} + +/// Removes out-of-chunk attributes from module. +static void extractAttributesFromModule(std::vector<Chunk> ChunksToKeep, + Module *Program) { + AttributeRemapper R(ChunksToKeep); + R.visit(Program); + + LLVMContext &C = Program->getContext(); + for (const auto &I : R.GlobalVariablesToRefine) + I.first->setAttributes(convertAttributeRefToAttributeSet(C, I.second)); + for (const auto &I : R.FunctionsToRefine) + I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second)); + for (const auto &I : R.CallsToRefine) + I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second)); +} + +/// Counts the amount of attributes. +static int countAttributes(Module *Program) { + AttributeCounter C; + + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + C.visit(Program); + outs() << "Number of attributes: " << C.AttributeCount << "\n"; + + return C.AttributeCount; +} + +void llvm::reduceAttributesDeltaPass(TestRunner &Test) { + outs() << "*** Reducing Attributes...\n"; + int AttributeCount = countAttributes(Test.getProgram()); + runDeltaPass(Test, AttributeCount, extractAttributesFromModule); +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAttributes.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAttributes.h new file mode 100644 index 0000000000..f8deb04556 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceAttributes.h @@ -0,0 +1,20 @@ +//===- ReduceAttributes.h - Specialized Delta Pass ------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting attributes. +// +//===----------------------------------------------------------------------===// + +namespace llvm { + +class TestRunner; + +void reduceAttributesDeltaPass(TestRunner &Test); + +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp new file mode 100644 index 0000000000..8c0832dd88 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp @@ -0,0 +1,150 @@ +//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting Arguments from defined functions. +// +//===----------------------------------------------------------------------===// + +#include "ReduceBasicBlocks.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> + +using namespace llvm; + +/// Replaces BB Terminator with one that only contains Chunk BBs +static void replaceBranchTerminator(BasicBlock &BB, + std::set<BasicBlock *> BBsToKeep) { + auto Term = BB.getTerminator(); + std::vector<BasicBlock *> ChunkSucessors; + for (auto Succ : successors(&BB)) + if (BBsToKeep.count(Succ)) + ChunkSucessors.push_back(Succ); + + // BB only references Chunk BBs + if (ChunkSucessors.size() == Term->getNumSuccessors()) + return; + + bool IsBranch = isa<BranchInst>(Term) || isa<InvokeInst>(Term); + Value *Address = nullptr; + if (auto IndBI = dyn_cast<IndirectBrInst>(Term)) + Address = IndBI->getAddress(); + + Term->replaceAllUsesWith(UndefValue::get(Term->getType())); + Term->eraseFromParent(); + + if (ChunkSucessors.empty()) { + auto *FnRetTy = BB.getParent()->getReturnType(); + ReturnInst::Create(BB.getContext(), + FnRetTy->isVoidTy() ? nullptr : UndefValue::get(FnRetTy), + &BB); + return; + } + + if (IsBranch) + BranchInst::Create(ChunkSucessors[0], &BB); + + if (Address) { + auto NewIndBI = + IndirectBrInst::Create(Address, ChunkSucessors.size(), &BB); + for (auto Dest : ChunkSucessors) + NewIndBI->addDestination(Dest); + } +} + +/// Removes uninteresting BBs from switch, if the default case ends up being +/// uninteresting, the switch is replaced with a void return (since it has to be +/// replace with something) +static void removeUninterestingBBsFromSwitch(SwitchInst &SwInst, + std::set<BasicBlock *> BBsToKeep) { + if (!BBsToKeep.count(SwInst.getDefaultDest())) { + auto *FnRetTy = SwInst.getParent()->getParent()->getReturnType(); + ReturnInst::Create(SwInst.getContext(), + FnRetTy->isVoidTy() ? nullptr : UndefValue::get(FnRetTy), + SwInst.getParent()); + SwInst.eraseFromParent(); + } else + for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) { + auto Case = SwInst.case_begin() + I; + if (!BBsToKeep.count(Case->getCaseSuccessor())) { + SwInst.removeCase(Case); + --I; + --E; + } + } +} + +/// Removes out-of-chunk arguments from functions, and modifies their calls +/// accordingly. It also removes allocations of out-of-chunk arguments. +static void extractBasicBlocksFromModule(std::vector<Chunk> ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + std::set<BasicBlock *> BBsToKeep; + + for (auto &F : *Program) + for (auto &BB : F) + if (O.shouldKeep()) + BBsToKeep.insert(&BB); + + std::vector<BasicBlock *> BBsToDelete; + for (auto &F : *Program) + for (auto &BB : F) { + if (!BBsToKeep.count(&BB)) { + BBsToDelete.push_back(&BB); + // Remove out-of-chunk BB from successor phi nodes + for (auto *Succ : successors(&BB)) + Succ->removePredecessor(&BB); + } + } + + // Replace terminators that reference out-of-chunk BBs + for (auto &F : *Program) + for (auto &BB : F) { + if (auto *SwInst = dyn_cast<SwitchInst>(BB.getTerminator())) + removeUninterestingBBsFromSwitch(*SwInst, BBsToKeep); + else + replaceBranchTerminator(BB, BBsToKeep); + } + + // Replace out-of-chunk switch uses + for (auto &BB : BBsToDelete) { + // Instructions might be referenced in other BBs + for (auto &I : *BB) + I.replaceAllUsesWith(UndefValue::get(I.getType())); + BB->eraseFromParent(); + } +} + +/// Counts the amount of basic blocks and prints their name & respective index +static int countBasicBlocks(Module *Program) { + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + int BBCount = 0; + for (auto &F : *Program) + for (auto &BB : F) { + if (BB.hasName()) + outs() << "\t" << ++BBCount << ": " << BB.getName() << "\n"; + else + outs() << "\t" << ++BBCount << ": Unnamed\n"; + } + + return BBCount; +} + +void llvm::reduceBasicBlocksDeltaPass(TestRunner &Test) { + outs() << "*** Reducing Basic Blocks...\n"; + int BBCount = countBasicBlocks(Test.getProgram()); + runDeltaPass(Test, BBCount, extractBasicBlocksFromModule); +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceBasicBlocks.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceBasicBlocks.h new file mode 100644 index 0000000000..cf76a0abbc --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceBasicBlocks.h @@ -0,0 +1,20 @@ +//===- ReduceArguments.h - Specialized Delta Pass -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting Arguments from defined functions. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" + +namespace llvm { +void reduceBasicBlocksDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp new file mode 100644 index 0000000000..99be76eac3 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp @@ -0,0 +1,57 @@ +//===- ReduceFunctions.cpp - Specialized Delta Pass -----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce function bodies in the provided Module. +// +//===----------------------------------------------------------------------===// + +#include "ReduceFunctionBodies.h" +#include "Delta.h" +#include "llvm/IR/GlobalValue.h" + +using namespace llvm; + +/// Removes all the bodies of defined functions that aren't inside any of the +/// desired Chunks. +static void +extractFunctionBodiesFromModule(const std::vector<Chunk> &ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + // Delete out-of-chunk function bodies + std::vector<Function *> FuncDefsToReduce; + for (auto &F : *Program) + if (!F.isDeclaration() && !O.shouldKeep()) { + F.deleteBody(); + F.setComdat(nullptr); + } +} + +/// Counts the amount of non-declaration functions and prints their +/// respective name & index +static int countFunctionDefinitions(Module *Program) { + // TODO: Silence index with --quiet flag + errs() << "----------------------------\n"; + errs() << "Function Definition Index Reference:\n"; + int FunctionDefinitionCount = 0; + for (auto &F : *Program) + if (!F.isDeclaration()) + errs() << "\t" << ++FunctionDefinitionCount << ": " << F.getName() + << "\n"; + + errs() << "----------------------------\n"; + return FunctionDefinitionCount; +} + +void llvm::reduceFunctionBodiesDeltaPass(TestRunner &Test) { + errs() << "*** Reducing Function Bodies...\n"; + int Functions = countFunctionDefinitions(Test.getProgram()); + runDeltaPass(Test, Functions, extractFunctionBodiesFromModule); + errs() << "----------------------------\n"; +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctionBodies.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctionBodies.h new file mode 100644 index 0000000000..8c06c2e4a1 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctionBodies.h @@ -0,0 +1,18 @@ +//===- ReduceFunctionBodies.h - Specialized Delta Pass --------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce function bodies in the provided Module. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" + +namespace llvm { +void reduceFunctionBodiesDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctions.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctions.cpp new file mode 100644 index 0000000000..d100935ee4 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctions.cpp @@ -0,0 +1,77 @@ +//===- ReduceFunctions.cpp - Specialized Delta Pass -----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce functions (and any instruction that calls it) in the provided +// Module. +// +//===----------------------------------------------------------------------===// + +#include "ReduceFunctions.h" +#include "Delta.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Instructions.h" +#include <iterator> +#include <vector> + +using namespace llvm; + +/// Removes all the Defined Functions +/// that aren't inside any of the desired Chunks. +static void extractFunctionsFromModule(const std::vector<Chunk> &ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + // Record all out-of-chunk functions. + std::vector<std::reference_wrapper<Function>> FuncsToRemove; + copy_if(Program->functions(), std::back_inserter(FuncsToRemove), + [&O](Function &F) { + // Intrinsics don't have function bodies that are useful to + // reduce. Additionally, intrinsics may have additional operand + // constraints. But, do drop intrinsics that are not referenced. + return (!F.isIntrinsic() || F.use_empty()) && !O.shouldKeep(); + }); + + // Then, drop body of each of them. We want to batch this and do nothing else + // here so that minimal number of remaining exteranal uses will remain. + for (Function &F : FuncsToRemove) + F.dropAllReferences(); + + // And finally, we can actually delete them. + for (Function &F : FuncsToRemove) { + // Replace all *still* remaining uses with undef. + F.replaceAllUsesWith(UndefValue::get(F.getType())); + // And finally, fully drop it. + F.eraseFromParent(); + } +} + +/// Counts the amount of functions and prints their +/// respective name & index +static int countFunctions(Module *Program) { + // TODO: Silence index with --quiet flag + errs() << "----------------------------\n"; + errs() << "Function Index Reference:\n"; + int FunctionCount = 0; + for (auto &F : *Program) { + if (F.isIntrinsic() && !F.use_empty()) + continue; + + errs() << '\t' << ++FunctionCount << ": " << F.getName() << '\n'; + } + + errs() << "----------------------------\n"; + return FunctionCount; +} + +void llvm::reduceFunctionsDeltaPass(TestRunner &Test) { + errs() << "*** Reducing Functions...\n"; + int Functions = countFunctions(Test.getProgram()); + runDeltaPass(Test, Functions, extractFunctionsFromModule); + errs() << "----------------------------\n"; +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctions.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctions.h new file mode 100644 index 0000000000..7c2cd3f33e --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceFunctions.h @@ -0,0 +1,20 @@ +//===- ReduceFunctions.h - Specialized Delta Pass -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce functions (and any instruction that calls it) in the provided +// Module. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" +#include "llvm/Transforms/Utils/Cloning.h" + +namespace llvm { +void reduceFunctionsDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp new file mode 100644 index 0000000000..fd5a5d1f02 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp @@ -0,0 +1,52 @@ +//===- ReduceGlobalVars.cpp - Specialized Delta Pass ----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce initializers of Global Variables in the provided Module. +// +//===----------------------------------------------------------------------===// + +#include "ReduceGlobalVarInitializers.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalValue.h" + +using namespace llvm; + +/// Removes all the Initialized GVs that aren't inside the desired Chunks. +static void extractGVsFromModule(std::vector<Chunk> ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + // Drop initializers of out-of-chunk GVs + for (auto &GV : Program->globals()) + if (GV.hasInitializer() && !O.shouldKeep()) { + GV.setInitializer(nullptr); + GV.setLinkage(GlobalValue::LinkageTypes::ExternalLinkage); + GV.setComdat(nullptr); + } +} + +/// Counts the amount of initialized GVs and displays their +/// respective name & index +static int countGVs(Module *Program) { + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + outs() << "GlobalVariable Index Reference:\n"; + int GVCount = 0; + for (auto &GV : Program->globals()) + if (GV.hasInitializer()) + outs() << "\t" << ++GVCount << ": " << GV.getName() << "\n"; + outs() << "----------------------------\n"; + return GVCount; +} + +void llvm::reduceGlobalsInitializersDeltaPass(TestRunner &Test) { + outs() << "*** Reducing GVs initializers...\n"; + int GVCount = countGVs(Test.getProgram()); + runDeltaPass(Test, GVCount, extractGVsFromModule); +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.h new file mode 100644 index 0000000000..39288adce8 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.h @@ -0,0 +1,21 @@ +//===- reduceGlobalsInitializersDeltaPass.h - Specialized Delta Pass +//-------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce initializers of Global Variables in the provided Module. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" +#include "llvm/IR/Value.h" +#include "llvm/Transforms/Utils/Cloning.h" + +namespace llvm { +void reduceGlobalsInitializersDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp new file mode 100644 index 0000000000..4b184e5b3e --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp @@ -0,0 +1,74 @@ +//===- ReduceGlobalVars.cpp - Specialized Delta Pass ----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce Global Variables in the provided Module. +// +//===----------------------------------------------------------------------===// + +#include "ReduceGlobalVars.h" +#include "llvm/IR/Constants.h" +#include <set> + +using namespace llvm; + +/// Removes all the GVs that aren't inside the desired Chunks. +static void extractGVsFromModule(std::vector<Chunk> ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + // Get GVs inside desired chunks + std::set<GlobalVariable *> GVsToKeep; + for (auto &GV : Program->globals()) + if (O.shouldKeep()) + GVsToKeep.insert(&GV); + + // Delete out-of-chunk GVs and their uses + std::vector<GlobalVariable *> ToRemove; + std::vector<WeakVH> InstToRemove; + for (auto &GV : Program->globals()) + if (!GVsToKeep.count(&GV)) { + for (auto U : GV.users()) + if (auto *Inst = dyn_cast<Instruction>(U)) + InstToRemove.push_back(Inst); + + GV.replaceAllUsesWith(UndefValue::get(GV.getType())); + ToRemove.push_back(&GV); + } + + // Delete (unique) Instruction uses of unwanted GVs + for (Value *V : InstToRemove) { + if (!V) + continue; + auto *Inst = cast<Instruction>(V); + Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); + Inst->eraseFromParent(); + } + + for (auto *GV : ToRemove) + GV->eraseFromParent(); +} + +/// Counts the amount of GVs and displays their +/// respective name & index +static int countGVs(Module *Program) { + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + outs() << "GlobalVariable Index Reference:\n"; + int GVCount = 0; + for (auto &GV : Program->globals()) + outs() << "\t" << ++GVCount << ": " << GV.getName() << "\n"; + outs() << "----------------------------\n"; + return GVCount; +} + +void llvm::reduceGlobalsDeltaPass(TestRunner &Test) { + outs() << "*** Reducing GVs...\n"; + int GVCount = countGVs(Test.getProgram()); + runDeltaPass(Test, GVCount, extractGVsFromModule); +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVars.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVars.h new file mode 100644 index 0000000000..c8ba7eacb8 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceGlobalVars.h @@ -0,0 +1,20 @@ +//===- ReduceGlobalVars.h - Specialized Delta Pass ------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce Global Variables in the provided Module. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" +#include "llvm/IR/Value.h" +#include "llvm/Transforms/Utils/Cloning.h" + +namespace llvm { +void reduceGlobalsDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceInstructions.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceInstructions.cpp new file mode 100644 index 0000000000..3e37ec5e17 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceInstructions.cpp @@ -0,0 +1,67 @@ +//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting Arguments from defined functions. +// +//===----------------------------------------------------------------------===// + +#include "ReduceInstructions.h" + +using namespace llvm; + +/// Removes out-of-chunk arguments from functions, and modifies their calls +/// accordingly. It also removes allocations of out-of-chunk arguments. +static void extractInstrFromModule(std::vector<Chunk> ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + std::set<Instruction *> InstToKeep; + + for (auto &F : *Program) + for (auto &BB : F) { + // Removing the terminator would make the block invalid. Only iterate over + // instructions before the terminator. + InstToKeep.insert(BB.getTerminator()); + for (auto &Inst : make_range(BB.begin(), std::prev(BB.end()))) + if (O.shouldKeep()) + InstToKeep.insert(&Inst); + } + + std::vector<Instruction *> InstToDelete; + for (auto &F : *Program) + for (auto &BB : F) + for (auto &Inst : BB) + if (!InstToKeep.count(&Inst)) { + Inst.replaceAllUsesWith(UndefValue::get(Inst.getType())); + InstToDelete.push_back(&Inst); + } + + for (auto &I : InstToDelete) + I->eraseFromParent(); +} + +/// Counts the amount of basic blocks and prints their name & respective index +static unsigned countInstructions(Module *Program) { + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + int InstCount = 0; + for (auto &F : *Program) + for (auto &BB : F) + // Well-formed blocks have terminators, which we cannot remove. + InstCount += BB.getInstList().size() - 1; + outs() << "Number of instructions: " << InstCount << "\n"; + + return InstCount; +} + +void llvm::reduceInstructionsDeltaPass(TestRunner &Test) { + outs() << "*** Reducing Instructions...\n"; + unsigned InstCount = countInstructions(Test.getProgram()); + runDeltaPass(Test, InstCount, extractInstrFromModule); +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceInstructions.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceInstructions.h new file mode 100644 index 0000000000..a9266acd05 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceInstructions.h @@ -0,0 +1,20 @@ +//===- ReduceArguments.h - Specialized Delta Pass -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting Arguments from defined functions. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" + +namespace llvm { +void reduceInstructionsDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceMetadata.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceMetadata.cpp new file mode 100644 index 0000000000..4587295a00 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceMetadata.cpp @@ -0,0 +1,127 @@ +//===- ReduceMetadata.cpp - Specialized Delta Pass ------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements two functions used by the Generic Delta Debugging +// Algorithm, which are used to reduce Metadata nodes. +// +//===----------------------------------------------------------------------===// + +#include "ReduceMetadata.h" +#include "Delta.h" +#include "llvm/ADT/SmallVector.h" +#include <set> +#include <vector> + +using namespace llvm; + +/// Adds all Unnamed Metadata Nodes that are inside desired Chunks to set +template <class T> +static void getChunkMetadataNodes(T &MDUser, Oracle &O, + std::set<MDNode *> &SeenNodes, + std::set<MDNode *> &NodesToKeep) { + SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; + MDUser.getAllMetadata(MDs); + for (auto &MD : MDs) { + SeenNodes.insert(MD.second); + if (O.shouldKeep()) + NodesToKeep.insert(MD.second); + } +} + +/// Erases out-of-chunk unnamed metadata nodes from its user +template <class T> +static void eraseMetadataIfOutsideChunk(T &MDUser, + const std::set<MDNode *> &NodesToKeep) { + SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; + MDUser.getAllMetadata(MDs); + for (int I = 0, E = MDs.size(); I != E; ++I) + if (!NodesToKeep.count(MDs[I].second)) + MDUser.setMetadata(I, NULL); +} + +/// Removes all the Named and Unnamed Metadata Nodes, as well as any debug +/// functions that aren't inside the desired Chunks. +static void extractMetadataFromModule(const std::vector<Chunk> &ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + std::set<MDNode *> SeenNodes; + std::set<MDNode *> NodesToKeep; + + // Add chunk MDNodes used by GVs, Functions, and Instructions to set + for (auto &GV : Program->globals()) + getChunkMetadataNodes(GV, O, SeenNodes, NodesToKeep); + + for (auto &F : *Program) { + getChunkMetadataNodes(F, O, SeenNodes, NodesToKeep); + for (auto &BB : F) + for (auto &Inst : BB) + getChunkMetadataNodes(Inst, O, SeenNodes, NodesToKeep); + } + + // Once more, go over metadata nodes, but deleting the ones outside chunks + for (auto &GV : Program->globals()) + eraseMetadataIfOutsideChunk(GV, NodesToKeep); + + for (auto &F : *Program) { + eraseMetadataIfOutsideChunk(F, NodesToKeep); + for (auto &BB : F) + for (auto &Inst : BB) + eraseMetadataIfOutsideChunk(Inst, NodesToKeep); + } + + + // Get out-of-chunk Named metadata nodes + std::vector<NamedMDNode *> NamedNodesToDelete; + for (auto &MD : Program->named_metadata()) + if (!O.shouldKeep()) + NamedNodesToDelete.push_back(&MD); + + for (auto *NN : NamedNodesToDelete) { + for (int I = 0, E = NN->getNumOperands(); I != E; ++I) + NN->setOperand(I, NULL); + NN->eraseFromParent(); + } +} + +// Gets unnamed metadata nodes used by a given instruction/GV/function and adds +// them to the set of seen nodes +template <class T> +static void addMetadataToSet(T &MDUser, std::set<MDNode *> &UnnamedNodes) { + SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; + MDUser.getAllMetadata(MDs); + for (auto &MD : MDs) + UnnamedNodes.insert(MD.second); +} + +/// Returns the amount of Named and Unnamed Metadata Nodes +static int countMetadataTargets(Module *Program) { + std::set<MDNode *> UnnamedNodes; + int NamedMetadataNodes = Program->named_metadata_size(); + + // Get metadata nodes used by globals + for (auto &GV : Program->globals()) + addMetadataToSet(GV, UnnamedNodes); + + // Do the same for nodes used by functions & instructions + for (auto &F : *Program) { + addMetadataToSet(F, UnnamedNodes); + for (auto &BB : F) + for (auto &I : BB) + addMetadataToSet(I, UnnamedNodes); + } + + return UnnamedNodes.size() + NamedMetadataNodes; +} + +void llvm::reduceMetadataDeltaPass(TestRunner &Test) { + outs() << "*** Reducing Metadata...\n"; + int MDCount = countMetadataTargets(Test.getProgram()); + runDeltaPass(Test, MDCount, extractMetadataFromModule); + outs() << "----------------------------\n"; +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceMetadata.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceMetadata.h new file mode 100644 index 0000000000..275b44c2aa --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceMetadata.h @@ -0,0 +1,18 @@ +//===- ReduceMetadata.h - Specialized Delta Pass ------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements two functions used by the Generic Delta Debugging +// Algorithm, which are used to reduce Metadata nodes. +// +//===----------------------------------------------------------------------===// + +#include "TestRunner.h" + +namespace llvm { +void reduceMetadataDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp new file mode 100644 index 0000000000..77cb73837c --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp @@ -0,0 +1,124 @@ +//===- ReduceOperandBundes.cpp - Specialized Delta Pass -------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting operand bundes from calls. +// +//===----------------------------------------------------------------------===// + +#include "ReduceOperandBundles.h" +#include "Delta.h" +#include "TestRunner.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <iterator> +#include <vector> + +namespace llvm { +class Module; +} // namespace llvm + +using namespace llvm; + +namespace { + +/// Given ChunksToKeep, produce a map of calls and indexes of operand bundles +/// to be preserved for each call. +class OperandBundleRemapper : public InstVisitor<OperandBundleRemapper> { + Oracle O; + +public: + DenseMap<CallBase *, std::vector<unsigned>> CallsToRefine; + + explicit OperandBundleRemapper(ArrayRef<Chunk> ChunksToKeep) + : O(ChunksToKeep) {} + + /// So far only CallBase sub-classes can have operand bundles. + /// Let's see which of the operand bundles of this call are to be kept. + void visitCallBase(CallBase &Call) { + if (!Call.hasOperandBundles()) + return; // No bundles to begin with. + + // Insert this call into map, we will likely want to rebuild it. + auto &OperandBundlesToKeepIndexes = CallsToRefine[&Call]; + OperandBundlesToKeepIndexes.reserve(Call.getNumOperandBundles()); + + // Enumerate every operand bundle on this call. + for (unsigned BundleIndex : seq(0U, Call.getNumOperandBundles())) + if (O.shouldKeep()) // Should we keep this one? + OperandBundlesToKeepIndexes.emplace_back(BundleIndex); + } +}; + +struct OperandBundleCounter : public InstVisitor<OperandBundleCounter> { + /// How many features (in this case, operand bundles) did we count, total? + int OperandBundeCount = 0; + + /// So far only CallBase sub-classes can have operand bundles. + void visitCallBase(CallBase &Call) { + // Just accumulate the total number of operand bundles. + OperandBundeCount += Call.getNumOperandBundles(); + } +}; + +} // namespace + +static void maybeRewriteCallWithDifferentBundles( + CallBase *OrigCall, ArrayRef<unsigned> OperandBundlesToKeepIndexes) { + if (OperandBundlesToKeepIndexes.size() == OrigCall->getNumOperandBundles()) + return; // Not modifying operand bundles of this call after all. + + std::vector<OperandBundleDef> NewBundles; + NewBundles.reserve(OperandBundlesToKeepIndexes.size()); + + // Actually copy over the bundles that we want to keep. + transform(OperandBundlesToKeepIndexes, std::back_inserter(NewBundles), + [OrigCall](unsigned Index) { + return OperandBundleDef(OrigCall->getOperandBundleAt(Index)); + }); + + // Finally actually replace the bundles on the call. + CallBase *NewCall = CallBase::Create(OrigCall, NewBundles, OrigCall); + OrigCall->replaceAllUsesWith(NewCall); + OrigCall->eraseFromParent(); +} + +/// Removes out-of-chunk operand bundles from calls. +static void extractOperandBundesFromModule(std::vector<Chunk> ChunksToKeep, + Module *Program) { + OperandBundleRemapper R(ChunksToKeep); + R.visit(Program); + + for (const auto &I : R.CallsToRefine) + maybeRewriteCallWithDifferentBundles(I.first, I.second); +} + +/// Counts the amount of operand bundles. +static int countOperandBundes(Module *Program) { + OperandBundleCounter C; + + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + C.visit(Program); + outs() << "Number of operand bundles: " << C.OperandBundeCount << "\n"; + + return C.OperandBundeCount; +} + +void llvm::reduceOperandBundesDeltaPass(TestRunner &Test) { + outs() << "*** Reducing OperandBundes...\n"; + int OperandBundeCount = countOperandBundes(Test.getProgram()); + runDeltaPass(Test, OperandBundeCount, extractOperandBundesFromModule); +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceOperandBundles.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceOperandBundles.h new file mode 100644 index 0000000000..382c5cb569 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceOperandBundles.h @@ -0,0 +1,20 @@ +//===- ReduceOperandBundes.h - Specialized Delta Pass ---------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting operand bundes from calls. +// +//===----------------------------------------------------------------------===// + +namespace llvm { + +class TestRunner; + +void reduceOperandBundesDeltaPass(TestRunner &Test); + +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp new file mode 100644 index 0000000000..dedeac8287 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp @@ -0,0 +1,62 @@ +//===- ReduceSpecialGlobals.cpp - Specialized Delta Pass ------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce special globals, like @llvm.used, in the provided Module. +// +// For more details about special globals, see +// https://llvm.org/docs/LangRef.html#intrinsic-global-variables +// +//===----------------------------------------------------------------------===// + +#include "ReduceSpecialGlobals.h" +#include "Delta.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalValue.h" + +using namespace llvm; + +static StringRef SpecialGlobalNames[] = {"llvm.used", "llvm.compiler.used"}; + +/// Removes all special globals aren't inside any of the +/// desired Chunks. +static void +extractSpecialGlobalsFromModule(const std::vector<Chunk> &ChunksToKeep, + Module *Program) { + Oracle O(ChunksToKeep); + + for (StringRef Name : SpecialGlobalNames) { + if (auto *Used = Program->getNamedGlobal(Name)) { + Used->replaceAllUsesWith(UndefValue::get(Used->getType())); + Used->eraseFromParent(); + } + } +} + +/// Counts the amount of special globals and prints their +/// respective name & index +static int countSpecialGlobals(Module *Program) { + // TODO: Silence index with --quiet flag + errs() << "----------------------------\n"; + errs() << "Special Globals Index Reference:\n"; + int Count = 0; + for (StringRef Name : SpecialGlobalNames) { + if (auto *Used = Program->getNamedGlobal(Name)) + errs() << "\t" << ++Count << ": " << Used->getName() << "\n"; + } + errs() << "----------------------------\n"; + return Count; +} + +void llvm::reduceSpecialGlobalsDeltaPass(TestRunner &Test) { + errs() << "*** Reducing Special Globals ...\n"; + int Functions = countSpecialGlobals(Test.getProgram()); + runDeltaPass(Test, Functions, extractSpecialGlobalsFromModule); + errs() << "----------------------------\n"; +} diff --git a/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceSpecialGlobals.h b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceSpecialGlobals.h new file mode 100644 index 0000000000..52ecaed4cd --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-reduce/deltas/ReduceSpecialGlobals.h @@ -0,0 +1,21 @@ +//===- ReduceSpecialGlobals.h - Specialized Delta Pass --------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce special globals, like @llvm.used, in the provided Module. +// +// For more details about special globals, see +// https://llvm.org/docs/LangRef.html#intrinsic-global-variables +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" + +namespace llvm { +void reduceSpecialGlobalsDeltaPass(TestRunner &Test); +} // namespace llvm |