mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
The reason why I am doing this is that right now SelectionDAG seems to sink certain llvm.dbg.addr to the end of block. By breaking the block, we ensure that we initialize the debug value of values early enough. NOTE: We are relying on code at -Onone not eliminating control flow which it does not today. A few additional notes: 1. I also fixed a small issue where I was not setting the proper debug scope for reinit debug_values. This came up when I was writing test cases for this commit. So I just fixed it at the same time. 2. Since I am splitting blocks and I don't want to invalidate dominators/etc at this point in the pipeline, I took advantage of the APIs ability to update dominators/loopinfo at the same time. 3. I also expanded the tests in tree further by adding debug info tests for the reinit copyable/addressonly cases in the multi-block case.
223 lines
9.8 KiB
C++
223 lines
9.8 KiB
C++
//===--- CFGOptUtils.h - SIL CFG edge utilities -----------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2019 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// APIs used by the SILOptimizer for low-level branch and CFG edge analysis
|
|
/// and operations. These may merge blocks, split blocks, or create empty
|
|
/// blocks, but don't duplicate whole blocks.
|
|
///
|
|
/// Essential CFG utilities are in SIL/CFG.h.
|
|
///
|
|
/// Whole block-level transformations are in BasicBlockOptUtils.h.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SILOPTIMIZER_UTILS_CFGOPTUTILS_H
|
|
#define SWIFT_SILOPTIMIZER_UTILS_CFGOPTUTILS_H
|
|
|
|
#include "swift/SIL/SILBuilder.h"
|
|
#include "swift/SIL/SILInstruction.h"
|
|
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
|
|
|
|
namespace llvm {
|
|
template <typename T> class TinyPtrVector;
|
|
}
|
|
|
|
namespace swift {
|
|
|
|
class DominanceInfo;
|
|
class SILLoop;
|
|
class SILLoopInfo;
|
|
struct InstModCallbacks;
|
|
|
|
/// Adds a new argument to an edge between a branch and a destination
|
|
/// block. Allows for user injected callbacks via \p callbacks.
|
|
///
|
|
/// \param branch The terminator to add the argument to.
|
|
/// \param dest The destination block of the edge.
|
|
/// \param val The value to the arguments of the branch.
|
|
/// \return The created branch. The old branch is deleted.
|
|
/// The argument is appended at the end of the argument tuple.
|
|
TermInst *addNewEdgeValueToBranch(TermInst *branch, SILBasicBlock *dest,
|
|
SILValue val, InstructionDeleter &deleter);
|
|
|
|
/// Changes the edge value between a branch and destination basic block
|
|
/// at the specified index. Changes all edges from \p Branch to \p Dest to carry
|
|
/// the value.
|
|
///
|
|
/// \param branch The branch to modify.
|
|
/// \param dest The destination of the edge.
|
|
/// \param idx The index of the argument to modify.
|
|
/// \param val The new value to use.
|
|
/// \return The new branch. Deletes the old one.
|
|
TermInst *changeEdgeValue(TermInst *branch, SILBasicBlock *dest, size_t idx,
|
|
SILValue val);
|
|
|
|
/// Deletes the edge value between a branch and a destination basic block at the
|
|
/// specified index. Asserts internally that the argument along the edge does
|
|
/// not have uses.
|
|
TermInst *deleteEdgeValue(TermInst *branch, SILBasicBlock *destBlock,
|
|
size_t argIndex);
|
|
|
|
/// Erase the \p argIndex phi argument from \p block. Asserts that the argument
|
|
/// is a /real/ phi argument. Removes all incoming values for the argument from
|
|
/// predecessor terminators. Asserts internally that it only ever is given
|
|
/// "true" phi argument.
|
|
void erasePhiArgument(SILBasicBlock *block, unsigned argIndex);
|
|
|
|
/// Replace a branch target.
|
|
///
|
|
/// \param t The terminating instruction to modify.
|
|
/// \param oldDest The successor block that will be replaced.
|
|
/// \param newDest The new target block.
|
|
/// \param preserveArgs If set, preserve arguments on the replaced edge.
|
|
void replaceBranchTarget(TermInst *t, SILBasicBlock *oldDest,
|
|
SILBasicBlock *newDest, bool preserveArgs);
|
|
|
|
/// Check if the edge from the terminator is critical.
|
|
bool isCriticalEdge(TermInst *t, unsigned edgeIdx);
|
|
|
|
inline bool isNonCriticalEdge(SILBasicBlock *predBB, SILBasicBlock *succBB) {
|
|
return predBB->getSingleSuccessorBlock() == succBB
|
|
|| succBB->getSinglePredecessorBlock() == predBB;
|
|
}
|
|
|
|
/// Splits the edge from terminator if it is critical.
|
|
///
|
|
/// Updates dominance information and loop information if not null.
|
|
/// Returns the newly created basic block on success or nullptr otherwise (if
|
|
/// the edge was not critical).
|
|
SILBasicBlock *splitCriticalEdge(TermInst *, unsigned edgeIdx,
|
|
DominanceInfo *domInfo = nullptr,
|
|
SILLoopInfo *loopInfo = nullptr);
|
|
|
|
/// Splits the critical edges between from and to. This code assumes there is
|
|
/// exactly one edge between the two basic blocks. It will return the wrong
|
|
/// result if there are multiple edges and will assert if there are no edges in
|
|
/// between the two blocks.
|
|
///
|
|
/// Updates dominance information and loop information if not null.
|
|
SILBasicBlock *splitIfCriticalEdge(SILBasicBlock *from, SILBasicBlock *to,
|
|
DominanceInfo *domInfo = nullptr,
|
|
SILLoopInfo *loopInfo = nullptr);
|
|
|
|
/// Splits all critical edges originating from `fromBB`.
|
|
bool splitCriticalEdgesFrom(SILBasicBlock *fromBB,
|
|
DominanceInfo *domInfo = nullptr,
|
|
SILLoopInfo *loopInfo = nullptr);
|
|
|
|
/// Splits all critical edges that have `toBB` as a destination.
|
|
bool splitCriticalEdgesTo(SILBasicBlock *toBB, DominanceInfo *domInfo = nullptr,
|
|
SILLoopInfo *loopInfo = nullptr);
|
|
|
|
/// Splits the edges between two basic blocks.
|
|
///
|
|
/// Updates dominance information and loop information if not null.
|
|
void splitEdgesFromTo(SILBasicBlock *from, SILBasicBlock *to,
|
|
DominanceInfo *domInfo = nullptr,
|
|
SILLoopInfo *loopInfo = nullptr);
|
|
|
|
/// Create a basic block to serve as the target of a conditional branch, or
|
|
/// other terminator with multiple successors. This avoids introducing critical
|
|
/// edges when inserting conditional branches.
|
|
///
|
|
/// This is a lightweight helper that assumes no block arguments and does not
|
|
/// update dominators or loops. For more general functionality, just create the
|
|
/// conditional branch then call splitCriticalEdge to fix it up.
|
|
SILBasicBlock *createSplitBranchTarget(SILBasicBlock *targetBlock,
|
|
SILBuilder &builder,
|
|
SILLocation loc);
|
|
|
|
/// Splits the basic block before the instruction with an unconditional branch
|
|
/// and updates the dominator tree and loop info. Returns the new, branched to
|
|
/// block that contains the end of \p SplitBeforeInst's block.
|
|
SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &builder,
|
|
SILInstruction *splitBeforeInst,
|
|
DominanceInfo *domInfo,
|
|
SILLoopInfo *loopInfo);
|
|
|
|
/// A version of splitBasicBlockAndBranch that takes a SILBuilderContext instead
|
|
/// of a SILBuilder. We generally are trying to eliminate APIs that take in
|
|
/// SILBuilder directly since that can cause weird downstream mistakes around
|
|
/// debug info scopes. So this provides a better choice for engineers.
|
|
///
|
|
/// TODO: Migrate all callers of splitBasicBlockAndBranch to use this entry
|
|
/// point.
|
|
inline SILBasicBlock *splitBasicBlockAndBranch(SILBuilderContext &builderCtx,
|
|
SILInstruction *splitBeforeInst,
|
|
DominanceInfo *domInfo,
|
|
SILLoopInfo *loopInfo) {
|
|
// Make sure we have the right debug scope from split before inst.
|
|
SILBuilderWithScope builder(splitBeforeInst, builderCtx);
|
|
return splitBasicBlockAndBranch(builder, splitBeforeInst, domInfo, loopInfo);
|
|
}
|
|
|
|
/// Return true if the function has a critical edge, false otherwise.
|
|
bool hasCriticalEdges(SILFunction &f, bool onlyNonCondBr);
|
|
|
|
/// Split all critical edges in the given function, updating the
|
|
/// dominator tree and loop information if they are provided.
|
|
///
|
|
/// FIXME: This should never be called! Fix passes that create critical edges.
|
|
bool splitAllCriticalEdges(SILFunction &F, DominanceInfo *domInfo,
|
|
SILLoopInfo *loopInfo);
|
|
|
|
/// Split all cond_br critical edges with non-trivial arguments in the
|
|
/// function updating the dominator tree and loop information (if they are not
|
|
/// set to null).
|
|
///
|
|
/// A current invariant of Ownership SIL is that cond_br can only have critical
|
|
/// edges with non-trivial arguments. This simplifies computation.
|
|
bool splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &fn,
|
|
DominanceInfo *domInfo,
|
|
SILLoopInfo *loopInfo);
|
|
|
|
/// Merge a basic block ending in a branch with its successor
|
|
/// if possible. If dominance information or loop info is non null update it.
|
|
/// Return true if block was merged.
|
|
bool mergeBasicBlockWithSuccessor(SILBasicBlock *bb, DominanceInfo *domInfo,
|
|
SILLoopInfo *loopInfo);
|
|
|
|
/// Merge basic blocks in the given function by eliminating all unconditional
|
|
/// branches to single-predecessor branch targets.
|
|
///
|
|
/// During optimization, SimplifyCFG also handles this, but this is a basic
|
|
/// canonicalization after any pass that splits blocks, such as inlining. This
|
|
/// is not done on-the-fly after splitting blocks because merging is linear in
|
|
/// the number of instructions, so interleaved merging and splitting is
|
|
/// quadratic.
|
|
bool mergeBasicBlocks(SILFunction *f);
|
|
|
|
/// Return true if we conservatively find all bb's that are non-failure exit
|
|
/// basic blocks and place them in \p bbs. If we find something we don't
|
|
/// understand, bail.
|
|
///
|
|
/// A non-failure exit BB is defined as a BB that:
|
|
///
|
|
/// 1. Has a return terminator.
|
|
/// 2. unreachable + noreturn terminator sequence.
|
|
/// 3. has a throw terminator.
|
|
///
|
|
/// If we just have an unreachable without a noreturn call before it, we must
|
|
/// have a failure BB.
|
|
///
|
|
/// We use a TinyPtrVector since in most cases this will only return one
|
|
/// SILBasicBlock since non-failure noreturn functions should not occur often
|
|
/// implying in most cases this will be one element.
|
|
///
|
|
/// TODO:
|
|
bool findAllNonFailureExitBBs(SILFunction *f,
|
|
llvm::TinyPtrVector<SILBasicBlock *> &bbs);
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|