Skip to content

Conversation

jeanPerier
Copy link
Contributor

This is needed for #153222.

The semantics patch will allow lowering to represent contiguous designator as such in FIR in some cases of array component reference, but this creates a new hlfir.designate pattern that had no code generation support.

@vzakhari implemented the hlfir.designate to fir lowering for this pattern in #154232. This introduced a usage of fir.box_addr in fir.global that had no support for llvm code generation because it was never used.

FIR lowering of the fir.box type inside fir.global is special (it is an actual descriptor struct value instead of being a descriptor in memory) and causes builtin.unrealized_conversion_cast to be inserted under the hood by MLIR dialect conversion framework after each operation producing a fir.box is translated. These builtin.unrealized_conversion_cast must be removed before the code generation of operation of using the fir.box in order to get the right "by value" code generation required in global initial value definitions.

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir flang:codegen labels Sep 5, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 5, 2025

@llvm/pr-subscribers-flang-codegen

@llvm/pr-subscribers-flang-fir-hlfir

Author: None (jeanPerier)

Changes

This is needed for #153222.

The semantics patch will allow lowering to represent contiguous designator as such in FIR in some cases of array component reference, but this creates a new hlfir.designate pattern that had no code generation support.

@vzakhari implemented the hlfir.designate to fir lowering for this pattern in #154232. This introduced a usage of fir.box_addr in fir.global that had no support for llvm code generation because it was never used.

FIR lowering of the fir.box type inside fir.global is special (it is an actual descriptor struct value instead of being a descriptor in memory) and causes builtin.unrealized_conversion_cast to be inserted under the hood by MLIR dialect conversion framework after each operation producing a fir.box is translated. These builtin.unrealized_conversion_cast must be removed before the code generation of operation of using the fir.box in order to get the right "by value" code generation required in global initial value definitions.


Full diff: https://github.com/llvm/llvm-project/pull/157120.diff

2 Files Affected:

  • (modified) flang/lib/Optimizer/CodeGen/CodeGen.cpp (+28-19)
  • (added) flang/test/Fir/box_addr-codegen-in-global.fir (+24)
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 76f3cbd421cb9..0800ed4db8c31 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -329,6 +329,31 @@ struct AllocaOpConversion : public fir::FIROpConversion<fir::AllocaOp> {
 } // namespace
 
 namespace {
+
+static bool isInGlobalOp(mlir::ConversionPatternRewriter &rewriter) {
+  auto *thisBlock = rewriter.getInsertionBlock();
+  return thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp());
+}
+
+// Inside a fir.global, the input box was produced as an llvm.struct<>
+// because objects cannot be handled in memory inside a fir.global body that
+// must be constant foldable. However, the type translation are not
+// contextual, so the fir.box<T> type of the operation that produced the
+// fir.box was translated to an llvm.ptr<llvm.struct<>> and the MLIR pass
+// manager inserted a builtin.unrealized_conversion_cast that was inserted
+// and needs to be removed here.
+// This should be called by any pattern operating on operations that are
+// accepting fir.box inputs and are used in fir.global.
+static mlir::Value
+fixBoxInputInsideGlobalOp(mlir::ConversionPatternRewriter &rewriter,
+                          mlir::Value box) {
+  if (isInGlobalOp(rewriter))
+    if (auto unrealizedCast =
+            box.getDefiningOp<mlir::UnrealizedConversionCastOp>())
+      return unrealizedCast.getInputs()[0];
+  return box;
+}
+
 /// Lower `fir.box_addr` to the sequence of operations to extract the first
 /// element of the box.
 struct BoxAddrOpConversion : public fir::FIROpConversion<fir::BoxAddrOp> {
@@ -341,6 +366,7 @@ struct BoxAddrOpConversion : public fir::FIROpConversion<fir::BoxAddrOp> {
     auto loc = boxaddr.getLoc();
     if (auto argty =
             mlir::dyn_cast<fir::BaseBoxType>(boxaddr.getVal().getType())) {
+      a = fixBoxInputInsideGlobalOp(rewriter, a);
       TypePair boxTyPair = getBoxTypePair(argty);
       rewriter.replaceOp(boxaddr,
                          getBaseAddrFromBox(loc, boxTyPair, a, rewriter));
@@ -1737,12 +1763,6 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
                        xbox.getSubcomponent().size());
   }
 
-  static bool isInGlobalOp(mlir::ConversionPatternRewriter &rewriter) {
-    auto *thisBlock = rewriter.getInsertionBlock();
-    return thisBlock &&
-           mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp());
-  }
-
   /// If the embox is not in a globalOp body, allocate storage for the box;
   /// store the value inside and return the generated alloca. Return the input
   /// value otherwise.
@@ -2076,21 +2096,10 @@ struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
                   mlir::ConversionPatternRewriter &rewriter) const override {
     mlir::Location loc = rebox.getLoc();
     mlir::Type idxTy = lowerTy().indexType();
-    mlir::Value loweredBox = adaptor.getOperands()[0];
+    mlir::Value loweredBox =
+        fixBoxInputInsideGlobalOp(rewriter, adaptor.getBox());
     mlir::ValueRange operands = adaptor.getOperands();
 
-    // Inside a fir.global, the input box was produced as an llvm.struct<>
-    // because objects cannot be handled in memory inside a fir.global body that
-    // must be constant foldable. However, the type translation are not
-    // contextual, so the fir.box<T> type of the operation that produced the
-    // fir.box was translated to an llvm.ptr<llvm.struct<>> and the MLIR pass
-    // manager inserted a builtin.unrealized_conversion_cast that was inserted
-    // and needs to be removed here.
-    if (isInGlobalOp(rewriter))
-      if (auto unrealizedCast =
-              loweredBox.getDefiningOp<mlir::UnrealizedConversionCastOp>())
-        loweredBox = unrealizedCast.getInputs()[0];
-
     TypePair inputBoxTyPair = getBoxTypePair(rebox.getBox().getType());
 
     // Create new descriptor and fill its non-shape related data.
diff --git a/flang/test/Fir/box_addr-codegen-in-global.fir b/flang/test/Fir/box_addr-codegen-in-global.fir
new file mode 100644
index 0000000000000..2e0b41b8cc805
--- /dev/null
+++ b/flang/test/Fir/box_addr-codegen-in-global.fir
@@ -0,0 +1,24 @@
+// Test codegen of fir.box_addr inside fir.global
+// RUN: tco %s | FileCheck %s
+
+fir.global @x_addr constant : !fir.type<sometype{p:i64}> {
+  %c-1 = arith.constant -1 : index
+  %c5 = arith.constant 5 : index
+  %c3 = arith.constant 3 : index
+  %c-3 = arith.constant -3 : index
+  %c2 = arith.constant 2 : index
+  %c1 = arith.constant 1 : index
+  %0 = fir.undefined !fir.type<sometype{p:i64}>
+  %1 = fir.address_of(@_QFEx) : !fir.ref<!fir.array<2x3x5x!fir.type<_QFTt1{c:i32}>>>
+  %2 = fir.shape_shift %c1, %c2, %c-3, %c3, %c1, %c5 : (index, index, index, index, index, index) -> !fir.shapeshift<3>
+  %3 = fir.field_index c, !fir.type<_QFTt1{c:i32}>
+  %4 = fir.slice %c1, %c2, %c1, %c-3, %c-1, %c1, %c1, %c5, %c1 path %3 : (index, index, index, index, index, index, index, index, index, !fir.field) -> !fir.slice<3>
+  %5 = fir.embox %1(%2) [%4] : (!fir.ref<!fir.array<2x3x5x!fir.type<_QFTt1{c:i32}>>>, !fir.shapeshift<3>, !fir.slice<3>) -> !fir.box<!fir.ref<!fir.array<2x3x5xi32>>>
+  %6 = fir.box_addr %5 : (!fir.box<!fir.ref<!fir.array<2x3x5xi32>>>) -> !fir.ref<!fir.array<2x3x5xi32>>
+  %7 = fir.convert %6 : (!fir.ref<!fir.array<2x3x5xi32>>) -> i64
+  %8 = fir.insert_value %0, %7, ["p", !fir.type<sometype{p:i64}>] : (!fir.type<sometype{p:i64}>, i64) -> !fir.type<sometype{p:i64}>
+  fir.has_value %8 : !fir.type<sometype{p:i64}>
+}
+fir.global @_QFEx target : !fir.array<2x3x5x!fir.type<_QFTt1{c:i32}>>
+
+// CHECK: @x_addr = constant %sometype { i64 ptrtoint (ptr @_QFEx to i64) }

Copy link
Contributor

@vzakhari vzakhari left a comment

Choose a reason for hiding this comment

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

Thank you, Jean!

@jeanPerier jeanPerier merged commit 355dbbc into llvm:main Sep 8, 2025
13 checks passed
@jeanPerier jeanPerier deleted the box-addr-global branch September 8, 2025 08:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:codegen flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants