Files
swift-mirror/lib/AST/RequirementMachine/RewriteSystem.h
Slava Pestov 156fa2cc04 RequirementMachine: Speed up term simplification with a prefix trie
Previously RewriteSystem::simplify() would attempt to apply every
rewrite rule at every position in the original term, which was
obviously a source of overhead.

The trie itself is somewhat unoptimized; for example, with a bit of
effort it could merge a node with its only child, if nodes stored
a range of elements to compare rather than a single element.
2021-08-05 21:42:50 -04:00

192 lines
5.5 KiB
C++

//===--- RewriteSystem.h - Generics with term rewriting ---------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_REWRITESYSTEM_H
#define SWIFT_REWRITESYSTEM_H
#include <algorithm>
#include "ProtocolGraph.h"
#include "Symbol.h"
#include "Term.h"
#include "Trie.h"
namespace llvm {
class raw_ostream;
}
namespace swift {
namespace rewriting {
class PropertyMap;
class RewriteContext;
/// A rewrite rule that replaces occurrences of LHS with RHS.
///
/// LHS must be greater than RHS in the linear order over terms.
///
/// Out-of-line methods are documented in RewriteSystem.cpp.
class Rule final {
Term LHS;
Term RHS;
bool deleted;
public:
Rule(Term lhs, Term rhs)
: LHS(lhs), RHS(rhs), deleted(false) {}
const Term &getLHS() const { return LHS; }
const Term &getRHS() const { return RHS; }
OverlapKind checkForOverlap(const Rule &other,
MutableTerm &t,
MutableTerm &v) const {
return LHS.checkForOverlap(other.LHS, t, v);
}
bool canReduceLeftHandSide(const Rule &other) const {
return LHS.containsSubTerm(other.LHS);
}
/// Returns if the rule was deleted.
bool isDeleted() const {
return deleted;
}
/// Deletes the rule, which removes it from consideration in term
/// simplification and completion. Deleted rules are simply marked as
/// such instead of being physically removed from the rules vector
/// in the rewrite system, to ensure that indices remain valid across
/// deletion.
void markDeleted() {
assert(!deleted);
deleted = true;
}
/// Returns the length of the left hand side.
unsigned getDepth() const {
return LHS.size();
}
void dump(llvm::raw_ostream &out) const;
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &out,
const Rule &rule) {
rule.dump(out);
return out;
}
};
/// A term rewrite system for working with types in a generic signature.
///
/// Out-of-line methods are documented in RewriteSystem.cpp.
class RewriteSystem final {
/// Rewrite context for memory allocation.
RewriteContext &Context;
/// The rules added so far, including rules from our client, as well
/// as rules introduced by the completion procedure.
std::vector<Rule> Rules;
/// A prefix trie of rule left hand sides to optimize lookup.
Trie RuleTrie;
/// The graph of all protocols transitively referenced via our set of
/// rewrite rules, used for the linear order on symbols.
ProtocolGraph Protos;
/// A list of pending terms for the associated type merging completion
/// heuristic.
///
/// The pair (lhs, rhs) satisfies the following conditions:
/// - lhs > rhs
/// - all symbols but the last are pair-wise equal in lhs and rhs
/// - the last symbol in both lhs and rhs is an associated type symbol
/// - the last symbol in both lhs and rhs has the same name
///
/// See RewriteSystem::processMergedAssociatedTypes() for details.
std::vector<std::pair<MutableTerm, MutableTerm>> MergedAssociatedTypes;
/// A list of pending pairs for checking overlap in the completion
/// procedure.
std::deque<std::pair<unsigned, unsigned>> Worklist;
/// Set these to true to enable debugging output.
unsigned DebugSimplify : 1;
unsigned DebugAdd : 1;
unsigned DebugMerge : 1;
unsigned DebugCompletion : 1;
public:
explicit RewriteSystem(RewriteContext &ctx);
~RewriteSystem();
RewriteSystem(const RewriteSystem &) = delete;
RewriteSystem(RewriteSystem &&) = delete;
RewriteSystem &operator=(const RewriteSystem &) = delete;
RewriteSystem &operator=(RewriteSystem &&) = delete;
/// Return the rewrite context used for allocating memory.
RewriteContext &getRewriteContext() const { return Context; }
/// Return the object recording information about known protocols.
const ProtocolGraph &getProtocols() const { return Protos; }
void initialize(std::vector<std::pair<MutableTerm, MutableTerm>> &&rules,
ProtocolGraph &&protos);
Symbol simplifySubstitutionsInSuperclassOrConcreteSymbol(Symbol symbol) const;
bool addRule(MutableTerm lhs, MutableTerm rhs);
bool simplify(MutableTerm &term) const;
enum class CompletionResult {
/// Confluent completion was computed successfully.
Success,
/// Maximum number of iterations reached.
MaxIterations,
/// Completion produced a rewrite rule whose left hand side has a length
/// exceeding the limit.
MaxDepth
};
std::pair<CompletionResult, unsigned>
computeConfluentCompletion(unsigned maxIterations,
unsigned maxDepth);
void simplifyRightHandSides();
std::pair<CompletionResult, unsigned>
buildPropertyMap(PropertyMap &map,
unsigned maxIterations,
unsigned maxDepth);
void dump(llvm::raw_ostream &out) const;
private:
Optional<std::pair<MutableTerm, MutableTerm>>
computeCriticalPair(const Rule &lhs, const Rule &rhs) const;
Symbol mergeAssociatedTypes(Symbol lhs, Symbol rhs) const;
void processMergedAssociatedTypes();
};
} // end namespace rewriting
} // end namespace swift
#endif