40
40
#include " swift/Strings.h"
41
41
#include " llvm/ADT/APFloat.h"
42
42
#include " llvm/ADT/APInt.h"
43
+ #include " llvm/ADT/SmallPtrSet.h"
43
44
#include " llvm/ADT/ilist.h"
44
45
#include " llvm/ADT/ilist_node.h"
45
46
#include " llvm/Support/TrailingObjects.h"
@@ -7318,6 +7319,20 @@ class TermInst : public NonValueInstruction {
7318
7319
}
7319
7320
};
7320
7321
7322
+ class OwnershipForwardingTermInst : public TermInst {
7323
+ ValueOwnershipKind ownershipKind;
7324
+
7325
+ protected:
7326
+ OwnershipForwardingTermInst (SILInstructionKind kind,
7327
+ SILDebugLocation debugLoc,
7328
+ ValueOwnershipKind ownershipKind)
7329
+ : TermInst(kind, debugLoc), ownershipKind(ownershipKind) {}
7330
+
7331
+ public:
7332
+ ValueOwnershipKind getOwnershipKind () const { return ownershipKind; }
7333
+ void setOwnershipKind (ValueOwnershipKind newKind) { ownershipKind = newKind; }
7334
+ };
7335
+
7321
7336
// / UnreachableInst - Position in the code which would be undefined to reach.
7322
7337
// / These are always implicitly generated, e.g. when falling off the end of a
7323
7338
// / function or after a no-return function call.
@@ -7806,9 +7821,9 @@ class SwitchValueInst final
7806
7821
}
7807
7822
};
7808
7823
7809
- // / Common implementation for the switch_enum and
7810
- // / switch_enum_addr instructions.
7811
- class SwitchEnumInstBase : public TermInst {
7824
+ // / Common implementation for the switch_enum and switch_enum_addr instructions.
7825
+ template < typename BaseTy>
7826
+ class SwitchEnumInstBase : public BaseTy {
7812
7827
FixedOperandList<1 > Operands;
7813
7828
7814
7829
// Tail-allocated after the SwitchEnumInst record are:
@@ -7837,48 +7852,97 @@ class SwitchEnumInstBase : public TermInst {
7837
7852
}
7838
7853
7839
7854
protected:
7855
+ template <typename ... Rest>
7840
7856
SwitchEnumInstBase (
7841
7857
SILInstructionKind Kind, SILDebugLocation DebugLoc, SILValue Operand,
7842
7858
SILBasicBlock *DefaultBB,
7843
7859
ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
7844
- Optional<ArrayRef<ProfileCounter>> Counts, ProfileCounter DefaultCount);
7860
+ Optional<ArrayRef<ProfileCounter>> Counts, ProfileCounter DefaultCount,
7861
+ Rest &&... rest)
7862
+ : BaseTy(Kind, DebugLoc, std::forward<Rest>(rest)...),
7863
+ Operands (this , Operand) {
7864
+ SILInstruction::Bits.SEIBase .HasDefault = bool (DefaultBB);
7865
+ SILInstruction::Bits.SEIBase .NumCases = CaseBBs.size ();
7866
+ // Initialize the case and successor arrays.
7867
+ auto *cases = getCaseBuf ();
7868
+ auto *succs = getSuccessorBuf ();
7869
+ for (unsigned i = 0 , size = CaseBBs.size (); i < size; ++i) {
7870
+ cases[i] = CaseBBs[i].first ;
7871
+ if (Counts) {
7872
+ ::new (succs + i)
7873
+ SILSuccessor (this , CaseBBs[i].second , Counts.getValue ()[i]);
7874
+ } else {
7875
+ ::new (succs + i) SILSuccessor (this , CaseBBs[i].second );
7876
+ }
7877
+ }
7878
+
7879
+ if (hasDefault ()) {
7880
+ ::new (succs + getNumCases ()) SILSuccessor (this , DefaultBB, DefaultCount);
7881
+ }
7882
+ }
7845
7883
7846
- template <typename SWITCH_ENUM_INST>
7884
+ template <typename SWITCH_ENUM_INST, typename ... RestTys >
7847
7885
static SWITCH_ENUM_INST *createSwitchEnum (
7848
7886
SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
7849
7887
ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
7850
7888
SILFunction &F, Optional<ArrayRef<ProfileCounter>> Counts,
7851
- ProfileCounter DefaultCount);
7889
+ ProfileCounter DefaultCount, RestTys &&... restArgs );
7852
7890
7853
7891
public:
7854
7892
// / Clean up tail-allocated successor records for the switch cases.
7855
- ~SwitchEnumInstBase ();
7893
+ ~SwitchEnumInstBase () {
7894
+ // Destroy the successor records to keep the CFG up to date.
7895
+ auto *succs = getSuccessorBuf ();
7896
+ for (unsigned i = 0 , end = getNumCases () + hasDefault (); i < end; ++i) {
7897
+ succs[i].~SILSuccessor ();
7898
+ }
7899
+ }
7856
7900
7857
7901
SILValue getOperand () const { return Operands[0 ].get (); }
7858
7902
7859
7903
ArrayRef<Operand> getAllOperands () const { return Operands.asArray (); }
7860
7904
MutableArrayRef<Operand> getAllOperands () { return Operands.asArray (); }
7861
7905
7862
- SuccessorListTy getSuccessors () {
7906
+ TermInst:: SuccessorListTy getSuccessors () {
7863
7907
return MutableArrayRef<SILSuccessor>{getSuccessorBuf (),
7864
7908
static_cast <size_t >(getNumCases () + hasDefault ())};
7865
7909
}
7866
7910
7867
- unsigned getNumCases () const {
7868
- return SILInstruction::Bits.SwitchEnumInstBase .NumCases ;
7869
- }
7911
+ unsigned getNumCases () const { return SILInstruction::Bits.SEIBase .NumCases ; }
7912
+
7870
7913
std::pair<EnumElementDecl*, SILBasicBlock*>
7871
7914
getCase (unsigned i) const {
7872
7915
assert (i < getNumCases () && " case out of bounds" );
7873
7916
return {getCaseBuf ()[i], getSuccessorBuf ()[i].getBB ()};
7874
7917
}
7918
+
7875
7919
ProfileCounter getCaseCount (unsigned i) const {
7876
7920
assert (i < getNumCases () && " case out of bounds" );
7877
7921
return getSuccessorBuf ()[i].getCount ();
7878
7922
}
7879
7923
7880
7924
// Swap the cases at indices \p i and \p j.
7881
- void swapCase (unsigned i, unsigned j);
7925
+ void swapCase (unsigned i, unsigned j) {
7926
+ assert (i < getNumCases () && " First index is out of bounds?!" );
7927
+ assert (j < getNumCases () && " Second index is out of bounds?!" );
7928
+
7929
+ auto *succs = getSuccessorBuf ();
7930
+
7931
+ // First grab our destination blocks.
7932
+ SILBasicBlock *iBlock = succs[i].getBB ();
7933
+ SILBasicBlock *jBlock = succs[j].getBB ();
7934
+
7935
+ // Then destroy the sil successors and reinitialize them with the new things
7936
+ // that they are pointing at.
7937
+ succs[i].~SILSuccessor ();
7938
+ ::new (succs + i) SILSuccessor (this , jBlock);
7939
+ succs[j].~SILSuccessor ();
7940
+ ::new (succs + j) SILSuccessor (this , iBlock);
7941
+
7942
+ // Now swap our cases.
7943
+ auto *cases = getCaseBuf ();
7944
+ std::swap (cases[i], cases[j]);
7945
+ }
7882
7946
7883
7947
// / Return the block that will be branched to on the specified enum
7884
7948
// / case.
@@ -7893,22 +7957,69 @@ class SwitchEnumInstBase : public TermInst {
7893
7957
}
7894
7958
7895
7959
// / If the default refers to exactly one case decl, return it.
7896
- NullablePtr<EnumElementDecl> getUniqueCaseForDefault ();
7960
+ NullablePtr<EnumElementDecl> getUniqueCaseForDefault () {
7961
+ auto enumValue = getOperand ();
7962
+ SILType enumType = enumValue->getType ();
7963
+
7964
+ auto *f = SILInstruction::getFunction ();
7965
+ if (!enumType.isEffectivelyExhaustiveEnumType (f))
7966
+ return nullptr ;
7967
+
7968
+ EnumDecl *decl = enumType.getEnumOrBoundGenericEnum ();
7969
+ assert (decl && " switch_enum operand is not an enum" );
7970
+
7971
+ SmallPtrSet<EnumElementDecl *, 4 > unswitchedElts;
7972
+ for (auto elt : decl->getAllElements ())
7973
+ unswitchedElts.insert (elt);
7974
+
7975
+ for (unsigned i = 0 , e = getNumCases (); i != e; ++i) {
7976
+ auto Entry = getCase (i);
7977
+ unswitchedElts.erase (Entry.first );
7978
+ }
7979
+
7980
+ if (unswitchedElts.size () == 1 )
7981
+ return *unswitchedElts.begin ();
7982
+
7983
+ return nullptr ;
7984
+ }
7897
7985
7898
7986
// / If the given block only has one enum element decl matched to it,
7899
7987
// / return it.
7900
- NullablePtr<EnumElementDecl> getUniqueCaseForDestination (SILBasicBlock *BB);
7901
-
7902
- bool hasDefault () const {
7903
- return SILInstruction::Bits.SwitchEnumInstBase .HasDefault ;
7988
+ NullablePtr<EnumElementDecl>
7989
+ getUniqueCaseForDestination (SILBasicBlock *block) {
7990
+ SILValue value = getOperand ();
7991
+ SILType enumType = value->getType ();
7992
+ EnumDecl *decl = enumType.getEnumOrBoundGenericEnum ();
7993
+ assert (decl && " switch_enum operand is not an enum" );
7994
+ (void )decl;
7995
+
7996
+ EnumElementDecl *eltDecl = nullptr ;
7997
+ for (unsigned i : range (getNumCases ())) {
7998
+ auto entry = getCase (i);
7999
+ if (entry.second == block) {
8000
+ if (eltDecl != nullptr )
8001
+ return nullptr ;
8002
+ eltDecl = entry.first ;
8003
+ }
8004
+ }
8005
+ if (!eltDecl && hasDefault () && getDefaultBB () == block) {
8006
+ return getUniqueCaseForDefault ();
8007
+ }
8008
+ return eltDecl;
7904
8009
}
7905
8010
8011
+ bool hasDefault () const { return SILInstruction::Bits.SEIBase .HasDefault ; }
8012
+
7906
8013
SILBasicBlock *getDefaultBB () const {
7907
8014
assert (hasDefault () && " doesn't have a default" );
7908
8015
return getSuccessorBuf ()[getNumCases ()];
7909
8016
}
7910
8017
7911
- NullablePtr<SILBasicBlock> getDefaultBBOrNull () const ;
8018
+ NullablePtr<SILBasicBlock> getDefaultBBOrNull () const {
8019
+ if (!hasDefault ())
8020
+ return nullptr ;
8021
+ return getDefaultBB ();
8022
+ }
7912
8023
7913
8024
ProfileCounter getDefaultCount () const {
7914
8025
assert (hasDefault () && " doesn't have a default" );
@@ -7925,7 +8036,7 @@ class SwitchEnumInstBase : public TermInst {
7925
8036
// / passed into the corresponding destination block as an argument.
7926
8037
class SwitchEnumInst
7927
8038
: public InstructionBase<SILInstructionKind::SwitchEnumInst,
7928
- SwitchEnumInstBase> {
8039
+ SwitchEnumInstBase<OwnershipForwardingTermInst> > {
7929
8040
friend SILBuilder;
7930
8041
7931
8042
private:
@@ -7937,7 +8048,7 @@ class SwitchEnumInst
7937
8048
Optional<ArrayRef<ProfileCounter>> CaseCounts,
7938
8049
ProfileCounter DefaultCount)
7939
8050
: InstructionBase(DebugLoc, Operand, DefaultBB, CaseBBs, CaseCounts,
7940
- DefaultCount) {}
8051
+ DefaultCount, Operand.getOwnershipKind() ) {}
7941
8052
static SwitchEnumInst *
7942
8053
create (SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
7943
8054
ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
@@ -7948,7 +8059,7 @@ class SwitchEnumInst
7948
8059
// / A switch on an enum's discriminator in memory.
7949
8060
class SwitchEnumAddrInst
7950
8061
: public InstructionBase<SILInstructionKind::SwitchEnumAddrInst,
7951
- SwitchEnumInstBase> {
8062
+ SwitchEnumInstBase<TermInst> > {
7952
8063
friend SILBuilder;
7953
8064
7954
8065
private:
0 commit comments