diff --git a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td index b29228eed1591..c05b03bd63ead 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td +++ b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td @@ -225,17 +225,25 @@ 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, 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..7491b7b6d52d2 100644 --- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp +++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp @@ -144,62 +144,80 @@ 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; + + // 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 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/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 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) }