>];
}
+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
//===----------------------------------------------------------------------===//
/// 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);
void forgetMapping(Region ®ion);
/// 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);
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);
}
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);
};
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"}
+}
}
!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"}
; // -----
+; 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}
// -----
-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]]}
// CHECK-DAG: ![[SCOPES13]] = !{![[SCOPE1]], ![[SCOPE3]]}
// CHECK-DAG: ![[SCOPES23]] = !{![[SCOPE2]], ![[SCOPE3]]}
-
// -----
// It is okay to have repeated successors if they have no arguments.