|
35 | 35 | #include "llvm/BinaryFormat/Dwarf.h"
|
36 | 36 | #include "llvm/Support/Debug.h"
|
37 | 37 | #include "llvm/Support/FileSystem.h"
|
| 38 | +#include "llvm/Support/FormatVariadic.h" |
38 | 39 | #include "llvm/Support/Path.h"
|
39 | 40 | #include "llvm/Support/raw_ostream.h"
|
40 | 41 |
|
@@ -104,6 +105,37 @@ bool debugInfoIsAlreadySet(mlir::Location loc) {
|
104 | 105 | return false;
|
105 | 106 | }
|
106 | 107 |
|
| 108 | +// Generates the name for the artificial DISubprogram that we are going to |
| 109 | +// generate for omp::TargetOp. Its logic is borrowed from |
| 110 | +// getTargetEntryUniqueInfo and |
| 111 | +// TargetRegionEntryInfo::getTargetRegionEntryFnName to generate the same name. |
| 112 | +// But even if there was a slight mismatch, it is not a problem because this |
| 113 | +// name is artificial and not important to debug experience. |
| 114 | +mlir::StringAttr getTargetFunctionName(mlir::MLIRContext *context, |
| 115 | + mlir::Location Loc, |
| 116 | + llvm::StringRef parentName) { |
| 117 | + auto fileLoc = Loc->findInstanceOf<mlir::FileLineColLoc>(); |
| 118 | + |
| 119 | + assert(fileLoc && "No file found from location"); |
| 120 | + llvm::StringRef fileName = fileLoc.getFilename().getValue(); |
| 121 | + |
| 122 | + llvm::sys::fs::UniqueID id; |
| 123 | + uint64_t line = fileLoc.getLine(); |
| 124 | + size_t fileId; |
| 125 | + size_t deviceId; |
| 126 | + if (auto ec = llvm::sys::fs::getUniqueID(fileName, id)) { |
| 127 | + fileId = llvm::hash_value(fileName.str()); |
| 128 | + deviceId = 0xdeadf17e; |
| 129 | + } else { |
| 130 | + fileId = id.getFile(); |
| 131 | + deviceId = id.getDevice(); |
| 132 | + } |
| 133 | + return mlir::StringAttr::get( |
| 134 | + context, |
| 135 | + std::string(llvm::formatv("__omp_offloading_{0:x-}_{1:x-}_{2}_l{3}", |
| 136 | + deviceId, fileId, parentName, line))); |
| 137 | +} |
| 138 | + |
107 | 139 | } // namespace
|
108 | 140 |
|
109 | 141 | bool AddDebugInfoPass::createCommonBlockGlobal(
|
@@ -446,13 +478,87 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
|
446 | 478 | line - 1, false);
|
447 | 479 | }
|
448 | 480 |
|
| 481 | + auto addTargetOpDISP = [&](bool lineTableOnly, |
| 482 | + llvm::ArrayRef<mlir::LLVM::DINodeAttr> entities) { |
| 483 | + // When we process the DeclareOp inside the OpenMP target region, all the |
| 484 | + // variables get the DISubprogram of the parent function of the target op as |
| 485 | + // the scope. In the codegen (to llvm ir), OpenMP target op results in the |
| 486 | + // creation of a separate function. As the variables in the debug info have |
| 487 | + // the DISubprogram of the parent function as the scope, the variables |
| 488 | + // need to be updated at codegen time to avoid verification failures. |
| 489 | + |
| 490 | + // This updating after the fact becomes more and more difficult when types |
| 491 | + // are dependent on local variables like in the case of variable size arrays |
| 492 | + // or string. We not only have to generate new variables but also new types. |
| 493 | + // We can avoid this problem by generating a DISubprogramAttr here for the |
| 494 | + // target op and make sure that all the variables inside the target region |
| 495 | + // get the correct scope in the first place. |
| 496 | + funcOp.walk([&](mlir::omp::TargetOp targetOp) { |
| 497 | + unsigned line = getLineFromLoc(targetOp.getLoc()); |
| 498 | + mlir::StringAttr name = |
| 499 | + getTargetFunctionName(context, targetOp.getLoc(), funcOp.getName()); |
| 500 | + mlir::LLVM::DISubprogramFlags flags = |
| 501 | + mlir::LLVM::DISubprogramFlags::Definition | |
| 502 | + mlir::LLVM::DISubprogramFlags::LocalToUnit; |
| 503 | + if (isOptimized) |
| 504 | + flags = flags | mlir::LLVM::DISubprogramFlags::Optimized; |
| 505 | + |
| 506 | + mlir::DistinctAttr id = |
| 507 | + mlir::DistinctAttr::create(mlir::UnitAttr::get(context)); |
| 508 | + llvm::SmallVector<mlir::LLVM::DITypeAttr> types; |
| 509 | + types.push_back(mlir::LLVM::DINullTypeAttr::get(context)); |
| 510 | + for (auto arg : targetOp.getRegion().getArguments()) { |
| 511 | + auto tyAttr = typeGen.convertType(fir::unwrapRefType(arg.getType()), |
| 512 | + fileAttr, cuAttr, /*declOp=*/nullptr); |
| 513 | + types.push_back(tyAttr); |
| 514 | + } |
| 515 | + CC = llvm::dwarf::getCallingConvention("DW_CC_normal"); |
| 516 | + mlir::LLVM::DISubroutineTypeAttr spTy = |
| 517 | + mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types); |
| 518 | + if (lineTableOnly) { |
| 519 | + auto spAttr = mlir::LLVM::DISubprogramAttr::get( |
| 520 | + context, id, compilationUnit, Scope, name, name, funcFileAttr, line, |
| 521 | + line, flags, spTy, /*retainedNodes=*/{}, /*annotations=*/{}); |
| 522 | + targetOp->setLoc(builder.getFusedLoc({targetOp.getLoc()}, spAttr)); |
| 523 | + return; |
| 524 | + } |
| 525 | + mlir::DistinctAttr recId = |
| 526 | + mlir::DistinctAttr::create(mlir::UnitAttr::get(context)); |
| 527 | + auto spAttr = mlir::LLVM::DISubprogramAttr::get( |
| 528 | + context, recId, /*isRecSelf=*/true, id, compilationUnit, Scope, name, |
| 529 | + name, funcFileAttr, line, line, flags, spTy, /*retainedNodes=*/{}, |
| 530 | + /*annotations=*/{}); |
| 531 | + |
| 532 | + // Make sure that information about the imported modules is copied in the |
| 533 | + // new function. |
| 534 | + llvm::SmallVector<mlir::LLVM::DINodeAttr> opEntities; |
| 535 | + for (mlir::LLVM::DINodeAttr N : entities) { |
| 536 | + if (auto entity = mlir::dyn_cast<mlir::LLVM::DIImportedEntityAttr>(N)) { |
| 537 | + auto importedEntity = mlir::LLVM::DIImportedEntityAttr::get( |
| 538 | + context, llvm::dwarf::DW_TAG_imported_module, spAttr, |
| 539 | + entity.getEntity(), fileAttr, /*line=*/1, /*name=*/nullptr, |
| 540 | + /*elements*/ {}); |
| 541 | + opEntities.push_back(importedEntity); |
| 542 | + } |
| 543 | + } |
| 544 | + |
| 545 | + id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context)); |
| 546 | + spAttr = mlir::LLVM::DISubprogramAttr::get( |
| 547 | + context, recId, /*isRecSelf=*/false, id, compilationUnit, Scope, name, |
| 548 | + name, funcFileAttr, line, line, flags, spTy, opEntities, |
| 549 | + /*annotations=*/{}); |
| 550 | + targetOp->setLoc(builder.getFusedLoc({targetOp.getLoc()}, spAttr)); |
| 551 | + }); |
| 552 | + }; |
| 553 | + |
449 | 554 | // Don't process variables if user asked for line tables only.
|
450 | 555 | if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly) {
|
451 | 556 | auto spAttr = mlir::LLVM::DISubprogramAttr::get(
|
452 | 557 | context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
|
453 | 558 | line, line, subprogramFlags, subTypeAttr, /*retainedNodes=*/{},
|
454 | 559 | /*annotations=*/{});
|
455 | 560 | funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
|
| 561 | + addTargetOpDISP(/*lineTableOnly=*/true, /*entities=*/{}); |
456 | 562 | return;
|
457 | 563 | }
|
458 | 564 |
|
@@ -510,9 +616,18 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
|
510 | 616 | funcName, fullName, funcFileAttr, line, line, subprogramFlags,
|
511 | 617 | subTypeAttr, entities, /*annotations=*/{});
|
512 | 618 | funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
|
| 619 | + addTargetOpDISP(/*lineTableOnly=*/false, entities); |
513 | 620 |
|
514 | 621 | funcOp.walk([&](fir::cg::XDeclareOp declOp) {
|
515 |
| - handleDeclareOp(declOp, fileAttr, spAttr, typeGen, symbolTable); |
| 622 | + mlir::LLVM::DISubprogramAttr spTy = spAttr; |
| 623 | + if (auto tOp = declOp->getParentOfType<mlir::omp::TargetOp>()) { |
| 624 | + if (auto fusedLoc = llvm::dyn_cast<mlir::FusedLoc>(tOp.getLoc())) { |
| 625 | + if (auto sp = llvm::dyn_cast<mlir::LLVM::DISubprogramAttr>( |
| 626 | + fusedLoc.getMetadata())) |
| 627 | + spTy = sp; |
| 628 | + } |
| 629 | + } |
| 630 | + handleDeclareOp(declOp, fileAttr, spTy, typeGen, symbolTable); |
516 | 631 | });
|
517 | 632 | // commonBlockMap ensures that we don't create multiple DICommonBlockAttr of
|
518 | 633 | // the same name in one function. But it is ok (rather required) to create
|
|
0 commit comments