[flang] Delete the legacy array-value operations from FIR (#213159)

Nothing in flang has produced fir.array_load, fir.array_fetch,
fir.array_update, fir.array_modify, fir.array_access, fir.array_amend,
or fir.array_merge_store since the legacy (non-HLFIR) expression
lowering was deleted (#210385, #210621, #210639, #210873), and the
array-value-copy pass that legalized them is gone (#211816, #212643).
Delete the operations and the surface that existed only for them:

- FIROps.td: the "Array value operations" section including the
copy-in/copy-out design comment; FIROps.cpp: the ops verifiers, effects
and getExtents. fir.array_coor is unrelated and stays, as does the
validTypeParams helper shared with fir.pack_array.
- Tests: the ops roundtrip/verifier blocks in fir-ops.fir and
invalid.fir; scaffolding rewrites in inline-elemental.fir (store via
hlfir.designate; hlfir.apply-in-do_loop coverage preserved),
loop-versioning.fir @test4 (the versioned loops are untouched), and
simplifyintrinsics.fir (inert copy-back loops dropped; no CHECK lines
affected).
- Docs: FIRArrayOperations.md (+ the index.md toctree line); past-tense
updates in HighLevelFIR.md; a stale comment in MutableBox.h; a
release-note entry recording the removal for downstream projects.
FIRLangRef is generated from FIROps.td and follows automatically.

Assisted-by: AI
This commit is contained in:
Eugene Epshteyn 2026-07-31 08:47:13 -04:00 committed by GitHub
parent 4dc60bbb98
commit 95ee221ea8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 28 additions and 1343 deletions

View file

@ -1,343 +0,0 @@
<!--===- docs/FIRArrayOperations.md
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
See https://llvm.org/LICENSE.txt for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->
# Design: FIR Array operations
```{contents}
---
local:
---
```
## General
The array operations in FIR model the copy-in/copy-out semantics over Fortran
statements.
Fortran language semantics sometimes require the compiler to make a temporary
copy of an array or array slice. Situations where this can occur include:
* Passing a non-contiguous array to a procedure that does not declare it as
assumed-shape.
* Array expressions, especially those involving `RESHAPE`, `PACK`, and `MERGE`.
* Assignments of arrays where the array appears on both the left and right-hand
sides of the assignment.
* Assignments of `POINTER` arrays.
There are currently the following operations:
- `fir.array_load`
- `fir.array_merge_store`
- `fir.array_fetch`
- `fir.array_update`
- `fir.array_access`
- `fir.array_amend`
`array_load`(s) and `array_merge_store` are a pairing that brackets the lifetime
of the array copies.
`array_fetch` and `array_update` are defined to work as getter/setter pairs on
values of elements from loaded array copies. These have "GEP-like" syntax and
semantics.
Fortran arrays are implicitly memory bound as are some other Fortran type/kind
entities. For entities that can be atomically promoted to the value domain,
we use `array_fetch` and `array_update`.
`array_access` and `array_amend` are defined to work as getter/setter pairs on
references to elements in loaded array copies. `array_access` has "GEP-like"
syntax. `array_amend` annotates which loaded array copy is being written to.
It is invalid to update an array copy without `array_amend`; doing so will
result in undefined behavior.
For those type/kinds that cannot be promoted to values, we must leave them in a
memory reference domain, and we use `array_access` and `array_amend`.
## array_load
This operation taken with `array_merge_store` captures Fortran's
copy-in/copy-out semantics. One way to think of this is that array_load
creates a snapshot copy of the entire array. This copy can then be used
as the "original value" of the array while the array's new value is
computed. The `array_merge_store` operation is the copy-out semantics, which
merge the updates with the original array value to produce the final array
result. This abstracts the copy operations as opposed to always creating
copies or requiring dependence analysis be performed on the syntax trees
and before lowering to the IR.
Load an entire array as a single SSA value.
```fortran
real :: a(o:n,p:m)
...
... = ... a ...
```
One can use `fir.array_load` to produce an ssa-value that captures an
immutable value of the entire array `a`, as in the Fortran array expression
shown above. Subsequent changes to the memory containing the array do not
alter its composite value. This operation lets one load an array as a
value while applying a runtime shape, shift, or slice to the memory
reference, and its semantics guarantee immutability.
```
%s = fir.shape_shift %lb1, %ex1, %lb2, %ex2 : (index, index, index, index) -> !fir.shapeshift<2>
// load the entire array 'a'
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
// a fir.store here into array %a does not change %v
```
## array_merge_store
The `array_merge_store` operation stores a merged array value to memory.
```fortran
real :: a(n,m)
...
a = ...
```
One can use `fir.array_merge_store` to merge/copy the value of `a` in an
array expression as shown above.
```
%v = fir.array_load %a(%shape) : ...
%r = fir.array_update %v, %f, %i, %j : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
fir.array_merge_store %v, %r to %a : !fir.ref<!fir.array<?x?xf32>>
```
This operation merges the original loaded array value, `%v`, with the
chained updates, `%r`, and stores the result to the array at address, `%a`.
This operation taken with `array_load`'s captures Fortran's
copy-in/copy-out semantics. The first operands of `array_merge_store` is the
result of the initial `array_load` operation. While this value could be
retrieved by reference chasing through the different array operations it is
useful to have it on hand directly for analysis passes since this directly
defines the "bounds" of the Fortran statement represented by these operations.
The intention is to allow copy-in/copy-out regions to be easily delineated,
analyzed, and optimized.
## array_fetch
The `array_fetch` operation fetches the value of an element in an array value.
```fortran
real :: a(n,m)
...
... a ...
... a(r,s+1) ...
```
One can use `fir.array_fetch` to fetch the (implied) value of `a(i,j)` in
an array expression as shown above. It can also be used to extract the
element `a(r,s+1)` in the second expression.
```
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
// load the entire array 'a'
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
// fetch the value of one of the array value's elements
%1 = fir.array_fetch %v, %i, %j : (!fir.array<?x?xf32>, index, index) -> f32
```
It is only possible to use `array_fetch` on an `array_load` result value or a
value that can be trace back transitively to an `array_load` as the dominating
source. Other array operation such as `array_update` can be in between.
## array_update
The `array_update` operation is used to update the value of an element in an
array value. A new array value is returned where all element values of the input
array are identical except for the selected element which is the value passed in
the update.
```fortran
real :: a(n,m)
...
a = ...
```
One can use `fir.array_update` to update the (implied) value of `a(i,j)`
in an array expression as shown above.
```
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
// load the entire array 'a'
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
// update the value of one of the array value's elements
// %r_{ij} = %f if (i,j) = (%i,%j), %v_{ij} otherwise
%r = fir.array_update %v, %f, %i, %j : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
fir.array_merge_store %v, %r to %a : !fir.ref<!fir.array<?x?xf32>>
```
An array value update behaves as if a mapping function from the indices
to the new value has been added, replacing the previous mapping. These
mappings can be added to the ssa-value, but will not be materialized in
memory until the `fir.array_merge_store` is performed.
`fir.array_update` can be seen as an array access with a notion that the array
will be changed at the accessed position when `fir.array_merge_store` is
performed.
## array_access
The `array_access` provides a reference to a single element from an array value.
This is *not* a view in the immutable array, otherwise it couldn't be stored to.
It can be see as a logical copy of the element and its position in the array.
Tis reference can be written to and modified withoiut changing the original
array.
The `array_access` operation is used to fetch the memory reference of an element
in an array value.
```fortran
real :: a(n,m)
...
... a ...
... a(r,s+1) ...
```
One can use `fir.array_access` to recover the implied memory reference to
the element `a(i,j)` in an array expression `a` as shown above. It can also
be used to recover the reference element `a(r,s+1)` in the second
expression.
```
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
// load the entire array 'a'
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
// fetch the value of one of the array value's elements
%1 = fir.array_access %v, %i, %j : (!fir.array<?x?xf32>, index, index) -> !fir.ref<f32>
```
It is only possible to use `array_access` on an `array_load` result value or a
value that can be trace back transitively to an `array_load` as the dominating
source. Other array operation such as `array_amend` can be in between.
`array_access` if mainly used with `character`'s arrays and arrays of derived
types where because they might have a non-compile time sizes that would be
useless too load entirely or too big to load.
Here is a simple example with a `character` array assignment.
Fortran
```
subroutine foo(c1, c2, n)
integer(8) :: n
character(n) :: c1(:), c2(:)
c1 = c2
end subroutine
```
It results in this cleaned-up FIR:
```
func @_QPfoo(%arg0: !fir.box<!fir.array<?x!fir.char<1,?>>>, %arg1: !fir.box<!fir.array<?x!fir.char<1,?>>>, %arg2: !fir.ref<i64>) {
%0 = fir.load %arg2 : !fir.ref<i64>
%c0 = arith.constant 0 : index
%1:3 = fir.box_dims %arg0, %c0 : (!fir.box<!fir.array<?x!fir.char<1,?>>>, index) -> (index, index, index)
%2 = fir.array_load %arg0 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> !fir.array<?x!fir.char<1,?>>
%3 = fir.array_load %arg1 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> !fir.array<?x!fir.char<1,?>>
%c1 = arith.constant 1 : index
%4 = arith.subi %1#1, %c1 : index
%5 = fir.do_loop %arg3 = %c0 to %4 step %c1 unordered iter_args(%arg4 = %2) -> (!fir.array<?x!fir.char<1,?>>) {
%6 = fir.array_access %3, %arg3 : (!fir.array<?x!fir.char<1,?>>, index) -> !fir.ref<!fir.char<1,?>>
%7 = fir.array_access %arg4, %arg3 : (!fir.array<?x!fir.char<1,?>>, index) -> !fir.ref<!fir.char<1,?>>
%false = arith.constant false
%8 = fir.convert %7 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
%9 = fir.convert %6 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
fir.call @llvm.memmove.p0i8.p0i8.i64(%8, %9, %0, %false) : (!fir.ref<i8>, !fir.ref<i8>, i64, i1) -> ()
%10 = fir.array_amend %arg4, %7 : (!fir.array<?x!fir.char<1,?>>, !fir.ref<!fir.char<1,?>>) -> !fir.array<?x!fir.char<1,?>>
fir.result %10 : !fir.array<?x!fir.char<1,?>>
}
fir.array_merge_store %2, %5 to %arg0 : !fir.array<?x!fir.char<1,?>>, !fir.array<?x!fir.char<1,?>>, !fir.box<!fir.array<?x!fir.char<1,?>>>
return
}
func private @llvm.memmove.p0i8.p0i8.i64(!fir.ref<i8>, !fir.ref<i8>, i64, i1)
}
```
`fir.array_access` and `fir.array_amend` split the two purposes of
`fir.array_update` into two distinct operations to work on type/kind that must
reside in the memory reference domain. `fir.array_access` captures the array
access semantics and `fir.array_amend` denotes which `fir.array_access` is the
lhs.
We do not want to start loading the entire `!fir.ref<!fir.char<1,?>>` here since
it has dynamic length, and even if constant, could be too long to do so.
## array_amend
The `array_amend` operation marks an array value as having been changed via a
reference obtain by an `array_access`. It acts as a logical transaction log
that is used to merge the final result back with an `array_merge_store`
operation.
```
// fetch the value of one of the array value's elements
%1 = fir.array_access %v, %i, %j : (!fir.array<?x?xT>, index, index) -> !fir.ref<T>
// modify the element by storing data using %1 as a reference
%2 = ... %1 ...
// mark the array value
%new_v = fir.array_amend %v, %2 : (!fir.array<?x?xT>, !fir.ref<T>) -> !fir.array<?x?xT>
```
## Example
Here is an example of a FIR code using several array operations together. The
example below is a simplified version of the FIR code comiing from the
following Fortran code snippet.
```fortran
subroutine s(a,l,u)
type t
integer m
end type t
type(t) :: a(:)
integer :: l, u
forall (i=l:u)
a(i) = a(u-i+1)
end forall
end
```
```
func @_QPs(%arg0: !fir.box<!fir.array<?x!fir.type<_QFsTt{m:i32}>>>, %arg1: !fir.ref<i32>, %arg2: !fir.ref<i32>) {
%l = fir.load %arg1 : !fir.ref<i32>
%l_index = fir.convert %l : (i32) -> index
%u = fir.load %arg2 : !fir.ref<i32>
%u_index = fir.convert %u : (i32) -> index
%c1 = arith.constant 1 : index
// This is the "copy-in" array used on the RHS of the expression. It will be indexed into and loaded at each iteration.
%array_a_src = fir.array_load %arg0 : (!fir.box<!fir.array<?x!fir.type<_QFsTt{m:i32}>>>) -> !fir.array<?x!fir.type<_QFsTt{m:i32}>>
// This is the "seed" for the "copy-out" array on the LHS. It'll flow from iteration to iteration and gets
// updated at each iteration.
%array_a_dest_init = fir.array_load %arg0 : (!fir.box<!fir.array<?x!fir.type<_QFsTt{m:i32}>>>) -> !fir.array<?x!fir.type<_QFsTt{m:i32}>>
%array_a_final = fir.do_loop %i = %l_index to %u_index step %c1 unordered iter_args(%array_a_dest = %array_a_dest_init) -> (!fir.array<?x!fir.type<_QFsTt{m:i32}>>) {
// Compute indexing for the RHS and array the element.
%u_minus_i = arith.subi %u_index, %i : index // u-i
%u_minus_i_plus_one = arith.addi %u_minus_i, %c1: index // u-i+1
%a_src_ref = fir.array_access %array_a_src, %u_minus_i_plus_one {Fortran.offsets} : (!fir.array<?x!fir.type<_QFsTt{m:i32}>>, index) -> !fir.ref<!fir.type<_QFsTt{m:i32}>>
%a_src_elt = fir.load %a_src_ref : !fir.ref<!fir.type<_QFsTt{m:i32}>>
// Get the reference to the element in the array on the LHS
%a_dst_ref = fir.array_access %array_a_dest, %i {Fortran.offsets} : (!fir.array<?x!fir.type<_QFsTt{m:i32}>>, index) -> !fir.ref<!fir.type<_QFsTt{m:i32}>>
// Store the value, and update the array
fir.store %a_src_elt to %a_dst_ref : !fir.ref<!fir.type<_QFsTt{m:i32}>>
%updated_array_a = fir.array_amend %array_a_dest, %a_dst_ref : (!fir.array<?x!fir.type<_QFsTt{m:i32}>>, !fir.ref<!fir.type<_QFsTt{m:i32}>>) -> !fir.array<?x!fir.type<_QFsTt{m:i32}>>
// Forward the current updated array to the next iteration.
fir.result %updated_array_a : !fir.array<?x!fir.type<_QFsTt{m:i32}>>
}
// Store back the result by merging the initial value loaded before the loop
// with the final one produced by the loop.
fir.array_merge_store %array_a_dest_init, %array_a_final to %arg0 : !fir.array<?x!fir.type<_QFsTt{m:i32}>>, !fir.array<?x!fir.type<_QFsTt{m:i32}>>, !fir.box<!fir.array<?x!fir.type<_QFsTt{m:i32}>>>
return
}
```

View file

@ -19,9 +19,9 @@ and how bufferizations of character and array expressions should be done.
This document proposes the addition of two concepts and a set of related
operations in a new dialect HLFIR to allow a simpler lowering to a higher-level
FIR representation that would later be lowered to the current FIR representation
via MLIR translation passes. As a result of these additions, it is likely that
the fir.array_load/fir.array_merge_store and related array operations could be
removed from FIR since array assignment analysis could directly happen on the
via MLIR translation passes. As a result of these additions, the
fir.array_load/fir.array_merge_store and related array operations have been
removed from FIR since array assignment analysis directly happens on the
higher-level FIR representation.
@ -110,8 +110,8 @@ The hlfir.declare operation and restrained memory types will allow:
assignments or transformational intrinsics).
- Generating debug information for the variables based on the hlfir.declare
operation.
- Generic Fortran aliasing analysis (currently implemented only around array
assignments with the fir.array_load concept).
- Generic Fortran aliasing analysis (previously implemented only around array
assignments with the since-removed fir.array_load concept).
The hlfir.declare will have a sibling fir.declare operation in FIR that will
allow keeping variable information until debug info is generated. The main
@ -501,7 +501,8 @@ The attributes can be:
- temporary_lhs: mark that the left hand side of the assignment is
a compiler generated temporary.
This will replace the current array_load/array_access/array_merge semantics.
This replaced the legacy array_load/array_access/array_merge semantics, whose
operations have since been removed from FIR.
Instead, a more generic alias analysis will be performed on the LHS and RHS to
detect aliasing, and a temporary inserted if needed. The alias analysis will
look at all the memory references in the RHS operand tree and base overlap
@ -1249,9 +1250,9 @@ func.func @_QPfoo(%arg0: !fir.box<!fir.array<?xf32>>, %arg1: !fir.box<!fir.array
Step 6: lower hlfir.designate/hlfir.assign in a translation pass:
At this point, the representation is similar to the current representation after
the array value copy pass, and the existing FIR flow is used (lowering
fir.do_loop to cfg and doing codegen to LLVM).
At this point, the representation is similar to what the legacy lowering
produced after its array value copy pass (both since removed), and the existing
FIR flow is used (lowering fir.do_loop to cfg and doing codegen to LLVM).
### Example 3: assignments with vector subscript

View file

@ -33,6 +33,16 @@ page](https://llvm.org/releases/).
## Non-comprehensive list of changes in this release
- The legacy array-value operations (`fir.array_load`, `fir.array_fetch`,
`fir.array_update`, `fir.array_modify`, `fir.array_access`,
`fir.array_amend`, `fir.array_merge_store`) have been removed from FIR,
together with the `array-value-copy` pass that legalized them and its
`-mmlir -disable-avc` option. Nothing in flang has produced these
operations since the legacy (non-HLFIR) expression lowering was deleted.
Downstream projects that still construct them must migrate to HLFIR (or
their own legalization) before rebasing. `fir.array_coor` is unrelated
and remains supported.
## New Compiler Flags
## Windows Support

View file

@ -69,7 +69,6 @@ on how to get in touch with us and to learn more about the current status.
DoConcurrent
DoConcurrentConversionToOpenMP
F202X
FIRArrayOperations
FIRLangRef
FlangDriver
FortranFeatureHistory

View file

@ -108,8 +108,7 @@ struct MutableBoxReallocation {
/// is an ExtendedValue for the storage pointer.
/// For example, when genReallocIfNeeded() is used for a LHS allocatable
/// array in an assignment, the callback performs the actual assignment
/// via the given storage pointer, so we end up generating array_updates and
/// array_merge_stores in each branch.
/// via the given storage pointer, in each branch.
using ReallocStorageHandlerFunc = std::function<void(fir::ExtendedValue)>;
MutableBoxReallocation

View file

@ -1544,402 +1544,6 @@ def fir_BoxTypeDescOp : fir_SimpleOneResultOp<"box_tdesc", [NoMemoryEffect]> {
let results = (outs fir_TypeDescType);
}
//===----------------------------------------------------------------------===//
// Array value operations
//===----------------------------------------------------------------------===//
// Array value operations are used to capture the semantics of
// Fortran's array expressions in FIR. An abstract array expression is
// evaluated in the following way.
//
// 1. Determination of the iteration space under which the assignment
// expression is to be evaluated. The iteration space may be implicit
// (from the shape of the result array) or explicit (defined by the user).
// 2. If there are masking expressions, evaluate (and cache) the
// masking expression for the iteration space (from 1).
// 3. The rhs of the assignment is evaluated for the iteration space. If
// masking expressions were present then the rhs is only evaluated where
// the mask was computed to be true. The entire rhs is completely evaluated
// before any results are stored to the lhs.
// 4. Each of the result values computed in the previous step are merged back
// to the lhs array's storage.
//
// The model (in pseudo-code) is thus:
//
// !- Load the arrays in the expression
// %10 = array_load A
// %11 = array_load B
// !- optional: compute mask values
// %masks = allocmem array<??xlogical>
// do_loop_nest %i = ... {
// %masks[i] = ...
// }
// !- Compute every element value "A = B ..."
// do_loop_nest %i = ... {
// if (%masks[i]) {
// array_fetch %11, ... !- B(...)
// %20 = ... !- element-by-element computation
// array_update %10, %20, ... !- A(...) = ...
// }
// }
// !- Merge the new and old values into the memory for "A"
// array_merge_store <updated A> to <A's address>
def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments,
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "Load an array as a value.";
let description = [{
This operation taken with array_merge_store captures Fortran's
copy-in/copy-out semantics. One way to think of this is that array_load
creates a snapshot copy of the entire array. This copy can then be used
as the "original value" of the array while the array's new value is
computed. The array_merge_store operation is the copy-out semantics, which
merge the updates with the original array value to produce the final array
result. This abstracts the copy operations as opposed to always creating
copies or requiring dependence analysis be performed on the syntax trees
and before lowering to the IR.
Load an entire array as a single SSA value.
```fortran
real :: a(o:n,p:m)
...
... = ... a ...
```
One can use `fir.array_load` to produce an ssa-value that captures an
immutable value of the entire array `a`, as in the Fortran array expression
shown above. Subsequent changes to the memory containing the array do not
alter its composite value. This operation lets one load an array as a
value while applying a runtime shape, shift, or slice to the memory
reference, and its semantics guarantee immutability.
```
%s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
// load the entire array 'a'
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
// a fir.store here into array %a does not change %v
```
}];
let arguments = (ins
AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Optional<fir_SliceType>:$slice,
Variadic<AnyIntegerType>:$typeparams
);
let results = (outs fir_SequenceType);
let assemblyFormat = [{
$memref (`(`$shape^`)`)? (`[`$slice^`]`)? (`typeparams` $typeparams^)?
attr-dict `:` functional-type(operands, results)
}];
let hasVerifier = 1;
let extraClassDeclaration = [{
std::vector<mlir::Value> getExtents();
}];
}
def fir_ArrayFetchOp : fir_Op<"array_fetch", [AttrSizedOperandSegments,
NoMemoryEffect]> {
let summary = "Fetch the value of an element of an array value";
let description = [{
Fetch the value of an element in an array value.
```fortran
real :: a(n,m)
...
... a ...
... a(r,s+1) ...
```
One can use `fir.array_fetch` to fetch the (implied) value of `a(i,j)` in
an array expression as shown above. It can also be used to extract the
element `a(r,s+1)` in the second expression.
```
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
// load the entire array 'a'
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
// fetch the value of one of the array value's elements
%1 = fir.array_fetch %v, %i, %j : (!fir.array<?x?xf32>, index, index) -> f32
```
It is only possible to use `array_fetch` on an `array_load` result value.
}];
let arguments = (ins
fir_SequenceType:$sequence,
Variadic<AnyCoordinateType>:$indices,
Variadic<AnyIntegerType>:$typeparams
);
let results = (outs AnyType:$element);
let assemblyFormat = [{
$sequence `,` $indices (`typeparams` $typeparams^)? attr-dict `:`
functional-type(operands, results)
}];
let hasVerifier = 1;
}
def fir_ArrayUpdateOp : fir_Op<"array_update", [AttrSizedOperandSegments,
NoMemoryEffect]> {
let summary = "Update the value of an element of an array value";
let description = [{
Updates the value of an element in an array value. A new array value is
returned where all element values of the input array are identical except
for the selected element which is the value passed in the update.
```fortran
real :: a(n,m)
...
a = ...
```
One can use `fir.array_update` to update the (implied) value of `a(i,j)`
in an array expression as shown above.
```
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
// load the entire array 'a'
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
// update the value of one of the array value's elements
// %r_{ij} = %f if (i,j) = (%i,%j), %v_{ij} otherwise
%r = fir.array_update %v, %f, %i, %j : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
fir.array_merge_store %v, %r to %a : !fir.ref<!fir.array<?x?xf32>>
```
An array value update behaves as if a mapping function from the indices
to the new value has been added, replacing the previous mapping. These
mappings can be added to the ssa-value, but will not be materialized in
memory until the `fir.array_merge_store` is performed.
}];
let arguments = (ins
fir_SequenceType:$sequence,
AnyType:$merge,
Variadic<AnyCoordinateType>:$indices,
Variadic<AnyIntegerType>:$typeparams
);
let results = (outs fir_SequenceType);
let assemblyFormat = [{
$sequence `,` $merge `,` $indices (`typeparams` $typeparams^)? attr-dict
`:` functional-type(operands, results)
}];
let hasVerifier = 1;
}
def fir_ArrayModifyOp : fir_Op<"array_modify", [AttrSizedOperandSegments,
NoMemoryEffect]> {
let summary = "Get an address for an array value to modify it.";
let description = [{
Modify the value of an element in an array value through actions done
on the returned address. A new array value is also
returned where all element values of the input array are identical except
for the selected element which is the value after the modification done
on the element address.
```fortran
real :: a(n)
...
! Elemental user defined assignment from type(SomeType) to real.
a = value_of_some_type
```
One can use `fir.array_modify` to update the (implied) value of `a(i)`
in an array expression as shown above.
```
%s = fir.shape %n : (index) -> !fir.shape<1>
// Load the entire array 'a'.
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.array<?xf32>
// Update the value of one of the array value's elements with a user
// defined assignment from %rhs.
%new = fir.do_loop %i = ... (%inner = %v) {
%rhs = ...
%addr, %r = fir.array_modify %inner, %i : (!fir.array<?xf32>, index) -> (fir.ref<f32>, !fir.array<?xf32>)
fir.call @user_def_assign(%addr, %rhs) (fir.ref<f32>, fir.ref<!fir.type<SomeType>>) -> ()
fir.result %r : !fir.ref<!fir.array<?xf32>>
}
fir.array_merge_store %v, %new to %a : !fir.ref<!fir.array<?xf32>>
```
An array value modification behaves as if a mapping function from the indices
to the new value has been added, replacing the previous mapping. These
mappings can be added to the ssa-value, but will not be materialized in
memory until the `fir.array_merge_store` is performed.
}];
let arguments = (ins
fir_SequenceType:$sequence,
Variadic<AnyCoordinateType>:$indices,
Variadic<AnyIntegerType>:$typeparams
);
let results = (outs fir_ReferenceType, fir_SequenceType);
let assemblyFormat = [{
$sequence `,` $indices (`typeparams` $typeparams^)? attr-dict
`:` functional-type(operands, results)
}];
let hasVerifier = 1;
}
def fir_ArrayAccessOp : fir_Op<"array_access", [AttrSizedOperandSegments,
NoMemoryEffect]> {
let summary = "Fetch the reference of an element of an array value";
let description = [{
The `array_access` provides a reference to a single element from an array
value. This is *not* a view in the immutable array, otherwise it couldn't
be stored to. It can be see as a logical copy of the element and its
position in the array. This reference can be written to and modified without
changing the original array.
The `array_access` operation is used to fetch the memory reference of an
element in an array value.
```fortran
real :: a(n,m)
...
... a ...
... a(r,s+1) ...
```
One can use `fir.array_access` to recover the implied memory reference to
the element `a(i,j)` in an array expression `a` as shown above. It can also
be used to recover the reference element `a(r,s+1)` in the second
expression.
```
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
// load the entire array 'a'
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
// fetch the value of one of the array value's elements
%1 = fir.array_access %v, %i, %j : (!fir.array<?x?xf32>, index, index) -> !fir.ref<f32>
```
It is only possible to use `array_access` on an `array_load` result value or
a value that can be trace back transitively to an `array_load` as the
dominating source. Other array operations such as `array_amend` can be in
between.
TODO: The above restriction is not enforced. The design of the operation
might need to be revisited to avoid such restrictions.
More information about `array_access` and other array operations can be
found in flang/docs/FIRArrayOperations.md.
}];
let arguments = (ins
fir_SequenceType:$sequence,
Variadic<AnyCoordinateType>:$indices,
Variadic<AnyIntegerType>:$typeparams
);
let results = (outs fir_ReferenceType:$element);
let assemblyFormat = [{
$sequence `,` $indices (`typeparams` $typeparams^)? attr-dict `:`
functional-type(operands, results)
}];
let hasVerifier = 1;
}
def fir_ArrayAmendOp : fir_Op<"array_amend", [NoMemoryEffect]> {
let summary = "Mark an array value as having been changed by reference.";
let description = [{
The `array_amend` operation marks an array value as having been changed via
a reference obtained by an `array_access`. It acts as a logical transaction
log that is used to merge the final result back with an `array_merge_store`
operation.
```
// fetch the value of one of the array value's elements
%1 = fir.array_access %v, %i, %j : (!fir.array<?x?xT>, index, index) -> !fir.ref<T>
// modify the element by storing data using %1 as a reference
%2 = ... %1 ...
// mark the array value
%new_v = fir.array_amend %v, %2 : (!fir.array<?x?xT>, !fir.ref<T>) -> !fir.array<?x?xT>
```
More information about `array_amend` and other array operations can be
found in flang/docs/FIRArrayOperations.md.
}];
let arguments = (ins
fir_SequenceType:$sequence,
fir_ReferenceType:$memref
);
let results = (outs fir_SequenceType);
let assemblyFormat = [{
$sequence `,` $memref attr-dict `:` functional-type(operands, results)
}];
}
def fir_ArrayMergeStoreOp : fir_Op<"array_merge_store",
[AttrSizedOperandSegments, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "Store merged array value to memory.";
let description = [{
Store a merged array value to memory.
```fortran
real :: a(n,m)
...
a = ...
```
One can use `fir.array_merge_store` to merge/copy the value of `a` in an
array expression as shown above.
```
%v = fir.array_load %a(%shape) : ...
%r = fir.array_update %v, %f, %i, %j : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
fir.array_merge_store %v, %r to %a : !fir.ref<!fir.array<?x?xf32>>
```
This operation merges the original loaded array value, `%v`, with the
chained updates, `%r`, and stores the result to the array at address, `%a`.
}];
let arguments = (ins
fir_SequenceType:$original,
fir_SequenceType:$sequence,
AnyRefOrBox:$memref,
Optional<fir_SliceType>:$slice,
Variadic<AnyIntegerType>:$typeparams
);
let assemblyFormat = [{
$original `,` $sequence `to` $memref (`[` $slice^ `]`)? (`typeparams`
$typeparams^)? attr-dict `:` type(operands)
}];
let hasVerifier = 1;
}
//===----------------------------------------------------------------------===//
// Record and array type operations
//===----------------------------------------------------------------------===//

View file

@ -1261,218 +1261,6 @@ std::optional<std::int64_t> fir::ArrayCoorOp::getViewOffset(mlir::OpResult) {
return std::nullopt;
}
//===----------------------------------------------------------------------===//
// ArrayLoadOp
//===----------------------------------------------------------------------===//
static mlir::Type adjustedElementType(mlir::Type t) {
if (auto ty = mlir::dyn_cast<fir::ReferenceType>(t)) {
auto eleTy = ty.getEleTy();
if (fir::isa_char(eleTy))
return eleTy;
if (fir::isa_derived(eleTy))
return eleTy;
if (mlir::isa<fir::SequenceType>(eleTy))
return eleTy;
}
return t;
}
std::vector<mlir::Value> fir::ArrayLoadOp::getExtents() {
if (auto sh = getShape())
if (auto *op = sh.getDefiningOp()) {
if (auto shOp = mlir::dyn_cast<fir::ShapeOp>(op)) {
auto extents = shOp.getExtents();
return {extents.begin(), extents.end()};
}
return mlir::cast<fir::ShapeShiftOp>(op).getExtents();
}
return {};
}
void fir::ArrayLoadOp::getEffects(
llvm::SmallVectorImpl<
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
&effects) {
effects.emplace_back(mlir::MemoryEffects::Read::get(), &getMemrefMutable(),
mlir::SideEffects::DefaultResource::get());
addVolatileMemoryEffects({getMemref().getType()}, effects);
}
llvm::LogicalResult fir::ArrayLoadOp::verify() {
auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy);
if (!arrTy)
return emitOpError("must be a reference to an array");
auto arrDim = arrTy.getDimension();
if (auto shapeOp = getShape()) {
auto shapeTy = shapeOp.getType();
unsigned shapeTyRank = 0u;
if (auto s = mlir::dyn_cast<fir::ShapeType>(shapeTy)) {
shapeTyRank = s.getRank();
} else if (auto ss = mlir::dyn_cast<fir::ShapeShiftType>(shapeTy)) {
shapeTyRank = ss.getRank();
} else {
auto s = mlir::cast<fir::ShiftType>(shapeTy);
shapeTyRank = s.getRank();
if (!mlir::isa<fir::BaseBoxType>(getMemref().getType()))
return emitOpError("shift can only be provided with fir.box memref");
}
if (arrDim && arrDim != shapeTyRank)
return emitOpError("rank of dimension mismatched");
}
if (auto sliceOp = getSlice()) {
if (auto sl = mlir::dyn_cast_or_null<fir::SliceOp>(sliceOp.getDefiningOp()))
if (!sl.getSubstr().empty())
return emitOpError("array_load cannot take a slice with substring");
if (auto sliceTy = mlir::dyn_cast<fir::SliceType>(sliceOp.getType()))
if (sliceTy.getRank() != arrDim)
return emitOpError("rank of dimension in slice mismatched");
}
if (!validTypeParams(getMemref().getType(), getTypeparams()))
return emitOpError("invalid type parameters");
return mlir::success();
}
//===----------------------------------------------------------------------===//
// ArrayMergeStoreOp
//===----------------------------------------------------------------------===//
llvm::LogicalResult fir::ArrayMergeStoreOp::verify() {
if (!mlir::isa<fir::ArrayLoadOp>(getOriginal().getDefiningOp()))
return emitOpError("operand #0 must be result of a fir.array_load op");
if (auto sl = getSlice()) {
if (auto sliceOp =
mlir::dyn_cast_or_null<fir::SliceOp>(sl.getDefiningOp())) {
if (!sliceOp.getSubstr().empty())
return emitOpError(
"array_merge_store cannot take a slice with substring");
if (!sliceOp.getFields().empty()) {
// This is an intra-object merge, where the slice is projecting the
// subfields that are to be overwritten by the merge operation.
auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) {
auto projTy =
fir::applyPathToType(seqTy.getEleTy(), sliceOp.getFields());
if (fir::unwrapSequenceType(getOriginal().getType()) != projTy)
return emitOpError(
"type of origin does not match sliced memref type");
if (fir::unwrapSequenceType(getSequence().getType()) != projTy)
return emitOpError(
"type of sequence does not match sliced memref type");
return mlir::success();
}
return emitOpError("referenced type is not an array");
}
}
return mlir::success();
}
auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
if (getOriginal().getType() != eleTy)
return emitOpError("type of origin does not match memref element type");
if (getSequence().getType() != eleTy)
return emitOpError("type of sequence does not match memref element type");
if (!validTypeParams(getMemref().getType(), getTypeparams()))
return emitOpError("invalid type parameters");
return mlir::success();
}
void fir::ArrayMergeStoreOp::getEffects(
llvm::SmallVectorImpl<
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
&effects) {
effects.emplace_back(mlir::MemoryEffects::Write::get(), &getMemrefMutable(),
mlir::SideEffects::DefaultResource::get());
addVolatileMemoryEffects({getMemref().getType()}, effects);
}
//===----------------------------------------------------------------------===//
// ArrayFetchOp
//===----------------------------------------------------------------------===//
// Template function used for both array_fetch and array_update verification.
template <typename A>
mlir::Type validArraySubobject(A op) {
auto ty = op.getSequence().getType();
return fir::applyPathToType(ty, op.getIndices());
}
llvm::LogicalResult fir::ArrayFetchOp::verify() {
auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());
auto indSize = getIndices().size();
if (indSize < arrTy.getDimension())
return emitOpError("number of indices != dimension of array");
if (indSize == arrTy.getDimension() &&
::adjustedElementType(getElement().getType()) != arrTy.getEleTy())
return emitOpError("return type does not match array");
auto ty = validArraySubobject(*this);
if (!ty || ty != ::adjustedElementType(getType()))
return emitOpError("return type and/or indices do not type check");
if (!mlir::isa<fir::ArrayLoadOp>(getSequence().getDefiningOp()))
return emitOpError("argument #0 must be result of fir.array_load");
if (!validTypeParams(arrTy, getTypeparams()))
return emitOpError("invalid type parameters");
return mlir::success();
}
//===----------------------------------------------------------------------===//
// ArrayAccessOp
//===----------------------------------------------------------------------===//
llvm::LogicalResult fir::ArrayAccessOp::verify() {
auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());
std::size_t indSize = getIndices().size();
if (indSize < arrTy.getDimension())
return emitOpError("number of indices != dimension of array");
if (indSize == arrTy.getDimension() &&
getElement().getType() != fir::ReferenceType::get(arrTy.getEleTy()))
return emitOpError("return type does not match array");
mlir::Type ty = validArraySubobject(*this);
if (!ty || fir::ReferenceType::get(ty) != getType())
return emitOpError("return type and/or indices do not type check");
if (!validTypeParams(arrTy, getTypeparams()))
return emitOpError("invalid type parameters");
return mlir::success();
}
//===----------------------------------------------------------------------===//
// ArrayUpdateOp
//===----------------------------------------------------------------------===//
llvm::LogicalResult fir::ArrayUpdateOp::verify() {
if (fir::isa_ref_type(getMerge().getType()))
return emitOpError("does not support reference type for merge");
auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());
auto indSize = getIndices().size();
if (indSize < arrTy.getDimension())
return emitOpError("number of indices != dimension of array");
if (indSize == arrTy.getDimension() &&
::adjustedElementType(getMerge().getType()) != arrTy.getEleTy())
return emitOpError("merged value does not have element type");
auto ty = validArraySubobject(*this);
if (!ty || ty != ::adjustedElementType(getMerge().getType()))
return emitOpError("merged value and/or indices do not type check");
if (!validTypeParams(arrTy, getTypeparams()))
return emitOpError("invalid type parameters");
return mlir::success();
}
//===----------------------------------------------------------------------===//
// ArrayModifyOp
//===----------------------------------------------------------------------===//
llvm::LogicalResult fir::ArrayModifyOp::verify() {
auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());
auto indSize = getIndices().size();
if (indSize < arrTy.getDimension())
return emitOpError("number of indices must match array dimension");
return mlir::success();
}
//===----------------------------------------------------------------------===//
// BoxAddrOp
//===----------------------------------------------------------------------===//

View file

@ -658,27 +658,8 @@ func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n :
%arr3 = fir.insert_on_range %arr2, %c1_i32 from (2) to (9) : (!fir.array<10xi32>, i32) -> !fir.array<10xi32>
fir.call @noret1(%arr3) : (!fir.array<10xi32>) -> ()
// CHECK: [[SHAPE:%.*]] = fir.shape_shift [[INDXM:%.*]], [[INDXN:%.*]], [[INDXO:%.*]], [[INDXP:%.*]] : (index, index, index, index) -> !fir.shapeshift<2>
// CHECK: [[AV1:%.*]] = fir.array_load [[ARR1]]([[SHAPE]]) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
// CHECK: [[FVAL:%.*]] = fir.array_fetch [[AV1]], [[I10]], [[J20]] : (!fir.array<?x?xf32>, index, index) -> f32
// CHECK: [[AV2:%.*]] = fir.array_update [[AV1]], [[FVAL]], [[I10]], [[J20]] : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
// CHECK: fir.array_merge_store [[AV1]], [[AV2]] to [[ARR1]] : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
// CHECK: fir.shape_shift [[INDXM]], [[INDXN]], [[INDXO]], [[INDXP]] : (index, index, index, index) -> !fir.shapeshift<2>
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
%f = fir.array_fetch %av1, %i10, %j20 : (!fir.array<?x?xf32>, index, index) -> f32
%av2 = fir.array_update %av1, %f, %i10, %j20 : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
fir.array_merge_store %av1, %av2 to %arr1 : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
// CHECK: [[AV3:%.*]] = fir.array_load [[ARR1]]([[SHAPE]]) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
// CHECK: [[FVAL2:%.*]] = fir.array_fetch [[AV3]], [[I10]], [[J20]] : (!fir.array<?x?xf32>, index, index) -> f32
// CHECK: [[AV4:%.*]]:2 = fir.array_modify [[AV3]], [[I10]], [[J20]] : (!fir.array<?x?xf32>, index, index) -> (!fir.ref<f32>, !fir.array<?x?xf32>)
// CHECK: fir.store [[FVAL2]] to [[AV4]]#0 : !fir.ref<f32>
// CHECK: fir.array_merge_store [[AV3]], [[AV4]]#1 to [[ARR1]] : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
%av3 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
%f2 = fir.array_fetch %av3, %i10, %j20 : (!fir.array<?x?xf32>, index, index) -> f32
%addr, %av4 = fir.array_modify %av3, %i10, %j20 : (!fir.array<?x?xf32>, index, index) -> (!fir.ref<f32>, !fir.array<?x?xf32>)
fir.store %f2 to %addr : !fir.ref<f32>
fir.array_merge_store %av3, %av4 to %arr1 : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
return
}
@ -813,29 +794,6 @@ func.func @load_invariant(%arg0: !fir.ref<i32>) -> i32 {
return %0 : i32
}
func.func @array_access_ops(%a : !fir.ref<!fir.array<?x?xf32>>) {
%c1 = arith.constant 1 : index
%n = arith.constant 0 : index
%m = arith.constant 50 : index
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
%p = fir.array_access %v, %c1, %c1 : (!fir.array<?x?xf32>, index, index) -> !fir.ref<f32>
// CHECK: %{{.*}} = fir.array_access %{{.*}}, %{{.*}}, %{{.*}} : (!fir.array<?x?xf32>, index, index) -> !fir.ref<f32>
return
}
func.func @array_amend_ops(%a : !fir.ref<!fir.array<?x?xf32>>) {
%c1 = arith.constant 1 : index
%n = arith.constant 0 : index
%m = arith.constant 50 : index
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
%p = fir.array_access %v, %c1, %c1 : (!fir.array<?x?xf32>, index, index) -> !fir.ref<f32>
%res = fir.array_amend %v, %p : (!fir.array<?x?xf32>, !fir.ref<f32>) -> !fir.array<?x?xf32>
// CHECK: %{{.*}} = fir.array_amend %{{.*}}, %{{.*}} : (!fir.array<?x?xf32>, !fir.ref<f32>) -> !fir.array<?x?xf32>
return
}
func.func private @dispatch(%arg0: !fir.class<!fir.type<dispatch_derived1{a:i32,b:i32}>>, %arg1: i32) -> () {
// CHECK-LABEL: func.func private @dispatch(
// CHECK-SAME: %[[CLASS:.*]]: !fir.class<!fir.type<dispatch_derived1{a:i32,b:i32}>>, %[[INTARG:.*]]: i32)

View file

@ -214,57 +214,6 @@ func.func @array_access(%arr : !fir.ref<!fir.array<?x?xf32>>) {
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%c2 = arith.constant 2 : index
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
// expected-error@+1 {{'fir.array_load' op operand #0 must be any reference or box, but got 'index'}}
%av1 = fir.array_load %c2(%s) : (index, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<f32>, %m : index, %n : index, %o : index, %p : index) {
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
// expected-error@+1 {{'fir.array_load' op must be a reference to an array}}
%av1 = fir.array_load %arr1(%s) : (!fir.ref<f32>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%s = fir.shape_shift %m, %n: (index, index) -> !fir.shapeshift<1>
// expected-error@+1 {{'fir.array_load' op rank of dimension mismatched}}
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<1>) -> !fir.array<?x?xf32>
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%c2 = arith.constant 2 : index
%shift = fir.shift %c2 : (index) -> !fir.shift<1>
// expected-error@+1 {{'fir.array_load' op shift can only be provided with fir.box memref}}
%av1 = fir.array_load %arr1(%shift) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shift<1>) -> !fir.array<?x?xf32>
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%c47 = arith.constant 47 : index
%c78 = arith.constant 78 : index
%c3 = arith.constant 3 : index
%slice = fir.slice %c47, %c78, %c3 : (index,index,index) -> !fir.slice<1>
%s = fir.shape_shift %m, %n, %o, %p: (index, index, index, index) -> !fir.shapeshift<2>
// expected-error@+1 {{'fir.array_load' op rank of dimension in slice mismatched}}
%av1 = fir.array_load %arr1(%s)[%slice] : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>, !fir.slice<1>) -> !fir.array<?x?xf32>
return
}
// -----
func.func @test_coordinate_of(%arr : !fir.ref<!fir.array<?x?xf32>>) {
%1 = arith.constant 10 : i32
// expected-error@+1 {{'fir.coordinate_of' op cannot find coordinate with unknown extents}}
@ -647,84 +596,6 @@ func.func @bad_save_result(%buffer : !fir.ref<!fir.array<?xf32>>, %n :index) {
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
// expected-error@+1 {{'fir.array_fetch' op number of indices != dimension of array}}
%f = fir.array_fetch %av1, %m : (!fir.array<?x?xf32>, index) -> f32
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
// expected-error@+1 {{'fir.array_fetch' op return type does not match array}}
%f = fir.array_fetch %av1, %m, %n : (!fir.array<?x?xf32>, index, index) -> i32
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
%f = fir.array_fetch %av1, %m, %n : (!fir.array<?x?xf32>, index, index) -> f32
// expected-error@+1 {{'fir.array_update' op number of indices != dimension of array}}
%av2 = fir.array_update %av1, %f, %m : (!fir.array<?x?xf32>, f32, index) -> !fir.array<?x?xf32>
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
%c0 = arith.constant 0 : i32
// expected-error@+1 {{'fir.array_update' op merged value does not have element type}}
%av2 = fir.array_update %av1, %c0, %m, %n : (!fir.array<?x?xf32>, i32, index, index) -> !fir.array<?x?xf32>
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index, %f: !fir.ref<i32>) {
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
// expected-error@+1 {{'fir.array_update' op does not support reference type for merge}}
%av2 = fir.array_update %av1, %f, %m, %n : (!fir.array<?x?xf32>, !fir.ref<i32>, index, index) -> !fir.array<?x?xf32>
return
}
// -----
func.func @test_misc_ops(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index) {
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
%f = fir.array_fetch %av1, %m, %n : (!fir.array<?x?xf32>, index, index) -> f32
%av2 = fir.array_update %av1, %f, %m, %n : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
// expected-error@+1 {{'fir.array_merge_store' op operand #0 must be result of a fir.array_load op}}
fir.array_merge_store %av2, %av2 to %arr1 : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
return
}
// -----
func.func @bad_array_modify(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index, %f : f32) {
%i10 = arith.constant 10 : index
%j20 = arith.constant 20 : index
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
// expected-error@+1 {{'fir.array_modify' op number of indices must match array dimension}}
%addr, %av2 = fir.array_modify %av1, %i10 : (!fir.array<?x?xf32>, index) -> (!fir.ref<f32>, !fir.array<?x?xf32>)
fir.store %f to %addr : !fir.ref<f32>
fir.array_merge_store %av1, %av2 to %arr1 : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
return
}
// -----
func.func @slice_must_be_integral() {
%0 = arith.constant 42 : i32
%1 = fir.field_index field, !fir.type<t(param:i32){field:i32}> (%0 : i32)
@ -746,86 +617,6 @@ func.func @array_coor_no_slice_substr(%a : !fir.ref<!fir.array<?x?xf32>>) {
// -----
func.func @array_coor_no_slice_substr(%a : !fir.ref<!fir.array<?x?xf32>>) {
%c1 = arith.constant 1 : index
%c10 = arith.constant 10 : index
%slice = fir.slice %c1, %c10, %c1 substr %c1, %c10 : (index, index, index, index, index) -> !fir.slice<1>
// expected-error@+1 {{'fir.array_load' op array_load cannot take a slice with substring}}
%v = fir.array_load %a[%slice] : (!fir.ref<!fir.array<?x?xf32>>, !fir.slice<1>) -> !fir.array<?x?xf32>
return
}
// -----
func.func @array_merge_store_no_slice_substr(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m : index, %n : index, %o : index, %p : index, %f : f32) {
%i10 = arith.constant 10 : index
%j20 = arith.constant 20 : index
%c1 = arith.constant 1 : index
%c10 = arith.constant 10 : index
%s = fir.shape_shift %m, %n, %o, %p : (index, index, index, index) -> !fir.shapeshift<2>
%slice = fir.slice %c1, %c10, %c1 substr %c1, %c10 : (index, index, index, index, index) -> !fir.slice<1>
%av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
%addr, %av2 = fir.array_modify %av1, %i10, %i10 : (!fir.array<?x?xf32>, index, index) -> (!fir.ref<f32>, !fir.array<?x?xf32>)
fir.store %f to %addr : !fir.ref<f32>
// expected-error@+1 {{'fir.array_merge_store' op array_merge_store cannot take a slice with substring}}
fir.array_merge_store %av1, %av2 to %arr1[%slice] : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>, !fir.slice<1>
return
}
// -----
func.func @array_access(%a : !fir.ref<!fir.array<?x?xf32>>) {
%c1 = arith.constant 1 : index
%n = arith.constant 0 : index
%m = arith.constant 50 : index
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
// expected-error@+1 {{'fir.array_access' op number of indices != dimension of array}}
%p = fir.array_access %v, %c1 : (!fir.array<?x?xf32>, index) -> !fir.ref<f32>
return
}
// -----
func.func @array_access(%a : !fir.ref<!fir.array<?x?xf32>>) {
%c1 = arith.constant 1 : index
%n = arith.constant 0 : index
%m = arith.constant 50 : index
%s = fir.shape %n, %m : (index, index) -> !fir.shape<2>
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
// expected-error@+1 {{'fir.array_access' op return type does not match array}}
%p = fir.array_access %v, %c1, %c1 : (!fir.array<?x?xf32>, index, index) -> !fir.ref<f64>
return
}
// -----
func.func @foo(%arg0: !fir.ref<!fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>>) {
%c1 = arith.constant 1 : index
%c0 = arith.constant 0 : index
%c9 = arith.constant 9 : index
%c19 = arith.constant 19 : index
%c30 = arith.constant 30 : index
%0 = fir.shape %c30 : (index) -> !fir.shape<1>
%1 = fir.array_load %arg0(%0) : (!fir.ref<!fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>>, !fir.shape<1>) -> !fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>
%2 = fir.do_loop %arg1 = %c1 to %c9 step %c1 unordered iter_args(%arg2 = %1) -> (!fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>) {
%3 = fir.field_index c, !fir.type<t{c:!fir.array<20xi32>}>
%4 = fir.do_loop %arg3 = %c0 to %c19 step %c1 unordered iter_args(%arg4 = %arg2) -> (!fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>) {
// expected-error@+1 {{'fir.array_access' op return type and/or indices do not type check}}
%5 = fir.array_access %1, %arg1, %3, %arg3 : (!fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>, index, !fir.field, index) -> !fir.ref<f32>
%6 = fir.call @ifoo(%5) : (!fir.ref<f32>) -> i32
%7 = fir.array_update %arg4, %6, %arg1, %3, %arg3 : (!fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>, i32, index, !fir.field, index) -> !fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>
fir.result %7 : !fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>
}
fir.result %4 : !fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>
}
fir.array_merge_store %1, %2 to %arg0 : !fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>, !fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>, !fir.ref<!fir.array<30x!fir.type<t{c:!fir.array<20xi32>}>>>
return
}
func.func private @ifoo(!fir.ref<f32>) -> i32
// -----
func.func private @dispatch(%arg0: !fir.class<!fir.type<derived{a:i32,b:i32}>>) -> () {
// expected-error@+1 {{'fir.dispatch' op pass_arg_pos must be smaller than the number of operands}}
fir.dispatch "proc1"(%arg0 : !fir.class<!fir.type<derived{a:i32,b:i32}>>) (%arg0 : !fir.class<!fir.type<derived{a:i32,b:i32}>>) {pass_arg_pos = 1 : i32}

View file

@ -81,18 +81,16 @@ func.func @inline_to_loop(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "
%12 = arith.muli %10, %11 : i32
hlfir.yield_element %12 : i32
}
%array = fir.array_load %0#0 : (!fir.box<!fir.array<?xi32>>) -> !fir.array<?xi32>
%c1 = arith.constant 1 : index
%max = arith.subi %4#1, %c1 : index
%7 = fir.do_loop %arg4 = %c0 to %max step %c1 unordered iter_args(%arg5 = %array) -> (!fir.array<?xi32>) {
fir.do_loop %arg4 = %c0 to %max step %c1 unordered {
%8 = hlfir.apply %6, %arg4 : (!hlfir.expr<?xi32>, index) -> i32
%9 = hlfir.designate %3#0 (%arg4) : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
%10 = fir.load %9 : !fir.ref<i32>
%11 = arith.addi %8, %10 : i32
%12 = fir.array_update %arg5, %11, %arg4 : (!fir.array<?xi32>, i32, index) -> !fir.array<?xi32>
fir.result %12 : !fir.array<?xi32>
%12 = hlfir.designate %0#0 (%arg4) : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
fir.store %11 to %12 : !fir.ref<i32>
}
fir.array_merge_store %array, %7 to %arg0 : !fir.array<?xi32>, !fir.array<?xi32>, !fir.box<!fir.array<?xi32>>
hlfir.destroy %6 : !hlfir.expr<?xi32>
return
}
@ -108,9 +106,8 @@ func.func @inline_to_loop(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "
// CHECK-DAG: %[[C:.*]]:2 = hlfir.declare %[[C_ARG]]
// CHECK-DAG: %[[D:.*]]:2 = hlfir.declare %[[D_ARG]]
// CHECK-NEXT: %[[B_DIM0:.*]]:3 = fir.box_dims %[[B]]#0, %[[C0]]
// CHECK-NEXT: %[[ARRAY:.*]] = fir.array_load %[[A]]#0
// CHECK-NEXT: %[[MAX:.*]] = arith.subi %[[B_DIM0]]#1, %[[C1]]
// CHECK-NEXT: %[[LOOP:.*]] = fir.do_loop %[[I:.*]] = %[[C0]] to %[[MAX]] step %[[C1]] unordered iter_args(%[[LOOP_ARRAY:.*]] = %[[ARRAY]])
// CHECK-NEXT: fir.do_loop %[[I:.*]] = %[[C0]] to %[[MAX]] step %[[C1]] unordered {
// inline the elemental:
// CHECK-NEXT: %[[B_I_REF:.*]] = hlfir.designate %[[B]]#0 (%[[I]])
// CHECK-NEXT: %[[C_I_REF:.*]] = hlfir.designate %[[C]]#0 (%[[I]])
@ -121,10 +118,9 @@ func.func @inline_to_loop(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "
// CHECK-NEXT: %[[D_I_REF:.*]] = hlfir.designate %[[D]]#0 (%[[I]])
// CHECK-NEXT: %[[D_I:.*]] = fir.load %[[D_I_REF]]
// CHECK-NEXT: %[[ADD:.*]] = arith.addi %[[MUL]], %[[D_I]]
// CHECK-NEXT: %[[ARRAY_UPD:.*]] = fir.array_update %[[LOOP_ARRAY]], %[[ADD]], %[[I]]
// CHECK-NEXT: fir.result %[[ARRAY_UPD]]
// CHECK-NEXT: %[[A_I_REF:.*]] = hlfir.designate %[[A]]#0 (%[[I]])
// CHECK-NEXT: fir.store %[[ADD]] to %[[A_I_REF]]
// CHECK-NEXT: }
// CHECK-NEXT: fir.array_merge_store %[[ARRAY]], %[[LOOP]] to %[[A_ARG]]
// CHECK-NEXT: return
// CHECK-NEXT: }

View file

@ -192,9 +192,6 @@ func.func @sum1dfixed(%arg0: !fir.ref<!fir.array<?xf64>> {fir.bindc_name = "a"},
func.func @test4(%arg0: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "a"}, %arg1: !fir.box<!fir.array<?x?xf32>> {fir.bindc_name = "b"}, %arg2: !fir.ref<i32> {fir.bindc_name = "n1"}, %arg3: !fir.ref<i32> {fir.bindc_name = "m1"}) {
%0 = fir.alloca index {bindc_name = ".buff.pos"}
%1 = fir.alloca index {bindc_name = ".buff.size"}
%c0 = arith.constant 0 : index
%2:3 = fir.box_dims %arg0, %c0 : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
%3 = fir.array_load %arg0 : (!fir.box<!fir.array<?xf32>>) -> !fir.array<?xf32>
%c0_0 = arith.constant 0 : index
fir.store %c0_0 to %0 : !fir.ref<index>
%c32 = arith.constant 32 : index
@ -243,18 +240,6 @@ func.func @sum1dfixed(%arg0: !fir.ref<!fir.array<?xf64>> {fir.bindc_name = "a"},
fir.result %26 : !fir.heap<f32>
}
%13 = fir.convert %12 : (!fir.heap<f32>) -> !fir.heap<!fir.array<?xf32>>
%14 = fir.load %0 : !fir.ref<index>
%15 = fir.shape %14 : (index) -> !fir.shape<1>
%16 = fir.array_load %13(%15) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.array<?xf32>
%c1 = arith.constant 1 : index
%c0_1 = arith.constant 0 : index
%17 = arith.subi %2#1, %c1 : index
%18 = fir.do_loop %arg4 = %c0_1 to %17 step %c1 unordered iter_args(%arg5 = %3) -> (!fir.array<?xf32>) {
%19 = fir.array_fetch %16, %arg4 : (!fir.array<?xf32>, index) -> f32
%20 = fir.array_update %arg5, %19, %arg4 : (!fir.array<?xf32>, f32, index) -> !fir.array<?xf32>
fir.result %20 : !fir.array<?xf32>
}
fir.array_merge_store %3, %18 to %arg0 : !fir.array<?xf32>, !fir.array<?xf32>, !fir.box<!fir.array<?xf32>>
fir.freemem %13 : !fir.heap<!fir.array<?xf32>>
return
}

View file

@ -1220,7 +1220,6 @@ func.func @_QMtestPcount_generate_mask(%arg0: !fir.ref<!fir.array<10x10x!fir.log
%c10_1 = arith.constant 10 : index
%1 = fir.alloca !fir.array<10xi32> {bindc_name = "res", uniq_name = "_QMtestFcount_generate_maskEres"}
%2 = fir.shape %c10_1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.array<10xi32>
%c2_i32 = arith.constant 2 : i32
%4 = fir.shape %c10, %c10_0 : (index, index) -> !fir.shape<2>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10x10x!fir.logical<4>>>, !fir.shape<2>) -> !fir.box<!fir.array<10x10x!fir.logical<4>>>
@ -1242,16 +1241,9 @@ func.func @_QMtestPcount_generate_mask(%arg0: !fir.ref<!fir.array<10x10x!fir.log
%16:3 = fir.box_dims %15, %c0_2 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%17 = fir.box_addr %15 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%18 = fir.shape_shift %16#0, %16#1 : (index, index) -> !fir.shapeshift<1>
%19 = fir.array_load %17(%18) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1 = arith.constant 1 : index
%c0_3 = arith.constant 0 : index
%20 = arith.subi %c10_1, %c1 : index
%21 = fir.do_loop %arg1 = %c0_3 to %20 step %c1 unordered iter_args(%arg2 = %3) -> (!fir.array<10xi32>) {
%23 = fir.array_fetch %19, %arg1 : (!fir.array<?xi32>, index) -> i32
%24 = fir.array_update %arg2, %23, %arg1 : (!fir.array<10xi32>, i32, index) -> !fir.array<10xi32>
fir.result %24 : !fir.array<10xi32>
}
fir.array_merge_store %3, %21 to %1 : !fir.array<10xi32>, !fir.array<10xi32>, !fir.ref<!fir.array<10xi32>>
fir.freemem %17 : !fir.heap<!fir.array<?xi32>>
%22 = fir.load %1 : !fir.ref<!fir.array<10xi32>>
return %22 : !fir.array<10xi32>
@ -1405,7 +1397,6 @@ func.func @_QPtestAny_DimArg(%arg0: !fir.ref<!fir.array<10x10x!fir.logical<4>>>
%c10_1 = arith.constant 10 : index
%1 = fir.alloca !fir.array<10x!fir.logical<4>> {bindc_name = "testAny_DimArg", uniq_name = "_QFtestAny_DimArgEtestAny_DimArg"}
%2 = fir.shape %c10_1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<10x!fir.logical<4>>>, !fir.shape<1>) -> !fir.array<10x!fir.logical<4>>
%c2_i32 = arith.constant 2 : i32
%4 = fir.shape %c10, %c10_0 : (index, index) -> !fir.shape<2>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10x10x!fir.logical<4>>>, !fir.shape<2>) -> !fir.box<!fir.array<10x10x!fir.logical<4>>>
@ -1425,16 +1416,9 @@ func.func @_QPtestAny_DimArg(%arg0: !fir.ref<!fir.array<10x10x!fir.logical<4>>>
%15:3 = fir.box_dims %14, %c0_2 : (!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>, index) -> (index, index, index)
%16 = fir.box_addr %14 : (!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>) -> !fir.heap<!fir.array<?x!fir.logical<4>>>
%17 = fir.shape_shift %15#0, %15#1 : (index, index) -> !fir.shapeshift<1>
%18 = fir.array_load %16(%17) : (!fir.heap<!fir.array<?x!fir.logical<4>>>, !fir.shapeshift<1>) -> !fir.array<?x!fir.logical<4>>
%c1 = arith.constant 1 : index
%c0_3 = arith.constant 0 : index
%19 = arith.subi %c10_1, %c1 : index
%20 = fir.do_loop %arg1 = %c0_3 to %19 step %c1 unordered iter_args(%arg2 = %3) -> (!fir.array<10x!fir.logical<4>>) {
%22 = fir.array_fetch %18, %arg1 : (!fir.array<?x!fir.logical<4>>, index) -> !fir.logical<4>
%23 = fir.array_update %arg2, %22, %arg1 : (!fir.array<10x!fir.logical<4>>, !fir.logical<4>, index) -> !fir.array<10x!fir.logical<4>>
fir.result %23 : !fir.array<10x!fir.logical<4>>
}
fir.array_merge_store %3, %20 to %1 : !fir.array<10x!fir.logical<4>>, !fir.array<10x!fir.logical<4>>, !fir.ref<!fir.array<10x!fir.logical<4>>>
fir.freemem %16 : !fir.heap<!fir.array<?x!fir.logical<4>>>
%21 = fir.load %1 : !fir.ref<!fir.array<10x!fir.logical<4>>>
return %21 : !fir.array<10x!fir.logical<4>>
@ -1644,7 +1628,6 @@ func.func @_QPtestAll_DimArg(%arg0: !fir.ref<!fir.array<10x10x!fir.logical<4>>>
%c10_1 = arith.constant 10 : index
%1 = fir.alloca !fir.array<10x!fir.logical<4>> {bindc_name = "testAll_DimArg", uniq_name = "_QFtestAll_DimArgEtestAll_DimArg"}
%2 = fir.shape %c10_1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<10x!fir.logical<4>>>, !fir.shape<1>) -> !fir.array<10x!fir.logical<4>>
%c1_i32 = arith.constant 1 : i32
%4 = fir.shape %c10, %c10_0 : (index, index) -> !fir.shape<2>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10x10x!fir.logical<4>>>, !fir.shape<2>) -> !fir.box<!fir.array<10x10x!fir.logical<4>>>
@ -1664,16 +1647,9 @@ func.func @_QPtestAll_DimArg(%arg0: !fir.ref<!fir.array<10x10x!fir.logical<4>>>
%15:3 = fir.box_dims %14, %c0_2 : (!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>, index) -> (index, index, index)
%16 = fir.box_addr %14 : (!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>) -> !fir.heap<!fir.array<?x!fir.logical<4>>>
%17 = fir.shape_shift %15#0, %15#1 : (index, index) -> !fir.shapeshift<1>
%18 = fir.array_load %16(%17) : (!fir.heap<!fir.array<?x!fir.logical<4>>>, !fir.shapeshift<1>) -> !fir.array<?x!fir.logical<4>>
%c1 = arith.constant 1 : index
%c0_3 = arith.constant 0 : index
%19 = arith.subi %c10_1, %c1 : index
%20 = fir.do_loop %arg1 = %c0_3 to %19 step %c1 unordered iter_args(%arg2 = %3) -> (!fir.array<10x!fir.logical<4>>) {
%22 = fir.array_fetch %18, %arg1 : (!fir.array<?x!fir.logical<4>>, index) -> !fir.logical<4>
%23 = fir.array_update %arg2, %22, %arg1 : (!fir.array<10x!fir.logical<4>>, !fir.logical<4>, index) -> !fir.array<10x!fir.logical<4>>
fir.result %23 : !fir.array<10x!fir.logical<4>>
}
fir.array_merge_store %3, %20 to %1 : !fir.array<10x!fir.logical<4>>, !fir.array<10x!fir.logical<4>>, !fir.ref<!fir.array<10x!fir.logical<4>>>
fir.freemem %16 : !fir.heap<!fir.array<?x!fir.logical<4>>>
%21 = fir.load %1 : !fir.ref<!fir.array<10x!fir.logical<4>>>
return %21 : !fir.array<10x!fir.logical<4>>
@ -1695,7 +1671,6 @@ func.func @_QPtestminloc_works1d(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_
%c1 = arith.constant 1 : index
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testminloc_works1d", uniq_name = "_QFtestminloc_works1dEtestminloc_works1d"}
%2 = fir.shape %c1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%4 = fir.shape %c10 : (index) -> !fir.shape<1>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
%6 = fir.shape %c10_0 : (index) -> !fir.shape<1>
@ -1720,16 +1695,9 @@ func.func @_QPtestminloc_works1d(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_
%19:3 = fir.box_dims %18, %c0_1 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%20 = fir.box_addr %18 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%21 = fir.shape_shift %19#0, %19#1 : (index, index) -> !fir.shapeshift<1>
%22 = fir.array_load %20(%21) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1_2 = arith.constant 1 : index
%c0_3 = arith.constant 0 : index
%23 = arith.subi %c1, %c1_2 : index
%24 = fir.do_loop %arg2 = %c0_3 to %23 step %c1_2 unordered iter_args(%arg3 = %3) -> (!fir.array<1xi32>) {
%26 = fir.array_fetch %22, %arg2 : (!fir.array<?xi32>, index) -> i32
%27 = fir.array_update %arg3, %26, %arg2 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %27 : !fir.array<1xi32>
}
fir.array_merge_store %3, %24 to %1 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
fir.freemem %20 : !fir.heap<!fir.array<?xi32>>
%25 = fir.load %1 : !fir.ref<!fir.array<1xi32>>
return %25 : !fir.array<1xi32>
@ -1820,7 +1788,6 @@ func.func @_QPtestminloc_works2d_nomask(%arg0: !fir.ref<!fir.array<10x10xi32>> {
%c2 = arith.constant 2 : index
%1 = fir.alloca !fir.array<2xi32> {bindc_name = "testminloc_works2d_nomask", uniq_name = "_QFtestminloc_works2d_nomaskEtestminloc_works2d_nomask"}
%2 = fir.shape %c2 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<2xi32>>, !fir.shape<1>) -> !fir.array<2xi32>
%4 = fir.shape %c10, %c10_0 : (index, index) -> !fir.shape<2>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10x10xi32>>, !fir.shape<2>) -> !fir.box<!fir.array<10x10xi32>>
%c8_i32 = arith.constant 8 : i32
@ -1843,17 +1810,9 @@ func.func @_QPtestminloc_works2d_nomask(%arg0: !fir.ref<!fir.array<10x10xi32>> {
%17:3 = fir.box_dims %16, %c0_1 : (!fir.box<!fir.heap<!fir.array<?xi64>>>, index) -> (index, index, index)
%18 = fir.box_addr %16 : (!fir.box<!fir.heap<!fir.array<?xi64>>>) -> !fir.heap<!fir.array<?xi64>>
%19 = fir.shape_shift %17#0, %17#1 : (index, index) -> !fir.shapeshift<1>
%20 = fir.array_load %18(%19) : (!fir.heap<!fir.array<?xi64>>, !fir.shapeshift<1>) -> !fir.array<?xi64>
%c1 = arith.constant 1 : index
%c0_2 = arith.constant 0 : index
%21 = arith.subi %c2, %c1 : index
%22 = fir.do_loop %arg1 = %c0_2 to %21 step %c1 unordered iter_args(%arg2 = %3) -> (!fir.array<2xi32>) {
%24 = fir.array_fetch %20, %arg1 : (!fir.array<?xi64>, index) -> i64
%25 = fir.convert %24 : (i64) -> i32
%26 = fir.array_update %arg2, %25, %arg1 : (!fir.array<2xi32>, i32, index) -> !fir.array<2xi32>
fir.result %26 : !fir.array<2xi32>
}
fir.array_merge_store %3, %22 to %1 : !fir.array<2xi32>, !fir.array<2xi32>, !fir.ref<!fir.array<2xi32>>
fir.freemem %18 : !fir.heap<!fir.array<?xi64>>
%23 = fir.load %1 : !fir.ref<!fir.array<2xi32>>
return %23 : !fir.array<2xi32>
@ -1939,7 +1898,6 @@ func.func @_QPtestminloc_works1d_scalarmask_f64(%arg0: !fir.ref<!fir.array<10xf6
%c1 = arith.constant 1 : index
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testminloc_works1d_scalarmask_f64", uniq_name = "_QFtestminloc_works1d_scalarmask_f64Etestminloc_works1d_scalarmask_f64"}
%2 = fir.shape %c1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%4 = fir.shape %c10 : (index) -> !fir.shape<1>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10xf64>>, !fir.shape<1>) -> !fir.box<!fir.array<10xf64>>
%6 = fir.embox %arg1 : (!fir.ref<!fir.logical<4>>) -> !fir.box<!fir.logical<4>>
@ -1963,16 +1921,9 @@ func.func @_QPtestminloc_works1d_scalarmask_f64(%arg0: !fir.ref<!fir.array<10xf6
%18:3 = fir.box_dims %17, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%19 = fir.box_addr %17 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%20 = fir.shape_shift %18#0, %18#1 : (index, index) -> !fir.shapeshift<1>
%21 = fir.array_load %19(%20) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1_1 = arith.constant 1 : index
%c0_2 = arith.constant 0 : index
%22 = arith.subi %c1, %c1_1 : index
%23 = fir.do_loop %arg2 = %c0_2 to %22 step %c1_1 unordered iter_args(%arg3 = %3) -> (!fir.array<1xi32>) {
%25 = fir.array_fetch %21, %arg2 : (!fir.array<?xi32>, index) -> i32
%26 = fir.array_update %arg3, %25, %arg2 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %26 : !fir.array<1xi32>
}
fir.array_merge_store %3, %23 to %1 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
fir.freemem %19 : !fir.heap<!fir.array<?xi32>>
%24 = fir.load %1 : !fir.ref<!fir.array<1xi32>>
return %24 : !fir.array<1xi32>
@ -2051,7 +2002,6 @@ func.func @_QPtestminloc_doesntwork1d_back(%arg0: !fir.ref<!fir.array<10xi32>> {
%c1 = arith.constant 1 : index
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testminloc_doesntwork1d_back", uniq_name = "_QFtestminloc_doesntwork1d_backEtestminloc_doesntwork1d_back"}
%2 = fir.shape %c1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%4 = fir.shape %c10 : (index) -> !fir.shape<1>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
%true = arith.constant true
@ -2075,16 +2025,9 @@ func.func @_QPtestminloc_doesntwork1d_back(%arg0: !fir.ref<!fir.array<10xi32>> {
%18:3 = fir.box_dims %17, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%19 = fir.box_addr %17 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%20 = fir.shape_shift %18#0, %18#1 : (index, index) -> !fir.shapeshift<1>
%21 = fir.array_load %19(%20) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1_1 = arith.constant 1 : index
%c0_2 = arith.constant 0 : index
%22 = arith.subi %c1, %c1_1 : index
%23 = fir.do_loop %arg1 = %c0_2 to %22 step %c1_1 unordered iter_args(%arg2 = %3) -> (!fir.array<1xi32>) {
%25 = fir.array_fetch %21, %arg1 : (!fir.array<?xi32>, index) -> i32
%26 = fir.array_update %arg2, %25, %arg1 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %26 : !fir.array<1xi32>
}
fir.array_merge_store %3, %23 to %1 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
fir.freemem %19 : !fir.heap<!fir.array<?xi32>>
%24 = fir.load %1 : !fir.ref<!fir.array<1xi32>>
return %24 : !fir.array<1xi32>
@ -2105,7 +2048,6 @@ func.func @_QPtestminloc_1d_dim(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_n
%c1 = arith.constant 1 : index
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testminloc_1d_dim", uniq_name = "_QFtestminloc_1d_dimEtestminloc_1d_dim"}
%2 = fir.shape %c1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%4 = fir.shape %c10 : (index) -> !fir.shape<1>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
%c1_i32 = arith.constant 1 : i32
@ -2130,11 +2072,6 @@ func.func @_QPtestminloc_1d_dim(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_n
%c1_0 = arith.constant 1 : index
%c0 = arith.constant 0 : index
%19 = arith.subi %c1, %c1_0 : index
%20 = fir.do_loop %arg1 = %c0 to %19 step %c1_0 unordered iter_args(%arg2 = %3) -> (!fir.array<1xi32>) {
%22 = fir.array_update %arg2, %18, %arg1 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %22 : !fir.array<1xi32>
}
fir.array_merge_store %3, %20 to %1 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
%21 = fir.load %1 : !fir.ref<!fir.array<1xi32>>
return %21 : !fir.array<1xi32>
}
@ -2203,7 +2140,6 @@ func.func @_QPtestminloc_doesntwork1d_unknownsize(%arg0: !fir.box<!fir.array<?xi
%c1 = arith.constant 1 : index
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testminloc_doesntwork1d_unknownsize", uniq_name = "_QFtestminloc_doesntwork1d_unknownsizeEtestminloc_doesntwork1d_unknownsize"}
%2 = fir.shape %c1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%4 = fir.absent !fir.box<i1>
%c4 = arith.constant 4 : index
%false = arith.constant false
@ -2225,16 +2161,9 @@ func.func @_QPtestminloc_doesntwork1d_unknownsize(%arg0: !fir.box<!fir.array<?xi
%16:3 = fir.box_dims %15, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%17 = fir.box_addr %15 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%18 = fir.shape_shift %16#0, %16#1 : (index, index) -> !fir.shapeshift<1>
%19 = fir.array_load %17(%18) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1_1 = arith.constant 1 : index
%c0_2 = arith.constant 0 : index
%20 = arith.subi %c1, %c1_1 : index
%21 = fir.do_loop %arg1 = %c0_2 to %20 step %c1_1 unordered iter_args(%arg2 = %3) -> (!fir.array<1xi32>) {
%23 = fir.array_fetch %19, %arg1 : (!fir.array<?xi32>, index) -> i32
%24 = fir.array_update %arg2, %23, %arg1 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %24 : !fir.array<1xi32>
}
fir.array_merge_store %3, %21 to %1 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
fir.freemem %17 : !fir.heap<!fir.array<?xi32>>
%22 = fir.load %1 : !fir.ref<!fir.array<1xi32>>
return %22 : !fir.array<1xi32>
@ -2256,7 +2185,6 @@ func.func @_QPtestminloc_doesntwork1d_chars(%arg0: !fir.boxchar<1> {fir.bindc_na
%c1 = arith.constant 1 : index
%3 = fir.alloca !fir.array<1xi32> {bindc_name = "testminloc_doesntwork1d_chars", uniq_name = "_QFtestminloc_doesntwork1d_charsEtestminloc_doesntwork1d_chars"}
%4 = fir.shape %c1 : (index) -> !fir.shape<1>
%5 = fir.array_load %3(%4) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%6 = fir.shape %c10 : (index) -> !fir.shape<1>
%7 = fir.embox %2(%6) : (!fir.ref<!fir.array<10x!fir.char<1>>>, !fir.shape<1>) -> !fir.box<!fir.array<10x!fir.char<1>>>
%8 = fir.absent !fir.box<i1>
@ -2280,16 +2208,9 @@ func.func @_QPtestminloc_doesntwork1d_chars(%arg0: !fir.boxchar<1> {fir.bindc_na
%20:3 = fir.box_dims %19, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%21 = fir.box_addr %19 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%22 = fir.shape_shift %20#0, %20#1 : (index, index) -> !fir.shapeshift<1>
%23 = fir.array_load %21(%22) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1_1 = arith.constant 1 : index
%c0_2 = arith.constant 0 : index
%24 = arith.subi %c1, %c1_1 : index
%25 = fir.do_loop %arg1 = %c0_2 to %24 step %c1_1 unordered iter_args(%arg2 = %5) -> (!fir.array<1xi32>) {
%27 = fir.array_fetch %23, %arg1 : (!fir.array<?xi32>, index) -> i32
%28 = fir.array_update %arg2, %27, %arg1 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %28 : !fir.array<1xi32>
}
fir.array_merge_store %5, %25 to %3 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
fir.freemem %21 : !fir.heap<!fir.array<?xi32>>
%26 = fir.load %3 : !fir.ref<!fir.array<1xi32>>
return %26 : !fir.array<1xi32>
@ -2327,7 +2248,6 @@ func.func @_QPtestminloc_doesntwork1d_unknownmask(%arg0: !fir.ref<!fir.array<10x
%c1_0 = arith.constant 1 : index
fir.store %c1_0 to %4 : !fir.ref<index>
%13 = fir.shape %c1 : (index) -> !fir.shape<1>
%14 = fir.array_load %7(%13) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%15 = fir.shape %c10 : (index) -> !fir.shape<1>
%16 = fir.embox %arg0(%15) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
%17 = fir.load %3 : !fir.ref<!fir.heap<!fir.array<?x!fir.logical<4>>>>
@ -2361,16 +2281,9 @@ func.func @_QPtestminloc_doesntwork1d_unknownmask(%arg0: !fir.ref<!fir.array<10x
%38:3 = fir.box_dims %37, %c0_2 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%39 = fir.box_addr %37 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%40 = fir.shape_shift %38#0, %38#1 : (index, index) -> !fir.shapeshift<1>
%41 = fir.array_load %39(%40) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1_3 = arith.constant 1 : index
%c0_4 = arith.constant 0 : index
%42 = arith.subi %c1, %c1_3 : index
%43 = fir.do_loop %arg1 = %c0_4 to %42 step %c1_3 unordered iter_args(%arg2 = %14) -> (!fir.array<1xi32>) {
%45 = fir.array_fetch %41, %arg1 : (!fir.array<?xi32>, index) -> i32
%46 = fir.array_update %arg2, %45, %arg1 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %46 : !fir.array<1xi32>
}
fir.array_merge_store %14, %43 to %7 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
fir.freemem %39 : !fir.heap<!fir.array<?xi32>>
%44 = fir.load %7 : !fir.ref<!fir.array<1xi32>>
return %44 : !fir.array<1xi32>
@ -2391,7 +2304,6 @@ func.func @_QPtestmaxloc_works1d(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_
%c1 = arith.constant 1 : index
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testmaxloc_works1d", uniq_name = "_QFtestmaxloc_works1dEtestmaxloc_works1d"}
%2 = fir.shape %c1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%4 = fir.shape %c10 : (index) -> !fir.shape<1>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
%6 = fir.shape %c10_0 : (index) -> !fir.shape<1>
@ -2416,16 +2328,9 @@ func.func @_QPtestmaxloc_works1d(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_
%19:3 = fir.box_dims %18, %c0_1 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%20 = fir.box_addr %18 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%21 = fir.shape_shift %19#0, %19#1 : (index, index) -> !fir.shapeshift<1>
%22 = fir.array_load %20(%21) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1_2 = arith.constant 1 : index
%c0_3 = arith.constant 0 : index
%23 = arith.subi %c1, %c1_2 : index
%24 = fir.do_loop %arg2 = %c0_3 to %23 step %c1_2 unordered iter_args(%arg3 = %3) -> (!fir.array<1xi32>) {
%26 = fir.array_fetch %22, %arg2 : (!fir.array<?xi32>, index) -> i32
%27 = fir.array_update %arg3, %26, %arg2 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %27 : !fir.array<1xi32>
}
fir.array_merge_store %3, %24 to %1 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
fir.freemem %20 : !fir.heap<!fir.array<?xi32>>
%25 = fir.load %1 : !fir.ref<!fir.array<1xi32>>
return %25 : !fir.array<1xi32>
@ -2515,7 +2420,6 @@ func.func @_QPtestmaxloc_works1d_scalarmask_f64(%arg0: !fir.ref<!fir.array<10xf6
%c1 = arith.constant 1 : index
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testmaxloc_works1d_scalarmask_f64", uniq_name = "_QFtestmaxloc_works1d_scalarmask_f64Etestminloc_works1d_scalarmask_f64"}
%2 = fir.shape %c1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%4 = fir.shape %c10 : (index) -> !fir.shape<1>
%5 = fir.embox %arg0(%4) : (!fir.ref<!fir.array<10xf64>>, !fir.shape<1>) -> !fir.box<!fir.array<10xf64>>
%6 = fir.embox %arg1 : (!fir.ref<!fir.logical<4>>) -> !fir.box<!fir.logical<4>>
@ -2539,16 +2443,9 @@ func.func @_QPtestmaxloc_works1d_scalarmask_f64(%arg0: !fir.ref<!fir.array<10xf6
%18:3 = fir.box_dims %17, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
%19 = fir.box_addr %17 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
%20 = fir.shape_shift %18#0, %18#1 : (index, index) -> !fir.shapeshift<1>
%21 = fir.array_load %19(%20) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.array<?xi32>
%c1_1 = arith.constant 1 : index
%c0_2 = arith.constant 0 : index
%22 = arith.subi %c1, %c1_1 : index
%23 = fir.do_loop %arg2 = %c0_2 to %22 step %c1_1 unordered iter_args(%arg3 = %3) -> (!fir.array<1xi32>) {
%25 = fir.array_fetch %21, %arg2 : (!fir.array<?xi32>, index) -> i32
%26 = fir.array_update %arg3, %25, %arg2 : (!fir.array<1xi32>, i32, index) -> !fir.array<1xi32>
fir.result %26 : !fir.array<1xi32>
}
fir.array_merge_store %3, %23 to %1 : !fir.array<1xi32>, !fir.array<1xi32>, !fir.ref<!fir.array<1xi32>>
fir.freemem %19 : !fir.heap<!fir.array<?xi32>>
%24 = fir.load %1 : !fir.ref<!fir.array<1xi32>>
return %24 : !fir.array<1xi32>