@@ -743,7 +743,7 @@ forwardIntoSubtree(SILGenFunction &SGF, SILLocation loc,
743
743
(void )consumptionKind;
744
744
745
745
// If we have an object and it is take always, we need to borrow the value
746
- // since we do not own the value at this point .
746
+ // since our subtree does not own the value.
747
747
if (outerMV.getType ().isObject ()) {
748
748
assert (consumptionKind == CastConsumptionKind::TakeAlways &&
749
749
" Object without cleanup that is not take_always?!" );
@@ -1429,45 +1429,59 @@ emitTupleDispatch(ArrayRef<RowToSpecialize> rows, ConsumableManagedValue src,
1429
1429
1430
1430
// If our source is an address that is loadable, perform a load_borrow.
1431
1431
if (src.getType ().isAddress () && src.getType ().isLoadable (SGF.getModule ())) {
1432
+ // We should only see take_on_success if we have a base type that is address
1433
+ // only.
1434
+ assert (src.getFinalConsumption () != CastConsumptionKind::TakeOnSuccess &&
1435
+ " Can only occur if base type is address only?!" );
1432
1436
src = {SGF.B .createLoadBorrow (loc, src.getFinalManagedValue ()),
1433
1437
CastConsumptionKind::BorrowAlways};
1434
1438
}
1435
1439
1436
1440
// Then if we have an object...
1437
1441
if (src.getType ().isObject ()) {
1438
- // Make sure that if we ahve a copy_on_success, non-trivial value that we do
1442
+ // Make sure that if we have a copy_on_success, non-trivial value that we do
1439
1443
// not have a value with @owned ownership.
1440
1444
assert ((!src.getType ().isTrivial (SGF.getModule ()) ||
1441
1445
src.getFinalConsumption () != CastConsumptionKind::CopyOnSuccess ||
1442
1446
src.getOwnershipKind () != ValueOwnershipKind::Owned) &&
1443
1447
" @owned value without cleanup + copy_on_success" );
1444
1448
1445
- // If we have are asked to perform TakeOnSuccess, borrow the value instead.
1446
- //
1447
- // The reason why do this for TakeOnSuccess is that we want to not have to
1448
- // deal with unforwarding of aggregate tuples in failing cases since that
1449
- // causes ownership invariants to be violated since we already forwarded the
1450
- // aggregate to create cleanups on its elements.
1451
- //
1452
- // In contrast, we do still want to allow for TakeAlways variants to not
1453
- // need to borrow, so we do not borrow if we take always.
1454
- if (!src.getType ().isTrivial (SGF.getModule ()) &&
1455
- src.getFinalConsumption () == CastConsumptionKind::TakeOnSuccess) {
1456
- src = {src.getFinalManagedValue ().borrow (SGF, loc),
1457
- CastConsumptionKind::BorrowAlways};
1458
- }
1449
+ // We should only see take_on_success if we have a base type that is address
1450
+ // only.
1451
+ assert (src.getFinalConsumption () != CastConsumptionKind::TakeOnSuccess &&
1452
+ " Can only occur if base type is address only?!" );
1459
1453
1460
1454
// Then perform a forward or reborrow destructure on the object.
1461
1455
return emitTupleObjectDispatch (rows, src, handleCase, outerFailure);
1462
1456
}
1463
1457
1458
+ // Construct the specialized rows.
1459
+ SmallVector<SpecializedRow, 4 > specializedRows;
1460
+ specializedRows.resize (rows.size ());
1461
+ for (unsigned i = 0 , e = rows.size (); i != e; ++i) {
1462
+ specializedRows[i].RowIndex = rows[i].RowIndex ;
1463
+
1464
+ auto pattern = cast<TuplePattern>(rows[i].Pattern );
1465
+ for (auto &elt : pattern->getElements ()) {
1466
+ specializedRows[i].Patterns .push_back (elt.getPattern ());
1467
+ }
1468
+ }
1469
+
1464
1470
// At this point we know that we must have an address only type, since we
1465
1471
// would have loaded it earlier.
1466
1472
SILValue v = src.getFinalManagedValue ().forward (SGF);
1467
1473
assert (v->getType ().isAddressOnly (SGF.getModule ()) &&
1468
1474
" Loadable values were handled earlier" );
1469
1475
1470
- SmallVector<ConsumableManagedValue, 4 > destructured;
1476
+ // The destructured tuple that we pass off to our sub pattern. This may
1477
+ // contain values that we have performed a load_borrow from subsequent to
1478
+ // "performing a SILGenPattern borrow".
1479
+ SmallVector<ConsumableManagedValue, 4 > subPatternArgs;
1480
+
1481
+ // An array of values that have the same underlying values as our
1482
+ // subPatternArgs, but may have a different cleanup and final consumption
1483
+ // kind. These are at +1 and are unforwarded.
1484
+ SmallVector<ConsumableManagedValue, 4 > unforwardArgs;
1471
1485
1472
1486
// Break down the values.
1473
1487
auto tupleSILTy = v->getType ();
@@ -1476,65 +1490,87 @@ emitTupleDispatch(ArrayRef<RowToSpecialize> rows, ConsumableManagedValue src,
1476
1490
auto &fieldTL = SGF.getTypeLowering (fieldTy);
1477
1491
1478
1492
SILValue member = SGF.B .createTupleElementAddr (loc, v, i, fieldTy);
1479
- ConsumableManagedValue memberCMV;
1493
+ // Inline constructor.
1494
+ auto memberCMV = ([&]() -> ConsumableManagedValue {
1495
+ if (!fieldTL.isLoadable ()) {
1496
+ // If we have an address only type, just get the managed
1497
+ // subobject.
1498
+ return getManagedSubobject (SGF, member, fieldTL,
1499
+ src.getFinalConsumption ());
1500
+ }
1480
1501
1481
- // If we have a loadable sub-type of our tuple...
1482
- if (fieldTL.isLoadable ()) {
1502
+ // If we have a loadable type, then we have a loadable sub-type of the
1503
+ // underlying address only tuple.
1504
+ auto memberMV = ManagedValue::forUnmanaged (member);
1483
1505
switch (src.getFinalConsumption ()) {
1484
1506
case CastConsumptionKind::TakeAlways: {
1485
- // and our consumption is take always, perform a load [take] and
1486
- // continue.
1487
- auto memberMV = ManagedValue::forUnmanaged (member);
1488
- memberCMV = {SGF.B .createLoadTake (loc, memberMV),
1489
- CastConsumptionKind::TakeAlways};
1490
- break ;
1507
+ // If our original source value is take always, perform a load [take].
1508
+ return {SGF.B .createLoadTake (loc, memberMV),
1509
+ CastConsumptionKind::TakeAlways};
1510
+ }
1511
+ case CastConsumptionKind::TakeOnSuccess: {
1512
+ // If we have a take_on_success, we propagate down the member as a +1
1513
+ // address value and do not load.
1514
+ //
1515
+ // DISCUSSION: Unforwarding objects violates ownership since
1516
+ // unforwarding relies on forwarding an aggregate into subvalues and
1517
+ // on failure disabling the subvalue cleanups and re-enabling the
1518
+ // cleanup for the aggregate (which was already destroyed). So we are
1519
+ // forced to use an address here so we can forward/unforward this
1520
+ // value. We maintain our invariants that loadable types are always
1521
+ // loaded and are never take on success by passing down to our
1522
+ // subPattern a borrow of this value. See below.
1523
+ return getManagedSubobject (SGF, member, fieldTL,
1524
+ src.getFinalConsumption ());
1491
1525
}
1492
- case CastConsumptionKind::TakeOnSuccess:
1493
1526
case CastConsumptionKind::CopyOnSuccess: {
1494
- // otherwise we have take on success or copy on success perform a
1495
- // load_borrow.
1527
+ // We translate copy_on_success => borrow_always.
1496
1528
auto memberMV = ManagedValue::forUnmanaged (member);
1497
- memberCMV = {SGF.B .createLoadBorrow (loc, memberMV),
1498
- CastConsumptionKind::BorrowAlways};
1499
- break ;
1529
+ return {SGF.B .createLoadBorrow (loc, memberMV),
1530
+ CastConsumptionKind::BorrowAlways};
1500
1531
}
1501
- case CastConsumptionKind::BorrowAlways:
1502
- llvm_unreachable (" Borrow always can not be used on objects" );
1532
+ case CastConsumptionKind::BorrowAlways: {
1533
+ llvm_unreachable (
1534
+ " Borrow always can only occur along object only code paths" );
1503
1535
}
1504
- } else {
1505
- // Otherwise, if we have an address only type, just get the managed
1506
- // subobject.
1507
- memberCMV =
1508
- getManagedSubobject (SGF, member, fieldTL, src.getFinalConsumption ());
1509
- }
1510
-
1511
- destructured.push_back (memberCMV);
1512
- }
1513
-
1514
- // Construct the specialized rows.
1515
- SmallVector<SpecializedRow, 4 > specializedRows;
1516
- specializedRows.resize (rows.size ());
1517
- for (unsigned i = 0 , e = rows.size (); i != e; ++i) {
1518
- specializedRows[i].RowIndex = rows[i].RowIndex ;
1536
+ }
1537
+ }());
1519
1538
1520
- auto pattern = cast<TuplePattern>(rows[i].Pattern );
1521
- for (auto &elt : pattern->getElements ()) {
1522
- specializedRows[i].Patterns .push_back (elt.getPattern ());
1539
+ // If we aren't loadable, add to the unforward array.
1540
+ if (!fieldTL.isLoadable ()) {
1541
+ unforwardArgs.push_back (memberCMV);
1542
+ } else {
1543
+ // If we have a loadable type that we didn't load, we must have had a
1544
+ // take_on_success address. This means that our parent cleanup is
1545
+ // currently persistently active, so we needed to propagate an active +1
1546
+ // cleanup on our address so we can take if we actually succeed. That
1547
+ // being said, we do not want to pass objects with take_on_success into
1548
+ // the actual subtree. So we perform a load_borrow at this point. This
1549
+ // will ensure that we will always finish the end_borrow before we jumped
1550
+ // to a failure point, but at the same time the original +1 value will be
1551
+ // appropriately destroyed/forwarded around.
1552
+ if (memberCMV.getType ().isAddress ()) {
1553
+ unforwardArgs.push_back (memberCMV);
1554
+ auto val = memberCMV.getFinalManagedValue ();
1555
+ memberCMV = {SGF.B .createLoadBorrow (loc, val),
1556
+ CastConsumptionKind::BorrowAlways};
1557
+ }
1523
1558
}
1559
+ subPatternArgs.push_back (memberCMV);
1524
1560
}
1525
1561
1526
1562
// Maybe revert to the original cleanups during failure branches.
1527
1563
const FailureHandler *innerFailure = &outerFailure;
1528
1564
FailureHandler specializedFailure = [&](SILLocation loc) {
1529
1565
ArgUnforwarder unforwarder (SGF);
1530
- unforwarder.unforwardBorrowedValues (src, destructured );
1566
+ unforwarder.unforwardBorrowedValues (src, unforwardArgs );
1531
1567
outerFailure (loc);
1532
1568
};
1533
1569
if (ArgUnforwarder::requiresUnforwarding (SGF, src))
1534
1570
innerFailure = &specializedFailure;
1535
1571
1536
1572
// Recurse.
1537
- handleCase (destructured , specializedRows, *innerFailure);
1573
+ handleCase (subPatternArgs , specializedRows, *innerFailure);
1538
1574
}
1539
1575
1540
1576
static CanType getTargetType (const RowToSpecialize &row) {
@@ -1564,46 +1600,53 @@ emitCastOperand(SILGenFunction &SGF, SILLocation loc,
1564
1600
return src;
1565
1601
}
1566
1602
1603
+ // We know that we must have a loadable type at this point since address only
1604
+ // types do not need reabstraction and are addresses. So we should have exited
1605
+ // above already.
1606
+ assert (src.getType ().isLoadable (SGF.getModule ()) &&
1607
+ " Should have a loadable value at this point" );
1608
+
1609
+ // Since our finalValue is loadable, we could not have had a take_on_success
1610
+ // here.
1611
+ assert (src.getFinalConsumption () != CastConsumptionKind::TakeOnSuccess &&
1612
+ " Loadable types can not have take_on_success?!" );
1613
+
1567
1614
std::unique_ptr<TemporaryInitialization> init;
1568
1615
SGFContext ctx;
1569
1616
if (requiresAddress) {
1570
1617
init = SGF.emitTemporary (loc, srcAbstractTL);
1571
1618
ctx = SGFContext (init.get ());
1572
1619
}
1573
1620
1574
- ManagedValue substValue = SGF.getManagedValue (loc, src);
1575
- ManagedValue finalValue;
1621
+ // This will always produce a +1 take always value no matter what src's
1622
+ // ownership is.
1623
+ ManagedValue finalValue = SGF.getManagedValue (loc, src);
1576
1624
if (hasAbstraction) {
1577
- assert (src.getType ().isObject () &&
1578
- " address-only type with abstraction difference?" );
1579
- // Produce the value at +1.
1580
- finalValue = SGF.emitSubstToOrigValue (loc, substValue,
1581
- abstraction, sourceType, ctx);
1582
- } else {
1583
- finalValue = substValue;
1584
- }
1585
-
1586
- if (requiresAddress) {
1587
- if (finalValue.getOwnershipKind () == ValueOwnershipKind::Guaranteed)
1588
- finalValue = finalValue.copy (SGF, loc);
1589
- SGF.B .emitStoreValueOperation (loc, finalValue.forward (SGF),
1590
- init->getAddress (),
1591
- StoreOwnershipQualifier::Init);
1592
- init->finishInitialization (SGF);
1593
-
1594
- // If we had borrow_always, we need to switch to copy_on_success since
1595
- // that is the address only variant of borrow_always.
1596
- auto consumption = src.getFinalConsumption ();
1597
- if (consumption == CastConsumptionKind::BorrowAlways)
1598
- consumption = CastConsumptionKind::CopyOnSuccess;
1599
- ConsumableManagedValue result = {init->getManagedAddress (), consumption};
1600
- if (ArgUnforwarder::requiresUnforwarding (SGF, src))
1601
- borrowedValues.push_back (result);
1602
-
1603
- return result;
1604
- }
1605
-
1606
- return ConsumableManagedValue::forOwned (finalValue);
1625
+ // Reabstract the value if we need to. This should produce a +1 value as
1626
+ // well.
1627
+ finalValue =
1628
+ SGF.emitSubstToOrigValue (loc, finalValue, abstraction, sourceType, ctx);
1629
+ }
1630
+ assert (finalValue.isPlusOne (SGF));
1631
+
1632
+ // If we at this point do not require an address, return final value. We know
1633
+ // that it is a +1 take always value.
1634
+ if (!requiresAddress) {
1635
+ return ConsumableManagedValue::forOwned (finalValue);
1636
+ }
1637
+
1638
+ // At this point, we know that we have a non-address only type since we are
1639
+ // materializing an object into memory and addresses can not be stored into
1640
+ // memory.
1641
+ SGF.B .emitStoreValueOperation (loc, finalValue.forward (SGF),
1642
+ init->getAddress (),
1643
+ StoreOwnershipQualifier::Init);
1644
+ init->finishInitialization (SGF);
1645
+
1646
+ // We know that either our initial value was already take_always or we made a
1647
+ // copy of the underlying value. In either case, we now have a take_always +1
1648
+ // value.
1649
+ return ConsumableManagedValue::forOwned (init->getManagedAddress ());
1607
1650
}
1608
1651
1609
1652
// / Perform specialized dispatch for a sequence of IsPatterns.
@@ -1938,27 +1981,18 @@ void PatternMatchEmission::emitEnumElementDispatch(
1938
1981
1939
1982
// If our source is an address that is loadable, perform a load_borrow.
1940
1983
if (src.getType ().isAddress () && src.getType ().isLoadable (SGF.getModule ())) {
1984
+ assert (src.getFinalConsumption () != CastConsumptionKind::TakeOnSuccess &&
1985
+ " Can only have take_on_success with address only values" );
1941
1986
src = {SGF.B .createLoadBorrow (loc, src.getFinalManagedValue ()),
1942
1987
CastConsumptionKind::BorrowAlways};
1943
1988
}
1944
1989
1945
1990
// If we have an object...
1946
1991
if (src.getType ().isObject ()) {
1947
- // And we have a non-trivial object type that we are asked to perform take
1948
- // on success for, borrow the value instead.
1949
- //
1950
- // The reason why do this for TakeOnSuccess is that we want to not have to
1951
- // deal with unforwarding of aggregate tuples in failing cases since that
1952
- // causes ownership invariants to be violated since we already forwarded the
1953
- // aggregate to create cleanups on its elements.
1954
- //
1955
- // In contrast, we do still want to allow for TakeAlways variants to not
1956
- // need to borrow, so we do not borrow if we take always.
1957
- if (!src.getType ().isTrivial (SGF.getModule ()) &&
1958
- src.getFinalConsumption () == CastConsumptionKind::TakeOnSuccess) {
1959
- src = {src.getFinalManagedValue ().borrow (SGF, loc),
1960
- CastConsumptionKind::BorrowAlways};
1961
- }
1992
+ // Do a quick assert that we do not have take_on_success. This should only
1993
+ // be passed take_on_success if src is an address only type.
1994
+ assert (src.getFinalConsumption () != CastConsumptionKind::TakeOnSuccess &&
1995
+ " Can only have take_on_success with address only values" );
1962
1996
1963
1997
// Finally perform the enum element dispatch.
1964
1998
return emitEnumElementObjectDispatch (rows, src, handleCase, outerFailure,
0 commit comments