Files
swift-mirror/include/swift/SILOptimizer/Utils/SILInliner.h
Adrian Prantl 5ea2d13f5e Improve the performance of IRGenDebugInfo
This commit changes how inline information is stored in SILDebugScope
from a tree to a linear chain of inlined call sites (similar to what
LLVM is using). This makes creating inlined SILDebugScopes slightly
more expensive, but makes lowering SILDebugScopes into LLVM metadata
much faster because entire inlined-at chains can now be cached. This
means that SIL is no longer preserve the inlining history (i.e., ((a
was inlined into b) was inlined into c) is represented the same as (a
was inlined into (b was inlined into c)), but this information was not
used by anyone.

On my late 2012 i7 iMac, this saves about 4 seconds when compiling the
RelWithDebInfo x86_64 swift standard library — or 40% of IRGen time.

rdar://problem/28311051
2017-04-05 08:33:55 -07:00

127 lines
4.5 KiB
C++

//===--- SILInliner.h - Inlines SIL functions -------------------*- 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 defines the SILInliner class, used for inlining SIL functions into
// function application sites
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_SILINLINER_H
#define SWIFT_SIL_SILINLINER_H
#include "llvm/ADT/DenseMap.h"
#include "swift/SIL/TypeSubstCloner.h"
#include <functional>
namespace swift {
// For now Free is 0 and Expensive is 1. This can be changed in the future by
// adding more categories.
enum class InlineCost : unsigned {
Free = 0,
Expensive = 1
};
/// Return the 'cost' of one instruction. Instructions that are expected to
/// disappear at the LLVM IR level are assigned a cost of 'Free'.
InlineCost instructionInlineCost(SILInstruction &I);
class SILInliner : public TypeSubstCloner<SILInliner> {
public:
friend class SILVisitor<SILInliner>;
friend class SILCloner<SILInliner>;
enum class InlineKind {
MandatoryInline,
PerformanceInline
};
SILInliner(SILFunction &To, SILFunction &From, InlineKind IKind,
SubstitutionList ApplySubs,
SILOpenedArchetypesTracker &OpenedArchetypesTracker,
CloneCollector::CallbackType Callback = nullptr)
: TypeSubstCloner<SILInliner>(To, From, ApplySubs,
OpenedArchetypesTracker, true),
IKind(IKind), CalleeEntryBB(nullptr),
Callback(Callback) {
}
/// inlineFunction - This method inlines a callee function, assuming that it
/// is called with the given arguments, into the caller at a given instruction
/// (as specified by a basic block iterator), assuming that the instruction
/// corresponds semantically to an application of the function. It only
/// performs one step of inlining: it does not recursively inline functions
/// called by the callee.
///
/// Returns true on success or false if it is unable to inline the function
/// (for any reason). If successful, I now points to the first inlined
/// instruction, or the next instruction after the removed instruction in the
/// original function, in case the inlined function is completely trivial
bool inlineFunction(FullApplySite AI, ArrayRef<SILValue> Args);
private:
void visitDebugValueInst(DebugValueInst *Inst);
void visitDebugValueAddrInst(DebugValueAddrInst *Inst);
const SILDebugScope *getOrCreateInlineScope(const SILDebugScope *DS);
void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
// Call client-supplied callback function.
if (Callback)
Callback(Orig, Cloned);
// We just updated the debug scope information. Intentionally
// don't call SILClonerWithScopes<SILInliner>::postProcess().
SILCloner<SILInliner>::postProcess(Orig, Cloned);
}
SILLocation remapLocation(SILLocation InLoc) {
// For performance inlining return the original location.
if (IKind == InlineKind::PerformanceInline)
return InLoc;
// Inlined location wraps the call site that is being inlined, regardless
// of the input location.
return Loc.hasValue() ? Loc.getValue() :
MandatoryInlinedLocation::getMandatoryInlinedLocation((Decl*)nullptr);
}
const SILDebugScope *remapScope(const SILDebugScope *DS) {
if (IKind == InlineKind::MandatoryInline)
// Transparent functions are absorbed into the call
// site. No soup, err, debugging for you!
return CallSiteScope;
else
// Create an inlined version of the scope.
return getOrCreateInlineScope(DS);
}
InlineKind IKind;
SILBasicBlock *CalleeEntryBB;
/// \brief The location representing the inlined instructions.
///
/// This location wraps the call site AST node that is being inlined.
/// Alternatively, it can be the SIL file location of the call site (in case
/// of SIL-to-SIL transformations).
Optional<SILLocation> Loc;
const SILDebugScope *CallSiteScope = nullptr;
SILFunction *CalleeFunction;
llvm::SmallDenseMap<const SILDebugScope *,
const SILDebugScope *> InlinedScopeCache;
CloneCollector::CallbackType Callback;
};
} // end namespace swift
#endif