From c742a2b5f59f73336a0aa092f9096ff58574a543 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Wed, 19 Nov 2025 14:20:15 +0000 Subject: [PATCH 1/4] [flang][debug] Make common blocks data extraction more robust. Our current implementation for extracting information about common block required traversal of FIR which was not ideal but previously there was no other way to obtain that information. The `[hl]fir.declare` was extended in commit https://github.com/llvm/llvm-project/pull/155325 to include storage and storage_offset. This commit adds these operands in `fircg.ext_declare` and then use them in `AddDebugInfoPass` to create debug data for common blocks. --- .../flang/Optimizer/Dialect/FIRCG/CGOps.td | 6 +- flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp | 1 + .../lib/Optimizer/Transforms/AddDebugInfo.cpp | 116 ++++++++++-------- flang/test/Fir/declare-codegen.fir | 20 +++ flang/test/Transforms/debug-common-block.fir | 36 +++--- 5 files changed, 107 insertions(+), 72 deletions(-) diff --git a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td index b29228eed1591..1e2709a20c0d6 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td +++ b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td @@ -229,13 +229,17 @@ def fircg_XDeclareOp : fircg_Op<"ext_declare", [AttrSizedOperandSegments]> { let arguments = (ins AnyRefOrBox:$memref, Variadic:$shape, Variadic:$shift, Variadic:$typeparams, - Optional:$dummy_scope, Builtin_StringAttr:$uniq_name, + Optional:$dummy_scope, + Optional:$storage, + DefaultValuedAttr:$storage_offset, + Builtin_StringAttr:$uniq_name, OptionalAttr:$dummy_arg_no); let results = (outs AnyRefOrBox); let assemblyFormat = [{ $memref (`(` $shape^ `)`)? (`origin` $shift^)? (`typeparams` $typeparams^)? (`dummy_scope` $dummy_scope^ (`arg` $dummy_arg_no^)?)? + (`storage` `(` $storage^ `[` $storage_offset `]` `)`)? attr-dict `:` functional-type(operands, results) }]; diff --git a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp index bafeb32660e6c..3b137d1e54234 100644 --- a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp +++ b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp @@ -310,6 +310,7 @@ class DeclareOpConversion : public mlir::OpRewritePattern { auto xDeclOp = fir::cg::XDeclareOp::create( rewriter, loc, declareOp.getType(), declareOp.getMemref(), shapeOpers, shiftOpers, declareOp.getTypeparams(), declareOp.getDummyScope(), + declareOp.getStorage(), declareOp.getStorageOffset(), declareOp.getUniqName(), dummyArgNoAttr); LLVM_DEBUG(llvm::dbgs() << "rewriting " << declareOp << " to " << xDeclOp << '\n'); diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp index b21cb85e1256b..ae38e83977198 100644 --- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp +++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp @@ -144,62 +144,72 @@ bool AddDebugInfoPass::createCommonBlockGlobal( fir::DebugTypeGenerator &typeGen, mlir::SymbolTable *symbolTable) { mlir::MLIRContext *context = &getContext(); mlir::OpBuilder builder(context); - std::optional optint; - mlir::Operation *op = declOp.getMemref().getDefiningOp(); - if (auto conOp = mlir::dyn_cast_if_present(op)) - op = conOp.getValue().getDefiningOp(); + std::optional offset; + mlir::Value storage = declOp.getStorage(); + if (!storage) + return false; + + // Extract offset from storage_offset attribute + uint64_t storageOffset = declOp.getStorageOffset(); + if (storageOffset != 0) + offset = static_cast(storageOffset); + + // Get the GlobalOp from the storage value. + // The storage may be wrapped in ConvertOp, so unwrap it first. + mlir::Operation *storageOp = storage.getDefiningOp(); + if (auto convertOp = mlir::dyn_cast_if_present(storageOp)) + storageOp = convertOp.getValue().getDefiningOp(); + + auto addrOfOp = mlir::dyn_cast_if_present(storageOp); + if (!addrOfOp) + return false; + + mlir::SymbolRefAttr sym = addrOfOp.getSymbol(); + fir::GlobalOp global = + symbolTable->lookup(sym.getRootReference()); + if (!global) + return false; + + // FIXME: We are trying to extract the name of the common block from the + // name of the global. As part of mangling, GetCommonBlockObjectName can + // add a trailing _ in the name of that global. The demangle function + // does not seem to handle such cases. So the following hack is used to + // remove the trailing '_'. + llvm::StringRef globalSymbol = sym.getRootReference(); + llvm::StringRef commonName = globalSymbol; + if (commonName != Fortran::common::blankCommonObjectName && + !commonName.empty() && commonName.back() == '_') + commonName = commonName.drop_back(); + + // Create the debug attributes. + unsigned line = getLineFromLoc(global.getLoc()); + mlir::LLVM::DICommonBlockAttr commonBlock = + getOrCreateCommonBlockAttr(commonName, fileAttr, scopeAttr, line); + + mlir::LLVM::DITypeAttr diType = typeGen.convertType( + fir::unwrapRefType(declOp.getType()), fileAttr, scopeAttr, declOp); + + line = getLineFromLoc(declOp.getLoc()); + auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get( + context, commonBlock, mlir::StringAttr::get(context, name), + declOp.getUniqName(), fileAttr, line, diType, + /*isLocalToUnit*/ false, /*isDefinition*/ true, /* alignInBits*/ 0); + + // Create DIExpression for offset if needed + mlir::LLVM::DIExpressionAttr expr; + if (offset && *offset != 0) { + llvm::SmallVector ops; + ops.push_back(mlir::LLVM::DIExpressionElemAttr::get( + context, llvm::dwarf::DW_OP_plus_uconst, *offset)); + expr = mlir::LLVM::DIExpressionAttr::get(context, ops); + } - if (auto cordOp = mlir::dyn_cast_if_present(op)) { - auto coors = cordOp.getCoor(); - if (coors.size() != 1) - return false; - optint = fir::getIntIfConstant(coors[0]); - if (!optint) - return false; - op = cordOp.getRef().getDefiningOp(); - if (auto conOp2 = mlir::dyn_cast_if_present(op)) - op = conOp2.getValue().getDefiningOp(); + auto dbgExpr = mlir::LLVM::DIGlobalVariableExpressionAttr::get( + global.getContext(), gvAttr, expr); + globalToGlobalExprsMap[global].push_back(dbgExpr); - if (auto addrOfOp = mlir::dyn_cast_if_present(op)) { - mlir::SymbolRefAttr sym = addrOfOp.getSymbol(); - if (auto global = - symbolTable->lookup(sym.getRootReference())) { - - unsigned line = getLineFromLoc(global.getLoc()); - llvm::StringRef commonName(sym.getRootReference()); - // FIXME: We are trying to extract the name of the common block from the - // name of the global. As part of mangling, GetCommonBlockObjectName can - // add a trailing _ in the name of that global. The demangle function - // does not seem to handle such cases. So the following hack is used to - // remove the trailing '_'. - if (commonName != Fortran::common::blankCommonObjectName && - commonName.back() == '_') - commonName = commonName.drop_back(); - mlir::LLVM::DICommonBlockAttr commonBlock = - getOrCreateCommonBlockAttr(commonName, fileAttr, scopeAttr, line); - mlir::LLVM::DITypeAttr diType = typeGen.convertType( - fir::unwrapRefType(declOp.getType()), fileAttr, scopeAttr, declOp); - line = getLineFromLoc(declOp.getLoc()); - auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get( - context, commonBlock, mlir::StringAttr::get(context, name), - declOp.getUniqName(), fileAttr, line, diType, - /*isLocalToUnit*/ false, /*isDefinition*/ true, /* alignInBits*/ 0); - mlir::LLVM::DIExpressionAttr expr; - if (*optint != 0) { - llvm::SmallVector ops; - ops.push_back(mlir::LLVM::DIExpressionElemAttr::get( - context, llvm::dwarf::DW_OP_plus_uconst, *optint)); - expr = mlir::LLVM::DIExpressionAttr::get(context, ops); - } - auto dbgExpr = mlir::LLVM::DIGlobalVariableExpressionAttr::get( - global.getContext(), gvAttr, expr); - globalToGlobalExprsMap[global].push_back(dbgExpr); - return true; - } - } - } - return false; + return true; } void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp, diff --git a/flang/test/Fir/declare-codegen.fir b/flang/test/Fir/declare-codegen.fir index fe8d84ef2d19f..9413525a5dbd3 100644 --- a/flang/test/Fir/declare-codegen.fir +++ b/flang/test/Fir/declare-codegen.fir @@ -52,3 +52,23 @@ func.func @unreachable_code(%arg0: !fir.ref>) { // NODECL-NOT: uniq_name = "live_code" // DECL-LABEL: func.func @unreachable_code( // DECL: uniq_name = "live_code" + +// Test that storage and storage_offset operands are preserved during conversion +func.func @test_storage_operands() { + %c0 = arith.constant 0 : index + %c4 = arith.constant 4 : index + %0 = fir.address_of(@common_block) : !fir.ref> + %1 = fir.coordinate_of %0, %c0 : (!fir.ref>, index) -> !fir.ref + %2 = fir.convert %1 : (!fir.ref) -> !fir.ref + %3 = fir.declare %2 storage(%0[0]) {uniq_name = "_QFEx"} : (!fir.ref, !fir.ref>) -> !fir.ref + %4 = fir.coordinate_of %0, %c4 : (!fir.ref>, index) -> !fir.ref + %5 = fir.convert %4 : (!fir.ref) -> !fir.ref + %6 = fir.declare %5 storage(%0[4]) {uniq_name = "_QFEy"} : (!fir.ref, !fir.ref>) -> !fir.ref + return +} +fir.global @common_block : !fir.array<8xi8> + +// DECL-LABEL: func.func @test_storage_operands() +// DECL: %[[STORAGE:.*]] = fir.address_of(@common_block) : !fir.ref> +// DECL: fircg.ext_declare {{.*}} storage(%[[STORAGE]][0]) {uniq_name = "_QFEx"} +// DECL: fircg.ext_declare {{.*}} storage(%[[STORAGE]][4]) {uniq_name = "_QFEy"} diff --git a/flang/test/Transforms/debug-common-block.fir b/flang/test/Transforms/debug-common-block.fir index d68b524225df5..1d2beae0e0ef4 100644 --- a/flang/test/Transforms/debug-common-block.fir +++ b/flang/test/Transforms/debug-common-block.fir @@ -16,18 +16,18 @@ module { %1 = fir.convert %0 : (!fir.ref>>) -> !fir.ref> %2 = fir.coordinate_of %1, %c0 : (!fir.ref>, index) -> !fir.ref %3 = fir.convert %2 : (!fir.ref) -> !fir.ref - %4 = fircg.ext_declare %3 {uniq_name = "_QFf1Ex"} : (!fir.ref) -> !fir.ref loc(#loc4) + %4 = fircg.ext_declare %3 storage(%0[0]) {uniq_name = "_QFf1Ex"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc4) %5 = fir.address_of(@a_) : !fir.ref>> %6 = fir.convert %5 : (!fir.ref>>) -> !fir.ref> %7 = fir.coordinate_of %6, %c0 : (!fir.ref>, index) -> !fir.ref %8 = fir.convert %7 : (!fir.ref) -> !fir.ref - %9 = fircg.ext_declare %8 {uniq_name = "_QFf1Exa"} : (!fir.ref) -> !fir.ref loc(#loc5) + %9 = fircg.ext_declare %8 storage(%5[0]) {uniq_name = "_QFf1Exa"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc5) %10 = fir.coordinate_of %1, %c4 : (!fir.ref>, index) -> !fir.ref %11 = fir.convert %10 : (!fir.ref) -> !fir.ref - %12 = fircg.ext_declare %11 {uniq_name = "_QFf1Ey"} : (!fir.ref) -> !fir.ref loc(#loc6) + %12 = fircg.ext_declare %11 storage(%0[4]) {uniq_name = "_QFf1Ey"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc6) %13 = fir.coordinate_of %6, %c4 : (!fir.ref>, index) -> !fir.ref %14 = fir.convert %13 : (!fir.ref) -> !fir.ref - %15 = fircg.ext_declare %14 {uniq_name = "_QFf1Eya"} : (!fir.ref) -> !fir.ref loc(#loc7) + %15 = fircg.ext_declare %14 storage(%5[4]) {uniq_name = "_QFf1Eya"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc7) return } loc(#loc3) func.func @f2() { @@ -40,24 +40,24 @@ module { %1 = fir.convert %0 : (!fir.ref>>) -> !fir.ref> %2 = fir.coordinate_of %1, %c0 : (!fir.ref>, index) -> !fir.ref %3 = fir.convert %2 : (!fir.ref) -> !fir.ref - %4 = fircg.ext_declare %3 {uniq_name = "_QFf2Ex"} : (!fir.ref) -> !fir.ref loc(#loc9) + %4 = fircg.ext_declare %3 storage(%0[0]) {uniq_name = "_QFf2Ex"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc9) %5 = fir.address_of(@a_) : !fir.ref>> %6 = fir.convert %5 : (!fir.ref>>) -> !fir.ref> %7 = fir.coordinate_of %6, %c0 : (!fir.ref>, index) -> !fir.ref %8 = fir.convert %7 : (!fir.ref) -> !fir.ref - %9 = fircg.ext_declare %8 {uniq_name = "_QFf2Exa"} : (!fir.ref) -> !fir.ref loc(#loc10) + %9 = fircg.ext_declare %8 storage(%5[0]) {uniq_name = "_QFf2Exa"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc10) %10 = fir.coordinate_of %1, %c4 : (!fir.ref>, index) -> !fir.ref %11 = fir.convert %10 : (!fir.ref) -> !fir.ref - %12 = fircg.ext_declare %11 {uniq_name = "_QFf2Ey"} : (!fir.ref) -> !fir.ref loc(#loc11) + %12 = fircg.ext_declare %11 storage(%0[4]) {uniq_name = "_QFf2Ey"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc11) %13 = fir.coordinate_of %6, %c4 : (!fir.ref>, index) -> !fir.ref %14 = fir.convert %13 : (!fir.ref) -> !fir.ref - %15 = fircg.ext_declare %14 {uniq_name = "_QFf2Eya"} : (!fir.ref) -> !fir.ref loc(#loc12) + %15 = fircg.ext_declare %14 storage(%5[4]) {uniq_name = "_QFf2Eya"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc12) %16 = fir.coordinate_of %1, %c8 : (!fir.ref>, index) -> !fir.ref %17 = fir.convert %16 : (!fir.ref) -> !fir.ref - %18 = fircg.ext_declare %17 {uniq_name = "_QFf2Ez"} : (!fir.ref) -> !fir.ref loc(#loc13) + %18 = fircg.ext_declare %17 storage(%0[8]) {uniq_name = "_QFf2Ez"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc13) %19 = fir.coordinate_of %6, %c8 : (!fir.ref>, index) -> !fir.ref %20 = fir.convert %19 : (!fir.ref) -> !fir.ref - %21 = fircg.ext_declare %20 {uniq_name = "_QFf2Eza"} : (!fir.ref) -> !fir.ref loc(#loc14) + %21 = fircg.ext_declare %20 storage(%5[8]) {uniq_name = "_QFf2Eza"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc14) return } loc(#loc8) func.func @f3() { @@ -69,12 +69,12 @@ module { %1 = fir.convert %0 : (!fir.ref>>) -> !fir.ref> %2 = fir.coordinate_of %1, %c0 : (!fir.ref>, index) -> !fir.ref %3 = fir.convert %2 : (!fir.ref) -> !fir.ref - %4 = fircg.ext_declare %3 {uniq_name = "_QFf3Ex"} : (!fir.ref) -> !fir.ref loc(#loc16) + %4 = fircg.ext_declare %3 storage(%0[0]) {uniq_name = "_QFf3Ex"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc16) %5 = fir.address_of(@a_) : !fir.ref>> %6 = fir.convert %5 : (!fir.ref>>) -> !fir.ref> %7 = fir.coordinate_of %6, %c0 : (!fir.ref>, index) -> !fir.ref %8 = fir.convert %7 : (!fir.ref) -> !fir.ref - %9 = fircg.ext_declare %8 {uniq_name = "_QFf3Exa"} : (!fir.ref) -> !fir.ref loc(#loc17) + %9 = fircg.ext_declare %8 storage(%5[0]) {uniq_name = "_QFf3Exa"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc17) return } loc(#loc15) func.func @test() { @@ -87,24 +87,24 @@ module { %1 = fir.convert %0 : (!fir.ref>>) -> !fir.ref> %2 = fir.coordinate_of %1, %c0 : (!fir.ref>, index) -> !fir.ref %3 = fir.convert %2 : (!fir.ref) -> !fir.ref - %4 = fircg.ext_declare %3 {uniq_name = "_QFEv1"} : (!fir.ref) -> !fir.ref loc(#loc19) + %4 = fircg.ext_declare %3 storage(%0[0]) {uniq_name = "_QFEv1"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc19) %5 = fir.coordinate_of %1, %c4 : (!fir.ref>, index) -> !fir.ref %6 = fir.convert %5 : (!fir.ref) -> !fir.ref - %7 = fircg.ext_declare %6 {uniq_name = "_QFEv2"} : (!fir.ref) -> !fir.ref loc(#loc20) + %7 = fircg.ext_declare %6 storage(%0[4]) {uniq_name = "_QFEv2"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc20) %8 = fir.coordinate_of %1, %c8 : (!fir.ref>, index) -> !fir.ref %9 = fir.convert %8 : (!fir.ref) -> !fir.ref - %10 = fircg.ext_declare %9 {uniq_name = "_QFEv3"} : (!fir.ref) -> !fir.ref loc(#loc21) + %10 = fircg.ext_declare %9 storage(%0[8]) {uniq_name = "_QFEv3"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc21) %11 = fir.address_of(@a_) : !fir.ref>> %12 = fir.convert %11 : (!fir.ref>>) -> !fir.ref> %13 = fir.coordinate_of %12, %c0 : (!fir.ref>, index) -> !fir.ref %14 = fir.convert %13 : (!fir.ref) -> !fir.ref - %15 = fircg.ext_declare %14 {uniq_name = "_QFEva1"} : (!fir.ref) -> !fir.ref loc(#loc22) + %15 = fircg.ext_declare %14 storage(%11[0]) {uniq_name = "_QFEva1"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc22) %16 = fir.coordinate_of %12, %c4 : (!fir.ref>, index) -> !fir.ref %17 = fir.convert %16 : (!fir.ref) -> !fir.ref - %18 = fircg.ext_declare %17 {uniq_name = "_QFEva2"} : (!fir.ref) -> !fir.ref loc(#loc23) + %18 = fircg.ext_declare %17 storage(%11[4]) {uniq_name = "_QFEva2"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc23) %19 = fir.coordinate_of %12, %c8 : (!fir.ref>, index) -> !fir.ref %20 = fir.convert %19 : (!fir.ref) -> !fir.ref - %21 = fircg.ext_declare %20 {uniq_name = "_QFEva3"} : (!fir.ref) -> !fir.ref loc(#loc24) + %21 = fircg.ext_declare %20 storage(%11[8]) {uniq_name = "_QFEva3"} : (!fir.ref, !fir.ref>>) -> !fir.ref loc(#loc24) return } loc(#loc18) } From 3a263a387c28a7c50de595c2120470546fedf664 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Wed, 19 Nov 2025 20:02:21 +0000 Subject: [PATCH 2/4] Reject module equivalance variables. --- flang/lib/Optimizer/Transforms/AddDebugInfo.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp index ae38e83977198..7491b7b6d52d2 100644 --- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp +++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp @@ -171,12 +171,20 @@ bool AddDebugInfoPass::createCommonBlockGlobal( if (!global) return false; + // Check if the global is actually a common block by demangling its name. + // Module EQUIVALENCE variables also use storage operands but are mangled + // as VARIABLE type, so we reject them to avoid treating them as common + // blocks. + llvm::StringRef globalSymbol = sym.getRootReference(); + auto globalResult = fir::NameUniquer::deconstruct(globalSymbol); + if (globalResult.first == fir::NameUniquer::NameKind::VARIABLE) + return false; + // FIXME: We are trying to extract the name of the common block from the // name of the global. As part of mangling, GetCommonBlockObjectName can // add a trailing _ in the name of that global. The demangle function // does not seem to handle such cases. So the following hack is used to // remove the trailing '_'. - llvm::StringRef globalSymbol = sym.getRootReference(); llvm::StringRef commonName = globalSymbol; if (commonName != Fortran::common::blankCommonObjectName && !commonName.empty() && commonName.back() == '_') From 231c960c04061ed74287f972b8a9b6f7aa2194a8 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Wed, 19 Nov 2025 20:09:13 +0000 Subject: [PATCH 3/4] Add comments. --- flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td index 1e2709a20c0d6..c05b03bd63ead 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td +++ b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td @@ -225,6 +225,10 @@ def fircg_XDeclareOp : fircg_Op<"ext_declare", [AttrSizedOperandSegments]> { let description = [{ Prior to lowering to LLVM IR dialect, a DeclareOp will be converted to an extended DeclareOp. + + Most operands are inherited from fir.declare except for the shape and shift + operands, which are "expanded" forms of the corresponding shape/shift + operands of fir.declare. }]; let arguments = (ins AnyRefOrBox:$memref, Variadic:$shape, From 3160b07a67a0854ebe849a34fa8307b204942783 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Wed, 19 Nov 2025 20:20:07 +0000 Subject: [PATCH 4/4] Add a regression test. --- .../Integration/debug-module-equivalence.f90 | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 flang/test/Integration/debug-module-equivalence.f90 diff --git a/flang/test/Integration/debug-module-equivalence.f90 b/flang/test/Integration/debug-module-equivalence.f90 new file mode 100644 index 0000000000000..ed709f17f990a --- /dev/null +++ b/flang/test/Integration/debug-module-equivalence.f90 @@ -0,0 +1,20 @@ +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s + +! Test that module EQUIVALENCE does not generate DICommonBlock. + +module data_module + real :: var1, var2 + equivalence (var1, var2) +end module data_module + +subroutine test_module_equiv + use data_module + var1 = 1.5 + var2 = 2.5 +end subroutine + +program main + call test_module_equiv() +end program + +! CHECK-NOT: DICommonBlock