[mlir] Add support for basic location translation to LLVM.
authorRiver Riddle <riddleriver@gmail.com>
Thu, 6 Feb 2020 01:10:55 +0000 (17:10 -0800)
committerRiver Riddle <riddleriver@gmail.com>
Thu, 6 Feb 2020 01:41:51 +0000 (17:41 -0800)
Summary:
This revision adds basic support for emitting line table information when exporting to LLVMIR. We don't yet have a story for supporting all of the LLVM debug metadata, so this revision stubs some features(like subprograms) to enable emitting line tables.

Differential Revision: https://reviews.llvm.org/D73934

12 files changed:
mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
mlir/include/mlir/Transforms/Passes.h
mlir/lib/Target/CMakeLists.txt
mlir/lib/Target/LLVMIR/ConvertToNVVMIR.cpp
mlir/lib/Target/LLVMIR/ConvertToROCDLIR.cpp
mlir/lib/Target/LLVMIR/DebugTranslation.cpp [new file with mode: 0644]
mlir/lib/Target/LLVMIR/DebugTranslation.h [new file with mode: 0644]
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
mlir/lib/Transforms/StripDebugInfo.cpp
mlir/test/Target/llvmir-debug.mlir [new file with mode: 0644]
mlir/test/Target/llvmir.mlir
mlir/tools/mlir-cuda-runner/mlir-cuda-runner.cpp

index b58a57d..5eda0f6 100644 (file)
@@ -32,13 +32,17 @@ class Operation;
 
 namespace LLVM {
 
+namespace detail {
+class DebugTranslation;
+} // end namespace detail
+
 class LLVMFuncOp;
 
-// Implementation class for module translation.  Holds a reference to the module
-// being translated, and the mappings between the original and the translated
-// functions, basic blocks and values.  It is practically easier to hold these
-// mappings in one class since the conversion of control flow operations
-// needs to look up block and function mappings.
+/// Implementation class for module translation. Holds a reference to the module
+/// being translated, and the mappings between the original and the translated
+/// functions, basic blocks and values. It is practically easier to hold these
+/// mappings in one class since the conversion of control flow operations
+/// needs to look up block and function mappings.
 class ModuleTranslation {
 public:
   template <typename T = ModuleTranslation>
@@ -51,8 +55,7 @@ public:
     if (!llvmModule)
       return nullptr;
 
-    T translator(m);
-    translator.llvmModule = std::move(llvmModule);
+    T translator(m, std::move(llvmModule));
     translator.convertGlobals();
     if (failed(translator.convertFunctions()))
       return nullptr;
@@ -65,14 +68,12 @@ public:
   static Block &getModuleBody(Operation *m) { return m->getRegion(0).front(); }
 
 protected:
-  // Translate the given MLIR module expressed in MLIR LLVM IR dialect into an
-  // LLVM IR module.  The MLIR LLVM IR dialect holds a pointer to an
-  // LLVMContext, the LLVM IR module will be created in that context.
-  explicit ModuleTranslation(Operation *module) : mlirModule(module) {
-    assert(satisfiesLLVMModule(mlirModule) &&
-           "mlirModule should honor LLVM's module semantics.");
-  }
-  virtual ~ModuleTranslation() {}
+  /// Translate the given MLIR module expressed in MLIR LLVM IR dialect into an
+  /// LLVM IR module. The MLIR LLVM IR dialect holds a pointer to an
+  /// LLVMContext, the LLVM IR module will be created in that context.
+  ModuleTranslation(Operation *module,
+                    std::unique_ptr<llvm::Module> llvmModule);
+  virtual ~ModuleTranslation();
 
   virtual LogicalResult convertOperation(Operation &op,
                                          llvm::IRBuilder<> &builder);
@@ -94,15 +95,18 @@ private:
   llvm::Constant *getLLVMConstant(llvm::Type *llvmType, Attribute attr,
                                   Location loc);
 
-  // Original and translated module.
+  /// Original and translated module.
   Operation *mlirModule;
   std::unique_ptr<llvm::Module> llvmModule;
 
-  // Mappings between llvm.mlir.global definitions and corresponding globals.
+  /// A converter for translating debug information.
+  std::unique_ptr<detail::DebugTranslation> debugTranslation;
+
+  /// Mappings between llvm.mlir.global definitions and corresponding globals.
   DenseMap<Operation *, llvm::GlobalValue *> globalsMapping;
 
 protected:
-  // Mappings between original and translated values, used for lookups.
+  /// Mappings between original and translated values, used for lookups.
   llvm::StringMap<llvm::Function *> functionMapping;
   DenseMap<Value, llvm::Value *> valueMapping;
   DenseMap<Block *, llvm::BasicBlock *> blockMapping;
index a78f5a9..673f3db 100644 (file)
@@ -118,7 +118,7 @@ std::unique_ptr<OpPassBase<FuncOp>> createAffineDataCopyGenerationPass(
 std::unique_ptr<OpPassBase<FuncOp>> createMemRefDataFlowOptPass();
 
 /// Creates a pass to strip debug information from a function.
-std::unique_ptr<OpPassBase<FuncOp>> createStripDebugInfoPass();
+std::unique_ptr<Pass> createStripDebugInfoPass();
 
 /// Creates a pass which tests loop fusion utilities.
 std::unique_ptr<OpPassBase<FuncOp>> createTestLoopFusionPass();
index 25000d9..53786b9 100644 (file)
@@ -1,4 +1,5 @@
 add_llvm_library(MLIRTargetLLVMIRModuleTranslation
+  LLVMIR/DebugTranslation.cpp
   LLVMIR/ModuleTranslation.cpp
 
   ADDITIONAL_HEADER_DIRS
index 28264ba..c07f61c 100644 (file)
@@ -48,11 +48,8 @@ static llvm::Intrinsic::ID getShflBflyIntrinsicId(llvm::Type *resultType,
 
 namespace {
 class ModuleTranslation : public LLVM::ModuleTranslation {
-
 public:
-  explicit ModuleTranslation(Operation *module)
-      : LLVM::ModuleTranslation(module) {}
-  ~ModuleTranslation() override {}
+  using LLVM::ModuleTranslation::ModuleTranslation;
 
 protected:
   LogicalResult convertOperation(Operation &opInst,
@@ -66,7 +63,6 @@ protected:
 } // namespace
 
 std::unique_ptr<llvm::Module> mlir::translateModuleToNVVMIR(Operation *m) {
-  ModuleTranslation translation(m);
   auto llvmModule =
       LLVM::ModuleTranslation::translateModule<ModuleTranslation>(m);
   if (!llvmModule)
index 212029b..bcaec6c 100644 (file)
@@ -57,11 +57,8 @@ static llvm::Value *createDeviceFunctionCall(llvm::IRBuilder<> &builder,
 
 namespace {
 class ModuleTranslation : public LLVM::ModuleTranslation {
-
 public:
-  explicit ModuleTranslation(Operation *module)
-      : LLVM::ModuleTranslation(module) {}
-  ~ModuleTranslation() override {}
+  using LLVM::ModuleTranslation::ModuleTranslation;
 
 protected:
   LogicalResult convertOperation(Operation &opInst,
@@ -75,8 +72,6 @@ protected:
 } // namespace
 
 std::unique_ptr<llvm::Module> mlir::translateModuleToROCDLIR(Operation *m) {
-  ModuleTranslation translation(m);
-
   // lower MLIR (with RODL Dialect) to LLVM IR (with ROCDL intrinsics)
   auto llvmModule =
       LLVM::ModuleTranslation::translateModule<ModuleTranslation>(m);
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
new file mode 100644 (file)
index 0000000..3b0709a
--- /dev/null
@@ -0,0 +1,194 @@
+//===- DebugTranslation.cpp - MLIR to LLVM Debug conversion ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DebugTranslation.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace mlir;
+using namespace mlir::LLVM;
+using namespace mlir::LLVM::detail;
+
+/// A utility walker that interrupts if the operation has valid debug
+/// information.
+static WalkResult interruptIfValidLocation(Operation *op) {
+  return op->getLoc().isa<UnknownLoc>() ? WalkResult::advance()
+                                        : WalkResult::interrupt();
+}
+
+DebugTranslation::DebugTranslation(Operation *module, llvm::Module &llvmModule)
+    : builder(llvmModule), llvmCtx(llvmModule.getContext()),
+      compileUnit(nullptr) {
+
+  // If the module has no location information, there is nothing to do.
+  if (!module->walk(interruptIfValidLocation).wasInterrupted())
+    return;
+
+  // TODO(riverriddle) Several parts of this are incorrect. Different source
+  // languages may interpret different parts of the debug information
+  // differently. Frontends will also want to pipe in various information, like
+  // flags. This is fine for now as we only emit line-table information and not
+  // types or variables. This should disappear as the debug information story
+  // evolves; i.e. when we have proper attributes for LLVM debug metadata.
+  compileUnit = builder.createCompileUnit(
+      llvm::dwarf::DW_LANG_C,
+      builder.createFile(llvmModule.getModuleIdentifier(), "/"),
+      /*Producer=*/"mlir", /*isOptimized=*/true, /*Flags=*/"", /*RV=*/0);
+
+  // Mark this module as having debug information.
+  StringRef debugVersionKey = "Debug Info Version";
+  if (!llvmModule.getModuleFlag(debugVersionKey))
+    llvmModule.addModuleFlag(llvm::Module::Warning, debugVersionKey,
+                             llvm::DEBUG_METADATA_VERSION);
+}
+
+/// Finalize the translation of debug information.
+void DebugTranslation::finalize() { builder.finalize(); }
+
+/// Attempt to extract a filename for the given loc.
+static FileLineColLoc extractFileLoc(Location loc) {
+  if (auto fileLoc = loc.dyn_cast<FileLineColLoc>())
+    return fileLoc;
+  if (auto nameLoc = loc.dyn_cast<NameLoc>())
+    return extractFileLoc(nameLoc.getChildLoc());
+  if (auto opaqueLoc = loc.dyn_cast<OpaqueLoc>())
+    return extractFileLoc(opaqueLoc.getFallbackLocation());
+  return FileLineColLoc();
+}
+
+/// Translate the debug information for the given function.
+void DebugTranslation::translate(LLVMFuncOp func, llvm::Function &llvmFunc) {
+  // If the function doesn't have location information, there is nothing to
+  // translate.
+  if (!compileUnit || !func.walk(interruptIfValidLocation).wasInterrupted())
+    return;
+
+  FileLineColLoc fileLoc = extractFileLoc(func.getLoc());
+  auto *file = translateFile(fileLoc ? fileLoc.getFilename() : "<unknown>");
+  unsigned line = fileLoc ? fileLoc.getLine() : 0;
+
+  // TODO(riverriddle) This is the bare essentials for now. We will likely end
+  // up with wrapper metadata around LLVMs metadata in the future, so this
+  // doesn't need to be smart until then.
+  llvm::DISubroutineType *type =
+      builder.createSubroutineType(builder.getOrCreateTypeArray(llvm::None));
+  llvm::DISubprogram::DISPFlags spFlags = llvm::DISubprogram::SPFlagDefinition |
+                                          llvm::DISubprogram::SPFlagOptimized;
+  llvm::DISubprogram *program =
+      builder.createFunction(compileUnit, func.getName(), func.getName(), file,
+                             line, type, line, llvm::DINode::FlagZero, spFlags);
+  llvmFunc.setSubprogram(program);
+  builder.finalizeSubprogram(program);
+}
+
+//===----------------------------------------------------------------------===//
+// Locations
+//===----------------------------------------------------------------------===//
+
+/// Translate the given location to an llvm debug location.
+const llvm::DILocation *
+DebugTranslation::translateLoc(Location loc, llvm::DILocalScope *scope) {
+  if (!compileUnit)
+    return nullptr;
+  return translateLoc(loc, scope, /*inlinedAt=*/nullptr);
+}
+
+/// Translate the given location to an llvm DebugLoc.
+const llvm::DILocation *
+DebugTranslation::translateLoc(Location loc, llvm::DILocalScope *scope,
+                               const llvm::DILocation *inlinedAt) {
+  // LLVM doesn't have a representation for unknown.
+  if (!scope || loc.isa<UnknownLoc>())
+    return nullptr;
+
+  // Check for a cached instance.
+  const auto *&llvmLoc = locationToLoc[std::make_pair(loc, scope)];
+  if (llvmLoc)
+    return llvmLoc;
+
+  switch (loc->getKind()) {
+  case StandardAttributes::CallSiteLocation: {
+    auto callLoc = loc.dyn_cast<CallSiteLoc>();
+
+    // For callsites, the caller is fed as the inlinedAt for the callee.
+    const auto *callerLoc = translateLoc(callLoc.getCaller(), scope, inlinedAt);
+    llvmLoc = translateLoc(callLoc.getCallee(), scope, callerLoc);
+    break;
+  }
+  case StandardAttributes::FileLineColLocation: {
+    auto fileLoc = loc.dyn_cast<FileLineColLoc>();
+    auto *file = translateFile(fileLoc.getFilename());
+    auto *fileScope = builder.createLexicalBlockFile(scope, file);
+    llvmLoc = llvm::DILocation::get(llvmCtx, fileLoc.getLine(),
+                                    fileLoc.getColumn(), fileScope,
+                                    const_cast<llvm::DILocation *>(inlinedAt));
+    break;
+  }
+  case StandardAttributes::FusedLocation: {
+    auto fusedLoc = loc.dyn_cast<FusedLoc>();
+    ArrayRef<Location> locations = fusedLoc.getLocations();
+
+    // For fused locations, merge each of the nodes.
+    llvmLoc = translateLoc(locations.front(), scope, inlinedAt);
+    for (Location locIt : locations.drop_front()) {
+      llvmLoc = llvm::DILocation::getMergedLocation(
+          llvmLoc, translateLoc(locIt, scope, inlinedAt));
+    }
+    break;
+  }
+  case StandardAttributes::NameLocation:
+    llvmLoc = translateLoc(loc.cast<NameLoc>().getChildLoc(), scope, inlinedAt);
+    break;
+  case StandardAttributes::OpaqueLocation:
+    llvmLoc = translateLoc(loc.cast<OpaqueLoc>().getFallbackLocation(), scope,
+                           inlinedAt);
+    break;
+  default:
+    llvm_unreachable("unknown location kind");
+  }
+  return llvmLoc;
+}
+
+/// Create an llvm debug file for the given file path.
+llvm::DIFile *DebugTranslation::translateFile(StringRef fileName) {
+  auto *&file = fileMap[fileName];
+  if (file)
+    return file;
+
+  // Make sure the current working directory is up-to-date.
+  if (currentWorkingDir.empty())
+    llvm::sys::fs::current_path(currentWorkingDir);
+
+  StringRef directory = currentWorkingDir;
+  SmallString<128> dirBuf;
+  SmallString<128> fileBuf;
+  if (llvm::sys::path::is_absolute(fileName)) {
+    // Strip the common prefix (if it is more than just "/") from current
+    // directory and FileName for a more space-efficient encoding.
+    auto fileIt = llvm::sys::path::begin(fileName);
+    auto fileE = llvm::sys::path::end(fileName);
+    auto curDirIt = llvm::sys::path::begin(directory);
+    auto curDirE = llvm::sys::path::end(directory);
+    for (; curDirIt != curDirE && *curDirIt == *fileIt; ++curDirIt, ++fileIt)
+      llvm::sys::path::append(dirBuf, *curDirIt);
+    if (std::distance(llvm::sys::path::begin(directory), curDirIt) == 1) {
+      // Don't strip the common prefix if it is only the root "/"  since that
+      // would make LLVM diagnostic locations confusing.
+      directory = StringRef();
+    } else {
+      for (; fileIt != fileE; ++fileIt)
+        llvm::sys::path::append(fileBuf, *fileIt);
+      directory = dirBuf;
+      fileName = fileBuf;
+    }
+  }
+  return (file = builder.createFile(fileName, directory));
+}
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h
new file mode 100644 (file)
index 0000000..ae04f2b
--- /dev/null
@@ -0,0 +1,74 @@
+//===- DebugTranslation.h - MLIR to LLVM Debug conversion -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the translation between an MLIR debug information and
+// the corresponding LLVMIR representation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_LIB_TARGET_LLVMIR_DEBUGTRANSLATION_H_
+#define MLIR_LIB_TARGET_LLVMIR_DEBUGTRANSLATION_H_
+
+#include "mlir/IR/Location.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/DIBuilder.h"
+
+namespace mlir {
+class Operation;
+
+namespace LLVM {
+class LLVMFuncOp;
+
+namespace detail {
+class DebugTranslation {
+public:
+  DebugTranslation(Operation *module, llvm::Module &llvmModule);
+
+  /// Finalize the translation of debug information.
+  void finalize();
+
+  /// Translate the given location to an llvm debug location.
+  const llvm::DILocation *translateLoc(Location loc, llvm::DILocalScope *scope);
+
+  /// Translate the debug information for the given function.
+  void translate(LLVMFuncOp func, llvm::Function &llvmFunc);
+
+private:
+  /// Translate the given location to an llvm debug location with the given
+  /// scope and inlinedAt parameters.
+  const llvm::DILocation *translateLoc(Location loc, llvm::DILocalScope *scope,
+                                       const llvm::DILocation *inlinedAt);
+
+  /// Create an llvm debug file for the given file path.
+  llvm::DIFile *translateFile(StringRef fileName);
+
+  /// A mapping between mlir location+scope and the corresponding llvm debug
+  /// metadata.
+  DenseMap<std::pair<Location, llvm::DILocalScope *>, const llvm::DILocation *>
+      locationToLoc;
+
+  /// A mapping between filename and llvm debug file.
+  /// TODO(riverriddle) Change this to DenseMap<Identifier, ...> when we can
+  /// access the Identifier filename in FileLineColLoc.
+  llvm::StringMap<llvm::DIFile *> fileMap;
+
+  /// A string containing the current working directory of the compiler.
+  SmallString<256> currentWorkingDir;
+
+  /// Debug information fields.
+  llvm::DIBuilder builder;
+  llvm::LLVMContext &llvmCtx;
+  llvm::DICompileUnit *compileUnit;
+};
+
+} // end namespace detail
+} // end namespace LLVM
+} // end namespace mlir
+
+#endif // MLIR_LIB_TARGET_LLVMIR_DEBUGTRANSLATION_H_
index 4c44e67..cbcc2e6 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "mlir/Target/LLVMIR/ModuleTranslation.h"
 
+#include "DebugTranslation.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/IR/Attributes.h"
 #include "mlir/IR/Module.h"
@@ -30,6 +31,7 @@
 
 using namespace mlir;
 using namespace mlir::LLVM;
+using namespace mlir::LLVM::detail;
 
 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
 
@@ -265,6 +267,16 @@ static llvm::AtomicOrdering getLLVMAtomicOrdering(AtomicOrdering ordering) {
   llvm_unreachable("incorrect atomic ordering");
 }
 
+ModuleTranslation::ModuleTranslation(Operation *module,
+                                     std::unique_ptr<llvm::Module> llvmModule)
+    : mlirModule(module), llvmModule(std::move(llvmModule)),
+      debugTranslation(
+          std::make_unique<DebugTranslation>(module, *this->llvmModule)) {
+  assert(satisfiesLLVMModule(mlirModule) &&
+         "mlirModule should honor LLVM's module semantics.");
+}
+ModuleTranslation::~ModuleTranslation() {}
+
 /// Given a single MLIR operation, create the corresponding LLVM IR operation
 /// using the `builder`.  LLVM IR Builder does not have a generic interface so
 /// this has to be a long chain of `if`s calling different functions with a
@@ -371,6 +383,7 @@ LogicalResult ModuleTranslation::convertOperation(Operation &opInst,
 /// are not connected to the source basic blocks, which may not exist yet.
 LogicalResult ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments) {
   llvm::IRBuilder<> builder(blockMapping[&bb]);
+  auto *subprogram = builder.GetInsertBlock()->getParent()->getSubprogram();
 
   // Before traversing operations, make block arguments available through
   // value remapping and PHI nodes, but do not add incoming edges for the PHI
@@ -395,6 +408,10 @@ LogicalResult ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments) {
 
   // Traverse operations.
   for (auto &op : bb) {
+    // Set the current debug location within the builder.
+    builder.SetCurrentDebugLocation(
+        debugTranslation->translateLoc(op.getLoc(), subprogram));
+
     if (failed(convertOperation(op, builder)))
       return failure();
   }
@@ -520,6 +537,10 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
   blockMapping.clear();
   valueMapping.clear();
   llvm::Function *llvmFunc = functionMapping.lookup(func.getName());
+
+  // Translate the debug information for this function.
+  debugTranslation->translate(func, *llvmFunc);
+
   // Add function arguments to the value remapping table.
   // If there was noalias info then we decorate each argument accordingly.
   unsigned int argIdx = 0;
index ad4840e..1a8b213 100644 (file)
 using namespace mlir;
 
 namespace {
-struct StripDebugInfo : public FunctionPass<StripDebugInfo> {
-  void runOnFunction() override;
+struct StripDebugInfo : public OperationPass<StripDebugInfo> {
+  void runOnOperation() override;
 };
 } // end anonymous namespace
 
-void StripDebugInfo::runOnFunction() {
-  FuncOp func = getFunction();
+void StripDebugInfo::runOnOperation() {
+  // Strip the debug info from all operations.
   auto unknownLoc = UnknownLoc::get(&getContext());
-
-  // Strip the debug info from the function and its operations.
-  func.setLoc(unknownLoc);
-  func.walk([&](Operation *op) { op->setLoc(unknownLoc); });
+  getOperation()->walk([&](Operation *op) { op->setLoc(unknownLoc); });
 }
 
 /// Creates a pass to strip debug information from a function.
-std::unique_ptr<OpPassBase<FuncOp>> mlir::createStripDebugInfoPass() {
+std::unique_ptr<Pass> mlir::createStripDebugInfoPass() {
   return std::make_unique<StripDebugInfo>();
 }
 
 static PassRegistration<StripDebugInfo>
-    pass("strip-debuginfo", "Strip debug info from functions and operations");
+    pass("strip-debuginfo", "Strip debug info from all operations");
diff --git a/mlir/test/Target/llvmir-debug.mlir b/mlir/test/Target/llvmir-debug.mlir
new file mode 100644 (file)
index 0000000..2a94448
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+// CHECK-LABEL: define void @func_no_debug()
+// CHECK-NOT: !dbg
+llvm.func @func_no_debug() {
+  llvm.return loc(unknown)
+} loc(unknown)
+
+// CHECK-LABEL: define void @func_with_debug()
+// CHECK-SAME: !dbg ![[FUNC_LOC:[0-9]+]]
+llvm.func @func_with_debug() {
+  // CHECK: call void @func_no_debug()
+  // CHECK-NOT: !dbg
+  llvm.call @func_no_debug() : () -> () loc(unknown)
+
+  // CHECK: call void @func_no_debug(), !dbg ![[CALLSITE_LOC:[0-9]+]]
+  llvm.call @func_no_debug() : () -> () loc(callsite("mysource.cc":3:4 at "mysource.cc":5:6))
+
+  // CHECK: call void @func_no_debug(), !dbg ![[FILE_LOC:[0-9]+]]
+  llvm.call @func_no_debug() : () -> () loc("foo.mlir":1:2)
+
+  // CHECK: call void @func_no_debug(), !dbg ![[NAMED_LOC:[0-9]+]]
+  llvm.call @func_no_debug() : () -> () loc("named"("foo.mlir":10:10))
+
+  // CHECK: call void @func_no_debug(), !dbg ![[FUSED_LOC:[0-9]+]]
+  llvm.call @func_no_debug() : () -> () loc(fused[callsite("mysource.cc":1:1 at "mysource.cc":5:6), "mysource.cc":1:1])
+
+  llvm.return
+} loc("foo.mlir":1:1)
+
+// CHECK-DAG: ![[FUNC_LOC]] = distinct !DISubprogram{{.*}}, line: 1
+// CHECK-DAG: ![[CALLSITE_LOC]] = !DILocation(line: 3, column: 4,
+// CHECK-DAG: ![[FILE_LOC]] = !DILocation(line: 1, column: 2,
+// CHECK-DAG: ![[NAMED_LOC]] = !DILocation(line: 10, column: 10
+// CHECK-DAG: ![[FUSED_LOC]] = !DILocation(line: 1, column: 1
index 5b426d7..1049c9c 100644 (file)
@@ -74,7 +74,7 @@ llvm.func @malloc(!llvm.i64) -> !llvm<"i8*">
 // phi nodes, scalar type conversion, arithmetic operations.
 //
 
-// CHECK-LABEL: define void @empty() {
+// CHECK-LABEL: define void @empty()
 // CHECK-NEXT:    ret void
 // CHECK-NEXT:  }
 llvm.func @empty() {
@@ -102,7 +102,7 @@ llvm.func @global_refs() {
 llvm.func @body(!llvm.i64)
 
 
-// CHECK-LABEL: define void @simple_loop() {
+// CHECK-LABEL: define void @simple_loop()
 llvm.func @simple_loop() {
 // CHECK: br label %[[SIMPLE_bb1:[0-9]+]]
   llvm.br ^bb1
@@ -139,7 +139,7 @@ llvm.func @simple_loop() {
   llvm.return
 }
 
-// CHECK-LABEL: define void @simple_caller() {
+// CHECK-LABEL: define void @simple_caller()
 // CHECK-NEXT:   call void @simple_loop()
 // CHECK-NEXT:   ret void
 // CHECK-NEXT: }
@@ -155,7 +155,7 @@ llvm.func @simple_caller() {
 //  return
 //}
 
-// CHECK-LABEL: define void @ml_caller() {
+// CHECK-LABEL: define void @ml_caller()
 // CHECK-NEXT:   call void @simple_loop()
 // CHECK-NEXT:   call void @more_imperfectly_nested_loops()
 // CHECK-NEXT:   ret void
@@ -171,7 +171,7 @@ llvm.func @body_args(!llvm.i64) -> !llvm.i64
 // CHECK-LABEL: declare i32 @other(i64, i32)
 llvm.func @other(!llvm.i64, !llvm.i32) -> !llvm.i32
 
-// CHECK-LABEL: define i32 @func_args(i32 {{%.*}}, i32 {{%.*}}) {
+// CHECK-LABEL: define i32 @func_args(i32 {{%.*}}, i32 {{%.*}})
 // CHECK-NEXT: br label %[[ARGS_bb1:[0-9]+]]
 llvm.func @func_args(%arg0: !llvm.i32, %arg1: !llvm.i32) -> !llvm.i32 {
   %0 = llvm.mlir.constant(0 : i32) : !llvm.i32
@@ -226,7 +226,7 @@ llvm.func @body2(!llvm.i64, !llvm.i64)
 // CHECK: declare void @post(i64)
 llvm.func @post(!llvm.i64)
 
-// CHECK-LABEL: define void @imperfectly_nested_loops() {
+// CHECK-LABEL: define void @imperfectly_nested_loops()
 // CHECK-NEXT:   br label %[[IMPER_bb1:[0-9]+]]
 llvm.func @imperfectly_nested_loops() {
   llvm.br ^bb1
@@ -301,7 +301,7 @@ llvm.func @mid(!llvm.i64)
 llvm.func @body3(!llvm.i64, !llvm.i64)
 
 // A complete function transformation check.
-// CHECK-LABEL: define void @more_imperfectly_nested_loops() {
+// CHECK-LABEL: define void @more_imperfectly_nested_loops()
 // CHECK-NEXT:   br label %1
 // CHECK: 1:                                      ; preds = %0
 // CHECK-NEXT:   br label %2
@@ -638,7 +638,7 @@ llvm.func @store_load_mixed(%arg0: !llvm.i64) {
   llvm.return
 }
 
-// CHECK-LABEL: define { float*, i64 } @memref_args_rets({ float* } {{%.*}}, { float*, i64 } {{%.*}}, { float*, i64 } {{%.*}}) {
+// CHECK-LABEL: define { float*, i64 } @memref_args_rets({ float* } {{%.*}}, { float*, i64 } {{%.*}}, { float*, i64 } {{%.*}})
 llvm.func @memref_args_rets(%arg0: !llvm<"{ float* }">, %arg1: !llvm<"{ float*, i64 }">, %arg2: !llvm<"{ float*, i64 }">) -> !llvm<"{ float*, i64 }"> {
   %0 = llvm.mlir.constant(7 : index) : !llvm.i64
 // CHECK-NEXT: %{{[0-9]+}} = call i64 @get_index()
@@ -718,7 +718,7 @@ llvm.func @get_i64() -> !llvm.i64
 llvm.func @get_f32() -> !llvm.float
 llvm.func @get_memref() -> !llvm<"{ float*, i64, i64 }">
 
-// CHECK-LABEL: define { i64, float, { float*, i64, i64 } } @multireturn() {
+// CHECK-LABEL: define { i64, float, { float*, i64, i64 } } @multireturn()
 llvm.func @multireturn() -> !llvm<"{ i64, float, { float*, i64, i64 } }"> {
   %0 = llvm.call @get_i64() : () -> !llvm.i64
   %1 = llvm.call @get_f32() : () -> !llvm.float
@@ -735,7 +735,7 @@ llvm.func @multireturn() -> !llvm<"{ i64, float, { float*, i64, i64 } }"> {
 }
 
 
-// CHECK-LABEL: define void @multireturn_caller() {
+// CHECK-LABEL: define void @multireturn_caller()
 llvm.func @multireturn_caller() {
 // CHECK-NEXT:   %1 = call { i64, float, { float*, i64, i64 } } @multireturn()
 // CHECK-NEXT:   [[ret0:%[0-9]+]] = extractvalue { i64, float, { float*, i64, i64 } } %1, 0
@@ -769,7 +769,7 @@ llvm.func @multireturn_caller() {
   llvm.return
 }
 
-// CHECK-LABEL: define <4 x float> @vector_ops(<4 x float> {{%.*}}, <4 x i1> {{%.*}}, <4 x i64> {{%.*}}) {
+// CHECK-LABEL: define <4 x float> @vector_ops(<4 x float> {{%.*}}, <4 x i1> {{%.*}}, <4 x i64> {{%.*}})
 llvm.func @vector_ops(%arg0: !llvm<"<4 x float>">, %arg1: !llvm<"<4 x i1>">, %arg2: !llvm<"<4 x i64>">) -> !llvm<"<4 x float>"> {
   %0 = llvm.mlir.constant(dense<4.200000e+01> : vector<4xf32>) : !llvm<"<4 x float>">
 // CHECK-NEXT: %4 = fadd <4 x float> %0, <float 4.200000e+01, float 4.200000e+01, float 4.200000e+01, float 4.200000e+01>
@@ -883,7 +883,7 @@ llvm.func @ops(%arg0: !llvm.float, %arg1: !llvm.float, %arg2: !llvm.i32, %arg3:
 // Indirect function calls
 //
 
-// CHECK-LABEL: define void @indirect_const_call(i64 {{%.*}}) {
+// CHECK-LABEL: define void @indirect_const_call(i64 {{%.*}})
 llvm.func @indirect_const_call(%arg0: !llvm.i64) {
 // CHECK-NEXT:  call void @body(i64 %0)
   %0 = llvm.mlir.constant(@body) : !llvm<"void (i64)*">
@@ -892,7 +892,7 @@ llvm.func @indirect_const_call(%arg0: !llvm.i64) {
   llvm.return
 }
 
-// CHECK-LABEL: define i32 @indirect_call(i32 (float)* {{%.*}}, float {{%.*}}) {
+// CHECK-LABEL: define i32 @indirect_call(i32 (float)* {{%.*}}, float {{%.*}})
 llvm.func @indirect_call(%arg0: !llvm<"i32 (float)*">, %arg1: !llvm.float) -> !llvm.i32 {
 // CHECK-NEXT:  %3 = call i32 %0(float %1)
   %0 = llvm.call %arg0(%arg1) : (!llvm.float) -> !llvm.i32
@@ -905,7 +905,7 @@ llvm.func @indirect_call(%arg0: !llvm<"i32 (float)*">, %arg1: !llvm.float) -> !l
 // predecessor more than once.
 //
 
-// CHECK-LABEL: define void @cond_br_arguments(i1 {{%.*}}, i1 {{%.*}}) {
+// CHECK-LABEL: define void @cond_br_arguments(i1 {{%.*}}, i1 {{%.*}})
 llvm.func @cond_br_arguments(%arg0: !llvm.i1, %arg1: !llvm.i1) {
 // CHECK-NEXT:   br i1 %0, label %3, label %5
   llvm.cond_br %arg0, ^bb1(%arg0 : !llvm.i1), ^bb2
@@ -922,7 +922,7 @@ llvm.func @cond_br_arguments(%arg0: !llvm.i1, %arg1: !llvm.i1) {
   llvm.br ^bb1(%arg1 : !llvm.i1)
 }
 
-// CHECK-LABEL: define void @llvm_noalias(float* noalias {{%*.}}) {
+// CHECK-LABEL: define void @llvm_noalias(float* noalias {{%*.}})
 llvm.func @llvm_noalias(%arg0: !llvm<"float*"> {llvm.noalias = true}) {
   llvm.return
 }
index 0eb06ec..1754e0e 100644 (file)
@@ -28,6 +28,7 @@
 #include "mlir/Pass/PassManager.h"
 #include "mlir/Support/JitRunner.h"
 #include "mlir/Transforms/DialectConversion.h"
+#include "mlir/Transforms/Passes.h"
 
 #include "cuda.h"
 
@@ -106,6 +107,7 @@ static LogicalResult runMLIRPasses(ModuleOp m) {
 
   pm.addPass(createGpuKernelOutliningPass());
   auto &kernelPm = pm.nest<gpu::GPUModuleOp>();
+  kernelPm.addPass(createStripDebugInfoPass());
   kernelPm.addPass(createLowerGpuOpsToNVVMOpsPass());
   kernelPm.addPass(createConvertGPUKernelToCubinPass(&compilePtxToCubin));
   pm.addPass(createLowerToLLVMPass());