-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[region-isolation] Track elements -> regions and regions -> consuming separately. #69787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[region-isolation] Track elements -> regions and regions -> consuming separately. #69787
Conversation
Needed this API. Unwrapping the onion to make further commits easier to review.
…gnoseFailures. This is only used in one place in partition analysis which is a data structure that does computation. In contrast, we want BlockPartitionState to be more of a POD type of data that each BasicBlock has mapped to it. Simplifying the code. This also let me get rid of the translator field in BasicBlockState. We only need to pass it in as an argument to the constructor to initialize our translation. It doesn't need to be stored anymore.
…on ops rather than use a callback. There isn't a strong reason to use a callback here since we aren't ever composing transformations on partition ops. Better instead to go for simplicity and just iterate directly. If we start doing complex transformations over partition ops with composable APIs, we can always add this back in later. As a nice benefit, one doesn't need to worry that the callback API is hiding actual complexity... since just by using a for loop we communicate that nothing interesting is happening here. Just reducing the amount of code surface area in the pass.
…ion. What this does is really split the one dataflow we are performing into two dataflows we perform at the same time. The first dataflow is the region dataflow that we already have with transferring never occurring. The second dataflow is a simple gen/kill dataflow where we gen on a transfer instruction and kill on AssignFresh. What it tracks are regions where a specific element is transferred and propagates the region until the element is given a new value. This of course means that once the dataflow has converged, we have to emit an error not if the value was transferred, but if any value in its region was transferred.
Was experimenting with making PartitionOps a noncopyable type and I discovered these places where we copy PartitionOps when we could use a const reference. It is good not to copy PartitionOps since they potentially contain a heap allocated array. Sadly, my change to make PartitionOps noncopyable will have to wait until a forthcoming commit here I overhaul how we emit errors since that older code copies PartitionOps a lot and I would rather just delete that code and then fix PartitionOps. But these are on the surface safe changes that makes sense to get in separately to make that next patch easier to review.
…nostic. These are not actionable to the user.
…SILLocation. getExprForPartitionOp(...) just returned the expression from the loc of op.currentInst: SILInstruction *sourceInstr = op.getSourceInst(/*assertNonNull=*/true); Expr *expr = sourceInstr->getLoc().getAsASTNode<Expr>(); Instead of mucking around with exprs, just use the SILLocation from the SILInstruction. I also changed how we unique transfer instructions to just use the transfer instruction itself instead of the AST/Expr of the transfer instruction.
@swift-ci smoke test |
}); | ||
}; | ||
eval.nonTransferrableElements = translator.getNeverTransferredValues(); | ||
eval.isActorDerivedCallback = [&](Element element) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if these callbacks are worth it at all, do they allow unit testing or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think they are. The idea is to make it so that one can visit/process the blocks and then reuse the same visiting code to visit/emit the errors. I'll see if I can come up with something better.
@@ -485,6 +485,21 @@ class ApplySite { | |||
llvm_unreachable("covered switch"); | |||
} | |||
|
|||
/// Return a list of applied operands of the apply without self. | |||
ArrayRef<Operand> getOperandsWithoutSelf() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any other places this can be used?
This PR contains a few different improvements to the pass. The most important one is that we as a result of this change actually perform two separate data flows at the same time: one mapping elements to regions and a second that maps regions to transferring instructions. In contrast previously we would track transferring just by marking the region of an element as -1, losing the region information and not storing what instruction caused the transfer to occur. The reason why I am making this change is that:
The patches are: