63 Commits

Author SHA1 Message Date
Timm Baeder
ad29ee51f4
[clang][bytecode] Always initialize scope before conditional operator (#171133)
Otherwise, the scope might be (lazily) initialized in one of the arms of
the conditional operator, which means the will NOT be intialized in the
other arm.

Fixes https://github.com/llvm/llvm-project/issues/170981
2025-12-09 08:03:27 +01:00
Timm Baeder
5b2eb0dcb7
[clang][bytecode][NFC] Add FullExpression scopes (#170705)
And use them instead of the extending decl. This is close to what the
current interpreter is doing.

This is NFC right now but fixes a problem I encountered while looking
into the expansion statement stuff.
2025-12-05 10:22:37 +01:00
Timm Baeder
d44d329c0b
[clang][bytecode] Fix compound assign operators for IntAP(S) (#169303)
We didn't take `IntAP`/`IntAPS` into account when casting to and from
the computation LHS type. This broke the
`std/ranges/range.factories/range.iota.view/end.pass.cpp` test.
2025-11-24 11:48:00 +01:00
Timm Baeder
95f0fab7fa
[clang][bytecode] Fix conditional operator scoping wrt. local variables (#169030)
We used to create a scope for the true- and false expression of a
conditional operator. This was done so e.g. in this example:

```c++
  struct A { constexpr A(){}; ~A(); constexpr int get() { return 10; } }; // all-note 2{{declared here}}
  static_assert( (false ? A().get() : 1) == 1);
```

we did _not_ evaluate the true branch at all, meaning we did not
register the local variable for the temporary of type `A`, which means
we also didn't call it destructor.

However, this breaks the case where the temporary needs to outlive the
conditional operator and instead be destroyed via the surrounding
`ExprWithCleanups`:
```
constexpr bool test2(bool b) {
  unsigned long __ms = b ? (const unsigned long &)0 : __ms;
  return true;
}
static_assert(test2(true));
```
Before this patch, we diagnosed this example:
```console
./array.cpp:180:15: error: static assertion expression is not an integral constant expression
  180 | static_assert(test2(true));
      |               ^~~~~~~~~~~
./array.cpp:177:24: note: read of temporary whose lifetime has ended
  177 |   unsigned long __ms = b ? (const unsigned long &)0 : __ms;
      |                        ^
./array.cpp:180:15: note: in call to 'test2(true)'
  180 | static_assert(test2(true));
      |               ^~~~~~~~~~~
./array.cpp:177:51: note: temporary created here
  177 |   unsigned long __ms = b ? (const unsigned long &)0 : __ms;
      |                                                   ^
1 error generated.
```
because the temporary created for the true branch got immediately
destroyed.

The problem in essence is that since the conditional operator doesn't
create a scope at all, we register the local variables for both its
branches, but we later only execute one of them, which means we should
also only destroy the locals of one of the branches.

We fix this similar to clang codgen's `is_active` flag: In the case of a
conditional operator (which is so far the only case where this is
problematic, and this also helps minimize the performance impact of this
change), we make local variables as disabled-by-default and then emit a
`EnableLocal` opcode later, which marks them as enabled. The code
calling their destructors checks whether the local was enabled at all.
2025-11-24 07:34:48 +01:00
Timm Baeder
cc4dd015ad
[clang][bytecode][NFC] Remove VariableScope::emitDestruction (#169148)
destroyLocals() does the same thing.
2025-11-22 16:41:00 +01:00
Timm Baeder
8e3188a47f
[clang][bytecode] Mark CXXDefaultInitExprs in InitLink chain (#166395)
So we know before _what_ entry in the chain we need to look for the
InitList.

Fixes https://github.com/llvm/llvm-project/issues/166171
2025-11-11 10:36:00 +01:00
Timm Baeder
a8a0ffba73
[clang][bytecode] Check source pointer for bitcast validity (#166907)
Unfortunately this is more dynamic than anticipated.

Fixes https://github.com/llvm/llvm-project/issues/165006
2025-11-10 08:17:08 +01:00
Timm Baeder
14c76437ee
[clang][bytecode] Check types when loading values (#165385)
We need to allow BitCasts between pointer types to different prim types,
but that means we need to catch the problem at a later stage, i.e. when
loading the values.

Fixes https://github.com/llvm/llvm-project/issues/158527
Fixes https://github.com/llvm/llvm-project/issues/163778
2025-11-05 16:02:19 +01:00
Timm Baeder
c750487292
[clang][bytecode] Diagnose volatile writes (#160350) 2025-09-28 07:21:40 +02:00
Timm Baeder
c46cf1ea3b
[clang][bytecode][NFC] Remove BlockScope (#158656)
Unused these days.
2025-09-16 05:10:13 +02:00
Timm Baeder
03c356c554
[clang][bytecode] Pass initializer along in evaluateAsInitializer() (#158056)
We just called `getInit()`, which isn't always correct and used the
wrong initializer in the module test case.
2025-09-15 07:39:11 +02:00
Timm Baeder
859e8a6d6b
[clang][bytecode] Implement C23 named loops (#156856) 2025-09-11 09:19:17 +02:00
Timm Baeder
46f2b35a98
[clang][bytecode][NFC] Remove instance pointer from emitDestruction (#157040)
We only call this when we just pushed a new pointer to the stack, so try
to save the folling PopPtr op by removing the pointer inside
emitDestruction directly, e.g. by letting the Call op just remove it.
2025-09-05 10:29:43 +02:00
Timm Baeder
ab8b4f6629
[clang][bytecode][NFC] Replace std::optional<unsigned> with UnsignedO… (#154286)
…rNone
2025-08-19 11:37:32 +02:00
Timm Baeder
a1039c1b84
[clang][bytecode] Fix initializing float elements from #embed (#154285)
Fixes #152885
2025-08-19 11:04:21 +02:00
Timm Baeder
0d05c42b6a
[clang][bytecode] Improve __builtin_{,dynamic_}object_size implementation (#153601) 2025-08-18 11:12:33 +02:00
Timm Baeder
2c40fd6dd1
[clang][bytecode] Use Param decl as variable source if we can (#152909)
This results in diagnostics that are closer to what the current
interpreter produces.
2025-08-10 16:58:42 +02:00
Timm Baeder
b9fef09e8e
[clang][bytecode] Add canClassify() helper (#152755)
Sometimes we don't need the return value of a classsify() call, we only
need to know if we can map the given Expr/Type to a primitive type. Add
canClassify() for that.
2025-08-09 15:08:14 +02:00
Timm Baeder
dc7c3c2b2b
[clang][bytecode] Disable location tracking for implicit field inits (#150190) 2025-08-05 13:14:01 +02:00
Timm Baeder
3c62303ac3
[clang][bytecode] Clean up {Compiler,Interp}.h (#151335)
Remove else after return and remove some unused includes.
2025-07-30 16:04:30 +02:00
Timm Baeder
23eef9a7c4
[clang][bytecode] Activate primitive fields before initializing them (#149963)
The initializer itself might need the field to be active.
2025-07-23 06:09:27 +02:00
Timm Baeder
e39ee62c5b
[clang][bytecode] Use OptPrimType instead of std::optional<PrimType> (#149812)
We use this construct a lot. Use something similar to clang's
UnsignedOrNone.

This results in some slighy compile time improvements:
https://llvm-compile-time-tracker.com/compare.php?from=17a4b0399d161a3b89d8f0ce82add1638f23f5d4&to=a251d81ecd0ed45dd190462663155fdb303ef04d&stat=instructions:u
2025-07-21 17:16:13 +02:00
Timm Baeder
17d3029331
[clang][bytecode] Make union activation more granular (#148835)
Only activate things if the syntactical structure suggests so. This adds
a bunch of new opcodes to control whether to activate in stores, etc.

Fixes #134789
2025-07-16 09:03:33 +02:00
Timm Baeder
376b3f7049
[clang][bytecode] Devirtualize calls during con- and destruction (#147685)
When compiliung compiling a ctor or dtor, we need to devirtualize the
virtual function calls so we always call the implementation of the
current class.
2025-07-09 14:37:10 +02:00
Timm Baeder
00cdaa5c39
[clang][bytecode] Add Descriptor::hasTrivialDtor() (#146286)
We sometimes used to have a long list of 

```
  GetLocalPtr
  PopPtr
  [...]
```

ops at the end of scopes, because we first got a pointer to a local
variable and only then did we figure out that we didn't actually want to
call the destructor for it. Add a new function that allows us to just
ask the `Descriptor` whether we need to call its destructor.
2025-06-30 16:59:57 +02:00
Timm Baeder
32fc625a3f
Reapply "Reapply "[clang][bytecode] Allocate IntegralAP and Floating … (#145014)
…types usi… (#144676)"

This reverts commit 68471d29eed2c49f9b439e505b3f24d387d54f97.

IntegralAP contains a union:
  union {
    uint64_t *Memory = nullptr;
    uint64_t Val;
  };

On 64bit systems, both Memory and Val have the same size. However, on 32
bit system, Val is 64bit and Memory only 32bit. Which means the default
initializer for Memory will only zero half of Val. We fixed this by
zero-initializing Val explicitly in the IntegralAP(unsigned BitWidth)
constructor.


See also the discussion in
https://github.com/llvm/llvm-project/pull/144246
2025-06-20 18:06:01 +02:00
Timm Bäder
68471d29ee Revert "Reapply "[clang][bytecode] Allocate IntegralAP and Floating types usi… (#144676)"
This reverts commit 7c15edb306932e41c159f3d69c161ed0d89d47b7.

This still breaks clang-armv8-quick:
https://lab.llvm.org/buildbot/#/builders/154/builds/17587
2025-06-18 15:17:53 +02:00
Timm Baeder
7c15edb306
Reapply "[clang][bytecode] Allocate IntegralAP and Floating types usi… (#144676)
…ng an allocator (#144246)"

This reverts commit 57828fec760f086b334ce0cb1c465fc559dcaea4.
2025-06-18 14:37:29 +02:00
Timm Bäder
57828fec76 Revert "[clang][bytecode] Allocate IntegralAP and Floating types using an allocator (#144246)"
This reverts commit c66be289901b3f035187d391e80e3610d7d6232e.

This breaks the armv8-quick builder:
https://lab.llvm.org/buildbot/#/builders/154/builds/17549
2025-06-17 21:08:23 +02:00
Timm Baeder
c66be28990
[clang][bytecode] Allocate IntegralAP and Floating types using an allocator (#144246)
Both `APInt` and `APFloat` will heap-allocate memory themselves using
the system allocator when the size of their data exceeds 64 bits.

This is why clang has `APNumericStorage`, which allocates its memory
using an allocator (via `ASTContext`) instead. Calling `getValue()` on
an ast node like that will then create a new `APInt`/`APFloat` , which
will copy the data (in the `APFloat` case, we even copy it twice).
That's sad but whatever.

In the bytecode interpreter, we have a similar problem. Large integers
and floating-point values are placement-new allocated into the
`InterpStack` (or into the bytecode, which is a `vector<std::byte>`).
When we then later interrupt interpretation, we don't run the destructor
for all items on the stack, which means we leak the memory the
`APInt`/`APFloat` (which backs the `IntegralAP`/`Floating` the
interpreter uses).

Fix this by using an approach similar to the one used in the AST. Add an
allocator to `InterpState`, which is used for temporaries and local
values. Those values will be freed at the end of interpretation. For
global variables, we need to promote the values to global lifetime,
which we do via `InitGlobal` and `FinishInitGlobal` ops.

Interestingly, this results in a slight _improvement_ in compile times:
https://llvm-compile-time-tracker.com/compare.php?from=6bfcdda9b1ddf0900f82f7e30cb5e3253a791d50&to=88d1d899127b408f0fb0f385c2c58e6283195049&stat=instructions:u
(but don't ask me why).

Fixes https://github.com/llvm/llvm-project/issues/139012
2025-06-17 18:31:06 +02:00
Timm Baeder
bca39f4e8f
[clang][bytecode] Add a scope to function calls (#140441)
We need a place to destroy the temporaries created for call arguments.
2025-05-19 11:49:27 +02:00
Timm Baeder
767a203a9e
[clang][bytecode] Fix discarded LValueToRValueBitCasts (#140034)
We handle discarding fine, but we used to ignore all discarded cast
expressions. Handle bitcasts differently.
2025-05-15 13:17:29 +02:00
Timm Baeder
3de2fa91e1
[clang][bytecode] Avoid classifying in visitArrayElemInit() (#139674)
We usually call this more than once, but the type of the initializer
never changes. Let's classify only once and pass that to
visitArrayElemInit().
2025-05-13 11:01:59 +02:00
Timm Baeder
a50269e999
[clang][bytecode] Diagnose dynamic_cast before C++20 (#137442)
Emit a CCE diagnostic.
2025-04-26 06:23:34 +02:00
Timm Baeder
05eafd9f2b
[clang][bytecode] Explicitly mark constexpr-unknown variables as such (#135806)
Instead of trying to figure out what's constexpr-unknown later on.
2025-04-16 09:00:52 +02:00
Timm Baeder
09588e93bb
[clang][bytecode] Fix an inconsistency with loop condition jumps (#135530)
When emitting the jump for e.g. a for loop condition, we used to jump
out of the CondScope, leaving the scope initialized, because we skipped
the corresponding Destroy opcode. If that loop was in a loop itself,
that outer loop could then iterate once more, leading to us initializing
a scope that was still initialized.
Fix this by also destroying the scope after the EndLabel.
2025-04-13 12:25:29 +02:00
Timm Baeder
e0db41615b
[clang][bytecode] Fix initializing array struct fields from an APValue (#131983)
We need to recurse once more here and move the array case into the
bigger if chain.
2025-03-19 12:43:37 +01:00
Younan Zhang
f4218753ad
[Clang] Implement P0963R3 "Structured binding declaration as a condition" (#130228)
This implements the R2 semantics of P0963.

The R1 semantics, as outlined in the paper, were introduced in Clang 6.
In addition to that, the paper proposes swapping the evaluation order of
condition expressions and the initialization of binding declarations
(i.e. std::tuple-like decompositions).
2025-03-11 15:41:56 +08:00
Timm Baeder
d08cf7900d
[clang][bytecode] Implement __builtin_constant_p (#130143)
Use the regular code paths for interpreting.

Add new instructions: `StartSpeculation` will reset the diagnostics
pointers to `nullptr`, which will keep us from reporting any diagnostics
during speculation. `EndSpeculation` will undo this.

The rest depends on what `Emitter` we use.

For `EvalEmitter`, we have no bytecode, so we implement `speculate()` by
simply visiting the first argument of `__builtin_constant_p`. If the
evaluation fails, we push a `0` on the stack, otherwise a `1`.

For `ByteCodeEmitter`, add another instrucion called `BCP`, that
interprets all the instructions following it until the next
`EndSpeculation` instruction. If any of those instructions fails, we
jump to the `EndLabel`, which brings us right before the
`EndSpeculation`. We then push the result on the stack.
2025-03-08 06:06:14 +01:00
Timm Baeder
97ed2019c4
[clang][bytecode] Use ExtendingDecl mechanism for primitives as well (#128141)
... when creating the temporary variables for a
MaterializeTemporaryExpr.
2025-02-21 09:47:08 +01:00
Timm Baeder
707e2b83a5
[clang][bytecode] Handle union move assignment operators as well (#125516) 2025-02-03 17:43:32 +01:00
Timm Baeder
21a8c920fe
[clang][bytecode] Add special handling for union copy assign operators (#125476) 2025-02-03 12:41:49 +01:00
Timm Baeder
d2d8e2e030
[clang][bytecode] Handle invalid temporary descriptors (#125033)
This happens e.g. when a vector element type is not primitive.
2025-01-31 08:53:31 +01:00
Timm Baeder
58fa55c04b
[clang][bytecode] Add init link for the RVO ptr (#122904) 2025-01-14 17:18:04 +01:00
Timm Baeder
ac857f9bdd
[clang][bytecode] Change the way we do init chains (#122871)
See the comment in Compiler<>::VisitCXXThisExpr.
We need to mark the InitList explicitly, so we later know what to refer
to when the init chain is active.
2025-01-14 10:57:36 +01:00
Timm Baeder
e86b68ff56
[clang][bytecode] Add support for typeid pointers (#121251)
Add it as another kind of pointer, saving both a `Type*` for the result
of the typeid() expression as well as one for the type of the typeid
expression.
2024-12-28 14:07:01 +01:00
Timm Baeder
ceaf6e912a
[clang][bytecode] Support ImplicitValueInitExpr for multi-dim arrays (#117312)
The attached test case from
https://github.com/llvm/llvm-project/issues/117294 used to cause an
assertion because we called classifPrim() on an array type.

The new result doesn't crash but isn't exactly perfect either. Since the
problem arises when evaluating an ImplicitValueInitExpr, we have no
proper source location to point to. Point to the caller instead.
2024-11-25 12:15:31 +01:00
Timm Baeder
ef2a104c94
[clang][bytecode] Start implementing __builtin_bit_cast (#112126)
This is a subset of #68288, with hopefully narrower scope. It does not
support bitcasting to non-integral types yet.
Bitfields are supported, but only if they result in a full byte-sized
final buffer. It does not support casting from null-pointers yet or
casting from indeterminate bits.


The tests are from #68288 and partially from #74775.

The `BitcastBuffer` struct is currently always working in single bits,
but I plan to (try to) optimize this for the common full-byte case.
2024-10-31 18:09:40 +01:00
Timm Baeder
9ae41c24b3
[clang][bytecode] Create dummy pointers for non-reference DeclRefExprs (#113202)
... with non-constant initializers.
2024-10-22 10:38:13 +02:00
Timm Baeder
55d51dd9dc
[clang][bytecode] Fix temporary lvalue base expression (#111808)
We need to use the MaterializeTemporaryExpr here so the checks in
ExprConstant.cpp do the right thing.
2024-10-10 14:10:38 +02:00