@@ -934,115 +934,73 @@ class Partition {
934
934
// / A data structure that applies a series of PartitionOps to a single Partition
935
935
// / that it modifies.
936
936
// /
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>
945
941
struct 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:
946
947
using Element = PartitionPrimitives::Element;
947
948
using Region = PartitionPrimitives::Region;
948
949
using TransferringOperandSetFactory =
949
950
Partition::TransferringOperandSetFactory;
950
951
952
+ protected:
951
953
TransferringOperandSetFactory &ptrSetFactory;
952
954
953
955
Partition &p;
954
956
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:
1000
958
PartitionOpEvaluator (Partition &p,
1001
959
TransferringOperandSetFactory &ptrSetFactory)
1002
960
: ptrSetFactory(ptrSetFactory), p(p) {}
1003
961
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.
1005
968
void handleFailure (const PartitionOp &op, Element elt,
1006
969
TransferringOperand transferringOp) const {
1007
- if (!failureCallback)
1008
- return ;
1009
- failureCallback (op, elt, transferringOp);
970
+ return asImpl ().handleFailure (op, elt, transferringOp);
1010
971
}
1011
972
1012
- // / A wrapper around transferNonTransferrableCallback that only calls it if it
1013
- // / is not null.
973
+ // / Call handleTransferNonTransferrable on our CRTP subclass.
1014
974
void handleTransferNonTransferrable (const PartitionOp &op,
1015
975
Element elt) const {
1016
- if (!transferredNonTransferrableCallback)
1017
- return ;
1018
- transferredNonTransferrableCallback (op, elt);
976
+ return asImpl ().handleTransferNonTransferrable (op, elt);
1019
977
}
1020
978
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.
1024
980
bool isActorDerived (Element elt) const {
1025
- return bool (isActorDerivedCallback) && isActorDerivedCallback (elt);
981
+ return asImpl (). isActorDerived (elt);
1026
982
}
1027
983
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.
1031
985
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 ();
1034
992
}
1035
993
1036
994
// / Apply \p op to the partition op.
1037
995
void apply (const PartitionOp &op) const {
1038
- if (emitLog ) {
996
+ if (shouldEmitVerboseLogging () ) {
1039
997
REGIONBASEDISOLATION_VERBOSE_LOG (llvm::dbgs () << " Applying: " ;
1040
998
op.print (llvm::dbgs ()));
1041
999
REGIONBASEDISOLATION_VERBOSE_LOG (llvm::dbgs () << " Before: " ;
1042
1000
p.print (llvm::dbgs ()));
1043
1001
}
1044
1002
SWIFT_DEFER {
1045
- if (emitLog ) {
1003
+ if (shouldEmitVerboseLogging () ) {
1046
1004
REGIONBASEDISOLATION_VERBOSE_LOG (llvm::dbgs () << " After: " ;
1047
1005
p.print (llvm::dbgs ()));
1048
1006
}
@@ -1078,7 +1036,7 @@ struct PartitionOpEvaluator {
1078
1036
1079
1037
// check if any nontransferrables are transferred here, and handle the
1080
1038
// failure if so
1081
- for (Element nonTransferrable : nonTransferrableElements ) {
1039
+ for (Element nonTransferrable : getNonTransferrableElements () ) {
1082
1040
assert (
1083
1041
p.isTrackingElement (nonTransferrable) &&
1084
1042
" nontransferrables should be function args and self, and therefore"
@@ -1167,6 +1125,75 @@ struct PartitionOpEvaluator {
1167
1125
}
1168
1126
};
1169
1127
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
+
1170
1197
} // namespace swift
1171
1198
1172
1199
#endif // SWIFT_PARTITIONUTILS_H
0 commit comments