[mlir][llvm] Add experimental alias scope decl intrinsic.
authorTobias Gysi <tobias.gysi@nextsilicon.com>
Wed, 22 Mar 2023 09:20:55 +0000 (10:20 +0100)
committerTobias Gysi <tobias.gysi@nextsilicon.com>
Wed, 22 Mar 2023 09:21:09 +0000 (10:21 +0100)
The revision adds the llvm.experimental.noalias.scope.decl intrinsic
to the LLVM dialect and updates the import and export accordingly.

Reviewed By: Dinistro

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

mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
mlir/include/mlir/Target/LLVMIR/ModuleImport.h
mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
mlir/lib/Target/LLVMIR/ModuleImport.cpp
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
mlir/test/Dialect/LLVMIR/roundtrip.mlir
mlir/test/Target/LLVMIR/Import/import-failure.ll
mlir/test/Target/LLVMIR/Import/metadata-alias-scopes.ll
mlir/test/Target/LLVMIR/llvmir.mlir

index 1b62ce0ca3e6e298a5720e1f183c3058ef7695fb..391de1ffaa5dcfa17b0f8e8bd90632398dd44386 100644 (file)
@@ -167,6 +167,31 @@ def LLVM_MemsetOp : LLVM_ZeroResultIntrOp<"memset", [0, 2], [],
   >];
 }
 
+def LLVM_NoAliasScopeDeclOp
+    : LLVM_ZeroResultIntrOp<"experimental.noalias.scope.decl"> {
+  let arguments = (ins SymbolRefAttr:$scope);
+  string llvmBuilder = [{
+    // Wrap the scope argument into a list since the LLVM IR intrinsic takes
+    // a list containing exactly one scope rather than a scope itself.
+    llvm::MDNode* node = moduleTranslation.getAliasScopes(op, {$scope});
+    builder.CreateNoAliasScopeDeclaration(node);
+  }];
+  string mlirBuilder = [{
+    FailureOr<SmallVector<SymbolRefAttr>> scopeAttrs =
+      moduleImport.matchAliasScopeAttrs(llvmOperands[0]);
+    // Drop the intrinsic if the alias scope translation fails since the scope
+    // is not used by an aliasing operation, such as a load or store, that is
+    // used to convert the alias scope metadata.
+    if (failed(scopeAttrs))
+      return success();
+    if (scopeAttrs->size() != 1)
+      return failure();
+    $_op = $_builder.create<LLVM::NoAliasScopeDeclOp>(
+      $_location, (*scopeAttrs)[0]);
+  }];
+  let assemblyFormat = "$scope attr-dict";
+}
+
 //===----------------------------------------------------------------------===//
 // Lifetime Markers
 //===----------------------------------------------------------------------===//
index be4f6e5717b11101f0be5bd2220671f7d1a0e55f..e1a94d6b80cc9464b7661e9f8766cb75d38ce7a0 100644 (file)
@@ -135,6 +135,11 @@ public:
   /// fails.
   DILocalVariableAttr matchLocalVariableAttr(llvm::Value *value);
 
+  /// Converts `value` to an array of symbol references pointing to alias scope
+  /// operations, or returns failure if the conversion fails.
+  FailureOr<SmallVector<SymbolRefAttr>>
+  matchAliasScopeAttrs(llvm::Value *value);
+
   /// Translates the debug location.
   Location translateLoc(llvm::DILocation *loc);
 
index 67091257a3cf93a1a09596294c040084d9e7c983..a04e285af580e3fe79493674c1a1df488b45b9ce 100644 (file)
@@ -122,9 +122,14 @@ public:
   void forgetMapping(Region &region);
 
   /// Returns the LLVM metadata corresponding to a symbol reference to an mlir
-  /// LLVM dialect alias scope operation
+  /// LLVM dialect alias scope operation.
   llvm::MDNode *getAliasScope(Operation *op, SymbolRefAttr aliasScopeRef) const;
 
+  /// Returns the LLVM metadata corresponding to an array of symbol references
+  /// to mlir LLVM dialect alias scope operations.
+  llvm::MDNode *getAliasScopes(Operation *op,
+                               ArrayRef<SymbolRefAttr> aliasScopeRefs) const;
+
   // Sets LLVM metadata for memory operations that are in a parallel loop.
   void setAccessGroupsMetadata(AccessGroupOpInterface op,
                                llvm::Instruction *inst);
index a45768726bc4310efb482fe685c82e3045205055..d3ac7dcc175549430108209a558def08f226f0b9 100644 (file)
@@ -1215,6 +1215,13 @@ DILocalVariableAttr ModuleImport::matchLocalVariableAttr(llvm::Value *value) {
   return debugImporter->translate(node);
 }
 
+FailureOr<SmallVector<SymbolRefAttr>>
+ModuleImport::matchAliasScopeAttrs(llvm::Value *value) {
+  auto *nodeAsVal = cast<llvm::MetadataAsValue>(value);
+  auto *node = cast<llvm::MDNode>(nodeAsVal->getMetadata());
+  return lookupAliasScopeAttrs(node);
+}
+
 Location ModuleImport::translateLoc(llvm::DILocation *loc) {
   return debugImporter->translateLoc(loc);
 }
index ca5fb7dda3841e1e4dd5acf8587e511dc0b386d4..7159aa49540ef531645737762e31609a4888049f 100644 (file)
@@ -1065,16 +1065,22 @@ ModuleTranslation::getAliasScope(Operation *op,
   return aliasScopeMetadataMapping.lookup(aliasScopeOp);
 }
 
+llvm::MDNode *ModuleTranslation::getAliasScopes(
+    Operation *op, ArrayRef<SymbolRefAttr> aliasScopeRefs) const {
+  SmallVector<llvm::Metadata *> nodes;
+  nodes.reserve(aliasScopeRefs.size());
+  for (SymbolRefAttr aliasScopeRef : aliasScopeRefs)
+    nodes.push_back(getAliasScope(op, aliasScopeRef));
+  return llvm::MDNode::get(getLLVMContext(), nodes);
+}
+
 void ModuleTranslation::setAliasScopeMetadata(AliasAnalysisOpInterface op,
                                               llvm::Instruction *inst) {
-  auto populateScopeMetadata = [&](ArrayAttr scopeRefs, unsigned kind) {
-    if (!scopeRefs || scopeRefs.empty())
+  auto populateScopeMetadata = [&](ArrayAttr aliasScopeRefs, unsigned kind) {
+    if (!aliasScopeRefs || aliasScopeRefs.empty())
       return;
-    llvm::Module *module = inst->getModule();
-    SmallVector<llvm::Metadata *> scopeMDs;
-    for (SymbolRefAttr scopeRef : scopeRefs.getAsRange<SymbolRefAttr>())
-      scopeMDs.push_back(getAliasScope(op, scopeRef));
-    llvm::MDNode *node = llvm::MDNode::get(module->getContext(), scopeMDs);
+    llvm::MDNode *node = getAliasScopes(
+        op, llvm::to_vector(aliasScopeRefs.getAsRange<SymbolRefAttr>()));
     inst->setMetadata(kind, node);
   };
 
index c9db19b409e25a76e67129e6d3f13374510afefc..9147027c9d4b2e7f64e43031d81826f72e079dc0 100644 (file)
@@ -596,3 +596,15 @@ llvm.func @stackrestore_opaque_pointers(%arg0: !llvm.ptr)  {
   llvm.intr.stackrestore %arg0 : !llvm.ptr
   llvm.return
 }
+
+// CHECK-LABEL: @experimental_noalias_scope_decl
+llvm.func @experimental_noalias_scope_decl() {
+  // CHECK: llvm.intr.experimental.noalias.scope.decl @metadata::@scope
+  llvm.intr.experimental.noalias.scope.decl @metadata::@scope
+  llvm.return
+}
+
+llvm.metadata @metadata {
+  llvm.alias_scope_domain @domain {description = "The domain"}
+  llvm.alias_scope @scope {domain = @domain, description = "The first scope"}
+}
index 16f2cf2b6283cf09b456e71545f7b94caad16289..b330f654d3d517bed9ac5afd958df53a4735691f 100644 (file)
@@ -322,3 +322,18 @@ bb2:
 }
 
 !0 = !{!"function_entry_count", i64 42}
+
+; // -----
+
+; CHECK:      import-failure.ll
+; CHECK-SAME: warning: dropped instruction: call void @llvm.experimental.noalias.scope.decl(metadata !0)
+define void @unused_scope() {
+  call void @llvm.experimental.noalias.scope.decl(metadata !0)
+  ret void
+}
+
+declare void @llvm.experimental.noalias.scope.decl(metadata)
+
+!0 = !{!1}
+!1 = !{!1, !2}
+!2 = distinct !{!2, !"The domain"}
index a9ed8e9ee556f6caaea94858b0ea978248482c2f..eb74b0ab880bbbe0ce068a72733cce5294831980 100644 (file)
@@ -62,27 +62,34 @@ define void @two_domains(ptr %arg1) {
 
 ; // -----
 
+; CHECK: llvm.metadata @__llvm_global_metadata {
+; CHECK:   llvm.alias_scope_domain @[[DOMAIN:.*]] {description = "The domain"}
+; CHECK:   llvm.alias_scope @[[$SCOPE:.*]] {domain = @[[DOMAIN]]}
+; CHECK: }
+
 ; CHECK-LABEL: llvm.func @supported_ops
 define void @supported_ops(ptr %arg1, float %arg2, i32 %arg3, i32 %arg4) {
-  ; CHECK: llvm.load {{.*}}alias_scopes =
-  %1 = load i32, ptr %arg1, !alias.scope !3
-  ; CHECK: llvm.store {{.*}}alias_scopes =
-  store i32 %1, ptr %arg1, !alias.scope !3
-  ; CHECK: llvm.atomicrmw {{.*}}alias_scopes =
-  %2 = atomicrmw fmax ptr %arg1, float %arg2 acquire, !alias.scope !3
-  ; CHECK: llvm.cmpxchg {{.*}}alias_scopes =
-  %3 = cmpxchg ptr %arg1, i32 %arg3, i32 %arg4 monotonic seq_cst, !alias.scope !3
-  ; CHECK: "llvm.intr.memcpy"{{.*}}alias_scopes =
-  call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg1, i32 4, i1 false), !alias.scope !3
-  ; CHECK: "llvm.intr.memset"{{.*}}alias_scopes =
-  call void @llvm.memset.p0.i32(ptr %arg1, i8 42, i32 4, i1 false), !alias.scope !3
+  ; CHECK: llvm.intr.experimental.noalias.scope.decl @__llvm_global_metadata::@[[$SCOPE]]
+  call void @llvm.experimental.noalias.scope.decl(metadata !2)
+  ; CHECK: llvm.load {{.*}}alias_scopes = [@__llvm_global_metadata::@[[$SCOPE]]]
+  %1 = load i32, ptr %arg1, !alias.scope !2
+  ; CHECK: llvm.store {{.*}}alias_scopes = [@__llvm_global_metadata::@[[$SCOPE]]]
+  store i32 %1, ptr %arg1, !alias.scope !2
+  ; CHECK: llvm.atomicrmw {{.*}}alias_scopes = [@__llvm_global_metadata::@[[$SCOPE]]]
+  %2 = atomicrmw fmax ptr %arg1, float %arg2 acquire, !alias.scope !2
+  ; CHECK: llvm.cmpxchg {{.*}}alias_scopes = [@__llvm_global_metadata::@[[$SCOPE]]]
+  %3 = cmpxchg ptr %arg1, i32 %arg3, i32 %arg4 monotonic seq_cst, !alias.scope !2
+  ; CHECK: "llvm.intr.memcpy"{{.*}}alias_scopes = [@__llvm_global_metadata::@[[$SCOPE]]]
+  call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg1, i32 4, i1 false), !alias.scope !2
+  ; CHECK: "llvm.intr.memset"{{.*}}alias_scopes = [@__llvm_global_metadata::@[[$SCOPE]]]
+  call void @llvm.memset.p0.i32(ptr %arg1, i8 42, i32 4, i1 false), !alias.scope !2
   ret void
 }
 
+declare void @llvm.experimental.noalias.scope.decl(metadata)
 declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg)
 declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg)
 
 !0 = distinct !{!0, !"The domain"}
-!1 = distinct !{!1}
-!2 = !{!2, !0}
-!3 = !{!2}
+!1 = !{!1, !0}
+!2 = !{!1}
index ce65ff995709ca98b6129bc7abd0fe72a8354e27..46120cb3482966301de9b63f953b89bac8b7f43e 100644 (file)
@@ -2016,38 +2016,41 @@ llvm.func @switch_weights(%arg0: i32) -> i32 {
 
 // -----
 
-module {
-  llvm.func @aliasScope(%arg1 : !llvm.ptr) {
-      %0 = llvm.mlir.constant(0 : i32) : i32
-      llvm.store %0, %arg1 {alias_scopes = [@metadata::@scope1], noalias_scopes = [@metadata::@scope2, @metadata::@scope3]} : i32, !llvm.ptr
-      %1 = llvm.load %arg1 {alias_scopes = [@metadata::@scope2], noalias_scopes = [@metadata::@scope1, @metadata::@scope3]} : !llvm.ptr -> i32
-      %2 = llvm.atomicrmw add %arg1, %0 monotonic {alias_scopes = [@metadata::@scope3], noalias_scopes = [@metadata::@scope1, @metadata::@scope2]} : !llvm.ptr, i32
-      %3 = llvm.cmpxchg %arg1, %1, %2 acq_rel monotonic {alias_scopes = [@metadata::@scope3]} : !llvm.ptr, i32
-      %4 = llvm.mlir.constant(0 : i1) : i1
-      %5 = llvm.mlir.constant(42 : i8) : i8
-      "llvm.intr.memcpy"(%arg1, %arg1, %0, %4) {alias_scopes = [@metadata::@scope3]} : (!llvm.ptr, !llvm.ptr, i32, i1) -> ()
-      "llvm.intr.memset"(%arg1, %5, %0, %4) {noalias_scopes = [@metadata::@scope3]} : (!llvm.ptr, i8, i32, i1) -> ()
-      llvm.return
-  }
-
-  llvm.metadata @metadata {
-    llvm.alias_scope_domain @domain {description = "The domain"}
-    llvm.alias_scope @scope1 {domain = @domain, description = "The first scope"}
-    llvm.alias_scope @scope2 {domain = @domain}
-    llvm.alias_scope @scope3 {domain = @domain}
-  }
-}
-
-// Function
 // CHECK-LABEL: aliasScope
-// CHECK:  store {{.*}}, !alias.scope ![[SCOPES1:[0-9]+]], !noalias ![[SCOPES23:[0-9]+]]
-// CHECK:  load {{.*}}, !alias.scope ![[SCOPES2:[0-9]+]], !noalias ![[SCOPES13:[0-9]+]]
-// CHECK:  atomicrmw {{.*}}, !alias.scope ![[SCOPES3:[0-9]+]], !noalias ![[SCOPES12:[0-9]+]]
-// CHECK:  cmpxchg {{.*}}, !alias.scope ![[SCOPES3]]
-// CHECK:  llvm.memcpy{{.*}}, !alias.scope ![[SCOPES3]]
-// CHECK:  llvm.memset{{.*}}, !noalias ![[SCOPES3]]
-
-// Metadata
+llvm.func @aliasScope(%arg1 : !llvm.ptr) {
+  %0 = llvm.mlir.constant(0 : i32) : i32
+  // CHECK:  call void @llvm.experimental.noalias.scope.decl(metadata ![[SCOPES1:[0-9]+]])
+  llvm.intr.experimental.noalias.scope.decl @metadata::@scope1
+  // CHECK:  store {{.*}}, !alias.scope ![[SCOPES1]], !noalias ![[SCOPES23:[0-9]+]]
+  llvm.store %0, %arg1 {alias_scopes = [@metadata::@scope1], noalias_scopes = [@metadata::@scope2, @metadata::@scope3]} : i32, !llvm.ptr
+  // CHECK:  load {{.*}}, !alias.scope ![[SCOPES2:[0-9]+]], !noalias ![[SCOPES13:[0-9]+]]
+  %1 = llvm.load %arg1 {alias_scopes = [@metadata::@scope2], noalias_scopes = [@metadata::@scope1, @metadata::@scope3]} : !llvm.ptr -> i32
+  // CHECK:  atomicrmw {{.*}}, !alias.scope ![[SCOPES3:[0-9]+]], !noalias ![[SCOPES12:[0-9]+]]
+  %2 = llvm.atomicrmw add %arg1, %0 monotonic {alias_scopes = [@metadata::@scope3], noalias_scopes = [@metadata::@scope1, @metadata::@scope2]} : !llvm.ptr, i32
+  // CHECK:  cmpxchg {{.*}}, !alias.scope ![[SCOPES3]]
+  %3 = llvm.cmpxchg %arg1, %1, %2 acq_rel monotonic {alias_scopes = [@metadata::@scope3]} : !llvm.ptr, i32
+  %4 = llvm.mlir.constant(0 : i1) : i1
+  %5 = llvm.mlir.constant(42 : i8) : i8
+  // CHECK:  llvm.memcpy{{.*}}, !alias.scope ![[SCOPES3]]
+  "llvm.intr.memcpy"(%arg1, %arg1, %0, %4) {alias_scopes = [@metadata::@scope3]} : (!llvm.ptr, !llvm.ptr, i32, i1) -> ()
+  // CHECK:  llvm.memset{{.*}}, !noalias ![[SCOPES3]]
+  "llvm.intr.memset"(%arg1, %5, %0, %4) {noalias_scopes = [@metadata::@scope3]} : (!llvm.ptr, i8, i32, i1) -> ()
+  llvm.return
+}
+
+llvm.metadata @metadata {
+  llvm.alias_scope_domain @domain {description = "The domain"}
+  llvm.alias_scope @scope1 {domain = @domain, description = "The first scope"}
+  llvm.alias_scope @scope2 {domain = @domain}
+  llvm.alias_scope @scope3 {domain = @domain}
+}
+
+// Check the intrinsic declarations.
+// CHECK-DAG: declare void @llvm.experimental.noalias.scope.decl(metadata)
+// CHECK-DAG: declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg)
+// CHECK-DAG: declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg)
+
+// Check the translated metadata.
 // CHECK-DAG: ![[DOMAIN:[0-9]+]] = distinct !{![[DOMAIN]], !"The domain"}
 // CHECK-DAG: ![[SCOPE1:[0-9]+]] = distinct !{![[SCOPE1]], ![[DOMAIN]], !"The first scope"}
 // CHECK-DAG: ![[SCOPE2:[0-9]+]] = distinct !{![[SCOPE2]], ![[DOMAIN]]}
@@ -2059,7 +2062,6 @@ module {
 // CHECK-DAG: ![[SCOPES13]] = !{![[SCOPE1]], ![[SCOPE3]]}
 // CHECK-DAG: ![[SCOPES23]] = !{![[SCOPE2]], ![[SCOPE3]]}
 
-
 // -----
 
 // It is okay to have repeated successors if they have no arguments.