Changing Operation results in place

Hello,

We have an operation with a single graph region and single terminator:

def Yield_Op : Op<"yield", [
        NoSideEffect, Terminator, HasParent<"Region_Op">
    ]> {

  let arguments = (ins
    Variadic<AnyType>:$operands
  );
}

def Region_Op : Op<"region", [
      SingleBlockImplicitTerminator<"Yield_Op">,
      RegionKindInterface
    ]> {

  let regions = (region
    SizedRegion<1>:$body
  );

  let results = (outs
    Variadic<AnyType>:$outputs);
}

In the end the types and number of outputs should match the terminator
operands.

In our passes we first create a region op with a dummy results type, and after
creation we fill its region with some other ops and a terminator. Only at that
point we know the number of outputs and their types. We can
replace region op with a new region op with a matching result type, but there
seems to be no obvious way to mutate the number and type of results of the
existing region op in place.

The generated code for ops creates API returning ::mlir::MutableOperandRange for operands, but something like ::mlir::MutableResultRange doesn’t exist. Is replacing the existing op the only way?

You can’t mutate the number of results, but you can change their type with setType - but that’s strongly discouraged except in special situations. The storage for results is allocated only when the op is created.

Thanks! That is a bit unfortunate though.

You can consider creating a detached region / block, populating it with the ops and create the surrounding op after that. It is possible to move the contents of a region to another region with, e.g., Region::takeBody.