[mlir][llvm] Make the import of LLVM IR metadata extensible.
authorTobias Gysi <tobias.gysi@nextsilicon.com>
Tue, 3 Jan 2023 12:46:08 +0000 (13:46 +0100)
committerTobias Gysi <tobias.gysi@nextsilicon.com>
Tue, 3 Jan 2023 13:47:25 +0000 (14:47 +0100)
This revision extends the LLVMImportDialectInterface to make the import
of LLVM IR instruction-level metadata extensible. It extends the
signature of the existing dialect interface to provide a method to
import specific metadata kinds and attach them to the imported
operation. The conversion function can rely on the ModuleImport class
to perform support tasks.

The revision implements the second part of the
"extensible llvm ir import" rfc:
https://discourse.llvm.org/t/rfc-extensible-llvm-ir-import/67256/6

The interface method names changed a bit compared to the suggested
design. The hook to set the instruction level metadata is now called
setMetadataAttrs and takes the metadata kind as an additional parameter.
We do not hand in the original LLVM IR instruction since it is not used
at this point. Importing named module-level meta data can be added in a
later stage after gaining some experience with this extension mechanism.

Depends on D140374

Reviewed By: ftynse, Dinistro

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

mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
mlir/include/mlir/Target/LLVMIR/ModuleImport.h
mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
mlir/lib/Target/LLVMIR/ModuleImport.cpp
mlir/test/Target/LLVMIR/Import/import-failure.ll
mlir/test/Target/LLVMIR/Import/profiling-metadata.ll [new file with mode: 0644]
mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp

index 0e478ce..1ce8e80 100644 (file)
@@ -178,14 +178,14 @@ class LLVM_LifetimeBaseOp<string opName> : LLVM_ZeroResultIntrOp<opName> {
 def LLVM_LifetimeStartOp : LLVM_LifetimeBaseOp<"lifetime.start"> {
   // Custom builder to convert the size argument to an attribute.
   string mlirBuilder = [{
-    $_builder.create<LLVM::LifetimeStartOp>(
+    $_op = $_builder.create<LLVM::LifetimeStartOp>(
       $_location, $_int_attr($size), $ptr);
   }];
 }
 def LLVM_LifetimeEndOp : LLVM_LifetimeBaseOp<"lifetime.end"> {
   // Custom builder to convert the size argument to an attribute.
   string mlirBuilder = [{
-    $_builder.create<LLVM::LifetimeEndOp>(
+    $_op = $_builder.create<LLVM::LifetimeEndOp>(
       $_location, $_int_attr($size), $ptr);
   }];
 }
@@ -286,7 +286,7 @@ class LLVM_DbgIntrOp<string name, string argName> : LLVM_IntrOp<name, [], [], []
     // convertible to MLIR.
     auto *dbgIntr = cast<llvm::DbgVariableIntrinsic>(inst);
     if (dbgIntr->getExpression()->getNumElements() == 0)
-      $_builder.create<$_qualCppClassName>($_location,
+      $_op = $_builder.create<$_qualCppClassName>($_location,
         $}] # argName # [{, $_var_attr($varInfo));
   }];
   let assemblyFormat = [{
@@ -484,7 +484,7 @@ def LLVM_MatrixColumnMajorStoreOp : LLVM_ZeroResultIntrOp<"matrix.column.major.s
       $rows, $columns);
   }];
   string mlirBuilder = [{
-    $_builder.create<LLVM::MatrixColumnMajorStoreOp>(
+    $_op = $_builder.create<LLVM::MatrixColumnMajorStoreOp>(
       $_location, $matrix, $data, $stride,
       $_int_attr($isVolatile), $_int_attr($rows), $_int_attr($columns));
   }];
@@ -579,7 +579,7 @@ def LLVM_MaskedStoreOp : LLVM_ZeroResultIntrOp<"masked.store"> {
       $value, $data, llvm::Align($alignment), $mask);
   }];
   string mlirBuilder = [{
-    $_builder.create<LLVM::MaskedStoreOp>($_location,
+    $_op = $_builder.create<LLVM::MaskedStoreOp>($_location,
       $value, $data, $mask, $_int_attr($alignment));
   }];
   list<int> llvmArgIndices = [0, 1, 3, 2];
@@ -621,7 +621,7 @@ def LLVM_masked_scatter : LLVM_ZeroResultIntrOp<"masked.scatter"> {
       $value, $ptrs, llvm::Align($alignment), $mask);
   }];
   string mlirBuilder = [{
-    $_builder.create<LLVM::masked_scatter>($_location,
+    $_op = $_builder.create<LLVM::masked_scatter>($_location,
       $value, $ptrs, $mask, $_int_attr($alignment));
   }];
   list<int> llvmArgIndices = [0, 1, 3, 2];
index 048281f..c85df7d 100644 (file)
@@ -234,12 +234,16 @@ class LLVM_OpBase<Dialect dialect, string mnemonic, list<Trait> traits = []> :
   //             of the MLIR operation argument with the given name, or if the
   //             name matches the result name, by a reference to store the
   //             result of the newly created MLIR operation to;
+  //   - $_op - substituted by a reference to store the newly created MLIR
+  //            operation (only for MLIR operations that return no result);
   //   - $_int_attr - substituted by a call to an integer attribute matcher;
   //   - $_var_attr - substituted by a call to a variable attribute matcher;
   //   - $_resultType - substituted with the MLIR result type;
   //   - $_location - substituted with the MLIR location;
   //   - $_builder - substituted with the MLIR builder;
   //   - $_qualCppClassName - substitiuted with the MLIR operation class name.
+  // Always either store a reference to the result of the newly created
+  // operation, or to the operation itself if it does not return a result.
   // Additionally, `$$` can be used to produce the dollar character.
   string mlirBuilder = "";
 
@@ -388,7 +392,7 @@ class LLVM_IntrOpBase<Dialect dialect, string opName, string enumName,
       $_location, resultTypes, *mlirOperands);
     }] # !if(!gt(requiresFastmath, 0),
       "moduleImport.setFastmathFlagsAttr(inst, op);", "")
-    # !if(!gt(numResults, 0), "$res = op;", "(void)op;");
+    # !if(!gt(numResults, 0), "$res = op;", "$_op = op;");
 }
 
 // Base class for LLVM intrinsic operations, should not be used directly. Places
index 2e46a71..714209c 100644 (file)
@@ -400,7 +400,7 @@ def LLVM_StoreOp : LLVM_Op<"store">, MemoryOpWithAlignmentAndAttributes {
      # setAliasScopeMetadataCode;
   // FIXME: Import attributes.
   string mlirBuilder = [{
-    $_builder.create<LLVM::StoreOp>($_location, $value, $addr);
+    $_op = $_builder.create<LLVM::StoreOp>($_location, $value, $addr);
   }];
   let builders = [
     OpBuilder<(ins "Value":$value, "Value":$addr,
@@ -830,7 +830,7 @@ def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [Pure, ReturnLike]> {
       moduleImport.convertValues(llvmOperands);
     if (failed(mlirOperands))
       return failure();
-    $_builder.create<LLVM::ReturnOp>($_location, *mlirOperands);
+    $_op = $_builder.create<LLVM::ReturnOp>($_location, *mlirOperands);
   }];
 }
 
@@ -841,7 +841,7 @@ def LLVM_ResumeOp : LLVM_TerminatorOp<"resume"> {
   string llvmInstName = "Resume";
   string llvmBuilder = [{ builder.CreateResume($value); }];
   string mlirBuilder = [{
-    $_builder.create<LLVM::ResumeOp>($_location, $value);
+    $_op = $_builder.create<LLVM::ResumeOp>($_location, $value);
   }];
 }
 def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable"> {
@@ -849,7 +849,7 @@ def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable"> {
   string llvmInstName = "Unreachable";
   string llvmBuilder = [{ builder.CreateUnreachable(); }];
   string mlirBuilder = [{
-    $_builder.create<LLVM::UnreachableOp>($_location);
+    $_op = $_builder.create<LLVM::UnreachableOp>($_location);
   }];
 }
 
@@ -1559,7 +1559,7 @@ def LLVM_FenceOp : LLVM_Op<"fence"> {
   }];
   string mlirBuilder = [{
     llvm::FenceInst *fenceInst = cast<llvm::FenceInst>(inst);
-    $_builder.create<LLVM::FenceOp>(
+    $_op = $_builder.create<LLVM::FenceOp>(
       $_location,
       getLLVMAtomicOrdering(fenceInst->getOrdering()),
       getLLVMSyncScope(fenceInst));
index 014107a..9f8da83 100644 (file)
@@ -52,10 +52,24 @@ public:
     return failure();
   }
 
+  /// Hook for derived dialect interfaces to implement the import of metadata
+  /// into MLIR. Attaches the converted metadata kind and node to the provided
+  /// operation.
+  virtual LogicalResult
+  setMetadataAttrs(OpBuilder &builder, unsigned kind, llvm::MDNode *node,
+                   Operation *op, LLVM::ModuleImport &moduleImport) const {
+    return failure();
+  }
+
   /// Hook for derived dialect interfaces to publish the supported intrinsics.
   /// As every LLVM IR intrinsic has a unique integer identifier, the function
   /// returns the list of supported intrinsic identifiers.
   virtual ArrayRef<unsigned> getSupportedIntrinsics() const { return {}; }
+
+  /// Hook for derived dialect interfaces to publish the supported metadata
+  /// kinds. As every metadata kind has a unique integer identifier, the
+  /// function returns the list of supported metadata identifiers.
+  virtual ArrayRef<unsigned> getSupportedMetadata() const { return {}; }
 };
 
 /// Interface collection for the import of LLVM IR that dispatches to a concrete
@@ -67,10 +81,10 @@ class LLVMImportInterface
 public:
   using Base::Base;
 
-  /// Queries all dialect interfaces to build a map from intrinsic identifiers
-  /// to the dialect interface that supports importing the intrinsic. Returns
-  /// failure if multiple dialect interfaces translate the same LLVM IR
-  /// intrinsic.
+  /// Queries all registered dialect interfaces for the supported LLVM IR
+  /// intrinsic and metadata kinds and builds the dispatch tables for the
+  /// conversion. Returns failure if multiple dialect interfaces translate the
+  /// same LLVM IR intrinsic.
   LogicalResult initializeImport() {
     for (const LLVMImportDialectInterface &iface : *this) {
       // Verify the supported intrinsics have not been mapped before.
@@ -89,6 +103,9 @@ public:
       // Add a mapping for all supported intrinsic identifiers.
       for (unsigned id : iface.getSupportedIntrinsics())
         intrinsicToDialect[id] = iface.getDialect();
+      // Add a mapping for all supported metadata kinds.
+      for (unsigned kind : iface.getSupportedMetadata())
+        metadataToDialect[kind].push_back(iface.getDialect());
     }
 
     return success();
@@ -115,8 +132,41 @@ public:
     return intrinsicToDialect.count(id);
   }
 
+  /// Attaches the given LLVM metadata to the imported operation if a conversion
+  /// to one or more MLIR dialect attributes exists and succeeds. Returns
+  /// success if at least one of the conversions is successful and failure if
+  /// all of them fail.
+  LogicalResult setMetadataAttrs(OpBuilder &builder, unsigned kind,
+                                 llvm::MDNode *node, Operation *op,
+                                 LLVM::ModuleImport &moduleImport) const {
+    // Lookup the dialect interfaces for the given metadata.
+    auto it = metadataToDialect.find(kind);
+    if (it == metadataToDialect.end())
+      return failure();
+
+    // Dispatch the conversion to the dialect interfaces.
+    bool isSuccess = false;
+    for (Dialect *dialect : it->getSecond()) {
+      const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
+      assert(iface && "expected to find a dialect interface");
+      if (succeeded(
+              iface->setMetadataAttrs(builder, kind, node, op, moduleImport)))
+        isSuccess = true;
+    }
+
+    // Returns failure if all conversions fail.
+    return success(isSuccess);
+  }
+
+  /// Returns true if the given LLVM IR metadata is convertible to an MLIR
+  /// attribute.
+  bool isConvertibleMetadata(unsigned kind) {
+    return metadataToDialect.count(kind);
+  }
+
 private:
   DenseMap<unsigned, Dialect *> intrinsicToDialect;
+  DenseMap<unsigned, SmallVector<Dialect *, 1>> metadataToDialect;
 };
 
 } // namespace mlir
index 903160f..27e2b29 100644 (file)
@@ -46,9 +46,9 @@ public:
   ModuleImport(ModuleOp mlirModule, std::unique_ptr<llvm::Module> llvmModule);
 
   /// Calls the LLVMImportInterface initialization that queries the registered
-  /// dialect interfaces for the supported LLVM IR intrinsics and builds the
-  /// dispatch table. Returns failure if multiple dialect interfaces translate
-  /// the same LLVM IR intrinsic.
+  /// dialect interfaces for the supported LLVM IR intrinsics and metadata kinds
+  /// and builds the dispatch tables. Returns failure if multiple dialect
+  /// interfaces translate the same LLVM IR intrinsic.
   LogicalResult initializeImportInterface() { return iface.initializeImport(); }
 
   /// Converts all functions of the LLVM module to MLIR functions.
@@ -72,6 +72,35 @@ public:
   /// Returns the MLIR value mapped to the given LLVM value.
   Value lookupValue(llvm::Value *value) { return valueMapping.lookup(value); }
 
+  /// Stores a mapping between an LLVM instruction and the imported MLIR
+  /// operation if the operation returns no result. Asserts if the operation
+  /// returns a result and should be added to valueMapping instead.
+  void mapNoResultOp(llvm::Instruction *inst, Operation *mlir) {
+    mapNoResultOp(inst) = mlir;
+  }
+
+  /// Provides write-once access to store the MLIR operation corresponding to
+  /// the given LLVM instruction if the operation returns no result. Asserts if
+  /// the operation returns a result and should be added to valueMapping
+  /// instead.
+  Operation *&mapNoResultOp(llvm::Instruction *inst) {
+    Operation *&mlir = noResultOpMapping[inst];
+    assert(inst->getType()->isVoidTy() &&
+           "attempting to map an operation that returns a result");
+    assert(mlir == nullptr &&
+           "attempting to map an operation that is already mapped");
+    return mlir;
+  }
+
+  /// Returns the MLIR operation mapped to the given LLVM instruction. Queries
+  /// valueMapping and noResultOpMapping to support operations with and without
+  /// result.
+  Operation *lookupOperation(llvm::Instruction *inst) {
+    if (Value value = lookupValue(inst))
+      return value.getDefiningOp();
+    return noResultOpMapping.lookup(inst);
+  }
+
   /// Stores the mapping between an LLVM block and its MLIR counterpart.
   void mapBlock(llvm::BasicBlock *llvm, Block *mlir) {
     auto result = blockMapping.try_emplace(llvm, mlir);
@@ -127,6 +156,7 @@ private:
   /// Clears the block and value mapping before processing a new region.
   void clearBlockAndValueMapping() {
     valueMapping.clear();
+    noResultOpMapping.clear();
     blockMapping.clear();
   }
   /// Sets the constant insertion point to the start of the given block.
@@ -146,8 +176,14 @@ private:
   /// counterpart exists. Otherwise, returns failure.
   LogicalResult convertInstruction(OpBuilder &odsBuilder,
                                    llvm::Instruction *inst);
+  /// Converts the metadata attached to the original instruction `inst` if
+  /// a dialect interfaces supports the specific kind of metadata and attaches
+  /// the resulting dialect attributes to the converted operation `op`. Emits a
+  /// warning if the conversion of a supported metadata kind fails.
+  void setNonDebugMetadataAttrs(llvm::Instruction *inst, Operation *op);
   /// Imports `inst` and populates valueMapping[inst] with the result of the
-  /// imported operation.
+  /// imported operation or noResultOpMapping[inst] with the imported operation
+  /// if it has no result.
   LogicalResult processInstruction(llvm::Instruction *inst);
   /// Converts the `branch` arguments in the order of the phi's found in
   /// `target` and appends them to the `blockArguments` to attach to the
@@ -205,6 +241,10 @@ private:
   DenseMap<llvm::BasicBlock *, Block *> blockMapping;
   /// Function-local mapping between original and imported values.
   DenseMap<llvm::Value *, Value> valueMapping;
+  /// Function-local mapping between original instructions and imported
+  /// operations for all operations that return no result. All operations that
+  /// return a result have a valueMapping entry instead.
+  DenseMap<llvm::Instruction *, Operation *> noResultOpMapping;
   /// Uniquing map of GlobalVariables.
   DenseMap<llvm::GlobalVariable *, GlobalOp> globals;
   /// The stateful type translator (contains named structs).
index ff6ed96..493be27 100644 (file)
@@ -65,6 +65,51 @@ static LogicalResult convertIntrinsicImpl(OpBuilder &odsBuilder,
   return failure();
 }
 
+/// Returns the list of LLVM IR metadata kinds that are convertible to MLIR LLVM
+/// dialect attributes.
+static ArrayRef<unsigned> getSupportedMetadataImpl() {
+  static const SmallVector<unsigned> convertibleMetadata = {
+      llvm::LLVMContext::MD_prof // profiling metadata
+  };
+  return convertibleMetadata;
+}
+
+/// Attaches the given profiling metadata to the imported operation if a
+/// conversion to an MLIR profiling attribute exists and succeeds. Returns
+/// failure otherwise.
+static LogicalResult setProfilingAttrs(OpBuilder &builder, llvm::MDNode *node,
+                                       Operation *op,
+                                       LLVM::ModuleImport &moduleImport) {
+  // Return success for empty metadata nodes since there is nothing to import.
+  if (!node->getNumOperands())
+    return success();
+
+  // Return failure for non-"branch_weights" metadata.
+  auto *name = dyn_cast<llvm::MDString>(node->getOperand(0));
+  if (!name || !name->getString().equals("branch_weights"))
+    return failure();
+
+  // Copy the branch weights to an array.
+  SmallVector<int32_t> branchWeights;
+  branchWeights.reserve(node->getNumOperands() - 1);
+  for (unsigned i = 1, e = node->getNumOperands(); i != e; ++i) {
+    llvm::ConstantInt *branchWeight =
+        llvm::mdconst::extract<llvm::ConstantInt>(node->getOperand(i));
+    branchWeights.push_back(branchWeight->getZExtValue());
+  }
+
+  // Attach the branch weights to the operations that support it.
+  if (auto condBrOp = dyn_cast<CondBrOp>(op)) {
+    condBrOp.setBranchWeightsAttr(builder.getI32VectorAttr(branchWeights));
+    return success();
+  }
+  if (auto switchOp = dyn_cast<SwitchOp>(op)) {
+    switchOp.setBranchWeightsAttr(builder.getI32VectorAttr(branchWeights));
+    return success();
+  }
+  return failure();
+}
+
 namespace {
 
 /// Implementation of the dialect interface that converts operations belonging
@@ -80,11 +125,31 @@ public:
     return convertIntrinsicImpl(builder, inst, moduleImport);
   }
 
+  /// Attaches the given LLVM metadata to the imported operation if a conversion
+  /// to an LLVM dialect attribute exists and succeeds. Returns failure
+  /// otherwise.
+  LogicalResult setMetadataAttrs(OpBuilder &builder, unsigned kind,
+                                 llvm::MDNode *node, Operation *op,
+                                 LLVM::ModuleImport &moduleImport) const final {
+    // Call metadata specific handlers.
+    if (kind == llvm::LLVMContext::MD_prof)
+      return setProfilingAttrs(builder, node, op, moduleImport);
+
+    // A handler for a supported metadata kind is missing.
+    llvm_unreachable("unknown metadata type");
+  }
+
   /// Returns the list of LLVM IR intrinsic identifiers that are convertible to
   /// MLIR LLVM dialect intrinsics.
   ArrayRef<unsigned> getSupportedIntrinsics() const final {
     return getSupportedIntrinsicsImpl();
   }
+
+  /// Returns the list of LLVM IR metadata kinds that are convertible to MLIR
+  /// LLVM dialect attributes.
+  ArrayRef<unsigned> getSupportedMetadata() const final {
+    return getSupportedMetadataImpl();
+  }
 };
 } // namespace
 
index 77828c9..750e967 100644 (file)
@@ -29,6 +29,7 @@
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Metadata.h"
 #include "llvm/IR/Operator.h"
 
 using namespace mlir;
@@ -331,6 +332,20 @@ LogicalResult ModuleImport::convertFunctions() {
   return success();
 }
 
+void ModuleImport::setNonDebugMetadataAttrs(llvm::Instruction *inst,
+                                            Operation *op) {
+  SmallVector<std::pair<unsigned, llvm::MDNode *>> allMetadata;
+  inst->getAllMetadataOtherThanDebugLoc(allMetadata);
+  for (auto &[kind, node] : allMetadata) {
+    if (!iface.isConvertibleMetadata(kind))
+      continue;
+    if (failed(iface.setMetadataAttrs(builder, kind, node, op, *this))) {
+      Location loc = debugImporter->translateLoc(inst->getDebugLoc());
+      emitWarning(loc) << "unhandled metadata (" << kind << ") " << diag(*inst);
+    }
+  }
+}
+
 void ModuleImport::setFastmathFlagsAttr(llvm::Instruction *inst,
                                         Operation *op) const {
   auto iface = cast<FastmathFlagsInterface>(op);
@@ -625,6 +640,8 @@ FailureOr<Value> ModuleImport::convertConstant(llvm::Constant *constant) {
     // resulting in a conflicting `valueMapping` entry.
     llvm::Instruction *inst = constExpr->getAsInstruction();
     auto guard = llvm::make_scope_exit([&]() {
+      assert(noResultOpMapping.find(inst) == noResultOpMapping.end() &&
+             "expected constant expression to return a result");
       valueMapping.erase(inst);
       inst->deleteValue();
     });
@@ -833,17 +850,19 @@ LogicalResult ModuleImport::convertInstruction(OpBuilder &odsBuilder,
       succBlockArgs.push_back(blockArgs);
     }
 
-    if (brInst->isConditional()) {
-      FailureOr<Value> condition = convertValue(brInst->getCondition());
-      if (failed(condition))
-        return failure();
-      builder.create<LLVM::CondBrOp>(loc, *condition, succBlocks.front(),
-                                     succBlockArgs.front(), succBlocks.back(),
-                                     succBlockArgs.back());
-    } else {
-      builder.create<LLVM::BrOp>(loc, succBlockArgs.front(),
-                                 succBlocks.front());
+    if (!brInst->isConditional()) {
+      auto brOp = builder.create<LLVM::BrOp>(loc, succBlockArgs.front(),
+                                             succBlocks.front());
+      mapNoResultOp(inst, brOp);
+      return success();
     }
+    FailureOr<Value> condition = convertValue(brInst->getCondition());
+    if (failed(condition))
+      return failure();
+    auto condBrOp = builder.create<LLVM::CondBrOp>(
+        loc, *condition, succBlocks.front(), succBlockArgs.front(),
+        succBlocks.back(), succBlockArgs.back());
+    mapNoResultOp(inst, condBrOp);
     return success();
   }
   if (inst->getOpcode() == llvm::Instruction::Switch) {
@@ -874,9 +893,10 @@ LogicalResult ModuleImport::convertInstruction(OpBuilder &odsBuilder,
       caseBlocks[it.index()] = lookupBlock(succBB);
     }
 
-    builder.create<SwitchOp>(loc, *condition, lookupBlock(defaultBB),
-                             defaultBlockArgs, caseValues, caseBlocks,
-                             caseOperandRefs);
+    auto switchOp = builder.create<SwitchOp>(
+        loc, *condition, lookupBlock(defaultBB), defaultBlockArgs, caseValues,
+        caseBlocks, caseOperandRefs);
+    mapNoResultOp(inst, switchOp);
     return success();
   }
   if (inst->getOpcode() == llvm::Instruction::PHI) {
@@ -903,6 +923,8 @@ LogicalResult ModuleImport::convertInstruction(OpBuilder &odsBuilder,
     setFastmathFlagsAttr(inst, callOp);
     if (!callInst->getType()->isVoidTy())
       mapValue(inst, callOp.getResult());
+    else
+      mapNoResultOp(inst, callOp);
     return success();
   }
   if (inst->getOpcode() == llvm::Instruction::LandingPad) {
@@ -918,9 +940,9 @@ LogicalResult ModuleImport::convertInstruction(OpBuilder &odsBuilder,
     }
 
     Type type = convertType(lpInst->getType());
-    Value res =
+    auto lpOp =
         builder.create<LandingpadOp>(loc, type, lpInst->isCleanup(), operands);
-    mapValue(inst, res);
+    mapValue(inst, lpOp);
     return success();
   }
   if (inst->getOpcode() == llvm::Instruction::Invoke) {
@@ -951,6 +973,8 @@ LogicalResult ModuleImport::convertInstruction(OpBuilder &odsBuilder,
     }
     if (!invokeInst->getType()->isVoidTy())
       mapValue(inst, invokeOp.getResults().front());
+    else
+      mapNoResultOp(inst, invokeOp);
     return success();
   }
   if (inst->getOpcode() == llvm::Instruction::GetElementPtr) {
@@ -973,9 +997,9 @@ LogicalResult ModuleImport::convertInstruction(OpBuilder &odsBuilder,
     }
 
     Type type = convertType(inst->getType());
-    Value res = builder.create<GEPOp>(loc, type, sourceElementType, *basePtr,
-                                      indices, gepInst->isInBounds());
-    mapValue(inst, res);
+    auto gepOp = builder.create<GEPOp>(loc, type, sourceElementType, *basePtr,
+                                       indices, gepInst->isInBounds());
+    mapValue(inst, gepOp);
     return success();
   }
 
@@ -1131,6 +1155,16 @@ LogicalResult ModuleImport::processBasicBlock(llvm::BasicBlock *bb,
   for (llvm::Instruction &inst : *bb) {
     if (failed(processInstruction(&inst)))
       return failure();
+
+    // Set the non-debug metadata attributes on the imported operation and emit
+    // a warning if an instruction other than a phi instruction is dropped
+    // during the import.
+    if (Operation *op = lookupOperation(&inst)) {
+      setNonDebugMetadataAttrs(&inst, op);
+    } else if (inst.getOpcode() != llvm::Instruction::PHI) {
+      Location loc = debugImporter->translateLoc(inst.getDebugLoc());
+      emitWarning(loc) << "dropped instruction " << diag(inst);
+    }
   }
   return success();
 }
index cefb6bb..740f055 100644 (file)
@@ -1,6 +1,6 @@
 ; RUN: not mlir-translate -import-llvm -split-input-file %s 2>&1 | FileCheck %s
 
-; CHECK: unhandled instruction indirectbr i8* %dst, [label %bb1, label %bb2]
+; CHECK: error: unhandled instruction indirectbr i8* %dst, [label %bb1, label %bb2]
 define i32 @unhandled_instruction(i8* %dst) {
   indirectbr i8* %dst, [label %bb1, label %bb2]
 bb1:
@@ -19,7 +19,7 @@ define i32 @unhandled_value(i32 %arg0) {
 
 ; // -----
 
-; CHECK: unhandled constant i8* blockaddress(@unhandled_constant, %bb1)
+; CHECK: error: unhandled constant i8* blockaddress(@unhandled_constant, %bb1)
 define i8* @unhandled_constant() {
 bb1:
   ret i8* blockaddress(@unhandled_constant, %bb1)
@@ -29,8 +29,41 @@ bb1:
 
 declare void @llvm.gcroot(ptr %arg0, ptr %arg1)
 
-; CHECK: unhandled intrinsic call void @llvm.gcroot(ptr %arg0, ptr %arg1)
+; CHECK: error: unhandled intrinsic call void @llvm.gcroot(ptr %arg0, ptr %arg1)
 define void @unhandled_intrinsic(ptr %arg0, ptr %arg1) {
   call void @llvm.gcroot(ptr %arg0, ptr %arg1)
   ret void
 }
+
+; // -----
+
+; CHECK: warning: unhandled metadata (2)   br i1 %arg1, label %bb1, label %bb2, !prof !0
+define i64 @cond_br(i1 %arg1, i64 %arg2) {
+entry:
+  br i1 %arg1, label %bb1, label %bb2, !prof !0
+bb1:
+  ret i64 %arg2
+bb2:
+  ret i64 %arg2
+}
+
+!0 = !{!"unknown metadata"}
+
+; // -----
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+; CHECK: warning: dropped instruction   call void @llvm.dbg.value(metadata i64 %arg1, metadata !3, metadata !DIExpression(DW_OP_plus_uconst, 42, DW_OP_stack_value)), !dbg !5
+define void @dropped_instruction(i64 %arg1) {
+  call void @llvm.dbg.value(metadata i64 %arg1, metadata !3, metadata !DIExpression(DW_OP_plus_uconst, 42, DW_OP_stack_value)), !dbg !5
+  ret void
+}
+
+!llvm.dbg.cu = !{!1}
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2)
+!2 = !DIFile(filename: "debug-info.ll", directory: "/")
+!3 = !DILocalVariable(scope: !4, name: "arg", file: !2, line: 1, arg: 1, align: 32);
+!4 = distinct !DISubprogram(name: "intrinsic", scope: !2, file: !2, spFlags: DISPFlagDefinition, unit: !1)
+!5 = !DILocation(line: 1, column: 2, scope: !4)
diff --git a/mlir/test/Target/LLVMIR/Import/profiling-metadata.ll b/mlir/test/Target/LLVMIR/Import/profiling-metadata.ll
new file mode 100644 (file)
index 0000000..402271a
--- /dev/null
@@ -0,0 +1,35 @@
+; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
+
+; CHECK-LABEL: @cond_br
+define i64 @cond_br(i1 %arg1, i64 %arg2) {
+entry:
+  ; CHECK: llvm.cond_br
+  ; CHECK-SAME: weights(dense<[0, 3]> : vector<2xi32>)
+  br i1 %arg1, label %bb1, label %bb2, !prof !0
+bb1:
+  ret i64 %arg2
+bb2:
+  ret i64 %arg2
+}
+
+!0 = !{!"branch_weights", i32 0, i32 3}
+
+; // -----
+
+; CHECK-LABEL: @simple_switch(
+define i32 @simple_switch(i32 %arg1) {
+  ; CHECK: llvm.switch
+  ; CHECK: {branch_weights = dense<[42, 3, 5]> : vector<3xi32>}
+  switch i32 %arg1, label %bbd [
+    i32 0, label %bb1
+    i32 9, label %bb2
+  ], !prof !0
+bb1:
+  ret i32 %arg1
+bb2:
+  ret i32 %arg1
+bbd:
+  ret i32 %arg1
+}
+
+!0 = !{!"branch_weights", i32 42, i32 3, i32 5}
index 4e59c8b..1aa5232 100644 (file)
@@ -262,6 +262,8 @@ static LogicalResult emitOneMLIRBuilder(const Record &record, raw_ostream &os,
       if (op.getNumResults() != 1)
         return emitError(record, "expected op to have one result");
       bs << "moduleImport.mapValue(inst)";
+    } else if (name == "_op") {
+      bs << "moduleImport.mapNoResultOp(inst)";
     } else if (name == "_int_attr") {
       bs << "moduleImport.matchIntegerAttr";
     } else if (name == "_var_attr") {