Skip to content

Refactor SILCombiner code for better reuse and extensibility #17934

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

Closed
wants to merge 1 commit into from

Conversation

rajbarik
Copy link
Contributor

This PR refactors SILCombiner code by
(1) Changing the return type of "propagateConcreteTypeOfInitExistential(FullApplySite Apply, WitnessMethodInst *WMI)" to a boolean instead of "SILInstruction *". Today, the return type is not used anywhere. See #17373.
(2) Adding a new method replaceWitnessMethodInst that abstracts out WMI creationfunctionality to a new function. No new new functionality added here.
(3) In function "createApplyWithConcreteType", the condition
"if (CEI.isCopied && !canReplaceCopiedSelf(Apply, CEI.InitExistential, DA))" was changed to
"if (CEI.isCopied && (!CEI.InitExistential ||
!canReplaceCopiedSelf(Apply, CEI.InitExistential, DA)))"
in order to handle scenarios where CEI.InitExistential is null. This happens for #17373.

@rajbarik
Copy link
Contributor Author

@atrick @slavapestov could you guys review this PR quickly? I am blocked on this for my PR #17373

@@ -286,11 +286,18 @@ class SILCombiner :
const ConcreteExistentialInfo &CEI,
SILBuilderContext &BuilderCtx);

SILInstruction *
bool
Copy link
Contributor

@atrick atrick Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the return value mean?
(Please don't answer me in the PR. That's what function comments are for. )
A dox comment belongs here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok.

@@ -603,6 +603,23 @@ SILCombiner::optimizeConcatenationOfStringLiterals(ApplyInst *AI) {
return tryToConcatenateStrings(AI, Builder);
}

/// This routine replaces the old witness method inst with a new one.
void SILCombiner::replaceWitnessMethodInst(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be generally useful, shouldn't the new instruction be returned?

@@ -712,7 +729,8 @@ SILCombiner::createApplyWithConcreteType(FullApplySite Apply,
}
// The apply can only be rewritten in terms of the concrete value if it is
// legal to pass that value as the self argument.
if (CEI.isCopied && !canReplaceCopiedSelf(Apply, CEI.InitExistential, DA))
if (CEI.isCopied && (!CEI.InitExistential ||
!canReplaceCopiedSelf(Apply, CEI.InitExistential, DA)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thinking about this a bit more: this still does not look correct to me. When types are determined from protocolconformances, even though CEI.InitExistential is null,I still want to be able to create a new Apply instruction for it. there are checks inside canReplaceCopiedSelf that I want to check as well. Does it look ok for you to add a check for returning true when InitExistential is null in canReplaceCopiedSelf (after the first check?). This way we can retain the old check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canReplaceCopiedSelf currently assumes that self is coming from an init_existential, so you should not call it in your case, at least without somehow generalizing it.

In the subsequent code, self is being replaced by the concrete value from the existential (CEI.ConcreteValue). If the existential itself was copied, then that's not generally valid!

In your case, how to you know it's safe to replace self with CEI.ConcreteValue? What if the original self was copied?

SelfConformance != WMI->getConformance()) {
replaceWitnessMethodInst(Apply, WMI, BuilderCtx, CEI.ConcreteType,
SelfConformance);
newWMIAdded = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bizarre. It's fine to return a bool, but the convention in SILCombine, and the optimizer in general is that returning true indicates success. This function should return true whenever createApplyWithConcreteType is called.

If the caller needs to know whether the witness_method was also needed to be rewritten then you have plenty of options:

  • Check the witness_method lookup type in the caller.
  • Check if the witness_method instruction has changed in the caller.
  • Pass in a reference to a WitnessMethodInst* result.
  • Define a more complicated return type struct { bool success, WitnessMethodInst *newWMI }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Returning bool was one of the suggestions made by @slavapestov as opposed to my code checking for WMI change in the caller, since we do not use the return type -- which made sense to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, any of the above options for checking WMI are fine, but giving propagateConcreteTypeOfInitExistential a counterintuitive return value for the sake of convenience would be bad.

Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments inline.

@rajbarik
Copy link
Contributor Author

rajbarik commented Jul 16, 2018 via email

@atrick
Copy link
Contributor

atrick commented Jul 16, 2018

Are these two sufficient to replace the self with CEI.ConcreteValue?

I don't know. This is the most dangerous part of the code now because propagateConcreteTypeOfInitExistential is making an assumption about what its caller is doing and how ConcreteExistentialInfo was generated.

We need to establish some contract between ConcreteExistentialInfo and its clients. The client knows that the apply will be rewritten with ConcreteValue as the new self argument. If that's not clear, could you improve the comments?

So, in your new optimization, how can we guarantee that it's safe to replace self with ConcreteValue? In canReplaceCopiedSelf we have some very hacky but conservative logic that proves that a value being used in init_existential is still live at the call site. What SIL patterns can you handle now where self is an address? Can ConcreteValue and self be actually be a different memory location? If so, you could probably generalize canReplaceCopiedSelf to handle your cases.

Again, I don't think you should attempt to weaken the check at all until you have test cases for each pattern you need to optimize.

@rajbarik
Copy link
Contributor Author

rajbarik commented Jul 17, 2018 via email

@atrick
Copy link
Contributor

atrick commented Jul 18, 2018

Thanks for the example. I don't see why there would be an issue with this case; CEI.isCopied should be false...

This scenario needs that your check for
if (CEI.InitExistential && CEI.isCopied && !canReplaceCopiedSelf(Apply, CEI.InitExistential, DA))

I don't know where this expression came from, the condition for bailout in on your patch is currently:

CEI.isCopied && (!CEI.InitExistential ||
                   !canReplaceCopiedSelf(Apply, CEI.InitExistential, DA))

Maybe you would prefer to write the equivalent:

 if (CEI.isCopied) {
   if !(CEI.InitExistential
        && canReplaceCopiedSelf(Apply, CEI.InitExistential, DA))
      // BAILOUT

I could invoke findInitExistential in my pass and determine
IE/copy_addr and pass them to your createApplyWithConcreteType --
everything should work as is.

I'm not sure why you would do that. Is there a case that is not currently being optimized that you think should be optimized?

@rajbarik
Copy link
Contributor Author

rajbarik commented Jul 20, 2018 via email

@rajbarik
Copy link
Contributor Author

Refined version at #18109

@rajbarik rajbarik closed this Jul 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants