CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
287 lines
12 KiB
MLIR
287 lines
12 KiB
MLIR
// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \
|
|
// RUN: -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s
|
|
|
|
// -----
|
|
|
|
// Distinct fir.alloca in each branch; unrelated fir.alloca outside the if.
|
|
// CHECK-LABEL: Testing : "test_rb_both_alloc_distinct"
|
|
// CHECK-DAG: outside_alloc#0 <-> join_alloc#0: NoAlias
|
|
|
|
func.func @test_rb_both_alloc_distinct() {
|
|
%cond = arith.constant true
|
|
%a_out = fir.alloca f32 {uniq_name = "_QFEa_out"}
|
|
%d_out = fir.declare %a_out {uniq_name = "_QFEa_out", test.ptr = "outside_alloc"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%jf = fir.if %cond -> !fir.ref<f32> {
|
|
%a1 = fir.alloca f32 {uniq_name = "_QFEa1"}
|
|
%d1 = fir.declare %a1 {uniq_name = "_QFEa1"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
fir.result %d1 : !fir.ref<f32>
|
|
} else {
|
|
%a2 = fir.alloca f32 {uniq_name = "_QFEa2"}
|
|
%d2 = fir.declare %a2 {uniq_name = "_QFEa2"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
fir.result %d2 : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_alloc"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Each branch yields different fir.declare which means that the
|
|
// origin is from either - this case is handled as Indirect.
|
|
// CHECK-LABEL: Testing : "test_rb_both_alloc_distinct_outer_scope"
|
|
// CHECK-DAG: d1#0 <-> join_outer#0: MayAlias
|
|
// CHECK-DAG: d2#0 <-> join_outer#0: MayAlias
|
|
// CHECK-DAG: outside_outer#0 <-> join_outer#0: MayAlias
|
|
|
|
func.func @test_rb_both_alloc_distinct_outer_scope() {
|
|
%cond = arith.constant true
|
|
%a1 = fir.alloca f32 {uniq_name = "_QFEa1o"}
|
|
%a2 = fir.alloca f32 {uniq_name = "_QFEa2o"}
|
|
%d1 = fir.declare %a1 {uniq_name = "_QFEa1o", test.ptr = "d1"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%d2 = fir.declare %a2 {uniq_name = "_QFEa2o", test.ptr = "d2"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%a_ext = fir.alloca f32 {uniq_name = "_QFEa_ext_o"}
|
|
%d_ext = fir.declare %a_ext {uniq_name = "_QFEa_ext_o", test.ptr = "outside_outer"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%jf = fir.if %cond -> !fir.ref<f32> {
|
|
fir.result %d1 : !fir.ref<f32>
|
|
} else {
|
|
fir.result %d2 : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_outer"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Both branches yield the same fir.declare from outside.
|
|
// CHECK-LABEL: Testing : "test_rb_both_alloc_same_decl"
|
|
// CHECK-DAG: shared_decl#0 <-> join_same#0: MustAlias
|
|
|
|
func.func @test_rb_both_alloc_same_decl() {
|
|
%cond = arith.constant true
|
|
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
|
%da = fir.declare %a {uniq_name = "_QFEa", test.ptr = "shared_decl"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%jf = fir.if %cond -> !fir.ref<f32> {
|
|
fir.result %da : !fir.ref<f32>
|
|
} else {
|
|
fir.result %da : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_same"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// An example of conservative behavior where one branch return value comes from
|
|
// outside. Because at the merge we do not find a common origin and since there's
|
|
// currently no way to record multiple origins, we fallback to MayAlias.
|
|
// TODO: Ideally this should be NoAlias
|
|
// CHECK-LABEL: Testing : "test_rb_alloc_outer_vs_inner"
|
|
// CHECK-DAG: outside_neither#0 <-> join_oi#0: MayAlias
|
|
|
|
func.func @test_rb_alloc_outer_vs_inner() {
|
|
%cond = arith.constant true
|
|
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
|
%da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%a_neither = fir.alloca f32 {uniq_name = "_QFEa_neither"}
|
|
%d_neither = fir.declare %a_neither {uniq_name = "_QFEa_neither", test.ptr = "outside_neither"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%jf = fir.if %cond -> !fir.ref<f32> {
|
|
fir.result %da : !fir.ref<f32>
|
|
} else {
|
|
%a_else = fir.alloca f32 {uniq_name = "_QFEa_else"}
|
|
%d_else = fir.declare %a_else {uniq_name = "_QFEa_else"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
fir.result %d_else : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_oi"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
fir.global @rb_merge_g : f32 {
|
|
%0 = arith.constant 0.0 : f32
|
|
fir.has_value %0 : f32
|
|
}
|
|
|
|
// Both branches yield the same global.
|
|
// CHECK-LABEL: Testing : "test_rb_both_same_global"
|
|
// CHECK-DAG: global_decl#0 <-> join_g#0: MustAlias
|
|
|
|
func.func @test_rb_both_same_global() {
|
|
%cond = arith.constant true
|
|
%addr = fir.address_of(@rb_merge_g) : !fir.ref<f32>
|
|
%dg = fir.declare %addr {uniq_name = "_QErb_merge_g", test.ptr = "global_decl"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%jf = fir.if %cond -> !fir.ref<f32> {
|
|
fir.result %dg : !fir.ref<f32>
|
|
} else {
|
|
fir.result %dg : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_g"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Both branches yield the same dummy argument.
|
|
// CHECK-LABEL: Testing : "test_rb_both_same_argument"
|
|
// CHECK-DAG: decl_arg#0 <-> join_arg#0: MustAlias
|
|
|
|
func.func @test_rb_both_same_argument(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) {
|
|
%cond = arith.constant true
|
|
%ds = fir.dummy_scope : !fir.dscope
|
|
%dx = fir.declare %arg0 dummy_scope %ds arg 1 {uniq_name = "_QFEex", test.ptr = "decl_arg"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
|
|
%jf = fir.if %cond -> !fir.ref<f32> {
|
|
fir.result %dx : !fir.ref<f32>
|
|
} else {
|
|
fir.result %dx : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_arg"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
fir.global @rb_side_g : f32 {
|
|
%0 = arith.constant 0.0 : f32
|
|
fir.has_value %0 : f32
|
|
}
|
|
|
|
// Merged kinds differ (Allocate vs Global) thus conservative MayAlias
|
|
// (and this would be the case even if we tracked multiple origins).
|
|
// CHECK-LABEL: Testing : "test_rb_merged_unknown_global_vs_alloc"
|
|
// CHECK-DAG: outside_mixed#0 <-> join_mixed#0: MayAlias
|
|
|
|
func.func @test_rb_merged_unknown_global_vs_alloc() {
|
|
%cond = arith.constant true
|
|
%addr = fir.address_of(@rb_side_g) : !fir.ref<f32>
|
|
%dg = fir.declare %addr {uniq_name = "_QErb_side_g"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
|
%da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%a_by = fir.alloca f32 {uniq_name = "_QFEa_by"}
|
|
%d_by = fir.declare %a_by {uniq_name = "_QFEa_by", test.ptr = "outside_mixed"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%jf = fir.if %cond -> !fir.ref<f32> {
|
|
fir.result %dg : !fir.ref<f32>
|
|
} else {
|
|
fir.result %da : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_mixed"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Distinct fir.alloca in each branch with mismatched Fortran attrs on the declares;
|
|
// despite being different allocations inside the branches, we give conservative
|
|
// response. This is primarily to test that the attribute merge is working but
|
|
// this pattern is unlikely to be generated from real Fortran code.
|
|
// CHECK-LABEL: Testing : "test_rb_merged_unknown_attr_mismatch"
|
|
// CHECK-DAG: outside_attr#0 <-> join_attr#0: MayAlias
|
|
|
|
func.func @test_rb_merged_unknown_attr_mismatch() {
|
|
%cond = arith.constant true
|
|
%a_ext = fir.alloca f32 {uniq_name = "_QFEa_attr_ext"}
|
|
%d_ext = fir.declare %a_ext {uniq_name = "_QFEa_attr_ext", test.ptr = "outside_attr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%jf = fir.if %cond -> !fir.ref<f32> {
|
|
%a1 = fir.alloca f32 {uniq_name = "_QFEa1"}
|
|
%dt = fir.declare %a1 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEa1"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
fir.result %dt : !fir.ref<f32>
|
|
} else {
|
|
%a2 = fir.alloca f32 {uniq_name = "_QFEa2"}
|
|
%dp = fir.declare %a2 {uniq_name = "_QFEa2"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
fir.result %dp : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_attr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// One branch yields the dummy box, the other yields fir.pack_array of the same
|
|
// box (approximateSource on that predecessor). Join is disambiguated from a
|
|
// different dummy argument's data.
|
|
// CHECK-LABEL: Testing : "test_rb_merge_one_branch_pack_array"
|
|
// CHECK-DAG: join_pack#0 <-> other_arg_box#0: NoAlias
|
|
|
|
func.func @test_rb_merge_one_branch_pack_array(
|
|
%arg0: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x"},
|
|
%arg1: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "y"}) {
|
|
%c = arith.constant true
|
|
%packed = fir.pack_array %arg0 heap whole : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
|
|
%jf = fir.if %c -> !fir.box<!fir.array<?xf32>> {
|
|
fir.result %arg0 : !fir.box<!fir.array<?xf32>>
|
|
} else {
|
|
fir.result %packed : !fir.box<!fir.array<?xf32>>
|
|
}
|
|
%join = fir.convert %jf {test.ptr = "join_pack"} : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
|
|
%other = fir.convert %arg1 {test.ptr = "other_arg_box"} : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// OPTIONAL pattern tested against an unrelated fir.alloca.
|
|
// CHECK-LABEL: Testing : "test_rb_optional_ref_present_absent"
|
|
// CHECK-DAG: outside_opt#0 <-> opt_join#0: NoAlias
|
|
|
|
func.func @test_rb_optional_ref_present_absent(%arg0: !fir.ref<i32> {fir.bindc_name = "x", fir.optional}) {
|
|
%present = fir.is_present %arg0 : (!fir.ref<i32>) -> i1
|
|
%a_ext = fir.alloca i32 {uniq_name = "_QFEopt_ext"}
|
|
%d_ext = fir.declare %a_ext {uniq_name = "_QFEopt_ext", test.ptr = "outside_opt"} : (!fir.ref<i32>) -> !fir.ref<i32>
|
|
%slot = fir.if %present -> !fir.ref<i32> {
|
|
%a = fir.alloca i32 {uniq_name = "_QFEopt"}
|
|
%d = fir.declare %a {uniq_name = "_QFEopt"} : (!fir.ref<i32>) -> !fir.ref<i32>
|
|
fir.result %d : !fir.ref<i32>
|
|
} else {
|
|
%abs = fir.absent !fir.ref<i32>
|
|
fir.result %abs : !fir.ref<i32>
|
|
}
|
|
%join = fir.convert %slot {test.ptr = "opt_join"} : (!fir.ref<i32>) -> !fir.ref<i32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Same OPTIONAL idea as above, but the unrelated fir.alloca outside the if is
|
|
// declared with TARGET: join should still not alias that unrelated storage.
|
|
// CHECK-LABEL: Testing : "test_rb_optional_ref_outside_target"
|
|
// CHECK-DAG: outside_opt_tgt#0 <-> opt_join_tgt#0: NoAlias
|
|
|
|
func.func @test_rb_optional_ref_outside_target(%arg0: !fir.ref<i32> {fir.bindc_name = "x", fir.optional}) {
|
|
%present = fir.is_present %arg0 : (!fir.ref<i32>) -> i1
|
|
%a_ext = fir.alloca i32 {uniq_name = "_QFEopt_ext_t"}
|
|
%d_ext = fir.declare %a_ext {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEopt_ext_t", test.ptr = "outside_opt_tgt"} : (!fir.ref<i32>) -> !fir.ref<i32>
|
|
%slot = fir.if %present -> !fir.ref<i32> {
|
|
%a = fir.alloca i32 {uniq_name = "_QFEopt_t"}
|
|
%d = fir.declare %a {uniq_name = "_QFEopt_t"} : (!fir.ref<i32>) -> !fir.ref<i32>
|
|
fir.result %d : !fir.ref<i32>
|
|
} else {
|
|
%abs = fir.absent !fir.ref<i32>
|
|
fir.result %abs : !fir.ref<i32>
|
|
}
|
|
%join = fir.convert %slot {test.ptr = "opt_join_tgt"} : (!fir.ref<i32>) -> !fir.ref<i32>
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Add loop test whose result is based on BlockArguments to ensure
|
|
// no cycle.
|
|
// CHECK-LABEL: Testing : "test_rb_do_loop_iter_carry_ref"
|
|
// CHECK-DAG: carry_init#0 <-> outside_loop#0: NoAlias
|
|
// CHECK-DAG: carry_init#0 <-> loop_join_ref#0: MayAlias
|
|
// CHECK-DAG: outside_loop#0 <-> loop_join_ref#0: MayAlias
|
|
|
|
func.func @test_rb_do_loop_iter_carry_ref() {
|
|
%lb = arith.constant 1 : index
|
|
%ub = arith.constant 2 : index
|
|
%st = arith.constant 1 : index
|
|
%a_carry = fir.alloca f32 {uniq_name = "_QFEcarry"}
|
|
%d_carry = fir.declare %a_carry {uniq_name = "_QFEcarry", test.ptr = "carry_init"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%a_out = fir.alloca f32 {uniq_name = "_QFEoutside"}
|
|
%d_out = fir.declare %a_out {uniq_name = "_QFEoutside", test.ptr = "outside_loop"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
%loop_res = fir.do_loop %iv = %lb to %ub step %st iter_args(%carry = %d_carry) -> (!fir.ref<f32>) {
|
|
fir.result %carry : !fir.ref<f32>
|
|
}
|
|
%join = fir.convert %loop_res {test.ptr = "loop_join_ref"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
|
return
|
|
}
|