blob: 3df6dd5f3aa317c733aa7b83adccb6b63b1f3e3c [file] [log] [blame]
//===--- DebugUtils.h - Utilities for debug-info instructions ---*- 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 file contains utilities to work with debug-info related instructions:
// debug_value and debug_value_addr.
//
// SIL optimizations should deal with debug-info related instructions when
// looking at the uses of a value.
// When performing an analysis, the usual thing is to just ignore all debug-info
// instructions.
// When transforming the SIL, a pass must decide what to do with debug-info
// instructions. Either delete them (if their value is no longer available),
// keep them (if the transformation has no effect on debug-info values) or
// update them.
//
// To ignore debug-info instructions during an analysis, this file provides
// some utility functions, which can be used instead of the relevant member
// functions in ValueBase and SILValue:
//
// V->use_empty() -> onlyHaveDebugUses(V)
// V.hasOneUse() -> hasOneNonDebugUse(V)
// V.getUses() -> getNonDebugUses(V)
// I->eraseFromParent() -> eraseFromParentWithDebugInsts(I)
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_DEBUGUTILS_H
#define SWIFT_SIL_DEBUGUTILS_H
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILInstruction.h"
namespace swift {
class SILInstruction;
/// Returns true if the instruction \p Inst is an instruction which is only
/// relevant for debug information and has no other impact on program semantics.
inline bool isDebugInst(SILInstruction *Inst) {
return isa<DebugValueInst>(Inst) || isa<DebugValueAddrInst>(Inst);
}
/// Deletes all of the debug instructions that use \p Inst.
inline void deleteAllDebugUses(ValueBase *Inst) {
for (auto UI = Inst->use_begin(), E = Inst->use_end(); UI != E;) {
auto *Inst = UI->getUser();
UI++;
if (isDebugInst(Inst))
Inst->eraseFromParent();
}
}
/// This iterator filters out any debug (or non-debug) instructions from a range
/// of uses, provided by the underlying ValueBaseUseIterator.
/// If \p nonDebugInsts is true, then the iterator provides a view to all non-
/// debug instructions. Otherwise it provides a view ot all debug-instructions.
template <bool nonDebugInsts> class DebugUseIterator
: public std::iterator<std::forward_iterator_tag, Operand *, ptrdiff_t> {
ValueBaseUseIterator BaseIterator;
// Skip any debug or non-debug instructions (depending on the nonDebugInsts
// template argument).
void skipInsts() {
while (true) {
if (*BaseIterator == nullptr)
return;
SILInstruction *User = BaseIterator->getUser();
if (isDebugInst(User) != nonDebugInsts)
return;
BaseIterator++;
}
}
public:
DebugUseIterator(ValueBaseUseIterator BaseIterator) :
BaseIterator(BaseIterator) {
skipInsts();
}
DebugUseIterator() = default;
Operand *operator*() const { return *BaseIterator; }
Operand *operator->() const { return *BaseIterator; }
SILInstruction *getUser() const { return BaseIterator.getUser(); }
DebugUseIterator &operator++() {
BaseIterator++;
skipInsts();
return *this;
}
DebugUseIterator operator++(int unused) {
DebugUseIterator Copy = *this;
++*this;
return Copy;
}
friend bool operator==(DebugUseIterator lhs,
DebugUseIterator rhs) {
return lhs.BaseIterator == rhs.BaseIterator;
}
friend bool operator!=(DebugUseIterator lhs,
DebugUseIterator rhs) {
return !(lhs == rhs);
}
};
/// Iterator for iteration over debug instructions.
using DUIterator = DebugUseIterator<false>;
/// Iterator for iteration over non-debug instructions.
using NonDUIterator = DebugUseIterator<true>;
/// Returns a range of all debug instructions in the uses of a value (e.g.
/// SILValue or SILInstruction).
inline iterator_range<DUIterator> getDebugUses(SILValue V) {
return make_range(DUIterator(V->use_begin()), DUIterator(V->use_end()));
}
/// Returns a range of all non-debug instructions in the uses of a value (e.g.
/// SILValue or SILInstruction).
inline iterator_range<NonDUIterator> getNonDebugUses(SILValue V) {
return make_range(NonDUIterator(V->use_begin()), NonDUIterator(V->use_end()));
}
/// Returns true if a value (e.g. SILInstruction) has no uses except debug
/// instructions.
inline bool onlyHaveDebugUses(SILValue V) {
auto NonDebugUses = getNonDebugUses(V);
return NonDebugUses.begin() == NonDebugUses.end();
}
/// Return true if all of the results of the given instruction have no uses
/// except debug instructions.
inline bool onlyHaveDebugUsesOfAllResults(SILInstruction *I) {
for (auto result : I->getResults()) {
if (!onlyHaveDebugUses(result))
return false;
}
return true;
}
/// Returns true if a value (e.g. SILInstruction) has exactly one use which is
/// not a debug instruction.
inline bool hasOneNonDebugUse(SILValue V) {
auto Range = getNonDebugUses(V);
auto I = Range.begin(), E = Range.end();
if (I == E) return false;
return ++I == E;
}
// Returns the use if the value has only one non debug user.
inline SILInstruction *getSingleNonDebugUser(SILValue V) {
auto Range = getNonDebugUses(V);
auto I = Range.begin(), E = Range.end();
if (I == E) return nullptr;
if (std::next(I) != E)
return nullptr;
return I->getUser();
}
/// Erases the instruction \p I from it's parent block and deletes it, including
/// all debug instructions which use \p I.
/// Precondition: The instruction may only have debug instructions as uses.
/// If the iterator \p InstIter references any deleted debug instruction, it is
/// incremented.
inline void eraseFromParentWithDebugInsts(SILInstruction *I,
SILBasicBlock::iterator &InstIter) {
auto results = I->getResults();
bool foundAny;
do {
foundAny = false;
for (auto result : results) {
while (!result->use_empty()) {
foundAny = true;
auto *User = result->use_begin()->getUser();
assert(isDebugInst(User));
if (InstIter != SILBasicBlock::iterator() &&
InstIter != I->getParent()->end() &&
&*InstIter == User) {
InstIter++;
}
User->eraseFromParent();
}
}
} while (foundAny);
I->eraseFromParent();
}
/// Erases the instruction \p I from it's parent block and deletes it, including
/// all debug instructions which use \p I.
/// Precondition: The instruction may only have debug instructions as uses.
inline void eraseFromParentWithDebugInsts(SILInstruction *I) {
SILBasicBlock::iterator nullIter;
eraseFromParentWithDebugInsts(I, nullIter);
}
} // end namespace swift
#endif /* SWIFT_SIL_DEBUGUTILS_H */