mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
There are a bunch of optimizations in SILCombine where we try to fold an ownership forwarding instruction A into another ownership forwarding instruction B without deleting A. Consider the upcasts in the example below: ``` %0 = upcast %x : $X->Y %1 = upcast %0 : $Y->Z ``` These sorts of optimizations fold the first instruction into the second like so: ``` %0 = upcast %x : $X->Y %1 = upcast %x : $X->Z ``` This creates a problem when we are dealing with owned values since we have just introduced two consumes for %x. To work around this, we have two options: 1. Introduce extra copies. 2. We recognize the situations where we can guarantee that we can delete the first upcast. The first choice I believe is not a choice since breaking a forwarding chain of ownership in favor of extra copies is a less canonical form. That leaves us with the second form. What are the necessary/sufficient conditions for deleting the first upcast. Simply it is that the upcast cannot have any non-debug, non-consuming uses! In such a case, we know that along all paths through the program the value has exactly one non-debug use, one of its consuming uses. If when optimizing upcasts we could recognize that pattern, duplicate the inst along paths not through our 2nd upcast and thus delete the original upcast fixing the ownership error! While this is all nice and good there is a problem with this: it doesn't scale. As I was writing a few optimizations like this I began to note that I had to write different versions of this same helper for many of the visitors (they generally varied by how many forwarding instructions they looked through). As I pondered the above, I chatted a bit with @atrick and during our conversation, we both realized that it is much easier to solve this problem in one block and that the condition above would allow us to sink these instructiosn into the same block and thus if we could check for this condition and canonicialize the IR to sink these instructions before we visiting, we could use a single helper to handle all of these cases.
49 lines
1.6 KiB
C++
49 lines
1.6 KiB
C++
//===--- DebugOptUtils.h --------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2020 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// Debug Info related utilities that rely on code in SILOptimizer/ and thus can
|
|
/// not be in include/swift/SIL/DebugUtils.h.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SILOPTIMIZER_DEBUGOPTUTILS_H
|
|
#define SWIFT_SILOPTIMIZER_DEBUGOPTUTILS_H
|
|
|
|
#include "swift/SIL/DebugUtils.h"
|
|
#include "swift/SIL/SILValue.h"
|
|
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
|
|
|
|
namespace swift {
|
|
|
|
/// Deletes all of the debug instructions that use \p value.
|
|
inline void deleteAllDebugUses(SILValue value, InstModCallbacks &callbacks) {
|
|
for (auto ui = value->use_begin(), ue = value->use_end(); ui != ue;) {
|
|
auto *inst = ui->getUser();
|
|
++ui;
|
|
if (inst->isDebugInstruction()) {
|
|
callbacks.deleteInst(inst);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Deletes all of the debug uses of any result of \p inst.
|
|
inline void deleteAllDebugUses(SILInstruction *inst,
|
|
InstModCallbacks &callbacks) {
|
|
for (SILValue v : inst->getResults()) {
|
|
deleteAllDebugUses(v, callbacks);
|
|
}
|
|
}
|
|
|
|
} // namespace swift
|
|
|
|
#endif
|