Files
swift-mirror/include/swift/SIL/BitDataflow.h
T
Michael Gottesman 8943dff0ee [gardening] Modernize BitDataflow debug printing to use print+dump pattern
NFC. Just peeling off small things from a alrger commit.

Replace the standalone dump() method with a print(llvm::raw_ostream &os)
method that writes to an arbitrary output stream, and implement dump() via
the SWIFT_DEBUG_DUMP macro delegating to print(llvm::dbgs()). Also fix a
minor indentation issue in the original dump() body and switch the loop
variable to a const reference.

This follows the standard Swift/SIL convention for debug-printable types,
making BitDataflow consistent with the rest of the codebase and allowing
its state to be printed to streams other than stderr.
2026-02-21 15:33:44 -08:00

149 lines
4.5 KiB
C++

//===--- BitDataflow.h ------------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 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
//
//===----------------------------------------------------------------------===//
///
/// \file Contains the BitDataflow utility for performing bit-wise dataflow
/// analysis on a SILFunction.
///
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_BIT_DATAFLOW_H
#define SWIFT_SIL_BIT_DATAFLOW_H
#include "swift/SIL/BasicBlockData.h"
#include "llvm/ADT/SmallBitVector.h"
namespace swift {
class SILFunction;
/// A utility to calculate forward or backward dataflow of bit sets on a
/// SILFunction.
class BitDataflow {
/// What kind of terminators can be reached from a block.
enum class ExitReachability : uint8_t {
/// Worst case: the block is part of a cycle which neither reaches a
/// function-exit nor an unreachable-instruction.
InInfiniteLoop,
/// An unreachable-instruction can be reached from the block, but not a
/// function-exit (like "return" or "throw").
ReachesUnreachable,
/// A function-exit can be reached from the block.
/// This is the case for most basic blocks.
ReachesExit
};
public:
using Bits = llvm::SmallBitVector;
/// Basic-block specific information used for dataflow analysis.
struct BlockState {
/// The bits valid at the entry (i.e. the first instruction) of the block.
Bits entrySet;
/// The bits valid at the exit (i.e. after the terminator) of the block.
Bits exitSet;
/// Generated bits of the block.
Bits genSet;
/// Killed bits of the block.
Bits killSet;
/// True, if this block is reachable from the entry block, i.e. is not an
/// unreachable block.
///
/// This flag is only computed if entryReachabilityAnalysis is called.
bool reachableFromEntry = false;
/// What kind of terminators can be reached from this block.
///
/// This is only computed if exitReachableAnalysis is called.
ExitReachability exitReachability = ExitReachability::InInfiniteLoop;
BlockState(unsigned numLocations) :
entrySet(numLocations), exitSet(numLocations),
genSet(numLocations), killSet(numLocations) {}
bool exitReachable() const {
return exitReachability == ExitReachability::ReachesExit;
}
bool isInInfiniteLoop() const {
return exitReachability == ExitReachability::InInfiniteLoop;
}
};
private:
BasicBlockData<BlockState> blockStates;
public:
using iterator = BasicBlockData<BlockState>::iterator;
/// Sets up the BlockState datastructures and associates all basic blocks with
/// a state.
BitDataflow(SILFunction *function, unsigned numLocations);
BitDataflow(const BitDataflow &) = delete;
BitDataflow &operator=(const BitDataflow &) = delete;
iterator begin() { return blockStates.begin(); }
iterator end() { return blockStates.end(); }
/// Returns the state of a block.
BlockState &operator[] (SILBasicBlock *block) {
return blockStates[block];
}
/// Calculates the BlockState::reachableFromEntry flags.
void entryReachabilityAnalysis();
/// Calculates the BlockState::exitReachable flags.
void exitReachableAnalysis();
using JoinOperation = std::function<void (Bits &dest, const Bits &src)>;
/// Derives the block exit sets from the entry sets by applying the gen and
/// kill sets.
/// At control flow joins, the \p join operation is applied.
void solveForward(JoinOperation join);
/// Calls solveForward() with a bit-intersection as join operation.
void solveForwardWithIntersect();
/// Calls solveForward() with a bit-union as join operation.
void solveForwardWithUnion();
/// Derives the block entry sets from the exit sets by applying the gen and
/// kill sets.
/// At control flow joins, the \p join operation is applied.
void solveBackward(JoinOperation join);
/// Calls solveBackward() with a bit-intersection as join operation.
void solveBackwardWithIntersect();
/// Calls solveBackward() with a bit-union as join operation.
void solveBackwardWithUnion();
/// Debug dump the BitDataflow state.
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
void print(llvm::raw_ostream &os) const;
};
} // end swift namespace
#endif