| !===----------------------------------------------------------------------===! |
| ! This directory can be used to add Integration tests involving multiple |
| ! stages of the compiler (for eg. from Fortran to LLVM IR). It should not |
| ! contain executable tests. We should only add tests here sparingly and only |
| ! if there is no other way to test. Repeat this message in each test that is |
| ! added to this directory and sub-directories. |
| !===----------------------------------------------------------------------===! |
| |
| ! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | tco -test-gen | FileCheck %s --check-prefixes=HOST,ALL |
| ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-is-target-device %s -o - | tco -test-gen | FileCheck %s --check-prefixes=DEVICE,ALL |
| |
| ! Test that OpenMP target regions in dead code are deleted from both host and |
| ! target device. |
| |
| ! Test 1: if (.false.) with target - target should be deleted |
| ! HOST-LABEL: llvm.func @_QPtest_dead_simple |
| ! HOST-NOT: omp.target |
| ! HOST: llvm.return |
| ! DEVICE-NOT: llvm.func @_QPtest_dead_simple |
| subroutine test_dead_simple() |
| real :: v |
| if (.false.) then |
| !$omp target map(tofrom:v) |
| v = 1.0 |
| !$omp end target |
| end if |
| end subroutine |
| |
| ! Test 2: Live target - should remain |
| ! ALL-LABEL: llvm.func @_QPtest_live_simple |
| ! ALL: omp.target |
| ! ALL: llvm.return |
| subroutine test_live_simple() |
| real :: v |
| if (.true.) then |
| !$omp target map(tofrom:v) |
| v = 2.0 |
| !$omp end target |
| end if |
| end subroutine |
| |
| ! Test 3: Mixed dead and live |
| ! ALL-LABEL: llvm.func @_QPtest_mixed |
| subroutine test_mixed() |
| real :: v |
| ! Dead - should be deleted |
| ! ALL-NOT: {{.*}} = llvm.mlir.constant(3.0{{.*}} : f32) |
| if (.false.) then |
| !$omp target map(tofrom:v) |
| v = 3.0 |
| !$omp end target |
| end if |
| |
| ! Live - should remain |
| !$omp target map(tofrom:v) |
| ! ALL: omp.target |
| ! ALL: {{.*}} = llvm.mlir.constant(4.0{{.*}} : f32) |
| v = 4.0 |
| !$omp end target |
| |
| ! Expect exactly 1 omp.target in function |
| ! ALL-NOT: omp.target |
| ! ALL: llvm.return |
| end subroutine |
| |
| ! Test 4: Nested - outer false, target should be deleted |
| ! HOST-LABEL: llvm.func @_QPtest_nested_outer_false |
| ! HOST-NOT: omp.target |
| ! HOST: llvm.return |
| ! DEVICE-NOT: llvm.func @_QPtest_nested_outer_false |
| subroutine test_nested_outer_false() |
| real :: v |
| if (.false.) then |
| if (.true.) then |
| !$omp target map(tofrom:v) |
| v = 5.0 |
| !$omp end target |
| end if |
| end if |
| end subroutine |
| |
| ! Test 5: Nested - inner false, target should be deleted |
| ! HOST-LABEL: llvm.func @_QPtest_nested_inner_false |
| ! HOST-NOT: omp.target |
| ! HOST: llvm.return |
| ! DEVICE-NOT: llvm.func @_QPtest_nested_inner_false |
| subroutine test_nested_inner_false() |
| real :: v |
| if (.true.) then |
| if (.false.) then |
| !$omp target map(tofrom:v) |
| v = 6.0 |
| !$omp end target |
| end if |
| end if |
| end subroutine |
| |
| ! Test 6: Nested - both true, target should remain |
| ! ALL-LABEL: llvm.func @_QPtest_nested_both_true |
| ! ALL: omp.target |
| ! ALL: llvm.return |
| subroutine test_nested_both_true() |
| real :: v |
| if (.true.) then |
| if (.true.) then |
| !$omp target map(tofrom:v) |
| v = 7.0 |
| !$omp end target |
| end if |
| end if |
| end subroutine |
| |
| ! Test 7: Multiple dead targets in dead branch - all should be deleted |
| ! HOST-LABEL: llvm.func @_QPtest_multiple_dead_targets |
| ! HOST-NOT: omp.target |
| ! HOST: llvm.return |
| ! DEVICE-NOT: llvm.func @_QPtest_multiple_dead_targets |
| subroutine test_multiple_dead_targets() |
| real :: v |
| if (.false.) then |
| !$omp target map(tofrom:v) |
| v = 8.0 |
| !$omp end target |
| !$omp target map(tofrom:v) |
| v = 9.0 |
| !$omp end target |
| !$omp target map(tofrom:v) |
| v = 10.0 |
| !$omp end target |
| end if |
| end subroutine |
| |
| ! Test 8: Parameter constant - target should be deleted |
| ! HOST-LABEL: llvm.func @_QPtest_parameter |
| ! HOST-NOT: omp.target |
| ! HOST: llvm.return |
| ! DEVICE-NOT: llvm.func @_QPtest_parameter |
| subroutine test_parameter() |
| real :: v |
| logical, parameter :: DEAD = .false. |
| if (DEAD) then |
| !$omp target map(tofrom:v) |
| v = 11.0 |
| !$omp end target |
| end if |
| end subroutine |
| |
| ! Test 9: Unused nested subroutine - target should be deleted |
| ! HOST-LABEL: llvm.func @_QPtest_outer |
| ! HOST-NOT: omp.target |
| ! HOST: llvm.return |
| ! DEVICE-NOT: llvm.func @_QPtest_outer |
| subroutine test_outer |
| implicit none |
| contains |
| subroutine unused_sub() |
| real :: v |
| !$omp target map(tofrom: v) |
| v = 12.0 |
| !$omp end target |
| end subroutine |
| end subroutine |
| |
| ! Test 10: if (.false.) with else - then-branch target deleted, else-branch remains |
| ! ALL-LABEL: llvm.func @_QPtest_if_else_false |
| subroutine test_if_else_false() |
| real :: v |
| ! Dead then-branch - target should be deleted |
| ! ALL-NOT: {{.*}} = llvm.mlir.constant(1.3{{.*}}e+01 : f32) |
| if (.false.) then |
| !$omp target map(tofrom:v) |
| v = 13.0 |
| !$omp end target |
| else |
| ! Live else-branch - target should remain |
| !$omp target map(tofrom:v) |
| ! ALL: omp.target |
| ! ALL: {{.*}} = llvm.mlir.constant(1.4{{.*}}e+01 : f32) |
| v = 14.0 |
| !$omp end target |
| end if |
| ! Expect exactly 1 omp.target in function |
| ! ALL-NOT: omp.target |
| ! ALL: llvm.return |
| end subroutine |
| |
| ! Test 11: Runtime condition - target should remain unchanged |
| ! ALL-LABEL: llvm.func @_QPtest_runtime_condition |
| ! ALL: omp.target |
| ! ALL: llvm.return |
| subroutine test_runtime_condition(cond) |
| logical, intent(in) :: cond |
| real :: v |
| if (cond) then |
| !$omp target map(tofrom:v) |
| v = 15.0 |
| !$omp end target |
| end if |
| end subroutine |
| |
| ! Test 12: Target nested in unreachable block - target should be deleted |
| ! ALL-LABEL: llvm.func @_QPtest_nested_in_unreachable_block |
| subroutine test_nested_in_unreachable_block() |
| real :: v |
| go to 10 |
| ! Unreachable block: even though condition is .true., the block itself is dead |
| ! ALL-NOT: {{.*}} = llvm.mlir.constant(1.6{{.*}}e+01 : f32) |
| if (.true.) then |
| !$omp target map(tofrom:v) |
| v = 16.0 |
| !$omp end target |
| end if |
| 10 continue |
| ! Reachable - target should remain |
| !$omp target map(tofrom:v) |
| ! ALL: omp.target |
| ! ALL: {{.*}} = llvm.mlir.constant(1.7{{.*}}e+01 : f32) |
| v = 17.0 |
| !$omp end target |
| ! Expect exactly 1 omp.target in function |
| ! ALL-NOT: omp.target |
| ! ALL: llvm.return |
| end subroutine |
| |
| ! Test 13: Multiple targets in unreachable blocks - all should be deleted |
| ! ALL-LABEL: llvm.func @_QPtest_multiple_unreachable_blocks |
| subroutine test_multiple_unreachable_blocks() |
| real :: v |
| go to 30 |
| ! First unreachable block - target should be deleted |
| ! ALL-NOT: {{.*}} = llvm.mlir.constant(1.8{{.*}}e+01 : f32) |
| !$omp target map(tofrom:v) |
| v = 18.0 |
| !$omp end target |
| go to 20 |
| 20 continue |
| ! Second unreachable block (only reachable from first unreachable block) |
| ! ALL-NOT: {{.*}} = llvm.mlir.constant(1.9{{.*}}e+01 : f32) |
| !$omp target map(tofrom:v) |
| v = 19.0 |
| !$omp end target |
| 30 continue |
| ! Reachable from entry - target should remain |
| !$omp target map(tofrom:v) |
| ! ALL: omp.target |
| ! ALL: {{.*}} = llvm.mlir.constant(2.0{{.*}}e+01 : f32) |
| v = 20.0 |
| !$omp end target |
| ! Expect exactly 1 omp.target in function |
| ! ALL-NOT: omp.target |
| ! ALL: llvm.return |
| end subroutine |
| |
| ! Test 14: Both branches reachable - all targets should remain |
| ! ALL-LABEL: llvm.func @_QPtest_both_branches_reachable |
| ! ALL: omp.target |
| ! ALL: omp.target |
| ! ALL: llvm.return |
| subroutine test_both_branches_reachable(cond) |
| logical, intent(in) :: cond |
| real :: v |
| if (cond) then |
| !$omp target map(tofrom:v) |
| v = 21.0 |
| !$omp end target |
| else |
| !$omp target map(tofrom:v) |
| v = 22.0 |
| !$omp end target |
| end if |
| end subroutine |