Skip to content

Commit 05bec97

Browse files
committed
[FSPrunedLiveness] Add extendToNonUse.
And use it in lifetime maximization. The preexisting member function updateForUse has been updated to match PrunedLiveness and gravitate towards lifetimeEnding=false. For a fixed instruction and bit, if called with lifetimeEnding=true and then lifetimeEnding=false, the lifetime-ending-ness of the instruction at the bit will be false; and if it is again called with lifetimeEnding=true, the lifetime-ending-ness of the instruction at the bit will remain false. In contrast the new member function extendToUse does not alter the lifetime-ending-ness if it is already set. If it is unset, the function sets the bit to lifetimeEnding=false.
1 parent c1716c9 commit 05bec97

File tree

5 files changed

+401
-29
lines changed

5 files changed

+401
-29
lines changed

include/swift/SIL/FieldSensitivePrunedLiveness.h

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,12 @@ struct TypeTreeLeafTypeRange {
375375

376376
/// Sets each bit in \p bits corresponding to an element of this range.
377377
void setBits(SmallBitVector &bits) const {
378-
for (auto element : getRange()) {
379-
bits.set(element);
380-
}
378+
bits.set(startEltOffset, endEltOffset);
379+
}
380+
381+
/// Resets each bit in \p bits corresponding to an element of this range.
382+
void resetBits(SmallBitVector &bits) const {
383+
bits.reset(startEltOffset, endEltOffset);
381384
}
382385

383386
IntRange<unsigned> getRange() const {
@@ -694,6 +697,15 @@ class FieldSensitivePrunedLiveness {
694697
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };
695698

696699
struct InterestingUser {
700+
// Together these bit vectors encode four states per field:
701+
// +---------------+----------------+---------------+
702+
// - | liveBits[bit] | consumingBits] | state |
703+
// +---------------+----------------+---------------+
704+
// | 0 | 0 | dead |
705+
// | 0 | 1 | non-use |
706+
// | 1 | 0 | non-consuming |
707+
// | 1 | 1 | consuming |
708+
// +---------------+----------------+---------------+
697709
SmallBitVector liveBits;
698710
SmallBitVector consumingBits;
699711

@@ -708,18 +720,33 @@ class FieldSensitivePrunedLiveness {
708720

709721
/// Record that the instruction uses the bits of the value in \p range.
710722
void addUses(TypeTreeLeafTypeRange range, bool lifetimeEnding) {
711-
range.setBits(liveBits);
712-
if (lifetimeEnding) {
713-
range.setBits(consumingBits);
714-
}
723+
SmallBitVector bits(liveBits.size());
724+
range.setBits(bits);
725+
addUses(bits, lifetimeEnding);
715726
}
716727

717728
/// Record that the instruction uses the bits in \p bits.
718729
void addUses(SmallBitVector const &bits, bool lifetimeEnding) {
719-
liveBits |= bits;
720730
if (lifetimeEnding) {
721-
consumingBits |= bits;
731+
consumingBits |= bits & ~liveBits;
732+
} else {
733+
consumingBits &= ~bits;
722734
}
735+
liveBits |= bits;
736+
}
737+
738+
/// Extend liveness at the bits in the specified \p range without
739+
/// overriding whether the lifetimes of those bits end.
740+
void extendToNonUse(TypeTreeLeafTypeRange range) {
741+
SmallBitVector bits(liveBits.size());
742+
range.setBits(bits);
743+
extendToNonUse(bits);
744+
}
745+
746+
/// Extend liveness at the specified \p bits without overriding whether the
747+
/// lifetimes of those bits end.
748+
void extendToNonUse(SmallBitVector const &bits) {
749+
consumingBits |= bits & ~liveBits;
723750
}
724751

725752
/// Populates the provided vector with contiguous ranges of bits which are
@@ -755,10 +782,18 @@ class FieldSensitivePrunedLiveness {
755782
}
756783

757784
IsInterestingUser isInterestingUser(unsigned element) const {
758-
if (!liveBits.test(element))
785+
auto isLive = liveBits.test(element);
786+
auto isConsuming = consumingBits.test(element);
787+
if (!isLive && !isConsuming) {
759788
return NonUser;
760-
return consumingBits.test(element) ? LifetimeEndingUse
761-
: NonLifetimeEndingUse;
789+
} else if (!isLive && isConsuming) {
790+
return NonLifetimeEndingUse;
791+
} else if (isLive && isConsuming) {
792+
return LifetimeEndingUse;
793+
} else if (isLive && !isConsuming) {
794+
return NonLifetimeEndingUse;
795+
}
796+
llvm_unreachable("covered conditions");
762797
}
763798
};
764799

@@ -875,6 +910,16 @@ class FieldSensitivePrunedLiveness {
875910
bool lifetimeEnding,
876911
SmallBitVector const &useBeforeDefBits);
877912

913+
/// Adds \p user which doesn't use the def to liveness.
914+
///
915+
/// Different from calling updateForUse because it never overrides the value
916+
/// \p lifetimeEnding stored for \p inst.
917+
void extendToNonUse(SILInstruction *user, TypeTreeLeafTypeRange span,
918+
SmallBitVector const &useBeforeDefBits);
919+
920+
void extendToNonUse(SILInstruction *user, SmallBitVector const &bits,
921+
SmallBitVector const &useBeforeDefBits);
922+
878923
void getBlockLiveness(SILBasicBlock *bb, TypeTreeLeafTypeRange span,
879924
SmallVectorImpl<FieldSensitivePrunedLiveBlocks::IsLive>
880925
&resultingFoundLiveness) const {
@@ -943,7 +988,7 @@ class FieldSensitivePrunedLiveness {
943988

944989
unsigned getNumSubElements() const { return liveBlocks.getNumBitsToTrack(); }
945990

946-
void print(llvm::raw_ostream &os) const { liveBlocks.print(os); }
991+
void print(llvm::raw_ostream &os) const;
947992
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
948993

949994
protected:
@@ -971,6 +1016,14 @@ class FieldSensitivePrunedLiveness {
9711016
bool lifetimeEnding) {
9721017
getOrCreateInterestingUser(user).addUses(bits, lifetimeEnding);
9731018
}
1019+
1020+
void extendToNonUse(SILInstruction *user, TypeTreeLeafTypeRange range) {
1021+
getOrCreateInterestingUser(user).extendToNonUse(range);
1022+
}
1023+
1024+
void extendToNonUse(SILInstruction *user, SmallBitVector const &bits) {
1025+
getOrCreateInterestingUser(user).extendToNonUse(bits);
1026+
}
9741027
};
9751028

9761029
/// Record the last use points and CFG edges that form the boundary of
@@ -1089,6 +1142,14 @@ class FieldSensitivePrunedLiveRange : public FieldSensitivePrunedLiveness {
10891142
void updateForUse(SILInstruction *user, SmallBitVector const &bits,
10901143
bool lifetimeEnding);
10911144

1145+
/// Customize extendToNonUse for FieldSensitivePrunedLiveness to consider
1146+
/// defs as kills.
1147+
void extendToNonUse(SILInstruction *user, TypeTreeLeafTypeRange span);
1148+
1149+
/// Customize extendToNonUse for FieldSensitivePrunedLiveness to consider
1150+
/// defs as kills.
1151+
void extendToNonUse(SILInstruction *user, SmallBitVector const &bits);
1152+
10921153
/// Compute the boundary from the blocks discovered during liveness analysis.
10931154
///
10941155
/// Precondition: \p liveness.getDiscoveredBlocks() is a valid list of all

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,114 @@ void FieldSensitivePrunedLiveness::updateForUse(
663663
addInterestingUser(user, bits, lifetimeEnding);
664664
}
665665

666+
void FieldSensitivePrunedLiveness::extendToNonUse(
667+
SILInstruction *user, TypeTreeLeafTypeRange range,
668+
SmallBitVector const &useBeforeDefBits) {
669+
SmallVector<FieldSensitivePrunedLiveBlocks::IsLive, 8> resultingLiveness;
670+
liveBlocks.updateForUse(user, range.startEltOffset, range.endEltOffset,
671+
useBeforeDefBits, resultingLiveness);
672+
673+
extendToNonUse(user, range);
674+
}
675+
676+
void FieldSensitivePrunedLiveness::extendToNonUse(
677+
SILInstruction *user, SmallBitVector const &bits,
678+
SmallBitVector const &useBeforeDefBits) {
679+
for (auto bit : bits.set_bits()) {
680+
liveBlocks.updateForUse(user, bit, useBeforeDefBits.test(bit));
681+
}
682+
683+
extendToNonUse(user, bits);
684+
}
685+
686+
void FieldSensitivePrunedLiveness::print(llvm::raw_ostream &os) const {
687+
liveBlocks.print(os);
688+
for (auto &userAndInterest : users) {
689+
for (size_t bit = 0, size = userAndInterest.second.liveBits.size();
690+
bit < size; ++bit) {
691+
auto isLive = userAndInterest.second.liveBits.test(bit);
692+
auto isConsuming = userAndInterest.second.consumingBits.test(bit);
693+
if (!isLive && !isConsuming) {
694+
continue;
695+
} else if (!isLive && isConsuming) {
696+
os << "non-user: ";
697+
} else if (isLive && isConsuming) {
698+
os << "lifetime-ending user: ";
699+
} else if (isLive && !isConsuming) {
700+
os << "regular user: ";
701+
}
702+
os << *userAndInterest.first << "\tat " << bit << "\n";
703+
}
704+
}
705+
}
706+
707+
namespace swift::test {
708+
// Arguments:
709+
// - SILValue: def whose pruned liveness will be calculated
710+
// - the string "uses:"
711+
// - variadic list of live-range user instructions
712+
// Dumps:
713+
// -
714+
static FunctionTest FieldSensitiveSSAUseLivenessTest(
715+
"fs_ssa_use_liveness", [](auto &function, auto &arguments, auto &test) {
716+
auto value = arguments.takeValue();
717+
auto begin = (unsigned)arguments.takeUInt();
718+
auto end = (unsigned)arguments.takeUInt();
719+
720+
SmallVector<SILBasicBlock *, 8> discoveredBlocks;
721+
FieldSensitiveSSAPrunedLiveRange liveness(&function, &discoveredBlocks);
722+
liveness.init(value);
723+
liveness.initializeDef(value, TypeTreeLeafTypeRange(begin, end));
724+
725+
auto argument = arguments.takeArgument();
726+
if (cast<StringArgument>(argument).getValue() != "uses:") {
727+
llvm::report_fatal_error(
728+
"test specification expects the 'uses:' label\n");
729+
}
730+
while (arguments.hasUntaken()) {
731+
auto *inst = arguments.takeInstruction();
732+
auto kindString = arguments.takeString();
733+
enum Kind {
734+
NonUse,
735+
Ending,
736+
NonEnding,
737+
};
738+
auto kind = llvm::StringSwitch<llvm::Optional<Kind>>(kindString)
739+
.Case("non-use", Kind::NonUse)
740+
.Case("ending", Kind::Ending)
741+
.Case("non-ending", Kind::NonEnding)
742+
.Default(llvm::None);
743+
if (!kind.has_value()) {
744+
llvm::errs() << "Unknown kind: " << kindString << "\n";
745+
llvm::report_fatal_error("Bad user kind. Value must be one of "
746+
"'non-use', 'ending', 'non-ending'");
747+
}
748+
auto begin = (unsigned)arguments.takeUInt();
749+
auto end = (unsigned)arguments.takeUInt();
750+
switch (kind.value()) {
751+
case Kind::NonUse:
752+
liveness.extendToNonUse(inst, TypeTreeLeafTypeRange(begin, end));
753+
break;
754+
case Kind::Ending:
755+
liveness.updateForUse(inst, TypeTreeLeafTypeRange(begin, end),
756+
/*lifetimeEnding*/ true);
757+
break;
758+
case Kind::NonEnding:
759+
liveness.updateForUse(inst, TypeTreeLeafTypeRange(begin, end),
760+
/*lifetimeEnding*/ false);
761+
break;
762+
}
763+
}
764+
765+
liveness.print(llvm::outs());
766+
767+
FieldSensitivePrunedLivenessBoundary boundary(1);
768+
liveness.computeBoundary(boundary);
769+
boundary.print(llvm::outs());
770+
});
771+
772+
} // end namespace swift::test
773+
666774
//===----------------------------------------------------------------------===//
667775
// MARK: FieldSensitivePrunedLiveRange
668776
//===----------------------------------------------------------------------===//
@@ -967,6 +1075,22 @@ void FieldSensitivePrunedLiveRange<LivenessWithDefs>::updateForUse(
9671075
useBeforeDefBits);
9681076
}
9691077

1078+
template <typename LivenessWithDefs>
1079+
void FieldSensitivePrunedLiveRange<LivenessWithDefs>::extendToNonUse(
1080+
SILInstruction *user, TypeTreeLeafTypeRange range) {
1081+
SmallBitVector useBeforeDefBits(getNumSubElements());
1082+
asImpl().isUserBeforeDef(user, range.getRange(), useBeforeDefBits);
1083+
FieldSensitivePrunedLiveness::extendToNonUse(user, range, useBeforeDefBits);
1084+
}
1085+
1086+
template <typename LivenessWithDefs>
1087+
void FieldSensitivePrunedLiveRange<LivenessWithDefs>::extendToNonUse(
1088+
SILInstruction *user, SmallBitVector const &bits) {
1089+
SmallBitVector useBeforeDefBits(getNumSubElements());
1090+
asImpl().isUserBeforeDef(user, bits.set_bits(), useBeforeDefBits);
1091+
FieldSensitivePrunedLiveness::extendToNonUse(user, bits, useBeforeDefBits);
1092+
}
1093+
9701094
//===----------------------------------------------------------------------===//
9711095
// MARK: Boundary Computation Utilities
9721096
//===----------------------------------------------------------------------===//

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,8 +1433,7 @@ class ExtendUnconsumedLiveness {
14331433
BasicBlockSet const &consumedAtExitBlocks,
14341434
BasicBlockSetVector const &consumedAtEntryBlocks);
14351435

1436-
void addPreviousInstructionToLiveness(SILInstruction *inst, unsigned element,
1437-
bool lifetimeEnding);
1436+
void addPreviousInstructionToLiveness(SILInstruction *inst, unsigned element);
14381437
};
14391438

14401439
} // namespace
@@ -3361,8 +3360,7 @@ void ExtendUnconsumedLiveness::runOnField(
33613360
continue;
33623361
// Add "the instruction(s) before the terminator" of the predecessor to
33633362
// liveness.
3364-
addPreviousInstructionToLiveness(predecessor->getTerminator(), element,
3365-
/*lifetimeEnding*/ false);
3363+
addPreviousInstructionToLiveness(predecessor->getTerminator(), element);
33663364
}
33673365
}
33683366

@@ -3373,8 +3371,7 @@ void ExtendUnconsumedLiveness::runOnField(
33733371
if (!shouldAddDestroyToLiveness(destroy, element, consumedAtExitBlocks,
33743372
consumedAtEntryBlocks))
33753373
continue;
3376-
addPreviousInstructionToLiveness(destroy, element,
3377-
/*lifetimeEnding*/ false);
3374+
addPreviousInstructionToLiveness(destroy, element);
33783375
}
33793376
}
33803377

@@ -3462,16 +3459,12 @@ bool ExtendUnconsumedLiveness::hasDefAfter(SILInstruction *start,
34623459
}
34633460

34643461
void ExtendUnconsumedLiveness::addPreviousInstructionToLiveness(
3465-
SILInstruction *inst, unsigned element, bool lifetimeEnding) {
3462+
SILInstruction *inst, unsigned element) {
34663463
auto range = TypeTreeLeafTypeRange(element, element + 1);
3467-
if (auto *previous = inst->getPreviousInstruction()) {
3468-
liveness.updateForUse(previous, range, lifetimeEnding);
3469-
} else {
3470-
for (auto *predecessor : inst->getParent()->getPredecessorBlocks()) {
3471-
liveness.updateForUse(predecessor->getTerminator(), range,
3472-
lifetimeEnding);
3473-
}
3474-
}
3464+
inst->visitPriorInstructions([&](auto *prior) {
3465+
liveness.extendToNonUse(prior, range);
3466+
return true;
3467+
});
34753468
}
34763469

34773470
bool MoveOnlyAddressCheckerPImpl::performSingleCheck(

test/SILOptimizer/field_sensitive_liverange_unit.sil

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ sil @getC : $@convention(thin) () -> (@owned C)
1515
// CHECK: def in range [0, 1) value: [[RB:%.*]] = argument of bb3 : $C
1616
// CHECK-NEXT: bb2: LiveWithin
1717
// CHECK-NEXT: bb3: LiveWithin
18-
// CHECK-NEXT: last user: br bb3([[B]] : $C)
18+
// All users are printed here.
19+
// CHECK: last user: br bb3([[B]] : $C)
1920
// CHECK-NEXT: at 1
2021
// CHECK-NEXT: last user: end_borrow [[RB]] : $C
2122
// CHECK-NEXT: at 1

0 commit comments

Comments
 (0)