mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Add pipeline invalidation
Replace the stub implementation of invalidation with the proper implementation. A ReadPathCache is added to each global so that it can keep tracks of what target are associated to which read paths.
This commit is contained in:
@@ -57,7 +57,7 @@ public:
|
||||
|
||||
private:
|
||||
T Content;
|
||||
mutable AccessTracker Exact;
|
||||
mutable AccessTracker Exact = AccessTracker(false);
|
||||
mutable std::vector<TrackingSet> NonExisting;
|
||||
mutable std::vector<llvm::BitVector> Existing;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
pipeline::InputPreservation::Preserve) };
|
||||
}
|
||||
|
||||
void run(pipeline::Context &Ctx,
|
||||
void run(pipeline::ExecutionContext &Ctx,
|
||||
const BinaryFileContainer &SourceBinary,
|
||||
pipeline::LLVMContainer &Output);
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ public:
|
||||
pipeline::InputPreservation::Preserve) };
|
||||
}
|
||||
|
||||
void run(const pipeline::Context &Ctx, pipeline::LLVMContainer &TargetsList);
|
||||
void run(const pipeline::ExecutionContext &Ctx,
|
||||
pipeline::LLVMContainer &TargetsList);
|
||||
|
||||
void print(const pipeline::Context &Ctx,
|
||||
llvm::raw_ostream &OS,
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
llvm::Error run(pipeline::Context &Context,
|
||||
llvm::Error run(pipeline::ExecutionContext &Context,
|
||||
const BinaryFileContainer &SourceBinary);
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = {};
|
||||
|
||||
public:
|
||||
void run(pipeline::Context &Context);
|
||||
void run(pipeline::ExecutionContext &Context);
|
||||
};
|
||||
|
||||
} // namespace revng::pipes
|
||||
|
||||
@@ -21,8 +21,54 @@ inline Logger<> ModelVerifyLogger("model-verify");
|
||||
namespace model {
|
||||
class Type;
|
||||
class Identifier;
|
||||
|
||||
class VerifyHelper {
|
||||
private:
|
||||
template<typename TrackableTupleTree>
|
||||
class TrackingSuspender {
|
||||
private:
|
||||
VerifyHelper *TheContext;
|
||||
std::optional<TrackGuard<TrackableTupleTree>> Guard;
|
||||
|
||||
public:
|
||||
TrackingSuspender(TrackingSuspender &&Other) :
|
||||
TheContext(Other.TheContext), Guard(std::move(Other.Guard)) {}
|
||||
TrackingSuspender &operator=(TrackingSuspender &Other) {
|
||||
if (this == Other)
|
||||
return *this;
|
||||
|
||||
onDestruction();
|
||||
TheContext = Other.TheContext;
|
||||
Guard = std::move(Other.Guard);
|
||||
return *this;
|
||||
}
|
||||
TrackingSuspender(const TrackingSuspender &Other) = delete;
|
||||
TrackingSuspender &operator=(const TrackingSuspender &Other) = delete;
|
||||
|
||||
public:
|
||||
TrackingSuspender(VerifyHelper &Context,
|
||||
const TrackableTupleTree &Trackable) :
|
||||
TheContext(&Context), Guard(std::nullopt) {
|
||||
revng_assert(TheContext != nullptr);
|
||||
if (not Context.hasPushedTracking()) {
|
||||
Context.setPushedTracking();
|
||||
Guard = TrackGuard<TrackableTupleTree>(Trackable);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
~TrackingSuspender() { onDestruction(); }
|
||||
|
||||
private:
|
||||
void onDestruction() {
|
||||
if (Guard.has_value()) {
|
||||
TheContext->setPushedTracking(false);
|
||||
Guard = std::nullopt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
friend class VerifyHelper;
|
||||
|
||||
private:
|
||||
std::set<const model::Type *> VerifiedCache;
|
||||
std::map<const model::Type *, uint64_t> SizeCache;
|
||||
@@ -30,6 +76,7 @@ private:
|
||||
std::set<const model::Type *> InProgress;
|
||||
bool AssertOnFail = false;
|
||||
std::map<model::Identifier, std::string> GlobalSymbols;
|
||||
bool HasPushedTracking = false;
|
||||
|
||||
// TODO: This is a hack for now, but the methods, when the Model does not
|
||||
// verify, should return an llvm::Error with the error message found by this.
|
||||
@@ -41,6 +88,19 @@ public:
|
||||
|
||||
~VerifyHelper() { revng_assert(InProgress.size() == 0); }
|
||||
|
||||
private:
|
||||
bool hasPushedTracking() const { return HasPushedTracking; }
|
||||
|
||||
void setPushedTracking(bool HasPushed = true) {
|
||||
HasPushedTracking = HasPushed;
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
TrackingSuspender<T> suspendTracking(const T &Trackable) {
|
||||
return TrackingSuspender<T>(*this, Trackable);
|
||||
}
|
||||
|
||||
public:
|
||||
void setVerified(const model::Type *T) {
|
||||
revng_assert(not isVerified(T));
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
Invokable.print(Ctx, OS, Indentation);
|
||||
}
|
||||
|
||||
llvm::Error run(Context &Ctx,
|
||||
llvm::Error run(ExecutionContext &Ctx,
|
||||
ContainerSet &Containers,
|
||||
const llvm::StringMap<std::string> &ExtraArgs) override {
|
||||
return Invokable.run(Ctx, Containers, ExtraArgs);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "revng/Pipeline/Container.h"
|
||||
#include "revng/Pipeline/ContainerSet.h"
|
||||
#include "revng/Pipeline/ExecutionContext.h"
|
||||
#include "revng/Pipeline/Global.h"
|
||||
#include "revng/Pipeline/GlobalsMap.h"
|
||||
#include "revng/Pipeline/KindsRegistry.h"
|
||||
@@ -126,6 +127,16 @@ public:
|
||||
public:
|
||||
llvm::Error store(const revng::DirectoryPath &Path) const;
|
||||
llvm::Error load(const revng::DirectoryPath &Path);
|
||||
};
|
||||
|
||||
public:
|
||||
void collectReadFields(const TargetInContainer &Target,
|
||||
llvm::StringMap<PathTargetBimap> &Out) const {
|
||||
Globals.collectReadFields(Target, Out);
|
||||
}
|
||||
|
||||
void clearAndResume() const { Globals.clearAndResume(); }
|
||||
void pushReadFields() const { Globals.pushReadFields(); }
|
||||
void popReadFields() const { Globals.popReadFields(); }
|
||||
void stopTracking() const { Globals.stopTracking(); }
|
||||
};
|
||||
} // namespace pipeline
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void run(const Context &, const Source &S, Destination &T) { T = S; }
|
||||
void run(const ExecutionContext &, const Source &S, Destination &T) { T = S; }
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace pipeline {
|
||||
class Context;
|
||||
class Target;
|
||||
class ContainerBase;
|
||||
class Step;
|
||||
struct PipeWrapper;
|
||||
|
||||
// A execution context is created and passed to each invocation of a pipe. It
|
||||
// provides a reference to the pipeline::Context, as well as carrying around
|
||||
// information about what is the state of the pipeline while the pipe is being
|
||||
// executed, such as what is the current step.
|
||||
//
|
||||
// The execution context is the intended way of letting the pipeline know when a
|
||||
// target is created, so that it may keep track of what paths inside pipeline
|
||||
// globals have been read to produce such target and thus it can be invalidated
|
||||
// when of element of the global indicated by such paths changes.
|
||||
//
|
||||
// We will not explain here how exactly the pipeline achieve this, but as a
|
||||
// mental model what is happening is that every access to any field of the model
|
||||
// is instrumented. When a ExecutionContext is created, or a when it commits (at
|
||||
// the end of the call, just after the commit happens), the entire tracking
|
||||
// state of the global is reset, and from that moment forward each time a
|
||||
// variable is accessed it is marked as being accessed.
|
||||
//
|
||||
// When commit with arguments Target and Container is inovked, the following
|
||||
// MUST be true:
|
||||
// * Target must be == to the last target that has been created in Container
|
||||
// * no field of any global can be read in betweet the last target being created
|
||||
// and Target being committed.
|
||||
// * Target cannot be erased by Container after commit has been invoked.
|
||||
// * No field of a global, directly or indirectly, can be read to produce a
|
||||
// target that is not the next Target to be committed. (that is, you can't
|
||||
// read fields to produce target X but then produce Y, commit Y, produce X,
|
||||
// commit X, unless you use pop and push to save and restore the state of read
|
||||
// fields).
|
||||
//
|
||||
// Less formally, you must produce and commit a target at the time.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// void SomePipeProducingFunctions(const ExecutionContext& Ctx, SomeContainer&
|
||||
// Container) {
|
||||
// ...
|
||||
// for (auto& Function : Container)
|
||||
// {
|
||||
// ...
|
||||
// Ctx.getContext().pushReadFields();
|
||||
// Ctx.commit(Container, Target(Function.metaadress()));
|
||||
// Ctx.getContext().popReadFields();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
class ExecutionContext {
|
||||
private:
|
||||
Context *TheContext = nullptr;
|
||||
Step *CurrentStep = nullptr;
|
||||
PipeWrapper *Pipe = nullptr;
|
||||
// false when running on a analysis
|
||||
bool RunningOnPipe = true;
|
||||
|
||||
void commit(const Target &Target, llvm::StringRef ContainerName);
|
||||
|
||||
public:
|
||||
~ExecutionContext();
|
||||
|
||||
public:
|
||||
ExecutionContext(Context &TheContext, Step &Step, PipeWrapper *Pipe);
|
||||
|
||||
public:
|
||||
void commit(const ContainerBase &Container, const Target &Target);
|
||||
void commitUniqueTarget(const ContainerBase &Container);
|
||||
|
||||
void clearAndResumeTracking();
|
||||
|
||||
public:
|
||||
const Context &getContext() const { return *TheContext; }
|
||||
Context &getContext() { return *TheContext; }
|
||||
|
||||
public:
|
||||
const Step &getStep() const { return *CurrentStep; }
|
||||
Step &getStep() { return *CurrentStep; }
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
@@ -176,7 +176,7 @@ public:
|
||||
return Contract;
|
||||
}
|
||||
|
||||
void run(const Context &, LLVMContainer &Container);
|
||||
void run(const ExecutionContext &, LLVMContainer &Container);
|
||||
|
||||
void addPass(const PureLLVMPassWrapper &Pass) {
|
||||
Passes.emplace_back(Pass.clone());
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include "revng/Pipeline/GlobalTupleTreeDiff.h"
|
||||
#include "revng/Pipeline/PathTargetBimap.h"
|
||||
#include "revng/Storage/Path.h"
|
||||
#include "revng/Support/YAMLTraits.h"
|
||||
#include "revng/TupleTree/Tracking.h"
|
||||
#include "revng/TupleTree/TupleTreeDiff.h"
|
||||
|
||||
namespace pipeline {
|
||||
@@ -57,6 +59,18 @@ public:
|
||||
|
||||
virtual llvm::Error store(const revng::FilePath &Path) const;
|
||||
virtual llvm::Error load(const revng::FilePath &Path);
|
||||
|
||||
virtual std::optional<TupleTreePath>
|
||||
deserializePath(llvm::StringRef Serialized) const = 0;
|
||||
virtual std::optional<std::string>
|
||||
serializePath(const TupleTreePath &Path) const = 0;
|
||||
|
||||
virtual void collectReadFields(const TargetInContainer &Target,
|
||||
PathTargetBimap &Out) = 0;
|
||||
virtual void clearAndResume() const = 0;
|
||||
virtual void pushReadFields() const = 0;
|
||||
virtual void popReadFields() const = 0;
|
||||
virtual void stopTracking() const = 0;
|
||||
};
|
||||
|
||||
template<TupleTreeCompatibleAndVerifiable Object>
|
||||
@@ -124,7 +138,10 @@ public:
|
||||
|
||||
llvm::Expected<GlobalTupleTreeDiff>
|
||||
deserializeDiff(const llvm::MemoryBuffer &Buffer) override {
|
||||
return ::deserialize<TupleTreeDiff<Object>>(Buffer.getBuffer());
|
||||
auto MaybeDiff = ::deserialize<TupleTreeDiff<Object>>(Buffer.getBuffer());
|
||||
if (not MaybeDiff)
|
||||
return MaybeDiff.takeError();
|
||||
return GlobalTupleTreeDiff(std::move(*MaybeDiff), getName());
|
||||
}
|
||||
|
||||
bool verify() const override { return Value->verify(); }
|
||||
@@ -132,7 +149,7 @@ public:
|
||||
GlobalTupleTreeDiff diff(const Global &Other) const override {
|
||||
const TupleTreeGlobal &Casted = llvm::cast<TupleTreeGlobal>(Other);
|
||||
auto Diff = ::diff(*Value, *Casted.Value);
|
||||
return GlobalTupleTreeDiff(std::move(Diff));
|
||||
return GlobalTupleTreeDiff(std::move(Diff), getName());
|
||||
}
|
||||
|
||||
llvm::Error applyDiff(const llvm::MemoryBuffer &Diff) override {
|
||||
@@ -159,6 +176,33 @@ public:
|
||||
|
||||
const TupleTree<Object> &get() const { return Value; }
|
||||
TupleTree<Object> &get() { return Value; }
|
||||
|
||||
std::optional<TupleTreePath>
|
||||
deserializePath(llvm::StringRef Serialized) const override {
|
||||
return stringAsPath<Object>(Serialized);
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
serializePath(const TupleTreePath &Path) const override {
|
||||
return pathAsString<Object>(Path);
|
||||
}
|
||||
|
||||
void collectReadFields(const TargetInContainer &Target,
|
||||
PathTargetBimap &Out) override {
|
||||
const TupleTree<Object> &AsConst = Value;
|
||||
ReadFields Results = revng::Tracking::collect(*AsConst);
|
||||
for (const TupleTreePath &Result : Results.Read)
|
||||
Out.insert(Target, Result);
|
||||
for (const TupleTreePath &Result : Results.ExactVectors)
|
||||
Out.insert(Target, Result);
|
||||
}
|
||||
|
||||
void clearAndResume() const override {
|
||||
revng::Tracking::clearAndResume(*Value);
|
||||
}
|
||||
void pushReadFields() const override { revng::Tracking::push(*Value); }
|
||||
void popReadFields() const override { revng::Tracking::pop(*Value); }
|
||||
void stopTracking() const override { revng::Tracking::stop(*Value); }
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
|
||||
@@ -12,14 +12,26 @@ namespace pipeline {
|
||||
class GlobalTupleTreeDiffBase {
|
||||
private:
|
||||
char *ID;
|
||||
llvm::StringRef GlobalName;
|
||||
|
||||
public:
|
||||
virtual ~GlobalTupleTreeDiffBase() = default;
|
||||
GlobalTupleTreeDiffBase(char *ID, llvm::StringRef GlobalName) :
|
||||
ID(ID), GlobalName(GlobalName) {}
|
||||
|
||||
public:
|
||||
virtual void serialize(llvm::raw_ostream &OS) const = 0;
|
||||
virtual ~GlobalTupleTreeDiffBase() = default;
|
||||
|
||||
public:
|
||||
virtual std::unique_ptr<GlobalTupleTreeDiffBase> clone() const = 0;
|
||||
virtual bool isEmpty() const = 0;
|
||||
GlobalTupleTreeDiffBase(char *ID) : ID(ID) {}
|
||||
|
||||
public:
|
||||
const char *getID() const { return ID; }
|
||||
|
||||
public:
|
||||
virtual bool isEmpty() const = 0;
|
||||
llvm::StringRef getGlobalName() const { return GlobalName; }
|
||||
virtual llvm::SmallVector<const TupleTreePath *, 4> getPaths() const = 0;
|
||||
};
|
||||
|
||||
template<TupleTreeCompatible T>
|
||||
@@ -33,8 +45,8 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
GlobalTupleTreeDiffImpl(TupleTreeDiff<T> Diff) :
|
||||
GlobalTupleTreeDiffBase(getID()), Diff(std::move(Diff)) {}
|
||||
GlobalTupleTreeDiffImpl(TupleTreeDiff<T> Diff, llvm::StringRef GlobalName) :
|
||||
GlobalTupleTreeDiffBase(getID(), GlobalName), Diff(std::move(Diff)) {}
|
||||
|
||||
~GlobalTupleTreeDiffImpl() override = default;
|
||||
|
||||
@@ -55,6 +67,14 @@ public:
|
||||
|
||||
TupleTreeDiff<T> &getDiff() { return Diff; }
|
||||
const TupleTreeDiff<T> &getDiff() const { return Diff; }
|
||||
|
||||
llvm::SmallVector<const TupleTreePath *, 4> getPaths() const override {
|
||||
llvm::SmallVector<const TupleTreePath *, 4> ToReturn;
|
||||
for (const Change<T> &Entry : Diff.Changes) {
|
||||
ToReturn.emplace_back(&Entry.Path);
|
||||
}
|
||||
return ToReturn;
|
||||
}
|
||||
};
|
||||
|
||||
class GlobalTupleTreeDiff {
|
||||
@@ -63,8 +83,8 @@ private:
|
||||
|
||||
public:
|
||||
template<TupleTreeCompatible T>
|
||||
GlobalTupleTreeDiff(TupleTreeDiff<T> Diff) :
|
||||
Diff(new GlobalTupleTreeDiffImpl<T>(std::move(Diff))) {}
|
||||
GlobalTupleTreeDiff(TupleTreeDiff<T> Diff, llvm::StringRef GlobalName) :
|
||||
Diff(new GlobalTupleTreeDiffImpl<T>(std::move(Diff), GlobalName)) {}
|
||||
|
||||
GlobalTupleTreeDiff(GlobalTupleTreeDiff &&) = default;
|
||||
GlobalTupleTreeDiff &operator=(GlobalTupleTreeDiff &&) = default;
|
||||
@@ -101,7 +121,12 @@ public:
|
||||
return &Casted->getDiff();
|
||||
}
|
||||
|
||||
llvm::SmallVector<const TupleTreePath *, 4> getPaths() const {
|
||||
return Diff->getPaths();
|
||||
}
|
||||
|
||||
bool isEmpty() const { return Diff.get()->isEmpty(); }
|
||||
llvm::StringRef getGlobalName() const { return Diff->getGlobalName(); }
|
||||
};
|
||||
|
||||
using DiffMap = llvm::StringMap<GlobalTupleTreeDiff>;
|
||||
|
||||
@@ -132,15 +132,6 @@ public:
|
||||
|
||||
size_t size() const { return Map.size(); }
|
||||
|
||||
std::vector<llvm::StringRef> getGlobalNames() const {
|
||||
std::vector<llvm::StringRef> ToReturn;
|
||||
|
||||
for (const auto &Global : Map)
|
||||
ToReturn.push_back(Global.first);
|
||||
|
||||
return ToReturn;
|
||||
}
|
||||
|
||||
public:
|
||||
GlobalsMap() = default;
|
||||
~GlobalsMap() = default;
|
||||
@@ -162,5 +153,28 @@ public:
|
||||
|
||||
return *this;
|
||||
}
|
||||
void collectReadFields(const TargetInContainer &Target,
|
||||
llvm::StringMap<PathTargetBimap> &Out) const {
|
||||
for (const auto &Global : Map) {
|
||||
Global.second->collectReadFields(Target, Out[Global.first]);
|
||||
}
|
||||
}
|
||||
|
||||
void clearAndResume() const {
|
||||
for (const auto &Global : Map)
|
||||
Global.second->clearAndResume();
|
||||
}
|
||||
void pushReadFields() const {
|
||||
for (const auto &Global : Map)
|
||||
Global.second->pushReadFields();
|
||||
}
|
||||
void popReadFields() const {
|
||||
for (const auto &Global : Map)
|
||||
Global.second->popReadFields();
|
||||
}
|
||||
void stopTracking() const {
|
||||
for (const auto &Global : Map)
|
||||
Global.second->stopTracking();
|
||||
}
|
||||
};
|
||||
} // namespace pipeline
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "revng/Pipeline/CLOption.h"
|
||||
#include "revng/Pipeline/Container.h"
|
||||
#include "revng/Pipeline/ContainerSet.h"
|
||||
#include "revng/Pipeline/Context.h"
|
||||
#include "revng/Pipeline/ExecutionContext.h"
|
||||
#include "revng/Pipeline/Option.h"
|
||||
#include "revng/Pipeline/Target.h"
|
||||
#include "revng/Support/Assert.h"
|
||||
@@ -63,9 +63,9 @@ concept ReturnsError = invokableTypeReturnsError<Invokable>();
|
||||
///
|
||||
/// * It must have a static constexpr field named Name that is a string
|
||||
/// describing its name. Mostly used for debug purposes.
|
||||
/// * a RetT run(T...) method where the first argument must be a Context& or
|
||||
/// const Context&, arguments after the first must be K& or const K& where
|
||||
/// K is derived from a container.
|
||||
/// * a RetT run(T...) method where the first argument must be a
|
||||
/// ExecutionContext& or const ExecutionContext&, arguments after the first
|
||||
/// must be K& or const K& where K is derived from a container.
|
||||
///
|
||||
/// Options after the last container can be of any type, but for each of
|
||||
/// them there must exists an entry in a constexpr tuple named Options that
|
||||
@@ -74,8 +74,8 @@ concept ReturnsError = invokableTypeReturnsError<Invokable>();
|
||||
/// RetT can either be llvm::Error or void, if it is void then the invokable
|
||||
/// never fails.
|
||||
///
|
||||
template<typename InvokableType, typename FirstRunArg, typename... Rest>
|
||||
concept Invokable = convertible_to<Context &, std::remove_cv_t<FirstRunArg>>
|
||||
template<typename InvokableType, typename First, typename... Rest>
|
||||
concept Invokable = convertible_to<ExecutionContext &, std::remove_cv_t<First>>
|
||||
and HasName<InvokableType>;
|
||||
|
||||
namespace detail {
|
||||
@@ -325,7 +325,7 @@ createCLOptions(llvm::cl::OptionCategory *Category = nullptr) {
|
||||
/// Invokes the F member function on the Pipe Pipe passing as nth argument the
|
||||
/// container with the name equal to the nth element of ArgsNames.
|
||||
template<typename InvokableType, typename ContextT, typename... Args>
|
||||
auto invokePipeFunction(Context &Ctx,
|
||||
auto invokePipeFunction(ExecutionContext &Ctx,
|
||||
InvokableType &Pipe,
|
||||
auto (InvokableType::*F)(ContextT &, Args...),
|
||||
ContainerSet &Containers,
|
||||
@@ -371,7 +371,7 @@ concept Printable = requires(InvokableType Pipe) {
|
||||
|
||||
class InvokableWrapperBase {
|
||||
public:
|
||||
virtual llvm::Error run(Context &Ctx,
|
||||
virtual llvm::Error run(ExecutionContext &Ctx,
|
||||
ContainerSet &Containers,
|
||||
const llvm::StringMap<std::string> &Options = {}) = 0;
|
||||
virtual ~InvokableWrapperBase() = default;
|
||||
@@ -412,7 +412,7 @@ public:
|
||||
std::string getName() const override { return InvokableType::Name; }
|
||||
|
||||
public:
|
||||
llvm::Error run(Context &Ctx,
|
||||
llvm::Error run(ExecutionContext &Ctx,
|
||||
ContainerSet &Containers,
|
||||
const llvm::StringMap<std::string> &OptionArgs) override {
|
||||
if constexpr (invokableTypeReturnsError<InvokableType>()) {
|
||||
|
||||
@@ -108,10 +108,6 @@ public:
|
||||
public:
|
||||
virtual ~Kind() = default;
|
||||
|
||||
virtual void getInvalidations(const Context &Ctx,
|
||||
pipeline::TargetsList &ToRemove,
|
||||
const GlobalTupleTreeDiff &Diff) const {}
|
||||
|
||||
virtual void appendAllTargets(const Context &Ctx, TargetsList &Out) const = 0;
|
||||
TargetsList allTargets(const Context &Ctx) const;
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
|
||||
#include "revng/Pipeline/Target.h"
|
||||
#include "revng/TupleTree/TupleTreePath.h"
|
||||
|
||||
namespace pipeline {
|
||||
class Context;
|
||||
|
||||
class TargetInContainer {
|
||||
private:
|
||||
Target Content;
|
||||
std::string ContainerName;
|
||||
|
||||
public:
|
||||
TargetInContainer(const Target &Target, const std::string &ContainerName) :
|
||||
Content(Target), ContainerName(ContainerName) {}
|
||||
|
||||
const Target &getTarget() const { return Content; }
|
||||
|
||||
llvm::StringRef getContainerName() const {
|
||||
return llvm::StringRef(ContainerName);
|
||||
}
|
||||
|
||||
Target &getTarget() { return Content; }
|
||||
|
||||
std::string &getContainerName() { return ContainerName; }
|
||||
|
||||
bool operator==(const TargetInContainer &) const = default;
|
||||
|
||||
bool operator!=(const TargetInContainer &) const = default;
|
||||
|
||||
bool operator<(const TargetInContainer &Other) const {
|
||||
const auto &LHS = std::tie(Content, ContainerName);
|
||||
return LHS < std::tie(Other.Content, Other.ContainerName);
|
||||
}
|
||||
};
|
||||
|
||||
/// A PathTargetBimap is a many to many relationship between a TupleTreePaths
|
||||
/// and TargetInContainer. It can be queried both ways, so from a target and a
|
||||
/// container you can get the list of tuple tree paths that contribuited to that
|
||||
/// target in that container, and from a tuple tree path you can know all the
|
||||
/// targets that have been created reading the field pointed by that path.
|
||||
class PathTargetBimap {
|
||||
private:
|
||||
using MapType = std::map<TupleTreePath, std::set<TargetInContainer>>;
|
||||
using ReverseMapType = std::map<TargetInContainer,
|
||||
std::vector<TupleTreePath>>;
|
||||
MapType Map;
|
||||
// When we will instrument the entire pipeline there will not be any longer a
|
||||
// need to have a reverse map, since it will only be inspected at load time of
|
||||
// the pipeline.
|
||||
ReverseMapType ReverseMap;
|
||||
|
||||
public:
|
||||
explicit PathTargetBimap() : Map() {}
|
||||
|
||||
public:
|
||||
auto begin() { return Map.begin(); }
|
||||
auto end() { return Map.end(); }
|
||||
auto begin() const { return Map.begin(); }
|
||||
auto end() const { return Map.end(); }
|
||||
|
||||
public:
|
||||
auto find(const TupleTreePath &Path) const { return Map.find(Path); }
|
||||
|
||||
public:
|
||||
void merge(PathTargetBimap &&Other) {
|
||||
for (auto &Entry : Other.Map)
|
||||
for (auto &Target : Entry.second)
|
||||
insert(std::move(Target), std::move(Entry.first));
|
||||
}
|
||||
|
||||
public:
|
||||
void clear() { Map = MapType(); }
|
||||
|
||||
void insert(const TargetInContainer &TargetInContainer,
|
||||
const TupleTreePath &Path) {
|
||||
Map[Path].insert(TargetInContainer);
|
||||
ReverseMap[TargetInContainer].push_back(Path);
|
||||
}
|
||||
|
||||
void insert(const Target &Target,
|
||||
const std::string &ContainerName,
|
||||
const TupleTreePath &Path) {
|
||||
TargetInContainer Located(Target, ContainerName);
|
||||
insert(Located, Path);
|
||||
}
|
||||
|
||||
void remove(const TargetsList &List, llvm::StringRef ContainerName) {
|
||||
for (auto &Target : List) {
|
||||
TargetInContainer ToErase(Target, ContainerName.str());
|
||||
auto Iter = ReverseMap.find(ToErase);
|
||||
if (Iter == ReverseMap.end())
|
||||
continue;
|
||||
|
||||
for (auto &Path : Iter->second) {
|
||||
Map.at(Path).erase(ToErase);
|
||||
}
|
||||
|
||||
ReverseMap.erase(Iter);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool contains(const TargetInContainer &Target) const {
|
||||
return ReverseMap.find(Target) != ReverseMap.end();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
@@ -20,8 +20,8 @@
|
||||
#include "revng/ADT/STLExtras.h"
|
||||
#include "revng/Pipeline/Container.h"
|
||||
#include "revng/Pipeline/ContainerSet.h"
|
||||
#include "revng/Pipeline/Context.h"
|
||||
#include "revng/Pipeline/Contract.h"
|
||||
#include "revng/Pipeline/ExecutionContext.h"
|
||||
#include "revng/Pipeline/Invokable.h"
|
||||
#include "revng/Pipeline/Target.h"
|
||||
#include "revng/Support/Debug.h"
|
||||
@@ -54,6 +54,8 @@ constexpr bool checkPipe(auto (C::*)(First, Rest...))
|
||||
template<typename PipeType>
|
||||
class PipeWrapperImpl;
|
||||
|
||||
// TODO: Rename, there are 3 layers of wrappers around a pipe and they are
|
||||
// getting confusing
|
||||
class PipeWrapperBase : public InvokableWrapperBase {
|
||||
public:
|
||||
template<typename PipeType>
|
||||
@@ -173,7 +175,7 @@ public:
|
||||
Invokable.print(Ctx, OS, Indentation);
|
||||
}
|
||||
|
||||
llvm::Error run(Context &Ctx,
|
||||
llvm::Error run(ExecutionContext &Ctx,
|
||||
ContainerSet &Containers,
|
||||
const llvm::StringMap<std::string> &ExtraArgs) override {
|
||||
return Invokable.run(Ctx, Containers, ExtraArgs);
|
||||
@@ -198,6 +200,94 @@ public:
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using PipeWrapper = InvokableWrapper<detail::PipeWrapperBase>;
|
||||
// Due to invokable wrapper not being controllable by this file we need to have
|
||||
// a extra wrapper that carries along the invalidation metadata too.
|
||||
struct PipeWrapper {
|
||||
|
||||
class InvalidationMetadata {
|
||||
private:
|
||||
llvm::StringMap<PathTargetBimap> PathCache;
|
||||
|
||||
public:
|
||||
void registerTargetsDependingOn(const Context &Ctx,
|
||||
llvm::StringRef GlobalName,
|
||||
const TupleTreePath &Path,
|
||||
ContainerToTargetsMap &Out) const {
|
||||
if (auto Iter = PathCache.find(GlobalName); Iter != PathCache.end()) {
|
||||
|
||||
auto &Bimap = Iter->second;
|
||||
auto It = Bimap.find(Path);
|
||||
if (It == Bimap.end())
|
||||
return;
|
||||
|
||||
for (const auto &Entry : It->second)
|
||||
Out.add(Entry.getContainerName(), Entry.getTarget());
|
||||
}
|
||||
}
|
||||
|
||||
void remove(const ContainerToTargetsMap &Map) {
|
||||
for (auto &Pair : Map) {
|
||||
auto Iter = PathCache.find(Pair.first());
|
||||
if (Iter == PathCache.end())
|
||||
continue;
|
||||
|
||||
Iter->second.remove(Pair.second, Pair.first());
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(llvm::StringRef GlobalName,
|
||||
const TargetInContainer &Target) const {
|
||||
if (auto Iter = PathCache.find(GlobalName); Iter != PathCache.end())
|
||||
return Iter->second.contains(Target);
|
||||
return false;
|
||||
}
|
||||
|
||||
const llvm::StringMap<PathTargetBimap> &getPathCache() const {
|
||||
return PathCache;
|
||||
}
|
||||
llvm::StringMap<PathTargetBimap> &getPathCache() { return PathCache; }
|
||||
|
||||
const PathTargetBimap &getPathCache(llvm::StringRef GlobalName) const {
|
||||
revng_assert(PathCache.find(GlobalName) != PathCache.end());
|
||||
return PathCache.find(GlobalName)->second;
|
||||
}
|
||||
PathTargetBimap &getPathCache(llvm::StringRef GlobalName) {
|
||||
return PathCache[GlobalName];
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using WrapperType = InvokableWrapper<detail::PipeWrapperBase>;
|
||||
WrapperType Pipe;
|
||||
InvalidationMetadata InvalidationMetadata;
|
||||
|
||||
template<typename PipeType>
|
||||
static PipeWrapper
|
||||
make(PipeType Pipe, std::vector<std::string> RunningContainersNames) {
|
||||
return WrapperType::make<PipeType>(Pipe, std::move(RunningContainersNames));
|
||||
}
|
||||
|
||||
template<typename PipeType>
|
||||
static PipeWrapper make(std::vector<std::string> RunningContainersNames) {
|
||||
return WrapperType::make<PipeType>(std::move(RunningContainersNames));
|
||||
}
|
||||
|
||||
PipeWrapper(const InvokableWrapper<detail::PipeWrapperBase> &Other) :
|
||||
Pipe(Other) {}
|
||||
|
||||
PipeWrapper(const PipeWrapper &Other,
|
||||
std::vector<std::string> RunningContainersNames) :
|
||||
Pipe(Other.Pipe, RunningContainersNames) {}
|
||||
|
||||
template<typename PipeType, typename... ContainerNames>
|
||||
static PipeWrapper bind(ContainerNames &&...Names) {
|
||||
return WrapperType::bind<PipeType, ContainerNames...>(Names...);
|
||||
}
|
||||
|
||||
template<typename PipeType, typename... ContainerNames>
|
||||
static PipeWrapper bind(PipeType &&E, ContainerNames &&...Names) {
|
||||
return WrapperType::bind<PipeType, ContainerNames...>(E, Names...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
|
||||
@@ -73,9 +73,9 @@ public:
|
||||
const KindsRegistry &getKindsRegistry() const;
|
||||
|
||||
llvm::Error apply(const GlobalTupleTreeDiff &Diff,
|
||||
pipeline::InvalidationMap &Map);
|
||||
pipeline::TargetInStepSet &Map);
|
||||
void getDiffInvalidations(const GlobalTupleTreeDiff &Diff,
|
||||
pipeline::InvalidationMap &Out) const;
|
||||
pipeline::TargetInStepSet &Out) const;
|
||||
|
||||
public:
|
||||
Step &operator[](llvm::StringRef Name) { return getStep(Name); }
|
||||
@@ -127,11 +127,11 @@ public:
|
||||
/// every step will be registered in the returned invalidation map. The
|
||||
/// propagations will not be calculated.
|
||||
llvm::Error getInvalidations(const Target &Target,
|
||||
pipeline::InvalidationMap &Invalidations) const;
|
||||
pipeline::TargetInStepSet &Invalidations) const;
|
||||
|
||||
/// Deduces and register in the invalidation map all the targets that have
|
||||
/// been produced starting from targets already presents in the map.
|
||||
llvm::Error getInvalidations(pipeline::InvalidationMap &Invalidated) const;
|
||||
llvm::Error getInvalidations(pipeline::TargetInStepSet &Invalidated) const;
|
||||
|
||||
public:
|
||||
template<typename... PipeWrappers>
|
||||
@@ -141,12 +141,14 @@ public:
|
||||
PipeWrappers &&...Wrappers) {
|
||||
IsContainerFactoriesRegistryFinalized = true;
|
||||
if (PreviousStepName.empty())
|
||||
return addStep(Step(StepName.str(),
|
||||
return addStep(Step(*TheContext,
|
||||
StepName.str(),
|
||||
Component.str(),
|
||||
ContainerFactoriesRegistry.createEmpty(),
|
||||
std::forward<PipeWrappers>(Wrappers)...));
|
||||
else
|
||||
return addStep(Step(StepName.str(),
|
||||
return addStep(Step(*TheContext,
|
||||
StepName.str(),
|
||||
Component.str(),
|
||||
ContainerFactoriesRegistry.createEmpty(),
|
||||
operator[](PreviousStepName),
|
||||
@@ -173,12 +175,12 @@ public:
|
||||
runAnalysis(llvm::StringRef AnalysisName,
|
||||
llvm::StringRef StepName,
|
||||
const ContainerToTargetsMap &Targets,
|
||||
pipeline::InvalidationMap &InvalidationsMap,
|
||||
pipeline::TargetInStepSet &InvalidationsMap,
|
||||
const llvm::StringMap<std::string> &Options = {});
|
||||
|
||||
llvm::Expected<DiffMap>
|
||||
runAnalyses(const AnalysesList &List,
|
||||
pipeline::InvalidationMap &InvalidationsMap,
|
||||
pipeline::TargetInStepSet &InvalidationsMap,
|
||||
const llvm::StringMap<std::string> &Options = {});
|
||||
|
||||
void addContainerFactory(llvm::StringRef Name, ContainerFactory Entry) {
|
||||
@@ -203,7 +205,7 @@ public:
|
||||
/// Remove the provided target from all containers in all the steps, as well
|
||||
/// as all all their transitive dependencies
|
||||
llvm::Error invalidate(const Target &Target);
|
||||
llvm::Error invalidate(const pipeline::InvalidationMap &Invalidations);
|
||||
llvm::Error invalidate(const pipeline::TargetInStepSet &Invalidations);
|
||||
|
||||
public:
|
||||
llvm::Error store(const revng::DirectoryPath &DirPath) const;
|
||||
|
||||
@@ -69,10 +69,12 @@ private:
|
||||
Step *PreviousStep;
|
||||
ArtifactsInfo Artifacts;
|
||||
AnalysisMapType AnalysisMap;
|
||||
Context *Ctx;
|
||||
|
||||
public:
|
||||
template<typename... PipeWrapperTypes>
|
||||
Step(std::string Name,
|
||||
Step(Context &Ctx,
|
||||
std::string Name,
|
||||
std::string Component,
|
||||
ContainerSet Containers,
|
||||
PipeWrapperTypes &&...PipeWrappers) :
|
||||
@@ -80,10 +82,12 @@ public:
|
||||
Component(std::move(Component)),
|
||||
Containers(std::move(Containers)),
|
||||
Pipes({ std::forward<PipeWrapperTypes>(PipeWrappers)... }),
|
||||
PreviousStep(nullptr) {}
|
||||
PreviousStep(nullptr),
|
||||
Ctx(&Ctx) {}
|
||||
|
||||
template<typename... PipeWrapperTypes>
|
||||
Step(std::string Name,
|
||||
Step(Context &Ctx,
|
||||
std::string Name,
|
||||
std::string Component,
|
||||
ContainerSet Containers,
|
||||
Step &PreviousStep,
|
||||
@@ -92,7 +96,40 @@ public:
|
||||
Component(std::move(Component)),
|
||||
Containers(std::move(Containers)),
|
||||
Pipes({ std::forward<PipeWrapperTypes>(PipeWrappers)... }),
|
||||
PreviousStep(&PreviousStep) {}
|
||||
PreviousStep(&PreviousStep),
|
||||
Ctx(&Ctx) {}
|
||||
|
||||
public:
|
||||
// TODO: drop the Out parameter pattern if favour of coorutines in the whole
|
||||
// codebase.
|
||||
void registerTargetsDependingOn(llvm::StringRef GlobalName,
|
||||
const TupleTreePath &Path,
|
||||
TargetInStepSet &Out) const {
|
||||
for (const PipeWrapper &Pipe : Pipes) {
|
||||
Pipe.InvalidationMetadata.registerTargetsDependingOn(*Ctx,
|
||||
GlobalName,
|
||||
Path,
|
||||
Out[getName()]);
|
||||
}
|
||||
}
|
||||
|
||||
bool invalidationMetadataContains(llvm::StringRef GlobalName,
|
||||
const TargetInContainer &Target) const {
|
||||
for (const PipeWrapper &Pipe : Pipes) {
|
||||
if (Pipe.InvalidationMetadata.contains(GlobalName, Target))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::Error loadInvalidationMetadataImpl(const revng::DirectoryPath &Path,
|
||||
ContainerSet::value_type &Pair);
|
||||
|
||||
private:
|
||||
llvm::Error loadInvalidationMetadata(const revng::DirectoryPath &Path);
|
||||
|
||||
llvm::Error storeInvalidationMetadata(const revng::DirectoryPath &Path) const;
|
||||
|
||||
public:
|
||||
void addAnalysis(llvm::StringRef Name, AnalysisWrapper Analysis) {
|
||||
@@ -164,7 +201,7 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto &ContainerName = Artifacts.Container;
|
||||
const std::string &ContainerName = Artifacts.Container;
|
||||
if (Containers.isContainerRegistered(ContainerName)) {
|
||||
Containers[ContainerName];
|
||||
return &*Containers.find(ContainerName);
|
||||
@@ -196,27 +233,24 @@ public:
|
||||
|
||||
public:
|
||||
llvm::Error runAnalysis(llvm::StringRef AnalysisName,
|
||||
Context &Ctx,
|
||||
const ContainerToTargetsMap &Targets,
|
||||
const llvm::StringMap<std::string> &ExtraArgs = {});
|
||||
|
||||
/// Executes all the pipes of this step, merges the results in the final
|
||||
/// containers and returns the containers filtered according to the request.
|
||||
ContainerSet run(Context &Ctx, ContainerSet &&Targets);
|
||||
ContainerSet run(ContainerSet &&Targets);
|
||||
|
||||
/// Returns the set of goals that are already contained in the backing
|
||||
/// containers of this step, furthermore adds to the container ToLoad those
|
||||
/// that were not present.
|
||||
ContainerToTargetsMap
|
||||
analyzeGoals(const Context &Ctx,
|
||||
const ContainerToTargetsMap &RequiredGoals) const;
|
||||
analyzeGoals(const ContainerToTargetsMap &RequiredGoals) const;
|
||||
|
||||
llvm::Error checkPrecondition(const Context &Ctx) const;
|
||||
llvm::Error checkPrecondition() const;
|
||||
|
||||
/// Returns the predicted state of the Input containers status after the
|
||||
/// execution of all the pipes in this step.
|
||||
ContainerToTargetsMap deduceResults(const Context &Ctx,
|
||||
ContainerToTargetsMap Input) const;
|
||||
ContainerToTargetsMap deduceResults(ContainerToTargetsMap Input) const;
|
||||
|
||||
public:
|
||||
void addPipe(PipeWrapper Wrapper) { Pipes.push_back(std::move(Wrapper)); }
|
||||
@@ -237,8 +271,8 @@ public:
|
||||
|
||||
indent(OS, Indentation + 1);
|
||||
OS << "Pipes: \n";
|
||||
for (const auto &Pipe : Pipes)
|
||||
Pipe.dump(OS, Indentation + 2);
|
||||
for (const PipeWrapper &Pipe : Pipes)
|
||||
Pipe.Pipe.dump(OS, Indentation + 2);
|
||||
|
||||
indent(OS, Indentation + 1);
|
||||
OS << " containers: \n";
|
||||
@@ -256,8 +290,7 @@ private:
|
||||
void removeSatisfiedGoals(ContainerToTargetsMap &Targets,
|
||||
ContainerToTargetsMap &ToLoad) const;
|
||||
|
||||
void explainExecutedPipe(const Context &Ctx,
|
||||
const InvokableWrapperBase &Wrapper,
|
||||
void explainExecutedPipe(const InvokableWrapperBase &Wrapper,
|
||||
size_t Indentation = 0) const;
|
||||
void explainStartStep(const ContainerToTargetsMap &Wrapper,
|
||||
size_t Indentation = 0) const;
|
||||
|
||||
@@ -391,14 +391,14 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
using InvalidationMap = llvm::StringMap<ContainerToTargetsMap>;
|
||||
using TargetInStepSet = llvm::StringMap<ContainerToTargetsMap>;
|
||||
|
||||
llvm::Error parseTarget(const Context &Ctx,
|
||||
ContainerToTargetsMap &CurrentStatus,
|
||||
llvm::StringRef AsString,
|
||||
const KindsRegistry &Dict);
|
||||
|
||||
inline void merge(InvalidationMap &Map, const InvalidationMap &Other) {
|
||||
inline void merge(TargetInStepSet &Map, const TargetInStepSet &Other) {
|
||||
for (const auto &Entry : Other) {
|
||||
if (auto Iter = Map.find(Entry.first()); Iter != Map.end()) {
|
||||
Iter->second.merge(Entry.second);
|
||||
|
||||
@@ -52,7 +52,7 @@ typedef const pipeline::TargetsList rp_targets_list;
|
||||
typedef const pipeline::Step::AnalysisValueType rp_analysis;
|
||||
typedef const pipeline::DiffMap rp_diff_map;
|
||||
typedef llvm::StringMap<std::string> rp_string_map;
|
||||
typedef pipeline::InvalidationMap rp_invalidations;
|
||||
typedef pipeline::TargetInStepSet rp_invalidations;
|
||||
typedef llvm::SmallVector<char, 0> rp_buffer;
|
||||
typedef pipeline::ContainerToTargetsMap rp_container_targets_map;
|
||||
typedef const pipeline::AnalysesList rp_analyses_list;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "revng/Pipeline/Kind.h"
|
||||
#include "revng/Pipeline/Option.h"
|
||||
|
||||
namespace revng::pipes {
|
||||
|
||||
struct ApplyDiffAnalysis {
|
||||
static constexpr auto Name = "Apply";
|
||||
|
||||
constexpr static std::tuple Options = { pipeline::Option("diff-path", "") };
|
||||
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = {};
|
||||
|
||||
llvm::Error run(pipeline::ExecutionContext &Ctx, std::string DiffLocation);
|
||||
};
|
||||
} // namespace revng::pipes
|
||||
@@ -32,7 +32,7 @@ struct ApplyDiffAnalysis {
|
||||
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = {};
|
||||
|
||||
llvm::Error run(pipeline::Context &Ctx,
|
||||
llvm::Error run(pipeline::ExecutionContext &Ctx,
|
||||
std::string DiffGlobalName,
|
||||
std::string DiffContent);
|
||||
};
|
||||
@@ -46,7 +46,7 @@ struct VerifyDiffAnalysis {
|
||||
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = {};
|
||||
|
||||
llvm::Error run(pipeline::Context &Ctx,
|
||||
llvm::Error run(pipeline::ExecutionContext &Ctx,
|
||||
std::string DiffGlobalNane,
|
||||
std::string DiffContent);
|
||||
};
|
||||
@@ -61,7 +61,7 @@ struct SetGlobalAnalysis {
|
||||
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = {};
|
||||
|
||||
llvm::Error run(pipeline::Context &Ctx,
|
||||
llvm::Error run(pipeline::ExecutionContext &Ctx,
|
||||
std::string SetGlobalNane,
|
||||
std::string GlobalContent);
|
||||
};
|
||||
@@ -75,7 +75,7 @@ struct VerifyGlobalAnalysis {
|
||||
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = {};
|
||||
|
||||
llvm::Error run(pipeline::Context &Ctx,
|
||||
llvm::Error run(pipeline::ExecutionContext &Ctx,
|
||||
std::string SetGlobalNane,
|
||||
std::string GlobalContent);
|
||||
};
|
||||
|
||||
@@ -18,9 +18,10 @@ namespace revng::pipes {
|
||||
template<typename... Passes>
|
||||
class LLVMAnalysisImplementation {
|
||||
public:
|
||||
void run(const pipeline::Context &Ctx, pipeline::LLVMContainer &Container) {
|
||||
void run(const pipeline::ExecutionContext &Ctx,
|
||||
pipeline::LLVMContainer &Container) {
|
||||
llvm::legacy::PassManager Manager;
|
||||
registerPasses(Ctx, Manager);
|
||||
registerPasses(Ctx.getContext(), Manager);
|
||||
Manager.run(Container.getModule());
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ getModelFromContext(const pipeline::Context &Ctx) {
|
||||
return Model->get();
|
||||
}
|
||||
|
||||
inline const TupleTree<model::Binary> &
|
||||
getModelFromContext(const pipeline::ExecutionContext &Ctx) {
|
||||
return getModelFromContext(Ctx.getContext());
|
||||
}
|
||||
|
||||
inline TupleTree<model::Binary> &
|
||||
getWritableModelFromContext(pipeline::Context &Ctx) {
|
||||
using Wrapper = ModelGlobal;
|
||||
@@ -38,4 +43,8 @@ getWritableModelFromContext(pipeline::Context &Ctx) {
|
||||
return Model->get();
|
||||
}
|
||||
|
||||
inline TupleTree<model::Binary> &
|
||||
getWritableModelFromContext(pipeline::ExecutionContext &Ctx) {
|
||||
return getWritableModelFromContext(Ctx.getContext());
|
||||
}
|
||||
} // namespace revng
|
||||
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
const pipeline::Step::AnalysisValueType &
|
||||
getAnalysis(const pipeline::AnalysisReference &Reference) const;
|
||||
|
||||
llvm::Expected<pipeline::InvalidationMap>
|
||||
llvm::Expected<pipeline::TargetInStepSet>
|
||||
deserializeContainer(pipeline::Step &Step,
|
||||
llvm::StringRef ContainerName,
|
||||
const llvm::MemoryBuffer &Buffer);
|
||||
@@ -140,8 +140,8 @@ public:
|
||||
return produceAllPossibleTargets(true);
|
||||
}
|
||||
|
||||
llvm::Expected<pipeline::InvalidationMap> invalidateAllPossibleTargets();
|
||||
llvm::Expected<pipeline::InvalidationMap>
|
||||
llvm::Expected<pipeline::TargetInStepSet> invalidateAllPossibleTargets();
|
||||
llvm::Expected<pipeline::TargetInStepSet>
|
||||
invalidateFromDiff(const llvm::StringRef Name,
|
||||
const pipeline::GlobalTupleTreeDiff &Diff);
|
||||
|
||||
@@ -171,7 +171,7 @@ public:
|
||||
|
||||
llvm::Expected<pipeline::DiffMap>
|
||||
runAnalyses(const pipeline::AnalysesList &List,
|
||||
pipeline::InvalidationMap &Map,
|
||||
pipeline::TargetInStepSet &Map,
|
||||
const llvm::StringMap<std::string> &Options = {},
|
||||
llvm::raw_ostream *DiagnosticLog = nullptr);
|
||||
|
||||
@@ -179,7 +179,7 @@ public:
|
||||
runAnalysis(llvm::StringRef AnalysisName,
|
||||
llvm::StringRef StepName,
|
||||
const pipeline::ContainerToTargetsMap &Targets,
|
||||
pipeline::InvalidationMap &Map,
|
||||
pipeline::TargetInStepSet &Map,
|
||||
const llvm::StringMap<std::string> &Options = {},
|
||||
llvm::raw_ostream *DiagnosticLog = nullptr);
|
||||
|
||||
|
||||
@@ -25,11 +25,6 @@ public:
|
||||
|
||||
void appendAllTargets(const pipeline::Context &Ctx,
|
||||
pipeline::TargetsList &Out) const override;
|
||||
|
||||
void
|
||||
getInvalidations(const pipeline::Context &Ctx,
|
||||
pipeline::TargetsList &ToRemove,
|
||||
const pipeline::GlobalTupleTreeDiff &Base) const override;
|
||||
};
|
||||
|
||||
class IsolatedRootKind : public pipeline::LLVMKind {
|
||||
|
||||
@@ -23,6 +23,9 @@ private:
|
||||
// It is on the heap to avoid Initialization Order Fiasco
|
||||
std::unique_ptr<llvm::SmallVector<TaggedFunctionKind *>> Children = nullptr;
|
||||
|
||||
// we have a redundant extra list of children here that would be a subset of
|
||||
// that present in kind because kinds are not upcastable, and so we would not
|
||||
// be able to know which one we care about without a second list.
|
||||
void registerChild(TaggedFunctionKind *Child) {
|
||||
if (Children == nullptr)
|
||||
Children = std::make_unique<llvm::SmallVector<TaggedFunctionKind *>>();
|
||||
@@ -42,16 +45,13 @@ public:
|
||||
TaggedFunctionKind &Parent,
|
||||
const BaseRank &Rank,
|
||||
const FunctionTags::Tag &Tag) :
|
||||
pipeline::LLVMKind(Name, Parent, Rank), Tag(&Tag) {}
|
||||
pipeline::LLVMKind(Name, Parent, Rank), Tag(&Tag) {
|
||||
Parent.registerChild(this);
|
||||
}
|
||||
|
||||
std::optional<pipeline::Target>
|
||||
symbolToTarget(const llvm::Function &Symbol) const override;
|
||||
|
||||
void
|
||||
getInvalidations(const pipeline::Context &Ctx,
|
||||
pipeline::TargetsList &ToRemove,
|
||||
const pipeline::GlobalTupleTreeDiff &Diff) const override;
|
||||
|
||||
void appendAllTargets(const pipeline::Context &Ctx,
|
||||
pipeline::TargetsList &Out) const override;
|
||||
};
|
||||
|
||||
@@ -40,9 +40,7 @@ public:
|
||||
A1("l",
|
||||
llvm::cl::desc("Alias for --load"),
|
||||
llvm::cl::aliasopt(llvm::LoadOpt),
|
||||
llvm::cl::cat(Category))
|
||||
|
||||
{}
|
||||
llvm::cl::cat(Category)) {}
|
||||
|
||||
llvm::Error overrideModel(revng::FilePath ModelOverride,
|
||||
PipelineManager &Manager) {
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
std::array<pipeline::ContractGroup, 1> getContract() const {
|
||||
return { pipeline::ContractGroup(kinds::Root, 0, kinds::Object, 1) };
|
||||
}
|
||||
void run(const pipeline::Context &,
|
||||
void run(const pipeline::ExecutionContext &,
|
||||
pipeline::LLVMContainer &TargetsList,
|
||||
ObjectFileContainer &TargetBinary);
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
pipeline::Contract IsolatedPart(kinds::Isolated, 0, kinds::Object, 1);
|
||||
return { pipeline::ContractGroup({ RootPart, IsolatedPart }) };
|
||||
}
|
||||
void run(const pipeline::Context &,
|
||||
void run(const pipeline::ExecutionContext &,
|
||||
pipeline::LLVMContainer &TargetsList,
|
||||
ObjectFileContainer &TargetBinary);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
return { pipeline::ContractGroup({ BinaryPart, ObjectPart }) };
|
||||
}
|
||||
|
||||
void run(const pipeline::Context &Ctx,
|
||||
void run(const pipeline::ExecutionContext &Ctx,
|
||||
BinaryFileContainer &InputBinary,
|
||||
ObjectFileContainer &ObjectFile,
|
||||
TranslatedFileContainer &OutputBinary);
|
||||
|
||||
@@ -16,15 +16,23 @@ namespace revng {
|
||||
///
|
||||
class AccessTracker {
|
||||
private:
|
||||
uint8_t Counter = 0;
|
||||
std::uint8_t Counter = 0;
|
||||
bool IsTracking;
|
||||
|
||||
public:
|
||||
AccessTracker(bool StartsActive) { IsTracking = StartsActive; }
|
||||
|
||||
public:
|
||||
bool operator==(const AccessTracker &Other) const = default;
|
||||
|
||||
bool operator!=(const AccessTracker &Other) const = default;
|
||||
|
||||
void clear() { Counter &= ~0x1; }
|
||||
void access() { Counter |= 0x1; }
|
||||
public:
|
||||
void clear() {
|
||||
Counter &= ~0x1;
|
||||
IsTracking = true;
|
||||
}
|
||||
void access() { Counter |= (0x1 & IsTracking); }
|
||||
void push() {
|
||||
revng_assert(llvm::countLeadingZeros(Counter) != 0,
|
||||
"More than 8 pushes have been performed");
|
||||
@@ -34,6 +42,7 @@ public:
|
||||
bool front() const { return (Counter & 0x1) == 0; }
|
||||
bool peak() const { return Counter & 0x1; }
|
||||
bool isSet() const { return Counter; }
|
||||
void stopTracking() { IsTracking = false; }
|
||||
};
|
||||
|
||||
} // namespace revng
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
/// The field Read is the set of paths of fields that were accessed.
|
||||
/// The exact vectors contains the paths of all vectors that were marked as
|
||||
/// requiring being identical.
|
||||
///
|
||||
/// We divide into read and exact vectors because when we will introduce the
|
||||
/// cold start invalidation based on the hash, the hash will be different
|
||||
/// depending if they are just read or if they are vectors required to be exact.
|
||||
struct ReadFields {
|
||||
std::set<TupleTreePath> Read;
|
||||
std::set<TupleTreePath> ExactVectors;
|
||||
@@ -85,8 +89,9 @@ private:
|
||||
if constexpr (I < std::tuple_size_v<T>) {
|
||||
|
||||
Stack.push_back(size_t(I));
|
||||
if (LHS.template getTracker<I>().isSet())
|
||||
if (LHS.template getTracker<I>().isSet()) {
|
||||
Info.Read.insert(Stack);
|
||||
}
|
||||
collectImpl<M>(LHS.template untrackedGet<I>(), Stack, Info);
|
||||
Stack.pop_back();
|
||||
|
||||
@@ -114,7 +119,8 @@ private:
|
||||
if (TrackingResult.Exact)
|
||||
Info.ExactVectors.insert(Stack);
|
||||
|
||||
for (auto &Key : TrackingResult.InspectedKeys) {
|
||||
using KeyType = std::remove_cv_t<typename T::key_type>;
|
||||
for (KeyType Key : TrackingResult.InspectedKeys) {
|
||||
Stack.push_back(Key);
|
||||
Info.Read.insert(Stack);
|
||||
Stack.pop_back();
|
||||
@@ -122,10 +128,7 @@ private:
|
||||
for (auto &LHSElement : LHS.Content) {
|
||||
using value_type = typename T::value_type;
|
||||
|
||||
if constexpr (TupleSizeCompatible<value_type>)
|
||||
Stack.push_back(LHSElement.untrackedKey());
|
||||
else
|
||||
Stack.push_back(KeyedObjectTraits<value_type>::key(LHSElement));
|
||||
Stack.push_back(KeyedObjectTraits<value_type>::key(LHSElement));
|
||||
|
||||
collectImpl<M>(LHSElement, Stack, Info);
|
||||
Stack.pop_back();
|
||||
@@ -175,14 +178,16 @@ private:
|
||||
public:
|
||||
template<typename M>
|
||||
static ReadFields collect(const M &LHS) {
|
||||
stop(LHS);
|
||||
TupleTreePath Stack;
|
||||
ReadFields Info;
|
||||
collectImpl<M>(LHS, Stack, Info);
|
||||
clearAndResume(LHS);
|
||||
return Info;
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
static void clear(const M &LHS) {
|
||||
static void clearAndResume(const M &LHS) {
|
||||
visitTuple<M, ClearVisitor>(LHS);
|
||||
}
|
||||
|
||||
@@ -201,5 +206,4 @@ public:
|
||||
visitTuple<M, StopTrackingVisitor>(LHS);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace revng
|
||||
|
||||
@@ -25,11 +25,59 @@
|
||||
#include "revng/Support/Assert.h"
|
||||
#include "revng/Support/Debug.h"
|
||||
#include "revng/Support/YAMLTraits.h"
|
||||
#include "revng/TupleTree/Tracking.h"
|
||||
#include "revng/TupleTree/TupleTreeCompatible.h"
|
||||
#include "revng/TupleTree/TupleTreePath.h"
|
||||
#include "revng/TupleTree/TupleTreeReference.h"
|
||||
#include "revng/TupleTree/Visits.h"
|
||||
|
||||
template<typename T>
|
||||
concept HasTracking = requires(T _) { T::HasTracking; };
|
||||
|
||||
template<typename T>
|
||||
struct TrackGuard {
|
||||
const T *TrackedObject;
|
||||
|
||||
public:
|
||||
TrackGuard(const T &TrackedObject) : TrackedObject(&TrackedObject) {
|
||||
// Since the model classes may have been generated either with or without
|
||||
// tracking, a trackguard should do nothing if the concept returns false.
|
||||
if constexpr (HasTracking<T>)
|
||||
revng::Tracking::push(*this->TrackedObject);
|
||||
}
|
||||
|
||||
TrackGuard(const TrackGuard &Other) = delete;
|
||||
TrackGuard &operator=(const TrackGuard &Other) = delete;
|
||||
|
||||
TrackGuard(TrackGuard &&Other) {
|
||||
TrackedObject = Other.TrackedObject;
|
||||
Other.TrackedObject = nullptr;
|
||||
}
|
||||
TrackGuard &operator=(TrackGuard &&Other) {
|
||||
if (this == &Other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
onDestruction();
|
||||
TrackedObject = Other.TrackedObject;
|
||||
Other.TrackedObject = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~TrackGuard() { onDestruction(); }
|
||||
|
||||
private:
|
||||
void onDestruction() {
|
||||
if constexpr (HasTracking<T>) {
|
||||
if (TrackedObject != nullptr) {
|
||||
revng::Tracking::pop(*TrackedObject);
|
||||
}
|
||||
}
|
||||
TrackedObject = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template<TupleTreeCompatible T>
|
||||
class TupleTree {
|
||||
private:
|
||||
@@ -169,6 +217,7 @@ public:
|
||||
|
||||
private:
|
||||
void initializeUncachedReferences() {
|
||||
TrackGuard Guard(*Root);
|
||||
visitReferences([this](auto &Element) {
|
||||
Element.Root = Root.get();
|
||||
Element.evictCachedTarget();
|
||||
@@ -178,17 +227,20 @@ private:
|
||||
|
||||
public:
|
||||
void initializeReferences() {
|
||||
TrackGuard Guard(*Root);
|
||||
revng_assert(not AllReferencesAreCached);
|
||||
visitReferences([this](auto &Element) { Element.Root = Root.get(); });
|
||||
}
|
||||
|
||||
void cacheReferences() {
|
||||
TrackGuard Guard(*Root);
|
||||
if (not AllReferencesAreCached)
|
||||
visitReferencesInternal([](auto &Element) { Element.cacheTarget(); });
|
||||
AllReferencesAreCached = true;
|
||||
}
|
||||
|
||||
void evictCachedReferences() {
|
||||
TrackGuard Guard(*Root);
|
||||
if (AllReferencesAreCached)
|
||||
visitReferencesInternal([](auto &E) { E.evictCachedTarget(); });
|
||||
AllReferencesAreCached = false;
|
||||
@@ -251,6 +303,7 @@ public:
|
||||
|
||||
private:
|
||||
bool verifyReferences(bool Assert) const {
|
||||
TrackGuard Guard(*Root);
|
||||
bool Result = true;
|
||||
|
||||
visitReferences([&Result,
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void run(pipeline::Context &Context,
|
||||
void run(pipeline::ExecutionContext &Context,
|
||||
const BinaryFileContainer &SourceBinary,
|
||||
const pipeline::LLVMContainer &TargetsList,
|
||||
FunctionAssemblyStringMap &OutputAssembly);
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void run(pipeline::Context &Context,
|
||||
void run(pipeline::ExecutionContext &Context,
|
||||
const pipeline::LLVMContainer &TargetsList,
|
||||
CrossRelationsFileContainer &OutputFile);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void run(pipeline::Context &Context,
|
||||
void run(pipeline::ExecutionContext &Context,
|
||||
const FunctionAssemblyStringMap &Input,
|
||||
FunctionAssemblyPTMLStringMap &Output);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void run(pipeline::Context &Context,
|
||||
void run(pipeline::ExecutionContext &Context,
|
||||
const CrossRelationsFileContainer &InputFile,
|
||||
CallGraphSVGFileContainer &OutputFile);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void run(pipeline::Context &Context,
|
||||
void run(pipeline::ExecutionContext &Context,
|
||||
const pipeline::LLVMContainer &TargetList,
|
||||
const CrossRelationsFileContainer &InputFile,
|
||||
CallGraphSliceSVGStringMap &Output);
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void run(pipeline::Context &Context,
|
||||
void run(pipeline::ExecutionContext &Context,
|
||||
const FunctionAssemblyStringMap &Input,
|
||||
FunctionControlFlowStringMap &Output);
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
};
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = {};
|
||||
|
||||
void run(pipeline::Context &Context,
|
||||
void run(pipeline::ExecutionContext &Context,
|
||||
std::string TargetABI,
|
||||
std::string Mode,
|
||||
std::string ABIConfidence) {
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = {};
|
||||
|
||||
void run(pipeline::Context &Context) {
|
||||
void run(pipeline::ExecutionContext &Context) {
|
||||
auto &Model = revng::getWritableModelFromContext(Context);
|
||||
|
||||
model::VerifyHelper VH;
|
||||
|
||||
@@ -99,7 +99,8 @@ public:
|
||||
Implementation.print(Ctx, OS, ContainerNames);
|
||||
}
|
||||
|
||||
void run(const pipeline::Context &Ctx, pipeline::LLVMContainer &Container) {
|
||||
void run(const pipeline::ExecutionContext &Ctx,
|
||||
pipeline::LLVMContainer &Container) {
|
||||
Implementation.run(Ctx, Container);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -358,7 +358,8 @@ MaterializedValue JumpTargetManager::readFromPointer(MetaAddress LoadAddress,
|
||||
uint64_t Addend = Relocation.Addend();
|
||||
auto RelocationSize = model::RelocationType::getSize(Relocation.Type());
|
||||
if (LoadAddress == Relocation.Address() and LoadSize == RelocationSize) {
|
||||
revng_assert(not StringRef(Function.name()).contains('\0'));
|
||||
// TODO: add this to model verify
|
||||
revng_assert(not StringRef(Function.OriginalName()).contains('\0'));
|
||||
Result = MaterializedValue::fromSymbol(Function.OriginalName(),
|
||||
NewAPInt(Addend));
|
||||
++MatchCount;
|
||||
|
||||
@@ -26,9 +26,9 @@ using namespace llvm;
|
||||
using namespace pipeline;
|
||||
using namespace ::revng::pipes;
|
||||
|
||||
void Lift::run(Context &Ctx,
|
||||
void Lift::run(ExecutionContext &Ctx,
|
||||
const BinaryFileContainer &SourceBinary,
|
||||
LLVMContainer &TargetsList) {
|
||||
LLVMContainer &Output) {
|
||||
if (not SourceBinary.exists())
|
||||
return;
|
||||
|
||||
@@ -43,7 +43,9 @@ void Lift::run(Context &Ctx,
|
||||
PM.add(new LoadModelWrapperPass(Model));
|
||||
PM.add(new LoadBinaryWrapperPass(Buffer->getBuffer()));
|
||||
PM.add(new LiftPass);
|
||||
PM.run(TargetsList.getModule());
|
||||
PM.run(Output.getModule());
|
||||
|
||||
Ctx.commitUniqueTarget(Output);
|
||||
}
|
||||
|
||||
llvm::Error Lift::checkPrecondition(const pipeline::Context &Ctx) const {
|
||||
|
||||
@@ -81,12 +81,12 @@ void LinkSupport::print(const pipeline::Context &Ctx,
|
||||
<< Names[0] << "\n";
|
||||
}
|
||||
|
||||
void revng::pipes::LinkSupport::run(const Context &Ctx,
|
||||
void revng::pipes::LinkSupport::run(const ExecutionContext &Ctx,
|
||||
LLVMContainer &TargetsList) {
|
||||
if (TargetsList.enumerate().empty())
|
||||
return;
|
||||
|
||||
std::string SupportPath = getSupportPath(Ctx);
|
||||
std::string SupportPath = getSupportPath(Ctx.getContext());
|
||||
|
||||
llvm::SMDiagnostic Err;
|
||||
auto Module = llvm::parseIRFile(SupportPath,
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
//
|
||||
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/ScopeExit.h"
|
||||
#include "llvm/BinaryFormat/ELF.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/DOTGraphTraits.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/Support/raw_os_ostream.h"
|
||||
|
||||
#include "revng/ADT/GenericGraph.h"
|
||||
@@ -15,6 +18,7 @@
|
||||
#include "revng/Model/TypeSystemPrinter.h"
|
||||
#include "revng/Model/VerifyHelper.h"
|
||||
#include "revng/Support/OverflowSafeInt.h"
|
||||
#include "revng/TupleTree/Tracking.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@@ -78,6 +82,7 @@ bool Binary::verifyTypes(bool Assert) const {
|
||||
}
|
||||
|
||||
bool Binary::verifyTypes(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
// All types on their own should verify
|
||||
std::set<Identifier> Names;
|
||||
for (auto &Type : Types()) {
|
||||
@@ -95,10 +100,13 @@ bool Binary::verifyTypes(VerifyHelper &VH) const {
|
||||
}
|
||||
|
||||
void Binary::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
void Binary::dumpTypeGraph(const char *Path) const {
|
||||
TrackGuard Guard(*this);
|
||||
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream Out(Path, EC);
|
||||
if (EC)
|
||||
@@ -109,6 +117,7 @@ void Binary::dumpTypeGraph(const char *Path) const {
|
||||
}
|
||||
|
||||
std::string Binary::toString() const {
|
||||
TrackGuard Guard(*this);
|
||||
std::string S;
|
||||
llvm::raw_string_ostream OS(S);
|
||||
serialize(OS, *this);
|
||||
@@ -152,6 +161,8 @@ bool VerifyHelper::registerGlobalSymbol(const model::Identifier &Name,
|
||||
|
||||
static bool verifyGlobalNamespace(VerifyHelper &VH,
|
||||
const model::Binary &Model) {
|
||||
|
||||
auto Guard = VH.suspendTracking(Model);
|
||||
// Namespacing rules:
|
||||
//
|
||||
// 1. each struct/union induces a namespace for its field names;
|
||||
@@ -197,6 +208,8 @@ static bool verifyGlobalNamespace(VerifyHelper &VH,
|
||||
bool Binary::verify(VerifyHelper &VH) const {
|
||||
// First of all, verify the global namespace: we need to fully populate it
|
||||
// before we can verify namespaces with smaller scopes
|
||||
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
if (not verifyGlobalNamespace(VH, *this))
|
||||
return VH.fail();
|
||||
|
||||
@@ -282,6 +295,8 @@ bool Relocation::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
bool Relocation::verify(VerifyHelper &VH) const {
|
||||
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
if (Type() == model::RelocationType::Invalid)
|
||||
return VH.fail("Invalid relocation", *this);
|
||||
|
||||
@@ -298,6 +313,7 @@ bool Section::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
bool Section::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
auto EndAddress = StartAddress() + Size();
|
||||
if (not EndAddress.isValid())
|
||||
return VH.fail("Computing the end address leads to overflow");
|
||||
@@ -318,6 +334,7 @@ Identifier Segment::name() const {
|
||||
}
|
||||
|
||||
void Segment::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -331,6 +348,7 @@ bool Segment::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
bool Segment::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
using OverflowSafeInt = OverflowSafeInt<uint64_t>;
|
||||
|
||||
if (FileSize() > VirtualSize())
|
||||
@@ -394,10 +412,12 @@ bool Segment::verify(VerifyHelper &VH) const {
|
||||
}
|
||||
|
||||
void Function::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
void Function::dumpTypeGraph(const char *Path) const {
|
||||
TrackGuard Guard(*this);
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream Out(Path, EC);
|
||||
if (EC)
|
||||
@@ -417,6 +437,7 @@ bool Function::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
bool Function::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
if (not Entry().isValid())
|
||||
return VH.fail("Invalid Entry", *this);
|
||||
|
||||
@@ -459,6 +480,7 @@ bool Function::verify(VerifyHelper &VH) const {
|
||||
}
|
||||
|
||||
void DynamicFunction::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -472,6 +494,7 @@ bool DynamicFunction::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
bool DynamicFunction::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
// Ensure we have a name
|
||||
if (OriginalName().size() == 0)
|
||||
return VH.fail("Dynamic functions must have a OriginalName", *this);
|
||||
@@ -501,6 +524,7 @@ bool DynamicFunction::verify(VerifyHelper &VH) const {
|
||||
}
|
||||
|
||||
void CallSitePrototype::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -514,6 +538,7 @@ bool CallSitePrototype::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
bool CallSitePrototype::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
if (Prototype().empty() or not Prototype().isValid())
|
||||
return VH.fail("Invalid prototype");
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
using namespace revng::pipes;
|
||||
|
||||
llvm::Error ImportBinaryAnalysis::run(pipeline::Context &Context,
|
||||
llvm::Error ImportBinaryAnalysis::run(pipeline::ExecutionContext &Context,
|
||||
const BinaryFileContainer &SourceBinary) {
|
||||
if (not SourceBinary.exists())
|
||||
return llvm::Error::success();
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds;
|
||||
|
||||
public:
|
||||
llvm::Error run(pipeline::Context &Context) {
|
||||
llvm::Error run(pipeline::ExecutionContext &Context) {
|
||||
std::vector<std::unique_ptr<WellKnownModel>> WellKnownModels;
|
||||
std::map<WellKnownFunctionKey,
|
||||
std::pair<WellKnownModel *, model::Function *>>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
namespace revng::pipes {
|
||||
|
||||
void AddPrimitiveTypesAnalysis::run(pipeline::Context &Context) {
|
||||
void AddPrimitiveTypesAnalysis::run(pipeline::ExecutionContext &Context) {
|
||||
model::addPrimitiveTypes(getWritableModelFromContext(Context));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <type_traits>
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/ScopeExit.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
@@ -343,6 +344,7 @@ Identifier model::Type::name() const {
|
||||
}
|
||||
|
||||
void Qualifier::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -356,6 +358,8 @@ bool Qualifier::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
bool Qualifier::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
|
||||
switch (Kind()) {
|
||||
case QualifierKind::Invalid:
|
||||
return VH.fail("Invalid qualifier found", *this);
|
||||
@@ -597,6 +601,7 @@ PrimitiveType::PrimitiveType(uint64_t ID) :
|
||||
}
|
||||
|
||||
void EnumEntry::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -625,6 +630,7 @@ std::optional<uint64_t> QualifiedType::trySize() const {
|
||||
|
||||
RecursiveCoroutine<std::optional<uint64_t>>
|
||||
QualifiedType::size(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
std::optional<uint64_t> MaybeSize = rc_recur trySize(VH);
|
||||
revng_check(MaybeSize);
|
||||
if (*MaybeSize == 0)
|
||||
@@ -635,6 +641,7 @@ QualifiedType::size(VerifyHelper &VH) const {
|
||||
|
||||
RecursiveCoroutine<std::optional<uint64_t>>
|
||||
QualifiedType::trySize(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
// This code assumes that the QualifiedType QT is well formed.
|
||||
auto QIt = Qualifiers().begin();
|
||||
auto QEnd = Qualifiers().end();
|
||||
@@ -832,6 +839,7 @@ std::optional<uint64_t> Type::trySize() const {
|
||||
}
|
||||
|
||||
std::optional<uint64_t> Type::size(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
std::optional<uint64_t> MaybeSize = trySize(VH);
|
||||
revng_check(MaybeSize);
|
||||
if (*MaybeSize == 0)
|
||||
@@ -846,6 +854,7 @@ std::optional<uint64_t> Type::size(VerifyHelper &VH) const {
|
||||
// to its little brother as well.
|
||||
RecursiveCoroutine<std::optional<uint64_t>>
|
||||
Type::trySize(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
auto MaybeSize = VH.size(this);
|
||||
if (MaybeSize)
|
||||
rc_return MaybeSize;
|
||||
@@ -923,6 +932,7 @@ Type::trySize(VerifyHelper &VH) const {
|
||||
|
||||
static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
const PrimitiveType *T) {
|
||||
auto Guard = VH.suspendTracking(*T);
|
||||
revng_assert(T->Kind() == TypeKind::PrimitiveType);
|
||||
|
||||
if (not T->CustomName().empty() or not T->OriginalName().empty())
|
||||
@@ -973,6 +983,8 @@ bool Identifier::verify(VerifyHelper &VH) const {
|
||||
|
||||
static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
const EnumType *T) {
|
||||
|
||||
auto Guard = VH.suspendTracking(*T);
|
||||
if (T->Kind() != TypeKind::EnumType or T->Entries().empty()
|
||||
or not T->CustomName().verify(VH))
|
||||
rc_return VH.fail();
|
||||
@@ -1002,6 +1014,7 @@ static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
|
||||
static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
const TypedefType *T) {
|
||||
auto Guard = VH.suspendTracking(*T);
|
||||
rc_return VH.maybeFail(T->CustomName().verify(VH)
|
||||
and T->Kind() == TypeKind::TypedefType
|
||||
and rc_recur T->UnderlyingType().verify(VH));
|
||||
@@ -1042,6 +1055,8 @@ bool model::QualifiedType::isScalar() const {
|
||||
|
||||
static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
const StructType *T) {
|
||||
|
||||
auto Guard = VH.suspendTracking(*T);
|
||||
using namespace llvm;
|
||||
|
||||
revng_assert(T->Kind() == TypeKind::StructType);
|
||||
@@ -1118,6 +1133,7 @@ static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
|
||||
static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
const UnionType *T) {
|
||||
auto Guard = VH.suspendTracking(*T);
|
||||
revng_assert(T->Kind() == TypeKind::UnionType);
|
||||
|
||||
if (not T->CustomName().verify(VH))
|
||||
@@ -1163,6 +1179,8 @@ static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
|
||||
static RecursiveCoroutine<bool> verifyImpl(VerifyHelper &VH,
|
||||
const CABIFunctionType *T) {
|
||||
|
||||
auto Guard = VH.suspendTracking(*T);
|
||||
if (not T->CustomName().verify(VH) or T->Kind() != TypeKind::CABIFunctionType
|
||||
or not rc_recur T->ReturnType().verify(VH))
|
||||
rc_return VH.fail();
|
||||
@@ -1269,6 +1287,8 @@ bool Type::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
RecursiveCoroutine<bool> Type::verify(VerifyHelper &VH) const {
|
||||
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
if (VH.isVerified(this))
|
||||
rc_return true;
|
||||
|
||||
@@ -1326,6 +1346,7 @@ RecursiveCoroutine<bool> Type::verify(VerifyHelper &VH) const {
|
||||
}
|
||||
|
||||
void QualifiedType::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -1339,6 +1360,8 @@ bool QualifiedType::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
RecursiveCoroutine<bool> QualifiedType::verify(VerifyHelper &VH) const {
|
||||
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
if (not UnqualifiedType().isValid())
|
||||
rc_return VH.fail("Underlying type is invalid", *this);
|
||||
|
||||
@@ -1423,6 +1446,7 @@ verifyTypedRegisterCommon(const T &TypedRegister, VerifyHelper &VH) {
|
||||
}
|
||||
|
||||
void TypedRegister::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -1436,10 +1460,12 @@ bool TypedRegister::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
RecursiveCoroutine<bool> TypedRegister::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
rc_return verifyTypedRegisterCommon(this, VH);
|
||||
}
|
||||
|
||||
void NamedTypedRegister::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -1453,6 +1479,7 @@ bool NamedTypedRegister::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
RecursiveCoroutine<bool> NamedTypedRegister::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
// Ensure the name is valid
|
||||
if (not CustomName().verify(VH))
|
||||
rc_return VH.fail();
|
||||
@@ -1470,6 +1497,7 @@ bool StructField::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
RecursiveCoroutine<bool> StructField::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
if (not rc_recur Type().verify(VH))
|
||||
rc_return VH.fail("Aggregate field type is not valid");
|
||||
|
||||
@@ -1491,6 +1519,8 @@ bool UnionField::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
RecursiveCoroutine<bool> UnionField::verify(VerifyHelper &VH) const {
|
||||
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
if (not rc_recur Type().verify(VH))
|
||||
rc_return VH.fail("Aggregate field type is not valid");
|
||||
|
||||
@@ -1503,6 +1533,7 @@ RecursiveCoroutine<bool> UnionField::verify(VerifyHelper &VH) const {
|
||||
}
|
||||
|
||||
void Argument::dump() const {
|
||||
TrackGuard Guard(*this);
|
||||
serialize(dbg, *this);
|
||||
}
|
||||
|
||||
@@ -1516,6 +1547,7 @@ bool Argument::verify(bool Assert) const {
|
||||
}
|
||||
|
||||
RecursiveCoroutine<bool> Argument::verify(VerifyHelper &VH) const {
|
||||
auto Guard = VH.suspendTracking(*this);
|
||||
rc_return VH.maybeFail(CustomName().verify(VH)
|
||||
and rc_recur Type().verify(VH));
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ revng_add_library_internal(
|
||||
RegisterKind.cpp
|
||||
Registry.cpp
|
||||
Step.cpp
|
||||
ExecutionContext.cpp
|
||||
Target.cpp
|
||||
Global.cpp
|
||||
GlobalsMap.cpp)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/// \file ExecutionContext.cpp
|
||||
/// \brief
|
||||
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include "revng/Pipeline/Context.h"
|
||||
#include "revng/Pipeline/ExecutionContext.h"
|
||||
#include "revng/Pipeline/Step.h"
|
||||
#include "revng/Pipeline/Target.h"
|
||||
|
||||
using namespace pipeline;
|
||||
|
||||
ExecutionContext::ExecutionContext(Context &Ctx,
|
||||
Step &Step,
|
||||
PipeWrapper *Pipe) :
|
||||
TheContext(&Ctx),
|
||||
CurrentStep(&Step),
|
||||
Pipe(Pipe),
|
||||
RunningOnPipe(Pipe != nullptr) {
|
||||
// pipe is null when execution a analysis. We could just provide a context to
|
||||
// analyses, for the sake of uniformity we pass a execution context to them
|
||||
// too.
|
||||
if (RunningOnPipe)
|
||||
getContext().clearAndResume();
|
||||
}
|
||||
|
||||
pipeline::ExecutionContext::~ExecutionContext() {
|
||||
if (RunningOnPipe)
|
||||
getContext().stopTracking();
|
||||
}
|
||||
|
||||
void ExecutionContext::commit(const Target &Target,
|
||||
llvm::StringRef ContainerName) {
|
||||
revng_assert(Pipe != nullptr);
|
||||
TargetInContainer ToCollect(Target, ContainerName.str());
|
||||
getContext().collectReadFields(ToCollect,
|
||||
Pipe->InvalidationMetadata.getPathCache());
|
||||
}
|
||||
|
||||
void ExecutionContext::clearAndResumeTracking() {
|
||||
getContext().clearAndResume();
|
||||
}
|
||||
|
||||
void ExecutionContext::commitUniqueTarget(const ContainerBase &Container) {
|
||||
auto Enumeration = Container.enumerate();
|
||||
revng_check(Enumeration.size() == 1);
|
||||
commit(Enumeration[0], Container.name());
|
||||
}
|
||||
|
||||
void ExecutionContext::commit(const ContainerBase &Container,
|
||||
const Target &Target) {
|
||||
commit(Target, Container.name());
|
||||
}
|
||||
@@ -29,7 +29,7 @@ std::unique_ptr<LLVMPassWrapperBase> PureLLVMPassWrapper::clone() const {
|
||||
return std::make_unique<PureLLVMPassWrapper>(*this);
|
||||
}
|
||||
|
||||
void GenericLLVMPipe::run(const Context &, LLVMContainer &Container) {
|
||||
void GenericLLVMPipe::run(const ExecutionContext &, LLVMContainer &Container) {
|
||||
llvm::legacy::PassManager Manager;
|
||||
for (const auto &Element : Passes)
|
||||
Element->registerPasses(Manager);
|
||||
|
||||
@@ -148,7 +148,7 @@ Loader::parseInvocation(Step &Step,
|
||||
continue;
|
||||
|
||||
const auto &RoleName = ReadOnlyNames.find(ContainerName)->second;
|
||||
if (Pipe->isContainerArgumentConst(Index))
|
||||
if (Pipe.Pipe->isContainerArgumentConst(Index))
|
||||
continue;
|
||||
|
||||
if (PipelineContext->hasRegisteredReadOnlyContainer(ContainerName)) {
|
||||
|
||||
+60
-57
@@ -40,11 +40,11 @@ static Error getObjectives(Runner &Runner,
|
||||
const ContainerToTargetsMap &Targets,
|
||||
std::vector<PipelineExecutionEntry> &ToExec) {
|
||||
ContainerToTargetsMap ToLoad = Targets;
|
||||
auto *CurrentStep = &(Runner[EndingStepName]);
|
||||
Step *CurrentStep = &(Runner[EndingStepName]);
|
||||
while (CurrentStep != nullptr and not ToLoad.empty()) {
|
||||
|
||||
ContainerToTargetsMap Output = ToLoad;
|
||||
ToLoad = CurrentStep->analyzeGoals(Runner.getContext(), ToLoad);
|
||||
ToLoad = CurrentStep->analyzeGoals(ToLoad);
|
||||
ToExec.emplace_back(*CurrentStep, Output, ToLoad);
|
||||
CurrentStep = CurrentStep->hasPredecessor() ?
|
||||
&CurrentStep->getPredecessor() :
|
||||
@@ -82,7 +82,7 @@ static void explainPipeline(const ContainerToTargetsMap &Targets,
|
||||
|
||||
for (size_t I = Requirements.size(); I != 0; I--) {
|
||||
StringRef StepName = Requirements[I - 1].ToExecute->getName();
|
||||
const auto &TargetsNeeded = Requirements[I - 1].Input;
|
||||
const ContainerToTargetsMap &TargetsNeeded = Requirements[I - 1].Input;
|
||||
|
||||
indent(ExplanationLogger, 1);
|
||||
ExplanationLogger << StepName << ":\n";
|
||||
@@ -92,9 +92,9 @@ static void explainPipeline(const ContainerToTargetsMap &Targets,
|
||||
ExplanationLogger << DoLog;
|
||||
}
|
||||
|
||||
Error Runner::getInvalidations(InvalidationMap &Invalidated) const {
|
||||
Error Runner::getInvalidations(TargetInStepSet &Invalidated) const {
|
||||
|
||||
for (const auto &NextS : *this) {
|
||||
for (const Step &NextS : *this) {
|
||||
if (not NextS.hasPredecessor())
|
||||
continue;
|
||||
|
||||
@@ -104,7 +104,7 @@ Error Runner::getInvalidations(InvalidationMap &Invalidated) const {
|
||||
|
||||
ContainerToTargetsMap &Outputs = Invalidated[NextS.getName()];
|
||||
|
||||
auto Deduced = NextS.deduceResults(getContext(), Inputs);
|
||||
ContainerToTargetsMap Deduced = NextS.deduceResults(Inputs);
|
||||
NextS.containers().intersect(Deduced);
|
||||
Outputs.merge(Deduced);
|
||||
}
|
||||
@@ -121,8 +121,8 @@ Step &Runner::addStep(Step &&NewStep) {
|
||||
}
|
||||
|
||||
llvm::Error Runner::getInvalidations(const Target &Target,
|
||||
InvalidationMap &Invalidations) const {
|
||||
for (const auto &Step : *this)
|
||||
TargetInStepSet &Invalidations) const {
|
||||
for (const Step &Step : *this)
|
||||
for (const auto &Container : Step.containers()) {
|
||||
if (Container.second == nullptr)
|
||||
continue;
|
||||
@@ -131,7 +131,7 @@ llvm::Error Runner::getInvalidations(const Target &Target,
|
||||
Invalidations[Step.getName()].add(Container.first(), Target);
|
||||
}
|
||||
}
|
||||
if (auto Error = getInvalidations(Invalidations); !!Error)
|
||||
if (llvm::Error Error = getInvalidations(Invalidations); !!Error)
|
||||
return Error;
|
||||
|
||||
return llvm::Error::success();
|
||||
@@ -139,7 +139,7 @@ llvm::Error Runner::getInvalidations(const Target &Target,
|
||||
|
||||
Error Runner::invalidate(const Target &Target) {
|
||||
llvm::StringMap<ContainerToTargetsMap> Invalidations;
|
||||
if (auto Error = getInvalidations(Target, Invalidations); !!Error)
|
||||
if (llvm::Error Error = getInvalidations(Target, Invalidations); !!Error)
|
||||
return Error;
|
||||
return invalidate(Invalidations);
|
||||
}
|
||||
@@ -192,7 +192,7 @@ Error Runner::store(const revng::DirectoryPath &DirPath) const {
|
||||
return Error;
|
||||
|
||||
for (const auto &StepName : Steps.keys()) {
|
||||
if (auto Error = storeStepToDisk(StepName, DirPath); !!Error) {
|
||||
if (llvm::Error Error = storeStepToDisk(StepName, DirPath); !!Error) {
|
||||
return Error;
|
||||
}
|
||||
}
|
||||
@@ -240,10 +240,10 @@ llvm::Expected<DiffMap>
|
||||
Runner::runAnalysis(llvm::StringRef AnalysisName,
|
||||
llvm::StringRef StepName,
|
||||
const ContainerToTargetsMap &Targets,
|
||||
InvalidationMap &InvalidationsMap,
|
||||
TargetInStepSet &InvalidationsMap,
|
||||
const llvm::StringMap<std::string> &Options) {
|
||||
|
||||
auto Before = getContext().getGlobals();
|
||||
GlobalsMap Before = getContext().getGlobals();
|
||||
|
||||
auto MaybeStep = Steps.find(StepName);
|
||||
|
||||
@@ -255,23 +255,22 @@ Runner::runAnalysis(llvm::StringRef AnalysisName,
|
||||
|
||||
Task T(3, "Analysis execution");
|
||||
T.advance("Produce step " + StepName, true);
|
||||
if (auto Error = run(StepName, Targets))
|
||||
if (llvm::Error Error = run(StepName, Targets))
|
||||
return std::move(Error);
|
||||
|
||||
T.advance("Run analysis", true);
|
||||
if (auto Error = MaybeStep->second.runAnalysis(AnalysisName,
|
||||
*TheContext,
|
||||
Targets,
|
||||
Options);
|
||||
if (llvm::Error Error = MaybeStep->second.runAnalysis(AnalysisName,
|
||||
Targets,
|
||||
Options);
|
||||
Error) {
|
||||
return std::move(Error);
|
||||
}
|
||||
|
||||
T.advance("Apply diff produced by the analysis", true);
|
||||
auto &After = getContext().getGlobals();
|
||||
auto Map = Before.diff(After);
|
||||
const GlobalsMap &After = getContext().getGlobals();
|
||||
DiffMap Map = Before.diff(After);
|
||||
for (const auto &GlobalNameDiffPair : Map)
|
||||
if (auto Error = apply(GlobalNameDiffPair.second, InvalidationsMap))
|
||||
if (llvm::Error Error = apply(GlobalNameDiffPair.second, InvalidationsMap))
|
||||
return std::move(Error);
|
||||
|
||||
return std::move(Map);
|
||||
@@ -280,17 +279,18 @@ Runner::runAnalysis(llvm::StringRef AnalysisName,
|
||||
/// Run all analysis in reverse post order (that is: parents first),
|
||||
llvm::Expected<DiffMap>
|
||||
Runner::runAnalyses(const AnalysesList &List,
|
||||
InvalidationMap &InvalidationsMap,
|
||||
TargetInStepSet &InvalidationsMap,
|
||||
const llvm::StringMap<std::string> &Options) {
|
||||
auto Before = getContext().getGlobals();
|
||||
GlobalsMap Before = getContext().getGlobals();
|
||||
|
||||
Task T(List.size() + 1, "Analysis list " + List.getName());
|
||||
for (const AnalysisReference &Ref : List) {
|
||||
T.advance(Ref.getAnalysisName(), true);
|
||||
const auto &Step = getStep(Ref.getStepName());
|
||||
const auto &Analysis = Step.getAnalysis(Ref.getAnalysisName());
|
||||
const Step &Step = getStep(Ref.getStepName());
|
||||
const AnalysisWrapper &Analysis = Step.getAnalysis(Ref.getAnalysisName());
|
||||
ContainerToTargetsMap Map;
|
||||
const auto &Containers = Analysis->getRunningContainersNames();
|
||||
const std::vector<std::string>
|
||||
&Containers = Analysis->getRunningContainersNames();
|
||||
for (size_t I = 0; I < Containers.size(); I++) {
|
||||
for (const Kind *K : Analysis->getAcceptedKinds(I)) {
|
||||
Map.add(Containers[I], TargetsList::allTargets(getContext(), *K));
|
||||
@@ -307,7 +307,7 @@ Runner::runAnalyses(const AnalysesList &List,
|
||||
}
|
||||
|
||||
T.advance("Computing analysis list diff", true);
|
||||
auto &After = getContext().getGlobals();
|
||||
const GlobalsMap &After = getContext().getGlobals();
|
||||
return Before.diff(After);
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ Error Runner::run(const State &ToProduce) {
|
||||
Task T(ToProduce.size(), "Multi-step pipeline run");
|
||||
for (const auto &Request : ToProduce) {
|
||||
T.advance(Request.first(), true);
|
||||
if (auto Error = run(Request.first(), Request.second))
|
||||
if (llvm::Error Error = run(Request.first(), Request.second))
|
||||
return Error;
|
||||
}
|
||||
|
||||
@@ -327,7 +327,8 @@ Error Runner::run(llvm::StringRef EndingStepName,
|
||||
|
||||
vector<PipelineExecutionEntry> ToExec;
|
||||
|
||||
if (auto Error = getObjectives(*this, EndingStepName, Targets, ToExec); Error)
|
||||
if (llvm::Error Error = getObjectives(*this, EndingStepName, Targets, ToExec);
|
||||
Error)
|
||||
return Error;
|
||||
|
||||
explainPipeline(Targets, ToExec);
|
||||
@@ -335,9 +336,9 @@ Error Runner::run(llvm::StringRef EndingStepName,
|
||||
if (ToExec.size() <= 1)
|
||||
return Error::success();
|
||||
|
||||
for (auto &StepGoalsPairs : llvm::drop_begin(ToExec)) {
|
||||
auto &Step = *StepGoalsPairs.ToExecute;
|
||||
if (auto Error = Step.checkPrecondition(getContext()); Error)
|
||||
for (PipelineExecutionEntry &StepGoalsPairs : llvm::drop_begin(ToExec)) {
|
||||
Step &Step = *StepGoalsPairs.ToExecute;
|
||||
if (llvm::Error Error = Step.checkPrecondition(); Error)
|
||||
return llvm::make_error<AnnotatedError>(std::move(Error),
|
||||
"While scheduling step "
|
||||
+ Step.getName() + ":");
|
||||
@@ -351,16 +352,16 @@ Error Runner::run(llvm::StringRef EndingStepName,
|
||||
Task T2(3, "Run step");
|
||||
T2.advance("Clone and filter input containers", true);
|
||||
|
||||
auto &Parent = Step->getPredecessor();
|
||||
auto CurrentContainer = Parent.containers().cloneFiltered(Input);
|
||||
::Step &Parent = Step->getPredecessor();
|
||||
ContainerSet CurrentContainer = Parent.containers().cloneFiltered(Input);
|
||||
|
||||
// Run the step
|
||||
T2.advance("Run the step", true);
|
||||
Step->run(*TheContext, std::move(CurrentContainer));
|
||||
Step->run(std::move(CurrentContainer));
|
||||
|
||||
T2.advance("Extract the requested targets", true);
|
||||
if (VerifyLog.isEnabled()) {
|
||||
auto Produced = Step->containers().cloneFiltered(PredictedOutput);
|
||||
ContainerSet Produced = Step->containers().cloneFiltered(PredictedOutput);
|
||||
revng_check(Produced.enumerate().contains(PredictedOutput),
|
||||
"predicted output was not fully contained in actually "
|
||||
"produced");
|
||||
@@ -381,11 +382,11 @@ Error Runner::run(llvm::StringRef EndingStepName,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error Runner::invalidate(const InvalidationMap &Invalidations) {
|
||||
Error Runner::invalidate(const TargetInStepSet &Invalidations) {
|
||||
for (const auto &Step : Invalidations) {
|
||||
const auto &StepName = Step.first();
|
||||
const auto &ToRemove = Step.second;
|
||||
if (auto Error = operator[](StepName).invalidate(ToRemove); Error)
|
||||
llvm::StringRef StepName = Step.first();
|
||||
const ContainerToTargetsMap &ToRemove = Step.second;
|
||||
if (llvm::Error Error = operator[](StepName).invalidate(ToRemove); Error)
|
||||
return Error;
|
||||
}
|
||||
return Error::success();
|
||||
@@ -406,7 +407,7 @@ void Runner::deduceAllPossibleTargets(State &Out) const {
|
||||
continue;
|
||||
|
||||
const Step &Step = NextStep.getPredecessor();
|
||||
auto Result = NextStep.deduceResults(getContext(), Out[Step.getName()]);
|
||||
auto Result = NextStep.deduceResults(Out[Step.getName()]);
|
||||
Out[NextStep.getName()].merge(std::move(Result));
|
||||
}
|
||||
}
|
||||
@@ -415,36 +416,38 @@ const KindsRegistry &Runner::getKindsRegistry() const {
|
||||
}
|
||||
|
||||
void Runner::getDiffInvalidations(const GlobalTupleTreeDiff &Diff,
|
||||
InvalidationMap &Map) const {
|
||||
// the custom write invalidation rules do not know what is the current
|
||||
// content of each container, so first we overestimate the targets to be
|
||||
// invalidated, and then we do the intersection between the overestimated one
|
||||
// and those that do exists.
|
||||
TargetsList OverestimatedTargets;
|
||||
for (const Kind &Kind : getKindsRegistry())
|
||||
Kind.getInvalidations(getContext(), OverestimatedTargets, Diff);
|
||||
TargetInStepSet &Map) const {
|
||||
|
||||
for (const auto &Step : llvm::drop_begin(*this)) {
|
||||
for (const Step &Step : llvm::drop_begin(*this)) {
|
||||
auto &StepInvalidations = Map[Step.getName()];
|
||||
for (const auto &Container : Step.containers()) {
|
||||
if (not Container.second)
|
||||
continue;
|
||||
|
||||
const TargetsList &ExisitingTargets = Container.second->enumerate();
|
||||
TargetsList NewTargets;
|
||||
for (const auto &Target : OverestimatedTargets)
|
||||
if (ExisitingTargets.contains(Target))
|
||||
NewTargets.emplace_back(Target);
|
||||
const TargetsList &ExistingTargets = Container.second->enumerate();
|
||||
// for all targets that are not cached anywhere, mark them to be deleated
|
||||
// every time, since we must be conservative
|
||||
for (const Target &Target : ExistingTargets) {
|
||||
|
||||
StepInvalidations[Container.first()] = NewTargets;
|
||||
TargetInContainer ToFind(Target, Container.first().str());
|
||||
if (Step.invalidationMetadataContains(Diff.getGlobalName(), ToFind))
|
||||
continue;
|
||||
|
||||
StepInvalidations[Container.first()].push_back(Target);
|
||||
}
|
||||
}
|
||||
|
||||
for (const TupleTreePath *Path : Diff.getPaths()) {
|
||||
Step.registerTargetsDependingOn(Diff.getGlobalName(), *Path, Map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Error Runner::apply(const GlobalTupleTreeDiff &Diff,
|
||||
InvalidationMap &Map) {
|
||||
TargetInStepSet &Map) {
|
||||
getDiffInvalidations(Diff, Map);
|
||||
if (auto Error = getInvalidations(Map); Error)
|
||||
return Error;
|
||||
|
||||
return invalidate(Map);
|
||||
}
|
||||
|
||||
+325
-33
@@ -24,15 +24,201 @@ using namespace llvm;
|
||||
using namespace std;
|
||||
using namespace pipeline;
|
||||
|
||||
namespace pipeline {
|
||||
|
||||
class TargetInPipe {
|
||||
public:
|
||||
std::string SerializedTarget;
|
||||
std::string PipeName;
|
||||
|
||||
llvm::Expected<llvm::SmallVector<TargetInContainer, 2>>
|
||||
deserialize(const Context &Ctx, llvm::StringRef ContainerName) const;
|
||||
|
||||
static TargetInPipe fromTargetInContainer(const TargetInContainer &Target,
|
||||
llvm::StringRef PipeName);
|
||||
bool operator<(const TargetInPipe &Other) const {
|
||||
const auto &Tied = std::tie(SerializedTarget, PipeName);
|
||||
return Tied < std::tie(Other.SerializedTarget, Other.PipeName);
|
||||
}
|
||||
};
|
||||
|
||||
class ContainerInvalidationMetadata {
|
||||
public:
|
||||
using ValueType = std::pair<pipeline::TargetInPipe, std::vector<std::string>>;
|
||||
using Vector = std::vector<ValueType>;
|
||||
Vector Data;
|
||||
|
||||
void merge(ContainerInvalidationMetadata &&Other) {
|
||||
for (ValueType &Entry : Other.Data)
|
||||
Data.emplace_back(std::move(Entry));
|
||||
}
|
||||
|
||||
public:
|
||||
llvm::Expected<PathTargetBimap>
|
||||
deserialize(const Context &Ctx,
|
||||
const Global &Primitives,
|
||||
llvm::StringRef PipeName,
|
||||
llvm::StringRef ContainerName) const;
|
||||
|
||||
static ContainerInvalidationMetadata serialize(const PathTargetBimap &Map,
|
||||
const Global &Primitives,
|
||||
llvm::StringRef PipeName,
|
||||
llvm::StringRef ContainerName);
|
||||
};
|
||||
|
||||
class NamedPathTargetBimapVector {
|
||||
public:
|
||||
std::string GlobalName;
|
||||
ContainerInvalidationMetadata Map;
|
||||
};
|
||||
} // namespace pipeline
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(ContainerInvalidationMetadata::ValueType);
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
// YAML traits for TargetInContainer
|
||||
template<>
|
||||
struct MappingTraits<pipeline::TargetInPipe> {
|
||||
static void mapping(IO &IO, pipeline::TargetInPipe &TargetInContainer) {
|
||||
IO.mapRequired("Target", TargetInContainer.SerializedTarget);
|
||||
IO.mapRequired("PipeName", TargetInContainer.PipeName);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MappingTraits<pipeline::ContainerInvalidationMetadata> {
|
||||
static void mapping(IO &Io,
|
||||
pipeline::ContainerInvalidationMetadata &TargetMap) {
|
||||
Io.mapRequired("Map", TargetMap.Data);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MappingTraits<ContainerInvalidationMetadata::Vector::value_type> {
|
||||
static void
|
||||
mapping(IO &Io,
|
||||
pipeline::ContainerInvalidationMetadata::Vector::value_type
|
||||
&TargetMap) {
|
||||
Io.mapRequired("Target", TargetMap.first.SerializedTarget);
|
||||
Io.mapRequired("PipeName", TargetMap.first.PipeName);
|
||||
Io.mapRequired("ReadPaths", TargetMap.second);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace yaml
|
||||
} // namespace llvm
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::NamedPathTargetBimapVector);
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
template<>
|
||||
struct MappingTraits<pipeline::NamedPathTargetBimapVector> {
|
||||
static void mapping(IO &Io, pipeline::NamedPathTargetBimapVector &TargetMap) {
|
||||
Io.mapRequired("GlobalName", TargetMap.GlobalName);
|
||||
Io.mapRequired("Map", TargetMap.Map.Data);
|
||||
}
|
||||
};
|
||||
} // namespace yaml
|
||||
} // namespace llvm
|
||||
|
||||
llvm::Expected<llvm::SmallVector<TargetInContainer, 2>>
|
||||
TargetInPipe::deserialize(const Context &Ctx,
|
||||
llvm::StringRef ContainerName) const {
|
||||
TargetsList Targets;
|
||||
llvm::Error Error = parseTarget(Ctx,
|
||||
SerializedTarget,
|
||||
Ctx.getKindsRegistry(),
|
||||
Targets);
|
||||
if (Error)
|
||||
return std::move(Error);
|
||||
|
||||
llvm::SmallVector<TargetInContainer, 2> Return;
|
||||
for (const Target &Target : Targets) {
|
||||
Return.emplace_back(std::move(Target), ContainerName.str());
|
||||
}
|
||||
return Return;
|
||||
}
|
||||
|
||||
TargetInPipe
|
||||
TargetInPipe::fromTargetInContainer(const TargetInContainer &Target,
|
||||
llvm::StringRef PipeName) {
|
||||
TargetInPipe ToReturn;
|
||||
ToReturn.PipeName = PipeName;
|
||||
ToReturn.SerializedTarget = Target.getTarget().serialize();
|
||||
|
||||
return ToReturn;
|
||||
}
|
||||
|
||||
ContainerInvalidationMetadata
|
||||
ContainerInvalidationMetadata::serialize(const PathTargetBimap &Map,
|
||||
const Global &Global,
|
||||
llvm::StringRef PipeName,
|
||||
llvm::StringRef ContainerName) {
|
||||
ContainerInvalidationMetadata ToSerialize;
|
||||
std::map<pipeline::TargetInPipe, std::vector<std::string>> TemporaryMap;
|
||||
|
||||
for (const auto &Content : Map) {
|
||||
for (const TargetInContainer &Entry : Content.second) {
|
||||
if (Entry.getContainerName() != ContainerName)
|
||||
continue;
|
||||
|
||||
std::optional<std::string> AsString = Global.serializePath(Content.first);
|
||||
revng_check(AsString.has_value());
|
||||
TemporaryMap[TargetInPipe::fromTargetInContainer(Entry, PipeName)]
|
||||
.push_back(*AsString);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &Content : TemporaryMap) {
|
||||
std::pair ToEmplace{ Content.first, Content.second };
|
||||
ToSerialize.Data.emplace_back(std::move(ToEmplace));
|
||||
}
|
||||
|
||||
return ToSerialize;
|
||||
}
|
||||
|
||||
llvm::Expected<PathTargetBimap>
|
||||
ContainerInvalidationMetadata::deserialize(const Context &Ctx,
|
||||
const Global &Global,
|
||||
llvm::StringRef PipeName,
|
||||
llvm::StringRef ContainerName)
|
||||
const {
|
||||
|
||||
PathTargetBimap ToReturn;
|
||||
for (const ValueType &Entry : Data) {
|
||||
if (Entry.first.PipeName != PipeName)
|
||||
continue;
|
||||
llvm::Expected<SmallVector<TargetInContainer>>
|
||||
MaybeTarget = Entry.first.deserialize(Ctx, ContainerName);
|
||||
if (not MaybeTarget)
|
||||
return MaybeTarget.takeError();
|
||||
|
||||
for (auto &SerializedPath : Entry.second) {
|
||||
std::optional<TupleTreePath>
|
||||
MaybeParsedPath = Global.deserializePath(SerializedPath);
|
||||
if (not MaybeParsedPath)
|
||||
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||
"could not parse " + SerializedPath);
|
||||
for (const TargetInContainer &Path : *MaybeTarget)
|
||||
ToReturn.insert(std::move(Path), std::move(*MaybeParsedPath));
|
||||
}
|
||||
}
|
||||
|
||||
return ToReturn;
|
||||
}
|
||||
|
||||
ContainerToTargetsMap
|
||||
Step::analyzeGoals(const Context &Ctx,
|
||||
const ContainerToTargetsMap &RequiredGoals) const {
|
||||
Step::analyzeGoals(const ContainerToTargetsMap &RequiredGoals) const {
|
||||
|
||||
ContainerToTargetsMap AlreadyAvailable;
|
||||
ContainerToTargetsMap Targets = RequiredGoals;
|
||||
removeSatisfiedGoals(Targets, AlreadyAvailable);
|
||||
for (const auto &Pipe : llvm::make_range(Pipes.rbegin(), Pipes.rend())) {
|
||||
Targets = Pipe->getRequirements(Ctx, Targets);
|
||||
for (const PipeWrapper &Pipe :
|
||||
llvm::make_range(Pipes.rbegin(), Pipes.rend())) {
|
||||
Targets = Pipe.Pipe->getRequirements(*Ctx, Targets);
|
||||
}
|
||||
|
||||
return Targets;
|
||||
@@ -60,13 +246,12 @@ void Step::explainEndStep(const ContainerToTargetsMap &Targets,
|
||||
ExplanationLogger << DoLog;
|
||||
}
|
||||
|
||||
void Step::explainExecutedPipe(const Context &Ctx,
|
||||
const InvokableWrapperBase &Wrapper,
|
||||
void Step::explainExecutedPipe(const InvokableWrapperBase &Wrapper,
|
||||
size_t Indentation) const {
|
||||
ExplanationLogger << "RUN " << Wrapper.getName();
|
||||
ExplanationLogger << "(";
|
||||
|
||||
auto Vec = Wrapper.getRunningContainersNames();
|
||||
std::vector<std::string> Vec = Wrapper.getRunningContainersNames();
|
||||
if (not Vec.empty()) {
|
||||
for (size_t I = 0; I < Vec.size() - 1; I++) {
|
||||
ExplanationLogger << Vec[I];
|
||||
@@ -80,49 +265,50 @@ void Step::explainExecutedPipe(const Context &Ctx,
|
||||
ExplanationLogger << DoLog;
|
||||
|
||||
auto CommandStream = CommandLogger.getAsLLVMStream();
|
||||
Wrapper.print(Ctx, *CommandStream, Indentation);
|
||||
Wrapper.print(*Ctx, *CommandStream, Indentation);
|
||||
CommandStream->flush();
|
||||
CommandLogger << DoLog;
|
||||
}
|
||||
|
||||
ContainerSet Step::run(Context &Ctx, ContainerSet &&Input) {
|
||||
auto InputEnumeration = Input.enumerate();
|
||||
ContainerSet Step::run(ContainerSet &&Input) {
|
||||
ContainerToTargetsMap InputEnumeration = Input.enumerate();
|
||||
explainStartStep(InputEnumeration);
|
||||
|
||||
Task T(Pipes.size() + 1, "Step " + getName());
|
||||
for (PipeWrapper &Pipe : Pipes) {
|
||||
T.advance(Pipe->getName(), false);
|
||||
explainExecutedPipe(Ctx, *Pipe);
|
||||
cantFail(Pipe->run(Ctx, Input));
|
||||
T.advance(Pipe.Pipe->getName(), false);
|
||||
explainExecutedPipe(*Pipe.Pipe);
|
||||
ExecutionContext Context(*Ctx, *this, &Pipe);
|
||||
cantFail(Pipe.Pipe->run(Context, Input));
|
||||
llvm::cantFail(Input.verify());
|
||||
}
|
||||
|
||||
T.advance("Merging back", true);
|
||||
explainEndStep(Input.enumerate());
|
||||
Containers.mergeBack(std::move(Input));
|
||||
InputEnumeration = deduceResults(Ctx, InputEnumeration);
|
||||
auto Cloned = Containers.cloneFiltered(InputEnumeration);
|
||||
InputEnumeration = deduceResults(InputEnumeration);
|
||||
ContainerSet Cloned = Containers.cloneFiltered(InputEnumeration);
|
||||
return Cloned;
|
||||
}
|
||||
|
||||
llvm::Error Step::runAnalysis(llvm::StringRef AnalysisName,
|
||||
Context &Ctx,
|
||||
const ContainerToTargetsMap &Targets,
|
||||
const llvm::StringMap<std::string> &ExtraArgs) {
|
||||
auto Stream = ExplanationLogger.getAsLLVMStream();
|
||||
ContainerToTargetsMap Map = Containers.enumerate();
|
||||
|
||||
auto CollapsedTargets = Targets;
|
||||
ContainerToTargetsMap CollapsedTargets = Targets;
|
||||
|
||||
revng_assert(Map.contains(CollapsedTargets),
|
||||
"An analysis was requested, but not all targets are available");
|
||||
|
||||
auto &TheAnalysis = getAnalysis(AnalysisName);
|
||||
AnalysisWrapper &TheAnalysis = getAnalysis(AnalysisName);
|
||||
|
||||
explainExecutedPipe(Ctx, *TheAnalysis);
|
||||
explainExecutedPipe(*TheAnalysis);
|
||||
|
||||
auto Cloned = Containers.cloneFiltered(Targets);
|
||||
return TheAnalysis->run(Ctx, Cloned, ExtraArgs);
|
||||
ContainerSet Cloned = Containers.cloneFiltered(Targets);
|
||||
ExecutionContext ExecutionCtx(*Ctx, *this, nullptr);
|
||||
return TheAnalysis->run(ExecutionCtx, Cloned, ExtraArgs);
|
||||
}
|
||||
|
||||
void Step::removeSatisfiedGoals(TargetsList &RequiredInputs,
|
||||
@@ -144,8 +330,8 @@ void Step::removeSatisfiedGoals(ContainerToTargetsMap &Targets,
|
||||
ContainerToTargetsMap &ToLoad) const {
|
||||
for (auto &RequiredInputsFromContainer : Targets) {
|
||||
llvm::StringRef ContainerName = RequiredInputsFromContainer.first();
|
||||
auto &RequiredInputs = RequiredInputsFromContainer.second;
|
||||
auto &ToLoadFromCurrentContainer = ToLoad[ContainerName];
|
||||
TargetsList &RequiredInputs = RequiredInputsFromContainer.second;
|
||||
TargetsList &ToLoadFromCurrentContainer = ToLoad[ContainerName];
|
||||
if (Containers.contains(ContainerName))
|
||||
removeSatisfiedGoals(RequiredInputs,
|
||||
Containers.at(ContainerName),
|
||||
@@ -153,31 +339,137 @@ void Step::removeSatisfiedGoals(ContainerToTargetsMap &Targets,
|
||||
}
|
||||
}
|
||||
|
||||
ContainerToTargetsMap Step::deduceResults(const Context &Ctx,
|
||||
ContainerToTargetsMap Input) const {
|
||||
for (const auto &Pipe : Pipes)
|
||||
Input = Pipe->deduceResults(Ctx, Input);
|
||||
ContainerToTargetsMap Step::deduceResults(ContainerToTargetsMap Input) const {
|
||||
for (const PipeWrapper &Pipe : Pipes)
|
||||
Input = Pipe.Pipe->deduceResults(*Ctx, Input);
|
||||
return Input;
|
||||
}
|
||||
|
||||
Error Step::invalidate(const ContainerToTargetsMap &ToRemove) {
|
||||
for (auto &Pipe : Pipes) {
|
||||
Pipe.InvalidationMetadata.remove(ToRemove);
|
||||
}
|
||||
return containers().remove(ToRemove);
|
||||
}
|
||||
|
||||
Error Step::store(const revng::DirectoryPath &DirPath) const {
|
||||
return Containers.store(DirPath);
|
||||
if (auto Error = Containers.store(DirPath))
|
||||
return Error;
|
||||
|
||||
return storeInvalidationMetadata(DirPath);
|
||||
}
|
||||
|
||||
Error Step::checkPrecondition(const Context &Ctx) const {
|
||||
for (const auto &Pipe : Pipes) {
|
||||
if (auto Error = Pipe->checkPrecondition(Ctx); Error)
|
||||
Error Step::checkPrecondition() const {
|
||||
for (const PipeWrapper &Pipe : Pipes) {
|
||||
if (llvm::Error Error = Pipe.Pipe->checkPrecondition(*Ctx); Error)
|
||||
return llvm::make_error<AnnotatedError>(std::move(Error),
|
||||
"While scheduling pipe "
|
||||
+ Pipe->getName() + ":");
|
||||
+ Pipe.Pipe->getName() + ":");
|
||||
}
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
Error Step::load(const revng::DirectoryPath &DirPath) {
|
||||
return Containers.load(DirPath);
|
||||
auto MaybeBool = DirPath.exists();
|
||||
if (not MaybeBool)
|
||||
return MaybeBool.takeError();
|
||||
|
||||
if (not MaybeBool.get())
|
||||
return llvm::Error::success();
|
||||
|
||||
if (auto Error = Containers.load(DirPath))
|
||||
return Error;
|
||||
|
||||
return loadInvalidationMetadata(DirPath);
|
||||
}
|
||||
|
||||
llvm::Error
|
||||
Step::loadInvalidationMetadataImpl(const revng::DirectoryPath &Path,
|
||||
ContainerSet::value_type &Container) {
|
||||
auto FilePath = Path.getFile(Container.first().str() + ".cache");
|
||||
auto MaybeBool = FilePath.exists();
|
||||
if (not MaybeBool)
|
||||
return MaybeBool.takeError();
|
||||
|
||||
if (not MaybeBool.get())
|
||||
return llvm::Error::success();
|
||||
|
||||
auto File = FilePath.getReadableFile();
|
||||
if (not File)
|
||||
return File.takeError();
|
||||
|
||||
using Type = llvm::SmallVector<NamedPathTargetBimapVector, 2>;
|
||||
auto Parsed = ::deserialize<Type>(File.get()->buffer().getBuffer());
|
||||
if (not Parsed)
|
||||
return Parsed.takeError();
|
||||
|
||||
for (PipeWrapper &Pipe : Pipes) {
|
||||
for (NamedPathTargetBimapVector &Entry : *Parsed) {
|
||||
Global *Global = llvm::cantFail(Ctx->getGlobals().get(Entry.GlobalName));
|
||||
auto Parsed(Entry.Map.deserialize(*Ctx,
|
||||
*Global,
|
||||
Pipe.Pipe->getName(),
|
||||
Container.first()));
|
||||
if (not Parsed)
|
||||
return Parsed.takeError();
|
||||
Pipe.InvalidationMetadata.getPathCache(Global->getName())
|
||||
.merge(std::move(*Parsed));
|
||||
}
|
||||
}
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Error Step::loadInvalidationMetadata(const revng::DirectoryPath &Path) {
|
||||
|
||||
for (PipeWrapper &Pipe : Pipes) {
|
||||
Pipe.InvalidationMetadata = {};
|
||||
}
|
||||
for (auto &Container : Containers) {
|
||||
if (llvm::Error Error = loadInvalidationMetadataImpl(Path, Container))
|
||||
return Error;
|
||||
}
|
||||
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Error
|
||||
Step::storeInvalidationMetadata(const revng::DirectoryPath &Path) const {
|
||||
for (auto &Container : Containers) {
|
||||
if (Container.second == nullptr)
|
||||
continue;
|
||||
|
||||
using Type = llvm::SmallVector<NamedPathTargetBimapVector, 2>;
|
||||
Type ToStore = {};
|
||||
|
||||
for (const Global *Global : Ctx->getGlobals()) {
|
||||
NamedPathTargetBimapVector Entry;
|
||||
Entry.GlobalName = Global->getName();
|
||||
|
||||
for (const PipeWrapper &Pipe : Pipes) {
|
||||
auto &PathCache = Pipe.InvalidationMetadata.getPathCache();
|
||||
if (PathCache.count(Entry.GlobalName) == 0)
|
||||
continue;
|
||||
|
||||
using MetadataType = ContainerInvalidationMetadata;
|
||||
auto Serialize = MetadataType::serialize;
|
||||
MetadataType Serialized = Serialize(Pipe.InvalidationMetadata
|
||||
.getPathCache(Entry.GlobalName),
|
||||
*Global,
|
||||
Pipe.Pipe->getName(),
|
||||
Container.first());
|
||||
Entry.Map.merge(std::move(Serialized));
|
||||
}
|
||||
ToStore.emplace_back(std::move(Entry));
|
||||
}
|
||||
|
||||
auto File = Path.getFile(Container.first().str() + ".cache")
|
||||
.getWritableFile();
|
||||
if (not File)
|
||||
return File.takeError();
|
||||
::serialize(File->get()->os(), ToStore);
|
||||
if (auto Error = File->get()->commit())
|
||||
return Error;
|
||||
}
|
||||
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/// \file ApplyDiffAnalysis.cpp
|
||||
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include "revng/Pipeline/Context.h"
|
||||
#include "revng/Pipeline/RegisterAnalysis.h"
|
||||
#include "revng/Pipes/ApplyDiffAnalysis.h"
|
||||
#include "revng/Pipes/ModelGlobal.h"
|
||||
#include "revng/Support/YAMLTraits.h"
|
||||
#include "revng/TupleTree/TupleTreeDiff.h"
|
||||
|
||||
namespace revng::pipes {
|
||||
|
||||
llvm::Error ApplyDiffAnalysis::run(pipeline::ExecutionContext &Ctx,
|
||||
std::string DiffLocation) {
|
||||
if (DiffLocation == "")
|
||||
return llvm::Error::success();
|
||||
|
||||
auto &Model = getWritableModelFromContext(Ctx);
|
||||
|
||||
using DiffT = TupleTreeDiff<model::Binary>;
|
||||
|
||||
auto MaybeDiff = deserializeFileOrSTDIN<DiffT>(DiffLocation);
|
||||
if (!MaybeDiff)
|
||||
return MaybeDiff.takeError();
|
||||
|
||||
return MaybeDiff->apply(Model);
|
||||
}
|
||||
|
||||
static pipeline::RegisterAnalysis<ApplyDiffAnalysis> X;
|
||||
|
||||
} // namespace revng::pipes
|
||||
@@ -16,7 +16,7 @@
|
||||
namespace revng::pipes {
|
||||
|
||||
template<bool commit>
|
||||
static llvm::Error applyDiffImpl(pipeline::Context &Ctx,
|
||||
static llvm::Error applyDiffImpl(pipeline::ExecutionContext &Ctx,
|
||||
std::string DiffGlobalName,
|
||||
std::string DiffContent) {
|
||||
if (DiffGlobalName.empty()) {
|
||||
@@ -27,7 +27,7 @@ static llvm::Error applyDiffImpl(pipeline::Context &Ctx,
|
||||
std::unique_ptr<llvm::MemoryBuffer>
|
||||
Buffer = llvm::MemoryBuffer::getMemBuffer(DiffContent);
|
||||
|
||||
auto GlobalOrError = Ctx.getGlobals().get(DiffGlobalName);
|
||||
auto GlobalOrError = Ctx.getContext().getGlobals().get(DiffGlobalName);
|
||||
if (not GlobalOrError)
|
||||
return GlobalOrError.takeError();
|
||||
|
||||
@@ -54,20 +54,20 @@ static llvm::Error applyDiffImpl(pipeline::Context &Ctx,
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Error ApplyDiffAnalysis::run(pipeline::Context &Ctx,
|
||||
llvm::Error ApplyDiffAnalysis::run(pipeline::ExecutionContext &Ctx,
|
||||
std::string DiffGlobalName,
|
||||
std::string DiffContent) {
|
||||
return applyDiffImpl<true>(Ctx, DiffGlobalName, DiffContent);
|
||||
}
|
||||
|
||||
llvm::Error VerifyDiffAnalysis::run(pipeline::Context &Ctx,
|
||||
llvm::Error VerifyDiffAnalysis::run(pipeline::ExecutionContext &Ctx,
|
||||
std::string DiffGlobalName,
|
||||
std::string DiffContent) {
|
||||
return applyDiffImpl<false>(Ctx, DiffGlobalName, DiffContent);
|
||||
}
|
||||
|
||||
template<bool commit>
|
||||
inline llvm::Error setGlobalImpl(pipeline::Context &Ctx,
|
||||
inline llvm::Error setGlobalImpl(pipeline::ExecutionContext &Ctx,
|
||||
std::string SetGlobalName,
|
||||
std::string GlobalContent) {
|
||||
if (SetGlobalName.empty()) {
|
||||
@@ -78,7 +78,8 @@ inline llvm::Error setGlobalImpl(pipeline::Context &Ctx,
|
||||
std::unique_ptr<llvm::MemoryBuffer>
|
||||
Buffer = llvm::MemoryBuffer::getMemBuffer(GlobalContent);
|
||||
|
||||
auto MaybeNewGlobal = Ctx.getGlobals().createNew(SetGlobalName, *Buffer);
|
||||
auto MaybeNewGlobal = Ctx.getContext().getGlobals().createNew(SetGlobalName,
|
||||
*Buffer);
|
||||
if (not MaybeNewGlobal)
|
||||
return MaybeNewGlobal.takeError();
|
||||
|
||||
@@ -89,7 +90,7 @@ inline llvm::Error setGlobalImpl(pipeline::Context &Ctx,
|
||||
}
|
||||
|
||||
if constexpr (commit) {
|
||||
auto GlobalOrError = Ctx.getGlobals().get(SetGlobalName);
|
||||
auto GlobalOrError = Ctx.getContext().getGlobals().get(SetGlobalName);
|
||||
if (not GlobalOrError)
|
||||
return GlobalOrError.takeError();
|
||||
|
||||
@@ -99,13 +100,13 @@ inline llvm::Error setGlobalImpl(pipeline::Context &Ctx,
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Error SetGlobalAnalysis::run(pipeline::Context &Ctx,
|
||||
llvm::Error SetGlobalAnalysis::run(pipeline::ExecutionContext &Ctx,
|
||||
std::string SetGlobalName,
|
||||
std::string GlobalContent) {
|
||||
return setGlobalImpl<true>(Ctx, SetGlobalName, GlobalContent);
|
||||
}
|
||||
|
||||
llvm::Error VerifyGlobalAnalysis::run(pipeline::Context &Ctx,
|
||||
llvm::Error VerifyGlobalAnalysis::run(pipeline::ExecutionContext &Ctx,
|
||||
std::string SetGlobalName,
|
||||
std::string GlobalContent) {
|
||||
return setGlobalImpl<false>(Ctx, SetGlobalName, GlobalContent);
|
||||
|
||||
@@ -272,7 +272,7 @@ llvm::Error PipelineManager::storeStepToDisk(llvm::StringRef StepName) {
|
||||
return StorageClient->commit();
|
||||
}
|
||||
|
||||
llvm::Expected<InvalidationMap>
|
||||
llvm::Expected<TargetInStepSet>
|
||||
PipelineManager::deserializeContainer(pipeline::Step &Step,
|
||||
llvm::StringRef ContainerName,
|
||||
const llvm::MemoryBuffer &Buffer) {
|
||||
@@ -318,9 +318,9 @@ PipelineManager::store(llvm::ArrayRef<std::string> StoresOverrides) {
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Expected<InvalidationMap>
|
||||
llvm::Expected<TargetInStepSet>
|
||||
PipelineManager::invalidateAllPossibleTargets() {
|
||||
InvalidationMap ResultMap;
|
||||
TargetInStepSet ResultMap;
|
||||
auto Stream = ExplanationLogger.getAsLLVMStream();
|
||||
recalculateAllPossibleTargets();
|
||||
|
||||
@@ -346,7 +346,7 @@ PipelineManager::invalidateAllPossibleTargets() {
|
||||
*Stream << Step.first() << "/" << Container.first() << "/";
|
||||
Target.dump(*Stream);
|
||||
|
||||
InvalidationMap Map;
|
||||
TargetInStepSet Map;
|
||||
Map[Step.first()][Container.first()].push_back(Target);
|
||||
if (auto Error = Runner->getInvalidations(Map); Error)
|
||||
return std::move(Error);
|
||||
@@ -403,7 +403,7 @@ PipelineManager::getAnalysis(const AnalysisReference &Reference) const {
|
||||
|
||||
llvm::Expected<DiffMap>
|
||||
PipelineManager::runAnalyses(const pipeline::AnalysesList &List,
|
||||
InvalidationMap &Map,
|
||||
TargetInStepSet &Map,
|
||||
const llvm::StringMap<std::string> &Options,
|
||||
llvm::raw_ostream *DiagnosticLog) {
|
||||
auto Result = Runner->runAnalyses(List, Map, Options);
|
||||
@@ -411,11 +411,7 @@ PipelineManager::runAnalyses(const pipeline::AnalysesList &List,
|
||||
if (not Result)
|
||||
return Result.takeError();
|
||||
|
||||
// TODO: to remove once invalidations are working
|
||||
if (auto Invalidations = invalidateAllPossibleTargets(); !!Invalidations)
|
||||
Map = Invalidations.get();
|
||||
else
|
||||
return Invalidations.takeError();
|
||||
recalculateAllPossibleTargets();
|
||||
|
||||
PipelineContext->bumpCommitIndex();
|
||||
return Result;
|
||||
@@ -425,7 +421,7 @@ llvm::Expected<DiffMap>
|
||||
PipelineManager::runAnalysis(llvm::StringRef AnalysisName,
|
||||
llvm::StringRef StepName,
|
||||
const ContainerToTargetsMap &Targets,
|
||||
InvalidationMap &Map,
|
||||
TargetInStepSet &Map,
|
||||
const llvm::StringMap<std::string> &Options,
|
||||
llvm::raw_ostream *DiagnosticLog) {
|
||||
auto Result = Runner->runAnalysis(AnalysisName,
|
||||
@@ -438,20 +434,14 @@ PipelineManager::runAnalysis(llvm::StringRef AnalysisName,
|
||||
|
||||
recalculateAllPossibleTargets();
|
||||
|
||||
// TODO: to remove once invalidations are working
|
||||
if (auto Invalidations = invalidateAllPossibleTargets(); !!Invalidations)
|
||||
Map = Invalidations.get();
|
||||
else
|
||||
return Invalidations.takeError();
|
||||
|
||||
PipelineContext->bumpCommitIndex();
|
||||
return Result;
|
||||
}
|
||||
|
||||
llvm::Expected<InvalidationMap>
|
||||
llvm::Expected<TargetInStepSet>
|
||||
PipelineManager::invalidateFromDiff(const llvm::StringRef Name,
|
||||
const pipeline::GlobalTupleTreeDiff &Diff) {
|
||||
InvalidationMap Map;
|
||||
TargetInStepSet Map;
|
||||
if (auto ApplyError = getRunner().apply(Diff, Map); !!ApplyError)
|
||||
return std::move(ApplyError);
|
||||
|
||||
|
||||
@@ -42,27 +42,6 @@ IsolatedRootKind::symbolToTarget(const llvm::Function &Symbol) const {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void RootKind::getInvalidations(const Context &Ctx,
|
||||
TargetsList &ToRemove,
|
||||
const GlobalTupleTreeDiff &Base) const {
|
||||
|
||||
const auto *Diff = Base.getAs<model::Binary>();
|
||||
if (not Diff)
|
||||
return;
|
||||
|
||||
const TupleTreePath ToCheck = *stringAsPath<model::Binary>("/ExtraCodeAddre"
|
||||
"ss"
|
||||
"es");
|
||||
|
||||
bool RootChanged = llvm::any_of(Diff->Changes, [&ToCheck](const auto &Entry) {
|
||||
const auto &[Path, Old, New] = Entry;
|
||||
return ToCheck.isPrefixOf(Path);
|
||||
});
|
||||
|
||||
if (RootChanged)
|
||||
ToRemove.emplace_back(*this);
|
||||
}
|
||||
|
||||
void RootKind::appendAllTargets(const Context &Ctx, TargetsList &Out) const {
|
||||
Out.push_back(Target(*this));
|
||||
}
|
||||
|
||||
@@ -39,20 +39,6 @@ TaggedFunctionKind::symbolToTarget(const llvm::Function &Symbol) const {
|
||||
return pipeline::Target({ Address.toString() }, *this);
|
||||
}
|
||||
|
||||
using TaggedFK = TaggedFunctionKind;
|
||||
void TaggedFK::getInvalidations(const Context &Ctx,
|
||||
TargetsList &ToRemove,
|
||||
const GlobalTupleTreeDiff &Diff) const {
|
||||
const auto &CurrentModel = getModelFromContext(Ctx);
|
||||
|
||||
if (not Ctx.containsReadOnlyContainer(BinaryCrossRelationsRole))
|
||||
return;
|
||||
|
||||
const auto *ModelDiff = Diff.getAs<model::Binary>();
|
||||
if (not ModelDiff)
|
||||
return;
|
||||
}
|
||||
|
||||
void TaggedFunctionKind::appendAllTargets(const pipeline::Context &Ctx,
|
||||
pipeline::TargetsList &Out) const {
|
||||
const auto &Model = getModelFromContext(Ctx);
|
||||
|
||||
@@ -143,16 +143,16 @@ static void compileModuleRunImpl(const Context &Ctx,
|
||||
fs::setPermissions(*TargetBinary.path(), Permissions);
|
||||
}
|
||||
|
||||
void CompileModule::run(const Context &Ctx,
|
||||
void CompileModule::run(const ExecutionContext &Ctx,
|
||||
LLVMContainer &Module,
|
||||
ObjectFileContainer &TargetBinary) {
|
||||
compileModuleRunImpl(Ctx, Module, TargetBinary);
|
||||
compileModuleRunImpl(Ctx.getContext(), Module, TargetBinary);
|
||||
}
|
||||
|
||||
void CompileIsolatedModule::run(const Context &Ctx,
|
||||
void CompileIsolatedModule::run(const ExecutionContext &Ctx,
|
||||
LLVMContainer &Module,
|
||||
ObjectFileContainer &TargetBinary) {
|
||||
compileModuleRunImpl(Ctx, Module, TargetBinary);
|
||||
compileModuleRunImpl(Ctx.getContext(), Module, TargetBinary);
|
||||
}
|
||||
|
||||
static RegisterPipe<CompileModule> E2;
|
||||
|
||||
@@ -17,7 +17,7 @@ using namespace llvm::sys;
|
||||
using namespace pipeline;
|
||||
using namespace ::revng::pipes;
|
||||
|
||||
void LinkForTranslation::run(const Context &Ctx,
|
||||
void LinkForTranslation::run(const ExecutionContext &Ctx,
|
||||
BinaryFileContainer &InputBinary,
|
||||
ObjectFileContainer &ObjectFile,
|
||||
TranslatedFileContainer &OutputBinary) {
|
||||
|
||||
@@ -256,13 +256,13 @@ public:
|
||||
pipeline::InputPreservation::Preserve);
|
||||
return { pipeline::ContractGroup({ FunctionsContract, BinaryContract }) };
|
||||
}
|
||||
void run(const pipeline::Context &Ctx,
|
||||
void run(pipeline::ExecutionContext &Ctx,
|
||||
const BinaryFileContainer &SourceBinary,
|
||||
const pipeline::LLVMContainer &Module,
|
||||
HexDumpFileContainer &Output) {
|
||||
pipeline::TargetsList Enumeration = Module.enumerate();
|
||||
|
||||
if (not Enumeration.contains(kinds::Isolated.allTargets(Ctx)))
|
||||
if (not Enumeration.contains(kinds::Isolated.allTargets(Ctx.getContext())))
|
||||
return;
|
||||
|
||||
if (not SourceBinary.exists())
|
||||
|
||||
@@ -24,7 +24,7 @@ using ptml::PTMLBuilder;
|
||||
|
||||
namespace revng::pipes {
|
||||
|
||||
void ProcessAssembly::run(pipeline::Context &Context,
|
||||
void ProcessAssembly::run(pipeline::ExecutionContext &Context,
|
||||
const BinaryFileContainer &SourceBinary,
|
||||
const pipeline::LLVMContainer &TargetList,
|
||||
FunctionAssemblyStringMap &Output) {
|
||||
@@ -65,7 +65,7 @@ void ProcessAssembly::print(const pipeline::Context &,
|
||||
OS << "[this is a pure pipe, no command exists for its invocation]\n";
|
||||
}
|
||||
|
||||
void YieldAssembly::run(pipeline::Context &Context,
|
||||
void YieldAssembly::run(pipeline::ExecutionContext &Context,
|
||||
const FunctionAssemblyStringMap &Input,
|
||||
FunctionAssemblyPTMLStringMap &Output) {
|
||||
// Access the model
|
||||
|
||||
@@ -16,7 +16,7 @@ using ptml::PTMLBuilder;
|
||||
|
||||
namespace revng::pipes {
|
||||
|
||||
void YieldControlFlow::run(pipeline::Context &Context,
|
||||
void YieldControlFlow::run(pipeline::ExecutionContext &Context,
|
||||
const FunctionAssemblyStringMap &Input,
|
||||
FunctionControlFlowStringMap &Output) {
|
||||
// Access the model
|
||||
|
||||
@@ -24,7 +24,7 @@ using ptml::PTMLBuilder;
|
||||
|
||||
namespace revng::pipes {
|
||||
|
||||
void ProcessCallGraph::run(pipeline::Context &Context,
|
||||
void ProcessCallGraph::run(pipeline::ExecutionContext &Context,
|
||||
const pipeline::LLVMContainer &TargetList,
|
||||
CrossRelationsFileContainer &OutputFile) {
|
||||
// Access the model
|
||||
@@ -51,7 +51,7 @@ void ProcessCallGraph::print(const pipeline::Context &,
|
||||
OS << "[this is a pure pipe, no command exists for its invocation]\n";
|
||||
}
|
||||
|
||||
void YieldCallGraph::run(pipeline::Context &Context,
|
||||
void YieldCallGraph::run(pipeline::ExecutionContext &Context,
|
||||
const CrossRelationsFileContainer &Relations,
|
||||
CallGraphSVGFileContainer &Output) {
|
||||
// Access the model
|
||||
@@ -71,7 +71,7 @@ void YieldCallGraph::print(const pipeline::Context &,
|
||||
OS << "[this is a pure pipe, no command exists for its invocation]\n";
|
||||
}
|
||||
|
||||
void YieldCallGraphSlice::run(pipeline::Context &Context,
|
||||
void YieldCallGraphSlice::run(pipeline::ExecutionContext &Context,
|
||||
const pipeline::LLVMContainer &TargetList,
|
||||
const CrossRelationsFileContainer &Relations,
|
||||
CallGraphSliceSVGStringMap &Output) {
|
||||
|
||||
@@ -39,6 +39,7 @@ struct /*= struct | fullname =*/
|
||||
{
|
||||
/** if emit_tracking -**/
|
||||
friend struct revng::Tracking;
|
||||
inline static constexpr bool HasTracking = true;
|
||||
/**- endif **/
|
||||
|
||||
/** if struct.inherits **/
|
||||
@@ -57,7 +58,7 @@ private:
|
||||
static_assert(Yamlizable</*= field | field_type =*/>);
|
||||
|
||||
/**- if emit_tracking **/
|
||||
mutable revng::AccessTracker /*= field.name =*/Tracker;
|
||||
mutable revng::AccessTracker /*= field.name =*/Tracker = revng::AccessTracker(false);
|
||||
/** endif -**/
|
||||
|
||||
public:
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
set -x
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
|
||||
@@ -314,22 +314,6 @@ target_link_libraries(test_pipeline revngUnitTestHelpers revngPipeline
|
||||
revng_add_test(NAME test_pipeline COMMAND test_pipeline)
|
||||
set_tests_properties(test_pipeline PROPERTIES LABELS "unit")
|
||||
|
||||
#
|
||||
# test_diff_invalidation_event
|
||||
#
|
||||
|
||||
revng_add_test_executable(test_diff_invalidation_event
|
||||
"${SRC}/DiffInvalidationEvent.cpp")
|
||||
target_compile_definitions(test_diff_invalidation_event
|
||||
PRIVATE "BOOST_TEST_DYN_LINK=1")
|
||||
target_include_directories(test_diff_invalidation_event
|
||||
PRIVATE "${CMAKE_SOURCE_DIR}")
|
||||
target_link_libraries(test_diff_invalidation_event revngUnitTestHelpers
|
||||
revngPipes Boost::unit_test_framework ${LLVM_LIBRARIES})
|
||||
revng_add_test(NAME test_diff_invalidation_event COMMAND
|
||||
test_diff_invalidation_event)
|
||||
set_tests_properties(test_diff_invalidation_event PROPERTIES LABELS "unit")
|
||||
|
||||
#
|
||||
# test_pipeline_c
|
||||
#
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/// \file DiffInvalidationEvent.cpp
|
||||
/// Tests for C API of revng-pipeline.
|
||||
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include "revng/Model/Binary.h"
|
||||
#include "revng/Pipes/Kinds.h"
|
||||
#include "revng/Support/MetaAddress.h"
|
||||
|
||||
#define BOOST_TEST_MODULE PipelineC
|
||||
bool init_unit_test();
|
||||
#include "boost/test/unit_test.hpp"
|
||||
|
||||
#include "revng/UnitTestHelpers/UnitTestHelpers.h"
|
||||
|
||||
using namespace revng::kinds;
|
||||
using namespace pipeline;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(ModelInvalidationDiffSuite)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RootInvalidationTest) {
|
||||
model::Binary Empty;
|
||||
model::Binary New;
|
||||
|
||||
Context Ctx;
|
||||
MetaAddress Address(0x1000, MetaAddressType::Code_aarch64);
|
||||
New.ExtraCodeAddresses().insert(Address);
|
||||
|
||||
TargetsList ToRemove;
|
||||
GlobalTupleTreeDiff Event(diff(Empty, New));
|
||||
Root.getInvalidations(Ctx, ToRemove, Event);
|
||||
BOOST_TEST(ToRemove.size() == 1);
|
||||
BOOST_TEST(&ToRemove.front().getKind() == &Root);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(CollectReadFieldsShouldCompile) {
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TrackingResetterShouldCompile) {
|
||||
model::Binary Model;
|
||||
revng::Tracking::clear(Model);
|
||||
revng::Tracking::clearAndResume(Model);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TrackingPushAndPopperShouldCompile) {
|
||||
@@ -356,7 +356,7 @@ BOOST_AUTO_TEST_CASE(CollectReadFieldsShouldBeEmptyAtFirst) {
|
||||
model::Binary Model;
|
||||
auto MetaAddress = MetaAddress::fromPC(llvm::Triple::ArchType::x86_64, 0);
|
||||
Model.Segments().insert(Segment(MetaAddress, 1000));
|
||||
revng::Tracking::clear(Model);
|
||||
revng::Tracking::clearAndResume(Model);
|
||||
|
||||
auto Collected = revng::Tracking::collect(Model);
|
||||
BOOST_TEST(Collected.Read.size() == 0);
|
||||
@@ -367,7 +367,7 @@ BOOST_AUTO_TEST_CASE(CollectReadFieldsShouldCollectSegments) {
|
||||
const auto MetaAddress = MetaAddress::fromPC(llvm::Triple::ArchType::x86_64,
|
||||
0);
|
||||
Model.Segments().insert(Segment(MetaAddress, 1000));
|
||||
revng::Tracking::clear(Model);
|
||||
revng::Tracking::clearAndResume(Model);
|
||||
const auto &ConstModel = Model;
|
||||
ConstModel.Segments().at(Segment::Key(MetaAddress, 1000)).StartAddress();
|
||||
|
||||
@@ -389,7 +389,7 @@ BOOST_AUTO_TEST_CASE(CollectReadFieldsShouldCollectNotFoundSegments) {
|
||||
model::Binary Model;
|
||||
const auto MetaAddress = MetaAddress::fromPC(llvm::Triple::ArchType::x86_64,
|
||||
0);
|
||||
revng::Tracking::clear(Model);
|
||||
revng::Tracking::clearAndResume(Model);
|
||||
const auto &ConstModel = Model;
|
||||
ConstModel.Segments().tryGet(Segment::Key(MetaAddress, 1000));
|
||||
|
||||
@@ -407,7 +407,7 @@ BOOST_AUTO_TEST_CASE(CollectReadFieldsShouldCollectAllSegments) {
|
||||
const auto MetaAddress = MetaAddress::fromPC(llvm::Triple::ArchType::x86_64,
|
||||
0);
|
||||
Model.Segments().insert(Segment(MetaAddress, 1000));
|
||||
revng::Tracking::clear(Model);
|
||||
revng::Tracking::clearAndResume(Model);
|
||||
const auto &ConstModel = Model;
|
||||
ConstModel.Segments().begin();
|
||||
|
||||
@@ -428,7 +428,7 @@ BOOST_AUTO_TEST_CASE(QualifiersInsideAVectorAreNotVisited) {
|
||||
const auto MetaAddress = MetaAddress::fromPC(llvm::Triple::ArchType::x86_64,
|
||||
0);
|
||||
Type.Qualifiers().push_back(Qualifier());
|
||||
revng::Tracking::clear(Type);
|
||||
revng::Tracking::clearAndResume(Type);
|
||||
const auto &ConstType = Type;
|
||||
ConstType.Qualifiers().at(0).Size();
|
||||
|
||||
|
||||
+24
-13
@@ -243,7 +243,9 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
void run(const Context &, const MapContainer &Source, MapContainer &Target) {
|
||||
void run(const ExecutionContext &,
|
||||
const MapContainer &Source,
|
||||
MapContainer &Target) {
|
||||
Source.enumerate().dump();
|
||||
auto SrcCopy = Source;
|
||||
for (const auto &Element : SrcCopy.getMap())
|
||||
@@ -260,10 +262,12 @@ public:
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PipeCanBeWrapper) {
|
||||
Context Ctx;
|
||||
Step FakeStep(Ctx, "dc", "", {});
|
||||
ExecutionContext ExecutionCtx(Ctx, FakeStep, nullptr);
|
||||
MapContainer Map("RandomName");
|
||||
Map.get({ {}, RootKind }) = 1;
|
||||
TestPipe Enf;
|
||||
Enf.run(Ctx, Map, Map);
|
||||
Enf.run(ExecutionCtx, Map, Map);
|
||||
BOOST_TEST(Map.get({ {}, RootKind2 }) == 1);
|
||||
}
|
||||
|
||||
@@ -453,7 +457,8 @@ BOOST_AUTO_TEST_CASE(StepCanCloneAndRun) {
|
||||
ContainerSet Containers;
|
||||
auto Factory = getMapFactoryContainer();
|
||||
Containers.add(CName, Factory, Factory("dont_care"));
|
||||
Step Step("first_step",
|
||||
Step Step(Ctx,
|
||||
"first_step",
|
||||
"",
|
||||
std::move(Containers),
|
||||
PipeWrapper::bind<TestPipe>(CName, CName));
|
||||
@@ -465,7 +470,7 @@ BOOST_AUTO_TEST_CASE(StepCanCloneAndRun) {
|
||||
auto Factory2 = getMapFactoryContainer();
|
||||
Containers.add(CName, Factory, Factory("dont_care"));
|
||||
cast<MapContainer>(Containers[CName]).get(Target({}, RootKind)) = 1;
|
||||
auto Result = Step.run(Ctx, std::move(Containers));
|
||||
auto Result = Step.run(std::move(Containers));
|
||||
|
||||
auto &Cont = cast<MapContainer>(Result.at(CName));
|
||||
BOOST_TEST(Cont.get(Target({}, RootKind2)) == 1);
|
||||
@@ -477,7 +482,8 @@ BOOST_AUTO_TEST_CASE(PipelineCanBeManuallyExectued) {
|
||||
|
||||
Context Ctx;
|
||||
Runner Pip(Ctx);
|
||||
Pip.addStep(Step("first_step",
|
||||
Pip.addStep(Step(Ctx,
|
||||
"first_step",
|
||||
"",
|
||||
Registry.createEmpty(),
|
||||
PipeWrapper::bind<TestPipe>(CName, CName)));
|
||||
@@ -486,7 +492,7 @@ BOOST_AUTO_TEST_CASE(PipelineCanBeManuallyExectued) {
|
||||
auto &C1 = Containers.getOrCreate<MapContainer>(CName);
|
||||
C1.get(Target(RootKind)) = 1;
|
||||
|
||||
auto Res = Pip["first_step"].run(Ctx, std::move(Containers));
|
||||
auto Res = Pip["first_step"].run(std::move(Containers));
|
||||
BOOST_TEST(cast<MapContainer>(Res.at(CName)).get(Target(RootKind2)) == 1);
|
||||
const auto &StartingContainer = Pip["first_step"]
|
||||
.containers()
|
||||
@@ -505,14 +511,15 @@ BOOST_AUTO_TEST_CASE(SingleElementPipelineCanBeRunned) {
|
||||
auto &C1 = cast<MapContainer>(Content[CName]);
|
||||
C1.get(Target(RootKind)) = 1;
|
||||
|
||||
Step StepToAdd("first_step", "", std::move(Content));
|
||||
Step StepToAdd(Ctx, "first_step", "", std::move(Content));
|
||||
Pip.addStep(std::move(StepToAdd));
|
||||
ContainerSet &BCI = Pip["first_step"].containers();
|
||||
BOOST_TEST(cast<MapContainer>(BCI.at(CName)).get(Target(RootKind)) == 1);
|
||||
|
||||
ContainerSet Containers2;
|
||||
Containers2.add(CName, Factory, make_unique<MapContainer>("dont_care"));
|
||||
Pip.addStep(Step("End",
|
||||
Pip.addStep(Step(Ctx,
|
||||
"End",
|
||||
"",
|
||||
std::move(Containers2),
|
||||
Pip["first_step"],
|
||||
@@ -536,7 +543,8 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
void run(Context &, const MapContainer &Source, MapContainer &Target) {
|
||||
void
|
||||
run(ExecutionContext &, const MapContainer &Source, MapContainer &Target) {
|
||||
for (const auto &Element : Source.getMap()) {
|
||||
|
||||
if (&Element.first.getKind() != &RootKind)
|
||||
@@ -565,7 +573,8 @@ public:
|
||||
InputPreservation::Preserve) };
|
||||
}
|
||||
|
||||
void run(Context &, const MapContainer &Source, MapContainer &Target) {
|
||||
void
|
||||
run(ExecutionContext &, const MapContainer &Source, MapContainer &Target) {
|
||||
for (const auto &Element : Source.getMap())
|
||||
if (&Element.first.getKind() == &FunctionKind)
|
||||
Target.get(Element.first) = Element.second;
|
||||
@@ -1289,7 +1298,7 @@ BOOST_AUTO_TEST_CASE(MultiStepInvalidationTest) {
|
||||
|
||||
BOOST_TEST(C2End.get(ToProduce) == 1);
|
||||
|
||||
pipeline::InvalidationMap Invalidations;
|
||||
pipeline::TargetInStepSet Invalidations;
|
||||
Invalidations[Name][CName].push_back(T);
|
||||
|
||||
// C2End.enumerate().dump();
|
||||
@@ -1322,7 +1331,7 @@ public:
|
||||
|
||||
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds = { { &RootKind } };
|
||||
|
||||
void run(const Context &Ctx,
|
||||
void run(const ExecutionContext &Ctx,
|
||||
const MapContainer &Cont,
|
||||
int First,
|
||||
std::string Second,
|
||||
@@ -1337,11 +1346,13 @@ BOOST_AUTO_TEST_CASE(PipeOptions) {
|
||||
RegisterAnalysis<ArgumentTestAnalysis> Dummy;
|
||||
pipeline::AnalysisWrapperImpl W(ArgumentTestAnalysis(), { "container_name" });
|
||||
Context Ctx;
|
||||
Step FakeStep(Ctx, "dc", "", {});
|
||||
ExecutionContext ExecutionCtx(Ctx, FakeStep, nullptr);
|
||||
ContainerSet Set;
|
||||
auto Factory = ContainerFactory::create<MapContainer>();
|
||||
Set.add("container_name", Factory);
|
||||
Set["container_name"];
|
||||
if (auto Error = W.run(Ctx, Set, {}); Error)
|
||||
if (auto Error = W.run(ExecutionCtx, Set, {}); Error)
|
||||
BOOST_FAIL("unreachable");
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ static void runAnalysis(Runner &Pipeline, llvm::StringRef Target) {
|
||||
auto [AnalysisName, Rest2] = Rest.split("/");
|
||||
|
||||
ContainerToTargetsMap ToProduce;
|
||||
InvalidationMap Map;
|
||||
TargetInStepSet Map;
|
||||
AbortOnError(parseTarget(Pipeline.getContext(), ToProduce, Rest2, Registry));
|
||||
AbortOnError(Pipeline.runAnalysis(AnalysisName, Step, ToProduce, Map));
|
||||
}
|
||||
@@ -183,11 +183,12 @@ int main(int argc, char *argv[]) {
|
||||
auto Diff = AbortOnError(deserializeFileOrSTDIN<Type>(ApplyModelDiff));
|
||||
|
||||
auto &Runner = Manager.getRunner();
|
||||
InvalidationMap Map;
|
||||
AbortOnError(Runner.apply(GlobalTupleTreeDiff(std::move(Diff)), Map));
|
||||
TargetInStepSet Map;
|
||||
GlobalTupleTreeDiff GlobalDiff(std::move(Diff), ModelGlobalName);
|
||||
AbortOnError(Runner.apply(GlobalDiff, Map));
|
||||
}
|
||||
|
||||
InvalidationMap InvMap;
|
||||
TargetInStepSet InvMap;
|
||||
for (auto &AnalysesListName : AnalysesLists) {
|
||||
if (!Manager.getRunner().hasAnalysesList(AnalysesListName)) {
|
||||
AbortOnError(createStringError(inconvertibleErrorCode(),
|
||||
|
||||
@@ -121,7 +121,7 @@ int main(int argc, char *argv[]) {
|
||||
auto &InputContainer = Manager.getRunner().begin()->containers()["input"];
|
||||
AbortOnError(InputContainer.load(FilePath::fromLocalStorage(Arguments[1])));
|
||||
|
||||
InvalidationMap InvMap;
|
||||
TargetInStepSet InvMap;
|
||||
if (Manager.getRunner().hasAnalysesList(Arguments[0])) {
|
||||
AnalysesList AL = Manager.getRunner().getAnalysesList(Arguments[0]);
|
||||
AbortOnError(Manager.runAnalyses(AL, InvMap));
|
||||
|
||||
@@ -85,7 +85,7 @@ int main(int argc, char *argv[]) {
|
||||
auto &InputContainer = Manager.getRunner().begin()->containers()["input"];
|
||||
AbortOnError(InputContainer.load(FilePath::fromLocalStorage(Arguments[1])));
|
||||
|
||||
InvalidationMap InvMap;
|
||||
TargetInStepSet InvMap;
|
||||
for (auto &AnalysesListName : AnalysesLists) {
|
||||
if (!Manager.getRunner().hasAnalysesList(AnalysesListName)) {
|
||||
AbortOnError(createStringError(inconvertibleErrorCode(),
|
||||
|
||||
@@ -49,8 +49,8 @@ static ToolCLOptions BaseOptions(MainCategory);
|
||||
|
||||
static ExitOnError AbortOnError;
|
||||
|
||||
static InvalidationMap getInvalidationMap(Runner &Pipeline) {
|
||||
InvalidationMap Invalidations;
|
||||
static TargetInStepSet getTargetInStepSet(Runner &Pipeline) {
|
||||
TargetInStepSet Invalidations;
|
||||
|
||||
const auto &Registry = Pipeline.getKindsRegistry();
|
||||
for (llvm::StringRef Target : Targets) {
|
||||
@@ -63,8 +63,8 @@ static InvalidationMap getInvalidationMap(Runner &Pipeline) {
|
||||
return Invalidations;
|
||||
}
|
||||
|
||||
static void dumpInvalidationMap(llvm::raw_ostream &OS,
|
||||
const InvalidationMap &Map) {
|
||||
static void dumpTargetInStepSet(llvm::raw_ostream &OS,
|
||||
const TargetInStepSet &Map) {
|
||||
for (const auto &Pair : Map) {
|
||||
OS << Pair.first();
|
||||
Pair.second.dump(OS, 1);
|
||||
@@ -78,11 +78,11 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
auto Manager = AbortOnError(BaseOptions.makeManager());
|
||||
|
||||
auto Map = getInvalidationMap(Manager.getRunner());
|
||||
auto Map = getTargetInStepSet(Manager.getRunner());
|
||||
AbortOnError(Manager.getRunner().getInvalidations(Map));
|
||||
|
||||
if (DumpPredictedRemovals) {
|
||||
dumpInvalidationMap(llvm::outs(), Map);
|
||||
dumpTargetInStepSet(llvm::outs(), Map);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user