@@ -55,6 +55,33 @@ static inline llvm::hash_code hash_value(ValueKind K) {
55
55
return llvm::hash_value (size_t (K));
56
56
}
57
57
58
+ // / What constraint does the given use of an SSA value put on the lifetime of
59
+ // / the given SSA value.
60
+ // /
61
+ // / There are two possible constraints: MustBeLive and
62
+ // / MustBeInvalidated. MustBeLive means that the SSA value must be able to be
63
+ // / used in a valid way at the given use point. MustBeInvalidated means that any
64
+ // / use of given SSA value after this instruction on any path through this
65
+ // / instruction.
66
+ enum class UseLifetimeConstraint {
67
+ // / This use requires the SSA value to be live after the given instruction's
68
+ // / execution.
69
+ MustBeLive,
70
+
71
+ // / This use invalidates the given SSA value.
72
+ // /
73
+ // / This means that the given SSA value can not have any uses that are
74
+ // / reachable from this instruction. When a value has owned semantics this
75
+ // / means the SSA value is destroyed at this point. When a value has
76
+ // / guaranteed (i.e. shared borrow) semantics this means that the program
77
+ // / has left the scope of the borrowed SSA value and said value can not be
78
+ // / used.
79
+ MustBeInvalidated,
80
+ };
81
+
82
+ llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
83
+ UseLifetimeConstraint constraint);
84
+
58
85
// / A value representing the specific ownership semantics that a SILValue may
59
86
// / have.
60
87
struct ValueOwnershipKind {
@@ -64,27 +91,23 @@ struct ValueOwnershipKind {
64
91
// / with Trivial ownership kind can be used. Other side effects (e.g. Memory
65
92
// / dependencies) must still be respected. A SILValue with Trivial ownership
66
93
// / kind must be of Trivial SILType (i.e. SILType::isTrivial(SILModule &)
67
- // / must
68
- // / return true).
94
+ // / must return true).
69
95
// /
70
96
// / Some examples of SIL types with Trivial ownership are: Builtin.Int32,
71
97
// / Builtin.RawPointer, aggregates containing all trivial types.
72
98
Trivial,
73
99
74
100
// / A SILValue with `Unowned` ownership kind is an independent value that
75
- // / has
76
- // / a lifetime that is only guaranteed to last until the next program
77
- // / visible
78
- // / side-effect. To maintain the lifetime of an unowned value, it must be
79
- // / converted to an owned representation via a copy_value.
101
+ // / has a lifetime that is only guaranteed to last until the next program
102
+ // / visible side-effect. To maintain the lifetime of an unowned value, it
103
+ // / must be converted to an owned representation via a copy_value.
80
104
// /
81
105
// / Unowned ownership kind occurs mainly along method/function boundaries in
82
106
// / between Swift and Objective-C code.
83
107
Unowned,
84
108
85
109
// / A SILValue with `Owned` ownership kind is an independent value that has
86
- // / an
87
- // / ownership independent of any other ownership imbued within it. The
110
+ // / an ownership independent of any other ownership imbued within it. The
88
111
// / SILValue must be paired with a consuming operation that ends the SSA
89
112
// / value's lifetime exactly once along all paths through the program.
90
113
Owned,
@@ -105,10 +128,9 @@ struct ValueOwnershipKind {
105
128
Guaranteed,
106
129
107
130
// / A SILValue with undefined ownership. It can pair with /Any/ ownership
108
- // / kinds . This means that it could take on /any/ ownership semantics. This
131
+ // / kinds. This means that it could take on /any/ ownership semantics. This
109
132
// / is meant only to model SILUndef and to express certain situations where
110
- // / we
111
- // / use unqualified ownership. Expected to tighten over time.
133
+ // / we use unqualified ownership. Expected to tighten over time.
112
134
Any,
113
135
114
136
LastValueOwnershipKind = Any,
@@ -151,6 +173,23 @@ struct ValueOwnershipKind {
151
173
ValueOwnershipKind getProjectedOwnershipKind (SILModule &M,
152
174
SILType Proj) const ;
153
175
176
+ // / Return the lifetime constraint semantics for this
177
+ // / ValueOwnershipKind when forwarding ownership.
178
+ // /
179
+ // / This is MustBeInvalidated for Owned and MustBeLive for all other ownership
180
+ // / kinds.
181
+ UseLifetimeConstraint getForwardingLifetimeConstraint () const {
182
+ switch (Value) {
183
+ case ValueOwnershipKind::Trivial:
184
+ case ValueOwnershipKind::Any:
185
+ case ValueOwnershipKind::Guaranteed:
186
+ case ValueOwnershipKind::Unowned:
187
+ return UseLifetimeConstraint::MustBeLive;
188
+ case ValueOwnershipKind::Owned:
189
+ return UseLifetimeConstraint::MustBeInvalidated;
190
+ }
191
+ }
192
+
154
193
// / Returns true if \p Other can be merged successfully with this, implying
155
194
// / that the two ownership kinds are "compatibile".
156
195
// /
@@ -347,6 +386,149 @@ class SILValue {
347
386
DeadEndBlocks *DEBlocks = nullptr ) const ;
348
387
};
349
388
389
+ // / A map from a ValueOwnershipKind that an operand can accept to a
390
+ // / UseLifetimeConstraint that describes the effect that the operand's use has
391
+ // / on the underlying value. If a ValueOwnershipKind is not in this map then
392
+ // / matching an operand with the value results in an ill formed program.
393
+ // /
394
+ // / So for instance, a map could specify that if a value is used as an owned
395
+ // / parameter, then the use implies that the original value is destroyed at that
396
+ // / point. In contrast, if the value is used as a guaranteed parameter, then the
397
+ // / liveness constraint just requires that the value remains alive at the use
398
+ // / point.
399
+ struct OperandOwnershipKindMap {
400
+ // One bit for if a value exists and if the value exists, what the
401
+ // ownership constraint is. These are stored as pairs.
402
+ //
403
+ // NOTE: We are burning 1 bit per unset value. But this is without
404
+ // matter since we are always going to need less bits than 64, so we
405
+ // should always have a small case SmallBitVector, so there is no
406
+ // difference in size.
407
+ static constexpr unsigned NUM_DATA_BITS =
408
+ 2 * (unsigned (ValueOwnershipKind::LastValueOwnershipKind) + 1 );
409
+
410
+ // / A bit vector representing our "map". Given a ValueOwnershipKind k, if the
411
+ // / operand can accept k, the unsigned(k)*2 bit will be set to true. Assuming
412
+ // / that bit is set, the unsigned(k)*2+1 bit is set to the use lifetime
413
+ // / constraint provided by the value.
414
+ SmallBitVector data;
415
+
416
+ OperandOwnershipKindMap () : data(NUM_DATA_BITS) {}
417
+ OperandOwnershipKindMap (ValueOwnershipKind kind,
418
+ UseLifetimeConstraint constraint)
419
+ : data(NUM_DATA_BITS) {
420
+ add (kind, constraint);
421
+ }
422
+
423
+ // / Return the OperandOwnershipKindMap that tests for compatibility with
424
+ // / ValueOwnershipKind kind. This means that it will accept a element whose
425
+ // / ownership is ValueOwnershipKind::Any.
426
+ static OperandOwnershipKindMap
427
+ compatibilityMap (ValueOwnershipKind kind, UseLifetimeConstraint constraint) {
428
+ OperandOwnershipKindMap set;
429
+ set.addCompatibilityConstraint (kind, constraint);
430
+ return set;
431
+ }
432
+
433
+ // / Return a map that is compatible with any and all ValueOwnershipKinds
434
+ // / except for \p kind.
435
+ static OperandOwnershipKindMap
436
+ compatibleWithAllExcept (ValueOwnershipKind kind) {
437
+ OperandOwnershipKindMap map;
438
+ unsigned index = 0 ;
439
+ unsigned end = unsigned (ValueOwnershipKind::LastValueOwnershipKind) + 1 ;
440
+ for (; index != end; ++index) {
441
+ if (ValueOwnershipKind (index) == kind) {
442
+ continue ;
443
+ }
444
+ map.add (ValueOwnershipKind (index), UseLifetimeConstraint::MustBeLive);
445
+ }
446
+ return map;
447
+ }
448
+
449
+ // / Create a map that has compatibility constraints for each of the
450
+ // / ValueOwnershipKind, UseLifetimeConstraints in \p args.
451
+ static OperandOwnershipKindMap
452
+ compatibilityMap (std::initializer_list<
453
+ std::pair<ValueOwnershipKind, UseLifetimeConstraint>>
454
+ args) {
455
+ OperandOwnershipKindMap map;
456
+ for (auto &p : args) {
457
+ map.addCompatibilityConstraint (p.first , p.second );
458
+ }
459
+ return map;
460
+ }
461
+
462
+ // / Return a map that states that an operand can take any ownership with each
463
+ // / ownership having a must be live constraint.
464
+ static OperandOwnershipKindMap allLive () {
465
+ OperandOwnershipKindMap map;
466
+ unsigned index = 0 ;
467
+ unsigned end = unsigned (ValueOwnershipKind::LastValueOwnershipKind) + 1 ;
468
+ while (index != end) {
469
+ map.add (ValueOwnershipKind (index), UseLifetimeConstraint::MustBeLive);
470
+ ++index;
471
+ }
472
+ return map;
473
+ }
474
+
475
+ // / Specify that the operand associated with this set can accept a value with
476
+ // / ValueOwnershipKind \p kind. The value provided by the operand will have a
477
+ // / new ownership enforced constraint defined by \p constraint.
478
+ void add (ValueOwnershipKind kind, UseLifetimeConstraint constraint) {
479
+ unsigned index = unsigned (kind);
480
+ unsigned kindOffset = index * 2 ;
481
+ unsigned constraintOffset = index * 2 + 1 ;
482
+
483
+ // If we have already put this kind into the map, we require the constraint
484
+ // offset to be the same, i.e. we only allow for a kind to be added twice if
485
+ // the constraint is idempotent. We assert otherwise.
486
+ assert ((!data[kindOffset] || UseLifetimeConstraint (bool (
487
+ data[constraintOffset])) == constraint) &&
488
+ " Adding kind twice to the map with different constraints?!" );
489
+ data[kindOffset] = true ;
490
+ data[constraintOffset] = bool (constraint);
491
+ }
492
+
493
+ void addCompatibilityConstraint (ValueOwnershipKind kind,
494
+ UseLifetimeConstraint constraint) {
495
+ add (ValueOwnershipKind::Any, UseLifetimeConstraint::MustBeLive);
496
+ add (kind, constraint);
497
+ }
498
+
499
+ bool canAcceptKind (ValueOwnershipKind kind) const {
500
+ unsigned index = unsigned (kind);
501
+ unsigned kindOffset = index * 2 ;
502
+ return data[kindOffset];
503
+ }
504
+
505
+ UseLifetimeConstraint getLifetimeConstraint (ValueOwnershipKind kind) const ;
506
+
507
+ void print (llvm::raw_ostream &os) const ;
508
+ LLVM_ATTRIBUTE_DEPRECATED (void dump () const , "only for use in a debugger");
509
+ };
510
+
511
+ inline llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
512
+ OperandOwnershipKindMap map) {
513
+ map.print (os);
514
+ return os;
515
+ }
516
+
517
+ // Out of line to work around lack of forward declaration for operator <<.
518
+ inline UseLifetimeConstraint
519
+ OperandOwnershipKindMap::getLifetimeConstraint (ValueOwnershipKind kind) const {
520
+ #ifndef NDEBUG
521
+ if (!canAcceptKind (kind)) {
522
+ llvm::errs () << " Can not lookup lifetime constraint: " << kind
523
+ << " . Not in map!\n "
524
+ << *this ;
525
+ llvm_unreachable (" standard error assertion" );
526
+ }
527
+ #endif
528
+ unsigned constraintOffset = unsigned (kind) * 2 + 1 ;
529
+ return UseLifetimeConstraint (data[constraintOffset]);
530
+ }
531
+
350
532
// / A formal SIL reference to a value, suitable for use as a stored
351
533
// / operand.
352
534
class Operand {
@@ -413,10 +595,20 @@ class Operand {
413
595
SILInstruction *getUser () { return Owner; }
414
596
const SILInstruction *getUser () const { return Owner; }
415
597
416
- // / getOperandNumber - Return which operand this is in the operand list of the
417
- // / using instruction.
598
+ // / Return which operand this is in the operand list of the using instruction.
418
599
unsigned getOperandNumber () const ;
419
600
601
+ // / Return the static map of ValueOwnershipKinds that this operand can
602
+ // / potentially have to the UseLifetimeConstraint associated with that
603
+ // / ownership kind
604
+ // /
605
+ // / NOTE: This is implemented in OperandOwnershipKindMapClassifier.cpp.
606
+ // /
607
+ // / NOTE: The default argument isSubValue is a temporary staging flag that
608
+ // / will be removed once borrow scoping is checked by the normal verifier.
609
+ OperandOwnershipKindMap
610
+ getOwnershipKindMap (bool isForwardingSubValue = false ) const ;
611
+
420
612
private:
421
613
void removeFromCurrent () {
422
614
if (!Back) return ;
0 commit comments