1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
|
//===--- SILCombiner.h ------------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// A port of LLVM's InstCombiner to SIL. Its main purpose is for performing
// small combining operations/peepholes at the SIL level. It additionally
// performs dead code elimination when it initially adds instructions to the
// work queue in order to reduce compile time by not visiting trivially dead
// instructions.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILOPTIMIZER_PASSMANAGER_SILCOMBINER_H
#define SWIFT_SILOPTIMIZER_PASSMANAGER_SILCOMBINER_H
#include "swift/Basic/Defer.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILInstructionWorklist.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
#include "swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h"
#include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h"
#include "swift/SILOptimizer/OptimizerBridging.h"
#include "swift/SILOptimizer/PassManager/PassManager.h"
#include "swift/SILOptimizer/Utils/CastOptimizer.h"
#include "swift/SILOptimizer/Utils/Existential.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/OwnershipOptUtils.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
namespace swift {
class AliasAnalysis;
/// This is a class which maintains the state of the combiner and simplifies
/// many operations such as removing/adding instructions and syncing them with
/// the worklist.
class SILCombiner :
public SILInstructionVisitor<SILCombiner, SILInstruction *> {
SILFunctionTransform *parentTransform;
AliasAnalysis *AA;
BasicCalleeAnalysis *CA;
DominanceAnalysis *DA;
/// Determine the set of types a protocol conforms to in whole-module
/// compilation mode.
ProtocolConformanceAnalysis *PCA;
/// Class hierarchy analysis needed to confirm no derived classes of a sole
/// conforming class.
ClassHierarchyAnalysis *CHA;
/// Non local access block analysis that we use when canonicalize object
/// lifetimes in OSSA.
NonLocalAccessBlockAnalysis *NLABA;
public:
/// Worklist containing all of the instructions primed for simplification.
SmallSILInstructionWorklist<256> Worklist;
private:
/// Utility for dead code removal.
InstructionDeleter deleter;
/// A cache of "dead end blocks" through which all paths it is known that the
/// program will terminate. This means that we are allowed to leak
/// objects.
DeadEndBlocks deadEndBlocks;
/// Variable to track if the SILCombiner made any changes.
bool MadeChange;
/// If set to true then the optimizer is free to erase cond_fail instructions.
bool RemoveCondFails;
/// If set to true then copies are canonicalized in OSSA mode.
bool enableCopyPropagation;
/// Set to true if some alloc/dealloc_stack instruction are inserted and at
/// the end of the run stack nesting needs to be corrected.
bool invalidatedStackNesting = false;
/// The current iteration of the SILCombine.
unsigned Iteration;
// The tracking list is used by `Builder` for newly added
// instructions, which we will periodically move to our worklist.
llvm::SmallVector<SILInstruction *, 64> TrackingList;
public:
/// Builder used to insert instructions.
SILBuilder Builder;
private:
SILOptFunctionBuilder FuncBuilder;
/// Cast optimizer
CastOptimizer CastOpt;
/// Dead end blocks cache. SILCombine is already not allowed to mess with CFG
/// edges so it is safe to use this here.
DeadEndBlocks deBlocks;
/// External context struct used by \see ownershipRAUWHelper.
OwnershipFixupContext ownershipFixupContext;
/// For invoking Swift instruction passes.
SwiftPassInvocation swiftPassInvocation;
public:
SILCombiner(SILFunctionTransform *parentTransform,
bool removeCondFails, bool enableCopyPropagation);
bool runOnFunction(SILFunction &F);
void clear() {
Iteration = 0;
Worklist.resetChecked();
MadeChange = false;
}
/// A "syntactic" high level function that combines our insertPt with the main
/// builder's builder context.
///
/// Since this is syntactic and we assume that our caller is passing in a
/// lambda that if we inline will be eliminated, we mark this function always
/// inline.
///
/// What is nice about this formulation is it enables one to really concisely
/// create a SILBuilder that uses the SILCombiner's builder context but at a
/// different use point. Example:
///
/// SILBuilderWithScope builder(insertPt);
/// builder.createInst1(insertPt->getLoc(), ...);
/// builder.createInst2(insertPt->getLoc(), ...);
/// builder.createInst3(insertPt->getLoc(), ...);
/// auto *finalValue = builder.createInst4(insertPt->getLoc(), ...);
///
/// Thats a lot of typing! Instead, using this API, one can write:
///
/// auto *finalValue = withBuilder(insertPt, [&](auto &b, auto l) {
/// b.createInst1(l, ...);
/// b.createInst2(l, ...);
/// b.createInst3(l, ...);
/// return b.createInst4(l, ...);
/// });
///
/// Since this is meant to be just be syntactic, we always inline this method.
LLVM_ATTRIBUTE_ALWAYS_INLINE
SingleValueInstruction *
withBuilder(SILInstruction *insertPt,
llvm::function_ref<SingleValueInstruction * (SILBuilder &, SILLocation)> visitor) {
SILBuilderWithScope builder(insertPt, Builder);
return visitor(builder, insertPt->getLoc());
}
// Insert the instruction New before instruction Old in Old's parent BB. Add
// New to the worklist.
SILInstruction *insertNewInstBefore(SILInstruction *New,
SILInstruction &Old) {
return Worklist.insertNewInstBefore(New, Old);
}
// This method is to be used when an instruction is found to be dead,
// replaceable with another preexisting expression. Here we add all uses of I
// to the worklist, replace all uses of I with the new value, then return I,
// so that the combiner will know that I was modified.
void replaceInstUsesWith(SingleValueInstruction &I, ValueBase *V) {
return Worklist.replaceInstUsesWith(I, V);
}
/// Perform use->set(value) and add use->user to the worklist.
void setUseValue(Operand *use, SILValue value) {
use->set(value);
Worklist.add(use->getUser());
}
// This method is to be used when a value is found to be dead,
// replaceable with another preexisting expression. Here we add all
// uses of oldValue to the worklist, replace all uses of oldValue
// with newValue.
void replaceValueUsesWith(SILValue oldValue, SILValue newValue) {
Worklist.replaceValueUsesWith(oldValue, newValue);
}
void replaceInstUsesPairwiseWith(SILInstruction *oldI, SILInstruction *newI) {
Worklist.replaceInstUsesPairwiseWith(oldI, newI);
}
// Some instructions can never be "trivially dead" due to side effects or
// producing a void value. In those cases, since we cannot rely on
// SILCombines trivially dead instruction DCE in order to delete the
// instruction, visit methods should use this method to delete the given
// instruction and upon completion of their peephole return the value returned
// by this method.
SILInstruction *eraseInstFromFunction(SILInstruction &I,
SILBasicBlock::iterator &InstIter,
bool AddOperandsToWorklist = true) {
Worklist.eraseInstFromFunction(I, InstIter, AddOperandsToWorklist);
MadeChange = true;
// Dummy return, so the caller doesn't need to explicitly return nullptr.
return nullptr;
}
// Erases \p inst and all of its users, recursively.
// The caller has to make sure that all users are removable (e.g. dead).
void eraseInstIncludingUsers(SILInstruction *inst);
SILInstruction *eraseInstFromFunction(SILInstruction &I,
bool AddOperandsToWorklist = true) {
SILBasicBlock::iterator nullIter;
return eraseInstFromFunction(I, nullIter, AddOperandsToWorklist);
}
void addInitialGroup(ArrayRef<SILInstruction *> List) {
Worklist.addInitialGroup(List);
}
/// Base visitor that does not do anything.
SILInstruction *visitSILInstruction(SILInstruction *I) { return nullptr; }
/// Instruction visitors.
SILInstruction *visitPartialApplyInst(PartialApplyInst *AI);
SILInstruction *visitApplyInst(ApplyInst *AI);
SILInstruction *visitBeginApplyInst(BeginApplyInst *BAI);
SILInstruction *visitTryApplyInst(TryApplyInst *AI);
SILInstruction *optimizeStringObject(BuiltinInst *BI);
SILInstruction *visitBuiltinInst(BuiltinInst *BI);
SILInstruction *visitCondFailInst(CondFailInst *CFI);
SILInstruction *visitRefToRawPointerInst(RefToRawPointerInst *RRPI);
SILInstruction *visitUpcastInst(UpcastInst *UCI);
// NOTE: The load optimized in this method is a load [trivial].
SILInstruction *optimizeLoadFromStringLiteral(LoadInst *li);
SILInstruction *visitLoadBorrowInst(LoadBorrowInst *LI);
SILInstruction *visitIndexAddrInst(IndexAddrInst *IA);
bool optimizeStackAllocatedEnum(AllocStackInst *AS);
SILInstruction *visitAllocStackInst(AllocStackInst *AS);
SILInstruction *visitSwitchEnumAddrInst(SwitchEnumAddrInst *SEAI);
SILInstruction *visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI);
SILInstruction *visitPointerToAddressInst(PointerToAddressInst *PTAI);
SILInstruction *visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI);
SILInstruction *visitUncheckedRefCastInst(UncheckedRefCastInst *URCI);
SILInstruction *visitEndCOWMutationInst(EndCOWMutationInst *URCI);
SILInstruction *visitUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *URCI);
SILInstruction *visitBridgeObjectToRefInst(BridgeObjectToRefInst *BORI);
SILInstruction *visitUnconditionalCheckedCastInst(
UnconditionalCheckedCastInst *UCCI);
SILInstruction *
visitUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *UCCAI);
SILInstruction *visitRawPointerToRefInst(RawPointerToRefInst *RPTR);
SILInstruction *
visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *TEDAI);
SILInstruction *visitCondBranchInst(CondBranchInst *CBI);
SILInstruction *
visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *UTBCI);
SILInstruction *
visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *UBCI);
SILInstruction *visitSelectEnumInst(SelectEnumInst *EIT);
SILInstruction *visitSelectEnumAddrInst(SelectEnumAddrInst *EIT);
SILInstruction *visitAllocExistentialBoxInst(AllocExistentialBoxInst *S);
SILInstruction *visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *TTOCMI);
SILInstruction *visitObjCToThickMetatypeInst(ObjCToThickMetatypeInst *OCTTMI);
SILInstruction *visitTupleExtractInst(TupleExtractInst *TEI);
SILInstruction *visitFixLifetimeInst(FixLifetimeInst *FLI);
SILInstruction *visitSwitchValueInst(SwitchValueInst *SVI);
SILInstruction *
visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CCABI);
SILInstruction *
visitCheckedCastBranchInst(CheckedCastBranchInst *CBI);
SILInstruction *visitUnreachableInst(UnreachableInst *UI);
SILInstruction *visitAllocRefDynamicInst(AllocRefDynamicInst *ARDI);
SILInstruction *visitMarkDependenceInst(MarkDependenceInst *MDI);
SILInstruction *visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *CBOI);
SILInstruction *visitConvertFunctionInst(ConvertFunctionInst *CFI);
SILInstruction *
visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *Cvt);
SILInstruction *
visitDifferentiableFunctionExtractInst(DifferentiableFunctionExtractInst *DFEI);
SILInstruction *visitPackLengthInst(PackLengthInst *PLI);
SILInstruction *visitPackElementGetInst(PackElementGetInst *PEGI);
SILInstruction *visitTuplePackElementAddrInst(TuplePackElementAddrInst *TPEAI);
SILInstruction *visitCopyAddrInst(CopyAddrInst *CAI);
SILInstruction *legacyVisitGlobalValueInst(GlobalValueInst *globalValue);
#define PASS(ID, TAG, DESCRIPTION)
#define SWIFT_FUNCTION_PASS(ID, TAG, DESCRIPTION)
#define SWIFT_SILCOMBINE_PASS(INST) \
SILInstruction *visit##INST(INST *);
#include "swift/SILOptimizer/PassManager/Passes.def"
/// Instruction visitor helpers.
// Optimize the "isConcrete" builtin.
SILInstruction *optimizeBuiltinIsConcrete(BuiltinInst *I);
SILInstruction *optimizeBuiltinCOWBufferForReading(BuiltinInst *BI);
SILInstruction *optimizeBuiltinCOWBufferForReadingNonOSSA(BuiltinInst *BI);
SILInstruction *optimizeBuiltinCOWBufferForReadingOSSA(BuiltinInst *BI);
// Optimize the "trunc_N1_M2" builtin. if N1 is a result of "zext_M1_*" and
// the following holds true: N1 > M1 and M2>= M1
SILInstruction *optimizeBuiltinTruncOrBitCast(BuiltinInst *I);
// Optimize the "zext_M2_M3" builtin. if M2 is a result of "zext_M1_M2"
SILInstruction *optimizeBuiltinZextOrBitCast(BuiltinInst *I);
// Optimize the "cmp_eq_XXX" builtin. If \p NegateResult is true then negate
// the result bit.
SILInstruction *optimizeBuiltinCompareEq(BuiltinInst *AI, bool NegateResult);
SILInstruction *optimizeApplyOfConvertFunctionInst(FullApplySite AI,
ConvertFunctionInst *CFI);
bool tryOptimizeInoutKeypath(BeginApplyInst *AI);
/// Sinks owned forwarding instructions to their uses if they do not have
/// non-debug non-consuming uses. Deletes any debug_values and destroy_values
/// when this is done. Returns true if we deleted svi and thus we should not
/// try to visit it.
bool trySinkOwnedForwardingInst(SingleValueInstruction *svi);
/// Apply CanonicalizeOSSALifetime to the extended lifetime of any copy
/// introduced during SILCombine for an owned value.
void canonicalizeOSSALifetimes(SILInstruction *currentInst);
// Optimize concatenation of string literals.
// Constant-fold concatenation of string literals known at compile-time.
SILInstruction *optimizeConcatenationOfStringLiterals(ApplyInst *AI);
// Optimize an application of f_inverse(f(x)) -> x.
bool optimizeIdentityCastComposition(ApplyInst *FInverse,
StringRef FInverseName, StringRef FName);
/// Let \p user and \p value be two forwarding single value instructions with
/// the property that \p value is the value that \p user forwards. In this
/// case, this helper routine will eliminate \p value if it can rewrite user
/// in terms of \p newValue. This is intended to handle cases where we have
/// completely different types so we need to actually create a new instruction
/// with a different result type.
///
/// \param newValueGenerator Generator that produces the new value to
/// use. Conditionally called if we can perform the optimization.
SILInstruction *tryFoldComposedUnaryForwardingInstChain(
SingleValueInstruction *user, SingleValueInstruction *value,
function_ref<SILValue()> newValueGenerator);
SILInstruction *optimizeAlignment(PointerToAddressInst *ptrAdrInst);
InstModCallbacks &getInstModCallbacks() { return deleter.getCallbacks(); }
private:
// Build concrete existential information using findInitExistential.
std::optional<ConcreteOpenedExistentialInfo>
buildConcreteOpenedExistentialInfo(Operand &ArgOperand);
// Build concrete existential information using SoleConformingType.
std::optional<ConcreteOpenedExistentialInfo>
buildConcreteOpenedExistentialInfoFromSoleConformingType(Operand &ArgOperand);
// Common utility function to build concrete existential information for all
// arguments of an apply instruction.
void buildConcreteOpenedExistentialInfos(
FullApplySite Apply,
llvm::SmallDenseMap<unsigned, ConcreteOpenedExistentialInfo> &COEIs,
SILBuilderContext &BuilderCtx);
bool canReplaceArg(FullApplySite Apply, const OpenedArchetypeInfo &OAI,
const ConcreteExistentialInfo &CEI, unsigned ArgIdx);
SILValue canCastArg(FullApplySite Apply, const OpenedArchetypeInfo &OAI,
const ConcreteExistentialInfo &CEI, unsigned ArgIdx);
SILInstruction *createApplyWithConcreteType(
FullApplySite Apply,
const llvm::SmallDenseMap<unsigned, ConcreteOpenedExistentialInfo> &COEIs,
SILBuilderContext &BuilderCtx);
// Common utility function to replace the WitnessMethodInst using a
// BuilderCtx.
void replaceWitnessMethodInst(WitnessMethodInst *WMI,
SILBuilderContext &BuilderCtx,
CanType ConcreteType,
const ProtocolConformanceRef ConformanceRef);
SILInstruction *
propagateConcreteTypeOfInitExistential(FullApplySite Apply,
WitnessMethodInst *WMI);
SILInstruction *propagateConcreteTypeOfInitExistential(FullApplySite Apply);
/// Propagate concrete types from ProtocolConformanceAnalysis.
SILInstruction *propagateSoleConformingType(FullApplySite Apply,
WitnessMethodInst *WMI);
/// Perform one SILCombine iteration.
bool doOneIteration(SILFunction &F, unsigned Iteration);
/// Add reachable code to the worklist. Meant to be used when starting to
/// process a new function.
void addReachableCodeToWorklist(SILBasicBlock *BB);
typedef SmallVector<SILInstruction*, 4> UserListTy;
/// Returns a list of instructions that project or perform reference
/// counting operations on \p Value or on its uses.
/// \return return false if \p Value has other than ARC uses.
static bool recursivelyCollectARCUsers(UserListTy &Uses, ValueBase *Value);
/// Erases an apply instruction including all it's uses \p.
/// Inserts release/destroy instructions for all owner and in-parameters.
/// \return Returns true if successful.
bool eraseApply(FullApplySite FAS, const UserListTy &Users);
/// Returns true if the results of a try_apply are not used.
static bool isTryApplyResultNotUsed(UserListTy &AcceptedUses,
TryApplyInst *TAI);
bool hasOwnership() const {
return Builder.hasOwnership();
}
void runSwiftInstructionPass(SILInstruction *inst,
void (*runFunction)(BridgedInstructionPassCtxt));
};
} // end namespace swift
#endif
|