[flang-commits] [flang] 9e56d0d - [flang] Fixed TBAA tags for derived types with descriptors. (#148093)

via flang-commits flang-commits at lists.llvm.org
Mon Jul 14 09:41:18 PDT 2025


Author: Slava Zakharin
Date: 2025-07-14T09:41:15-07:00
New Revision: 9e56d0d2ab125377740245599e3cc950fcf406bc

URL: https://github.com/llvm/llvm-project/commit/9e56d0d2ab125377740245599e3cc950fcf406bc
DIFF: https://github.com/llvm/llvm-project/commit/9e56d0d2ab125377740245599e3cc950fcf406bc.diff

LOG: [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.

Added: 
    flang/test/Transforms/tbaa-derived-with-descriptor.fir

Modified: 
    flang/lib/Optimizer/Transforms/AddAliasTags.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
index 4e788f75d9d77..b27c1b26dedb3 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -79,6 +79,10 @@ class PassState {
   // For the given fir.declare returns the outermost fir.dummy_scope
   // in the current function.
   fir::DummyScopeOp getOutermostScope(fir::DeclareOp declareOp) const;
+  // Returns true, if the given type of a memref of a FirAliasTagOpInterface
+  // operation is a descriptor or contains a descriptor
+  // (e.g. !fir.ref<!fir.type<Derived{f:!fir.box<!fir.heap<f32>>}>>).
+  bool typeReferencesDescriptor(mlir::Type type);
 
 private:
   mlir::DominanceInfo &domInfo;
@@ -95,6 +99,10 @@ class PassState {
   // to the dominance information.
   llvm::DenseMap<mlir::func::FuncOp, llvm::SmallVector<fir::DummyScopeOp, 16>>
       sortedScopeOperations;
+
+  // Local pass cache for derived types that contain descriptor
+  // member(s), to avoid the cost of isRecordWithDescriptorMember().
+  llvm::DenseSet<mlir::Type> typesContainingDescriptors;
 };
 
 // Process fir.dummy_scope operations in the given func:
@@ -145,6 +153,22 @@ fir::DummyScopeOp PassState::getOutermostScope(fir::DeclareOp declareOp) const {
   return nullptr;
 }
 
+bool PassState::typeReferencesDescriptor(mlir::Type type) {
+  type = fir::unwrapAllRefAndSeqType(type);
+  if (mlir::isa<fir::BaseBoxType>(type))
+    return true;
+
+  if (mlir::isa<fir::RecordType>(type)) {
+    if (typesContainingDescriptors.contains(type))
+      return true;
+    if (fir::isRecordWithDescriptorMember(type)) {
+      typesContainingDescriptors.insert(type);
+      return true;
+    }
+  }
+  return false;
+}
+
 class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
 public:
   void runOnOperation() override;
@@ -200,11 +224,17 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
          "load and store only access one address");
   mlir::Value memref = accessedOperands.front();
 
-  // skip boxes. These get an "any descriptor access" tag in TBAABuilder
-  // (CodeGen). I didn't see any speedup from giving each box a separate TBAA
-  // type.
-  if (mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(memref.getType())))
+  // Skip boxes and derived types that contain descriptors.
+  // The box accesses get an "any descriptor access" tag in TBAABuilder
+  // (CodeGen). The derived types accesses get "any access" tag
+  // (because they access both the data and the descriptor(s)).
+  // Note that it would be incorrect to attach any "data" access
+  // tag to the derived type accesses here, because the tags
+  // attached to the descriptor accesses in CodeGen will make
+  // them non-conflicting with any descriptor accesses.
+  if (state.typeReferencesDescriptor(memref.getType()))
     return;
+
   LLVM_DEBUG(llvm::dbgs() << "Analysing " << op << "\n");
 
   const fir::AliasAnalysis::Source &source = state.getSource(memref);

diff  --git a/flang/test/Transforms/tbaa-derived-with-descriptor.fir b/flang/test/Transforms/tbaa-derived-with-descriptor.fir
new file mode 100644
index 0000000000000..18b9a801911f7
--- /dev/null
+++ b/flang/test/Transforms/tbaa-derived-with-descriptor.fir
@@ -0,0 +1,64 @@
+// Test TBAA tags attachment for accesses of derived types
+// that contain descriptors. They cannot be attached
+// with any reasonable "data" tag by fir-add-alias-tags pass,
+// because this will conflict with "any descriptor"
+// tags attached to the descriptor accesses that may be part
+// of these derived type values.
+// Representative Fortran example:
+// subroutine test
+//   type t
+//      real, allocatable :: f
+//   end type t
+//   associate(a => callee([1.0]))
+//     call ext(a(1)%f)
+//   end associate
+// contains
+//   elemental type(t) function callee(x)
+//     real, intent(in) :: x
+//     callee = t(x)
+//   end function callee
+// end subroutine test
+// RUN: fir-opt --fir-add-alias-tags %s | FileCheck %s
+
+func.func @_QPtest() {
+  %c0 = arith.constant 0 : index
+  %c1 = arith.constant 1 : index
+  %0 = fir.alloca !fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>> {bindc_name = ".tmp.array"}
+  %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>>}>>>
+  %2 = fir.alloca f32 {bindc_name = ".tmp"}
+  %3 = fir.alloca !fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}> {bindc_name = ".result"}
+  %4 = fir.dummy_scope : !fir.dscope
+  %14 = fir.address_of(@_QQro.1xr4.0) : !fir.ref<!fir.array<1xf32>>
+  %15 = fir.shape %c1 : (index) -> !fir.shape<1>
+  %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>>
+  %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>>}>>>
+  fir.do_loop %arg0 = %c1 to %c1 step %c1 unordered {
+    %27 = fir.array_coor %16(%15) %arg0 : (!fir.ref<!fir.array<1xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+    %28 = fir.declare %2 {uniq_name = ".tmp"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: fir.load %{{.*}} {tbaa = {{.*}}} : !fir.ref<f32>
+    %29 = fir.load %27 : !fir.ref<f32>
+// CHECK: fir.store %{{.*}} {tbaa = {{.*}}} : !fir.ref<f32>
+    fir.store %29 to %28 : !fir.ref<f32>
+    %30 = fir.call @_QFtestPcallee(%28) proc_attrs<elemental, pure> fastmath<fast> : (!fir.ref<f32>) -> !fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>
+    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>>}>>
+    %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>>}>>
+    %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>>}>>
+// CHECK: fir.load %{{[0-9]+}} : !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
+    %33 = fir.load %31 : !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
+// CHECK: fir.store %{{.*}} to %{{[0-9]+}} : !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
+    fir.store %33 to %32 : !fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>
+  }
+  %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>>}>>>
+  %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>>}>>>
+  %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>>}>>
+  %21 = fir.coordinate_of %20, f : (!fir.ref<!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+// CHECK: fir.load %{{[0-9]+}} : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %23 = fir.box_addr %22 : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %24 = fir.convert %23 : (!fir.heap<f32>) -> !fir.ref<f32>
+  fir.call @_QPext(%24) fastmath<fast> : (!fir.ref<f32>) -> ()
+  %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>>}>>>>
+  %26 = fir.convert %25 : (!fir.box<!fir.heap<!fir.array<1x!fir.type<_QFtestTt{f:!fir.box<!fir.heap<f32>>}>>>>) -> !fir.box<none>
+  fir.call @_FortranADestroyWithoutFinalization(%26) : (!fir.box<none>) -> ()
+  return
+}


        


More information about the flang-commits mailing list