xref: /llvm-project/flang/test/Fir/arrexp.fir (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1// RUN: tco %s | FileCheck %s
2
3// CHECK-LINE: define void @f1
4// CHECK: (ptr captures(none) %[[A:[^,]*]], {{.*}}, float %[[F:.*]])
5func.func @f1(%a : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : index, %p : index, %f : f32) {
6  %c1 = arith.constant 1 : index
7  %s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
8  %vIn = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
9  // CHECK: = icmp sgt
10  %r = fir.do_loop %j = %p to %m step %c1 iter_args(%v1 = %vIn) -> !fir.array<?x?xf32> {
11    // CHECK: = icmp sgt
12    %r = fir.do_loop %i = %o to %n step %c1 iter_args(%v = %v1) -> !fir.array<?x?xf32> {
13      // CHECK: %[[AOFF:.*]] = getelementptr float, ptr %[[A]], i64
14      // CHECK: store float %[[F]], ptr %[[AOFF]]
15      %r = fir.array_update %v, %f, %i, %j : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
16      fir.result %r : !fir.array<?x?xf32>
17    }
18    fir.result %r : !fir.array<?x?xf32>
19  }
20  fir.array_merge_store %vIn, %r to %a : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
21  // CHECK: ret void
22  return
23}
24
25// CHECK-LINE: define void @f2
26// CHECK: (ptr captures(none) %[[A:[^,]*]], {{.*}}, float %[[F:.*]])
27func.func @f2(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : index, %p : index, %f : f32) {
28  %c1 = arith.constant 1 : index
29  %s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
30  %vIn = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
31  %wIn = fir.array_load %b(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
32  // CHECK: = icmp sgt
33  %r = fir.do_loop %j = %p to %m step %c1 iter_args(%v1 = %vIn) -> !fir.array<?x?xf32> {
34    // CHECK: = icmp sgt
35    %r = fir.do_loop %i = %o to %n step %c1 iter_args(%v = %v1) -> !fir.array<?x?xf32> {
36      %x = fir.array_fetch %wIn, %i, %j : (!fir.array<?x?xf32>, index, index) -> f32
37      %y = arith.addf %x, %f : f32
38      // CHECK: %[[AOFF:.*]] = getelementptr float, ptr %[[A]], i64
39      %r = fir.array_update %v, %y, %i, %j : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
40      fir.result %r : !fir.array<?x?xf32>
41    }
42    fir.result %r : !fir.array<?x?xf32>
43  }
44  fir.array_merge_store %vIn, %r to %a : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
45  // CHECK: ret void
46  return
47}
48
49// CHECK-LINE: define void @f3
50// CHECK: (ptr captures(none) %[[A:[^,]*]], {{.*}}, float %[[F:.*]])
51func.func @f3(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : index, %p : index, %f : f32) {
52  %c1 = arith.constant 1 : index
53  %s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
54  %vIn = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
55  %wIn = fir.array_load %b(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
56  // CHECK: = icmp sgt
57  %r = fir.do_loop %j = %p to %m step %c1 iter_args(%v1 = %vIn) -> !fir.array<?x?xf32> {
58    // CHECK: = icmp sgt
59    %r = fir.do_loop %i = %o to %n step %c1 iter_args(%v = %v1) -> !fir.array<?x?xf32> {
60      %x = fir.array_fetch %wIn, %i, %j : (!fir.array<?x?xf32>, index, index) -> f32
61      %y = arith.addf %x, %f : f32
62      // CHECK: %[[AOFF:.*]] = getelementptr float, ptr %[[A]], i64
63      %i2 = arith.addi %i, %c1 : index
64      %r = fir.array_update %v, %y, %i2, %j : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
65      fir.result %r : !fir.array<?x?xf32>
66    }
67    fir.result %r : !fir.array<?x?xf32>
68  }
69  fir.array_merge_store %vIn, %r to %a : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
70  // CHECK: ret void
71  return
72}
73
74// CHECK-LINE: define void @f4
75// CHECK: (ptr captures(none) %[[A:[^,]*]], {{.*}}, float %[[F:.*]])
76func.func @f4(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : index, %p : index, %f : f32) {
77  %c1 = arith.constant 1 : index
78  %s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
79  %vIn = fir.array_load %a(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
80  %wIn = fir.array_load %b(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shapeshift<2>) -> !fir.array<?x?xf32>
81  // CHECK: = icmp sgt
82  %r = fir.do_loop %j = %p to %m step %c1 iter_args(%v1 = %vIn) -> !fir.array<?x?xf32> {
83    // CHECK: = icmp sgt
84    %r = fir.do_loop %i = %o to %n step %c1 iter_args(%v = %v1) -> !fir.array<?x?xf32> {
85      %x2 = fir.array_fetch %vIn, %i, %j : (!fir.array<?x?xf32>, index, index) -> f32
86      %x = fir.array_fetch %wIn, %i, %j : (!fir.array<?x?xf32>, index, index) -> f32
87      %y = arith.addf %x, %f : f32
88      %y2 = arith.addf %y, %x2 : f32
89      // CHECK: %[[AOFF:.*]] = getelementptr float, ptr %[[A]], i64
90      %i2 = arith.addi %i, %c1 : index
91      %r = fir.array_update %v, %y2, %i2, %j : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
92      fir.result %r : !fir.array<?x?xf32>
93    }
94    fir.result %r : !fir.array<?x?xf32>
95  }
96  fir.array_merge_store %vIn, %r to %a : !fir.array<?x?xf32>, !fir.array<?x?xf32>, !fir.ref<!fir.array<?x?xf32>>
97  // CHECK: ret void
98  return
99}
100
101// Array expression assignment with potentially non contiguous arrays (e.g.
102// `a = b + f`, with and v assumed shapes.
103// Tests that the stride from the descriptor is used.
104// CHECK-LINE: define void @f5
105// CHECK: (ptr %[[A:.*]], ptr %[[B:.*]], float %[[F:.*]])
106func.func @f5(%arg0: !fir.box<!fir.array<?xf32>>, %arg1: !fir.box<!fir.array<?xf32>>, %arg2: f32) {
107  %c0 = arith.constant 0 : index
108  %c1 = arith.constant 1 : index
109  %0:3 = fir.box_dims %arg0, %c0 : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
110  %1 = arith.subi %0#1, %c1 : index
111  %2 = fir.array_load %arg0 : (!fir.box<!fir.array<?xf32>>) -> !fir.array<?xf32>
112  %3 = fir.array_load %arg1 : (!fir.box<!fir.array<?xf32>>) -> !fir.array<?xf32>
113  // CHECK: icmp sgt
114  %4 = fir.do_loop %arg3 = %c0 to %1 step %c1 iter_args(%arg4 = %2) -> (!fir.array<?xf32>) {
115    // CHECK: %[[B_STRIDE_GEP:.*]] = getelementptr {{.*}}, ptr %[[B]], i32 0, i32 7, i32 0, i32 2
116    // CHECK: %[[B_STRIDE:.*]] = load i64, ptr %[[B_STRIDE_GEP]]
117    // CHECK: %[[B_DIM_OFFSET:.*]] = mul nsw i64 %{{.*}}, %[[B_STRIDE]]
118    // CHECK: %[[B_OFFSET:.*]] =  add nsw i64 %[[B_DIM_OFFSET]], 0
119    // CHECK: %[[B_BASE_GEP:.*]] = getelementptr {{.*}}, ptr %{{.*}}, i32 0, i32 0
120    // CHECK: %[[B_BASE:.*]] = load ptr, ptr %[[B_BASE_GEP]]
121    // CHECK: %[[B_VOID_ADDR:.*]] = getelementptr i8, ptr %[[B_BASE]], i64 %[[B_OFFSET]]
122    // CHECK: %[[B_VAL:.*]] = load float, ptr %[[B_VOID_ADDR]]
123    // CHECK: fadd float %[[B_VAL]], %[[F]]
124    %5 = fir.array_fetch %3, %arg3 : (!fir.array<?xf32>, index) -> f32
125    %6 = arith.addf %5, %arg2 : f32
126    %7 = fir.array_update %arg4, %6, %arg3 : (!fir.array<?xf32>, f32, index) -> !fir.array<?xf32>
127    fir.result %7 : !fir.array<?xf32>
128  }
129  fir.array_merge_store %2, %4 to %arg0 : !fir.array<?xf32>, !fir.array<?xf32>, !fir.box<!fir.array<?xf32>>
130  // CHECK: ret void
131  return
132}
133
134// Overlapping array expression assignment with a potentially non
135// contiguous array (e.g. `a(2:10:1) = a(1:9:1) + f`, with a assumed shape).
136// Test that a temp is created.
137// CHECK-LINE: define void @f6
138// CHECK: (ptr %[[A:[^,]*]], float %[[F:.*]])
139func.func @f6(%arg0: !fir.box<!fir.array<?xf32>>, %arg1: f32) {
140  %c0 = arith.constant 0 : index
141  %c1 = arith.constant 1 : index
142  %c2 = arith.constant 2 : index
143  %c9 = arith.constant 9 : index
144  %c10 = arith.constant 10 : index
145
146  // CHECK: %[[EXT_GEP:.*]] = getelementptr {{.*}} %[[A]], i32 0, i32 7, i64 0, i32 1
147  // CHECK: %[[EXTENT:.*]] = load i64, ptr %[[EXT_GEP]]
148  // CHECK: %[[SIZE:.*]] = mul i64 ptrtoint (ptr getelementptr (float, ptr null, i32 1) to i64), %[[EXTENT]]
149  // CHECK: %[[MALLOC:.*]] = call ptr @malloc(i64 %[[SIZE]])
150  %1 = fir.slice %c2, %c10, %c1 : (index, index, index) -> !fir.slice<1>
151  %2 = fir.array_load %arg0 [%1] : (!fir.box<!fir.array<?xf32>>, !fir.slice<1>) -> !fir.array<?xf32>
152  %3 = fir.slice %c1, %c9, %c1 : (index, index, index) -> !fir.slice<1>
153  %4 = fir.array_load %arg0 [%3] : (!fir.box<!fir.array<?xf32>>, !fir.slice<1>) -> !fir.array<?xf32>
154  %5 = fir.do_loop %arg2 = %c0 to %c9 step %c1 iter_args(%arg3 = %2) -> (!fir.array<?xf32>) {
155    %6 = fir.array_fetch %4, %arg2 : (!fir.array<?xf32>, index) -> f32
156    %7 = arith.addf %6, %arg1 : f32
157    %8 = fir.array_update %arg3, %7, %arg2 : (!fir.array<?xf32>, f32, index) -> !fir.array<?xf32>
158    fir.result %8 : !fir.array<?xf32>
159  }
160  fir.array_merge_store %2, %5 to %arg0[%1] : !fir.array<?xf32>, !fir.array<?xf32>, !fir.box<!fir.array<?xf32>>, !fir.slice<1>
161  // CHECK: ret void
162  return
163}
164
165// Non contiguous array with lower bounds (x = y(100), with y(4:))
166// Test array_coor offset computation.
167// CHECK-LABEL:  define void @f7(
168// CHECK: ptr captures(none) %[[X:[^,]*]], ptr %[[Y:.*]])
169func.func @f7(%arg0: !fir.ref<f32>, %arg1: !fir.box<!fir.array<?xf32>>) {
170  %c4 = arith.constant 4 : index
171  %c100 = arith.constant 100 : index
172  %0 = fir.shift %c4 : (index) -> !fir.shift<1>
173  // CHECK: %[[STRIDE_GEP:.*]] = getelementptr {{.*}}, ptr %[[Y]], i32 0, i32 7, i32 0, i32 2
174  // CHECK: %[[STRIDE:.*]] = load i64, ptr %[[STRIDE_GEP]]
175  // CHECK: mul nsw i64 96, %[[STRIDE]]
176  %1 = fir.array_coor %arg1(%0) %c100 : (!fir.box<!fir.array<?xf32>>, !fir.shift<1>, index) -> !fir.ref<f32>
177  %2 = fir.load %1 : !fir.ref<f32>
178  fir.store %2 to %arg0 : !fir.ref<f32>
179  return
180}
181
182// Test A(:, :)%x reference codegen with A constant shape.
183// CHECK-LABEL:  define void @f8(
184// CHECK-SAME: ptr captures(none) %[[A:.*]], i32 %[[I:.*]])
185func.func @f8(%a : !fir.ref<!fir.array<2x2x!fir.type<t{i:i32}>>>, %i : i32) {
186  %c0 = arith.constant 0 : index
187  %c1 = arith.constant 1 : index
188  %c2 = arith.constant 2 : index
189  %1 = fir.field_index i, !fir.type<t{i:i32}>
190  %2 = fir.shape %c2, %c2 : (index, index) -> !fir.shape<2>
191  %3 = fir.slice %c1, %c2, %c1, %c1, %c2, %c1 path %1 : (index, index, index, index, index, index, !fir.field) -> !fir.slice<2>
192  // CHECK: %[[GEP:.*]] = getelementptr %t, ptr %[[A]], i64 0, i32 0
193  %4 = fir.array_coor %a(%2) [%3] %c1, %c1 : (!fir.ref<!fir.array<2x2x!fir.type<t{i:i32}>>>, !fir.shape<2>, !fir.slice<2>, index, index) -> !fir.ref<i32>
194  // CHECK: store i32 %[[I]], ptr %[[GEP]], align 4
195  fir.store %i to %4 : !fir.ref<i32>
196  return
197}
198
199// Test casts in in array_coor offset computation when type parameters are not i64
200// CHECK-LABEL: define ptr @f9(
201// CHECK-SAME: i32 %[[I:.*]], i64 %{{.*}}, i64 %{{.*}}, ptr captures(none) %[[C:.*]])
202func.func @f9(%i: i32, %e : i64, %j: i64, %c: !fir.ref<!fir.array<?x?x!fir.char<1,?>>>) -> !fir.ref<!fir.char<1,?>> {
203  %s = fir.shape %e, %e : (i64, i64) -> !fir.shape<2>
204  // CHECK: %[[CAST:.*]] = sext i32 %[[I]] to i64
205  // CHECK: %[[OFFSET:.*]] = mul nsw i64 %{{.*}}, %[[CAST]]
206  // CHECK: getelementptr i8, ptr %[[C]], i64 %[[OFFSET]]
207  %a = fir.array_coor %c(%s) %j, %j typeparams %i : (!fir.ref<!fir.array<?x?x!fir.char<1,?>>>, !fir.shape<2>, i64, i64, i32) -> !fir.ref<!fir.char<1,?>>
208  return %a :  !fir.ref<!fir.char<1,?>>
209}
210