@@ -1723,9 +1723,13 @@ struct PartitionOpBuilder {
17231723 PartitionOp::Send (lookupValueID (representative), op));
17241724 }
17251725
1726- void addUndoSend (SILValue representative, SILInstruction *unsendingInst) {
1726+ void addUndoSend (TrackableValue value, SILInstruction *unsendingInst) {
1727+ if (value.isSendable ())
1728+ return ;
1729+
1730+ auto representative = value.getRepresentative ().getValue ();
17271731 assert (valueHasID (representative) &&
1728- " value should already have been encountered" );
1732+ " sent value should already have been encountered" );
17291733
17301734 currentInstPartitionOps->emplace_back (
17311735 PartitionOp::UndoSend (lookupValueID (representative), unsendingInst));
@@ -2430,7 +2434,7 @@ class PartitionOpTranslator {
24302434 }))
24312435 continue ;
24322436
2433- builder.addUndoSend (trackedArgValue. getRepresentative (). getValue () , ai);
2437+ builder.addUndoSend (trackedArgValue, ai);
24342438 }
24352439 }
24362440 }
@@ -2567,60 +2571,53 @@ class PartitionOpTranslator {
25672571 // gather our non-sending parameters.
25682572 SmallVector<Operand *, 8 > nonSendingParameters;
25692573 SmallVector<Operand *, 8 > sendingIndirectResults;
2570- if (fas.getNumArguments ()) {
2571- // NOTE: We want to process indirect parameters as if they are
2572- // parameters... so we process them in nonSendingParameters.
2573- for (auto &op : fas.getOperandsWithoutSelf ()) {
2574- // If op is the callee operand, skip it.
2575- if (fas.isCalleeOperand (op))
2576- continue ;
25772574
2578- if (fas.isSending (op)) {
2579- if (fas.isIndirectResultOperand (op)) {
2580- sendingIndirectResults.push_back (&op);
2581- continue ;
2582- }
2575+ // NOTE: We want to process indirect parameters as if they are
2576+ // parameters... so we process them in nonSendingParameters.
2577+ for (auto &op : fas->getAllOperands ()) {
2578+ // If op is the callee operand or type dependent operand, skip it.
2579+ if (op.isTypeDependent ())
2580+ continue ;
25832581
2584- // Attempt to lookup the value we are passing as sending. We want to
2585- // require/send value if it is non-Sendable and require its base if it
2586- // is non-Sendable as well.
2587- if (auto lookupResult = tryToTrackValue (op.get ())) {
2588- builder.addRequire (*lookupResult);
2589- builder.addSend (lookupResult->value , &op);
2590- }
2591- } else {
2592- nonSendingParameters.push_back (&op);
2582+ if (fas.isCalleeOperand (op)) {
2583+ if (auto calleeResult = tryToTrackValue (op.get ())) {
2584+ builder.addRequire (*calleeResult);
25932585 }
2586+ continue ;
25942587 }
2595- }
25962588
2597- // If our self parameter was sending, send it. Otherwise, just
2598- // stick it in the non self operand values array and run multiassign on
2599- // it.
2600- if (fas.hasSelfArgument ()) {
2601- auto &selfOperand = fas.getSelfArgumentOperand ();
2602- if (fas.getArgumentParameterInfo (selfOperand)
2603- .hasOption (SILParameterInfo::Sending)) {
2604- if (auto lookupResult = tryToTrackValue (selfOperand.get ())) {
2605- builder.addRequire (*lookupResult);
2606- builder.addSend (lookupResult->value , &selfOperand);
2607- }
2608- } else {
2609- nonSendingParameters.push_back (&selfOperand);
2589+ // If our parameter is not sending, just add it to the non-sending
2590+ // parameters array and continue.
2591+ if (!fas.isSending (op)) {
2592+ nonSendingParameters.push_back (&op);
2593+ continue ;
26102594 }
2611- }
26122595
2613- // Require our callee operand if it is non-Sendable.
2614- //
2615- // DISCUSSION: Even though we do not include our callee operand in the same
2616- // region as our operands/results, we still need to require that it is live
2617- // at the point of application. Otherwise, we will not emit errors if the
2618- // closure before this function application is already in the same region as
2619- // a sent value. In such a case, the function application must error.
2620- if (auto calleeResult = tryToTrackValue (fas.getCallee ())) {
2621- builder.addRequire (*calleeResult);
2596+ // Otherwise, first handle indirect result operands.
2597+ if (fas.isIndirectResultOperand (op)) {
2598+ sendingIndirectResults.push_back (&op);
2599+ continue ;
2600+ }
2601+
2602+ // Attempt to lookup the value we are passing as sending. We want to
2603+ // require/send value if it is non-Sendable and require its base if it
2604+ // is non-Sendable as well.
2605+ if (auto lookupResult = tryToTrackValue (op.get ())) {
2606+ builder.addRequire (*lookupResult);
2607+ builder.addSend (lookupResult->value , &op);
2608+ }
26222609 }
26232610
2611+ SWIFT_DEFER {
2612+ for (auto &op : fas->getAllOperands ()) {
2613+ if (!fas.isInOutSending (op))
2614+ continue ;
2615+ if (auto lookupResult = tryToTrackValue (op.get ())) {
2616+ builder.addUndoSend (lookupResult->value , op.getUser ());
2617+ }
2618+ }
2619+ };
2620+
26242621 SmallVector<SILValue, 8 > applyResults;
26252622 getApplyResults (*fas, applyResults);
26262623
@@ -2688,36 +2685,77 @@ class PartitionOpTranslator {
26882685
26892686 // / Handles the semantics for SIL applies that cross isolation.
26902687 // /
2691- // / Semantically this causes all arguments of the applysite to be sent.
2688+ // / Semantically we are attempting to implement the following:
2689+ // /
2690+ // / * Step 1: Require all non-sending parameters and then send those
2691+ // / parameters. We perform all of the requires first and the sends second
2692+ // / since all of the parameters are getting sent to the same isolation
2693+ // / domains and become part of the same region in our callee. So in a
2694+ // / certain sense, we are performing a require over the entire merge of the
2695+ // / parameter regions and then send each constituant part of the region
2696+ // / without requiring again so we do not emit use-after-send diagnostics.
2697+ // /
2698+ // / * Step 2: Require/Send each of the sending parameters one by one. This
2699+ // / includes both 'sending' and 'inout sending' parameters. We purposely
2700+ // / interleave the require/send operations to ensure that if one passes a
2701+ // / value twice to different 'sending' or 'inout sending' parameters, we
2702+ // / will emit an error.
2703+ // /
2704+ // / * Step 3: Unsend each of the unsending parameters. Since our caller
2705+ // / ensures that 'inout sending' parameters are disconnected on return and
2706+ // / are in different regions from all other parameters, we can just simply
2707+ // / unsend the parameter so we can use it again later.
26922708 void translateIsolationCrossingSILApply (FullApplySite applySite) {
2693- // Require all operands first before we emit a send.
2694- for (auto op : applySite.getArguments ()) {
2695- if (auto lookupResult = tryToTrackValue (op)) {
2709+ SmallVector<TrackableValue, 8 > inoutSendingParams;
2710+
2711+ // First go through and require all of our operands that are not 'sending'
2712+ for (auto &op : applySite.getArgumentOperands ()) {
2713+ if (applySite.isSending (op))
2714+ continue ;
2715+ if (auto lookupResult = tryToTrackValue (op.get ()))
26962716 builder.addRequire (*lookupResult);
2697- }
26982717 }
26992718
2700- auto handleSILOperands = [&](MutableArrayRef<Operand> operands) {
2701- for (auto &op : operands) {
2702- if (auto lookupResult = tryToTrackValue (op.get ())) {
2703- builder.addSend (lookupResult->value , &op);
2704- }
2719+ // Then go through our operands again and send all of our non-sending
2720+ // parameters. We do not interleave these sends with our requires since we
2721+ // are considering these values to be merged into the same region. We could
2722+ // also merge them in the caller but there is no point in doing so
2723+ // semantically since the values cannot be used again locally.
2724+ for (auto &op : applySite.getOperandsWithoutIndirectResults ()) {
2725+ if (applySite.isSending (op))
2726+ continue ;
2727+ if (auto lookupResult = tryToTrackValue (op.get ())) {
2728+ builder.addSend (lookupResult->value , &op);
27052729 }
27062730 };
27072731
2708- auto handleSILSelf = [&](Operand *self) {
2709- if (auto lookupResult = tryToTrackValue (self->get ())) {
2710- builder.addSend (lookupResult->value , self);
2732+ // Then go through our 'sending' params and require/send each in sequence.
2733+ //
2734+ // We do this interleaved so that if a value is passed to multiple 'sending'
2735+ // parameters, we emit errors.
2736+ for (auto &op : applySite.getOperandsWithoutIndirectResults ()) {
2737+ if (!applySite.isSending (op))
2738+ continue ;
2739+ auto lookupResult = tryToTrackValue (op.get ());
2740+ if (!lookupResult)
2741+ continue ;
2742+ builder.addRequire (*lookupResult);
2743+ builder.addSend (lookupResult->value , &op);
2744+ }
2745+
2746+ // Now use a SWIFT_DEFER so that when the function is done executing, we
2747+ // unsend 'inout sending' params.
2748+ SWIFT_DEFER {
2749+ for (auto &op : applySite.getOperandsWithoutIndirectResults ()) {
2750+ if (!applySite.isInOutSending (op))
2751+ continue ;
2752+ auto lookupResult = tryToTrackValue (op.get ());
2753+ if (!lookupResult)
2754+ continue ;
2755+ builder.addUndoSend (lookupResult->value , *applySite);
27112756 }
27122757 };
27132758
2714- if (applySite.hasSelfArgument ()) {
2715- handleSILOperands (applySite.getOperandsWithoutIndirectResultsOrSelf ());
2716- handleSILSelf (&applySite.getSelfArgumentOperand ());
2717- } else {
2718- handleSILOperands (applySite.getOperandsWithoutIndirectResults ());
2719- }
2720-
27212759 // Create a new assign fresh for each one of our values and unless our
27222760 // return value is sending, emit an extra error bit on the results that are
27232761 // non-Sendable.
0 commit comments