|
12 | 12 |
|
13 | 13 | #define DEBUG_TYPE "sil-combine"
|
14 | 14 | #include "SILCombiner.h"
|
| 15 | +#include "swift/Basic/STLExtras.h" |
| 16 | +#include "swift/SIL/DebugUtils.h" |
15 | 17 | #include "swift/SIL/DynamicCasts.h"
|
16 | 18 | #include "swift/SIL/PatternMatch.h"
|
17 | 19 | #include "swift/SIL/Projection.h"
|
18 | 20 | #include "swift/SIL/SILBuilder.h"
|
19 | 21 | #include "swift/SIL/SILVisitor.h"
|
20 |
| -#include "swift/SIL/DebugUtils.h" |
21 |
| -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" |
22 | 22 | #include "swift/SILOptimizer/Analysis/ARCAnalysis.h"
|
| 23 | +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" |
23 | 24 | #include "swift/SILOptimizer/Analysis/CFG.h"
|
24 | 25 | #include "swift/SILOptimizer/Analysis/ValueTracking.h"
|
25 |
| -#include "swift/SILOptimizer/Utils/Local.h" |
26 | 26 | #include "swift/SILOptimizer/Utils/Devirtualize.h"
|
| 27 | +#include "swift/SILOptimizer/Utils/Local.h" |
| 28 | +#include "llvm/ADT/DenseMap.h" |
27 | 29 | #include "llvm/ADT/SmallPtrSet.h"
|
28 | 30 | #include "llvm/ADT/SmallVector.h"
|
29 |
| -#include "llvm/ADT/DenseMap.h" |
30 | 31 |
|
31 | 32 | using namespace swift;
|
32 | 33 | using namespace swift::PatternMatch;
|
@@ -781,75 +782,156 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
|
781 | 782 |
|
782 | 783 | // Ok, we have a payload enum, make sure that we have a store previous to
|
783 | 784 | // us...
|
784 |
| - SILBasicBlock::iterator II = IEAI->getIterator(); |
785 |
| - StoreInst *SI = nullptr; |
| 785 | + SILValue ASO = IEAI->getOperand(); |
| 786 | + if (!isa<AllocStackInst>(ASO)) { |
| 787 | + return nullptr; |
| 788 | + } |
786 | 789 | InitEnumDataAddrInst *DataAddrInst = nullptr;
|
787 |
| - ApplyInst *AI = nullptr; |
788 |
| - Operand *EnumInitOperand = nullptr; |
789 |
| - for (;;) { |
790 |
| - if (II == IEAI->getParent()->begin()) |
791 |
| - return nullptr; |
792 |
| - --II; |
793 |
| - SI = dyn_cast<StoreInst>(&*II); |
794 |
| - if (SI) { |
795 |
| - // Find a Store whose destination is taken from an init_enum_data_addr |
796 |
| - // whose address is same allocation as our inject_enum_addr. |
797 |
| - DataAddrInst = dyn_cast<InitEnumDataAddrInst>(SI->getDest()); |
798 |
| - if (DataAddrInst && DataAddrInst->getOperand() == IEAI->getOperand()) |
799 |
| - break; |
800 |
| - SI = nullptr; |
| 790 | + InjectEnumAddrInst *EnumAddrIns = nullptr; |
| 791 | + llvm::SmallPtrSet<SILInstruction *, 32> WriteSet; |
| 792 | + for (auto UsersIt : ASO->getUses()) { |
| 793 | + SILInstruction *CurrUser = UsersIt->getUser(); |
| 794 | + if (CurrUser->isDeallocatingStack()) { |
| 795 | + // we don't care about the dealloc stack instructions |
| 796 | + continue; |
801 | 797 | }
|
802 |
| - // Check whether we have an apply initializing the enum. |
803 |
| - // %iedai = init_enum_data_addr %enum_addr |
804 |
| - // = apply(%iedai,...) |
805 |
| - // inject_enum_addr %enum_addr |
806 |
| - // |
807 |
| - // We can localize the store to an alloc_stack. |
808 |
| - // Allowing us to perform the same optimization as for the store. |
809 |
| - // |
810 |
| - // %alloca = alloc_stack |
811 |
| - // apply(%alloca,...) |
812 |
| - // %load = load %alloca |
813 |
| - // %1 = enum $EnumType, $EnumType.case, %load |
814 |
| - // store %1 to %nopayload_addr |
815 |
| - // |
816 |
| - if ((AI = dyn_cast<ApplyInst>(&*II))) { |
817 |
| - unsigned ArgIdx = 0; |
818 |
| - for (auto &Opd : AI->getArgumentOperands()) { |
819 |
| - // Found an apply that initializes the enum. We can optimize this by |
820 |
| - // localizing the initialization to an alloc_stack and loading from it. |
821 |
| - DataAddrInst = dyn_cast<InitEnumDataAddrInst>(Opd.get()); |
822 |
| - if (DataAddrInst && DataAddrInst->getOperand() == IEAI->getOperand() && |
823 |
| - ArgIdx < AI->getSubstCalleeType()->getNumIndirectResults()) { |
824 |
| - EnumInitOperand = &Opd; |
| 798 | + if (isDebugInst(CurrUser) || isa<LoadInst>(CurrUser)) { |
| 799 | + // These Instructions are a non-risky use we can ignore |
| 800 | + continue; |
| 801 | + } |
| 802 | + if (auto *CurrInst = dyn_cast<InitEnumDataAddrInst>(CurrUser)) { |
| 803 | + if (DataAddrInst) { |
| 804 | + return nullptr; |
| 805 | + } |
| 806 | + DataAddrInst = CurrInst; |
| 807 | + continue; |
| 808 | + } |
| 809 | + if (auto *CurrInst = dyn_cast<InjectEnumAddrInst>(CurrUser)) { |
| 810 | + if (EnumAddrIns) { |
| 811 | + return nullptr; |
| 812 | + } |
| 813 | + EnumAddrIns = CurrInst; |
| 814 | + continue; |
| 815 | + } |
| 816 | + if (isa<StoreInst>(CurrUser)) { |
| 817 | + // The only MayWrite Instruction we can safely handle |
| 818 | + WriteSet.insert(CurrUser); |
| 819 | + continue; |
| 820 | + } |
| 821 | + // It is too risky to continue if it is any other instruction. |
| 822 | + return nullptr; |
| 823 | + } |
| 824 | + |
| 825 | + if (!DataAddrInst || !EnumAddrIns) { |
| 826 | + return nullptr; |
| 827 | + } |
| 828 | + assert((EnumAddrIns == IEAI) && |
| 829 | + "Found InitEnumDataAddrInst differs from IEAI"); |
| 830 | + // Found the DataAddrInst to this enum payload. Check if it has only use. |
| 831 | + if (!hasOneNonDebugUse(DataAddrInst)) |
| 832 | + return nullptr; |
| 833 | + |
| 834 | + StoreInst *SI = dyn_cast<StoreInst>(getSingleNonDebugUser(DataAddrInst)); |
| 835 | + ApplyInst *AI = dyn_cast<ApplyInst>(getSingleNonDebugUser(DataAddrInst)); |
| 836 | + if (!SI && !AI) { |
| 837 | + return nullptr; |
| 838 | + } |
| 839 | + |
| 840 | + // Make sure the enum pattern instructions are the only ones which write to |
| 841 | + // this location |
| 842 | + if (!WriteSet.empty()) { |
| 843 | + // Analyze the instructions (implicit dominator analysis) |
| 844 | + // If we find any of MayWriteSet, return nullptr |
| 845 | + SILBasicBlock *InitEnumBB = DataAddrInst->getParent(); |
| 846 | + assert(InitEnumBB && "DataAddrInst is not in a valid Basic Block"); |
| 847 | + llvm::SmallVector<SILInstruction *, 64> Worklist; |
| 848 | + Worklist.push_back(IEAI); |
| 849 | + llvm::SmallPtrSet<SILBasicBlock *, 16> Preds; |
| 850 | + Preds.insert(IEAI->getParent()); |
| 851 | + while (!Worklist.empty()) { |
| 852 | + SILInstruction *CurrIns = Worklist.pop_back_val(); |
| 853 | + SILBasicBlock *CurrBB = CurrIns->getParent(); |
| 854 | + |
| 855 | + if (CurrBB->isEntry() && CurrBB != InitEnumBB) { |
| 856 | + // reached prologue without encountering the init bb |
| 857 | + return nullptr; |
| 858 | + } |
| 859 | + |
| 860 | + for (llvm::iplist<SILInstruction>::reverse_iterator InsIt( |
| 861 | + CurrIns->getIterator()); |
| 862 | + InsIt != CurrBB->rend(); ++InsIt) { |
| 863 | + SILInstruction *Ins = &*InsIt; |
| 864 | + if (Ins == DataAddrInst) { |
| 865 | + // don't care about what comes before init enum in the basic block |
825 | 866 | break;
|
826 | 867 | }
|
827 |
| - ++ArgIdx; |
| 868 | + if (WriteSet.count(Ins) != 0) { |
| 869 | + return nullptr; |
| 870 | + } |
| 871 | + } |
| 872 | + |
| 873 | + if (CurrBB == InitEnumBB) { |
| 874 | + continue; |
| 875 | + } |
| 876 | + |
| 877 | + // Go to predecessors and do all that again |
| 878 | + for (SILBasicBlock *Pred : CurrBB->getPreds()) { |
| 879 | + // If it's already in the set, then we've already queued and/or |
| 880 | + // processed the predecessors. |
| 881 | + if (Preds.insert(Pred).second) { |
| 882 | + Worklist.push_back(&*Pred->rbegin()); |
| 883 | + } |
828 | 884 | }
|
829 |
| - // We found an enum initialization. |
830 |
| - if (EnumInitOperand) |
831 |
| - break; |
832 |
| - AI = nullptr; |
833 | 885 | }
|
834 | 886 | }
|
835 |
| - // Found the store to this enum payload. Check if the store is the only use. |
836 |
| - if (!DataAddrInst->hasOneUse()) |
837 |
| - return nullptr; |
838 | 887 |
|
839 | 888 | if (SI) {
|
| 889 | + assert((SI->getDest() == DataAddrInst) && |
| 890 | + "Can't find StoreInst with DataAddrInst as its destination"); |
840 | 891 | // In that case, create the payload enum/store.
|
841 |
| - EnumInst *E = |
842 |
| - Builder.createEnum(DataAddrInst->getLoc(), SI->getSrc(), |
843 |
| - DataAddrInst->getElement(), |
844 |
| - DataAddrInst->getOperand()->getType().getObjectType()); |
| 892 | + EnumInst *E = Builder.createEnum( |
| 893 | + DataAddrInst->getLoc(), SI->getSrc(), DataAddrInst->getElement(), |
| 894 | + DataAddrInst->getOperand()->getType().getObjectType()); |
845 | 895 | Builder.createStore(DataAddrInst->getLoc(), E, DataAddrInst->getOperand());
|
846 | 896 | // Cleanup.
|
847 | 897 | eraseInstFromFunction(*SI);
|
848 | 898 | eraseInstFromFunction(*DataAddrInst);
|
849 | 899 | return eraseInstFromFunction(*IEAI);
|
850 | 900 | }
|
851 | 901 |
|
| 902 | + // Check whether we have an apply initializing the enum. |
| 903 | + // %iedai = init_enum_data_addr %enum_addr |
| 904 | + // = apply(%iedai,...) |
| 905 | + // inject_enum_addr %enum_addr |
| 906 | + // |
| 907 | + // We can localize the store to an alloc_stack. |
| 908 | + // Allowing us to perform the same optimization as for the store. |
| 909 | + // |
| 910 | + // %alloca = alloc_stack |
| 911 | + // apply(%alloca,...) |
| 912 | + // %load = load %alloca |
| 913 | + // %1 = enum $EnumType, $EnumType.case, %load |
| 914 | + // store %1 to %nopayload_addr |
| 915 | + // |
852 | 916 | assert(AI && "Must have an apply");
|
| 917 | + unsigned ArgIdx = 0; |
| 918 | + Operand *EnumInitOperand = nullptr; |
| 919 | + for (auto &Opd : AI->getArgumentOperands()) { |
| 920 | + // Found an apply that initializes the enum. We can optimize this by |
| 921 | + // localizing the initialization to an alloc_stack and loading from it. |
| 922 | + DataAddrInst = dyn_cast<InitEnumDataAddrInst>(Opd.get()); |
| 923 | + if (DataAddrInst && DataAddrInst->getOperand() == IEAI->getOperand() && |
| 924 | + ArgIdx < AI->getSubstCalleeType()->getNumIndirectResults()) { |
| 925 | + EnumInitOperand = &Opd; |
| 926 | + break; |
| 927 | + } |
| 928 | + ++ArgIdx; |
| 929 | + } |
| 930 | + |
| 931 | + if (!EnumInitOperand) { |
| 932 | + return nullptr; |
| 933 | + } |
| 934 | + |
853 | 935 | // Localize the address access.
|
854 | 936 | Builder.setInsertionPoint(AI);
|
855 | 937 | auto *AllocStack = Builder.createAllocStack(DataAddrInst->getLoc(),
|
|
0 commit comments