-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[flang] Added storage specification for [hl]fir.declare. #155325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
As proposed in https://discourse.llvm.org/t/rfc-flang-representation-for-objects-inside-physical-storage/88026, this patch adds a `storage` Value operand and a `storage_offset` Integer attribute for `[hl]fir.declare` operations. The `storage` operand indicates the raw address of the physical storage a variable belongs to. This is the beginning address of the physical storage. The `storage_offset` specifies a byte offset within the physical storage where the variable object starts.
@llvm/pr-subscribers-flang-fir-hlfir Author: Slava Zakharin (vzakhari) ChangesAs proposed in https://discourse.llvm.org/t/rfc-flang-representation-for-objects-inside-physical-storage/88026, The Patch is 26.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/155325.diff 15 Files Affected:
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 99b5105ab365e..2cfdf90c8f838 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -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 = [{
@@ -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.
+
Example:
CHARACTER(n), OPTIONAL, TARGET :: c(10:, 20:)
@@ -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)
}];
diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
index 2fdc9a96804da..c953d9ecb67cf 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
@@ -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">;
diff --git a/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.h b/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.h
index 60f71627a1bd4..028122878237a 100644
--- a/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.h
+++ b/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.h
@@ -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
diff --git a/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td b/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td
index c2c9a03d2b890..1f7e160878149 100644
--- a/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td
+++ b/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td
@@ -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
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index db3fb0b90464d..abb362dc5caea 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -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 = [{
@@ -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)
}];
diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
index 99533690018eb..b6501fd530992 100644
--- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp
+++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
@@ -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) {
diff --git a/flang/lib/Optimizer/Dialect/FortranVariableInterface.cpp b/flang/lib/Optimizer/Dialect/FortranVariableInterface.cpp
index 034f8c74ec79f..19c7924eb82e4 100644
--- a/flang/lib/Optimizer/Dialect/FortranVariableInterface.cpp
+++ b/flang/lib/Optimizer/Dialect/FortranVariableInterface.cpp
@@ -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");
+ 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();
+}
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 3c5095da0145a..242104c47886e 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -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() {
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 4e7de4732357d..8104e53920c27 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -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.
diff --git a/flang/test/Fir/declare.fir b/flang/test/Fir/declare.fir
index f335ae41b6871..652faef4f155a 100644
--- a/flang/test/Fir/declare.fir
+++ b/flang/test/Fir/declare.fir
@@ -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
+}
diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir
index e5dbec44220b7..553f69ccf83fd 100644
--- a/flang/test/Fir/invalid.fir
+++ b/flang/test/Fir/invalid.fir
@@ -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
+}
diff --git a/flang/test/HLFIR/declare-codegen.fir b/flang/test/HLFIR/declare-codegen.fir
index a4edb630c4adb..b3f0b73158603 100644
--- a/flang/test/HLFIR/declare-codegen.fir
+++ b/flang/test/HLFIR/declare-codegen.fir
@@ -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>...
[truncated]
|
std::uint64_t storageOffset = storageIface.getStorageOffset(); | ||
if (!storage) { | ||
if (storageOffset != 0) | ||
op->emitOpError("storage offset specified without the storage reference"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
op->emitOpError("storage offset specified without the storage reference"); | |
return op->emitOpError("storage offset specified without the storage reference"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Thanks!
The storage and storage_offset operands are optional and are required | ||
for FortranVariableStorageOpInterface, where they are documented. | ||
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this. LGTM.
As proposed in https://discourse.llvm.org/t/rfc-flang-representation-for-objects-inside-physical-storage/88026,
this patch adds a
storage
Value operand and astorage_offset
Integer attribute for
[hl]fir.declare
operations.The
storage
operand indicates the raw address of the physical storagea variable belongs to. This is the beginning address of the physical storage.
The
storage_offset
specifies a byte offset within the physical storagewhere the variable object starts.