From ed657c639f6438f18379418abe0636869988aa38 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 7 Oct 2025 07:58:10 -0700 Subject: [PATCH] [flang][HLFIR] add skip_rebox option to hlfir.declare --- flang/include/flang/Optimizer/HLFIR/HLFIROps.td | 8 +++++++- flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp | 5 ++++- flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp | 11 ++++++++--- flang/test/HLFIR/declare-codegen.fir | 9 +++++++++ flang/test/HLFIR/invalid.fir | 9 +++++++++ 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td index 218435a44c24f..b7563a2f752f0 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -73,6 +73,10 @@ def hlfir_DeclareOp local lower bound values. It is intended to be used when generating FIR from HLFIR in order to avoid descriptor creation for simple entities. + The attribute skip_rebox can be set to indicate that the second and first + result are known to be the same descriptors (the input descriptor is known + to already have the correct attributes and lower bounds). + Example: CHARACTER(n) :: c(10:n, 20:n) @@ -98,7 +102,8 @@ def hlfir_DeclareOp DefaultValuedAttr:$storage_offset, Builtin_StringAttr:$uniq_name, OptionalAttr:$fortran_attrs, - OptionalAttr:$data_attr); + OptionalAttr:$data_attr, + OptionalAttr:$skip_rebox); let results = (outs AnyFortranVariable, AnyRefOrBoxLike); @@ -106,6 +111,7 @@ def hlfir_DeclareOp $memref (`(` $shape^ `)`)? (`typeparams` $typeparams^)? (`dummy_scope` $dummy_scope^)? (`storage` `(` $storage^ `[` $storage_offset `]` `)`)? + (`skip_rebox` $skip_rebox^)? attr-dict `:` functional-type(operands, results) }]; diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp index 0cc65f939723e..1332dc57fb086 100644 --- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp @@ -281,7 +281,7 @@ void hlfir::DeclareOp::build(mlir::OpBuilder &builder, getDeclareOutputTypes(inputType, hasExplicitLbs); build(builder, result, {hlfirVariableType, firVarType}, memref, shape, typeparams, dummy_scope, storage, storage_offset, nameAttr, - fortran_attrs, data_attr); + fortran_attrs, data_attr, /*skip_rebox=*/mlir::UnitAttr{}); } llvm::LogicalResult hlfir::DeclareOp::verify() { @@ -294,6 +294,9 @@ llvm::LogicalResult hlfir::DeclareOp::verify() { return emitOpError("first result type is inconsistent with variable " "properties: expected ") << hlfirVariableType; + if (getSkipRebox() && !llvm::isa(getMemref().getType())) + return emitOpError( + "skip_rebox attribute must only be set when the input is a box"); // The rest of the argument verification is done by the // FortranVariableInterface verifier. auto fortranVar = diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp index 8104e53920c27..6a57bf2ae6fec 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp @@ -23,6 +23,7 @@ #include "flang/Optimizer/HLFIR/HLFIROps.h" #include "flang/Optimizer/HLFIR/Passes.h" #include "mlir/Transforms/DialectConversion.h" +#include "llvm/ADT/SmallSet.h" namespace hlfir { #define GEN_PASS_DEF_CONVERTHLFIRTOFIR @@ -312,10 +313,12 @@ class DeclareOpConversion : public mlir::OpRewritePattern { // Propagate other attributes from hlfir.declare to fir.declare. // OpenACC's acc.declare is one example. Right now, the propagation // is verbatim. - mlir::NamedAttrList elidedAttrs = - mlir::NamedAttrList{firDeclareOp->getAttrs()}; + llvm::SmallSet elidedAttrs; + for (const mlir::NamedAttribute &firAttr : firDeclareOp->getAttrs()) + elidedAttrs.insert(firAttr.getName()); + elidedAttrs.insert(declareOp.getSkipReboxAttrName()); for (const mlir::NamedAttribute &attr : declareOp->getAttrs()) - if (!elidedAttrs.get(attr.getName())) + if (!elidedAttrs.contains(attr.getName())) firDeclareOp->setAttr(attr.getName(), attr.getValue()); auto firBase = firDeclareOp.getResult(); @@ -328,6 +331,8 @@ class DeclareOpConversion : public mlir::OpRewritePattern { auto genHlfirBox = [&]() -> mlir::Value { if (auto baseBoxType = mlir::dyn_cast(firBase.getType())) { + if (declareOp.getSkipRebox()) + return firBase; // Rebox so that lower bounds and attributes are correct. if (baseBoxType.isAssumedRank()) return fir::ReboxAssumedRankOp::create( diff --git a/flang/test/HLFIR/declare-codegen.fir b/flang/test/HLFIR/declare-codegen.fir index b3f0b73158603..04c2ddcece4a7 100644 --- a/flang/test/HLFIR/declare-codegen.fir +++ b/flang/test/HLFIR/declare-codegen.fir @@ -124,6 +124,15 @@ func.func @array_declare_box_2(%arg0: !fir.box>) { // CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.box>) -> !fir.box> // CHECK: %[[VAL_2:.*]] = fir.rebox %[[VAL_1]] : (!fir.box>) -> !fir.box> +func.func @array_declare_box_3(%arg0: !fir.box>) -> !fir.box> { + %0:2 = hlfir.declare %arg0 skip_rebox {uniq_name = "x"} : (!fir.box>) -> (!fir.box>, !fir.box>) + return %0#0 : !fir.box> +} +// CHECK-LABEL: func.func @array_declare_box_3( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box>) -> !fir.box> { +// CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.box>) -> !fir.box> +// CHECK: return %[[VAL_1]] + func.func @array_declare_char_box(%arg0: !fir.box>>) { %0:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) return diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir index 887113959429c..91e9ed6c2e4c4 100644 --- a/flang/test/HLFIR/invalid.fir +++ b/flang/test/HLFIR/invalid.fir @@ -36,6 +36,15 @@ func.func @bad_array_declare(%arg0: !fir.ref>) { return } +// ----- +func.func @bad_declare_skip_rebox(%arg0: !fir.ref) { + // expected-error@+1 {{'hlfir.declare' op skip_rebox attribute must only be set when the input is a box}} + %0:2 = hlfir.declare %arg0 skip_rebox {uniq_name = "x"} : (!fir.ref) -> (!fir.ref, !fir.ref) + return +} + +// ----- + // ----- func.func @bad_assign_scalar_character(%arg0: !fir.boxchar<1>, %arg1: !fir.char<1,?>) { // expected-error@+1 {{'hlfir.assign' op operand #0 must be any Fortran value or variable type, but got '!fir.char<1,?>'}}