This is an archive of the discontinued LLVM Phabricator instance.

[AST] Pack GenericSelectionExpr
ClosedPublic

Authored by riccibruno on Jan 23 2019, 9:55 AM.

Details

Summary

Store the controlling expression, the association expressions and the corresponding
TypeSourceInfos as trailing objects.

Additionally use the bit-fields of Stmt to store one SourceLocation, saving one
additional pointer. This saves 3 pointers in total per GenericSelectionExpr.

Diff Detail

Repository
rL LLVM

Event Timeline

riccibruno created this revision.Jan 23 2019, 9:55 AM

Splitting the introduction of and porting to Create would significantly reduce the number of files touched by the 'real' change in this commit, and therefore reduce noise in the commit (following the idea of "do one thing per commit" to make the code reviewable in the future).

However, if you're opposed to that, it's not a hard requirement.

include/clang/AST/Expr.h
5048 ↗(On Diff #183119)

Would it be correct to use ASSOC_EXPR_START here instead of the magic 1?

I haven't done a full review as it's not obvious what parts of the diff relate to which separate change. Perhaps Aaron will review and approve though for you anyway.

Thanks!

riccibruno marked an inline comment as done.Jan 23 2019, 10:30 AM

Splitting the introduction of and porting to Create would significantly reduce the number of files touched by the 'real' change in this commit, and therefore reduce noise in the commit (following the idea of "do one thing per commit" to make the code reviewable in the future).

However, if you're opposed to that, it's not a hard requirement.

To be honest I don't really see the point. This is just the usual pattern of having a Create function doing the allocation,
which then dispatch to the private constructor with a placement new for the initialization.

include/clang/AST/Expr.h
5048 ↗(On Diff #183119)

Eh maybe ?

aaron.ballman added inline comments.Jan 23 2019, 11:20 AM
include/clang/AST/Expr.h
5043 ↗(On Diff #183119)

Do we want to use ControllingIndex and AssocExprStartIndex and combine with the enum you introduced above?

5048 ↗(On Diff #183119)

I think using this named constant adds confusion rather than clarifies things because it's not clear what the index has to do with the count. I think the comments suffice here rather than introducing a named constant with a sufficiently generic name.

lib/AST/Expr.cpp
3814 ↗(On Diff #183119)

-1U -> ResultDependentIndex

lib/Serialization/ASTReaderStmt.cpp
1034 ↗(On Diff #183119)

You should add a comment above the loop that explains the + 1 is for the controlling expression and that's why it's not needed for the type source information.

lib/Serialization/ASTWriterStmt.cpp
979 ↗(On Diff #183119)

Similar comment here as above.

Splitting the introduction of and porting to Create would significantly reduce the number of files touched by the 'real' change in this commit, and therefore reduce noise in the commit (following the idea of "do one thing per commit" to make the code reviewable in the future).

However, if you're opposed to that, it's not a hard requirement.

To be honest I don't really see the point.

Yes, the Create refactor a simple change. The point is to remove the noise of the simple change from the complex change so that the complex change becomes visible.

It would help reviewers like myself who are less familiar with what refactoring for tail allocation involves. I couldn't read your commit and know how to do it for another class because this commit is full of noise.

Anyway, if making the code reviewable (also in the future!) like that is not important enough, I won't block this one! :)

include/clang/AST/Expr.h
5095 ↗(On Diff #183119)

Why remove the LLVM_READONLY from this class instead of from everywhere in the file it is not needed? (in a separate commit, obviously).

Splitting the introduction of and porting to Create would significantly reduce the number of files touched by the 'real' change in this commit, and therefore reduce noise in the commit (following the idea of "do one thing per commit" to make the code reviewable in the future).

However, if you're opposed to that, it's not a hard requirement.

To be honest I don't really see the point.

Yes, the Create refactor a simple change. The point is to remove the noise of the simple change from the complex change so that the complex change becomes visible.

It would help reviewers like myself who are less familiar with what refactoring for tail allocation involves. I couldn't read your commit and know how to do it for another class because this commit is full of noise.

Anyway, if making the code reviewable (also in the future!) like that is not important enough, I won't block this one! :)

You are right that readability and review-ability is pretty important. My apologies for making this an unreadable mess :)
Let me clean this patch a little bit (along with addressing Aaron's comments).

riccibruno marked 2 inline comments as done.Jan 24 2019, 7:29 AM
riccibruno added inline comments.
include/clang/AST/Expr.h
5095 ↗(On Diff #183119)

LLVM_READONLY is a macro for __attribute__((pure)) (when supported). It is useful in some cases to give a hint to the optimizer about the behavior of a function. However in this case the definition of the function is visible in all translation units using this function. Therefore the optimizer can very well see on its own what this function is doing.

It would be perfectly possible to inspect all uses of LLVM_READONLY and only keep what is needed, but this is such a small issue that nobody bothered to do it until now.

steveire added inline comments.Jan 24 2019, 7:34 AM
include/clang/AST/Expr.h
5095 ↗(On Diff #183119)

My point was again about commit hygiene.

You could make a commit changing this without further review, leaving this review cleaner. You could do the same with the moved friend decl. Commits which only do one thing are easier to review.

riccibruno marked 3 inline comments as done.Jan 24 2019, 7:36 AM
riccibruno added inline comments.
include/clang/AST/Expr.h
5095 ↗(On Diff #183119)

Ah I see. Yes I can do this.

riccibruno marked an inline comment as done.Jan 24 2019, 7:38 AM
riccibruno marked 6 inline comments as done.

Cleanup the patch by factoring out the NFC changes.

@steveire This should be much clearer now.

Thanks, but I don't see the factored out changes in the repo. Are you going to commit those first?

Also, please factor out the introduction and use of ::Create. It seems to be unrelated to the trailing objects change.

Thanks, but I don't see the factored out changes in the repo. Are you going to commit those first?

Also, please factor out the introduction and use of ::Create. It seems to be unrelated to the trailing objects change.

I was planning to yes. I don't agree that the introduction of Create is unrelated. It is very much part of the changes
since the introduction of the trailing objects implies the need to do a placement new, which implies the need to
use a Create function. Also see pretty much every other patch which introduced trailing objects for the
statement/expression nodes.

aaron.ballman accepted this revision.Jan 24 2019, 12:39 PM

Thanks, but I don't see the factored out changes in the repo. Are you going to commit those first?

Also, please factor out the introduction and use of ::Create. It seems to be unrelated to the trailing objects change.

I was planning to yes. I don't agree that the introduction of Create is unrelated. It is very much part of the changes
since the introduction of the trailing objects implies the need to do a placement new, which implies the need to
use a Create function. Also see pretty much every other patch which introduced trailing objects for the
statement/expression nodes.

+1, the changes to the Create methods are germane to this review.

This LGTM, thank you for working on it!

This revision is now accepted and ready to land.Jan 24 2019, 12:39 PM

There's definitely a better possible ordering in two commits:

  1. Introduce ::Create and port to it
  2. Use trailing objects, taking advantage of the fact that ::Create exists.

That would make it clear in the future to other people because both commits would be cleaner, both commit messages would say what the commit does, and neither commit would have the noise of the other change.

Not splitting this commit makes it less reviewable to people who are not around today.

There's definitely a better possible ordering in two commits:

  1. Introduce ::Create and port to it
  2. Use trailing objects, taking advantage of the fact that ::Create exists.

That would make it clear in the future to other people because both commits would be cleaner, both commit messages would say what the commit does, and neither commit would have the noise of the other change.

Not splitting this commit makes it less reviewable to people who are not around today.

I highly recommend this 9 minute video if this is new to you or you haven't seen it before: https://youtu.be/qpdYRPL3SVE?t=103

There's definitely a better possible ordering in two commits:

  1. Introduce ::Create and port to it
  2. Use trailing objects, taking advantage of the fact that ::Create exists.

That would make it clear in the future to other people because both commits would be cleaner, both commit messages would say what the commit does, and neither commit would have the noise of the other change.

Not splitting this commit makes it less reviewable to people who are not around today.

I strongly disagree. The only reason for the Create method to exist is because we are using trailing objects.
It is not "oh nice Create exists, lets use it!". Furthermore, this is a standard pattern across the code-base and
this patch is already tiny.

There's definitely a better possible ordering in two commits:

  1. Introduce ::Create and port to it
  2. Use trailing objects, taking advantage of the fact that ::Create exists.

That would make it clear in the future to other people because both commits would be cleaner, both commit messages would say what the commit does, and neither commit would have the noise of the other change.

Not splitting this commit makes it less reviewable to people who are not around today.

I would find reviewing that more confusing because the two reviews are inextricably linked. There's no need for a Create() method without the other changes, and the other changes require a Create() method. I get what you mean about keeping reviews concise, but at some point you can split the reviews so much that it becomes really difficult to perform a sensible review because you get too much information in isolation.

There's definitely a better possible ordering in two commits:

  1. Introduce ::Create and port to it
  2. Use trailing objects, taking advantage of the fact that ::Create exists.

That would make it clear in the future to other people because both commits would be cleaner, both commit messages would say what the commit does, and neither commit would have the noise of the other change.

Not splitting this commit makes it less reviewable to people who are not around today.

I would find reviewing that more confusing because the two reviews are inextricably linked. There's no need for a Create() method without the other changes, and the other changes require a Create() method. I get what you mean about keeping reviews concise, but at some point you can split the reviews so much that it becomes really difficult to perform a sensible review because you get too much information in isolation.

+1 You can cut a commit into arbitrarily small pieces. As a silly example I could inherit from llvm::TrailingObjects in one commit.
Then remove the Stmt ** in another one and so on.

I highly recommend this 9 minute video if this is new to you or you haven't seen it before: https://youtu.be/qpdYRPL3SVE?t=103

I would like to add an additional meta-comment here, but please don't take this in a bad way. I am wondering
about the usefulness and the productivity of the "if this is new to you" in what I am assuming is a discussion
between professionals. I will be happy to address any further technical comments regarding the code itself.

I highly recommend this 9 minute video if this is new to you or you haven't seen it before: https://youtu.be/qpdYRPL3SVE?t=103

I would like to add an additional meta-comment here, but please don't take this in a bad way. I am wondering
about the usefulness and the productivity of the "if this is new to you" in what I am assuming is a discussion
between professionals. I will be happy to address any further technical comments regarding the code itself.

Sorry for that. It's a confusing conversation and text doesn't help! :)

Other classes have ::Create methods and if it's a justification you're looking for precedent could be it :).

My proposal is a patch which only does one thing (Pack GenericSelectionExpr) and a commit message that corresponds to that one thing. I'm not proposing 'doing half a thing' in a commit like just inheriting from llvm::TrailingObjects.

Your preference is a patch that packs GenericSelectionExpr and does something else.

I don't see how a person in the future would find the former more confusing than the latter. Someone in the future won't care that at the end of January 2019 the thing didn't already have a ::Create method. There is future-value reducing noise in commits. I know that's fuzzy and there isn't agreement on the specifics, but maybe you agree with the principle. I know many people don't agree with that principle, and many more people never use something like gitk/git log and don't see the value in granular commits (hence why someone went and gave a talk at a conference about it :)).

So, I've given that feedback and you have your LGTM. In my book, the rest is up to you! :)

I highly recommend this 9 minute video if this is new to you or you haven't seen it before: https://youtu.be/qpdYRPL3SVE?t=103

I would like to add an additional meta-comment here, but please don't take this in a bad way. I am wondering
about the usefulness and the productivity of the "if this is new to you" in what I am assuming is a discussion
between professionals. I will be happy to address any further technical comments regarding the code itself.

Sorry for that. It's a confusing conversation and text doesn't help! :)

I totally agree with that.

Other classes have ::Create methods and if it's a justification you're looking for precedent could be it :).

My proposal is a patch which only does one thing (Pack GenericSelectionExpr) and a commit message that corresponds to that one thing. I'm not proposing 'doing half a thing' in a commit like just inheriting from llvm::TrailingObjects.

Your preference is a patch that packs GenericSelectionExpr and does something else.

I don't think that this is accurate. This patch does one thing: pack GenericSelectionExpr. It does this by doing two logically distinct things:
1.) move some data to the bit-fields of Stmt and 2) tail-allocate the array of Stmt * and the array of TypeSourceInfo.

The addition of the Create function is part of 2) and not something distinct.

I don't see how a person in the future would find the former more confusing than the latter. Someone in the future won't care that at the end of January 2019 the thing didn't already have a ::Create method. There is future-value reducing noise in commits. I know that's fuzzy and there isn't agreement on the specifics, but maybe you agree with the principle. I know many people don't agree with that principle, and many more people never use something like gitk/git log and don't see the value in granular commits (hence why someone went and gave a talk at a conference about it :)).

I agree with you that granular commits (with good and accurate commit messages!) doing one thing are important.
I am (and I think that everyone is) a fan of (git log/blame/etc). It is indeed frustrating to do some git archaeology
and end up to a commit with no explanation.

I believe however that our disagreement here is not on whether we should have good commit messages (duh, of course we should),
nor on whether we should have granular commits (duh, of course we should too), but on whether this is a granular change.

I am arguing that it is and it seems that you are arguing that this is not the case.

So, I've given that feedback and you have your LGTM. In my book, the rest is up to you! :)

Consensus is important and I can totally miss things so I don't want to just ignore you and push ahead.

Cleanup the patch by factoring out the NFC changes.

@steveire This should be much clearer now.

I'd like to apply this patch locally, but I think the removed parts are not in the repo yet. Did I miss that somehow?

Cleanup the patch by factoring out the NFC changes.

@steveire This should be much clearer now.

I'd like to apply this patch locally, but I think the removed parts are not in the repo yet. Did I miss that somehow?

You are right that they were not available somewhere else. I just put them now in D57238. You should be able to apply D57238,
and then apply this patch on top.

This revision was automatically updated to reflect the committed changes.

I was just working on this this afternoon to show you the difference when it is split up. Looks like you committed this meanwhile.

While building I noticed that you introduced a -Wreorder bug in D57238, which isn't surprising given how many different things you do in that one commit :). It looks like you fixed that bug before commit though.

Thanks for the refactor!

Stephen.