@@ -934,115 +934,73 @@ class Partition {
934934// / A data structure that applies a series of PartitionOps to a single Partition
935935// / that it modifies.
936936// /
937- // / Apply the passed PartitionOp to this partition, performing its action. A
938- // / `handleFailure` closure can optionally be passed in that will be called if
939- // / a transferred region is required. The closure is given the PartitionOp
940- // / that failed, and the index of the SIL value that was required but
941- // / transferred. Additionally, a list of "nontransferrable" indices can be
942- // / passed in along with a handleTransferNonTransferrable closure. In the
943- // / event that a region containing one of the nontransferrable indices is
944- // / transferred, the closure will be called with the offending transfer.
937+ // / Callers use CRTP to modify its behavior. Please see the definition below of
938+ // / a "blank" subclass PartitionOpEvaluatorBaseImpl for a description of the
939+ // / methods needing to be implemented by other CRTP subclasses.
940+ template <typename Impl>
945941struct PartitionOpEvaluator {
942+ private:
943+ Impl &asImpl () { return *reinterpret_cast <Impl *>(this ); }
944+ const Impl &asImpl () const { return *reinterpret_cast <const Impl *>(this ); }
945+
946+ public:
946947 using Element = PartitionPrimitives::Element;
947948 using Region = PartitionPrimitives::Region;
948949 using TransferringOperandSetFactory =
949950 Partition::TransferringOperandSetFactory;
950951
952+ protected:
951953 TransferringOperandSetFactory &ptrSetFactory;
952954
953955 Partition &p;
954956
955- // / If this PartitionOp evaluator should emit log statements.
956- bool emitLog = true ;
957-
958- // / If set to a non-null function, then this callback will be called if we
959- // / discover a transferred value was used after it was transferred.
960- // /
961- // / The arguments passed to the closure are:
962- // /
963- // / 1. The PartitionOp that required the element to be alive.
964- // /
965- // / 2. The element in the PartitionOp that was asked to be alive.
966- // /
967- // / 3. The operand of the instruction that originally transferred the
968- // / region. Can be used to get the immediate value transferred or the
969- // / transferring instruction.
970- std::function<void (const PartitionOp &, Element, TransferringOperand)>
971- failureCallback = nullptr ;
972-
973- // / A list of elements that cannot be transferred. Whenever we transfer, we
974- // / check this list to see if we are transferring the element and then call
975- // / transferNonTransferrableCallback. This should consist only of function
976- // / arguments.
977- ArrayRef<Element> nonTransferrableElements = {};
978-
979- // / If set to a non-null function_ref, this is called if we detect a never
980- // / transferred element that was passed to a transfer instruction.
981- std::function<void (const PartitionOp &, Element)>
982- transferredNonTransferrableCallback = nullptr ;
983-
984- // / If set to a non-null function_ref, then this is used to determine if an
985- // / element is actor derived. If we determine that a region containing such an
986- // / element is transferred, we emit an error since actor regions cannot be
987- // / transferred.
988- std::function<bool (Element)> isActorDerivedCallback = nullptr ;
989-
990- // / Check if the representative value of \p elt is closure captured at \p
991- // / op.
992- // /
993- // / NOTE: We actually just use the user of \p op in our callbacks. The reason
994- // / why we do not just pass in that SILInstruction is that then we would need
995- // / to access the instruction in the evaluator which creates a problem when
996- // / since the operand we pass in is a dummy operand.
997- std::function<bool (Element elt, Operand *op)> isClosureCapturedCallback =
998- nullptr ;
999-
957+ public:
1000958 PartitionOpEvaluator (Partition &p,
1001959 TransferringOperandSetFactory &ptrSetFactory)
1002960 : ptrSetFactory(ptrSetFactory), p(p) {}
1003961
1004- // / A wrapper around the failure callback that checks if it is nullptr.
962+ // / Call shouldEmitVerboseLogging on our CRTP subclass.
963+ bool shouldEmitVerboseLogging () const {
964+ return asImpl ().shouldEmitVerboseLogging ();
965+ }
966+
967+ // / Call handleFailure on our CRTP subclass.
1005968 void handleFailure (const PartitionOp &op, Element elt,
1006969 TransferringOperand transferringOp) const {
1007- if (!failureCallback)
1008- return ;
1009- failureCallback (op, elt, transferringOp);
970+ return asImpl ().handleFailure (op, elt, transferringOp);
1010971 }
1011972
1012- // / A wrapper around transferNonTransferrableCallback that only calls it if it
1013- // / is not null.
973+ // / Call handleTransferNonTransferrable on our CRTP subclass.
1014974 void handleTransferNonTransferrable (const PartitionOp &op,
1015975 Element elt) const {
1016- if (!transferredNonTransferrableCallback)
1017- return ;
1018- transferredNonTransferrableCallback (op, elt);
976+ return asImpl ().handleTransferNonTransferrable (op, elt);
1019977 }
1020978
1021- // / A wrapper around isActorDerivedCallback that returns false if
1022- // / isActorDerivedCallback is nullptr and otherwise returns
1023- // / isActorDerivedCallback().
979+ // / Call isActorDerived on our CRTP subclass.
1024980 bool isActorDerived (Element elt) const {
1025- return bool (isActorDerivedCallback) && isActorDerivedCallback (elt);
981+ return asImpl (). isActorDerived (elt);
1026982 }
1027983
1028- // / A wraper around isClosureCapturedCallback that returns false if
1029- // / isClosureCapturedCallback is nullptr and otherwise returns
1030- // / isClosureCapturedCallback.
984+ // / Call isClosureCaptured on our CRTP subclass.
1031985 bool isClosureCaptured (Element elt, Operand *op) const {
1032- return bool (isClosureCapturedCallback) &&
1033- isClosureCapturedCallback (elt, op);
986+ return asImpl ().isClosureCaptured (elt, op);
987+ }
988+
989+ // / Call getNonTransferrableElements() on our CRTP subclass.
990+ ArrayRef<Element> getNonTransferrableElements () const {
991+ return asImpl ().getNonTransferrableElements ();
1034992 }
1035993
1036994 // / Apply \p op to the partition op.
1037995 void apply (const PartitionOp &op) const {
1038- if (emitLog ) {
996+ if (shouldEmitVerboseLogging () ) {
1039997 REGIONBASEDISOLATION_VERBOSE_LOG (llvm::dbgs () << " Applying: " ;
1040998 op.print (llvm::dbgs ()));
1041999 REGIONBASEDISOLATION_VERBOSE_LOG (llvm::dbgs () << " Before: " ;
10421000 p.print (llvm::dbgs ()));
10431001 }
10441002 SWIFT_DEFER {
1045- if (emitLog ) {
1003+ if (shouldEmitVerboseLogging () ) {
10461004 REGIONBASEDISOLATION_VERBOSE_LOG (llvm::dbgs () << " After: " ;
10471005 p.print (llvm::dbgs ()));
10481006 }
@@ -1078,7 +1036,7 @@ struct PartitionOpEvaluator {
10781036
10791037 // check if any nontransferrables are transferred here, and handle the
10801038 // failure if so
1081- for (Element nonTransferrable : nonTransferrableElements ) {
1039+ for (Element nonTransferrable : getNonTransferrableElements () ) {
10821040 assert (
10831041 p.isTrackingElement (nonTransferrable) &&
10841042 " nontransferrables should be function args and self, and therefore"
@@ -1167,6 +1125,75 @@ struct PartitionOpEvaluator {
11671125 }
11681126};
11691127
1128+ // / A base implementation that can be used to default initialize CRTP
1129+ // / subclasses. Only used to implement base functionality for subclass
1130+ // / CRTPs. For true basic evaluation, use PartitionOpEvaluatorBasic below.
1131+ template <typename Subclass>
1132+ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
1133+ using Element = PartitionPrimitives::Element;
1134+ using Region = PartitionPrimitives::Region;
1135+ using TransferringOperandSetFactory =
1136+ Partition::TransferringOperandSetFactory;
1137+ using Super = PartitionOpEvaluator<Subclass>;
1138+
1139+ PartitionOpEvaluatorBaseImpl (Partition &workingPartition,
1140+ TransferringOperandSetFactory &ptrSetFactory)
1141+ : Super(workingPartition, ptrSetFactory) {}
1142+
1143+ // / Should we emit extra verbose logging statements when evaluating
1144+ // / PartitionOps.
1145+ bool shouldEmitVerboseLogging () const { return true ; }
1146+
1147+ // / A function called if we discover a transferred value was used after it
1148+ // / was transferred.
1149+ // /
1150+ // / The arguments passed to the closure are:
1151+ // /
1152+ // / 1. The PartitionOp that required the element to be alive.
1153+ // /
1154+ // / 2. The element in the PartitionOp that was asked to be alive.
1155+ // /
1156+ // / 3. The operand of the instruction that originally transferred the
1157+ // / region. Can be used to get the immediate value transferred or the
1158+ // / transferring instruction.
1159+ void handleFailure (const PartitionOp &op, Element elt,
1160+ TransferringOperand transferringOp) const {}
1161+
1162+ // / A list of elements that cannot be transferred. Whenever we transfer, we
1163+ // / check this list to see if we are transferring the element and then call
1164+ // / transferNonTransferrableCallback. This should consist only of function
1165+ // / arguments.
1166+ ArrayRef<Element> getNonTransferrableElements () const { return {}; }
1167+
1168+ // / This is called if we detect a never transferred element that was passed to
1169+ // / a transfer instruction.
1170+ void handleTransferNonTransferrable (const PartitionOp &op,
1171+ Element elt) const {}
1172+
1173+ // / This is used to determine if an element is actor derived. If we determine
1174+ // / that a region containing such an element is transferred, we emit an error
1175+ // / since actor regions cannot be transferred.
1176+ bool isActorDerived (Element elt) const { return false ; }
1177+
1178+ // / Check if the representative value of \p elt is closure captured at \p
1179+ // / op.
1180+ // /
1181+ // / NOTE: We actually just use the user of \p op in our callbacks. The reason
1182+ // / why we do not just pass in that SILInstruction is that then we would need
1183+ // / to access the instruction in the evaluator which creates a problem when
1184+ // / since the operand we pass in is a dummy operand.
1185+ bool isClosureCaptured (Element elt, Operand *op) const { return false ; }
1186+ };
1187+
1188+ // / A subclass of PartitionOpEvaluatorBaseImpl that doesn't have any special
1189+ // / behavior.
1190+ struct PartitionOpEvaluatorBasic final
1191+ : PartitionOpEvaluatorBaseImpl<PartitionOpEvaluatorBasic> {
1192+ PartitionOpEvaluatorBasic (Partition &workingPartition,
1193+ TransferringOperandSetFactory &ptrSetFactory)
1194+ : PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory) {}
1195+ };
1196+
11701197} // namespace swift
11711198
11721199#endif // SWIFT_PARTITIONUTILS_H
0 commit comments