This is an archive of the discontinued LLVM Phabricator instance.

[flang][hlfir] add hlfir.shape_of
ClosedPublic

Authored by tblah on Mar 24 2023, 10:41 AM.

Details

Summary

This is an operation which returns the fir.shape for a hlfir.expr.

A hlfir.expr can be defined by:

  • A transformational intrinsic (e.g. hlfir.matmul)
  • hlfir.as_expr
  • hlfir.elemental

hlfir.elemental is easy because there is a compulsory shape operand.
hlfir.as_expr is defined as operating on a variable (defined using a
hlfir.declare). hlfir.declare has an optional shape argument. The
transformational intrinsics do not have an associated shape.

If all extents are known at compile time, the extents for the shape can
be fetched from the hlfir.expr's type. For example, the result of a
hlfir.matmul with arguments who's extents are known at compile time will
have constant extents which can be queried from the type. In this case
the hlfir.shape_of will be canonicalised to a fir.shape operation using
those extents.

If not all extents are known at compile time, shapes have to be read
from boxes after bufferization. In the case of the transformational
intrinsics, the shape read from the result box can be queried from the
hlfir.declare operation for the buffer allocated to that hlfir.expr (via
the hlfir.as_expr).

Diff Detail

Event Timeline

tblah created this revision.Mar 24 2023, 10:41 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald Transcript
tblah requested review of this revision.Mar 24 2023, 10:41 AM
tblah edited the summary of this revision. (Show Details)Mar 24 2023, 10:44 AM

Other than the circular dependency issue, LGTM.

Some cases are impossible to resolve using hlfir.shape_of. For example,

func.func @bad(%arg0: !hlfir.expr<?xi32>) {

%shape = hlfir.shape_of %arg0 : (!hlfir.expr<?xi32>) -> !fir.shape<1>

}
Here there is no way to get additional information about this
hlfir.expr and its extents are not known at compile time. Lowering must
not create MLIR like this. If this happens, there will be a failure in
the bufferization pass.

I agree this is not a desired pattern, but do not think it is impossible to support if we ever need to. This could translate to func.func @bad(%arg0: tuple<!fir.box<!fir.array<?xi32>>, i1>) { .... (hlfir.expr are translated to a tuple with the storage of the expression value, and a boolean flag indicating if the storage must be deallocated when hitting an hlfir.destroy). So the !fir.box would be here to support the shape. This comment does not change anything to your patch though (my code suggestion in D146833 will put some light on this. Note that we indeed do not currently translate block argument hlfir.expr type as illustrated above, so this would still fail to compile, but we could if we wanted/needed to).

flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
17

I think genExprShape cannot be here, this will create circular dependencies in shared library builds. Can't genExprShape use an mlir::OpBuilder &builder instead of a fir::FirOpBuilder, I am not sure the FirOpBuilder specific helpers are used by it, and since a FirOpBuilder inherits from mlir::OpBuilder, it can still be passed to genExprShape.

tblah updated this revision to Diff 513198.Apr 13 2023, 5:48 AM
tblah marked an inline comment as done.

Thanks for review.

Updated to fix the circular dependency.

tblah edited the summary of this revision. (Show Details)Apr 13 2023, 5:58 AM

LGTM

flang/include/flang/Optimizer/HLFIR/HLFIROps.td
766

Can probably also be given the Pure interface.

jeanPerier accepted this revision.Apr 13 2023, 9:45 AM
This revision is now accepted and ready to land.Apr 13 2023, 9:45 AM
tblah updated this revision to Diff 513536.Apr 14 2023, 4:22 AM

Add pure attribute to operation definition

jeanPerier accepted this revision.Apr 14 2023, 6:44 AM