mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
We ignore calls to ArraySemantic functions when we hoist uniqueness checks. With +0 self, this is disrupted by the release that now is in the caller instead of the callee. This patch fixes that problem by teaching COWArrayOpts about "guaranteed call sequences". This is the following pattern: retain(x) ... nothing that decrements reference counts ... call f1(@guaranteed_self x) ... nothing that decrements or uses ref counts ... call f2(@guaranteed_self x) ... nothing that decrements or uses ref counts ... ... ... nothing that decrements or uses ref counts ... call f$(n-1)(@guaranteed_self x) ... nothing that decrements or uses ref counts ... call fn(@guaranteed_self x) ... nothing that uses ref counts ... release(x) This pattern is created when there are a bunch of guaranteed calls together in a row (which seems to happen at the "semantic" SIL level). We pattern match the sequence and then verify that all of the calls are semantic calls. If the verification succeeds, we can hoist the uniqueness check. rdar://20340699 Swift SVN r26835
127 lines
3.9 KiB
C++
127 lines
3.9 KiB
C++
//===--- ArraySemantic.h - Wrapper around array semantic calls. -*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SILANALYSIS_ARRAYSEMANTIC_H
|
|
#define SWIFT_SILANALYSIS_ARRAYSEMANTIC_H
|
|
|
|
#include "swift/SIL/SILInstruction.h"
|
|
|
|
namespace swift {
|
|
class DominanceInfo;
|
|
|
|
/// The kind of array operation identified by looking at the semantics attribute
|
|
/// of the called function.
|
|
enum class ArrayCallKind {
|
|
kNone = 0,
|
|
kArrayPropsIsNative,
|
|
kArrayPropsNeedsTypeCheck,
|
|
kCheckSubscript,
|
|
kCheckIndex,
|
|
kGetCount,
|
|
kGetCapacity,
|
|
kGetElement,
|
|
kGetArrayOwner,
|
|
kGetElementAddress,
|
|
kMakeMutable,
|
|
kMutateUnknown,
|
|
// The following two semantic function kinds return the result @owned
|
|
// instead of operating on self passed as parameter.
|
|
kArrayInit,
|
|
kArrayUninitialized
|
|
};
|
|
|
|
/// Wrapper around array semantic calls.
|
|
class ArraySemanticsCall {
|
|
ApplyInst *SemanticsCall;
|
|
|
|
public:
|
|
/// Match array semantic calls.
|
|
ArraySemanticsCall(ValueBase *V, StringRef SemanticStr,
|
|
bool MatchPartialName);
|
|
|
|
/// Match any array semantics call.
|
|
ArraySemanticsCall(ValueBase *V) : ArraySemanticsCall(V, "array.", true) {}
|
|
|
|
/// Match a specific array semantic call.
|
|
ArraySemanticsCall(ValueBase *V, StringRef SemanticStr)
|
|
: ArraySemanticsCall(V, SemanticStr, false) {}
|
|
|
|
/// Can we hoist this call.
|
|
bool canHoist(SILInstruction *To, DominanceInfo *DT) const;
|
|
|
|
/// Determine which kind of array semantics call this is.
|
|
ArrayCallKind getKind() const;
|
|
|
|
/// Does this semantic call has a self argument.
|
|
///
|
|
/// For example, kArrayInit and kArrayUninitialized don't.
|
|
bool hasSelf() const;
|
|
|
|
/// Does this instruction have guaranteed self.
|
|
///
|
|
/// Once +0 self is enabled, this can be removed in favor of just hasSelf()
|
|
/// since all of these methods will have guaranteed self always.
|
|
bool hasGuaranteedSelf() const;
|
|
|
|
/// Get the self argument.
|
|
SILValue getSelf() const;
|
|
|
|
/// Get the self argument operand.
|
|
Operand &getSelfOperand() const;
|
|
|
|
/// Get the index for operations that have one.
|
|
SILValue getIndex() const;
|
|
|
|
/// Get the array.props.isNative argument.
|
|
SILValue getArrayPropertyIsNative() const;
|
|
|
|
/// Get the array.props.needsElementTypeCheck argument.
|
|
SILValue getArrayPropertyNeedsTypeCheck() const;
|
|
|
|
/// Remove the semantics call replacing it by a release of any @owned
|
|
/// parameter.
|
|
void removeCall();
|
|
|
|
/// Hoist the call to the insert point.
|
|
void hoist(SILInstruction *InsertBefore, DominanceInfo *DT) {
|
|
hoistOrCopy(InsertBefore, DT, false);
|
|
}
|
|
|
|
/// Copy the call to the insert point and return the newly created call.
|
|
ApplyInst *copyTo(SILInstruction *InsertBefore, DominanceInfo *DT) {
|
|
return hoistOrCopy(InsertBefore, DT, true);
|
|
}
|
|
|
|
/// Get the semantics call as an ApplyInst.
|
|
operator ApplyInst *() const { return SemanticsCall; }
|
|
|
|
/// Is this an semantics call.
|
|
operator bool() const { return SemanticsCall != nullptr; }
|
|
|
|
/// Does this array semantic call touch globals or ivars in a manner that
|
|
/// causes its effect on reference counts to not be described solely by its
|
|
/// signature.
|
|
bool isNoCapture() const;
|
|
|
|
protected:
|
|
/// Validate the signature of this call.
|
|
bool isValidSignature();
|
|
|
|
/// Hoist or copy the call to the insert point. If LeaveOriginal is true the
|
|
/// call is copied to the insert point. Returns the copied call.
|
|
ApplyInst *hoistOrCopy(SILInstruction *InsertBefore, DominanceInfo *DT,
|
|
bool LeaveOriginal);
|
|
};
|
|
|
|
} // End namespace swift.
|
|
#endif
|