1// RUN: tco %s | FileCheck %s 2// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s 3 4// Test applying slice on fir.box 5// subroutine foo(x) 6// real :: x(3:, 4:) 7// call bar(x(5, 6:80:3)) 8// end subroutine 9 10func.func private @bar1(!fir.box<!fir.array<?xf32>>) 11// CHECK-LABEL: define void @test_rebox_1( 12// CHECK-SAME: ptr %[[INBOX:.*]]) 13func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) { 14 // CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } 15 %c2 = arith.constant 2 : index 16 %c3 = arith.constant 3 : index 17 %c4 = arith.constant 4 : index 18 %c5 = arith.constant 5 : index 19 %c6 = arith.constant 6 : index 20 %c80 = arith.constant 80 : index 21 %undef = fir.undefined index 22 %0 = fir.slice %c5, %undef, %undef, %c6, %c80, %c3 : (index, index, index, index, index, index) -> !fir.slice<2> 23 %1 = fir.shift %c3, %c4 : (index, index) -> !fir.shift<2> 24 25 // CHECK: %[[EXTRA_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 6 26 // CHECK: %[[EXTRA:.*]] = load i8, ptr %[[EXTRA_GEP]] 27 // CHECK: %[[EXTRA_WITH_ADDENDUM_CORRECTION:.*]] = and i8 %[[EXTRA]] 28 // CHECK: %[[OUTBOX0:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } { ptr undef, i64 ptrtoint (ptr getelementptr (float, ptr null, i32 1) to i64), i32 20240719, i8 1, i8 27, i8 0, i8 undef, [1 x [3 x i64]] undef }, i8 %[[EXTRA_WITH_ADDENDUM_CORRECTION]], 6 29 // CHECK: %[[INSTRIDE_0_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i32 0, i32 2 30 // CHECK: %[[INSTRIDE_0:.*]] = load i64, ptr %[[INSTRIDE_0_GEP]] 31 // CHECK: %[[INSTRIDE_1_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i32 1, i32 2 32 // CHECK: %[[INSTRIDE_1:.*]] = load i64, ptr %[[INSTRIDE_1_GEP]] 33 // CHECK: %[[INBASE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 0 34 // CHECK: %[[INBASE:.*]] = load ptr, ptr %[[INBASE_GEP]] 35 // CHECK: %[[OFFSET_0:.*]] = mul i64 2, %[[INSTRIDE_0]] 36 // CHECK: %[[VOIDBASE0:.*]] = getelementptr i8, ptr %[[INBASE]], i64 %[[OFFSET_0]] 37 // CHECK: %[[OFFSET_1:.*]] = mul i64 2, %[[INSTRIDE_1]] 38 // CHECK: %[[VOIDBASE1:.*]] = getelementptr i8, ptr %[[VOIDBASE0]], i64 %[[OFFSET_1]] 39 // CHECK: %[[OUTSTRIDE0:.*]] = mul i64 3, %[[INSTRIDE_1]] 40 // CHECK: %[[OUTBOX1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %{{.*}}, i64 %[[OUTSTRIDE0]], 7, 0, 2 41 // CHECK: %[[OUTBOX2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[OUTBOX1]], ptr %[[VOIDBASE1]], 0 42 // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[OUTBOX2]], ptr %[[OUTBOX_ALLOC]], align 8 43 %2 = fir.rebox %arg0(%1) [%0] : (!fir.box<!fir.array<?x?xf32>>, !fir.shift<2>, !fir.slice<2>) -> !fir.box<!fir.array<?xf32>> 44 // CHECK: call void @bar1(ptr %[[OUTBOX_ALLOC]]) 45 fir.call @bar1(%2) : (!fir.box<!fir.array<?xf32>>) -> () 46 return 47} 48 49// Test that character length is propagated in rebox 50// subroutine foo(x) 51// character(*) :: x(:, :) 52// call bar(x(4:30:1, 4:30:1)) 53// end subroutine 54 55func.func private @bar_rebox_test2(!fir.box<!fir.array<?x?x!fir.char<1,?>>>) 56// CHECK-LABEL: define void @test_rebox_2( 57// CHECK-SAME: ptr %[[INBOX:.*]]) 58func.func @test_rebox_2(%arg0: !fir.box<!fir.array<?x?x!fir.char<1,?>>>) { 59 %c1 = arith.constant 1 : index 60 %c4 = arith.constant 4 : index 61 %c30 = arith.constant 30 : index 62 %0 = fir.slice %c4, %c30, %c1, %c4, %c30, %c1 : (index, index, index, index, index, index) -> !fir.slice<2> 63 // CHECK: %[[OUTBOX:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } 64 // CHECK: %[[LEN_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 1 65 // CHECK: %[[LEN:.*]] = load i64, ptr %[[LEN_GEP]] 66 // CHECK: %[[SIZE:.*]] = mul i64 ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64), %[[LEN]] 67 // CHECK: insertvalue { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } undef, i64 %[[SIZE]], 1 68 69 %1 = fir.rebox %arg0 [%0] : (!fir.box<!fir.array<?x?x!fir.char<1,?>>>, !fir.slice<2>) -> !fir.box<!fir.array<?x?x!fir.char<1,?>>> 70 fir.call @bar_rebox_test2(%1) : (!fir.box<!fir.array<?x?x!fir.char<1,?>>>) -> () 71 return 72} 73 74 75// Test setting a new shape on a fir.box 76// subroutine foo(x) 77// real :: x(:) 78// real, pointer(:, :, :), p 79// p(2:5, 3:7, 4:9) => x 80// call bar(p) 81// end subroutine 82 83func.func private @bar_rebox_test3(!fir.box<!fir.array<?x?x?xf32>>) 84// CHECK-LABEL: define void @test_rebox_3( 85// CHECK-SAME: ptr %[[INBOX:.*]]) 86func.func @test_rebox_3(%arg0: !fir.box<!fir.array<?xf32>>) { 87 // CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } 88 %c2 = arith.constant 2 : index 89 %c3 = arith.constant 3 : index 90 %c4 = arith.constant 4 : index 91 %c5 = arith.constant 5 : index 92 %1 = fir.shape_shift %c2, %c3, %c3, %c4, %c4, %c5 : (index, index, index, index, index, index) -> !fir.shapeshift<3> 93 // CHECK: %[[INSTRIDE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i32 0, i32 2 94 // CHECK: %[[INSTRIDE:.*]] = load i64, ptr %[[INSTRIDE_GEP]] 95 // CHECK: %[[INBASE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 0 96 // CHECK: %[[INBASE:.*]] = load ptr, ptr %[[INBASE_GEP]] 97 // CHECK: %[[OUTSTRIDE1:.*]] = mul i64 3, %[[INSTRIDE]] 98 // CHECK: %[[OUTSTRIDE2:.*]] = mul i64 4, %[[OUTSTRIDE1]] 99 // CHECK: %[[OUTBOX0:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %{{.*}}, i64 %[[INSTRIDE]], 7, 0, 2 100 // CHECK: %[[OUTBOX1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %[[OUTBOX0]], i64 3, 7, 1, 0 101 // CHECK: %[[OUTBOX2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %[[OUTBOX1]], i64 4, 7, 1, 1 102 // CHECK: %[[OUTBOX3:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %[[OUTBOX2]], i64 %[[OUTSTRIDE1]], 7, 1, 2 103 // CHECK: %[[OUTBOX4:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %[[OUTBOX3]], i64 4, 7, 2, 0 104 // CHECK: %[[OUTBOX5:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %[[OUTBOX4]], i64 5, 7, 2, 1 105 // CHECK: %[[OUTBOX6:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %[[OUTBOX5]], i64 %[[OUTSTRIDE2]], 7, 2, 2 106 // CHECK: %[[OUTBOX7:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %[[OUTBOX6]], ptr %[[INBASE]], 0 107 // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] } %[[OUTBOX7]], ptr %[[OUTBOX_ALLOC]] 108 %2 = fir.rebox %arg0(%1) : (!fir.box<!fir.array<?xf32>>, !fir.shapeshift<3>) -> !fir.box<!fir.array<?x?x?xf32>> 109 // CHECK: call void @bar_rebox_test3(ptr %[[OUTBOX_ALLOC]]) 110 fir.call @bar_rebox_test3(%2) : (!fir.box<!fir.array<?x?x?xf32>>) -> () 111 return 112} 113 114 115// Test reboxing of character entities where the input has dynamic length and the output has compile 116// time constant length. 117 118// CHECK-LABEL: define void @test_rebox_4( 119// CHECK-SAME: ptr %[[INPUT:.*]]) 120func.func @test_rebox_4(%arg0: !fir.box<!fir.array<?x!fir.char<1,?>>>) { 121 // CHECK: %[[NEWBOX_STORAGE:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } 122 // CHECK: %[[EXTENT_GEP:.*]] = getelementptr {{{.*}}}, ptr %[[INPUT]], i32 0, i32 7, i32 0, i32 1 123 // CHECK: %[[EXTENT:.*]] = load i64, ptr %[[EXTENT_GEP]] 124 // CHECK: %[[STRIDE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INPUT]], i32 0, i32 7, i32 0, i32 2 125 // CHECK: %[[STRIDE:.*]] = load i64, ptr %[[STRIDE_GEP]] 126 // CHECK: %[[BASE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INPUT]], i32 0, i32 0 127 // CHECK: %[[BASE:.*]] = load ptr, ptr %[[BASE_GEP]] 128 // CHECK: %[[NEWBOX1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %{{.*}}, i64 %[[EXTENT]], 7, 0, 1 129 // CHECK: %[[NEWBOX2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[NEWBOX1]], i64 %[[STRIDE]], 7, 0, 2 130 // CHECK: %[[NEWBOX3:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[NEWBOX2]], ptr %[[BASE]], 0 131 // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[NEWBOX3]], ptr %[[NEWBOX_STORAGE]] 132 // CHECK: call void @bar_test_rebox_4(ptr %[[NEWBOX_STORAGE]]) 133 134 %1 = fir.rebox %arg0 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> !fir.box<!fir.ptr<!fir.array<?x!fir.char<1,10>>>> 135 fir.call @bar_test_rebox_4(%1) : (!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,10>>>>) -> () 136 return 137} 138func.func private @bar_test_rebox_4(!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,10>>>>) 139 140// Testing complex part slice reboxing 141// subroutine test_cmplx_2(a) 142// complex :: a(:) 143// call bar1(a%re) 144// end subroutine 145 146// CHECK-LABEL: define void @test_cmplx_1( 147// CHECK-SAME: ptr %[[INBOX:.*]]) 148func.func @test_cmplx_1(%arg0: !fir.box<!fir.array<?xcomplex<f32>>>) { 149 // CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } 150 %c1 = arith.constant 1 : index 151 %c1_i32 = arith.constant 0 : i32 152 %c0 = arith.constant 0 : index 153 %0:3 = fir.box_dims %arg0, %c0 : (!fir.box<!fir.array<?xcomplex<f32>>>, index) -> (index, index, index) 154 %1 = fir.slice %c1, %0#1, %c1 path %c1_i32 : (index, index, index, i32) -> !fir.slice<1> 155 %2 = fir.rebox %arg0 [%1] : (!fir.box<!fir.array<?xcomplex<f32>>>, !fir.slice<1>) -> !fir.box<!fir.array<?xf32>> 156 // CHECK: %[[INSTRIDE_0_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i64 0, i32 1 157 // CHECK: %[[INSTRIDE_0:.*]] = load i64, ptr %[[INSTRIDE_0_GEP]] 158 // CHECK: %[[INSTRIDE_1_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i32 0, i32 2 159 // CHECK: %[[INSTRIDE_1:.*]] = load i64, ptr %[[INSTRIDE_1_GEP]] 160 // CHECK: %[[FRONT_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 0 161 // CHECK: %[[FRONT_PTR:.*]] = load ptr, ptr %[[FRONT_GEP]] 162 // CHECK: %[[FIELD_OFFSET_GEP:.*]] = getelementptr { float, float }, ptr %[[FRONT_PTR]], i64 0, i32 0 163 // CHECK: %[[FRONT_OFFSET:.*]] = mul i64 0, %[[INSTRIDE_1]] 164 // CHECK: %[[OFFSET_GEP:.*]] = getelementptr i8, ptr %[[FIELD_OFFSET_GEP]], i64 %[[FRONT_OFFSET]] 165 // CHECK: %[[SUB_1:.*]] = sub i64 %[[INSTRIDE_0]], 1 166 // CHECK: %[[ADD_1:.*]] = add i64 %[[SUB_1]], 1 167 // CHECK: %[[DIV_1:.*]] = sdiv i64 %[[ADD_1]], 1 168 // CHECK: %[[CHECK_NONZERO:.*]] = icmp sgt i64 %[[DIV_1]], 0 169 // CHECK: %[[CHECKED_BOUND:.*]] = select i1 %[[CHECK_NONZERO]], i64 %[[DIV_1]], i64 0 170 // CHECK: %[[STRIDE:.*]] = mul i64 1, %[[INSTRIDE_1]] 171 // CHECK: %[[VAL_BUILD_1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %{{.*}}, i64 %[[CHECKED_BOUND]], 7, 0, 1 172 // CHECK: %[[VAL_BUILD_2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_1]], i64 %[[STRIDE]], 7, 0, 2 173 // CHECK: %[[VAL_BUILD_3:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_2]], ptr %[[OFFSET_GEP]], 0 174 // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_3]], ptr %[[OUTBOX_ALLOC]] 175 fir.call @bar1(%2) : (!fir.box<!fir.array<?xf32>>) -> () 176 // CHECK: call void @bar1(ptr %[[OUTBOX_ALLOC]]) 177 return 178} 179 180// Testing triple on complex part slice 181// subroutine test_cmplx_2(a) 182// complex :: a(:) 183// call bar1(a(7:60:5)%im) 184// end subroutine 185 186// CHECK-LABEL: define void @test_cmplx_2( 187// CHECK-SAME: ptr %[[INBOX:.*]]) 188func.func @test_cmplx_2(%arg0: !fir.box<!fir.array<?xcomplex<f32>>>) { 189 // CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } 190 %c7 = arith.constant 7 : index 191 %c5 = arith.constant 5 : index 192 %c60 = arith.constant 60 : index 193 %c1_i32 = arith.constant 1 : i32 194 %0 = fir.slice %c7, %c60, %c5 path %c1_i32 : (index, index, index, i32) -> !fir.slice<1> 195 %1 = fir.rebox %arg0 [%0] : (!fir.box<!fir.array<?xcomplex<f32>>>, !fir.slice<1>) -> !fir.box<!fir.array<11xf32>> 196 %2 = fir.convert %1 : (!fir.box<!fir.array<11xf32>>) -> !fir.box<!fir.array<?xf32>> 197 // CHECK: %[[INSTRIDE_0_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i32 0, i32 2 198 // CHECK: %[[INSTRIDE_0:.*]] = load i64, ptr %[[INSTRIDE_0_GEP]] 199 // CHECK: %[[FRONT_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 0 200 // CHECK: %[[FRONT_PTR:.*]] = load ptr, ptr %[[FRONT_GEP]] 201 // CHECK: %[[FIELD_OFFSET_GEP:.*]] = getelementptr { float, float }, ptr %[[FRONT_PTR]], i64 0, i32 1 202 // CHECK: %[[FRONT_OFFSET:.*]] = mul i64 6, %[[INSTRIDE_0]] 203 // CHECK: %[[OFFSET_GEP:.*]] = getelementptr i8, ptr %[[FIELD_OFFSET_GEP]], i64 %[[FRONT_OFFSET]] 204 // CHECK: %[[STRIDE:.*]] = mul i64 5, %[[INSTRIDE_0]] 205 // CHECK: %[[VAL_BUILD_1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %{{.*}}, i64 %[[STRIDE]], 7, 0, 2 206 // CHECK: %[[VAL_BUILD_2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_1]], ptr %[[OFFSET_GEP]], 0 207 // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_2]], ptr %[[OUTBOX_ALLOC]] 208 fir.call @bar1(%2) fastmath<contract> : (!fir.box<!fir.array<?xf32>>) -> () 209 // CHECK: call void @bar1(ptr %[[OUTBOX_ALLOC]]) 210 return 211} 212 213// Test reboxing of unlimited polymorphic. 214 215func.func @rebox_unlimited_polymorphic_box(%arg0 : !fir.class<!fir.array<?xnone>>, %arg1 : !fir.box<!fir.array<?xnone>>, %arg0r : !fir.ref<!fir.class<!fir.array<?xnone>>>, %arg1r : !fir.ref<!fir.box<!fir.array<?xnone>>>) { 216 %c1 = arith.constant 1 : index 217 %c10 = arith.constant 10 : index 218 %1 = fir.slice %c1, %c10, %c1 : (index, index, index) -> !fir.slice<1> 219 %2 = fir.rebox %arg0 [%1] : (!fir.class<!fir.array<?xnone>>, !fir.slice<1>) -> !fir.class<!fir.array<?xnone>> 220 %3 = fir.rebox %arg1 [%1] : (!fir.box<!fir.array<?xnone>>, !fir.slice<1>) -> !fir.box<!fir.array<?xnone>> 221 fir.store %2 to %arg0r : !fir.ref<!fir.class<!fir.array<?xnone>>> 222 fir.store %3 to %arg1r : !fir.ref<!fir.box<!fir.array<?xnone>>> 223 return 224} 225// CHECK-LABEL: define void @rebox_unlimited_polymorphic_box 226// CHECK: %[[VAL_16:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } 227// CHECK: %[[VAL_17:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } 228// ... 229// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %{{.*}}, ptr %[[VAL_17]] 230// ... 231// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %{{.*}}, ptr %[[VAL_16]] 232