Skip to content

Commit 50db7a7

Browse files
authored
[flang] Fixed fir.dummy_scope generation to work for TBAA. (#136382)
The nesting of fir.dummy_scope operations defines the roots of the TBAA forest. If we do not generate fir.dummy_scope in functions that do not have any dummy arguments, then the globals accessed in the function and the dummy arguments accessed by the callee may end up in different sub-trees of the same root. The added tbaa-with-dummy-scope2.fir demonstrates the issue.
1 parent db97d56 commit 50db7a7

File tree

7 files changed

+167
-2
lines changed

7 files changed

+167
-2
lines changed

flang/lib/Lower/Bridge.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5508,7 +5508,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
55085508
for (const Fortran::lower::CalleeInterface::PassedEntity &arg :
55095509
callee.getPassedArguments())
55105510
mapPassedEntity(arg);
5511-
if (lowerToHighLevelFIR() && !callee.getPassedArguments().empty()) {
5511+
5512+
// Always generate fir.dummy_scope even if there are no arguments.
5513+
// It is currently used to create proper TBAA forest.
5514+
if (lowerToHighLevelFIR()) {
55125515
mlir::Value scopeOp = builder->create<fir::DummyScopeOp>(toLocation());
55135516
setDummyArgsScope(scopeOp);
55145517
}

flang/test/Driver/emit-mlir.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
! CHECK-SAME: dlti.dl_spec =
1414
! CHECK-SAME: llvm.data_layout =
1515
! CHECK-LABEL: func @_QQmain() {
16+
! CHECK-NEXT: fir.dummy_scope
1617
! CHECK-NEXT: return
1718
! CHECK-NEXT: }
1819
! CHECK-NEXT: func.func private @_FortranAProgramStart(i32, !llvm.ptr, !llvm.ptr, !llvm.ptr)

flang/test/Lower/HLFIR/calls-f77.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ subroutine call_no_arg()
99
call void()
1010
end subroutine
1111
! CHECK-LABEL: func.func @_QPcall_no_arg() {
12+
! CHECK-NEXT: fir.dummy_scope
1213
! CHECK-NEXT: fir.call @_QPvoid() fastmath<contract> : () -> ()
1314
! CHECK-NEXT: return
1415

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
! RUN: bbc -emit-hlfir %s -o - | FileCheck %s
2+
3+
! Test fir.dummy_scope assignment to argument x
4+
subroutine sub_arg(x)
5+
integer :: x
6+
end subroutine sub_arg
7+
! CHECK-LABEL: func.func @_QPsub_arg(
8+
! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<i32> {fir.bindc_name = "x"}) {
9+
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
10+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFsub_argEx"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
11+
! CHECK: return
12+
! CHECK: }
13+
14+
! Test fir.dummy_scope is created even when there are no arguments.
15+
subroutine sub_noarg
16+
end subroutine sub_noarg
17+
! CHECK-LABEL: func.func @_QPsub_noarg() {
18+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
19+
! CHECK: return
20+
! CHECK: }
21+
22+
! Test fir.dummy_scope assignment to argument x
23+
function func_arg(x)
24+
integer :: x, func_arg
25+
func_arg = x
26+
end function func_arg
27+
! CHECK-LABEL: func.func @_QPfunc_arg(
28+
! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<i32> {fir.bindc_name = "x"}) -> i32 {
29+
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
30+
! CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "func_arg", uniq_name = "_QFfunc_argEfunc_arg"}
31+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFfunc_argEfunc_arg"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
32+
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFfunc_argEx"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
33+
! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<i32>
34+
! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_3]]#0 : i32, !fir.ref<i32>
35+
! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
36+
! CHECK: return %[[VAL_6]] : i32
37+
! CHECK: }
38+
39+
! Test fir.dummy_scope is created even when there are no arguments.
40+
function func_noarg
41+
integer :: func_noarg
42+
func_noarg = 1
43+
end function func_noarg
44+
! CHECK-LABEL: func.func @_QPfunc_noarg() -> i32 {
45+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
46+
! CHECK: %[[VAL_1:.*]] = fir.alloca i32 {bindc_name = "func_noarg", uniq_name = "_QFfunc_noargEfunc_noarg"}
47+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFfunc_noargEfunc_noarg"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
48+
! CHECK: %[[VAL_3:.*]] = arith.constant 1 : i32
49+
! CHECK: hlfir.assign %[[VAL_3]] to %[[VAL_2]]#0 : i32, !fir.ref<i32>
50+
! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<i32>
51+
! CHECK: return %[[VAL_4]] : i32
52+
! CHECK: }

flang/test/Lower/OpenMP/real10.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
!RUN: %flang_fc1 -emit-hlfir -fopenmp -triple amdgcn -fopenmp -fopenmp-is-target-device -o - %s | FileCheck %s
44

5-
!CHECK: hlfir.declare %0 {uniq_name = "_QFEx"} : (!fir.ref<f80>) -> (!fir.ref<f80>, !fir.ref<f80>)
5+
!CHECK: hlfir.declare %{{.*}} {uniq_name = "_QFEx"} : (!fir.ref<f80>) -> (!fir.ref<f80>, !fir.ref<f80>)
66

77
program p
88
real(10) :: x

flang/test/Lower/main_location.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
end
1313

1414
! TEST1: func.func @_QQmain() {
15+
! TEST1-NEXT: fir.dummy_scope : !fir.dscope loc("{{.*}}test1.f90":1:1)
1516
! TEST1-NEXT: return loc("{{.*}}test1.f90":3:1)
1617
! TEST1-NEXT: } loc("{{.*}}test1.f90":1:1)
1718

@@ -22,5 +23,6 @@
2223
end program
2324

2425
! TEST2: func.func @_QQmain() {
26+
! TEST2-NEXT: fir.dummy_scope : !fir.dscope loc("{{.*}}test2.f90":2:1)
2527
! TEST2-NEXT: return loc("{{.*}}test2.f90":4:1)
2628
! TEST2-NEXT: } loc("{{.*}}test2.f90":2:1)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// RUN: fir-opt --fir-add-alias-tags --split-input-file %s | FileCheck %s
2+
3+
// This test demonstrates the need for fir.dummy_scope even
4+
// when a function does not have dummy arguments.
5+
//
6+
// The original source is:
7+
// module m
8+
// integer :: glob
9+
// end module m
10+
// subroutine test1
11+
// use m
12+
// call inner(glob)
13+
// glob = 2
14+
// contains
15+
// subroutine inner(x)
16+
// integer :: x
17+
// integer :: y
18+
// y = 1
19+
// x = y
20+
// end subroutine inner
21+
// end subroutine test1
22+
//
23+
// 'inner' function is manually inlined in FIR.
24+
// When fir.dummy_scope is missing, TBAA tags for glob and x
25+
// are placed into the same TBAA root. Since glob is a global
26+
// and x is a dummy argument, TBAA ends up reporting no-alias
27+
// for them, which is incorrect.
28+
func.func @_QPtest1() attributes {noinline} {
29+
%c1_i32 = arith.constant 1 : i32
30+
%c2_i32 = arith.constant 2 : i32
31+
%0 = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFtest1FinnerEy"}
32+
%1 = fir.address_of(@_QMmEglob) : !fir.ref<i32>
33+
%2 = fir.declare %1 {uniq_name = "_QMmEglob"} : (!fir.ref<i32>) -> !fir.ref<i32>
34+
%3 = fir.dummy_scope : !fir.dscope
35+
%4 = fir.declare %2 dummy_scope %3 {uniq_name = "_QFtest1FinnerEx"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
36+
%5 = fir.declare %0 {uniq_name = "_QFtest1FinnerEy"} : (!fir.ref<i32>) -> !fir.ref<i32>
37+
fir.store %c1_i32 to %5 : !fir.ref<i32>
38+
%6 = fir.load %5 : !fir.ref<i32>
39+
fir.store %6 to %4 : !fir.ref<i32>
40+
fir.store %c2_i32 to %2 : !fir.ref<i32>
41+
return
42+
}
43+
// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest1">
44+
// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_0]], 0>}>
45+
// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_1]], 0>}>
46+
// CHECK: #[[$ATTR_3:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[$ATTR_2]], 0>}>
47+
// CHECK: #[[$ATTR_4:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_2]], 0>}>
48+
// CHECK: #[[$ATTR_5:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtest1FinnerEx", members = {<#[[$ATTR_3]], 0>}>
49+
// CHECK: #[[$ATTR_6:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMmEglob", members = {<#[[$ATTR_4]], 0>}>
50+
// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_5]], access_type = #[[$ATTR_5]], offset = 0>
51+
// CHECK: #[[$ATTR_8:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_6]], access_type = #[[$ATTR_6]], offset = 0>
52+
// CHECK-LABEL: func.func @_QPtest1() attributes {noinline} {
53+
// CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFtest1FinnerEy"}
54+
// CHECK: %[[VAL_3:.*]] = fir.address_of(@_QMmEglob) : !fir.ref<i32>
55+
// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_3]] {uniq_name = "_QMmEglob"} : (!fir.ref<i32>) -> !fir.ref<i32>
56+
// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope
57+
// CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_4]] dummy_scope %[[VAL_5]] {uniq_name = "_QFtest1FinnerEx"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
58+
// CHECK: %[[VAL_7:.*]] = fir.declare %[[VAL_2]] {uniq_name = "_QFtest1FinnerEy"} : (!fir.ref<i32>) -> !fir.ref<i32>
59+
// CHECK: fir.store %{{.*}} to %[[VAL_7]] : !fir.ref<i32>
60+
// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]] : !fir.ref<i32>
61+
// CHECK: fir.store %[[VAL_8]] to %[[VAL_6]] {tbaa = [#[[$ATTR_7]]]} : !fir.ref<i32>
62+
// CHECK: fir.store %{{.*}} to %[[VAL_4]] {tbaa = [#[[$ATTR_8]]]} : !fir.ref<i32>
63+
64+
// -----
65+
66+
// This test has fir.dummy_scope in place, and TBAA is correct.
67+
func.func @_QPtest2() attributes {noinline} {
68+
%c1_i32 = arith.constant 1 : i32
69+
%c2_i32 = arith.constant 2 : i32
70+
%0 = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFtest2FinnerEy"}
71+
%test_dummy_scope = fir.dummy_scope : !fir.dscope
72+
%1 = fir.address_of(@_QMmEglob) : !fir.ref<i32>
73+
%2 = fir.declare %1 {uniq_name = "_QMmEglob"} : (!fir.ref<i32>) -> !fir.ref<i32>
74+
%3 = fir.dummy_scope : !fir.dscope
75+
%4 = fir.declare %2 dummy_scope %3 {uniq_name = "_QFtest2FinnerEx"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
76+
%5 = fir.declare %0 {uniq_name = "_QFtest2FinnerEy"} : (!fir.ref<i32>) -> !fir.ref<i32>
77+
fir.store %c1_i32 to %5 : !fir.ref<i32>
78+
%6 = fir.load %5 : !fir.ref<i32>
79+
fir.store %6 to %4 : !fir.ref<i32>
80+
fir.store %c2_i32 to %2 : !fir.ref<i32>
81+
return
82+
}
83+
// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2 - Scope 1">
84+
// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2">
85+
// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_0]], 0>}>
86+
// CHECK: #[[$ATTR_3:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_1]], 0>}>
87+
// CHECK: #[[$ATTR_4:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_2]], 0>}>
88+
// CHECK: #[[$ATTR_5:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_3]], 0>}>
89+
// CHECK: #[[$ATTR_6:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[$ATTR_4]], 0>}>
90+
// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_5]], 0>}>
91+
// CHECK: #[[$ATTR_8:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtest2FinnerEx", members = {<#[[$ATTR_6]], 0>}>
92+
// CHECK: #[[$ATTR_9:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMmEglob", members = {<#[[$ATTR_7]], 0>}>
93+
// CHECK: #[[$ATTR_10:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_8]], access_type = #[[$ATTR_8]], offset = 0>
94+
// CHECK: #[[$ATTR_11:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_9]], access_type = #[[$ATTR_9]], offset = 0>
95+
// CHECK-LABEL: func.func @_QPtest2() attributes {noinline} {
96+
// CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFtest2FinnerEy"}
97+
// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
98+
// CHECK: %[[VAL_4:.*]] = fir.address_of(@_QMmEglob) : !fir.ref<i32>
99+
// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_4]] {uniq_name = "_QMmEglob"} : (!fir.ref<i32>) -> !fir.ref<i32>
100+
// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope
101+
// CHECK: %[[VAL_7:.*]] = fir.declare %[[VAL_5]] dummy_scope %[[VAL_6]] {uniq_name = "_QFtest2FinnerEx"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
102+
// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_2]] {uniq_name = "_QFtest2FinnerEy"} : (!fir.ref<i32>) -> !fir.ref<i32>
103+
// CHECK: fir.store %{{.*}} to %[[VAL_8]] : !fir.ref<i32>
104+
// CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_8]] : !fir.ref<i32>
105+
// CHECK: fir.store %[[VAL_9]] to %[[VAL_7]] {tbaa = [#[[$ATTR_10]]]} : !fir.ref<i32>
106+
// CHECK: fir.store %{{.*}} to %[[VAL_5]] {tbaa = [#[[$ATTR_11]]]} : !fir.ref<i32>

0 commit comments

Comments
 (0)