Zero initialization for globals with common linkage

In LLVM there is a feature for zero-initializing aggregate types like arrays. It’s called zeroinitializer (LLVM Language Reference Manual — LLVM 16.0.0git documentation).
In my MLIR dialect I have created a tensor-like type which I use for global declarations that have common linkage (common linkage requires a zero initializer).

Is there currently a way to use the zeroinitializer feature in the LLVM MLIR dialect ?

Not directly, and it is unclear to me whether we want a cross-type zero initializer or prefer something more structured. In the meantime, it is possible to create globals filled with zeros by using attributes with splat elements attributes:

llvm.mlir.global internal @a2(dense<0.0> : tensor<3xf32>) : !llvm.array<3xfloat>

llvm.mlir.global @cplx() : !llvm.struct<(array<2xi32>, array<3xfloat>)> {
  %0 = llvm.mlir.undef : !llvm.struct<(array<2xi32>, array<3xfloat>)>
  %1 = llvm.mlir.constant(dense<0> : tensor<2xi32>) : !llvm.array<2xi32>
  %2 = llvm.insertvalue %1, %0[0] : !llvm.struct<(array<2xi32>, array<3xfloat>)>
  %3 = llvm.mlir.constant(dense<0.0> : tensor<3xf32>) : !llvm.array<3xfloat>
  %4 = llvm.insertvalue %3, %2[1] :!llvm.struct<(array<2xi32>, array<3xfloat>)>
  llvm.return %4 : !llvm.struct<(array<2xi32>, array<3xfloat>)>
}

1 Like

It would be a “nice to have” feature in the LLVM IR dialect if there was a direct way to be able to generate zeroinitializer for aggregates. Fortran COMMON blocks (from which the linkage name derives) would be simpler to code gen, etc.

Reviving this old thread. I’m working on some code to zero-initialize globals in Flang. See:
https://reviews.llvm.org/D149877

It would make my life [and probably many other people’s lives] easier to have a mlir::LLVM::ZeroOp or mlir::LLVM::ZeroInitializer, similar to the mlir::LLVM::UndefOp, rather than first generating a bunch of code to set individual elements to zero, only for the translation to then find that “everything is zero, so set it zeroinitializer instead”. We may as well carry it forward as “this is all zeros”.

Adding a ZeroOp to LLVM dialect sounds useful if you have cycles to work on it!

As mentioned by @ftynse, splat constants may be a good approach for zero initialized arrays that work out-of-the-box with the current version of LLVM dialect.

I’m not opposed to having such an op, but the design must ensure it follows the overall principles of the LLVM dialect design. Specifically, we chose not to replicate the LLVM IR’s design that duplicates a part of the instruction set in constant expressions and use the regular operations instead. So the proposed zeroinitializer op must be usable everywhere without the need to introduce some zeroinit attribute, e.g., in globals.

1 Like

I have created a ticket internally for this to be worked on. Not sure how it will end up in the order of things to do yet, but I will try to get some time for working on this…

Reviving this thread again.

I’m currently working on a patch to add LLVM target extension types (TargetExtType) to the MLIR LLVM dialect: ⚙ D151446 [mlir][llvm] Add LLVM TargetExtType

Some target extension types can have zeroinitializer as constant value and in those cases zeroinitializer is the only permitted constant value (besides undef and poison).

As the target extension types are opaque to the compiler by design, the number of elements to initialize is unknown and filling with zeros is more difficult, so having an explicit zeroinitializer would be nice for this use-case.

@Leporacanthicus: Is there any update on adding a zeroinitializer operation to the LLVM dialect?

I’m afraid I’ve done nothing on that so far - and I’m about to move about in out organisation, so may not be able to work on this for some time - although I’ll still be working on MLIR, so it’s plausible I can get to it.

Jumping into the conversation here.

I’ve recently had issues zero-initializing large arrays of complex structs in ClangIR. I believe a llvm.mlir.zero operation to zero-initialize types would be of great help.

Is there anyone working on this? I have an idea of how to implement it, but I’m not sure if it will abide by LLVM’s dialect design.

3 Likes

Looks reasonable to me. Not sure if any of the others who have commented on the thread agrees… :slight_smile:

1 Like

A zero initializer operation sounds like a welcome addition to the LLVM dialect! In particular, it is preferable over having an attribute as discussed above.

1 Like

It will be consistent with how we are handling the other constant values (undef, poison): 'llvm' Dialect - MLIR.

1 Like

Thanks for working on this, looks very useful!

The draft only shows use in globals, but I assume the operation would also be usable outside initialization of globals, right?

1 Like

Thanks everyone for the feedback!

I have an idea of how to implement it

It seems that the idea is a good starting point. I’ll try to open a patch in LLVM this week and follow through on any design issues there.

I assume the operation would also be usable outside initialization of globals, right?

It’s supposed to work @sommerlukas. I’ll add some tests for non-global variables to make sure!

2 Likes

Quick follow-up: the llvm.mlir.zero patch has been merged.

5 Likes

Awesome, thanks!