[llvm-branch-commits] [flang] 85ec3af - Revert "[flang][mem2reg] promote memory slots through declares (#196975)"

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jun 17 03:12:14 PDT 2026


Author: jeanPerier
Date: 2026-06-17T12:12:10+02:00
New Revision: 85ec3af65318d5efe5922932ac5fc80ab518e602

URL: https://github.com/llvm/llvm-project/commit/85ec3af65318d5efe5922932ac5fc80ab518e602
DIFF: https://github.com/llvm/llvm-project/commit/85ec3af65318d5efe5922932ac5fc80ab518e602.diff

LOG: Revert "[flang][mem2reg] promote memory slots through declares (#196975)"

This reverts commit c1ec4b3c79967ae5ef824f7194540f6529405a03.

Added: 
    

Modified: 
    flang/include/flang/Optimizer/Dialect/FIROps.h
    flang/include/flang/Optimizer/Dialect/FIROps.td
    flang/lib/Optimizer/Dialect/FIROps.cpp
    flang/test/Fir/mem2reg.mlir

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Dialect/FIROps.h b/flang/include/flang/Optimizer/Dialect/FIROps.h
index 54aa3d58abe8c..9d771b1e60604 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.h
@@ -19,7 +19,6 @@
 #include "mlir/Dialect/Func/IR/FuncOps.h"
 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "mlir/Interfaces/LoopLikeInterface.h"
-#include "mlir/Interfaces/MemorySlotInterfaces.h"
 #include "mlir/Interfaces/SideEffectInterfaces.h"
 #include "mlir/Interfaces/ViewLikeInterface.h"
 

diff  --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 5a17db1c0ef1e..35a87c29d0cb6 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -3070,15 +3070,9 @@ def fir_VolatileCastOp
 }
 
 def fir_ConvertOp
-    : fir_SimpleOneResultOp<"convert",
-                            [NoMemoryEffect, ViewLikeOpInterface,
-                             ConditionallySpeculatable,
-                             DeclareOpInterfaceMethods<PromotableOpInterface>,
-                             DeclareOpInterfaceMethods<
-                                 PromotableAliaserInterface,
-                                 ["projectSlotValueToAliasValue",
-                                  "projectAliasValueToSlotValue"]>,
-                             fir_FortranObjectViewOpInterface]> {
+    : fir_SimpleOneResultOp<"convert", [NoMemoryEffect, ViewLikeOpInterface,
+                                        ConditionallySpeculatable,
+                                        fir_FortranObjectViewOpInterface]> {
   let summary = "encapsulates all Fortran entity type conversions";
 
   let description = [{
@@ -3607,7 +3601,6 @@ def fir_DeclareOp
                          DeclareOpInterfaceMethods<PromotableOpInterface,
                                                    ["requiresReplacedValues",
                                                     "visitReplacedValues"]>,
-                         DeclareOpInterfaceMethods<PromotableAliaserInterface>,
                          fir_FortranObjectViewOpInterface]> {
   let summary = "declare a variable";
 

diff  --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 6a64b76736cf5..1d61989eba6cf 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -2012,89 +2012,6 @@ void fir::ConvertOp::getCanonicalizationPatterns(
       context);
 }
 
-// Returns the pointee element type of a FIR reference-like type or a memref;
-// returns null if `ty` is not pointer-like or has no extractable element
-// type (e.g. unranked memref, box).
-static mlir::Type slotPointeeElemType(mlir::Type ty) {
-  if (mlir::Type fEle = fir::dyn_cast_ptrEleTy(ty))
-    return fEle;
-  if (auto memrefTy = mlir::dyn_cast<mlir::MemRefType>(ty))
-    return memrefTy.getElementType();
-  return {};
-}
-
-// Returns true if a `fir.convert` between pointers with element types
-// `srcElem` and `dstElem` is a no-op at the value level or can be replaced by
-// a bicast.
-static bool isAcceptableSlotElemTypePair(mlir::Type srcElem,
-                                         mlir::Type dstElem) {
-  if (srcElem == dstElem)
-    return true;
-  if (!isBitcastCompatibleType(srcElem) || !isBitcastCompatibleType(dstElem))
-    return false;
-  auto srcBits = getBitcastBitSize(srcElem);
-  auto dstBits = getBitcastBitSize(dstElem);
-  return srcBits && dstBits && *srcBits == *dstBits;
-}
-
-static bool isPromotableSlotAliasConvert(fir::ConvertOp op) {
-  mlir::Type srcElem = slotPointeeElemType(op.getValue().getType());
-  mlir::Type dstElem = slotPointeeElemType(op.getResult().getType());
-  return srcElem && dstElem && isAcceptableSlotElemTypePair(srcElem, dstElem);
-}
-
-void fir::ConvertOp::getPromotableSlotAliases(
-    mlir::OpOperand &aliasedSlotPointerOperand,
-    const mlir::MemorySlot & /*parentSlot*/,
-    llvm::SmallVectorImpl<mlir::MemorySlot> &newMemorySlots) {
-  if (aliasedSlotPointerOperand.get() != getValue())
-    return;
-  if (!isPromotableSlotAliasConvert(*this))
-    return;
-  mlir::Type dstElem = slotPointeeElemType(getResult().getType());
-  newMemorySlots.push_back(mlir::MemorySlot{getResult(), dstElem});
-}
-
-mlir::Value fir::ConvertOp::projectSlotValueToAliasValue(
-    mlir::OpOperand & /*aliasedSlotPointerOperand*/,
-    const mlir::MemorySlot & /*parentSlot*/, const mlir::MemorySlot &aliasSlot,
-    mlir::Value slotValue, mlir::OpBuilder &builder) {
-  if (slotValue.getType() == aliasSlot.elemType)
-    return slotValue;
-  return fir::BitcastOp::create(builder, getLoc(), aliasSlot.elemType,
-                                slotValue);
-}
-
-mlir::Value fir::ConvertOp::projectAliasValueToSlotValue(
-    mlir::OpOperand & /*aliasedSlotPointerOperand*/,
-    const mlir::MemorySlot &parentSlot, const mlir::MemorySlot & /*aliasSlot*/,
-    mlir::Value aliasValue, mlir::Value /*reachingDef*/,
-    mlir::OpBuilder &builder) {
-  if (aliasValue.getType() == parentSlot.elemType)
-    return aliasValue;
-  return fir::BitcastOp::create(builder, getLoc(), parentSlot.elemType,
-                                aliasValue);
-}
-
-bool fir::ConvertOp::canUsesBeRemoved(
-    const mlir::SmallPtrSetImpl<mlir::OpOperand *> &blockingUses,
-    mlir::SmallVectorImpl<mlir::OpOperand *> &newBlockingUses,
-    const mlir::DataLayout &dataLayout) {
-  // Only participate in promotion when this convert is a slot alias (if the
-  // address cast is not used, DCE should have removed it).
-  if (!isPromotableSlotAliasConvert(*this))
-    return false;
-  for (mlir::OpOperand &use : getResult().getUses())
-    newBlockingUses.push_back(&use);
-  return true;
-}
-
-mlir::DeletionKind fir::ConvertOp::removeBlockingUses(
-    const mlir::SmallPtrSetImpl<mlir::OpOperand *> &blockingUses,
-    mlir::OpBuilder &builder) {
-  return mlir::DeletionKind::Delete;
-}
-
 static bool isI1(mlir::Type ty) {
   if (auto intTy = mlir::dyn_cast<mlir::IntegerType>(ty))
     return intTy.getWidth() == 1;
@@ -3671,8 +3588,17 @@ llvm::SmallVector<mlir::Attribute> fir::LenParamIndexOp::getAttributes() {
 // LoadOp
 //===----------------------------------------------------------------------===//
 
+static bool isSlotOrDeclaredSlot(mlir::Value val,
+                                 const mlir::MemorySlot &slot) {
+  if (val == slot.ptr)
+    return true;
+  if (auto declareOp = val.getDefiningOp<fir::DeclareOp>())
+    return declareOp.getMemref() == slot.ptr;
+  return false;
+}
+
 bool fir::LoadOp::loadsFrom(const mlir::MemorySlot &slot) {
-  return getMemref() == slot.ptr;
+  return isSlotOrDeclaredSlot(getMemref(), slot);
 }
 
 bool fir::LoadOp::storesTo(const mlir::MemorySlot &slot) { return false; }
@@ -3692,8 +3618,7 @@ bool fir::LoadOp::canUsesBeRemoved(
   if (blockingUses.size() != 1)
     return false;
   mlir::Value blockingUse = (*blockingUses.begin())->get();
-  return blockingUse == slot.ptr && getMemref() == slot.ptr &&
-         getResult().getType() == slot.elemType;
+  return isSlotOrDeclaredSlot(blockingUse, slot) && getMemref() == blockingUse;
 }
 
 mlir::DeletionKind fir::LoadOp::removeBlockingUses(
@@ -5243,7 +5168,7 @@ llvm::LogicalResult fir::SliceOp::verify() {
 bool fir::StoreOp::loadsFrom(const mlir::MemorySlot &slot) { return false; }
 
 bool fir::StoreOp::storesTo(const mlir::MemorySlot &slot) {
-  return getMemref() == slot.ptr;
+  return isSlotOrDeclaredSlot(getMemref(), slot);
 }
 
 mlir::Value fir::StoreOp::getStored(const mlir::MemorySlot &slot,
@@ -5261,8 +5186,8 @@ bool fir::StoreOp::canUsesBeRemoved(
   if (blockingUses.size() != 1)
     return false;
   mlir::Value blockingUse = (*blockingUses.begin())->get();
-  return blockingUse == slot.ptr && getMemref() == slot.ptr &&
-         getValue() != slot.ptr && getValue().getType() == slot.elemType;
+  return isSlotOrDeclaredSlot(blockingUse, slot) &&
+         getMemref() == blockingUse && getValue() != blockingUse;
 }
 
 mlir::DeletionKind fir::StoreOp::removeBlockingUses(
@@ -6125,8 +6050,17 @@ bool fir::DeclareOp::canUsesBeRemoved(
     const mlir::DataLayout &dataLayout) {
   if (!isLegalTypeForValueDeclare(fir::unwrapRefType(getType())))
     return false;
-  for (mlir::OpOperand &use : getResult().getUses())
+  // MLIR's mem2reg computes defining blocks only from direct users of
+  // the slot pointer. Stores through fir.declare are not direct users,
+  // so they are not registered as defining blocks. This causes missing
+  // phi nodes at join points (e.g., loop headers). Restrict promotion
+  // to the single-block case where no phi nodes are needed.
+  mlir::Block *declBlock = getOperation()->getBlock();
+  for (mlir::OpOperand &use : getResult().getUses()) {
+    if (use.getOwner()->getBlock() != declBlock)
+      return false;
     newBlockingUses.push_back(&use);
+  }
   return true;
 }
 
@@ -6136,38 +6070,17 @@ mlir::DeletionKind fir::DeclareOp::removeBlockingUses(
   return mlir::DeletionKind::Delete;
 }
 
-void fir::DeclareOp::getPromotableSlotAliases(
-    mlir::OpOperand &aliasedSlotPointerOperand,
-    const mlir::MemorySlot & /*parentSlot*/,
-    llvm::SmallVectorImpl<mlir::MemorySlot> &newMemorySlots) {
-  if (aliasedSlotPointerOperand.get() != getMemref())
-    return;
-  // fir.declare is a transparent alias of its memref operand at the same
-  // element type.
-  mlir::Type aliasElemType = fir::dyn_cast_ptrEleTy(getResult().getType());
-  if (!aliasElemType)
-    return;
-  newMemorySlots.push_back(mlir::MemorySlot{getResult(), aliasElemType});
-}
-
 bool fir::DeclareOp::requiresReplacedValues() { return true; }
 
 void fir::DeclareOp::visitReplacedValues(
     llvm::ArrayRef<std::pair<mlir::Operation *, mlir::Value>> definitions,
     mlir::OpBuilder &builder) {
-  // TODO: extend `fir.declare_value` to carry the variable's declared type
-  // independently of the value's type. Once that is in place the type
-  // mismatch check below can be dropped (a bit-cast equivalent will be
-  // recorded on the op instead of skipping emission).
-  mlir::Type declaredElemType = fir::dyn_cast_ptrEleTy(getResult().getType());
   for (auto [op, value] : definitions) {
     // Do not emit DeclareValue when we have a dummy scope as this can
     // potentially result in us generating it where the DummyScope does not
     // dominate it. This can happen after inlining.
     if (getDummyScope())
       continue;
-    if (value.getType() != declaredElemType)
-      continue;
     builder.setInsertionPointAfter(op);
     fir::DeclareValueOp::create(builder, getLoc(), value, nullptr,
                                 getUniqNameAttr(), getFortranAttrsAttr(),

diff  --git a/flang/test/Fir/mem2reg.mlir b/flang/test/Fir/mem2reg.mlir
index 2aaf856c620d8..154580c626e7c 100644
--- a/flang/test/Fir/mem2reg.mlir
+++ b/flang/test/Fir/mem2reg.mlir
@@ -158,24 +158,17 @@ func.func @box_not_mem2reg(%arg0: !fir.ref<!fir.box<f32>> {fir.bindc_name = "i"}
 
 // -----
 
-// Conditional store in a 
diff erent block through fir.declare is promoted:
-// the through-declare store is discovered as a defining block via the
-// `getPromotableSlotView` interface and a block argument is added at the
-// merge point.
+// Conditional store in a 
diff erent block through fir.declare is not promoted
+// because MLIR mem2reg would not place the needed phi nodes correctly.
 
 // CHECK-LABEL: func.func @block_argument_value(
 // CHECK-SAME: %[[ARG0:.*]]: i32,
 // CHECK-SAME: %[[ARG1:.*]]: i1) -> i32 {
-// CHECK-NOT: fir.alloca
-// CHECK-NOT: fir.declare {{.*}} : (!fir.ref<i32>)
-// CHECK: %[[C42:.*]] = arith.constant 42 : i32
-// CHECK: fir.declare_value %[[C42]] {{.*}}
-// CHECK: llvm.cond_br %[[ARG1]], ^bb1, ^bb2(%[[C42]] : i32)
-// CHECK: ^bb1:
-// CHECK: fir.declare_value %[[ARG0]] {{.*}}
-// CHECK: llvm.br ^bb2(%[[ARG0]] : i32)
-// CHECK: ^bb2(%[[MERGE:.*]]: i32):
-// CHECK: return %[[MERGE]] : i32
+// CHECK: fir.alloca i32
+// CHECK: fir.declare
+// CHECK: fir.store
+// CHECK: fir.store
+// CHECK: fir.load
 func.func @block_argument_value(%arg0: i32, %cdt: i1) -> i32 {
   %c42_i32 = arith.constant 42 : i32
   %3 = fir.alloca i32 {bindc_name = "jlocal", uniq_name = "_QFfooEjlocal"}
@@ -192,26 +185,19 @@ func.func @block_argument_value(%arg0: i32, %cdt: i1) -> i32 {
 
 // -----
 
-// Conditional store inside a loop through fir.declare is promoted: the
-// loop header gets a block argument carrying the conditional update from
-// the loop body. This is the case that motivated the previous same-block
-// restriction in fir::DeclareOp::canUsesBeRemoved.
+// Conditional store inside a loop through fir.declare must not be promoted.
+// MLIR's mem2reg does not register stores through declares as defining blocks,
+// so phi nodes at the loop header would be missing, losing the update.
 
 // CHECK-LABEL: func.func @loop_conditional_update(
 // CHECK-SAME: %[[ARG0:.*]]: i32,
 // CHECK-SAME: %[[ARG1:.*]]: i1) -> i32 {
-// CHECK-NOT: fir.alloca
-// CHECK-NOT: fir.declare {{.*}} : (!fir.ref<i32>)
-// CHECK: fir.declare_value %[[ARG0]] {{.*}}
-// CHECK: llvm.br ^bb1(%[[ARG0]] : i32)
-// CHECK: ^bb1(%[[LOOP_ARG:.*]]: i32):
-// CHECK: llvm.cond_br %[[ARG1]], ^bb2, ^bb3
-// CHECK: ^bb2:
-// CHECK: %[[NEW:.*]] = arith.subi %[[LOOP_ARG]], {{.*}} : i32
-// CHECK: fir.declare_value %[[NEW]] {{.*}}
-// CHECK: llvm.br ^bb1(%[[NEW]] : i32)
-// CHECK: ^bb3:
-// CHECK: return %[[LOOP_ARG]] : i32
+// CHECK: fir.alloca i32
+// CHECK: fir.declare
+// CHECK: fir.store
+// CHECK: fir.load
+// CHECK: fir.store
+// CHECK: fir.load
 func.func @loop_conditional_update(%arg0: i32, %cdt: i1) -> i32 {
   %c1 = arith.constant 1 : i32
   %alloca = fir.alloca i32 {bindc_name = "mywatch", uniq_name = "_QFkernelEmywatch"}
@@ -232,171 +218,6 @@ func.func @loop_conditional_update(%arg0: i32, %cdt: i1) -> i32 {
 
 // -----
 
-// fir.convert at the same element type is a transparent view; the slot is
-// fully promoted with no value conversion needed.
-
-// CHECK-LABEL: func.func @convert_same_type(
-// CHECK-SAME: %[[ARG0:.*]]: i32) -> i32 {
-// CHECK-NOT: fir.alloca
-// CHECK-NOT: fir.convert
-// CHECK: return %[[ARG0]] : i32
-func.func @convert_same_type(%arg0: i32) -> i32 {
-  %alloca = fir.alloca i32
-  %ptr = fir.convert %alloca : (!fir.ref<i32>) -> !fir.ref<i32>
-  fir.store %arg0 to %ptr : !fir.ref<i32>
-  %v = fir.load %ptr : !fir.ref<i32>
-  return %v : i32
-}
-
-// -----
-
-// A type-changing fir.convert exposes the slot at a 
diff erent element type;
-// mem2reg materialises fir.bitcast value conversions at the store and load.
-
-// CHECK-LABEL: func.func @convert_type_changing(
-// CHECK-SAME: %[[ARG0:.*]]: f32) -> f32
-// CHECK-NOT: fir.alloca
-// CHECK: %[[I32:.*]] = fir.bitcast %[[ARG0]] : (f32) -> i32
-// CHECK: fir.bitcast %[[I32]] : (i32) -> f32
-// CHECK: return %{{.*}} : f32
-func.func @convert_type_changing(%arg0: f32) -> f32 {
-  %alloca = fir.alloca i32
-  %ptr = fir.convert %alloca : (!fir.ref<i32>) -> !fir.ref<f32>
-  fir.store %arg0 to %ptr : !fir.ref<f32>
-  %v = fir.load %ptr : !fir.ref<f32>
-  return %v : f32
-}
-
-// -----
-
-// Chained view: alloca -> fir.declare -> fir.convert -> load/store. The
-// declare's element type (i32) 
diff ers from the value type the store sees
-// at the leaf view (f32), so `fir.declare_value` is skipped until
-// `fir.declare_value` can carry the declared type independently of the
-// value type (see the TODO in fir::DeclareOp::visitReplacedValues).
-
-// CHECK-LABEL: func.func @declare_then_convert(
-// CHECK-SAME: %[[ARG0:.*]]: f32) -> f32
-// CHECK-NOT: fir.alloca
-// CHECK-NOT: fir.declare {{.*}} : (!fir.ref<i32>)
-// CHECK-NOT: fir.declare_value
-// CHECK: %[[I32:.*]] = fir.bitcast %[[ARG0]] : (f32) -> i32
-// CHECK: %[[F32:.*]] = fir.bitcast %[[I32]] : (i32) -> f32
-// CHECK: return %[[F32]] : f32
-func.func @declare_then_convert(%arg0: f32) -> f32 {
-  %alloca = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"}
-  %declare = fir.declare %alloca {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> !fir.ref<i32>
-  %ptr = fir.convert %declare : (!fir.ref<i32>) -> !fir.ref<f32>
-  fir.store %arg0 to %ptr : !fir.ref<f32>
-  %v = fir.load %ptr : !fir.ref<f32>
-  return %v : f32
-}
-
-// -----
-
-// Inverse chain: alloca -> fir.convert -> fir.declare -> load/store. The
-// declare's memref is the result of a type-changing convert, so the
-// declare sees the slot at f32 — the same type as the store value, so
-// `fir.declare_value` is emitted.
-
-// CHECK-LABEL: func.func @convert_then_declare(
-// CHECK-SAME: %[[ARG0:.*]]: f32) -> f32
-// CHECK-NOT: fir.alloca
-// CHECK-NOT: fir.declare {{.*}} : (!fir.ref<f32>)
-// CHECK: %[[I32:.*]] = fir.bitcast %[[ARG0]] : (f32) -> i32
-// CHECK: fir.declare_value %[[ARG0]] {{.*}} : f32
-// CHECK: %[[F32:.*]] = fir.bitcast %[[I32]] : (i32) -> f32
-// CHECK: return %[[F32]] : f32
-func.func @convert_then_declare(%arg0: f32) -> f32 {
-  %alloca = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"}
-  %ptr = fir.convert %alloca : (!fir.ref<i32>) -> !fir.ref<f32>
-  %declare = fir.declare %ptr {uniq_name = "_QFEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
-  fir.store %arg0 to %declare : !fir.ref<f32>
-  %v = fir.load %declare : !fir.ref<f32>
-  return %v : f32
-}
-
-// -----
-
-// A memref.alloca slot with a mixed memref/FIR view chain
-// (memref -> fir.convert -> fir.declare -> fir.convert -> memref). All
-// element types are the same, so the slot promotes with no value
-// conversions; only `fir.declare_value` is emitted from the declare.
-
-// CHECK-LABEL: func.func @memref_with_declare_chain(
-// CHECK-SAME: %[[ARG0:.*]]: i32) -> i32
-// CHECK-NOT: memref.alloca
-// CHECK-NOT: fir.declare {{.*}} : (!fir.ref<i32>)
-// CHECK-NOT: fir.convert
-// CHECK-NOT: memref.store
-// CHECK-NOT: memref.load
-// CHECK: fir.declare_value %[[ARG0]] {{.*}} : i32
-// CHECK: return %[[ARG0]] : i32
-func.func @memref_with_declare_chain(%arg0: i32) -> i32 {
-  %alloca = memref.alloca() : memref<i32>
-  %fref = fir.convert %alloca : (memref<i32>) -> !fir.ref<i32>
-  %decl = fir.declare %fref {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> !fir.ref<i32>
-  %mref = fir.convert %decl : (!fir.ref<i32>) -> memref<i32>
-  memref.store %arg0, %mref[] : memref<i32>
-  %v = memref.load %mref[] : memref<i32>
-  return %v : i32
-}
-
-// -----
-
-// Same mixed memref/FIR chain with a conditional store across blocks. The
-// merge-point block argument is at the root slot's element type (i32), and
-// `fir.declare_value` is emitted at each store site.
-
-// CHECK-LABEL: func.func @memref_with_declare_chain_blocks(
-// CHECK-SAME: %[[ARG0:.*]]: i32,
-// CHECK-SAME: %[[COND:.*]]: i1) -> i32
-// CHECK-NOT: memref.alloca
-// CHECK-NOT: fir.declare {{.*}} : (!fir.ref<i32>)
-// CHECK: %[[C42:.*]] = arith.constant 42 : i32
-// CHECK: fir.declare_value %[[C42]] {{.*}} : i32
-// CHECK: cf.cond_br %[[COND]], ^[[BB1:.*]], ^[[BB2:.*]](%[[C42]] : i32)
-// CHECK: ^[[BB1]]:
-// CHECK: fir.declare_value %[[ARG0]] {{.*}} : i32
-// CHECK: cf.br ^[[BB2]](%[[ARG0]] : i32)
-// CHECK: ^[[BB2]](%[[MERGE:.*]]: i32):
-// CHECK: return %[[MERGE]] : i32
-func.func @memref_with_declare_chain_blocks(%arg0: i32, %cond: i1) -> i32 {
-  %c42 = arith.constant 42 : i32
-  %alloca = memref.alloca() : memref<i32>
-  %fref = fir.convert %alloca : (memref<i32>) -> !fir.ref<i32>
-  %decl = fir.declare %fref {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> !fir.ref<i32>
-  %mref = fir.convert %decl : (!fir.ref<i32>) -> memref<i32>
-  memref.store %c42, %mref[] : memref<i32>
-  cf.cond_br %cond, ^bb1, ^bb2
-^bb1:
-  memref.store %arg0, %mref[] : memref<i32>
-  cf.br ^bb2
-^bb2:
-  %v = memref.load %mref[] : memref<i32>
-  return %v : i32
-}
-
-// -----
-
-// A ref->integer fir.convert is not a memory view; it must block promotion.
-
-// CHECK-LABEL: func.func @convert_to_integer_blocks_promotion(
-// CHECK: %[[ALLOCA:.*]] = fir.alloca i32
-// CHECK: fir.store
-// CHECK: %[[INT:.*]] = fir.convert %[[ALLOCA]] : (!fir.ref<i32>) -> i64
-// CHECK: fir.call @use_addr(%[[INT]])
-func.func private @use_addr(%a: i64)
-func.func @convert_to_integer_blocks_promotion(%arg0: i32) {
-  %alloca = fir.alloca i32
-  fir.store %arg0 to %alloca : !fir.ref<i32>
-  %addr = fir.convert %alloca : (!fir.ref<i32>) -> i64
-  fir.call @use_addr(%addr) : (i64) -> ()
-  return
-}
-
-// -----
-
 // Make sure we do not generate fir.declare_value for a replaced value
 // fir.declare with dummy_scope. This can result in the declare_value being
 // inserted before the dummy_scope it uses as would be the case here.


        


More information about the llvm-branch-commits mailing list