! Test lowering of WHERE construct and statements to HLFIR.
! RUN: bbc -emit-hlfir -o - %s | FileCheck %s

module where_defs
  logical :: mask(10)
  real :: x(10), y(10)
  real, allocatable :: a(:), b(:)
  interface
    function return_temporary_mask()
      logical, allocatable :: return_temporary_mask(:)
    end function
    function return_temporary_array()
      real, allocatable :: return_temporary_array(:)
    end function
  end interface
end module

subroutine simple_where()
  use where_defs, only: mask, x, y
  where (mask) x = y
end subroutine
! CHECK-LABEL:   func.func @_QPsimple_where() {
! CHECK:  %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Emask
! CHECK:  %[[VAL_7:.*]]:2 = hlfir.declare {{.*}}Ex
! CHECK:  %[[VAL_11:.*]]:2 = hlfir.declare {{.*}}Ey
! CHECK:  hlfir.where {
! CHECK:    hlfir.yield %[[VAL_3]]#0 : !fir.ref<!fir.array<10x!fir.logical<4>>>
! CHECK:  } do {
! CHECK:    hlfir.region_assign {
! CHECK:      hlfir.yield %[[VAL_11]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    } to {
! CHECK:      hlfir.yield %[[VAL_7]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    }
! CHECK:  }
! CHECK:  return
! CHECK:}

subroutine where_construct()
  use where_defs
  where (mask)
    x = y
    a = b
  end where
end subroutine
! CHECK-LABEL:   func.func @_QPwhere_construct() {
! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMwhere_defsEa"}
! CHECK:  %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMwhere_defsEb"}
! CHECK:  %[[VAL_7:.*]]:2 = hlfir.declare {{.*}}Emask
! CHECK:  %[[VAL_11:.*]]:2 = hlfir.declare {{.*}}Ex
! CHECK:  %[[VAL_15:.*]]:2 = hlfir.declare {{.*}}Ey
! CHECK:  hlfir.where {
! CHECK:    hlfir.yield %[[VAL_7]]#0 : !fir.ref<!fir.array<10x!fir.logical<4>>>
! CHECK:  } do {
! CHECK:    hlfir.region_assign {
! CHECK:      hlfir.yield %[[VAL_15]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    } to {
! CHECK:      hlfir.yield %[[VAL_11]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    }
! CHECK:    hlfir.region_assign {
! CHECK:      %[[VAL_16:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
! CHECK:      hlfir.yield %[[VAL_16]] : !fir.box<!fir.heap<!fir.array<?xf32>>>
! CHECK:    } to {
! CHECK:      %[[VAL_17:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
! CHECK:      hlfir.yield %[[VAL_17]] : !fir.box<!fir.heap<!fir.array<?xf32>>>
! CHECK:    }
! CHECK:  }
! CHECK:  return
! CHECK:}

subroutine where_cleanup()
  use where_defs, only: x, return_temporary_mask, return_temporary_array
  where (return_temporary_mask()) x = return_temporary_array()
end subroutine
! CHECK-LABEL:   func.func @_QPwhere_cleanup() {
! CHECK:  %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = ".result"}
! CHECK:  %[[VAL_1:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>> {bindc_name = ".result"}
! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Ex
! CHECK:  hlfir.where {
! CHECK:    %[[VAL_6:.*]] = fir.call @_QPreturn_temporary_mask() fastmath<contract> : () -> !fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>
! CHECK:    fir.save_result %[[VAL_6]] to %[[VAL_1]] : !fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
! CHECK:    %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>)
! CHECK:             %[[deref:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
! CHECK:             %[[MustFree:.*]] = arith.constant false
! CHECK:             %[[ResTemp:.*]] = hlfir.as_expr %[[deref]] move %[[MustFree]] : (!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>, i1) -> !hlfir.expr<?x!fir.logical<4>>
! CHECK:             hlfir.yield %[[ResTemp]] : !hlfir.expr<?x!fir.logical<4>> cleanup {
! CHECK:        fir.freemem
! CHECK:    }
! CHECK:  } do {
! CHECK:    hlfir.region_assign {
! CHECK:      %[[VAL_14:.*]] = fir.call @_QPreturn_temporary_array() fastmath<contract> : () -> !fir.box<!fir.heap<!fir.array<?xf32>>>
! CHECK:      fir.save_result %[[VAL_14]] to %[[VAL_0]] : !fir.box<!fir.heap<!fir.array<?xf32>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
! CHECK:      %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
! CHECK:               %[[deref:.*]] = fir.load %[[VAL_15]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
! CHECK:               %[[MustFree:.*]] = arith.constant false
! CHECK:               %[[ResTemp:.*]] = hlfir.as_expr %[[deref]] move %[[MustFree]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>, i1) -> !hlfir.expr<?xf32>
! CHECK:               hlfir.yield %[[ResTemp]] : !hlfir.expr<?xf32> cleanup {
! CHECK:          fir.freemem
! CHECK:      }
! CHECK:    } to {
! CHECK:      hlfir.yield %[[VAL_5]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    }
! CHECK:  }

subroutine simple_elsewhere()
  use where_defs
  where (mask)
    x = y
  elsewhere
    y = x
  end where
end subroutine
! CHECK-LABEL:   func.func @_QPsimple_elsewhere() {
! CHECK:  %[[VAL_7:.*]]:2 = hlfir.declare {{.*}}Emask
! CHECK:  %[[VAL_11:.*]]:2 = hlfir.declare {{.*}}Ex
! CHECK:  %[[VAL_15:.*]]:2 = hlfir.declare {{.*}}Ey
! CHECK:  hlfir.where {
! CHECK:    hlfir.yield %[[VAL_7]]#0 : !fir.ref<!fir.array<10x!fir.logical<4>>>
! CHECK:  } do {
! CHECK:    hlfir.region_assign {
! CHECK:      hlfir.yield %[[VAL_15]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    } to {
! CHECK:      hlfir.yield %[[VAL_11]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    }
! CHECK:    hlfir.elsewhere do {
! CHECK:      hlfir.region_assign {
! CHECK:        hlfir.yield %[[VAL_11]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:      } to {
! CHECK:        hlfir.yield %[[VAL_15]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:      }
! CHECK:    }
! CHECK:  }

subroutine elsewhere_2(mask2)
  use where_defs, only : mask, x, y
  logical :: mask2(:)
  where (mask)
    x = y
  elsewhere(mask2)
    y = x
  elsewhere
    x = foo()
  end where
end subroutine
! CHECK-LABEL:   func.func @_QPelsewhere_2(
! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Emask
! CHECK:  %[[VAL_6:.*]]:2 = hlfir.declare {{.*}}Emask2
! CHECK:  %[[VAL_11:.*]]:2 = hlfir.declare {{.*}}Ex
! CHECK:  %[[VAL_15:.*]]:2 = hlfir.declare {{.*}}Ey
! CHECK:  hlfir.where {
! CHECK:    hlfir.yield %[[VAL_5]]#0 : !fir.ref<!fir.array<10x!fir.logical<4>>>
! CHECK:  } do {
! CHECK:    hlfir.region_assign {
! CHECK:      hlfir.yield %[[VAL_15]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    } to {
! CHECK:      hlfir.yield %[[VAL_11]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:    }
! CHECK:    hlfir.elsewhere mask {
! CHECK:      hlfir.yield %[[VAL_6]]#0 : !fir.box<!fir.array<?x!fir.logical<4>>>
! CHECK:    } do {
! CHECK:      hlfir.region_assign {
! CHECK:        hlfir.yield %[[VAL_11]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:      } to {
! CHECK:        hlfir.yield %[[VAL_15]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:      }
! CHECK:      hlfir.elsewhere do {
! CHECK:        hlfir.region_assign {
! CHECK:          %[[VAL_16:.*]] = fir.call @_QPfoo() fastmath<contract> : () -> f32
! CHECK:          hlfir.yield %[[VAL_16]] : f32
! CHECK:        } to {
! CHECK:          hlfir.yield %[[VAL_11]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK:        }
! CHECK:      }
! CHECK:    }
! CHECK:  }
