@@ -488,4 +488,141 @@ struct ilist_traits<::swift::SILBasicBlock>
488
488
489
489
} // end llvm namespace
490
490
491
+ // ===----------------------------------------------------------------------===//
492
+ // PhiOperand & PhiValue
493
+ // ===----------------------------------------------------------------------===//
494
+
495
+ namespace swift {
496
+
497
+ // / Represent a phi argument without storing pointers to branches or their
498
+ // / operands which are invalidated by adding new, unrelated phi values. Because
499
+ // / this only stores a block pointer, it remains valid as long as the CFG is
500
+ // / immutable and the index of the phi value does not change.
501
+ // /
502
+ // / Note: this should not be confused with SILPhiArgument which should be
503
+ // / renamed to SILPhiValue and only used for actual phis.
504
+ // /
505
+ // / Warning: This is invalid for CondBranchInst arguments. Clients assume that
506
+ // / any instructions inserted at the phi argument is post-dominated by that phi
507
+ // / argument. This warning can be removed once the SILVerifier fully prohibits
508
+ // / CondBranchInst arguments at all SIL stages.
509
+ struct PhiOperand {
510
+ SILBasicBlock *predBlock = nullptr ;
511
+ unsigned argIndex = 0 ;
512
+
513
+ PhiOperand () = default ;
514
+
515
+ PhiOperand (Operand *operand) {
516
+ auto *branch = dyn_cast<BranchInst>(operand->getUser ());
517
+ if (!branch)
518
+ return ;
519
+
520
+ predBlock = branch->getParent ();
521
+ argIndex = operand->getOperandNumber ();
522
+ }
523
+
524
+ explicit operator bool () const { return predBlock != nullptr ; }
525
+
526
+ bool operator ==(PhiOperand other) const {
527
+ return predBlock == other.predBlock && argIndex == other.argIndex ;
528
+ }
529
+
530
+ bool operator !=(PhiOperand other) const { return !(*this == other); }
531
+
532
+ BranchInst *getBranch () const {
533
+ return cast<BranchInst>(predBlock->getTerminator ());
534
+ }
535
+
536
+ Operand *getOperand () const {
537
+ return &getBranch ()->getAllOperands ()[argIndex];
538
+ }
539
+
540
+ SILPhiArgument *getValue () const {
541
+ auto *branch = cast<BranchInst>(predBlock->getTerminator ());
542
+ return cast<SILPhiArgument>(branch->getDestBB ()->getArgument (argIndex));
543
+ }
544
+
545
+ SILValue getSource () const {
546
+ return getOperand ()->get ();
547
+ }
548
+
549
+ operator Operand *() const { return getOperand (); }
550
+ Operand *operator *() const { return getOperand (); }
551
+ Operand *operator ->() const { return getOperand (); }
552
+ };
553
+
554
+ // / Represent a phi value without referencing the SILValue, which is invalidated
555
+ // / by adding new, unrelated phi values. Because this only stores a block
556
+ // / pointer, it remains valid as long as the CFG is immutable and the index of
557
+ // / the phi value does not change.
558
+ struct PhiValue {
559
+ SILBasicBlock *phiBlock = nullptr ;
560
+ unsigned argIndex = 0 ;
561
+
562
+ PhiValue () = default ;
563
+
564
+ PhiValue (SILValue value) {
565
+ auto *blockArg = dyn_cast<SILPhiArgument>(value);
566
+ if (!blockArg || !blockArg->isPhiArgument ())
567
+ return ;
568
+
569
+ phiBlock = blockArg->getParent ();
570
+ argIndex = blockArg->getIndex ();
571
+ }
572
+
573
+ explicit operator bool () const { return phiBlock != nullptr ; }
574
+
575
+ bool operator ==(PhiValue other) const {
576
+ return phiBlock == other.phiBlock && argIndex == other.argIndex ;
577
+ }
578
+
579
+ bool operator !=(PhiValue other) const { return !(*this == other); }
580
+
581
+ SILPhiArgument *getValue () const {
582
+ return cast<SILPhiArgument>(phiBlock->getArgument (argIndex));
583
+ }
584
+
585
+ operator SILValue () const { return getValue (); }
586
+ SILValue operator *() const { return getValue (); }
587
+ SILValue operator ->() const { return getValue (); }
588
+ };
589
+
590
+ } // namespace swift
591
+
592
+ namespace llvm {
593
+
594
+ template <> struct DenseMapInfo <swift::PhiOperand> {
595
+ static swift::PhiOperand getEmptyKey () { return swift::PhiOperand (); }
596
+ static swift::PhiOperand getTombstoneKey () {
597
+ swift::PhiOperand phiOper;
598
+ phiOper.predBlock =
599
+ llvm::DenseMapInfo<swift::SILBasicBlock *>::getTombstoneKey ();
600
+ return phiOper;
601
+ }
602
+ static unsigned getHashValue (swift::PhiOperand phiOper) {
603
+ return llvm::hash_combine (phiOper.predBlock , phiOper.argIndex );
604
+ }
605
+ static bool isEqual (swift::PhiOperand lhs, swift::PhiOperand rhs) {
606
+ return lhs == rhs;
607
+ }
608
+ };
609
+
610
+ template <> struct DenseMapInfo <swift::PhiValue> {
611
+ static swift::PhiValue getEmptyKey () { return swift::PhiValue (); }
612
+ static swift::PhiValue getTombstoneKey () {
613
+ swift::PhiValue phiValue;
614
+ phiValue.phiBlock =
615
+ llvm::DenseMapInfo<swift::SILBasicBlock *>::getTombstoneKey ();
616
+ return phiValue;
617
+ }
618
+ static unsigned getHashValue (swift::PhiValue phiValue) {
619
+ return llvm::hash_combine (phiValue.phiBlock , phiValue.argIndex );
620
+ }
621
+ static bool isEqual (swift::PhiValue lhs, swift::PhiValue rhs) {
622
+ return lhs == rhs;
623
+ }
624
+ };
625
+
626
+ } // end namespace llvm
627
+
491
628
#endif
0 commit comments