Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions flang/include/flang/Optimizer/Dialect/FIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -3178,9 +3178,11 @@ def fir_IsPresentOp : fir_SimpleOp<"is_present", [NoMemoryEffect]> {
// operations if the values are unused. fir.declare may be used to generate
// debug information so we would like to keep this around even if the value
// is not used.
def fir_DeclareOp : fir_Op<"declare", [AttrSizedOperandSegments,
MemoryEffects<[MemAlloc<DebuggingResource>]>,
DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>]> {
def fir_DeclareOp
: fir_Op<"declare", [AttrSizedOperandSegments,
MemoryEffects<[MemAlloc<DebuggingResource>]>,
DeclareOpInterfaceMethods<
fir_FortranVariableStorageOpInterface>]> {
let summary = "declare a variable";

let description = [{
Expand All @@ -3203,6 +3205,9 @@ def fir_DeclareOp : fir_Op<"declare", [AttrSizedOperandSegments,
It must always be provided for characters and parametrized derived types
when memref is not a box value or address.

The storage and storage_offset operands are optional and are required
for FortranVariableStorageOpInterface, where they are documented.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to mention this for the HLFIR op too, and to explain the defaults assumed when these new attributes are not specified.

Example:

CHARACTER(n), OPTIONAL, TARGET :: c(10:, 20:)
Expand All @@ -3220,21 +3225,22 @@ def fir_DeclareOp : fir_Op<"declare", [AttrSizedOperandSegments,
```
}];

let arguments = (ins
AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Variadic<AnyIntegerType>:$typeparams,
Optional<fir_DummyScopeType>:$dummy_scope,
Builtin_StringAttr:$uniq_name,
OptionalAttr<fir_FortranVariableFlagsAttr>:$fortran_attrs,
OptionalAttr<cuf_DataAttributeAttr>:$data_attr
);
let arguments = (ins AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Variadic<AnyIntegerType>:$typeparams,
Optional<fir_DummyScopeType>:$dummy_scope,
Optional<AnyReferenceLike>:$storage,
DefaultValuedAttr<UI64Attr, "0">:$storage_offset,
Builtin_StringAttr:$uniq_name,
OptionalAttr<fir_FortranVariableFlagsAttr>:$fortran_attrs,
OptionalAttr<cuf_DataAttributeAttr>:$data_attr);

let results = (outs AnyRefOrBox);

let assemblyFormat = [{
$memref (`(` $shape^ `)`)? (`typeparams` $typeparams^)?
(`dummy_scope` $dummy_scope^)?
(`storage` `(` $storage^ `[` $storage_offset `]` `)`)?
attr-dict `:` functional-type(operands, results)
}];

Expand Down
7 changes: 4 additions & 3 deletions flang/include/flang/Optimizer/Dialect/FIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,10 @@ def AnyCompositeLike : TypeConstraint<Or<[fir_RecordType.predicate,
"any composite">;

// Reference types
def AnyReferenceLike : TypeConstraint<Or<[fir_ReferenceType.predicate,
fir_HeapType.predicate, fir_PointerType.predicate,
fir_LLVMPointerType.predicate]>, "any reference">;
def AnyReferenceLike
: Type<Or<[fir_ReferenceType.predicate, fir_HeapType.predicate,
fir_PointerType.predicate, fir_LLVMPointerType.predicate]>,
"any reference">;

def FuncType : TypeConstraint<FunctionType.predicate, "function type">;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpDefinition.h"

namespace fir::detail {
/// Verify operations implementing FortranVariableStorageOpInterface.
mlir::LogicalResult verifyFortranVariableStorageOpInterface(mlir::Operation *);
} // namespace fir::detail

#include "flang/Optimizer/Dialect/FortranVariableInterface.h.inc"

#endif // FORTRAN_OPTIMIZER_DIALECT_FORTRANVARIABLEINTERFACE_H
46 changes: 46 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,50 @@ def fir_FortranVariableOpInterface : OpInterface<"FortranVariableOpInterface"> {

}

def fir_FortranVariableStorageOpInterface
: OpInterface<"FortranVariableStorageOpInterface",
[fir_FortranVariableOpInterface]> {
let description = [{
An extension of FortranVariableOpInterface for operations that provide
information about the physical storage layout of the variable.
The operations provide the raw address of the physical storage
and the byte offset where the variable begins within the physical
storage.
The storage is a reference to an array of known size consisting
of i8 elements. This is how Flang represents COMMON and EQUIVALENCE
storage blocks with the member variables located within the storage
at different offsets. The storage offset for a variable must not
exceed the storage size. Note that the zero-sized variables
may start at the offset that is after the final byte of the storage.
}];

let methods =
[InterfaceMethod<
/*desc=*/"Returns the raw address of the physical storage",
/*retTy=*/"mlir::Value",
/*methodName=*/"getStorage",
/*args=*/(ins),
/*methodBody=*/[{}],
/*defaultImplementation=*/[{
ConcreteOp op = mlir::cast<ConcreteOp>(this->getOperation());
return op.getStorage();
}]>,
InterfaceMethod<
/*desc=*/"Returns the byte offset where the variable begins "
"within the physical storage",
/*retTy=*/"std::uint64_t",
/*methodName=*/"getStorageOffset",
/*args=*/(ins),
/*methodBody=*/[{}],
/*defaultImplementation=*/[{
ConcreteOp op = mlir::cast<ConcreteOp>(this->getOperation());
return op.getStorageOffset();
}]>,
];

let cppNamespace = "fir";
let verify =
[{ return detail::verifyFortranVariableStorageOpInterface($_op); }];
}

#endif // FORTRANVARIABLEINTERFACE
27 changes: 15 additions & 12 deletions flang/include/flang/Optimizer/HLFIR/HLFIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ class hlfir_Op<string mnemonic, list<Trait> traits>
// removed by dead code elimination if the value result is unused. Information
// from the declare operation can be used to generate debug information so we
// don't want to remove it as dead code
def hlfir_DeclareOp : hlfir_Op<"declare", [AttrSizedOperandSegments,
MemoryEffects<[MemAlloc<DebuggingResource>]>,
DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>]> {
def hlfir_DeclareOp
: hlfir_Op<"declare", [AttrSizedOperandSegments,
MemoryEffects<[MemAlloc<DebuggingResource>]>,
DeclareOpInterfaceMethods<
fir_FortranVariableStorageOpInterface>]> {
let summary = "declare a variable and produce an SSA value that can be used as a variable in HLFIR operations";

let description = [{
Expand Down Expand Up @@ -84,21 +86,22 @@ def hlfir_DeclareOp : hlfir_Op<"declare", [AttrSizedOperandSegments,
```
}];

let arguments = (ins
AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Variadic<AnyIntegerType>:$typeparams,
Optional<fir_DummyScopeType>:$dummy_scope,
Builtin_StringAttr:$uniq_name,
OptionalAttr<fir_FortranVariableFlagsAttr>:$fortran_attrs,
OptionalAttr<cuf_DataAttributeAttr>:$data_attr
);
let arguments = (ins AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Variadic<AnyIntegerType>:$typeparams,
Optional<fir_DummyScopeType>:$dummy_scope,
Optional<AnyReferenceLike>:$storage,
DefaultValuedAttr<UI64Attr, "0">:$storage_offset,
Builtin_StringAttr:$uniq_name,
OptionalAttr<fir_FortranVariableFlagsAttr>:$fortran_attrs,
OptionalAttr<cuf_DataAttributeAttr>:$data_attr);

let results = (outs AnyFortranVariable, AnyRefOrBoxLike);

let assemblyFormat = [{
$memref (`(` $shape^ `)`)? (`typeparams` $typeparams^)?
(`dummy_scope` $dummy_scope^)?
(`storage` `(` $storage^ `[` $storage_offset `]` `)`)?
attr-dict `:` functional-type(operands, results)
}];

Expand Down
9 changes: 5 additions & 4 deletions flang/lib/Optimizer/Builder/FIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,11 @@ mlir::Value fir::FirOpBuilder::genTempDeclareOp(
llvm::ArrayRef<mlir::Value> typeParams,
fir::FortranVariableFlagsAttr fortranAttrs) {
auto nameAttr = mlir::StringAttr::get(builder.getContext(), name);
return fir::DeclareOp::create(builder, loc, memref.getType(), memref, shape,
typeParams,
/*dummy_scope=*/nullptr, nameAttr, fortranAttrs,
cuf::DataAttributeAttr{});
return fir::DeclareOp::create(
builder, loc, memref.getType(), memref, shape, typeParams,
/*dummy_scope=*/nullptr,
/*storage=*/nullptr,
/*storage_offset=*/0, nameAttr, fortranAttrs, cuf::DataAttributeAttr{});
}

mlir::Value fir::FirOpBuilder::genStackSave(mlir::Location loc) {
Expand Down
27 changes: 27 additions & 0 deletions flang/lib/Optimizer/Dialect/FortranVariableInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,30 @@ fir::FortranVariableOpInterface::verifyDeclareLikeOpImpl(mlir::Value memref) {
}
return mlir::success();
}

mlir::LogicalResult
fir::detail::verifyFortranVariableStorageOpInterface(mlir::Operation *op) {
auto storageIface = mlir::cast<fir::FortranVariableStorageOpInterface>(op);
mlir::Value storage = storageIface.getStorage();
std::uint64_t storageOffset = storageIface.getStorageOffset();
if (!storage) {
if (storageOffset != 0)
op->emitOpError("storage offset specified without the storage reference");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
op->emitOpError("storage offset specified without the storage reference");
return op->emitOpError("storage offset specified without the storage reference");

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Thanks!

return mlir::success();
}

auto storageType =
mlir::dyn_cast<fir::SequenceType>(fir::unwrapRefType(storage.getType()));
if (!storageType || storageType.getDimension() != 1)
return op->emitOpError("storage must be a vector");
if (storageType.hasDynamicExtents())
return op->emitOpError("storage must have known extent");
if (storageType.getEleTy() != mlir::IntegerType::get(op->getContext(), 8))
return op->emitOpError("storage must be an array of i8 elements");
if (storageOffset > storageType.getConstantArraySize())
return op->emitOpError("storage offset exceeds the storage size");
// TODO: we should probably verify that the (offset + sizeof(var))
// is within the storage object, but this requires mlir::DataLayout.
// Can we make it available during the verification?
return mlir::success();
}
3 changes: 2 additions & 1 deletion flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
auto [hlfirVariableType, firVarType] =
getDeclareOutputTypes(inputType, hasExplicitLbs);
build(builder, result, {hlfirVariableType, firVarType}, memref, shape,
typeparams, dummy_scope, nameAttr, fortran_attrs, data_attr);
typeparams, dummy_scope, /*storage=*/nullptr, /*storage_offset=*/0,
nameAttr, fortran_attrs, data_attr);
}

llvm::LogicalResult hlfir::DeclareOp::verify() {
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ class DeclareOpConversion : public mlir::OpRewritePattern<hlfir::DeclareOp> {
auto firDeclareOp = fir::DeclareOp::create(
rewriter, loc, memref.getType(), memref, declareOp.getShape(),
declareOp.getTypeparams(), declareOp.getDummyScope(),
/*storage=*/declareOp.getStorage(),
/*storage_offset=*/declareOp.getStorageOffset(),
declareOp.getUniqName(), fortranAttrs, dataAttr);

// Propagate other attributes from hlfir.declare to fir.declare.
Expand Down
19 changes: 19 additions & 0 deletions flang/test/Fir/declare.fir
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,22 @@ func.func @array_declare_unlimited_polymorphic_boxaddr(%arg0: !fir.ref<!fir.clas
// CHECK-LABEL: func.func @array_declare_unlimited_polymorphic_boxaddr(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.class<!fir.ptr<!fir.array<?x?xnone>>>>) {
// CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x?xnone>>>>) -> !fir.ref<!fir.class<!fir.ptr<!fir.array<?x?xnone>>>>

// CHECK-LABEL: func.func @vars_within_physical_storage() {
// CHECK: %[[VAL_2:.*]] = fir.address_of(@block_) : !fir.ref<!fir.array<8xi8>>
// CHECK: %[[VAL_6:.*]] = fir.declare %{{.*}} storage(%[[VAL_2]][0]) {uniq_name = "a"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
// CHECK: %[[VAL_9:.*]] = fir.declare %{{.*}} storage(%[[VAL_2]][4]) {uniq_name = "b"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
fir.global common @block_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
func.func @vars_within_physical_storage() {
%c4 = arith.constant 4 : index
%c0 = arith.constant 0 : index
%1 = fir.address_of(@block_) : !fir.ref<!fir.array<8xi8>>
%2 = fir.convert %1 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
%3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
%5 = fir.declare %4 storage (%1[0]) {uniq_name = "a"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
%6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
%8 = fir.declare %7 storage (%1[4]) {uniq_name = "b"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
return
}
57 changes: 57 additions & 0 deletions flang/test/Fir/invalid.fir
Original file line number Diff line number Diff line change
Expand Up @@ -1426,3 +1426,60 @@ func.func @wrong_weights_number_in_if_then_else(%cond: i1) {
}
return
}

// -----

func.func @fir_declare_bad_storage_offset(%arg0: !fir.ref<!fir.array<8xi8>>) {
%c0 = arith.constant 0 : index
%addr = fir.address_of(@block_) : !fir.ref<!fir.array<8xi8>>
%2 = fir.convert %addr : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
%var = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
// expected-error@+1 {{negative integer literal not valid for unsigned integer type}}
%decl = fir.declare %var storage (%addr[-1]) {uniq_name = "a"} : (!fir.ref<i8>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<i8>
return
}

// -----

"func.func"() <{function_type = (!fir.ref<!fir.array<8xi8>>) -> (), sym_name = "fir_declare_bad_storage_offset"}> ({
^bb0(%arg0: !fir.ref<!fir.array<8xi8>>):
%0 = "arith.constant"() <{value = 0 : index}> : () -> index
%1 = "fir.address_of"() <{symbol = @block_}> : () -> !fir.ref<!fir.array<8xi8>>
%2 = "fir.convert"(%1) : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
%3 = "fir.coordinate_of"(%2, %0) <{baseType = !fir.ref<!fir.array<?xi8>>}> : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
// expected-error@+1 {{storage offset specified without the storage reference}}
%4 = "fir.declare"(%3) <{operandSegmentSizes = array<i32: 1, 0, 0, 0, 0>, storage_offset = 1 : ui64, uniq_name = "a"}> : (!fir.ref<i8>) -> !fir.ref<i8>
"func.return"() : () -> ()
}) : () -> ()

// -----

func.func @fir_declare_bad_storage(%arg0: !fir.ref<i8>) {
// expected-error@+1 {{storage must be a vector}}
%decl = fir.declare %arg0 storage (%arg0[0]) {uniq_name = "a"} : (!fir.ref<i8>, !fir.ref<i8>) -> !fir.ref<i8>
return
}

// -----

func.func @fir_declare_bad_storage(%arg0: !fir.ref<i8>, %arg1: !fir.ref<!fir.array<?xi8>>) {
// expected-error@+1 {{storage must have known extent}}
%decl = fir.declare %arg0 storage (%arg1[0]) {uniq_name = "a"} : (!fir.ref<i8>, !fir.ref<!fir.array<?xi8>>) -> !fir.ref<i8>
return
}

// -----

func.func @fir_declare_bad_storage(%arg0: !fir.ref<i8>, %arg1: !fir.ref<!fir.array<1xi32>>) {
// expected-error@+1 {{storage must be an array of i8 elements}}
%decl = fir.declare %arg0 storage (%arg1[0]) {uniq_name = "a"} : (!fir.ref<i8>, !fir.ref<!fir.array<1xi32>>) -> !fir.ref<i8>
return
}

// -----

func.func @fir_declare_bad_storage_offset(%arg0: !fir.ref<i8>, %arg1: !fir.ref<!fir.array<1xi8>>) {
// expected-error@+1 {{storage offset exceeds the storage size}}
%decl = fir.declare %arg0 storage (%arg1[2]) {uniq_name = "a"} : (!fir.ref<i8>, !fir.ref<!fir.array<1xi8>>) -> !fir.ref<i8>
return
}
27 changes: 27 additions & 0 deletions flang/test/HLFIR/declare-codegen.fir
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,30 @@ func.func @rebox_scalar_attrs(%arg0: !fir.class<!fir.ptr<!fir.type<sometype{i:i3
// CHECK-LABEL: @rebox_scalar_attrs
// CHECK: fir.rebox %{{.*}} : (!fir.class<!fir.ptr<!fir.type<sometype{i:i32}>>>) -> !fir.class<!fir.type<sometype{i:i32}>>
// CHECK: return

func.func @vars_within_physical_storage() {
%c4 = arith.constant 4 : index
%c0 = arith.constant 0 : index
%1 = fir.address_of(@block_) : !fir.ref<!fir.array<8xi8>>
%2 = fir.convert %1 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
%3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
%5:2 = hlfir.declare %4 storage (%1[0]) {uniq_name = "a"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
%6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
%8:2 = hlfir.declare %7 storage (%1[4]) {uniq_name = "b"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
return
}
// CHECK-LABEL: func.func @vars_within_physical_storage() {
// CHECK: %[[VAL_0:.*]] = arith.constant 4 : index
// CHECK: %[[VAL_1:.*]] = arith.constant 0 : index
// CHECK: %[[VAL_2:.*]] = fir.address_of(@block_) : !fir.ref<!fir.array<8xi8>>
// CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
// CHECK: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_3]], %[[VAL_1]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<i8>) -> !fir.ref<f32>
// CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_5]] storage(%[[VAL_2]][0]) {uniq_name = "a"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
// CHECK: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_3]], %[[VAL_0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ref<f32>
// CHECK: %[[VAL_9:.*]] = fir.declare %[[VAL_8]] storage(%[[VAL_2]][4]) {uniq_name = "b"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
// CHECK: return
// CHECK: }
18 changes: 18 additions & 0 deletions flang/test/HLFIR/declare.fir
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,21 @@ func.func @array_declare_unlimited_polymorphic_boxaddr(%arg0: !fir.ref<!fir.clas
// CHECK-LABEL: func.func @array_declare_unlimited_polymorphic_boxaddr(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.class<!fir.ptr<!fir.array<?x?xnone>>>>) {
// CHECK: %[[VAL_1:.*]] = hlfir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x?xnone>>>>) -> (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x?xnone>>>>, !fir.ref<!fir.class<!fir.ptr<!fir.array<?x?xnone>>>>)

func.func @vars_within_physical_storage() {
%c4 = arith.constant 4 : index
%c0 = arith.constant 0 : index
%1 = fir.address_of(@block_) : !fir.ref<!fir.array<8xi8>>
%2 = fir.convert %1 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
%3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
%5:2 = hlfir.declare %4 storage (%1[0]) {uniq_name = "a"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
%6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
%8:2 = hlfir.declare %7 storage (%1[4]) {uniq_name = "b"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
return
}
// CHECK-LABEL: func.func @vars_within_physical_storage() {
// CHECK: %[[VAL_2:.*]] = fir.address_of(@block_) : !fir.ref<!fir.array<8xi8>>
// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %{{.*}} storage(%[[VAL_2]][0]) {uniq_name = "a"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
// CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %{{.*}} storage(%[[VAL_2]][4]) {uniq_name = "b"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
Loading