Why there's no "std.undef"?


The LLVM and SPIRV dialects provide an “undef” operation that comes handy when generating code - simply because sometimes a variable does not need to take a precise value, so no code is needed to do so.

I was wondering why the std dialect does not provide it.


The major challenge the standard dialect faces is definitional - what do we include, more importantly what do we exclude. Furthermore, for anything we include, we need clearly defined semantics. This is one of the major challenges with undef.

And yet “undefined” exists in various programming language semantics. It can be either seen as an arbitrary value or as a special undefined symbol whose use in computations produces other undefined values.

I think the subtlety is that while “undefined” exists in many language, it does not have the same semantic for each language. That makes it challenging when defining an IR, and undef in LLVM is quite complex already, and still not satisfactory actually (seeing the recent years attempt to evolve it): see for example https://www.cs.utah.edu/~regehr/papers/undef-pldi17.pdf

1 Like

And even some thinking about removing undef as is from LLVM (Alive2 Part 3: Things You Can and Can’t Do with Undef in LLVM – Embedded in Academia).

Stepping up, you mention variable that need not be initialized & codegen, is this already in buffer world? We don’t really have variables in std (well beyond loop induction variables where this would not apply).

In the LLVM world, you can use undef to get an uninitialized SSA value. The “variable” here refers to a C/C++ variables which gets turned into an SSA value as possible.

int foo() {
  int i;
  return i;

would yield:

define dso_local i32 @_Z3foov() local_unnamed_addr #0 {
  ret i32 undef

Also aggregates and vectors are built piecewise by starting with an undef value and inserting elements one by one, like this for example:

  %ins = insertelement <2 x double> undef, double %x, i32 %y

So unsurprisingly, the LLVM dialect in MLIR has this ability as well, using (like for every constant) an operation instead: https://github.com/llvm/llvm-project/blob/master/mlir/test/Target/llvmir.mlir#L417

  %3 = llvm.mlir.undef : !llvm.struct<(ptr<float>)>

The SPIRV dialect also has an undef, but with a different semantics than LLVM I believe.