[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:
parent
4dc60bbb98
commit
95ee221ea8
12 changed files with 28 additions and 1343 deletions
|
|
@ -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
|
||||
}
|
||||
```
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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: }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue