Introduce a New DRuntime Hook Lowering Pass to Unify the Logic for All Hooks

Teodor Dutu teodor.dutu at gmail.com
Thu Feb 8 14:58:13 UTC 2024


Hi,

I am trying to add a template lowering for `ArrayLiteralExp`s. It 
should call `_d_arrayliteralTX` [1]. I introduced all previous 
lowerings in `expressionsem.d` and intended to do the same with 
this one by adding it here [2]. However, `ArrayLiteralExp`s are 
more finicky than other expressions because the compiler makes 
many optimisations that end up creating additional 
`ArrayLiteralExp`s or changing their type. Below are the main 
issues:

a. `constfold.d` will replace expressions such as `[1, 2] ~ 3` 
with `[1, 2, 3]` here [3]. The new `ArrayLiteralExp` is not 
semantically analysed (because it's obvious that the result has a 
correct type if the operands do so) and its type is set to that 
of `[1, 2]`. However, this causes `[1, 2, 3]` to miss its 
lowering. Also notice that now the lowering of `[1, 2]` is no 
longer used.

b. Sometimes the type of the array literal is promoted to the 
type of the variable in which it's stored. Consider this 
expression: `long[] arr = [1, 2, 3]`. `[1, 2, 3]` is initially 
analysed and its type inferred to `int[]` [2]. Then its type is 
bumped up to `long[]` using `implicitCastTo` [4]. If the hook is 
inserted in [2], its type is int[], thus causing an incorrect 
allocation of `3 * 4 = 12` bytes instead of `3 * 8 = 24`. This, 
in turn, leads to heap corruptions when initialising the elements 
of the array as `long`s.

Problem a can be solved individually by copying the lowering of 
`[1, 2]` to `[1, 2, 3]` and then updating the length argument of 
the hook from 2 to 3 in `e2ir.d` [5], which is where the AST no 
longer suffers any changes. This is ugly because it requires many 
changes to `constfold.d` and changes the logic of `e2ir.d`, which 
will require the same changes to be mimicked by GDC and LDC's 
glue layers. Problem b can also be solved individually by also 
performing the lowering in `implicitCastTo` [4]. But this 
solution is also ugly because now the lowering is performed in 2 
places, one of which is totally unintuitive. Coupled with the 
difficulties introduced by the solution to problem b, this patch 
is scattered all over the place, making code difficult to 
maintain and lacking in performance because of all the redundant 
lowerings and analyses made.

Hence what I am proposing as a global solution to both a and b 
and also applicable to other hooks is to create another pass just 
for lowering, after semantic analysis has finished and has 
produced a definitive AST. This will provide a unified place to 
introduce all DRuntime lowerings, thus leading to more readable 
and maintainable code in the long run. Traversing the AST in this 
manner will hurt performance, which is why it would be enough to 
just store the nodes that require lowerings in an array so that 
this new pass just iterates this much smaller array instead of 
the whole AST.

What do you think about my proposal in the paragraph above? Can 
you think of better approaches that you can suggest instead?

Thanks,
Teo

[1] 
https://github.com/dlang/dmd/blob/67135935086494408e511abad3d1dae7eda4699d/druntime/src/rt/lifetime.d#L2122-L2140
[2] 
https://github.com/dlang/dmd/blob/67135935086494408e511abad3d1dae7eda4699d/compiler/src/dmd/expressionsem.d#L4382-L4427
[3] 
https://github.com/dlang/dmd/blob/67135935086494408e511abad3d1dae7eda4699d/compiler/src/dmd/constfold.d#L1624
[4] 
https://github.com/dlang/dmd/blob/67135935086494408e511abad3d1dae7eda4699d/compiler/src/dmd/dcast.d#L185-L194
[5] 
https://github.com/dlang/dmd/blob/67135935086494408e511abad3d1dae7eda4699d/compiler/src/dmd/e2ir.d#L4051-L4054


More information about the Digitalmars-d mailing list