//===--- SILLowerAggregateInstrs.cpp - Aggregate insts to Scalar insts ---===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 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 // //===----------------------------------------------------------------------===// // // Simplify aggregate instructions into scalar instructions. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-lower-aggregate-instrs" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/Local.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILVisitor.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/TypeLowering.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" using namespace swift; using namespace swift::Lowering; STATISTIC(NumExpand, "Number of instructions expanded"); //===----------------------------------------------------------------------===// // Higher Level Operation Expansion //===----------------------------------------------------------------------===// /// \brief Lower copy_addr into loads/stores/retain/release if we have a /// non-address only type. We do this here so we can process the resulting /// loads/stores. /// /// This peephole implements the following optimizations: /// /// copy_addr %0 to %1 : $*T /// -> /// %new = load %0 : $*T // Load the new value from the source /// %old = load %1 : $*T // Load the old value from the destination /// strong_retain %new : $T // Retain the new value /// strong_release %old : $T // Release the old /// store %new to %1 : $*T // Store the new value to the destination /// /// copy_addr [take] %0 to %1 : $*T /// -> /// %new = load %0 : $*T /// %old = load %1 : $*T /// // no retain of %new! /// strong_release %old : $T /// store %new to %1 : $*T /// /// copy_addr %0 to [initialization] %1 : $*T /// -> /// %new = load %0 : $*T /// strong_retain %new : $T /// // no load/release of %old! /// store %new to %1 : $*T /// /// copy_addr [take] %0 to [initialization] %1 : $*T /// -> /// %new = load %0 : $*T /// // no retain of %new! /// // no load/release of %old! /// store %new to %1 : $*T static bool expandCopyAddr(CopyAddrInst *CA) { SILModule &M = CA->getModule(); SILValue Source = CA->getSrc(); // If we have an address only type don't do anything. SILType SrcType = Source->getType(); if (SrcType.isAddressOnly(M)) return false; SILBuilderWithScope Builder(CA); // %new = load %0 : $*T LoadInst *New = Builder.createLoad(CA->getLoc(), Source); SILValue Destination = CA->getDest(); // If our object type is not trivial, we may need to release the old value and // retain the new one. auto &TL = M.getTypeLowering(SrcType); // If we have a non-trivial type... if (!TL.isTrivial()) { // If we are not initializing: // %old = load %1 : $*T IsInitialization_t IsInit = CA->isInitializationOfDest(); LoadInst *Old = nullptr; if (IsInitialization_t::IsNotInitialization == IsInit) { Old = Builder.createLoad(CA->getLoc(), Destination); } // If we are not taking and have a reference type: // strong_retain %new : $*T // or if we have a non-trivial non-reference type. // retain_value %new : $*T IsTake_t IsTake = CA->isTakeOfSrc(); if (IsTake_t::IsNotTake == IsTake) { TL.emitLoweredRetainValue(Builder, CA->getLoc(), New, TypeLowering::LoweringStyle::DeepNoEnum); } // If we are not initializing: // strong_release %old : $*T // *or* // release_value %old : $*T if (Old) { TL.emitLoweredReleaseValue(Builder, CA->getLoc(), Old, TypeLowering::LoweringStyle::DeepNoEnum); } } // Create the store. Builder.createStore(CA->getLoc(), New, Destination); ++NumExpand; return true; } static bool expandDestroyAddr(DestroyAddrInst *DA) { SILModule &Module = DA->getModule(); SILBuilderWithScope Builder(DA); // Strength reduce destroy_addr inst into release/store if // we have a non-address only type. SILValue Addr = DA->getOperand(); // If we have an address only type, do nothing. SILType Type = Addr->getType(); if (Type.isAddressOnly(Module)) return false; // If we have a non-trivial type... if (!Type.isTrivial(Module)) { // If we have a type with reference semantics, emit a load/strong release. LoadInst *LI = Builder.createLoad(DA->getLoc(), Addr); auto &TL = Module.getTypeLowering(Type); TL.emitLoweredReleaseValue(Builder, DA->getLoc(), LI, TypeLowering::LoweringStyle::DeepNoEnum); } ++NumExpand; return true; } static bool expandReleaseValue(ReleaseValueInst *DV) { SILModule &Module = DV->getModule(); SILBuilderWithScope Builder(DV); // Strength reduce destroy_addr inst into release/store if // we have a non-address only type. SILValue Value = DV->getOperand(); // If we have an address only type, do nothing. SILType Type = Value->getType(); assert(Type.isLoadable(Module) && "release_value should never be called on a non-loadable type."); auto &TL = Module.getTypeLowering(Type); TL.emitLoweredReleaseValue(Builder, DV->getLoc(), Value, TypeLowering::LoweringStyle::DeepNoEnum); DEBUG(llvm::dbgs() << " Expanding Destroy Value: " << *DV); ++NumExpand; return true; } static bool expandRetainValue(RetainValueInst *CV) { SILModule &Module = CV->getModule(); SILBuilderWithScope Builder(CV); // Strength reduce destroy_addr inst into release/store if // we have a non-address only type. SILValue Value = CV->getOperand(); // If we have an address only type, do nothing. SILType Type = Value->getType(); assert(Type.isLoadable(Module) && "Copy Value can only be called on loadable " "types."); auto &TL = Module.getTypeLowering(Type); TL.emitLoweredRetainValue(Builder, CV->getLoc(), Value, TypeLowering::LoweringStyle::DeepNoEnum); DEBUG(llvm::dbgs() << " Expanding Copy Value: " << *CV); ++NumExpand; return true; } //===----------------------------------------------------------------------===// // Top Level Driver //===----------------------------------------------------------------------===// static bool processFunction(SILFunction &Fn) { bool Changed = false; for (auto BI = Fn.begin(), BE = Fn.end(); BI != BE; ++BI) { auto II = BI->begin(), IE = BI->end(); while (II != IE) { SILInstruction *Inst = &*II; DEBUG(llvm::dbgs() << "Visiting: " << *Inst); if (auto *CA = dyn_cast(Inst)) if (expandCopyAddr(CA)) { ++II; CA->eraseFromParent(); Changed = true; continue; } if (auto *DA = dyn_cast(Inst)) if (expandDestroyAddr(DA)) { ++II; DA->eraseFromParent(); Changed = true; continue; } if (auto *CV = dyn_cast(Inst)) if (expandRetainValue(CV)) { ++II; CV->eraseFromParent(); Changed = true; continue; } if (auto *DV = dyn_cast(Inst)) if (expandReleaseValue(DV)) { ++II; DV->eraseFromParent(); Changed = true; continue; } ++II; } } return Changed; } namespace { class SILLowerAggregate : public SILFunctionTransform { /// The entry point to the transformation. void run() override { SILFunction *F = getFunction(); DEBUG(llvm::dbgs() << "***** LowerAggregate on function: " << F->getName() << " *****\n"); bool Changed = processFunction(*F); if (Changed) { invalidateAnalysis(SILAnalysis::InvalidationKind::CallsAndInstructions); } } StringRef getName() override { return "Lower Aggregate Instructions"; } }; } // end anonymous namespace SILTransform *swift::createLowerAggregateInstrs() { return new SILLowerAggregate(); }