! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s ! RUN: %flang_fc1 -emit-hlfir -fwrapv -o - %s | FileCheck %s --check-prefix=NO-NSW ! Simple tests for structured ordered loops with loop-control. ! Tests the structure of the loop, storage to index variable and return and ! storage of the final value of the index variable. ! NO-NSW-NOT: overflow ! Test a simple loop with the final value of the index variable read outside the loop ! CHECK-LABEL: simple_loop subroutine simple_loop ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_loopEi"} ! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] integer :: i ! CHECK: %[[C1:.*]] = arith.constant 1 : i32 ! CHECK: %[[C1_CVT:.*]] = fir.convert %[[C1]] : (i32) -> index ! CHECK: %[[C5:.*]] = arith.constant 5 : i32 ! CHECK: %[[C5_CVT:.*]] = fir.convert %[[C5]] : (i32) -> index ! CHECK: %[[C1_STEP:.*]] = arith.constant 1 : index ! CHECK: %[[LB:.*]] = fir.convert %[[C1_CVT]] : (index) -> i32 ! CHECK: %[[LI_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] = ! CHECK-SAME: %[[C1_CVT]] to %[[C5_CVT]] step %[[C1_STEP]] ! CHECK-SAME: iter_args(%[[IV:.*]] = %[[LB]]) -> (i32) { do i=1,5 ! CHECK: fir.store %[[IV]] to %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[STEPCAST:.*]] = fir.convert %[[C1_STEP]] : (index) -> i32 ! CHECK: %[[IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[IVINC:.*]] = arith.addi %[[IVLOAD]], %[[STEPCAST]] overflow : i32 ! CHECK: fir.result %[[IVINC]] : i32 ! CHECK: } end do ! CHECK: fir.store %[[LI_RES]] to %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref ! CHECK: %{{.*}} = fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[I]]) {{.*}}: (!fir.ref, i32) -> i1 print *, i end subroutine ! Test a 2-nested loop with a body composed of a reduction. Values are read from a 2d array. ! CHECK-LABEL: nested_loop subroutine nested_loop ! CHECK: %[[ARR_REF:.*]] = fir.alloca !fir.array<5x5xi32> {bindc_name = "arr", uniq_name = "_QFnested_loopEarr"} ! CHECK: %[[ARR_DECL:.*]]:2 = hlfir.declare %[[ARR_REF]] ! CHECK: %[[ASUM_REF:.*]] = fir.alloca i32 {bindc_name = "asum", uniq_name = "_QFnested_loopEasum"} ! CHECK: %[[ASUM_DECL:.*]]:2 = hlfir.declare %[[ASUM_REF]] ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFnested_loopEi"} ! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] ! CHECK: %[[J_REF:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFnested_loopEj"} ! CHECK: %[[J_DECL:.*]]:2 = hlfir.declare %[[J_REF]] integer :: asum, arr(5,5) integer :: i, j asum = 0 ! CHECK: %[[S_I:.*]] = arith.constant 1 : i32 ! CHECK: %[[S_I_CVT:.*]] = fir.convert %[[S_I]] : (i32) -> index ! CHECK: %[[E_I:.*]] = arith.constant 5 : i32 ! CHECK: %[[E_I_CVT:.*]] = fir.convert %[[E_I]] : (i32) -> index ! CHECK: %[[ST_I:.*]] = arith.constant 1 : index ! CHECK: %[[I_LB:.*]] = fir.convert %[[S_I_CVT]] : (index) -> i32 ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] = ! CHECK-SAME: %[[S_I_CVT]] to %[[E_I_CVT]] step %[[ST_I]] ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i32) { do i=1,5 ! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[S_J:.*]] = arith.constant 1 : i32 ! CHECK: %[[S_J_CVT:.*]] = fir.convert %[[S_J]] : (i32) -> index ! CHECK: %[[E_J:.*]] = arith.constant 5 : i32 ! CHECK: %[[E_J_CVT:.*]] = fir.convert %[[E_J]] : (i32) -> index ! CHECK: %[[ST_J:.*]] = arith.constant 1 : index ! CHECK: %[[J_LB:.*]] = fir.convert %[[S_J_CVT]] : (index) -> i32 ! CHECK: %[[J_RES:.*]] = fir.do_loop %[[LJ:[^ ]*]] = ! CHECK-SAME: %[[S_J_CVT]] to %[[E_J_CVT]] step %[[ST_J]] ! CHECK-SAME: iter_args(%[[J_IV:.*]] = %[[J_LB]]) -> (i32) { do j=1,5 ! CHECK: fir.store %[[J_IV]] to %[[J_DECL]]#0 : !fir.ref ! CHECK: %[[ASUM:.*]] = fir.load %[[ASUM_DECL]]#0 : !fir.ref ! CHECK: %[[I:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I_CVT:.*]] = fir.convert %[[I]] : (i32) -> i64 ! CHECK: %[[J:.*]] = fir.load %[[J_DECL]]#0 : !fir.ref ! CHECK: %[[J_CVT:.*]] = fir.convert %[[J]] : (i32) -> i64 ! CHECK: %[[ARR_IJ_REF:.*]] = hlfir.designate %[[ARR_DECL]]#0 (%[[I_CVT]], %[[J_CVT]]) ! CHECK: %[[ARR_VAL:.*]] = fir.load %[[ARR_IJ_REF]] : !fir.ref ! CHECK: %[[ASUM_NEW:.*]] = arith.addi %[[ASUM]], %[[ARR_VAL]] : i32 ! CHECK: hlfir.assign %[[ASUM_NEW]] to %[[ASUM_DECL]]#0 : i32, !fir.ref asum = asum + arr(i,j) ! CHECK: %[[J_STEPCAST:.*]] = fir.convert %[[ST_J]] : (index) -> i32 ! CHECK: %[[J_IVLOAD:.*]] = fir.load %[[J_DECL]]#0 : !fir.ref ! CHECK: %[[J_IVINC:.*]] = arith.addi %[[J_IVLOAD]], %[[J_STEPCAST]] overflow : i32 ! CHECK: fir.result %[[J_IVINC]] : i32 ! CHECK: } end do ! CHECK: fir.store %[[J_RES]] to %[[J_DECL]]#0 : !fir.ref ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[ST_I]] : (index) -> i32 ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow : i32 ! CHECK: fir.result %[[I_IVINC]] : i32 ! CHECK: } end do ! CHECK: fir.store %[[I_RES]] to %[[I_DECL]]#0 : !fir.ref end subroutine ! Test a downcounting loop ! CHECK-LABEL: down_counting_loop subroutine down_counting_loop() integer :: i ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFdown_counting_loopEi"} ! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] ! CHECK: %[[C5:.*]] = arith.constant 5 : i32 ! CHECK: %[[C5_CVT:.*]] = fir.convert %[[C5]] : (i32) -> index ! CHECK: %[[C1:.*]] = arith.constant 1 : i32 ! CHECK: %[[C1_CVT:.*]] = fir.convert %[[C1]] : (i32) -> index ! CHECK: %[[CMINUS1:.*]] = arith.constant -1 : i32 ! CHECK: %[[CMINUS1_STEP_CVT:.*]] = fir.convert %[[CMINUS1]] : (i32) -> index ! CHECK: %[[I_LB:.*]] = fir.convert %[[C5_CVT]] : (index) -> i32 ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] = ! CHECK-SAME: %[[C5_CVT]] to %[[C1_CVT]] step %[[CMINUS1_STEP_CVT]] ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i32) { do i=5,1,-1 ! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[CMINUS1_STEP_CVT]] : (index) -> i32 ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow : i32 ! CHECK: fir.result %[[I_IVINC]] : i32 ! CHECK: } end do ! CHECK: fir.store %[[I_RES]] to %[[I_DECL]]#0 : !fir.ref end subroutine ! Test a general loop with a variable step ! CHECK-LABEL: loop_with_variable_step ! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref {fir.bindc_name = "st"}) { subroutine loop_with_variable_step(s,e,st) integer :: s, e, st ! CHECK-DAG: %[[E_DECL:.*]]:2 = hlfir.declare %[[E_REF]] ! CHECK-DAG: %[[S_DECL:.*]]:2 = hlfir.declare %[[S_REF]] ! CHECK-DAG: %[[ST_DECL:.*]]:2 = hlfir.declare %[[ST_REF]] ! CHECK-DAG: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFloop_with_variable_stepEi"} ! CHECK-DAG: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] ! CHECK: %[[S:.*]] = fir.load %[[S_DECL]]#0 : !fir.ref ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i32) -> index ! CHECK: %[[E:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index ! CHECK: %[[ST:.*]] = fir.load %[[ST_DECL]]#0 : !fir.ref ! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i32) -> index ! CHECK: %[[I_LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i32 ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] = ! CHECK-SAME: %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i32) { do i=s,e,st ! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[ST_CVT]] : (index) -> i32 ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow : i32 ! CHECK: fir.result %[[I_IVINC]] : i32 ! CHECK: } end do ! CHECK: fir.store %[[I_RES]] to %[[I_DECL]]#0 : !fir.ref end subroutine ! Test usage of pointer variables as index, start, end and step variables ! CHECK-LABEL: loop_with_pointer_variables ! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref {fir.bindc_name = "s", fir.target}, %[[E_REF:.*]]: !fir.ref {fir.bindc_name = "e", fir.target}, %[[ST_REF:.*]]: !fir.ref {fir.bindc_name = "st", fir.target}) { subroutine loop_with_pointer_variables(s,e,st) ! CHECK-DAG: %[[E_PTR_REF:.*]] = fir.alloca !fir.box> {bindc_name = "eptr", uniq_name = "_QFloop_with_pointer_variablesEeptr"} ! CHECK-DAG: %[[E_PTR_DECL:.*]]:2 = hlfir.declare %[[E_PTR_REF]] ! CHECK-DAG: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", fir.target, uniq_name = "_QFloop_with_pointer_variablesEi"} ! CHECK-DAG: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] ! CHECK-DAG: %[[I_PTR_REF:.*]] = fir.alloca !fir.box> {bindc_name = "iptr", uniq_name = "_QFloop_with_pointer_variablesEiptr"} ! CHECK-DAG: %[[I_PTR_DECL:.*]]:2 = hlfir.declare %[[I_PTR_REF]] ! CHECK-DAG: %[[S_PTR_REF:.*]] = fir.alloca !fir.box> {bindc_name = "sptr", uniq_name = "_QFloop_with_pointer_variablesEsptr"} ! CHECK-DAG: %[[S_PTR_DECL:.*]]:2 = hlfir.declare %[[S_PTR_REF]] ! CHECK-DAG: %[[ST_PTR_REF:.*]] = fir.alloca !fir.box> {bindc_name = "stptr", uniq_name = "_QFloop_with_pointer_variablesEstptr"} ! CHECK-DAG: %[[ST_PTR_DECL:.*]]:2 = hlfir.declare %[[ST_PTR_REF]] integer, target :: i integer, target :: s, e, st integer, pointer :: iptr, sptr, eptr, stptr ! CHECK: %[[I_PTR:.*]] = fir.embox %[[I_DECL]]#0 : (!fir.ref) -> !fir.box> ! CHECK: fir.store %[[I_PTR]] to %[[I_PTR_DECL]]#0 : !fir.ref>> iptr => i sptr => s eptr => e stptr => st ! CHECK: %[[I_BOX:.*]] = fir.load %[[I_PTR_DECL]]#0 : !fir.ref>> ! CHECK: %[[I_PTR:.*]] = fir.box_addr %[[I_BOX]] : (!fir.box>) -> !fir.ptr ! CHECK: %[[S_BOX:.*]] = fir.load %[[S_PTR_DECL]]#0 : !fir.ref>> ! CHECK: %[[S_PTR:.*]] = fir.box_addr %[[S_BOX]] : (!fir.box>) -> !fir.ptr ! CHECK: %[[S:.*]] = fir.load %[[S_PTR]] : !fir.ptr ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i32) -> index ! CHECK: %[[E_BOX:.*]] = fir.load %[[E_PTR_DECL]]#0 : !fir.ref>> ! CHECK: %[[E_PTR:.*]] = fir.box_addr %[[E_BOX]] : (!fir.box>) -> !fir.ptr ! CHECK: %[[E:.*]] = fir.load %[[E_PTR]] : !fir.ptr ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index ! CHECK: %[[ST_BOX:.*]] = fir.load %[[ST_PTR_DECL]]#0 : !fir.ref>> ! CHECK: %[[ST_PTR:.*]] = fir.box_addr %[[ST_BOX]] : (!fir.box>) -> !fir.ptr ! CHECK: %[[ST:.*]] = fir.load %[[ST_PTR]] : !fir.ptr ! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i32) -> index ! CHECK: %[[I_LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i32 ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] = ! CHECK-SAME: %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i32) { do iptr=sptr,eptr,stptr ! CHECK: fir.store %[[I_IV]] to %[[I_PTR]] : !fir.ptr ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[ST_CVT]] : (index) -> i32 ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_PTR]] : !fir.ptr ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow : i32 ! CHECK: fir.result %[[I_IVINC]] : i32 end do ! CHECK: } ! CHECK: fir.store %[[I_RES]] to %[[I_PTR]] : !fir.ptr end subroutine ! Test usage of non-default integer kind for loop control and loop index variable ! CHECK-LABEL: loop_with_non_default_integer ! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref {fir.bindc_name = "st"}) { subroutine loop_with_non_default_integer(s,e,st) ! CHECK-DAG: %[[E_DECL:.*]]:2 = hlfir.declare %[[E_REF]] ! CHECK-DAG: %[[S_DECL:.*]]:2 = hlfir.declare %[[S_REF]] ! CHECK-DAG: %[[ST_DECL:.*]]:2 = hlfir.declare %[[ST_REF]] ! CHECK-DAG: %[[I_REF:.*]] = fir.alloca i64 {bindc_name = "i", uniq_name = "_QFloop_with_non_default_integerEi"} ! CHECK-DAG: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] integer(kind=8):: i ! CHECK: %[[S:.*]] = fir.load %[[S_DECL]]#0 : !fir.ref ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i64) -> index ! CHECK: %[[E:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i64) -> index ! CHECK: %[[ST:.*]] = fir.load %[[ST_DECL]]#0 : !fir.ref ! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i64) -> index integer(kind=8) :: s, e, st ! CHECK: %[[I_LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i64 ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] = ! CHECK-SAME: %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i64) { do i=s,e,st ! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[ST_CVT]] : (index) -> i64 ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow : i64 ! CHECK: fir.result %[[I_IVINC]] : i64 end do ! CHECK: } ! CHECK: fir.store %[[I_RES]] to %[[I_DECL]]#0 : !fir.ref end subroutine ! Test real loop control. ! CHECK-LABEL: loop_with_real_control ! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref {fir.bindc_name = "st"}) { subroutine loop_with_real_control(s,e,st) ! CHECK-DAG: %[[INDEX_REF:.*]] = fir.alloca index ! CHECK-DAG: %[[X_REF:.*]] = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFloop_with_real_controlEx"} ! CHECK-DAG: %[[X_DECL:.*]]:2 = hlfir.declare %[[X_REF]] ! CHECK-DAG: %[[E_DECL:.*]]:2 = hlfir.declare %[[E_REF]] ! CHECK-DAG: %[[S_DECL:.*]]:2 = hlfir.declare %[[S_REF]] ! CHECK-DAG: %[[ST_DECL:.*]]:2 = hlfir.declare %[[ST_REF]] ! CHECK: %[[S:.*]] = fir.load %[[S_DECL]]#0 : !fir.ref ! CHECK: %[[E:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref ! CHECK: %[[ST:.*]] = fir.load %[[ST_DECL]]#0 : !fir.ref ! CHECK: fir.store %[[ST]] to %[[ST_VAR:.*]] : !fir.ref real :: x, s, e, st ! CHECK: %[[DIFF:.*]] = arith.subf %[[E]], %[[S]] {{.*}}: f32 ! CHECK: %[[RANGE:.*]] = arith.addf %[[DIFF]], %[[ST]] {{.*}}: f32 ! CHECK: %[[HIGH:.*]] = arith.divf %[[RANGE]], %[[ST]] {{.*}}: f32 ! CHECK: %[[HIGH_INDEX:.*]] = fir.convert %[[HIGH]] : (f32) -> index ! CHECK: fir.store %[[HIGH_INDEX]] to %[[INDEX_REF]] : !fir.ref ! CHECK: fir.store %[[S]] to %[[X_DECL]]#0 : !fir.ref ! CHECK: br ^[[HDR:.*]] ! CHECK: ^[[HDR]]: // 2 preds: ^{{.*}}, ^[[EXIT:.*]] ! CHECK-DAG: %[[INDEX:.*]] = fir.load %[[INDEX_REF]] : !fir.ref ! CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index ! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[INDEX]], %[[C0]] : index ! CHECK: cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]] do x=s,e,st ! CHECK: ^[[BODY]]: // pred: ^[[HDR]] ! CHECK-DAG: %[[INDEX2:.*]] = fir.load %[[INDEX_REF]] : !fir.ref ! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index ! CHECK: %[[INC:.*]] = arith.subi %[[INDEX2]], %[[C1]] : index ! CHECK: fir.store %[[INC]] to %[[INDEX_REF]] : !fir.ref ! CHECK: %[[X2:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref ! CHECK: %[[ST_VAL:.*]] = fir.load %[[ST_VAR]] : !fir.ref ! CHECK: %[[XINC:.*]] = arith.addf %[[X2]], %[[ST_VAL]] {{.*}}: f32 ! CHECK: fir.store %[[XINC]] to %[[X_DECL]]#0 : !fir.ref ! CHECK: br ^[[HDR]] end do end subroutine