Files
swift-mirror/include/swift/SILOptimizer/Utils/ConstExpr.h
Josh Soref 730b16c569 Spelling siloptimizer
* access
* accessed
* accesses
* accessor
* acquiring
* across
* activated
* additive
* address
* addresses'
* aggregated
* analysis
* and
* appropriately
* archetype
* argument
* associated
* availability
* barriers
* because
* been
* beginning
* belongs
* beneficial
* blocks
* borrow
* builtin
* cannot
* canonical
* canonicalize
* clazz
* cleanup
* coalesceable
* coalesced
* comparisons
* completely
* component
* computed
* concrete
* conjunction
* conservatively
* constituent
* construct
* consuming
* containing
* covered
* creates
* critical
* dataflow
* declaration
* defined
* defining
* definition
* deinitialization
* deliberately
* dependencies
* dependent
* deserialized
* destroy
* deterministic
* deterministically
* devirtualizes
* diagnostic
* diagnostics
* differentiation
* disable
* discipline
* dominate
* dominates
* don't
* element
* eliminate
* eliminating
* elimination
* embedded
* encounter
* epilogue
* epsilon
* escape
* escaping
* essential
* evaluating
* evaluation
* evaluator
* executing
* existential
* existentials
* explicit
* expression
* extended
* extension
* extract
* for
* from
* function
* generic
* guarantee
* guaranteed
* happened
* heuristic
* however
* identifiable
* immediately
* implementation
* improper
* include
* infinite
* initialize
* initialized
* initializer
* inside
* instruction
* interference
* interferes
* interleaved
* internal
* intersection
* intractable
* intrinsic
* invalidates
* irreducible
* irrelevant
* language
* lifetime
* literal
* looks
* materialize
* meaning
* mergeable
* might
* mimics
* modification
* modifies
* multiple
* mutating
* necessarily
* necessary
* needsmultiplecopies
* nonetheless
* nothing
* occurred
* occurs
* optimization
* optimizing
* original
* outside
* overflow
* overlapping
* overridden
* owned
* ownership
* parallel
* parameter
* paths
* patterns
* pipeline
* plottable
* possible
* potentially
* practically
* preamble
* precede
* preceding
* predecessor
* preferable
* preparation
* probably
* projection
* properties
* property
* protocol
* reabstraction
* reachable
* recognized
* recursive
* recursively
* redundant
* reentrancy
* referenced
* registry
* reinitialization
* reload
* represent
* requires
* response
* responsible
* retrieving
* returned
* returning
* returns
* rewriting
* rewritten
* sample
* scenarios
* scope
* should
* sideeffects
* similar
* simplify
* simplifycfg
* somewhat
* spaghetti
* specialization
* specializations
* specialized
* specially
* statistically
* substitute
* substitution
* succeeds
* successful
* successfully
* successor
* superfluous
* surprisingly
* suspension
* swift
* targeted
* that
* that our
* the
* therefore
* this
* those
* threshold
* through
* transform
* transformation
* truncated
* ultimate
* unchecked
* uninitialized
* unlikely
* unmanaged
* unoptimized key
* updataflow
* usefulness
* utilities
* villain
* whenever
* writes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2022-10-03 18:31:33 -04:00

231 lines
9.7 KiB
C++

//===--- ConstExpr.h - Constant expression evaluator -----------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
// This defines an interface to evaluate Swift language level constant
// expressions. Its model is intended to be general and reasonably powerful,
// with the goal of standardization in a future version of Swift.
//
// Constant expressions are functions without side effects that take constant
// values and return constant values. These constants may be integer, and
// floating point values. We allow abstractions to be built out of fragile
// structs and tuples.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILOPTIMIZER_CONSTEXPR_H
#define SWIFT_SILOPTIMIZER_CONSTEXPR_H
#include "swift/Basic/LLVM.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/SIL/ApplySite.h"
#include "swift/SIL/SILBasicBlock.h"
#include "llvm/ADT/SmallPtrSet.h"
namespace swift {
class ASTContext;
class Operand;
class SILFunction;
class SILModule;
class SILNode;
class SymbolicValue;
class SymbolicValueAllocator;
class ConstExprFunctionState;
class UnknownReason;
/// This class is the main entrypoint for evaluating constant expressions. It
/// also handles caching of previously computed constexpr results.
class ConstExprEvaluator {
SymbolicValueAllocator &allocator;
// Assert configuration that must be used by the evaluator. This determines
// the result of the builtin "assert_configuration".
unsigned assertConfig;
/// The current call stack, used for providing accurate diagnostics.
llvm::SmallVector<SourceLoc, 4> callStack;
/// When set to true, keep track of all functions called during an evaluation.
bool trackCallees;
/// Functions called during the evaluation. This is an auxiliary information
/// provided to the clients.
llvm::SmallPtrSet<SILFunction *, 2> calledFunctions;
void operator=(const ConstExprEvaluator &) = delete;
public:
explicit ConstExprEvaluator(SymbolicValueAllocator &alloc,
unsigned assertConf, bool trackCallees = false);
~ConstExprEvaluator();
explicit ConstExprEvaluator(const ConstExprEvaluator &other);
SymbolicValueAllocator &getAllocator() { return allocator; }
unsigned getAssertConfig() { return assertConfig; }
void pushCallStack(SourceLoc loc) { callStack.push_back(loc); }
void popCallStack() {
assert(!callStack.empty());
callStack.pop_back();
}
const llvm::SmallVector<SourceLoc, 4> &getCallStack() { return callStack; }
// As SymbolicValue::getUnknown(), but handles passing the call stack and
// allocator.
SymbolicValue getUnknown(SILNode *node, UnknownReason reason);
/// Analyze the specified values to determine if they are constant values.
/// This is done in code that is not necessarily itself a constexpr
/// function. The results are added to the results list which is a parallel
/// structure to the input values.
void computeConstantValues(ArrayRef<SILValue> values,
SmallVectorImpl<SymbolicValue> &results);
void recordCalledFunctionIfEnabled(SILFunction *callee) {
if (trackCallees) {
calledFunctions.insert(callee);
}
}
/// If the evaluator was initialized with \c trackCallees enabled, return the
/// SIL functions encountered during the evaluations performed with this
/// evaluator. The returned functions include those that were called but
/// failed to complete successfully.
const SmallPtrSetImpl<SILFunction *> &getFuncsCalledDuringEvaluation() const {
assert(trackCallees && "evaluator not configured to track callees");
return calledFunctions;
}
};
/// A constant-expression evaluator that can be used to step through a control
/// flow graph (SILFunction body) by evaluating one instruction at a time.
/// This evaluator can also "skip" instructions without evaluating them and
/// only track constant values of variables whose values could be computed.
class ConstExprStepEvaluator {
private:
ConstExprEvaluator evaluator;
ConstExprFunctionState *internalState;
unsigned stepsEvaluated = 0;
/// Targets of branches that were visited. This is used to detect loops during
/// evaluation.
SmallPtrSet<SILBasicBlock *, 8> visitedBlocks;
ConstExprStepEvaluator(const ConstExprStepEvaluator &) = delete;
void operator=(const ConstExprStepEvaluator &) = delete;
public:
/// Constructs a step evaluator given an allocator and a non-null pointer to a
/// SILFunction.
explicit ConstExprStepEvaluator(SymbolicValueAllocator &alloc,
SILFunction *fun, unsigned assertConf,
bool trackCallees = false);
~ConstExprStepEvaluator();
/// Evaluate an instruction in the current interpreter state.
/// \param instI instruction to be evaluated in the current interpreter state.
/// \returns a pair where the first and second elements are defined as
/// follows:
/// The first element is the iterator to the next instruction from where
/// the evaluation can continue, if the evaluation is successful.
/// Otherwise, it is None.
///
/// Second element is None, if the evaluation is successful.
/// Otherwise, is an unknown symbolic value that contains the error.
std::pair<Optional<SILBasicBlock::iterator>, Optional<SymbolicValue>>
evaluate(SILBasicBlock::iterator instI);
/// Skip the instruction without evaluating it and conservatively account for
/// the effects of the instruction on the internal state. This operation
/// resets to an unknown symbolic value any portion of a
/// SymbolicValueMemoryObject that could possibly be mutated by the given
/// instruction. This function preserves the soundness of the interpretation.
/// \param instI instruction to be skipped.
/// \returns a pair where the first and second elements are defined as
/// follows:
/// The first element, if is not None, is the iterator to the next
/// instruction from the where the evaluation must continue.
/// The first element is None if the next instruction from where the
/// evaluation must continue cannot be determined.
/// This would be the case if `instI` is a branch like a `condbr`.
///
/// Second element is None if skipping the instruction is successful.
/// Otherwise, it is an unknown symbolic value containing the error.
std::pair<Optional<SILBasicBlock::iterator>, Optional<SymbolicValue>>
skipByMakingEffectsNonConstant(SILBasicBlock::iterator instI);
/// Try evaluating an instruction and if the evaluation fails, skip the
/// instruction and make it effects non constant. Note that it may not always
/// be possible to skip an instruction whose evaluation failed and
/// continue evaluation (e.g. a conditional branch).
/// See `evaluate` and `skipByMakingEffectsNonConstant` functions for their
/// semantics.
/// \param instI instruction to be evaluated in the current interpreter state.
/// \returns a pair where the first and second elements are defined as
/// follows:
/// The first element, if is not None, is the iterator to the next
/// instruction from the where the evaluation must continue.
/// The first element is None iff both `evaluate` and `skip` functions
/// failed to determine the next instruction to continue evaluation from.
///
/// Second element is None if the evaluation is successful.
/// Otherwise, it is an unknown symbolic value containing the error.
std::pair<Optional<SILBasicBlock::iterator>, Optional<SymbolicValue>>
tryEvaluateOrElseMakeEffectsNonConstant(SILBasicBlock::iterator instI);
Optional<SymbolicValue> lookupConstValue(SILValue value);
/// Return the number of instructions evaluated for the last `evaluate`
/// operation. This could be used by the clients to limit the number of
/// instructions that should be evaluated by the step-wise evaluator.
/// Note that 'skipByMakingEffectsNonConstant' operation is not considered
/// as an evaluation.
unsigned instructionsEvaluatedByLastEvaluation() { return stepsEvaluated; }
/// If the evaluator was initialized with \c trackCallees enabled, return the
/// SIL functions encountered during the evaluations performed with this
/// evaluator. The returned functions include those that were called but
/// failed to complete successfully. Targets of skipped apply instructions
/// will not be included in the returned set.
const SmallPtrSetImpl<SILFunction *> &getFuncsCalledDuringEvaluation() {
return evaluator.getFuncsCalledDuringEvaluation();
}
/// Dump the internal state to standard error for debugging.
void dumpState();
};
bool hasConstantEvaluableAnnotation(SILFunction *fun);
bool isConstantEvaluable(SILFunction *fun);
/// Return true iff the \p applySite is constant-evaluable and read-only.
bool isReadOnlyConstantEvaluableCall(FullApplySite applySite);
/// Return true if and only if the given function \p fun is specially modeled
/// by the constant evaluator. These are typically functions in the standard
/// library, such as String.+=, Array.append, whose semantics is built into the
/// evaluator.
bool isKnownConstantEvaluableFunction(SILFunction *fun);
/// Return true if and only if \p errorVal denotes an error that requires
/// aborting interpretation and returning the error. Skipping an instruction
/// that produces such errors is not a valid behavior.
bool isFailStopError(SymbolicValue errorVal);
} // end namespace swift
#endif