blob: 13e2532c75a3bea646be23d8af5562ab5b25381b [file] [log] [blame]
//===--- CFG.h - Utilities for SIL CFG transformations ----------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILOPTIMIZER_UTILS_CFG_H
#define SWIFT_SILOPTIMIZER_UTILS_CFG_H
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILBuilder.h"
namespace swift {
class DominanceInfo;
class SILLoop;
class SILLoopInfo;
/// Adds a new argument to an edge between a branch and a destination
/// block.
///
/// \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);
/// 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);
/// 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);
/// 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 *T, unsigned EdgeIdx,
DominanceInfo *DT = nullptr,
SILLoopInfo *LI = 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 *DT = nullptr,
SILLoopInfo *LI = nullptr);
/// Splits all critical edges originating from `fromBB`.
bool splitCriticalEdgesFrom(SILBasicBlock *fromBB, DominanceInfo *DT = nullptr,
SILLoopInfo *LI = nullptr);
/// Splits the edges between two basic blocks.
///
/// Updates dominance information and loop information if not null.
void splitEdgesFromTo(SILBasicBlock *From, SILBasicBlock *To,
DominanceInfo *DT = nullptr, SILLoopInfo *LI = nullptr);
/// Rotate a loop's header as long as it is exiting and not equal to the
/// passed basic block.
/// If \p RotateSingleBlockLoops is true a single basic block loop will be
/// rotated once. ShouldVerify specifies whether to perform verification after
/// the transformation.
/// Returns true if the loop could be rotated.
bool rotateLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI,
bool RotateSingleBlockLoops, SILBasicBlock *UpTo,
bool ShouldVerify);
/// Splits the basic block before the instruction with an unconditional
/// branch and updates the dominator tree and loop info.
SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &B,
SILInstruction *SplitBeforeInst,
DominanceInfo *DT, SILLoopInfo *LI);
/// 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 *DT, SILLoopInfo *LI);
/// 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 *DT,
SILLoopInfo *LI);
/// 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 *DT,
SILLoopInfo *LI);
/// 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);
/// Given a list of \p UserBlocks and a list of \p DefBlocks, find a set of
/// blocks that together with \p UserBlocks joint-postdominate \p
/// DefBlocks. This is in a sense finding a set of blocks that "complete" \p
/// UserBlocks with respect to \p DefBlocks. As an example, for the following
/// CFG:
///
/// +-----+
/// | Def |
/// +-----+
/// | |
/// v v
/// +-----+ +-----+
/// | | | Use |
/// +-----+ +-----+
///
/// the completion of the joint post-dominance set would be the empty
/// block. This has two main uses:
///
/// 1. This can tell you the places where if you were to sink the Def one would
/// need to insert "compensating code".
///
/// 2. It can be used to prove ownership correctness of @owned values by
/// asserting that the set of UserBlocks has an empty completion, implying they
/// jointly-post dominate the def.
///
/// *NOTE* This completion may not be unique.
void completeJointPostDominanceSet(
ArrayRef<SILBasicBlock *> UserBlocks, ArrayRef<SILBasicBlock *> DefBlocks,
llvm::SmallVectorImpl<SILBasicBlock *> &Completion);
/// Remove all unreachable blocks in a function.
bool removeUnreachableBlocks(SILFunction &Fn);
} // end namespace swift
#endif