mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
3db971b8b4
We used to invalidate only if *all* inputs were invalidated.
214 lines
8.1 KiB
C++
214 lines
8.1 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <string>
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "revng/Pipeline/Context.h"
|
|
#include "revng/Pipeline/Kind.h"
|
|
#include "revng/Pipeline/Target.h"
|
|
|
|
namespace pipeline {
|
|
|
|
namespace InputPreservation {
|
|
enum Values {
|
|
Erase,
|
|
Preserve
|
|
};
|
|
} // namespace InputPreservation
|
|
|
|
/// A contract establishes what operations a pipe can perform on both input
|
|
/// and output containers referred by their index.
|
|
///
|
|
/// Before explaining more formally how contracts operates it's better consider
|
|
/// a couple of examples
|
|
///
|
|
/// A contract from root to binary (both kinds with granularity 1), requires
|
|
/// that the pipe it is attached to will convert all roots with pathComponents
|
|
/// (i) into binaries with pathComponents (i)
|
|
///
|
|
/// A contract from root(rank 1) to function(rank 2), requires
|
|
/// that the pipe it is attached to will convert all roots with pathComponents
|
|
/// (i) into functions with pathComponents(i, *).
|
|
///
|
|
/// A contract from functions(rank 2) to root(rank 1), requires
|
|
/// that the pipe it is attached to will convert all functions with
|
|
/// pathComponents (i, *) into roots with pathComponents(i). Furthermore it is
|
|
/// guaranteed that only functions in the form (i, *) are presents, in other
|
|
/// words that either all or none functions are forwarded to the pipe.
|
|
///
|
|
/// A pipe marked with a single contract must transform all the items from
|
|
/// the input container that have Targets with the same kind and only them.
|
|
/// If Exactness is not Exact, this also applies to the derived kinds.
|
|
///
|
|
/// Furthermore, the pipe must ensure that for each item in the input container
|
|
/// that matches the requirements another target is created in the target
|
|
/// container (if the target container exists), such that
|
|
///
|
|
/// If the output kind has a greater rank than the inputkind then for all
|
|
/// Targets in input with source kind and pathComponents (i1, ..., in) then a
|
|
/// target with kind output and pathComponents (i1, ..., in, *) exists.
|
|
///
|
|
/// If the output has a smaller rank g1 than the input rank g2
|
|
/// then for the pipe must operate on all targets with Kind source and
|
|
/// pathcomponents(i1, ..., i_g2) and yield a target for each with Kind target
|
|
/// and pathComponents(i1, ..., i_g1), it will be ensured that when the pipe
|
|
/// executed each target in the input container that must be transformed will be
|
|
/// in the form (i1, ..., i_g2) where each pathcomponents i_x such that g1 <= x
|
|
/// <= g2 is *.
|
|
///
|
|
/// A contract must refer to a source target containers than can be the same.
|
|
/// The index refers to the list of names passed in the various methods of this
|
|
/// class.
|
|
///
|
|
/// In practice they refer to the argument index of the run method of pipes,
|
|
/// ignoring argument zero which is always Context.
|
|
class Contract {
|
|
public:
|
|
static constexpr auto Erase = InputPreservation::Erase;
|
|
|
|
private:
|
|
const Kind *Source = nullptr;
|
|
const Kind *TargetKind = nullptr;
|
|
size_t PipeArgumentSourceIndex;
|
|
size_t PipeArgumentTargetIndex;
|
|
InputPreservation::Values Preservation;
|
|
|
|
public:
|
|
constexpr Contract(const Kind &Source,
|
|
size_t PipeArgumentSourceIndex,
|
|
const Kind &Target,
|
|
size_t PipeArgumentTargetIndex = 0,
|
|
InputPreservation::Values Preserve = Erase) :
|
|
Source(&Source),
|
|
TargetKind(&Target),
|
|
PipeArgumentSourceIndex(PipeArgumentSourceIndex),
|
|
PipeArgumentTargetIndex(PipeArgumentTargetIndex),
|
|
Preservation(Preserve) {}
|
|
|
|
constexpr Contract(const Kind &Target,
|
|
size_t PipeArgumentTargetIndex = 0,
|
|
InputPreservation::Values Preserve = Erase) :
|
|
Source(nullptr),
|
|
TargetKind(&Target),
|
|
PipeArgumentSourceIndex(0),
|
|
PipeArgumentTargetIndex(PipeArgumentSourceIndex),
|
|
Preservation(Preserve) {}
|
|
|
|
public:
|
|
void deduceResults(const Context &Context,
|
|
ContainerToTargetsMap &StepStatus,
|
|
llvm::ArrayRef<std::string> ContainerNames,
|
|
bool ForInvalidation = false) const;
|
|
|
|
void deduceResults(const Context &Context,
|
|
ContainerToTargetsMap &StepStatus,
|
|
TargetsList &Results,
|
|
llvm::ArrayRef<std::string> ContainerNames) const;
|
|
|
|
void deduceResults(const Context &Context,
|
|
ContainerToTargetsMap &StepStatus,
|
|
ContainerToTargetsMap &Results,
|
|
llvm::ArrayRef<std::string> ContainerNames) const;
|
|
|
|
ContainerToTargetsMap
|
|
deduceRequirements(const Context &Context,
|
|
const ContainerToTargetsMap &PipeOutput,
|
|
llvm::ArrayRef<std::string> ContainerNames) const;
|
|
|
|
bool forwardMatches(const ContainerToTargetsMap &Status,
|
|
llvm::ArrayRef<std::string> ContainerNames) const;
|
|
bool backwardMatches(const ContainerToTargetsMap &Status,
|
|
llvm::ArrayRef<std::string> ContainerNames) const;
|
|
|
|
void insertDefaultInput(const Context &Context,
|
|
ContainerToTargetsMap &Status,
|
|
llvm::ArrayRef<std::string> ContainerNames) const;
|
|
|
|
std::pair<size_t, const Kind *> getOutput() const;
|
|
|
|
private:
|
|
TargetsList forward(const Context &Context, TargetsList Input) const;
|
|
TargetsList backward(const Context &Context, TargetsList Output) const;
|
|
bool forwardMatches(const TargetsList &Input) const;
|
|
|
|
bool backwardMatchesImpl(const TargetsList &List) const;
|
|
|
|
/// Target is the container in which the Pipe would write when used to produce
|
|
/// the targets.
|
|
void deduceRequirements(const Context &Context,
|
|
TargetsList &SourceContainer,
|
|
TargetsList &TargetContainer) const;
|
|
};
|
|
|
|
/// A group contract is the way contracts can be composed.
|
|
/// All subcontracts inside a group contract are evaluated in parallel on the
|
|
/// same input and their output is merged.
|
|
class ContractGroup {
|
|
public:
|
|
static constexpr auto Erase = InputPreservation::Erase;
|
|
|
|
private:
|
|
llvm::SmallVector<Contract, 2> Content;
|
|
|
|
public:
|
|
ContractGroup(std::initializer_list<Contract> Content) :
|
|
Content(std::move(Content)) {}
|
|
|
|
ContractGroup(llvm::SmallVector<Contract, 2> Content) :
|
|
Content(std::move(Content)) {}
|
|
|
|
ContractGroup(llvm::ArrayRef<ContractGroup> Contracts) {
|
|
for (const auto &C : Contracts)
|
|
for (const auto &Entry : C.Content)
|
|
Content.push_back(Entry);
|
|
}
|
|
|
|
ContractGroup(const Kind &Source,
|
|
size_t PipeArgumentSourceIndex,
|
|
const Kind &Target,
|
|
size_t PipeArgumentTargetIndex = 0,
|
|
InputPreservation::Values Preservation = Erase) :
|
|
Content({ Contract(Source,
|
|
PipeArgumentSourceIndex,
|
|
Target,
|
|
PipeArgumentTargetIndex,
|
|
Preservation) }) {}
|
|
|
|
ContractGroup(const Kind &Source,
|
|
size_t PipeArgumentSourceIndex = 0,
|
|
InputPreservation::Values Preservation = Erase) :
|
|
Content({ Contract(Source, PipeArgumentSourceIndex, Preservation) }) {}
|
|
|
|
static ContractGroup
|
|
transformOnlyArgument(const Kind &Source,
|
|
const Kind &Target,
|
|
InputPreservation::Values Preservation) {
|
|
return ContractGroup(Source, 0, Target, 0, Preservation);
|
|
}
|
|
|
|
public:
|
|
[[nodiscard]] ContainerToTargetsMap
|
|
deduceRequirements(const Context &Context,
|
|
const ContainerToTargetsMap &StepStatus,
|
|
llvm::ArrayRef<std::string> ContainerNames) const;
|
|
void deduceResults(const Context &Context,
|
|
ContainerToTargetsMap &StepStatus,
|
|
llvm::ArrayRef<std::string> ContainerNames,
|
|
bool ForInvalidation = false) const;
|
|
|
|
bool forwardMatches(const ContainerToTargetsMap &Status,
|
|
llvm::ArrayRef<std::string> ContainerNames,
|
|
bool ForInvalidation = false) const;
|
|
bool backwardMatches(const ContainerToTargetsMap &Status,
|
|
llvm::ArrayRef<std::string> ContainerNames) const;
|
|
|
|
llvm::SmallVector<std::pair<size_t, const Kind *>, 4> getOutputs() const;
|
|
};
|
|
|
|
} // namespace pipeline
|