This is an archive of the discontinued LLVM Phabricator instance.

[clang][Interp] Implement inc/dec postfix and prefix operators
ClosedPublic

Authored by tbaeder on Oct 21 2022, 12:30 AM.

Details

Summary

This only works on integrals for now.

Add four new opcodes, Inc, IncPop, Dec and DecPop. The *Pop variants don't leave anything on the stack and exist because the common case is that the result is unused.

There are still a few corner cases left like floating values, pointers, and over/underflow handling.

Diff Detail

Event Timeline

tbaeder created this revision.Oct 21 2022, 12:30 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 21 2022, 12:30 AM
tbaeder requested review of this revision.Oct 21 2022, 12:30 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 21 2022, 12:30 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
tbaeder updated this revision to Diff 469530.Oct 21 2022, 3:22 AM
tbaeder updated this revision to Diff 469589.Oct 21 2022, 6:51 AM
tbaeder updated this revision to Diff 469971.Oct 23 2022, 2:56 AM

Handle integer over- and underflows.

aaron.ballman added inline comments.Oct 24 2022, 7:16 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
1065–1068

Style question: should we prefer doing something like: return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E); to discourage accidentally adding code between the two increment operations? (And applying this style more generally for discarded results?)

Alternatively, do we want to add a helper function to ByteCodeExprGen called doEmitInc() that hides the discarded result behavior so the Visit* functions don't have to keep doing that dance?

clang/lib/AST/Interp/Interp.h
284

Do we want to use enums for IsInc and PushVal so that call sites use IncDeclHelper<SomeType, Increment::Yes, Push::Yes> for clarity?

323–326
clang/test/AST/Interp/literals.cpp
346

I'd like some tests that the computed values are correct.

constexpr int zero() {
  int a = 0;
  return a++;
}
static_assert(zero() == 0);

constexpr int one() {
  int a = 0;
  return ++a;
}
static_assert(one() == 1);

constexpr int zero_again() {
  int a = 0;
  return a--;
}
static_assert(zero_again() == 0);

constexpr int neg_one() {
  int a = 0;
  return --a;
}
static_assert(neg_one() == -1);
tbaeder updated this revision to Diff 470159.Oct 24 2022, 8:03 AM
tbaeder marked 3 inline comments as done.
tbaeder added inline comments.Oct 24 2022, 8:05 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
1065–1068

Yeah I think the ternary makes sense here, like it's done in the Discard() function in VisitBinaryOperator().

For a function, I'll hold off for now, but it might make sense later (there's still a TODO comment for array initialization, which compiles to tons of code right now and we should use a loop there).

tbaeder updated this revision to Diff 470163.Oct 24 2022, 8:09 AM
aaron.ballman accepted this revision.Oct 24 2022, 8:17 AM

LGTM aside from nits.

clang/lib/AST/Interp/ByteCodeExprGen.cpp
1103–1105
1107–1108
1111–1113
1116–1118
1130–1131
This revision is now accepted and ready to land.Oct 24 2022, 8:17 AM
tbaeder marked 5 inline comments as done.Oct 24 2022, 8:34 AM
shafik accepted this revision.Oct 24 2022, 9:59 AM

LGTM

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

You could combine this with UO_PreInc and just use a bool flag to determine whether to call emitAdd or emitSub . Although maybe that it too clever.

clang/test/AST/Interp/literals.cpp
334

Fun tests

+[](){};
+'a';

The action will really be done by the casts but the + is still technically having that affect.

This revision was landed with ongoing or failed builds.Oct 28 2022, 9:01 AM
This revision was automatically updated to reflect the committed changes.