Skip to content

Commit 7b2fc07

Browse files
committed
[sil] Add new API ValueBase:getUsersOfType<T>().
For some time now we have had the API ValueBase::getSingleUserOfType<T>() but we never implemented getUsersOfType<T>() using transform/filter iterators. Since there wasn't a specific API, several incarnations of this API have been created for BeginBorrow, LoadBorrow, BeginAccess. In this commit, I introduce the API and use it to excise the redundant code in those above mentioned 3 instructions.
1 parent 25ceaab commit 7b2fc07

File tree

3 files changed

+50
-31
lines changed

3 files changed

+50
-31
lines changed

include/swift/Basic/STLExtras.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,8 @@ class OptionalTransformIterator {
578578
return *Op(*Current);
579579
}
580580

581+
reference operator*() { return *Op(*Current); }
582+
581583
OptionalTransformIterator &operator++() {
582584
++Current;
583585
skipNonMatching();

include/swift/SIL/SILInstruction.h

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3289,16 +3289,6 @@ class StoreInst
32893289

32903290
class EndBorrowInst;
32913291

3292-
struct UseToEndBorrow {
3293-
Optional<EndBorrowInst *> operator()(Operand *use) const {
3294-
if (auto endBorrow = dyn_cast<EndBorrowInst>(use->getUser())) {
3295-
return endBorrow;
3296-
} else {
3297-
return None;
3298-
}
3299-
}
3300-
};
3301-
33023292
/// Represents a load of a borrowed value. Must be paired with an end_borrow
33033293
/// instruction in its use-def list.
33043294
class LoadBorrowInst :
@@ -3312,14 +3302,14 @@ class LoadBorrowInst :
33123302
LValue->getType().getObjectType()) {}
33133303

33143304
using EndBorrowRange =
3315-
OptionalTransformRange<use_range, UseToEndBorrow, use_iterator>;
3305+
decltype(std::declval<ValueBase>().getUsersOfType<EndBorrowInst>());
33163306

33173307
/// Return a range over all EndBorrow instructions for this BeginBorrow.
33183308
EndBorrowRange getEndBorrows() const;
33193309
};
33203310

33213311
inline auto LoadBorrowInst::getEndBorrows() const -> EndBorrowRange {
3322-
return EndBorrowRange(getUses(), UseToEndBorrow());
3312+
return getUsersOfType<EndBorrowInst>();
33233313
}
33243314

33253315
/// Represents the begin scope of a borrowed value. Must be paired with an
@@ -3335,7 +3325,7 @@ class BeginBorrowInst
33353325

33363326
public:
33373327
using EndBorrowRange =
3338-
OptionalTransformRange<use_range, UseToEndBorrow, use_iterator>;
3328+
decltype(std::declval<ValueBase>().getUsersOfType<EndBorrowInst>());
33393329

33403330
/// Return a range over all EndBorrow instructions for this BeginBorrow.
33413331
EndBorrowRange getEndBorrows() const;
@@ -3350,7 +3340,7 @@ class BeginBorrowInst
33503340
};
33513341

33523342
inline auto BeginBorrowInst::getEndBorrows() const -> EndBorrowRange {
3353-
return EndBorrowRange(getUses(), UseToEndBorrow());
3343+
return getUsersOfType<EndBorrowInst>();
33543344
}
33553345

33563346
/// Represents a store of a borrowed value into an address. Returns the borrowed
@@ -3489,6 +3479,8 @@ enum class SILAccessEnforcement : uint8_t {
34893479
};
34903480
StringRef getSILAccessEnforcementName(SILAccessEnforcement enforcement);
34913481

3482+
class EndAccessInst;
3483+
34923484
/// Begins an access scope. Must be paired with an end_access instruction
34933485
/// along every path.
34943486
class BeginAccessInst
@@ -3560,13 +3552,8 @@ class BeginAccessInst
35603552
return getOperand();
35613553
}
35623554

3563-
private:
3564-
/// Predicate used to filter EndAccessRange.
3565-
struct UseToEndAccess;
3566-
3567-
public:
35683555
using EndAccessRange =
3569-
OptionalTransformRange<use_range, UseToEndAccess, use_iterator>;
3556+
decltype(std::declval<ValueBase>().getUsersOfType<EndAccessInst>());
35703557

35713558
/// Find all the associated end_access instructions for this begin_access.
35723559
EndAccessRange getEndAccesses() const;
@@ -3607,18 +3594,8 @@ class EndAccessInst
36073594
}
36083595
};
36093596

3610-
struct BeginAccessInst::UseToEndAccess {
3611-
Optional<EndAccessInst *> operator()(Operand *use) const {
3612-
if (auto access = dyn_cast<EndAccessInst>(use->getUser())) {
3613-
return access;
3614-
} else {
3615-
return None;
3616-
}
3617-
}
3618-
};
3619-
36203597
inline auto BeginAccessInst::getEndAccesses() const -> EndAccessRange {
3621-
return EndAccessRange(getUses(), UseToEndAccess());
3598+
return getUsersOfType<EndAccessInst>();
36223599
}
36233600

36243601
/// Begins an access without requiring a paired end_access.

include/swift/SIL/SILValue.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,27 @@ class ValueBase : public SILNode, public SILAllocated<ValueBase> {
275275
template <class T>
276276
inline T *getSingleUserOfType() const;
277277

278+
/// Helper struct for DowncastUserFilterRange
279+
struct UseToUser;
280+
281+
template <typename Subclass>
282+
using DowncastUserFilterRange =
283+
DowncastFilterRange<Subclass,
284+
llvm::iterator_range<llvm::mapped_iterator<
285+
use_iterator, UseToUser, SILInstruction *>>>;
286+
287+
/// Iterate over the use list of this ValueBase visiting all users that are of
288+
/// class T.
289+
///
290+
/// Example:
291+
///
292+
/// ValueBase *v = ...;
293+
/// for (CopyValueInst *cvi : v->getUsersOfType<CopyValueInst>()) { ... }
294+
///
295+
/// NOTE: Uses llvm::dyn_cast internally.
296+
template <typename T>
297+
inline DowncastUserFilterRange<T> getUsersOfType() const;
298+
278299
/// Return the instruction that defines this value, or null if it is
279300
/// not defined by an instruction.
280301
const SILInstruction *getDefiningInstruction() const {
@@ -717,6 +738,25 @@ inline T *ValueBase::getSingleUserOfType() const {
717738
return Result;
718739
}
719740

741+
struct ValueBase::UseToUser {
742+
SILInstruction *operator()(const Operand *use) const {
743+
return const_cast<SILInstruction *>(use->getUser());
744+
}
745+
SILInstruction *operator()(const Operand &use) const {
746+
return const_cast<SILInstruction *>(use.getUser());
747+
}
748+
SILInstruction *operator()(Operand *use) { return use->getUser(); }
749+
SILInstruction *operator()(Operand &use) { return use.getUser(); }
750+
};
751+
752+
template <typename T>
753+
inline ValueBase::DowncastUserFilterRange<T> ValueBase::getUsersOfType() const {
754+
auto begin = llvm::map_iterator(use_begin(), UseToUser());
755+
auto end = llvm::map_iterator(use_end(), UseToUser());
756+
auto transformRange = llvm::make_range(begin, end);
757+
return makeDowncastFilterRange<T>(transformRange);
758+
}
759+
720760
/// A constant-size list of the operands of an instruction.
721761
template <unsigned N> class FixedOperandList {
722762
Operand Buffer[N];

0 commit comments

Comments
 (0)