Skip to content

Commit 9e56d0d

Browse files
authored
[flang] Fixed TBAA tags for derived types with descriptors. (#148093)
We cannot attach any "data" or "descriptor" tag to accesses of derived types that contain descriptors, because this will make them non-aliasing with any generic "data" or "descriptor" accesses, which is not correct. We have to skip TBAA tags attachment for such accesses same way we do it for boxes.
1 parent fc99ef7 commit 9e56d0d

File tree

2 files changed

+98
-4
lines changed

2 files changed

+98
-4
lines changed

flang/lib/Optimizer/Transforms/AddAliasTags.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ class PassState {
7979
// For the given fir.declare returns the outermost fir.dummy_scope
8080
// in the current function.
8181
fir::DummyScopeOp getOutermostScope(fir::DeclareOp declareOp) const;
82+
// Returns true, if the given type of a memref of a FirAliasTagOpInterface
83+
// operation is a descriptor or contains a descriptor
84+
// (e.g. !fir.ref<!fir.type<Derived{f:!fir.box<!fir.heap<f32>>}>>).
85+
bool typeReferencesDescriptor(mlir::Type type);
8286

8387
private:
8488
mlir::DominanceInfo &domInfo;
@@ -95,6 +99,10 @@ class PassState {
9599
// to the dominance information.
96100
llvm::DenseMap<mlir::func::FuncOp, llvm::SmallVector<fir::DummyScopeOp, 16>>
97101
sortedScopeOperations;
102+
103+
// Local pass cache for derived types that contain descriptor
104+
// member(s), to avoid the cost of isRecordWithDescriptorMember().
105+
llvm::DenseSet<mlir::Type> typesContainingDescriptors;
98106
};
99107

100108
// Process fir.dummy_scope operations in the given func:
@@ -145,6 +153,22 @@ fir::DummyScopeOp PassState::getOutermostScope(fir::DeclareOp declareOp) const {
145153
return nullptr;
146154
}
147155

156+
bool PassState::typeReferencesDescriptor(mlir::Type type) {
157+
type = fir::unwrapAllRefAndSeqType(type);
158+
if (mlir::isa<fir::BaseBoxType>(type))
159+
return true;
160+
161+
if (mlir::isa<fir::RecordType>(type)) {
162+
if (typesContainingDescriptors.contains(type))
163+
return true;
164+
if (fir::isRecordWithDescriptorMember(type)) {
165+
typesContainingDescriptors.insert(type);
166+
return true;
167+
}
168+
}
169+
return false;
170+
}
171+
148172
class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
149173
public:
150174
void runOnOperation() override;
@@ -200,11 +224,17 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
200224
"load and store only access one address");
201225
mlir::Value memref = accessedOperands.front();
202226

203-
// skip boxes. These get an "any descriptor access" tag in TBAABuilder
204-
// (CodeGen). I didn't see any speedup from giving each box a separate TBAA
205-
// type.
206-
if (mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(memref.getType())))
227+
// Skip boxes and derived types that contain descriptors.
228+
// The box accesses get an "any descriptor access" tag in TBAABuilder
229+
// (CodeGen). The derived types accesses get "any access" tag
230+
// (because they access both the data and the descriptor(s)).
231+
// Note that it would be incorrect to attach any "data" access
232+
// tag to the derived type accesses here, because the tags
233+
// attached to the descriptor accesses in CodeGen will make
234+
// them non-conflicting with any descriptor accesses.
235+
if (state.typeReferencesDescriptor(memref.getType()))
207236
return;
237+
208238
LLVM_DEBUG(llvm::dbgs() << "Analysing " << op << "\n");
209239

210240
const fir::AliasAnalysis::Source &source = state.getSource(memref);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Test TBAA tags attachment for accesses of derived types
2+
// that contain descriptors. They cannot be attached
3+
// with any reasonable "data" tag by fir-add-alias-tags pass,
4+
// because this will conflict with "any descriptor"
5+
// tags attached to the descriptor accesses that may be part
6+
// of these derived type values.
7+
// Representative Fortran example:
8+
// subroutine test
9+
// type t
10+
// real, allocatable :: f
11+
// end type t
12+
// associate(a => callee([1.0]))
13+
// call ext(a(1)%f)
14+
// end associate
15+
// contains
16+
// elemental type(t) function callee(x)
17+
// real, intent(in) :: x
18+
// callee = t(x)
19+
// end function callee
20+
// end subroutine test
21+
// RUN: fir-opt --fir-add-alias-tags %s | FileCheck %s
22+
23+
func.func @_QPtest() {
24+
%c0 = arith.constant 0 : index
25+
%c1 = arith.constant 1 : index
26+
%0 = fir.alloca !fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>> {bindc_name = ".tmp.array"}
27+
%1 = fir.convert %0 : (!fir.ref<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>) -> !fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>
28+
%2 = fir.alloca f32 {bindc_name = ".tmp"}
29+
%3 = fir.alloca !fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}> {bindc_name = ".result"}
30+
%4 = fir.dummy_scope : !fir.dscope
31+
%14 = fir.address_of(@_QQro.1xr4.0) : !fir.ref<!fir.array<1xf32>>
32+
%15 = fir.shape %c1 : (index) -> !fir.shape<1>
33+
%16 = fir.declare %14(%15) {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQro.1xr4.0"} : (!fir.ref<!fir.array<1xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<1xf32>>
34+
%17 = fir.declare %1(%15) {uniq_name = ".tmp.array"} : (!fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>, !fir.shape<1>) -> !fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>
35+
fir.do_loop %arg0 = %c1 to %c1 step %c1 unordered {
36+
%27 = fir.array_coor %16(%15) %arg0 : (!fir.ref<!fir.array<1xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
37+
%28 = fir.declare %2 {uniq_name = ".tmp"} : (!fir.ref<f32>) -> !fir.ref<f32>
38+
// CHECK: fir.load %{{.*}} {tbaa = {{.*}}} : !fir.ref<f32>
39+
%29 = fir.load %27 : !fir.ref<f32>
40+
// CHECK: fir.store %{{.*}} {tbaa = {{.*}}} : !fir.ref<f32>
41+
fir.store %29 to %28 : !fir.ref<f32>
42+
%30 = fir.call @_QFtestPcallee(%28) proc_attrs<elemental, pure> fastmath<fast> : (!fir.ref<f32>) -> !fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>
43+
fir.save_result %30 to %3 : !fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>, !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
44+
%31 = fir.declare %3 {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
45+
%32 = fir.array_coor %17(%15) %arg0 : (!fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>, !fir.shape<1>, index) -> !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
46+
// CHECK: fir.load %{{[0-9]+}} : !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
47+
%33 = fir.load %31 : !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
48+
// CHECK: fir.store %{{.*}} to %{{[0-9]+}} : !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
49+
fir.store %33 to %32 : !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
50+
}
51+
%18 = fir.convert %17 : (!fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>) -> !fir.ref<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>
52+
%19 = fir.declare %18(%15) {uniq_name = "_QFtestEa"} : (!fir.ref<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>, !fir.shape<1>) -> !fir.ref<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>
53+
%20 = fir.array_coor %19(%15) %c1 : (!fir.ref<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>, !fir.shape<1>, index) -> !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
54+
%21 = fir.coordinate_of %20, f : (!fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
55+
// CHECK: fir.load %{{[0-9]+}} : !fir.ref<!fir.box<!fir.heap<f32>>>
56+
%22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
57+
%23 = fir.box_addr %22 : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
58+
%24 = fir.convert %23 : (!fir.heap<f32>) -> !fir.ref<f32>
59+
fir.call @_QPext(%24) fastmath<fast> : (!fir.ref<f32>) -> ()
60+
%25 = fir.embox %17(%15) : (!fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>>
61+
%26 = fir.convert %25 : (!fir.box<!fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>>) -> !fir.box<none>
62+
fir.call @_FortranADestroyWithoutFinalization(%26) : (!fir.box<none>) -> ()
63+
return
64+
}

0 commit comments

Comments
 (0)