Flang alias analysis used to find allocation site by pattern matching allocation ops in mainly FIR dialect. This MR extends the characterization to instead characterize based on whether the result of an op has MemAlloc effect.
254 lines
12 KiB
Fortran
254 lines
12 KiB
Fortran
! RUN: bbc -emit-fir -hlfir=false -o - %s | FileCheck %s
|
|
! RUN: %flang_fc1 -emit-fir -flang-deprecated-no-hlfir -o - %s | FileCheck %s
|
|
! RUN: %flang_fc1 -emit-fir -flang-deprecated-no-hlfir -fwrapv -o - %s | FileCheck %s --check-prefix=NO-NSW
|
|
|
|
! Tests for unstructured loops.
|
|
|
|
! NO-NSW-NOT: overflow<nsw>
|
|
|
|
! Test a simple unstructured loop. Test for the existence of,
|
|
! -> The initialization of the trip-count and loop-variable
|
|
! -> The branch to the body or the exit inside the header
|
|
! -> The increment of the trip-count and the loop-variable inside the body
|
|
subroutine simple_unstructured()
|
|
integer :: i
|
|
do i=1,100
|
|
goto 404
|
|
404 continue
|
|
end do
|
|
end subroutine
|
|
! CHECK-LABEL: simple_unstructured
|
|
! CHECK: %[[TRIP_VAR_REF:.*]] = fir.alloca i32
|
|
! CHECK: %[[LOOP_VAR_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_unstructuredEi"}
|
|
! CHECK: %[[ONE:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[HUNDRED:.*]] = arith.constant 100 : i32
|
|
! CHECK: %[[STEP_ONE:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TMP1:.*]] = arith.subi %[[HUNDRED]], %[[ONE]] : i32
|
|
! CHECK: %[[TMP2:.*]] = arith.addi %[[TMP1]], %[[STEP_ONE]] : i32
|
|
! CHECK: %[[TRIP_COUNT:.*]] = arith.divsi %[[TMP2]], %[[STEP_ONE]] : i32
|
|
! CHECK: fir.store %[[TRIP_COUNT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: fir.store %[[ONE]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER:.*]]
|
|
! CHECK: ^[[HEADER]]:
|
|
! CHECK: %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ZERO:.*]] = arith.constant 0 : i32
|
|
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[TRIP_VAR]], %[[ZERO]] : i32
|
|
! CHECK: cf.cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]]
|
|
! CHECK: ^[[BODY]]:
|
|
! CHECK: %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ONE_1:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TRIP_VAR_NEXT:.*]] = arith.subi %[[TRIP_VAR]], %[[ONE_1]] : i32
|
|
! CHECK: fir.store %[[TRIP_VAR_NEXT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[LOOP_VAR:.*]] = fir.load %[[LOOP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[STEP_ONE_2:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[LOOP_VAR_NEXT:.*]] = arith.addi %[[LOOP_VAR]], %[[STEP_ONE_2]] overflow<nsw> : i32
|
|
! CHECK: fir.store %[[LOOP_VAR_NEXT]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER]]
|
|
! CHECK: ^[[EXIT]]:
|
|
! CHECK: return
|
|
|
|
! Test an unstructured loop with a step. Mostly similar to the previous one.
|
|
! Only difference is a non-unit step.
|
|
subroutine simple_unstructured_with_step()
|
|
integer :: i
|
|
do i=1,100,2
|
|
goto 404
|
|
404 continue
|
|
end do
|
|
end subroutine
|
|
! CHECK-LABEL: simple_unstructured_with_step
|
|
! CHECK: %[[TRIP_VAR_REF:.*]] = fir.alloca i32
|
|
! CHECK: %[[LOOP_VAR_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_unstructured_with_stepEi"}
|
|
! CHECK: %[[ONE:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[HUNDRED:.*]] = arith.constant 100 : i32
|
|
! CHECK: %[[STEP:.*]] = arith.constant 2 : i32
|
|
! CHECK: %[[TMP1:.*]] = arith.subi %[[HUNDRED]], %[[ONE]] : i32
|
|
! CHECK: %[[TMP2:.*]] = arith.addi %[[TMP1]], %[[STEP]] : i32
|
|
! CHECK: %[[TRIP_COUNT:.*]] = arith.divsi %[[TMP2]], %[[STEP]] : i32
|
|
! CHECK: fir.store %[[TRIP_COUNT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: fir.store %[[ONE]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER:.*]]
|
|
! CHECK: ^[[HEADER]]:
|
|
! CHECK: %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ZERO:.*]] = arith.constant 0 : i32
|
|
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[TRIP_VAR]], %[[ZERO]] : i32
|
|
! CHECK: cf.cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]]
|
|
! CHECK: ^[[BODY]]:
|
|
! CHECK: %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ONE_1:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TRIP_VAR_NEXT:.*]] = arith.subi %[[TRIP_VAR]], %[[ONE_1]] : i32
|
|
! CHECK: fir.store %[[TRIP_VAR_NEXT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[LOOP_VAR:.*]] = fir.load %[[LOOP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[STEP_2:.*]] = arith.constant 2 : i32
|
|
! CHECK: %[[LOOP_VAR_NEXT:.*]] = arith.addi %[[LOOP_VAR]], %[[STEP_2]] overflow<nsw> : i32
|
|
! CHECK: fir.store %[[LOOP_VAR_NEXT]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER]]
|
|
! CHECK: ^[[EXIT]]:
|
|
! CHECK: return
|
|
|
|
! Test a three nested unstructured loop. Three nesting is the basic case where
|
|
! we have loops that are neither innermost or outermost.
|
|
subroutine nested_unstructured()
|
|
integer :: i, j, k
|
|
do i=1,100
|
|
do j=1,200
|
|
do k=1,300
|
|
goto 404
|
|
404 continue
|
|
end do
|
|
end do
|
|
end do
|
|
end subroutine
|
|
! CHECK-LABEL: nested_unstructured
|
|
! CHECK: %[[TRIP_VAR_K_REF:.*]] = fir.alloca i32
|
|
! CHECK: %[[TRIP_VAR_J_REF:.*]] = fir.alloca i32
|
|
! CHECK: %[[TRIP_VAR_I_REF:.*]] = fir.alloca i32
|
|
! CHECK: %[[LOOP_VAR_I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFnested_unstructuredEi"}
|
|
! CHECK: %[[LOOP_VAR_J_REF:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFnested_unstructuredEj"}
|
|
! CHECK: %[[LOOP_VAR_K_REF:.*]] = fir.alloca i32 {bindc_name = "k", uniq_name = "_QFnested_unstructuredEk"}
|
|
! CHECK: %[[I_START:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[I_END:.*]] = arith.constant 100 : i32
|
|
! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TMP1:.*]] = arith.subi %[[I_END]], %[[I_START]] : i32
|
|
! CHECK: %[[TMP2:.*]] = arith.addi %[[TMP1]], %[[I_STEP]] : i32
|
|
! CHECK: %[[TRIP_COUNT_I:.*]] = arith.divsi %[[TMP2]], %[[I_STEP]] : i32
|
|
! CHECK: fir.store %[[TRIP_COUNT_I]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: fir.store %[[I_START]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER_I:.*]]
|
|
! CHECK: ^[[HEADER_I]]:
|
|
! CHECK: %[[TRIP_VAR_I:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ZERO_1:.*]] = arith.constant 0 : i32
|
|
! CHECK: %[[COND_I:.*]] = arith.cmpi sgt, %[[TRIP_VAR_I]], %[[ZERO_1]] : i32
|
|
! CHECK: cf.cond_br %[[COND_I]], ^[[BODY_I:.*]], ^[[EXIT_I:.*]]
|
|
! CHECK: ^[[BODY_I]]:
|
|
! CHECK: %[[J_START:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[J_END:.*]] = arith.constant 200 : i32
|
|
! CHECK: %[[J_STEP:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TMP3:.*]] = arith.subi %[[J_END]], %[[J_START]] : i32
|
|
! CHECK: %[[TMP4:.*]] = arith.addi %[[TMP3]], %[[J_STEP]] : i32
|
|
! CHECK: %[[TRIP_COUNT_J:.*]] = arith.divsi %[[TMP4]], %[[J_STEP]] : i32
|
|
! CHECK: fir.store %[[TRIP_COUNT_J]] to %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: fir.store %[[J_START]] to %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER_J:.*]]
|
|
! CHECK: ^[[HEADER_J]]:
|
|
! CHECK: %[[TRIP_VAR_J:.*]] = fir.load %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ZERO_2:.*]] = arith.constant 0 : i32
|
|
! CHECK: %[[COND_J:.*]] = arith.cmpi sgt, %[[TRIP_VAR_J]], %[[ZERO_2]] : i32
|
|
! CHECK: cf.cond_br %[[COND_J]], ^[[BODY_J:.*]], ^[[EXIT_J:.*]]
|
|
! CHECK: ^[[BODY_J]]:
|
|
! CHECK: %[[K_START:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[K_END:.*]] = arith.constant 300 : i32
|
|
! CHECK: %[[K_STEP:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TMP3:.*]] = arith.subi %[[K_END]], %[[K_START]] : i32
|
|
! CHECK: %[[TMP4:.*]] = arith.addi %[[TMP3]], %[[K_STEP]] : i32
|
|
! CHECK: %[[TRIP_COUNT_K:.*]] = arith.divsi %[[TMP4]], %[[K_STEP]] : i32
|
|
! CHECK: fir.store %[[TRIP_COUNT_K]] to %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
|
|
! CHECK: fir.store %[[K_START]] to %[[LOOP_VAR_K_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER_K:.*]]
|
|
! CHECK: ^[[HEADER_K]]:
|
|
! CHECK: %[[TRIP_VAR_K:.*]] = fir.load %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ZERO_2:.*]] = arith.constant 0 : i32
|
|
! CHECK: %[[COND_K:.*]] = arith.cmpi sgt, %[[TRIP_VAR_K]], %[[ZERO_2]] : i32
|
|
! CHECK: cf.cond_br %[[COND_K]], ^[[BODY_K:.*]], ^[[EXIT_K:.*]]
|
|
! CHECK: ^[[BODY_K]]:
|
|
! CHECK: %[[TRIP_VAR_K:.*]] = fir.load %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ONE_1:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TRIP_VAR_K_NEXT:.*]] = arith.subi %[[TRIP_VAR_K]], %[[ONE_1]] : i32
|
|
! CHECK: fir.store %[[TRIP_VAR_K_NEXT]] to %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[LOOP_VAR_K:.*]] = fir.load %[[LOOP_VAR_K_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[K_STEP_2:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[LOOP_VAR_K_NEXT:.*]] = arith.addi %[[LOOP_VAR_K]], %[[K_STEP_2]] overflow<nsw> : i32
|
|
! CHECK: fir.store %[[LOOP_VAR_K_NEXT]] to %[[LOOP_VAR_K_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER_K]]
|
|
! CHECK: ^[[EXIT_K]]:
|
|
! CHECK: %[[TRIP_VAR_J:.*]] = fir.load %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ONE_1:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TRIP_VAR_J_NEXT:.*]] = arith.subi %[[TRIP_VAR_J]], %[[ONE_1]] : i32
|
|
! CHECK: fir.store %[[TRIP_VAR_J_NEXT]] to %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[LOOP_VAR_J:.*]] = fir.load %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[J_STEP_2:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[LOOP_VAR_J_NEXT:.*]] = arith.addi %[[LOOP_VAR_J]], %[[J_STEP_2]] overflow<nsw> : i32
|
|
! CHECK: fir.store %[[LOOP_VAR_J_NEXT]] to %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER_J]]
|
|
! CHECK: ^[[EXIT_J]]:
|
|
! CHECK: %[[TRIP_VAR_I:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ONE_1:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TRIP_VAR_I_NEXT:.*]] = arith.subi %[[TRIP_VAR_I]], %[[ONE_1]] : i32
|
|
! CHECK: fir.store %[[TRIP_VAR_I_NEXT]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[LOOP_VAR_I:.*]] = fir.load %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[I_STEP_2:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[LOOP_VAR_I_NEXT:.*]] = arith.addi %[[LOOP_VAR_I]], %[[I_STEP_2]] overflow<nsw> : i32
|
|
! CHECK: fir.store %[[LOOP_VAR_I_NEXT]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER_I]]
|
|
! CHECK: ^[[EXIT_I]]:
|
|
! CHECK: return
|
|
|
|
! Test the existence of a structured loop inside an unstructured loop.
|
|
! Only minimal checks are inserted for the structured loop.
|
|
subroutine nested_structured_in_unstructured()
|
|
integer :: i, j
|
|
do i=1,100
|
|
do j=1,100
|
|
end do
|
|
goto 404
|
|
404 continue
|
|
end do
|
|
end subroutine
|
|
! CHECK-LABEL: nested_structured_in_unstructured
|
|
! CHECK: %[[TRIP_VAR_I_REF:.*]] = fir.alloca i32
|
|
! CHECK: %[[LOOP_VAR_I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFnested_structured_in_unstructuredEi"}
|
|
! CHECK: %[[LOOP_VAR_J_REF:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFnested_structured_in_unstructuredEj"}
|
|
! CHECK: %[[I_START:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[I_END:.*]] = arith.constant 100 : i32
|
|
! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TMP1:.*]] = arith.subi %[[I_END]], %[[I_START]] : i32
|
|
! CHECK: %[[TMP2:.*]] = arith.addi %[[TMP1]], %[[I_STEP]] : i32
|
|
! CHECK: %[[TRIP_COUNT:.*]] = arith.divsi %[[TMP2]], %[[I_STEP]] : i32
|
|
! CHECK: fir.store %[[TRIP_COUNT]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: fir.store %[[I_START]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER:.*]]
|
|
! CHECK: ^[[HEADER]]:
|
|
! CHECK: %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[ZERO:.*]] = arith.constant 0 : i32
|
|
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[TRIP_VAR]], %[[ZERO]] : i32
|
|
! CHECK: cf.cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]]
|
|
! CHECK: ^[[BODY]]:
|
|
! CHECK: %{{.*}} = fir.do_loop %[[J_INDEX:[^ ]*]] =
|
|
! CHECK-SAME: %{{.*}} to %{{.*}} step %[[ST:[^ ]*]]
|
|
! CHECK-SAME: iter_args(%[[J_IV:.*]] = %{{.*}}) -> (i32) {
|
|
! CHECK: fir.store %[[J_IV]] to %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[LOOP_VAR_J:.*]] = fir.load %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[LOOP_VAR_J_NEXT:.*]] = arith.addi %[[LOOP_VAR_J]], %{{[^ ]*}} overflow<nsw> : i32
|
|
! CHECK: }
|
|
! CHECK: %[[TRIP_VAR_I:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[C1_3:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[TRIP_VAR_I_NEXT:.*]] = arith.subi %[[TRIP_VAR_I]], %[[C1_3]] : i32
|
|
! CHECK: fir.store %[[TRIP_VAR_I_NEXT]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[LOOP_VAR_I:.*]] = fir.load %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: %[[I_STEP_2:.*]] = arith.constant 1 : i32
|
|
! CHECK: %[[LOOP_VAR_I_NEXT:.*]] = arith.addi %[[LOOP_VAR_I]], %[[I_STEP_2]] overflow<nsw> : i32
|
|
! CHECK: fir.store %[[LOOP_VAR_I_NEXT]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
|
|
! CHECK: cf.br ^[[HEADER]]
|
|
! CHECK: ^[[EXIT]]:
|
|
! CHECK: return
|
|
|
|
subroutine unstructured_do_concurrent
|
|
logical :: success
|
|
do concurrent (i=1:10) local(success)
|
|
success = .false.
|
|
error stop "fail"
|
|
enddo
|
|
end
|
|
! CHECK-LABEL: func.func @_QPunstructured_do_concurrent
|
|
! CHECK: %[[ITER_VAR:.*]] = fir.alloca i32
|
|
|
|
! CHECK: ^[[HEADER]]:
|
|
! CHECK: %{{.*}} = fir.load %[[ITER_VAR]] : !fir.ref<i32>
|
|
! CHECK: cf.cond_br %{{.*}}, ^[[BODY:.*]], ^[[EXIT:.*]]
|
|
|
|
! CHECK: ^[[BODY]]:
|
|
! CHECK-NEXT: %{{.*}} = fir.alloca !fir.logical<4> {bindc_name = "success", {{.*}}}
|
|
|
|
! CHECK: ^[[EXIT]]:
|
|
! CHECK-NEXT: return
|