This is an archive of the discontinued LLVM Phabricator instance.

[clang][Interp] Rework how initializers work
ClosedPublic

Authored by tbaeder on Jul 22 2023, 7:51 AM.

Details

Summary

Before this patch, we had visitRecordInitializer() and visitArrayInitializer(), which were different from the regular visit() in that they expected a pointer on the top of the stack, which they initialized. For example, visitArrayInitializer handled InitListExprs by looping over the members and initializing the elements of that pointer.

However, this had a few corner cases and problems. For example, in visitLambdaExpr() (a lambda is always of record type), it was not clear whether we should always create a new local variable to save the lambda to, or not. This is why https://reviews.llvm.org/D153616 changed things around.

There is also a long-standing problem with fucnction calls, because we always visit the call arguments like:

for (const auto *Arg : CtorExpr->arguments()) {
  if (!this->visit(Arg))
    return false;
}

but if the argument returns a composite type, where does the storage for it come from? Before this patch, it sometimes works and sometimes doesn't.

This patch changes the visiting functions to:

  1. visit(): Always leaves a new value on the stack. If the expression can be mapped to a primitive type, it's just visited and the value is put on the stack. If it's of composite type, this function will create a local variable for the expression value and call visitInitializer(). The pointer to the local variable will stay on the stack.
  2. visitInitializer(): Visits the given expression, assuming there is a pointer on top of the stack that will be initialized by it.
  3. discard(): Visit the expression for side-effects, but don't leave a value on the stack.

It also adds an additional Initializing flag to differentiate between the initializing and non-initializing case.

Diff Detail

Event Timeline

tbaeder created this revision.Jul 22 2023, 7:51 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 22 2023, 7:51 AM
tbaeder requested review of this revision.Jul 22 2023, 7:51 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 22 2023, 7:51 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
tbaeder updated this revision to Diff 543255.Jul 22 2023, 11:58 PM

Note that this patch also supercedes:

  1. https://reviews.llvm.org/D153616
  2. https://reviews.llvm.org/D153653
  3. https://reviews.llvm.org/D147591

since it handles those cases more generally.

clang/lib/AST/Interp/Context.cpp
131

I've removed this change in https://reviews.llvm.org/D144164 since it didn't seem necessary, but it is necessary after applying this patch.

Note that this patch also supercedes:

  1. https://reviews.llvm.org/D153616
  2. https://reviews.llvm.org/D153653
  3. https://reviews.llvm.org/D147591

since it handles those cases more generally.

Can you abandon the revisions you are no longer pursuing? Thanks!

tbaeder added inline comments.Jul 26 2023, 5:20 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
155

This pattern shows up a few times, so it might make sense to add a function that simply passes on all the flags and doesn't do anything else. I'm just not sure what to call it.

aaron.ballman added inline comments.Jul 28 2023, 8:26 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
155

It's not clear to me when you should use this pattern to begin with.

1899

And if it is a member call expression?

clang/lib/AST/Interp/ByteCodeExprGen.h
140–142
144–147
clang/lib/AST/Interp/Context.cpp
131

Which test case exercises this bit?

tbaeder marked an inline comment as done.Jul 28 2023, 12:38 PM
tbaeder added inline comments.
clang/lib/AST/Interp/ByteCodeExprGen.cpp
1899

For member calls, the layout at this point is:

ThisPtr
RVOPtr
RVOPtr

(top of the stack is where we're at). The dup here is supposed to dup the RVO ptr, but we can't do that for member calls because the top is currently the instance pointer. Tha'ts why VisitCXXMemberCallExpr() handles this separately.

tbaeder updated this revision to Diff 545336.Jul 28 2023, 11:21 PM
tbaeder marked 3 inline comments as done.
tbaeder added inline comments.Jul 29 2023, 5:31 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
155

Whenever you just pass on the visit, essentially ignoring the current node. Another good example is ConstantExprs, where we don't do anything for the node and then just pass move on to the SubExpr.

tbaeder added inline comments.Jul 29 2023, 6:08 AM
clang/lib/AST/Interp/Context.cpp
131

We have this line in records.cpp:

constexpr int value = (s.*foo)();

and its type is:

BuiltinType 0x62100001fbe0 '<bound member function type>'

it just so happens that we _now_ call classify() on this earlier in the code path while before we didn't do that, so we need to know that the bound member function type is now some composite type.

Do you want me to squash the patches I abandoned into this one?

Do you want me to squash the patches I abandoned into this one?

I think that could help us to see the bigger picture; I'm assuming that only adds a bit of code rather than three full patches' worth of code.

clang/lib/AST/Interp/ByteCodeExprGen.cpp
155

Ah, I see, so it's basically when you want to delegate the visit to a child node? If so, perhaps that's a reasonable name (delegateVisit())?

1899

Thank you for the explanation!

clang/lib/AST/Interp/Context.cpp
131

Ah, thank you! That makes sense.

tbaeder updated this revision to Diff 545926.Jul 31 2023, 11:32 PM

Add ::delegate(const Expr *E) and squash previous commits into this one.

tbaeder updated this revision to Diff 545928.Jul 31 2023, 11:32 PM
tbaeder updated this revision to Diff 545929.Jul 31 2023, 11:36 PM

merge visitConditional() into its only caller, VisitAbstractConditionalOperator(). This works now sine the initializer and non-initializer code paths are the same.

aaron.ballman added inline comments.Aug 2 2023, 6:35 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
462–464

We might be able to get away with this for floats as well (IIRC, all zero bits is +0 for any IEEE 754 float type, so at least some of the more common floats could probably do this). Same is true for any pointer type so long as it's not a member pointer type.

1428–1432
tbaeder updated this revision to Diff 548522.Aug 9 2023, 2:10 AM
tbaeder marked an inline comment as done.
tbaeder added inline comments.
clang/lib/AST/Interp/ByteCodeExprGen.cpp
462–464

IIRC doesn't work since floating point is represented using an Floating, which uses APFloat.

aaron.ballman accepted this revision.Aug 9 2023, 8:24 AM

LGTM!

clang/lib/AST/Interp/ByteCodeExprGen.cpp
462–464

Ah true!

This revision is now accepted and ready to land.Aug 9 2023, 8:24 AM
This revision was landed with ongoing or failed builds.Aug 20 2023, 4:33 AM
This revision was automatically updated to reflect the committed changes.