mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This is in prepration for other bug fixes. Clarify the SIL utilities that return canonical address values for formal access given the address used by some memory operation: - stripAccessMarkers - getAddressAccess - getAccessedAddress These are closely related to the code in MemAccessUtils. Make sure passes use these utilities consistently so that optimizations aren't defeated by normal variations in SIL patterns. Create an isLetAddress() utility alongside these basic utilities to make sure it is used consistently with the address corresponding to formal access. When this query is used inconsistently, it defeats optimization. It can also cause correctness bugs because some optimizations assume that 'let' initialization is only performed on a unique address value. Functional changes to Memory Behavior: - An instruction with side effects now conservatively still has side effects even when the queried value is a 'let'. Let values are certainly sensitive to side effects, such as the parent object being deallocated. - Return the correct MemBehavior for begin/end_access markers.
179 lines
6.9 KiB
C++
179 lines
6.9 KiB
C++
//===--- InstructionUtils.h - Utilities for SIL instructions ----*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 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_SIL_INSTRUCTIONUTILS_H
|
|
#define SWIFT_SIL_INSTRUCTIONUTILS_H
|
|
|
|
#include "swift/SIL/SILInstruction.h"
|
|
|
|
namespace swift {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SSA Use-Def Helpers
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Strip off casts/indexing insts/address projections from V until there is
|
|
/// nothing left to strip.
|
|
SILValue getUnderlyingObject(SILValue V);
|
|
|
|
SILValue getUnderlyingObjectStopAtMarkDependence(SILValue V);
|
|
|
|
SILValue stripSinglePredecessorArgs(SILValue V);
|
|
|
|
/// Return the underlying SILValue after stripping off all casts from the
|
|
/// current SILValue.
|
|
SILValue stripCasts(SILValue V);
|
|
|
|
/// Return the underlying SILValue after stripping off all casts (but
|
|
/// mark_dependence) from the current SILValue.
|
|
SILValue stripCastsWithoutMarkDependence(SILValue V);
|
|
|
|
/// Return the underlying SILValue after stripping off all copy_value and
|
|
/// begin_borrow instructions.
|
|
SILValue stripOwnershipInsts(SILValue v);
|
|
|
|
/// Return the underlying SILValue after stripping off all upcasts from the
|
|
/// current SILValue.
|
|
SILValue stripUpCasts(SILValue V);
|
|
|
|
/// Return the underlying SILValue after stripping off all
|
|
/// upcasts and downcasts.
|
|
SILValue stripClassCasts(SILValue V);
|
|
|
|
/// Return the underlying SILValue after stripping off all address projection
|
|
/// instructions.
|
|
SILValue stripAddressProjections(SILValue V);
|
|
|
|
/// Return the underlying SILValue after stripping off all aggregate projection
|
|
/// instructions.
|
|
///
|
|
/// An aggregate projection instruction is either a struct_extract or a
|
|
/// tuple_extract instruction.
|
|
SILValue stripValueProjections(SILValue V);
|
|
|
|
/// Return the underlying SILValue after stripping off all indexing
|
|
/// instructions.
|
|
///
|
|
/// An indexing inst is either index_addr or index_raw_pointer.
|
|
SILValue stripIndexingInsts(SILValue V);
|
|
|
|
/// Returns the underlying value after stripping off a builtin expect
|
|
/// intrinsic call.
|
|
SILValue stripExpectIntrinsic(SILValue V);
|
|
|
|
/// If V is a begin_borrow, strip off the begin_borrow and return. Otherwise,
|
|
/// ust return V.
|
|
SILValue stripBorrow(SILValue V);
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction Properties
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Return a non-null SingleValueInstruction if the given instruction merely
|
|
/// copies the value of its first operand, possibly changing its type or
|
|
/// ownership state, but otherwise having no effect.
|
|
///
|
|
/// The returned instruction may have additional "incidental" operands;
|
|
/// mark_dependence for example.
|
|
///
|
|
/// This is useful for checking all users of a value to verify that the value is
|
|
/// only used in recognizable patterns without otherwise "escaping". These are
|
|
/// instructions that the use-visitor can recurse into. Note that the value's
|
|
/// type may be changed by a cast.
|
|
SingleValueInstruction *getSingleValueCopyOrCast(SILInstruction *I);
|
|
|
|
/// Return true if this instruction terminates a SIL-level scope. Scope end
|
|
/// instructions do not produce a result.
|
|
bool isEndOfScopeMarker(SILInstruction *user);
|
|
|
|
/// Return true if the given instruction has no effect on it's operand values
|
|
/// and produces no result. These are typically end-of scope markers.
|
|
///
|
|
/// This is useful for checking all users of a value to verify that the value is
|
|
/// only used in recognizable patterns without otherwise "escaping".
|
|
bool isIncidentalUse(SILInstruction *user);
|
|
|
|
/// Return true if the given `user` instruction modifies the value's refcount
|
|
/// without propagating the value or having any other effect aside from
|
|
/// potentially destroying the value itself (and executing associated cleanups).
|
|
///
|
|
/// This is useful for checking all users of a value to verify that the value is
|
|
/// only used in recognizable patterns without otherwise "escaping".
|
|
bool onlyAffectsRefCount(SILInstruction *user);
|
|
|
|
/// Returns true if the given user instruction checks the ref count of a
|
|
/// pointer.
|
|
bool mayCheckRefCount(SILInstruction *User);
|
|
|
|
/// Return true when the instruction represents added instrumentation for
|
|
/// run-time sanitizers.
|
|
bool isSanitizerInstrumentation(SILInstruction *Instruction);
|
|
|
|
/// Check that this is a partial apply of a reabstraction thunk and return the
|
|
/// argument of the partial apply if it is.
|
|
SILValue isPartialApplyOfReabstractionThunk(PartialApplyInst *PAI);
|
|
|
|
/// Returns true if \p PAI is only used by an assign_by_wrapper instruction as
|
|
/// init or set function.
|
|
bool onlyUsedByAssignByWrapper(PartialApplyInst *PAI);
|
|
|
|
/// If V is a function closure, return the reaching set of partial_apply's.
|
|
void findClosuresForFunctionValue(SILValue V,
|
|
TinyPtrVector<PartialApplyInst *> &results);
|
|
|
|
/// Given a polymorphic builtin \p bi that may be generic and thus have in/out
|
|
/// params, stash all of the information needed for either specializing while
|
|
/// inlining or propagating the type in constant propagation.
|
|
///
|
|
/// NOTE: If we perform this transformation, our builtin will no longer have any
|
|
/// substitutions since we only substitute to concrete static overloads.
|
|
struct PolymorphicBuiltinSpecializedOverloadInfo {
|
|
const BuiltinInfo *builtinInfo;
|
|
Identifier staticOverloadIdentifier;
|
|
SmallVector<SILType, 8> argTypes;
|
|
SILType resultType;
|
|
bool hasOutParam;
|
|
|
|
private:
|
|
bool isInitialized;
|
|
|
|
public:
|
|
PolymorphicBuiltinSpecializedOverloadInfo()
|
|
: builtinInfo(nullptr), staticOverloadIdentifier(), argTypes(),
|
|
resultType(), hasOutParam(false), isInitialized(false) {}
|
|
|
|
/// Returns true if we were able to map the polymorphic builtin to a static
|
|
/// overload. False otherwise.
|
|
///
|
|
/// NOTE: This does not mean that the static overload actually exists.
|
|
bool init(BuiltinInst *bi);
|
|
|
|
bool doesOverloadExist() const {
|
|
CanBuiltinType builtinType = argTypes.front().getAs<BuiltinType>();
|
|
return canBuiltinBeOverloadedForType(builtinInfo->ID, builtinType);
|
|
}
|
|
|
|
private:
|
|
bool init(SILFunction *fn, BuiltinValueKind builtinKind,
|
|
ArrayRef<SILType> oldOperandTypes, SILType oldResultType);
|
|
};
|
|
|
|
/// Given a polymorphic builtin \p bi, analyze its types and create a builtin
|
|
/// for the static overload that the builtin corresponds to. If \p bi is not a
|
|
/// polymorphic builtin or does not have any available overload for these types,
|
|
/// return SILValue().
|
|
SILValue getStaticOverloadForSpecializedPolymorphicBuiltin(BuiltinInst *bi);
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|