[flang][NFC] Characterize allocation based on MemAlloc effect instead of pattern matching (#166806)

Flang alias analysis used to find allocation site by pattern matching
allocation ops in mainly FIR dialect. This MR extends the
characterization to instead characterize based on whether the result of
an op has MemAlloc effect.
This commit is contained in:
Susan Tan (ス-ザン タン)
2025-11-10 17:33:43 -05:00
committed by GitHub
parent 7b12a08f5e
commit bf3b704c60
19 changed files with 172 additions and 96 deletions

View File

@@ -80,8 +80,7 @@ def AnyRefOfConstantSizeAggregateType : TypeConstraint<
// Memory SSA operations
//===----------------------------------------------------------------------===//
def fir_AllocaOp : fir_Op<"alloca", [AttrSizedOperandSegments,
MemoryEffects<[MemAlloc<AutomaticAllocationScopeResource>]>]> {
def fir_AllocaOp : fir_Op<"alloca", [AttrSizedOperandSegments]> {
let summary = "allocate storage for a temporary on the stack given a type";
let description = [{
This primitive operation is used to allocate an object on the stack. A
@@ -162,7 +161,9 @@ def fir_AllocaOp : fir_Op<"alloca", [AttrSizedOperandSegments,
Variadic<AnyIntegerType>:$shape
);
let results = (outs fir_ReferenceType);
let results =
(outs Res<fir_ReferenceType,
"", [MemAlloc<AutomaticAllocationScopeResource>]>:$res);
let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;
@@ -212,8 +213,7 @@ def fir_AllocaOp : fir_Op<"alloca", [AttrSizedOperandSegments,
}];
}
def fir_AllocMemOp : fir_Op<"allocmem",
[MemoryEffects<[MemAlloc<DefaultResource>]>, AttrSizedOperandSegments]> {
def fir_AllocMemOp : fir_Op<"allocmem", [AttrSizedOperandSegments]> {
let summary = "allocate storage on the heap for an object of a given type";
let description = [{
@@ -235,7 +235,7 @@ def fir_AllocMemOp : fir_Op<"allocmem",
Variadic<AnyIntegerType>:$typeparams,
Variadic<AnyIntegerType>:$shape
);
let results = (outs fir_HeapType);
let results = (outs Res<fir_HeapType, "", [MemAlloc<DefaultResource>]>:$res);
let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;

View File

@@ -27,6 +27,26 @@ using namespace mlir;
#define DEBUG_TYPE "fir-alias-analysis"
// Inspect for value-scoped Allocate effects and determine whether
// 'candidate' is a new allocation. Returns SourceKind::Allocate if a
// MemAlloc effect is attached
static fir::AliasAnalysis::SourceKind
classifyAllocateFromEffects(mlir::Operation *op, mlir::Value candidate) {
if (!op)
return fir::AliasAnalysis::SourceKind::Unknown;
auto interface = llvm::dyn_cast<mlir::MemoryEffectOpInterface>(op);
if (!interface)
return fir::AliasAnalysis::SourceKind::Unknown;
llvm::SmallVector<mlir::MemoryEffects::EffectInstance, 4> effects;
interface.getEffects(effects);
for (mlir::MemoryEffects::EffectInstance &e : effects) {
if (mlir::isa<mlir::MemoryEffects::Allocate>(e.getEffect()) &&
e.getValue() && e.getValue() == candidate)
return fir::AliasAnalysis::SourceKind::Allocate;
}
return fir::AliasAnalysis::SourceKind::Unknown;
}
//===----------------------------------------------------------------------===//
// AliasAnalysis: alias
//===----------------------------------------------------------------------===//
@@ -535,6 +555,11 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
mlir::Operation *instantiationPoint{nullptr};
while (defOp && !breakFromLoop) {
ty = defOp->getResultTypes()[0];
// Value-scoped allocation detection via effects.
if (classifyAllocateFromEffects(defOp, v) == SourceKind::Allocate) {
type = SourceKind::Allocate;
break;
}
llvm::TypeSwitch<Operation *>(defOp)
.Case<hlfir::AsExprOp>([&](auto op) {
v = op.getVar();
@@ -554,11 +579,6 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
defOp = v.getDefiningOp();
}
})
.Case<fir::AllocaOp, fir::AllocMemOp>([&](auto op) {
// Unique memory allocation.
type = SourceKind::Allocate;
breakFromLoop = true;
})
.Case<fir::ConvertOp>([&](auto op) {
// Skip ConvertOp's and track further through the operand.
v = op->getOperand(0);
@@ -628,16 +648,23 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
type = SourceKind::Global;
} else {
auto def = llvm::cast<mlir::Value>(boxSrc.origin.u);
// TODO: Add support to fir.allocmem
if (auto allocOp = def.template getDefiningOp<fir::AllocaOp>()) {
v = def;
defOp = v.getDefiningOp();
type = SourceKind::Allocate;
} else if (isDummyArgument(def)) {
defOp = nullptr;
v = def;
} else {
type = SourceKind::Indirect;
bool classified = false;
if (auto defDefOp = def.getDefiningOp()) {
if (classifyAllocateFromEffects(defDefOp, def) ==
SourceKind::Allocate) {
v = def;
defOp = defDefOp;
type = SourceKind::Allocate;
classified = true;
}
}
if (!classified) {
if (isDummyArgument(def)) {
defOp = nullptr;
v = def;
} else {
type = SourceKind::Indirect;
}
}
}
breakFromLoop = true;

View File

@@ -15,5 +15,7 @@
func.func @_QPfoo() {
%1 = fir.alloca i32
%0 = arith.constant 0 : i32
fir.store %0 to %1 : !fir.ref<i32>
return
}

View File

@@ -372,8 +372,17 @@ func.func @alloca_unlimited_polymorphic_box() {
%1 = fir.alloca !fir.class<!fir.array<?xnone>>
%2 = fir.alloca !fir.box<none>
%3 = fir.alloca !fir.box<!fir.array<?xnone>>
// Add real uses so allocas are not trivially dead.
fir.call @__use_class_none(%0) : (!fir.ref<!fir.class<none>>) -> ()
fir.call @__use_class_array(%1) : (!fir.ref<!fir.class<!fir.array<?xnone>>>) -> ()
fir.call @__use_box_none(%2) : (!fir.ref<!fir.box<none>>) -> ()
fir.call @__use_box_array(%3) : (!fir.ref<!fir.box<!fir.array<?xnone>>>) -> ()
return
}
func.func private @__use_class_none(!fir.ref<!fir.class<none>>) -> ()
func.func private @__use_class_array(!fir.ref<!fir.class<!fir.array<?xnone>>>) -> ()
func.func private @__use_box_none(!fir.ref<!fir.box<none>>) -> ()
func.func private @__use_box_array(!fir.ref<!fir.box<!fir.array<?xnone>>>) -> ()
// Note: allocmem of fir.box are not possible (fir::HeapType::verify does not
// accept box types), so there is no equivalent of
// alloca_unlimited_polymorphic_box for allocmem.

View File

@@ -28,9 +28,11 @@ func.func @_QQmain() attributes {fir.bindc_name = "reduce"} {
omp.parallel reduction(byref @test_reduction %4 -> %arg0 : !fir.ref<!fir.box<i32>>) {
omp.terminator
}
func.call @__use_box_i32(%4) : (!fir.ref<!fir.box<i32>>) -> ()
return
}
func.func private @__use_box_i32(!fir.ref<!fir.box<i32>>) -> ()
// basically we are testing that there isn't a crash
// CHECK-LABEL: define void @_QQmain
// CHECK-NEXT: alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1, align 8

View File

@@ -95,14 +95,14 @@ func.func @_QTt1P.f2.offset(%0 : i32, %1 : i32) -> i32 {
// end program p
func.func private @bar(!fir.ref<!fir.char<1,?>>)
func.func private @__use_t1(!fir.ref<!fir.type<_QTt1(p1:i32,p2:i32){f1:!fir.char<1,?>,f2:!fir.char<1,?>}>>) -> ()
// CHECK-LABEL: define void @_QPfoo(i32 %0, i32 %1)
func.func @_QPfoo(%arg0 : i32, %arg1 : i32) {
// CHECK: %[[size:.*]] = call i64 @_QTt1P.mem.size(i32 %0, i32 %1)
// CHECK: %[[alloc:.*]] = alloca i8, i64 %[[size]]
%0 = fir.alloca !fir.type<_QTt1(p1:i32,p2:i32){f1:!fir.char<1,?>,f2:!fir.char<1,?>}>(%arg0, %arg1 : i32, i32)
//%2 = fir.coordinate_of %0, f2 : (!fir.ref<!fir.type<_QTt1>>) -> !fir.ref<!fir.char<1,?>>
%2 = fir.zero_bits !fir.ref<!fir.char<1,?>>
fir.call @bar(%2) : (!fir.ref<!fir.char<1,?>>) -> ()
// Keep alloca live without creating an unsupported coordinate_of on dynamic-sized field.
func.call @__use_t1(%0) : (!fir.ref<!fir.type<_QTt1(p1:i32,p2:i32){f1:!fir.char<1,?>,f2:!fir.char<1,?>}>>) -> ()
return
}

View File

@@ -75,7 +75,7 @@ func.func private @_test_inline_copy_in(%arg0: !fir.box<!fir.array<?x?x?xf64>> {
// CHECK: %[[VAL_22:.*]] = fir.box_addr %[[VAL_21:.*]]#0 : (!fir.box<!fir.array<?xf64>>) -> !fir.ref<!fir.array<?xf64>>
// CHECK: %[[VAL_23:.*]]:3 = hlfir.associate %[[VAL_5:.*]] {adapt.valuebyref} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
// CHECK: fir.call @_QFPsb(%[[VAL_22:.*]], %[[VAL_23:.*]]#0) fastmath<contract> : (!fir.ref<!fir.array<?xf64>>, !fir.ref<i32>) -> ()
// CHECK: hlfir.copy_out %16, %15#1 : (!fir.ref<!fir.box<!fir.array<?xf64>>>, i1) -> ()
// CHECK: hlfir.copy_out %{{.*}}, %[[VAL_21:.*]]#1 : (!fir.ref<!fir.box<!fir.array<?xf64>>>, i1) -> ()
// CHECK: hlfir.end_associate %[[VAL_23:.*]]#1, %[[VAL_23:.*]]#2 : !fir.ref<i32>, i1
// CHECK: return
// CHECK: }

View File

@@ -153,7 +153,6 @@ subroutine dynamic_shape_lower(cptr, fpr, shape, lower)
! CHECK: %[[VAL_2:.*]] = fir.shape %[[C_0]], %[[C_0]] : (index, index) -> !fir.shape<2>
! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_1:.*]](%[[VAL_2]]) : (!fir.ptr<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.box<!fir.ptr<!fir.array<?x?xf32>>>
! CHECK: fir.store %[[VAL_3]] to %[[VAL_0:.*]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x?xf32>>>>
! CHECK: %[[VAL_4:.*]] = fir.alloca i32 {bindc_name = "n", uniq_name = "_QFdynamic_shape_lowerEn"}
! CHECK: %[[VAL_5:.*]] = fir.coordinate_of %[[ARG_0:.*]], __address : (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) -> !fir.ref<i64>
! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref<i64>
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> !fir.ptr<!fir.array<?x?xf32>>

View File

@@ -32,11 +32,9 @@ end subroutine
! CHECK-LABEL: @_QPss
subroutine ss(count)
! CHECK: %[[V_0:[0-9]+]] = fir.alloca !fir.box<!fir.heap<i64>> {bindc_name = "count_max", uniq_name = "_QFssEcount_max"}
! CHECK: %[[V_1:[0-9]+]] = fir.alloca !fir.heap<i64> {uniq_name = "_QFssEcount_max.addr"}
! CHECK: %[[V_2:[0-9]+]] = fir.zero_bits !fir.heap<i64>
! CHECK: fir.store %[[V_2]] to %[[V_1]] : !fir.ref<!fir.heap<i64>>
! CHECK: %[[V_3:[0-9]+]] = fir.alloca !fir.box<!fir.ptr<i64>> {bindc_name = "count_rate", uniq_name = "_QFssEcount_rate"}
! CHECK: %[[V_4:[0-9]+]] = fir.alloca !fir.ptr<i64> {uniq_name = "_QFssEcount_rate.addr"}
! CHECK: %[[V_5:[0-9]+]] = fir.zero_bits !fir.ptr<i64>
! CHECK: fir.store %[[V_5]] to %[[V_4]] : !fir.ref<!fir.ptr<i64>>

View File

@@ -56,7 +56,7 @@ subroutine foodim1()
! CHECK-DAG: fir.load %[[xAddrVar]] : !fir.ref<!fir.heap<!fir.array<?xf32>>>
deallocate(x)
! CHECK: %[[xAddr1:.*]] = fir.load %1 : !fir.ref<!fir.heap<!fir.array<?xf32>>>
! CHECK: %[[xAddr1:.*]] = fir.load %{{.*}} : !fir.ref<!fir.heap<!fir.array<?xf32>>>
! CHECK: fir.freemem %[[xAddr1]]
! CHECK: %[[nullAddr1:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
! CHECK: fir.store %[[nullAddr1]] to %[[xAddrVar]] : !fir.ref<!fir.heap<!fir.array<?xf32>>>
@@ -67,10 +67,6 @@ subroutine foodim2()
! Test lowering of local allocatable specification
real, allocatable :: x(:, :)
! CHECK-DAG: fir.alloca !fir.heap<!fir.array<?x?xf32>> {{{.*}}uniq_name = "_QFfoodim2Ex.addr"}
! CHECK-DAG: fir.alloca index {{{.*}}uniq_name = "_QFfoodim2Ex.lb0"}
! CHECK-DAG: fir.alloca index {{{.*}}uniq_name = "_QFfoodim2Ex.ext0"}
! CHECK-DAG: fir.alloca index {{{.*}}uniq_name = "_QFfoodim2Ex.lb1"}
! CHECK-DAG: fir.alloca index {{{.*}}uniq_name = "_QFfoodim2Ex.ext1"}
end subroutine
! test lowering of character allocatables. Focus is placed on the length handling

View File

@@ -8,6 +8,7 @@
subroutine scalar_cst_len()
character(10) :: c
! CHECK: fir.alloca !fir.char<1,10> {{{.*}}uniq_name = "_QFscalar_cst_lenEc"}
print *, c
end subroutine
! CHECK-LABEL: func @_QPscalar_dyn_len
@@ -19,12 +20,14 @@ subroutine scalar_dyn_len(l)
! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[lexpr]], %c0{{.*}} : i32
! CHECK: %[[l:.*]] = arith.select %[[is_positive]], %[[lexpr]], %c0{{.*}} : i32
! CHECK: fir.alloca !fir.char<1,?>(%[[l]] : i32) {{{.*}}uniq_name = "_QFscalar_dyn_lenEc"}
print *, c
end subroutine
! CHECK-LABEL: func @_QPcst_array_cst_len
subroutine cst_array_cst_len()
character(10) :: c(20)
! CHECK: fir.alloca !fir.array<20x!fir.char<1,10>> {{{.*}}uniq_name = "_QFcst_array_cst_lenEc"}
print *, c(1)
end subroutine
! CHECK-LABEL: func @_QPcst_array_dyn_len
@@ -36,6 +39,7 @@ subroutine cst_array_dyn_len(l)
! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[lexpr]], %c0{{.*}} : i32
! CHECK: %[[l:.*]] = arith.select %[[is_positive]], %[[lexpr]], %c0{{.*}} : i32
! CHECK: fir.alloca !fir.array<10x!fir.char<1,?>>(%[[l]] : i32) {{{.*}}uniq_name = "_QFcst_array_dyn_lenEc"}
print *, c(1)
end subroutine
! CHECK-LABEL: func @_QPdyn_array_cst_len
@@ -48,6 +52,7 @@ subroutine dyn_array_cst_len(n)
! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[ni]], %c0{{.*}} : index
! CHECK: %[[extent:.*]] = arith.select %[[is_positive]], %[[ni]], %c0{{.*}} : index
! CHECK: fir.alloca !fir.array<?x!fir.char<1,10>>, %[[extent]] {{{.*}}uniq_name = "_QFdyn_array_cst_lenEc"}
print *, c(1)
end subroutine
! CHECK: func @_QPdyn_array_dyn_len
@@ -63,12 +68,14 @@ subroutine dyn_array_dyn_len(l, n)
! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[ni]], %c0{{.*}} : index
! CHECK: %[[extent:.*]] = arith.select %[[is_positive]], %[[ni]], %c0{{.*}} : index
! CHECK: fir.alloca !fir.array<?x!fir.char<1,?>>(%[[l]] : i32), %[[extent]] {{{.*}}uniq_name = "_QFdyn_array_dyn_lenEc"}
print *, c(1)
end subroutine
! CHECK-LABEL: func @_QPcst_array_cst_len_lb
subroutine cst_array_cst_len_lb()
character(10) :: c(11:30)
! CHECK: fir.alloca !fir.array<20x!fir.char<1,10>> {{{.*}}uniq_name = "_QFcst_array_cst_len_lbEc"}
print *, c(11)
end subroutine
! CHECK-LABEL: func @_QPcst_array_dyn_len_lb
@@ -80,6 +87,7 @@ subroutine cst_array_dyn_len_lb(l)
! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[lexpr]], %c0{{.*}} : i64
! CHECK: %[[l:.*]] = arith.select %[[is_positive]], %[[lexpr]], %c0{{.*}} : i64
! CHECK: fir.alloca !fir.array<10x!fir.char<1,?>>(%[[l]] : i64) {{{.*}}uniq_name = "_QFcst_array_dyn_len_lbEc"}
print *, c(11)
end subroutine
! CHECK-LABEL: func @_QPdyn_array_cst_len_lb
@@ -94,6 +102,7 @@ subroutine dyn_array_cst_len_lb(n)
! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[raw_extent]], %c0{{.*}} : index
! CHECK: %[[extent:.*]] = arith.select %[[is_positive]], %[[raw_extent]], %c0{{.*}} : index
! CHECK: fir.alloca !fir.array<?x!fir.char<1,10>>, %[[extent]] {{{.*}}uniq_name = "_QFdyn_array_cst_len_lbEc"}
print *, c(11)
end subroutine
! CHECK-LABEL: func @_QPdyn_array_dyn_len_lb
@@ -111,6 +120,7 @@ subroutine dyn_array_dyn_len_lb(l, n)
! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[raw_extent]], %c0{{.*}} : index
! CHECK: %[[extent:.*]] = arith.select %[[is_positive]], %[[raw_extent]], %c0{{.*}} : index
! CHECK: fir.alloca !fir.array<?x!fir.char<1,?>>(%[[l]] : i64), %[[extent]] {{{.*}}uniq_name = "_QFdyn_array_dyn_len_lbEc"}
print *, c(11)
end subroutine
! Test that the length of assumed length parameter is correctly deduced in lowering.
@@ -129,4 +139,5 @@ end
subroutine scalar_cst_neg_len()
character(-1) :: c
! CHECK: fir.alloca !fir.char<1,0> {{{.*}}uniq_name = "_QFscalar_cst_neg_lenEc"}
print *, c
end subroutine

View File

@@ -35,6 +35,8 @@ subroutine local_derived()
! CHECK-DAG: fir.alloca !fir.type<_QMdTr{x:f32}>
type(r) :: some_r
type(c2) :: some_c2
print *, some_c2%ch_array(1,1)
print *, some_r%x
end subroutine
! CHECK-LABEL: func @_QMdPsaved_derived(

View File

@@ -235,6 +235,7 @@ end subroutine
subroutine unstructured_do_concurrent
logical :: success
do concurrent (i=1:10) local(success)
success = .false.
error stop "fail"
enddo
end

View File

@@ -318,7 +318,6 @@ end subroutine s2_3
! CHECK-LABEL: func @_QPs2_3(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>> {fir.bindc_name = "x"}) {
! CHECK: %[[VAL_1:.*]] = fir.alloca i32 {adapt.valuebyref, bindc_name = "i"}
! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "y", fir.target, uniq_name = "_QFs2_3Ey"}
! CHECK: %[[VAL_3:.*]] = fir.alloca !fir.heap<!fir.array<?xi32>> {uniq_name = "_QFs2_3Ey.addr"}
! CHECK: %[[VAL_4:.*]] = fir.alloca index {uniq_name = "_QFs2_3Ey.lb0"}
! CHECK: %[[VAL_5:.*]] = fir.alloca index {uniq_name = "_QFs2_3Ey.ext0"}

View File

@@ -13,20 +13,19 @@ end subroutine forall_with_allocatable
! CHECK-LABEL: func @_QPforall_with_allocatable(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xf32>>{{.*}}) {
! CHECK: %[[VAL_1:.*]] = fir.alloca i32 {adapt.valuebyref, bindc_name = "i"}
! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "arr", uniq_name = "_QFforall_with_allocatableEarr"}
! CHECK: %[[VAL_3:.*]] = fir.alloca !fir.heap<!fir.array<?xf32>> {uniq_name = "_QFforall_with_allocatableEarr.addr"}
! CHECK: %[[VAL_4:.*]] = fir.alloca index {uniq_name = "_QFforall_with_allocatableEarr.lb0"}
! CHECK: %[[VAL_5:.*]] = fir.alloca index {uniq_name = "_QFforall_with_allocatableEarr.ext0"}
! CHECK: %[[VAL_6:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
! CHECK: fir.store %[[VAL_6]] to %[[VAL_3]] : !fir.ref<!fir.heap<!fir.array<?xf32>>>
! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.heap<!fir.array<?xf32>> {uniq_name = "_QFforall_with_allocatableEarr.addr"}
! CHECK: %[[VAL_3:.*]] = fir.alloca index {uniq_name = "_QFforall_with_allocatableEarr.lb0"}
! CHECK: %[[VAL_4:.*]] = fir.alloca index {uniq_name = "_QFforall_with_allocatableEarr.ext0"}
! CHECK: %[[VAL_5:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
! CHECK: fir.store %[[VAL_5]] to %[[VAL_2]] : !fir.ref<!fir.heap<!fir.array<?xf32>>>
! CHECK: %[[VAL_7:.*]] = arith.constant 5 : i32
! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> index
! CHECK: %[[VAL_9:.*]] = arith.constant 15 : i32
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i32) -> index
! CHECK: %[[VAL_11:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_4]] : !fir.ref<index>
! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_5]] : !fir.ref<index>
! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_3]] : !fir.ref<!fir.heap<!fir.array<?xf32>>>
! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_3]] : !fir.ref<index>
! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_4]] : !fir.ref<index>
! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.heap<!fir.array<?xf32>>>
! CHECK: %[[VAL_15:.*]] = fir.shape_shift %[[VAL_12]], %[[VAL_13]] : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[VAL_16:.*]] = fir.array_load %[[VAL_14]](%[[VAL_15]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shapeshift<1>) -> !fir.array<?xf32>
! CHECK: %[[VAL_17:.*]] = fir.array_load %[[VAL_0]] : (!fir.box<!fir.array<?xf32>>) -> !fir.array<?xf32>

View File

@@ -90,7 +90,6 @@ subroutine lis(n)
! CHECK-DAG: fir.alloca !fir.array<?x?x?xi32>, %{{.*}}, %{{.*}}, %{{.*}} {bindc_name = "a", fir.target, uniq_name = "_QFlisEa"}
! CHECK-DAG: fir.alloca !fir.array<?x?xi32>, %{{.*}}, %{{.*}} {bindc_name = "r", uniq_name = "_QFlisEr"}
! CHECK-DAG: fir.alloca !fir.array<?x?xi32>, %{{.*}}, %{{.*}} {bindc_name = "s", uniq_name = "_QFlisEs"}
! CHECK-DAG: fir.alloca !fir.array<?x?xi32>, %{{.*}}, %{{.*}} {bindc_name = "t", uniq_name = "_QFlisEt"}
integer, target :: a(n,n,n) ! operand via p
integer :: r(n,n) ! result, unspecified locality
integer :: s(n,n) ! shared locality

View File

@@ -287,7 +287,6 @@ module polymorphic_test
! First test is here to have a reference with non polymorphic on both sides.
! CHECK-LABEL: func.func @_QMpolymorphic_testPpointer_assign_parent(
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<_QMpolymorphic_testTp2{a:i32,b:i32,c:f32}>> {fir.bindc_name = "p", fir.target}) {
! CHECK: %[[TP:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>> {bindc_name = "tp", uniq_name = "_QMpolymorphic_testFpointer_assign_parentEtp"}
! CHECK: %[[PTR:.*]] = fir.alloca !fir.ptr<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>> {uniq_name = "_QMpolymorphic_testFpointer_assign_parentEtp.addr"}
! CHECK: %[[ZERO:.*]] = fir.zero_bits !fir.ptr<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>
! CHECK: fir.store %[[ZERO]] to %[[PTR]] : !fir.ref<!fir.ptr<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>>
@@ -302,7 +301,6 @@ module polymorphic_test
! CHECK-LABEL: func.func @_QMpolymorphic_testPpointer_assign_non_poly(
! CHECK-SAME: %arg0: !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>> {fir.bindc_name = "p", fir.target}) {
! CHECK: %[[TP:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>> {bindc_name = "tp", uniq_name = "_QMpolymorphic_testFpointer_assign_non_polyEtp"}
! CHECK: %[[PTR:.*]] = fir.alloca !fir.ptr<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>> {uniq_name = "_QMpolymorphic_testFpointer_assign_non_polyEtp.addr"}
! CHECK: %[[ZERO:.*]] = fir.zero_bits !fir.ptr<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>
! CHECK: fir.store %[[ZERO]] to %[[PTR]] : !fir.ref<!fir.ptr<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>>
@@ -1103,11 +1101,9 @@ module polymorphic_test
! CHECK-LABEL: func.func @_QMpolymorphic_testPclass_with_entry(
! CHECK-SAME: %[[A:.*]]: !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>> {fir.bindc_name = "a"}) {
! CHECK: %[[B:.*]] = fir.alloca !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>> {bindc_name = "b", uniq_name = "_QMpolymorphic_testFclass_with_entryEb"}
! CHECK-LABEL: func.func @_QMpolymorphic_testPd(
! CHECK-SAME: %[[B:.*]]: !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>> {fir.bindc_name = "b"}) {
! CHECK: %[[A:.*]] = fir.alloca !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>> {bindc_name = "a", uniq_name = "_QMpolymorphic_testFclass_with_entryEa"}
subroutine class_array_with_entry(a)
class(p1) :: a(:), b(:)

View File

@@ -129,7 +129,6 @@ integer function test_stmt_character_with_different_length_2(c, n)
character(n) :: argc
character(*) :: c
! CHECK: %[[unboxed:.*]]:2 = fir.unboxchar %[[arg0]] :
! CHECK: fir.load %[[arg1]] : !fir.ref<i32>
! CHECK: %[[n:.*]] = fir.load %[[arg1]] : !fir.ref<i32>
! CHECK: %[[n_is_positive:.*]] = arith.cmpi sgt, %[[n]], %c0{{.*}} : i32
! CHECK: %[[len:.*]] = arith.select %[[n_is_positive]], %[[n]], %c0{{.*}} : i32

View File

@@ -3,13 +3,17 @@
// Simplest transformation
func.func @simple() {
%0 = fir.allocmem !fir.array<42xi32>
%c0_s = arith.constant 0 : index
%c0_i32_s = arith.constant 0 : i32
%ref_s = fir.convert %0 : (!fir.heap<!fir.array<42xi32>>) -> !fir.ref<!fir.array<42xi32>>
%elt_s = fir.coordinate_of %ref_s, %c0_s : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
fir.store %c0_i32_s to %elt_s : !fir.ref<i32>
fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
return
}
// CHECK: func.func @simple() {
// CHECK-NEXT: fir.alloca !fir.array<42xi32>
// CHECK-NEXT: return
// CHECK-NEXT: }
// CHECK: func.func @simple()
// CHECK: fir.alloca !fir.array<42xi32>
// CHECK: return
// Check fir.must_be_heap allocations are not moved
func.func @must_be_heap() {
@@ -17,7 +21,7 @@ func.func @must_be_heap() {
fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
return
}
// CHECK: func.func @must_be_heap() {
// CHECK-LABEL: func.func @must_be_heap()
// CHECK-NEXT: %[[ALLOC:.*]] = fir.allocmem !fir.array<42xi32> {fir.must_be_heap = true}
// CHECK-NEXT: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<42xi32>>
// CHECK-NEXT: return
@@ -36,7 +40,7 @@ func.func @dfa1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
}
return
}
// CHECK: func.func @dfa1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
// CHECK-LABEL: func.func @dfa1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"})
// CHECK-NEXT: %[[C42:.*]] = arith.constant 42 : index
// CHECK-NEXT: %[[MEM:.*]] = fir.allocmem !fir.array<?xi32>, %[[C42]] {uniq_name = "_QFdfa1Earr.alloc"}
// CHECK-NEXT: %[[LOGICAL:.*]] = fir.load %arg0 : !fir.ref<!fir.logical<4>>
@@ -57,7 +61,7 @@ func.func @dfa2(%arg0: i1) {
}
return
}
// CHECK: func.func @dfa2(%arg0: i1) {
// CHECK-LABEL: func.func @dfa2(%arg0: i1)
// CHECK-NEXT: %[[MEM:.*]] = fir.allocmem !fir.array<1xi8>
// CHECK-NEXT: scf.if %arg0 {
// CHECK-NEXT: fir.freemem %[[MEM]] : !fir.heap<!fir.array<1xi8>>
@@ -74,15 +78,16 @@ func.func @dfa3(%arg0: i1) {
} else {
fir.freemem %a : !fir.heap<!fir.array<1xi8>>
}
%c0_d3 = arith.constant 0 : index
%c0_i8_d3 = arith.constant 0 : i8
%ref_d3 = fir.convert %a : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
%elt_d3 = fir.coordinate_of %ref_d3, %c0_d3 : (!fir.ref<!fir.array<1xi8>>, index) -> !fir.ref<i8>
fir.store %c0_i8_d3 to %elt_d3 : !fir.ref<i8>
return
}
// CHECK: func.func @dfa3(%arg0: i1) {
// CHECK-NEXT: %[[MEM:.*]] = fir.alloca !fir.array<1xi8>
// CHECK-NEXT: fir.if %arg0 {
// CHECK-NEXT: } else {
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
// CHECK: func.func @dfa3(%arg0: i1)
// CHECK: %[[MEM:.*]] = fir.alloca !fir.array<1xi8>
// CHECK: return
func.func private @dfa3a_foo(!fir.ref<!fir.array<1xi8>>) -> ()
func.func private @dfa3a_bar(!fir.ref<!fir.array<1xi8>>) -> ()
@@ -101,7 +106,7 @@ func.func @dfa3a(%arg0: i1) {
}
return
}
// CHECK: func.func @dfa3a(%arg0: i1) {
// CHECK-LABEL: func.func @dfa3a(%arg0: i1)
// CHECK-NEXT: %[[MEM:.*]] = fir.alloca !fir.array<1xi8>
// CHECK-NEXT: %[[HEAP:.*]] = fir.convert %[[MEM]] : (!fir.ref<!fir.array<1xi8>>) -> !fir.heap<!fir.array<1xi8>>
// CHECK-NEXT: fir.if %arg0 {
@@ -123,13 +128,18 @@ func.func @placement1() {
// operand is now available
%4 = fir.allocmem !fir.array<?xi32>, %3
// ...
%c0 = arith.constant 0 : index
%c0_i32 = arith.constant 0 : i32
%ref1 = fir.convert %4 : (!fir.heap<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
%elt1 = fir.coordinate_of %ref1, %c0 : (!fir.ref<!fir.array<?xi32>>, index) -> !fir.ref<i32>
fir.store %c0_i32 to %elt1 : !fir.ref<i32>
fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
return
}
// CHECK: func.func @placement1() {
// CHECK-LABEL: func.func @placement1()
// CHECK-NEXT: %[[ARG:.*]] = arith.constant 3 : index
// CHECK-NEXT: %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[ARG]]
// CHECK-NEXT: return
// CHECK: return
// CHECK-NEXT: }
// check that if there are no operands, then the alloca is placed early
@@ -140,16 +150,21 @@ func.func @placement2() {
%3 = arith.addi %1, %2 : index
%4 = fir.allocmem !fir.array<42xi32>
// ...
%c0_p2 = arith.constant 0 : index
%c0_i32_p2 = arith.constant 0 : i32
%ref_p2 = fir.convert %4 : (!fir.heap<!fir.array<42xi32>>) -> !fir.ref<!fir.array<42xi32>>
%elt_p2 = fir.coordinate_of %ref_p2, %c0_p2 : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
fir.store %c0_i32_p2 to %elt_p2 : !fir.ref<i32>
fir.freemem %4 : !fir.heap<!fir.array<42xi32>>
return
}
// CHECK: func.func @placement2() {
// CHECK-NEXT: %[[MEM:.*]] = fir.alloca !fir.array<42xi32>
// CHECK-NEXT: %[[ONE:.*]] = arith.constant 1 : index
// CHECK-NEXT: %[[TWO:.*]] = arith.constant 2 : index
// CHECK-NEXT: %[[SUM:.*]] = arith.addi %[[ONE]], %[[TWO]] : index
// CHECK-NEXT: return
// CHECK-NEXT: }
// CHECK-LABEL: func.func @placement2()
// CHECK: %[[MEM:.*]] = fir.alloca !fir.array<42xi32>
// CHECK: %[[ONE:.*]] = arith.constant 1 : index
// CHECK: %[[TWO:.*]] = arith.constant 2 : index
// CHECK: %[[SUM:.*]] = arith.addi %[[ONE]], %[[TWO]] : index
// CHECK: return
// CHECK: }
// check that stack allocations which must be placed in loops use stacksave
func.func @placement3() {
@@ -162,12 +177,17 @@ func.func @placement3() {
// operand is now available
%4 = fir.allocmem !fir.array<?xi32>, %3
// ...
%c0 = arith.constant 0 : index
%c0_i32 = arith.constant 0 : i32
%ref2 = fir.convert %4 : (!fir.heap<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
%elt2 = fir.coordinate_of %ref2, %c0 : (!fir.ref<!fir.array<?xi32>>, index) -> !fir.ref<i32>
fir.store %c0_i32 to %elt2 : !fir.ref<i32>
fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
fir.result %3, %c1_i32 : index, i32
}
return
}
// CHECK: func.func @placement3() {
// CHECK-LABEL: func.func @placement3()
// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index
// CHECK-NEXT: %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
// CHECK-NEXT: %[[C2:.*]] = arith.constant 2 : index
@@ -176,7 +196,7 @@ func.func @placement3() {
// CHECK-NEXT: %[[SUM:.*]] = arith.addi %[[C1]], %[[C2]] : index
// CHECK-NEXT: %[[SP:.*]] = llvm.intr.stacksave : !llvm.ptr
// CHECK-NEXT: %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[SUM]]
// CHECK-NEXT: llvm.intr.stackrestore %[[SP]] : !llvm.ptr
// CHECK: llvm.intr.stackrestore %[[SP]] : !llvm.ptr
// CHECK-NEXT: fir.result
// CHECK-NEXT: }
// CHECK-NEXT: return
@@ -194,12 +214,17 @@ func.func @placement4(%arg0 : i1) {
// operand is now available
%4 = fir.allocmem !fir.array<?xi32>, %3
// ...
%c0 = arith.constant 0 : index
%c0_i32 = arith.constant 0 : i32
%ref3 = fir.convert %4 : (!fir.heap<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
%elt3 = fir.coordinate_of %ref3, %c0 : (!fir.ref<!fir.array<?xi32>>, index) -> !fir.ref<i32>
fir.store %c0_i32 to %elt3 : !fir.ref<i32>
fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
cf.cond_br %arg0, ^bb1, ^bb2
^bb2:
return
}
// CHECK: func.func @placement4(%arg0: i1) {
// CHECK-LABEL: func.func @placement4(%arg0: i1)
// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index
// CHECK-NEXT: %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
// CHECK-NEXT: %[[C10:.*]] = arith.constant 10 : index
@@ -208,7 +233,7 @@ func.func @placement4(%arg0 : i1) {
// CHECK-NEXT: %[[C3:.*]] = arith.constant 3 : index
// CHECK-NEXT: %[[SP:.*]] = llvm.intr.stacksave : !llvm.ptr
// CHECK-NEXT: %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[C3]]
// CHECK-NEXT: llvm.intr.stackrestore %[[SP]] : !llvm.ptr
// CHECK: llvm.intr.stackrestore %[[SP]] : !llvm.ptr
// CHECK-NEXT: cf.cond_br %arg0, ^bb1, ^bb2
// CHECK-NEXT: ^bb2:
// CHECK-NEXT: return
@@ -230,7 +255,7 @@ func.func @placement5() {
}
return
}
// CHECK: func.func @placement5() {
// CHECK-LABEL: func.func @placement5()
// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index
// CHECK-NEXT: %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
// CHECK-NEXT: %[[C2:.*]] = arith.constant 2 : index
@@ -268,7 +293,7 @@ func.func @placement6(%arg0: i1) {
fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
cf.br ^bb1
}
// CHECK: func.func @placement6(%arg0: i1) {
// CHECK-LABEL: func.func @placement6(%arg0: i1)
// CHECK-NEXT: %[[c1:.*]] = arith.constant 1 : index
// CHECK-NEXT: %[[c1_i32:.*]] = fir.convert %[[c1]] : (index) -> i32
// CHECK-NEXT: %[[c2:.*]] = arith.constant 2 : index
@@ -289,6 +314,11 @@ func.func @placement6(%arg0: i1) {
// Check multiple returns, where the memory is always freed
func.func @returns(%arg0: i1) {
%0 = fir.allocmem !fir.array<42xi32>
%c0_ret = arith.constant 0 : index
%c0_i32_ret = arith.constant 0 : i32
%ref_ret = fir.convert %0 : (!fir.heap<!fir.array<42xi32>>) -> !fir.ref<!fir.array<42xi32>>
%elt_ret = fir.coordinate_of %ref_ret, %c0_ret : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
fir.store %c0_i32_ret to %elt_ret : !fir.ref<i32>
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
@@ -297,9 +327,9 @@ func.func @returns(%arg0: i1) {
fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
return
}
// CHECK: func.func @returns(%[[COND:.*]]: i1) {
// CHECK-NEXT: %[[ALLOC:.*]] = fir.alloca !fir.array<42xi32>
// CHECK-NEXT: cf.cond_br %[[COND]], ^bb1, ^bb2
// CHECK-LABEL: func.func @returns(
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.array<42xi32>
// CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2
// CHECK-NEXT: ^bb1:
// CHECK-NEXT: return
// CHECK-NEXT: ^bb2:
@@ -309,6 +339,11 @@ func.func @returns(%arg0: i1) {
// Check multiple returns, where the memory is not freed on one branch
func.func @returns2(%arg0: i1) {
%0 = fir.allocmem !fir.array<42xi32>
%c0_ret2 = arith.constant 0 : index
%c0_i32_ret2 = arith.constant 0 : i32
%ref_ret2 = fir.convert %0 : (!fir.heap<!fir.array<42xi32>>) -> !fir.ref<!fir.array<42xi32>>
%elt_ret2 = fir.coordinate_of %ref_ret2, %c0_ret2 : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
fir.store %c0_i32_ret2 to %elt_ret2 : !fir.ref<i32>
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
@@ -316,9 +351,9 @@ func.func @returns2(%arg0: i1) {
^bb2:
return
}
// CHECK: func.func @returns2(%[[COND:.*]]: i1) {
// CHECK-NEXT: %[[ALLOC:.*]] = fir.allocmem !fir.array<42xi32>
// CHECK-NEXT: cf.cond_br %[[COND]], ^bb1, ^bb2
// CHECK-LABEL: func.func @returns2(
// CHECK: %[[ALLOC:.*]] = fir.allocmem !fir.array<42xi32>
// CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2
// CHECK-NEXT: ^bb1:
// CHECK-NEXT: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<42xi32>>
// CHECK-NEXT: return
@@ -338,7 +373,7 @@ func.func @omp_placement1() {
}
return
}
// CHECK: func.func @omp_placement1() {
// CHECK-LABEL: func.func @omp_placement1()
// CHECK-NEXT: %[[MEM:.*]] = fir.alloca !fir.array<42xi32>
// CHECK-NEXT: %[[MEM_CONV:.*]] = fir.convert %[[MEM]] : (!fir.ref<!fir.array<42xi32>>) -> !fir.heap<!fir.array<42xi32>>
// CHECK-NEXT: omp.sections {
@@ -353,19 +388,21 @@ func.func @omp_placement1() {
// function terminated by stop statement
func.func @stop_terminator() {
%0 = fir.allocmem !fir.array<42xi32>
%c0 = arith.constant 0 : index
%c0_i32_st = arith.constant 0 : i32
%ref4 = fir.convert %0 : (!fir.heap<!fir.array<42xi32>>) -> !fir.ref<!fir.array<42xi32>>
%elt4 = fir.coordinate_of %ref4, %c0 : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
fir.store %c0_i32_st to %elt4 : !fir.ref<i32>
fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
%c0_i32 = arith.constant 0 : i32
%false = arith.constant false
fir.call @_FortranAStopStatement(%c0_i32, %false, %false) : (i32, i1, i1) -> ()
fir.unreachable
}
// CHECK: func.func @stop_terminator() {
// CHECK-NEXT: fir.alloca !fir.array<42xi32>
// CHECK-NEXT: %[[ZERO:.*]] = arith.constant 0 : i32
// CHECK-NEXT: %[[FALSE:.*]] = arith.constant false
// CHECK-NEXT: fir.call @_FortranAStopStatement(%[[ZERO]], %[[FALSE]], %[[FALSE]]) : (i32, i1, i1) -> ()
// CHECK-NEXT: fir.unreachable
// CHECK-NEXT: }
// CHECK-LABEL: func.func @stop_terminator()
// CHECK: fir.alloca !fir.array<42xi32>
// CHECK: fir.call @_FortranAStopStatement(
// CHECK: fir.unreachable
// check that stack allocations that use fir.declare which must be placed in loops
@@ -387,7 +424,7 @@ func.func @placement_loop_declare() {
}
return
}
// CHECK: func.func @placement_loop_declare() {
// CHECK-LABEL: func.func @placement_loop_declare()
// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index
// CHECK-NEXT: %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
// CHECK-NEXT: %[[C2:.*]] = arith.constant 2 : index
@@ -415,7 +452,7 @@ func.func @lookthrough() {
fir.freemem %4 : !fir.heap<!fir.array<42xi32>>
return
}
// CHECK: func.func @lookthrough() {
// CHECK-LABEL: func.func @lookthrough()
// CHECK: fir.alloca !fir.array<42xi32>
// CHECK-NOT: fir.freemem
@@ -457,6 +494,6 @@ func.func @finding_freemem_in_block() {
^bb3: // pred: ^bb1
return
}
// CHECK: func.func @finding_freemem_in_block() {
// CHECK-LABEL: func.func @finding_freemem_in_block()
// CHECK: fir.alloca !fir.array<?xi32>
// CHECK-NOT: fir.freemem