Skip to content

Commit

Permalink
[flang] TBAA for memory accesses of derived type values. (llvm#68047)
Browse files Browse the repository at this point in the history
Since HLFIR bufferization can introduce shallow copies of derived
type values we have to be careful not to treat these load/store
operations as data-only-accesses. If a derived type has descriptor
members, we attach any-access tag now.
  • Loading branch information
vzakhari authored Oct 3, 2023
1 parent f857bef commit cfe8ae3
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 2 deletions.
3 changes: 3 additions & 0 deletions flang/include/flang/Optimizer/CodeGen/TBAABuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ class TBAABuilder {
// Returns TBAATagAttr representing access tag:
// < <any data access>, <any data access>, 0 >
mlir::LLVM::TBAATagAttr getAnyDataAccessTag();
// Returns TBAATagAttr representing access tag:
// < <any access>, <any access>, 0 >
mlir::LLVM::TBAATagAttr getAnyAccessTag();

// Returns TBAATagAttr representing access tag described by the base and
// access FIR types and the LLVM::GepOp representing the access in terms of
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FIRType.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,10 @@ mlir::Type unwrapInnerType(mlir::Type ty);
/// Return true iff `ty` is a RecordType with members that are allocatable.
bool isRecordWithAllocatableMember(mlir::Type ty);

/// Return true iff `ty` is a scalar/array of RecordType
/// with members that are descriptors.
bool isRecordWithDescriptorMember(mlir::Type ty);

/// Return true iff `ty` is a RecordType with type parameters.
inline bool isRecordWithTypeParameters(mlir::Type ty) {
if (auto recTy = ty.dyn_cast_or_null<fir::RecordType>())
Expand Down
15 changes: 13 additions & 2 deletions flang/lib/Optimizer/CodeGen/TBAABuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ TBAATagAttr TBAABuilder::getDataAccessTag(Type baseFIRType, Type accessFIRType,
return getAnyDataAccessTag();
}

TBAATagAttr TBAABuilder::getAnyAccessTag() {
return getAccessTag(anyAccessTypeDesc, anyAccessTypeDesc, /*offset=*/0);
}

void TBAABuilder::attachTBAATag(AliasAnalysisOpInterface op, Type baseFIRType,
Type accessFIRType, GEPOp gep) {
if (!enableTBAA)
Expand All @@ -106,10 +110,17 @@ void TBAABuilder::attachTBAATag(AliasAnalysisOpInterface op, Type baseFIRType,
<< "\n");

TBAATagAttr tbaaTagSym;
if (baseFIRType.isa<fir::BaseBoxType>())
if (fir::isRecordWithDescriptorMember(baseFIRType)) {
// A memory access that addresses an aggregate that contains
// a mix of data members and descriptor members may alias
// with both data and descriptor accesses.
// Conservatively set any-access tag if there is any descriptor member.
tbaaTagSym = getAnyAccessTag();
} else if (baseFIRType.isa<fir::BaseBoxType>()) {
tbaaTagSym = getBoxAccessTag(baseFIRType, accessFIRType, gep);
else
} else {
tbaaTagSym = getDataAccessTag(baseFIRType, accessFIRType, gep);
}

if (!tbaaTagSym)
return;
Expand Down
12 changes: 12 additions & 0 deletions flang/lib/Optimizer/Dialect/FIRType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,18 @@ bool isRecordWithAllocatableMember(mlir::Type ty) {
return false;
}

bool isRecordWithDescriptorMember(mlir::Type ty) {
ty = unwrapSequenceType(ty);
if (auto recTy = ty.dyn_cast<fir::RecordType>())
for (auto [field, memTy] : recTy.getTypeList()) {
if (mlir::isa<fir::BaseBoxType>(memTy))
return true;
if (memTy.isa<fir::RecordType>() && isRecordWithDescriptorMember(memTy))
return true;
}
return false;
}

mlir::Type unwrapAllRefAndSeqType(mlir::Type ty) {
while (true) {
mlir::Type nt = unwrapSequenceType(unwrapRefType(ty));
Expand Down
34 changes: 34 additions & 0 deletions flang/test/Fir/tbaa.fir
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,37 @@ func.func @tbaa(%arg0: !fir.box<!fir.array<?xi32>>) {
// CHECK: %[[VAL_14:.*]] = llvm.bitcast %[[VAL_13]] : !llvm.ptr<i8> to !llvm.ptr<i32>
// CHECK: llvm.return
// CHECK: }

// -----

// Check that the scalar aggregate load/store with a descriptor member
// is mapped to any-access.
// CHECK-DAG: #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang Type TBAA Root">
// CHECK-DAG: #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
// CHECK-DAG: #[[$ANYT:.*]] = #llvm.tbaa_tag<base_type = #[[ANYACC]], access_type = #[[ANYACC]], offset = 0>

func.func @tbaa(%arg0: !fir.ref<!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>, %arg1: !fir.ref<!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>) {
%0 = fir.load %arg0 : !fir.ref<!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>
fir.store %0 to %arg1 : !fir.ref<!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>
return
}
// CHECK-LABEL: llvm.func @tbaa(
// CHECK: llvm.load{{.*}}{tbaa = [#[[$ANYT]]]}
// CHECK: llvm.store{{.*}}{tbaa = [#[[$ANYT]]]}

// -----

// Check that the array aggregate load/store with a descriptor member
// is mapped to any-access.
// CHECK-DAG: #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang Type TBAA Root">
// CHECK-DAG: #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
// CHECK-DAG: #[[$ANYT:.*]] = #llvm.tbaa_tag<base_type = #[[ANYACC]], access_type = #[[ANYACC]], offset = 0>

func.func @tbaa(%arg0: !fir.ref<!fir.array<2x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>, %arg1: !fir.ref<!fir.array<2x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>) {
%0 = fir.load %arg0 : !fir.ref<!fir.array<2x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>
fir.store %0 to %arg1 : !fir.ref<!fir.array<2x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>
return
}
// CHECK-LABEL: llvm.func @tbaa(
// CHECK: llvm.load{{.*}}{tbaa = [#[[$ANYT]]]}
// CHECK: llvm.store{{.*}}{tbaa = [#[[$ANYT]]]}

0 comments on commit cfe8ae3

Please sign in to comment.