diff --git a/tslang/include/TypeScript/LowerToLLVM/LLVMDebugInfoFixer.h b/tslang/include/TypeScript/LowerToLLVM/LLVMDebugInfoFixer.h index b975e35e..01dc4485 100644 --- a/tslang/include/TypeScript/LowerToLLVM/LLVMDebugInfoFixer.h +++ b/tslang/include/TypeScript/LowerToLLVM/LLVMDebugInfoFixer.h @@ -5,15 +5,12 @@ #include "TypeScript/LowerToLLVM/LLVMDebugInfo.h" #include "TypeScript/LowerToLLVM/LLVMTypeConverterHelper.h" -#include "mlir/IR/PatternMatch.h" +#include "mlir/IR/AttrTypeSubElements.h" #include "mlir/IR/Builders.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" -#include "llvm/ADT/TypeSwitch.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include - #define DEBUG_TYPE "llvm" using namespace mlir; @@ -22,95 +19,14 @@ namespace mlir_ts = mlir::typescript; namespace typescript { -class LLVMDebugInfoHelperCreator -{ - LLVM::LLVMFuncOp llvmFuncOp; - const LLVMTypeConverter *typeConverter; - MLIRContext *context; - CompileOptions& compileOptions; - -public: - LLVMDebugInfoHelperCreator(LLVM::LLVMFuncOp llvmFuncOp, const LLVMTypeConverter *typeConverter, CompileOptions& compileOptions) - : llvmFuncOp(llvmFuncOp), typeConverter(typeConverter), compileOptions(compileOptions) - { - context = llvmFuncOp.getContext(); - } - - auto createSubProgramAttr() -> void - { - auto location = llvmFuncOp->getLoc(); - if (auto funcLocWithSubprog = dyn_cast>(location)) - { - return; - } - - auto moduleOp = llvmFuncOp->getParentOp(); - auto moduleLocation = moduleOp->getLoc(); - if (auto funcLocWithCompileUnit = dyn_cast>(moduleLocation)) - { - auto compileUnit = funcLocWithCompileUnit.getMetadata(); - - LocationHelper lh(context); - LLVMTypeConverterHelper llvmtch(typeConverter); - LLVMDebugInfoHelper di(context, llvmtch, compileOptions); - - auto funcNameAttr = llvmFuncOp.getNameAttr(); - - // return type - auto [file, lineAndColumn] = lh.getLineAndColumnAndFile(location); - auto [line, column] = lineAndColumn; - - SmallVector resultTypes; - for (auto resType : llvmFuncOp.getResultTypes()) - { - auto diType = di.getDIType(location, {}, resType, file, line, file); - resultTypes.push_back(diType); - } - - if (llvmFuncOp.getArgumentTypes().size() > 0 && llvmFuncOp.getResultTypes().size() == 0) - { - // return type is null - resultTypes.push_back(mlir::LLVM::DINullTypeAttr()); - } - - for (auto argType : llvmFuncOp.getArgumentTypes()) - { - auto diType = di.getDIType(location, {}, argType, file, line, file); - resultTypes.push_back(diType); - } - - auto subroutineTypeAttr = mlir::LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, resultTypes); - - SmallVector retainedNodes; // TODO: review usage of it - SmallVector annotations; // TODO: review usage of it - auto subprogramAttr = mlir::LLVM::DISubprogramAttr::get( - context, - DistinctAttr::create(mlir::UnitAttr::get(context)), - compileUnit, - compileUnit, - funcNameAttr, - funcNameAttr, - compileUnit.getFile(), - line, - line, - LLVM::DISubprogramFlags::Pure, - subroutineTypeAttr, - retainedNodes, - annotations); - - LLVM_DEBUG(llvm::dbgs() << "\n!! new prog attr: " << subprogramAttr << "\n"); - - // we do not use replaceScope here as we are fixing metadata - auto newLoc = mlir::FusedLoc::get(location.getContext(), {location}, subprogramAttr); - llvmFuncOp->setLoc(newLoc); - } - } - - void clear() { - llvmFuncOp->setLoc(mlir::UnknownLoc::get(llvmFuncOp.getContext())); - } -}; - +// The DISubprogramAttr attached at MLIRGen time carries an empty +// DISubroutineTypeAttr: the DI types of the signature need LLVM layout +// information (LLVMTypeConverter) that only exists here, at lowering time. +// This helper rebuilds the subprogram with the real signature types and remaps +// every reference to the old scope inside the function - locations, block +// arguments, and debug-intrinsic attributes. Attributes that contain the old +// subprogram as a nested scope (lexical blocks, local variables, labels, +// nested subprograms) are rebuilt transitively by AttrTypeReplacer. class LLVMDebugInfoHelperFixer { mlir_ts::FuncOp funcOp; @@ -127,385 +43,74 @@ class LLVMDebugInfoHelperFixer void fix() { auto location = funcOp->getLoc(); - if (auto funcLocWithSubprog = dyn_cast>(location)) + auto funcLocWithSubprog = dyn_cast>(location); + if (!funcLocWithSubprog) { - LocationHelper lh(context); - LLVMTypeConverterHelper llvmtch(typeConverter); - LLVMDebugInfoHelper di(context, llvmtch, compileOptions); - - auto oldMetadata = funcLocWithSubprog.getMetadata(); - auto funcNameAttr = funcOp.getNameAttr(); - - // return type - auto [file, lineAndColumn] = lh.getLineAndColumnAndFile(location); - auto [line, column] = lineAndColumn; - - SmallVector resultTypes; - for (auto resType : funcOp.getResultTypes()) - { - auto diType = di.getDIType(location, {}, resType, file, line, file); - resultTypes.push_back(diType); - } - - if (funcOp.getArgumentTypes().size() > 0 && funcOp.getResultTypes().size() == 0) - { - // return type is null - resultTypes.push_back(mlir::LLVM::DINullTypeAttr()); - } - - for (auto argType : funcOp.getArgumentTypes()) - { - auto diType = di.getDIType(location, {}, argType, file, line, file); - resultTypes.push_back(diType); - } - - auto subroutineTypeAttr = mlir::LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, resultTypes); - SmallVector retainedNodes; // TODO: review usage of it - SmallVector annotations; // TODO: review usage of it - auto subprogramAttr = mlir::LLVM::DISubprogramAttr::get( - context, - DistinctAttr::create(mlir::UnitAttr::get(context)), - oldMetadata.getCompileUnit(), - oldMetadata.getScope(), - oldMetadata.getName(), - oldMetadata.getLinkageName(), - oldMetadata.getFile(), - oldMetadata.getLine(), - oldMetadata.getScopeLine(), - oldMetadata.getSubprogramFlags(), - subroutineTypeAttr, - retainedNodes, - annotations); - - LLVM_DEBUG(llvm::dbgs() << "\n!! new prog attr: " << subprogramAttr << "\n"); - - // we do not use replaceScope here as we are fixing metadata - funcOp->setLoc(replaceScope(location, subprogramAttr, oldMetadata)); - - fixNestedOpScope(subprogramAttr, oldMetadata); - //debugPrint(funcOp); - } - } - -private: - static void removeAllMetadata(mlir::func::FuncOp newFuncOp) { - newFuncOp->walk([&](Operation *op) { - op->setLoc(stripMetadata(op->getLoc())); - - // Strip block arguments debug info. - for (auto ®ion : op->getRegions()) { - for (auto &block : region.getBlocks()) { - for (auto &arg : block.getArguments()) { - arg.setLoc(stripMetadata(arg.getLoc())); - } - } - } - }); - } - - static mlir::Location stripMetadata(mlir::Location loc) - { - mlir::Location ret = loc; - mlir::TypeSwitch(loc) - .Case([&](mlir::FileLineColLoc loc) { - // nothing todo - }) - .Case([&](mlir::FusedLoc loc) { - SmallVector newLocs; - auto anyNewLoc = false; - for (auto subLoc : loc.getLocations()) - { - auto newSubLoc = stripMetadata(subLoc); - newLocs.push_back(newSubLoc); - anyNewLoc |= newSubLoc != subLoc; - } - - if (loc.getMetadata() || anyNewLoc) { - ret = mlir::FusedLoc::get(loc.getContext(), anyNewLoc ? newLocs : loc.getLocations()); - } - }) - .Case([&](mlir::UnknownLoc loc) { - // nothing todo - }) - .Case([&](mlir::NameLoc loc) { - auto newChildLoc = stripMetadata(loc.getChildLoc()); - if (newChildLoc != loc.getChildLoc()) { - ret = NameLoc::get(loc.getName(), newChildLoc); - } - }) - .Case([&](mlir::OpaqueLoc loc) { - auto newFallbackLoc = stripMetadata(loc.getFallbackLocation()); - if (newFallbackLoc != loc.getFallbackLocation()) { - ret = OpaqueLoc::get(loc.getContext(), newFallbackLoc); - } - }) - .Case([&](mlir::CallSiteLoc loc) { - auto newCallerLoc = stripMetadata(loc.getCaller()); - if (newCallerLoc != loc.getCaller()) { - ret = mlir::CallSiteLoc::get(loc.getCallee(), newCallerLoc); - } - }) - .Default([&](mlir::Location loc) { - llvm_unreachable("not implemented"); - }); - - return ret; - } - - mlir::LLVM::DILexicalBlockAttr recreateLexicalBlockForNewScope(mlir::LLVM::DILexicalBlockAttr lexicalBlockAttr, mlir::Attribute newScope, mlir::Attribute oldScope) { - if (lexicalBlockAttr.getScope() == oldScope) { - auto newLexicalBlockAttr = - mlir::LLVM::DILexicalBlockAttr::get( - lexicalBlockAttr.getContext(), - mlir::cast(newScope), - lexicalBlockAttr.getFile(), - lexicalBlockAttr.getLine(), - lexicalBlockAttr.getColumn()); - - // we need to fix nested scope again - fixNestedOpScope(newLexicalBlockAttr, lexicalBlockAttr); - - return newLexicalBlockAttr; - } - - return lexicalBlockAttr; - } - - static mlir::LLVM::DILocalVariableAttr recreateLocalVariableForNewScope(mlir::LLVM::DILocalVariableAttr localVarScope, mlir::Attribute newScope, mlir::Attribute oldScope) { - if (localVarScope.getScope() == oldScope) { - auto newLocalVar = mlir::LLVM::DILocalVariableAttr::get( - localVarScope.getContext(), - mlir::cast(newScope), - localVarScope.getName(), - localVarScope.getFile(), - localVarScope.getLine(), - localVarScope.getArg(), - localVarScope.getAlignInBits(), - localVarScope.getType(), - localVarScope.getFlags()); - return newLocalVar; - } - - return localVarScope; - } - - mlir::LLVM::DISubprogramAttr recreateSubprogramForNewScope(mlir::LLVM::DISubprogramAttr subprogScope, mlir::Attribute newScope, mlir::Attribute oldScope) { - if (subprogScope.getScope() == oldScope) { - SmallVector retainedNodes; // TODO: review usage of it - SmallVector annotations; // TODO: review usage of it - auto newSubprogramAttr = mlir::LLVM::DISubprogramAttr::get( - subprogScope.getContext(), - DistinctAttr::create(mlir::UnitAttr::get(subprogScope.getContext())), - subprogScope.getCompileUnit(), - mlir::cast(newScope), - subprogScope.getName(), - subprogScope.getLinkageName(), - subprogScope.getFile(), - subprogScope.getLine(), - subprogScope.getScopeLine(), - subprogScope.getSubprogramFlags(), - subprogScope.getType(), - retainedNodes, - annotations); - - // we need to fix nested scope again - fixNestedOpScope(newSubprogramAttr, subprogScope); - - return newSubprogramAttr; + return; } - return subprogScope; - } - - static mlir::LLVM::DILabelAttr recreateLabelForNewScope(mlir::LLVM::DILabelAttr labelScope, mlir::Attribute newScope, mlir::Attribute oldScope) { - if (labelScope.getScope() == oldScope) { - auto newLabel = mlir::LLVM::DILabelAttr::get( - labelScope.getContext(), - mlir::cast(newScope), - labelScope.getName(), - labelScope.getFile(), - labelScope.getLine()); - return newLabel; - } + LocationHelper lh(context); + LLVMTypeConverterHelper llvmtch(typeConverter); + LLVMDebugInfoHelper di(context, llvmtch, compileOptions); - return labelScope; - } + auto oldMetadata = funcLocWithSubprog.getMetadata(); - mlir::Attribute recreateMetadataForNewScope(mlir::Attribute currentMetadata, mlir::Attribute newScope, mlir::Attribute oldScope) { - if (auto lexicalBlockAttr = dyn_cast_or_null(currentMetadata)) { - return recreateLexicalBlockForNewScope(lexicalBlockAttr, newScope, oldScope); - } + auto [file, lineAndColumn] = lh.getLineAndColumnAndFile(location); + auto [line, column] = lineAndColumn; - if (auto localVarScope = dyn_cast_or_null(currentMetadata)) { - return recreateLocalVariableForNewScope(localVarScope, newScope, oldScope); + SmallVector resultTypes; + for (auto resType : funcOp.getResultTypes()) + { + auto diType = di.getDIType(location, {}, resType, file, line, file); + resultTypes.push_back(diType); } - if (auto subprogScope = dyn_cast_or_null(currentMetadata)) { - return recreateSubprogramForNewScope(subprogScope, newScope, oldScope); + if (funcOp.getArgumentTypes().size() > 0 && funcOp.getResultTypes().size() == 0) + { + // return type is null + resultTypes.push_back(mlir::LLVM::DINullTypeAttr()); } - if (auto labelScope = dyn_cast_or_null(currentMetadata)) { - return recreateLabelForNewScope(labelScope, newScope, oldScope); + for (auto argType : funcOp.getArgumentTypes()) + { + auto diType = di.getDIType(location, {}, argType, file, line, file); + resultTypes.push_back(diType); } - return currentMetadata; - } - - mlir::Location replaceScope(mlir::Location loc, mlir::Attribute newScope, mlir::Attribute oldScope) - { - return replaceMetadata(loc, [&](mlir::Attribute currentMetadata) -> mlir::Attribute { - if (currentMetadata == oldScope) + auto subroutineTypeAttr = mlir::LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, resultTypes); + SmallVector retainedNodes; // TODO: review usage of it + SmallVector annotations; // TODO: review usage of it + // a fresh DistinctAttr id: references to the old subprogram outside this + // function (if any) keep the old identity instead of colliding with the + // rebuilt one at LLVM IR translation time + auto subprogramAttr = mlir::LLVM::DISubprogramAttr::get( + context, + DistinctAttr::create(mlir::UnitAttr::get(context)), + oldMetadata.getCompileUnit(), + oldMetadata.getScope(), + oldMetadata.getName(), + oldMetadata.getLinkageName(), + oldMetadata.getFile(), + oldMetadata.getLine(), + oldMetadata.getScopeLine(), + oldMetadata.getSubprogramFlags(), + subroutineTypeAttr, + retainedNodes, + annotations); + + LLVM_DEBUG(llvm::dbgs() << "\n!! new prog attr: " << subprogramAttr << "\n"); + + mlir::AttrTypeReplacer replacer; + replacer.addReplacement([&](mlir::LLVM::DISubprogramAttr attr) -> std::optional { + if (attr == oldMetadata) { - return newScope; + return subprogramAttr; } - return recreateMetadataForNewScope(currentMetadata, newScope, oldScope); - }); - } - - static mlir::Location replaceMetadata(mlir::Location loc, std::function f) - { - mlir::Location ret = loc; - mlir::TypeSwitch(loc) - .Case([&](mlir::FileLineColLoc loc) { - // nothing todo - }) - .Case([&](mlir::FusedLoc loc) { - SmallVector newLocs; - auto anyNew = false; - for (auto subLoc : loc.getLocations()) - { - auto newSubLoc = replaceMetadata(subLoc, f); - newLocs.push_back(newSubLoc); - anyNew |= newSubLoc != subLoc; - } - - auto newMetadata = f(loc.getMetadata()); - if (loc.getMetadata() != newMetadata || anyNew) - { - ret = mlir::FusedLoc::get(loc.getContext(), anyNew ? newLocs : loc.getLocations(), newMetadata); - } - }) - .Case([&](mlir::UnknownLoc loc) { - // nothing todo - }) - .Case([&](mlir::NameLoc loc) { - auto newChildLoc = replaceMetadata(loc.getChildLoc(), f); - if (newChildLoc != loc.getChildLoc()) { - ret = NameLoc::get(loc.getName(), newChildLoc); - } - }) - .Case([&](mlir::OpaqueLoc loc) { - auto newFallbackLoc = replaceMetadata(loc.getFallbackLocation(), f); - if (newFallbackLoc != loc.getFallbackLocation()) { - ret = OpaqueLoc::get(loc.getContext(), newFallbackLoc); - } - }) - .Case([&](mlir::CallSiteLoc loc) { - auto newCallerLoc = replaceMetadata(loc.getCaller(), f); - if (newCallerLoc != loc.getCallee()) { - ret = mlir::CallSiteLoc::get(loc.getCallee(), newCallerLoc); - } - }) - .Default([&](mlir::Location loc) { - LLVM_DEBUG(llvm::dbgs() << "\n!! location: " << loc << "\n"); - llvm_unreachable("not implemented"); - }); - - return ret; - } - - static void walkMetadata(mlir::Location loc, std::function f) - { - mlir::TypeSwitch(loc) - .Case([&](mlir::FileLineColLoc loc) { - // nothing todo - }) - .Case([&](mlir::FusedLoc loc) { - f(loc.getMetadata()); - for (auto subLoc : loc.getLocations()) - { - walkMetadata(subLoc, f); - } - }) - .Case([&](mlir::UnknownLoc loc) { - // nothing todo - }) - .Case([&](mlir::NameLoc loc) { - walkMetadata(loc.getChildLoc(), f); - }) - .Case([&](mlir::OpaqueLoc loc) { - walkMetadata(loc.getFallbackLocation(), f); - }) - .Case([&](mlir::CallSiteLoc loc) { - walkMetadata(loc.getCaller(), f); - }) - .Default([&](mlir::Location loc) { - llvm_unreachable("not implemented"); - }); - } - - void fixNestedOpScope(mlir::Attribute newMetadata, mlir::Attribute oldMetadata) { - funcOp.walk([&, newMetadata, oldMetadata](Operation *op) { - - LLVM_DEBUG(llvm::dbgs() << "\n!! replacing for: " << *op << "\n"); - - op->setLoc(replaceScope(op->getLoc(), newMetadata, oldMetadata)); - - // Strip block arguments debug info. - for (auto ®ion : op->getRegions()) { - for (auto &block : region.getBlocks()) { - for (auto &arg : block.getArguments()) { - arg.setLoc(replaceScope(arg.getLoc(), newMetadata, oldMetadata)); - } - } - } - - // fix metadata for llvm.dbg.declare & llvm.dbg.value - if (auto dbgDeclare = dyn_cast(op)) { - auto newLocVar = recreateLocalVariableForNewScope(dbgDeclare.getVarInfo(), newMetadata, oldMetadata); - if (newLocVar != dbgDeclare.getVarInfo()) { - dbgDeclare.setVarInfoAttr(newLocVar); - } - } else if (auto dbgValue = dyn_cast(op)) { - auto newLocVar = recreateLocalVariableForNewScope(dbgValue.getVarInfo(), newMetadata, oldMetadata); - if (newLocVar != dbgDeclare.getVarInfo()) { - dbgValue.setVarInfoAttr(newLocVar); - } - } else if (auto dbgLabel = dyn_cast(op)) { - auto newLabel = recreateLabelForNewScope(dbgLabel.getLabel(), newMetadata, oldMetadata); - if (newLabel != dbgLabel.getLabel()) { - dbgLabel.setLabelAttr(newLabel); - } - } - }); - } - - void debugPrint(mlir::func::FuncOp newFuncOp) { - - // debug - walkMetadata(newFuncOp->getLoc(), [&](mlir::Attribute metadata) { - LLVM_DEBUG(llvm::dbgs() << "\n!! metadata: " << metadata << "\n"); - }); - - newFuncOp.walk([&](Operation *op) { - - walkMetadata(op->getLoc(), [&](mlir::Attribute metadata) { - LLVM_DEBUG(llvm::dbgs() << "\n!! metadata: " << metadata << "\n"); - }); - - // Strip block arguments debug info. - for (auto ®ion : op->getRegions()) { - for (auto &block : region.getBlocks()) { - for (auto &arg : block.getArguments()) { - walkMetadata(arg.getLoc(), [&](mlir::Attribute metadata) { - LLVM_DEBUG(llvm::dbgs() << "\n!! metadata: " << metadata << "\n"); - }); - } - } - } + return std::nullopt; }); + replacer.recursivelyReplaceElementsIn(funcOp, /*replaceAttrs=*/true, /*replaceLocs=*/true, /*replaceTypes=*/false); } }; @@ -513,4 +118,4 @@ class LLVMDebugInfoHelperFixer #undef DEBUG_TYPE -#endif // MLIR_TYPESCRIPT_LOWERTOLLVMLOGIC_LLVMDEBUGINFOFIXER_H_ \ No newline at end of file +#endif // MLIR_TYPESCRIPT_LOWERTOLLVMLOGIC_LLVMDEBUGINFOFIXER_H_