Skip to content

Commit 1c067a5

Browse files
wsmosesDinistroftynse
authored
[MLIR] Enable import of non self referential alias scopes (#121987)
Fixes #121965. --------- Co-authored-by: Christian Ulmann <[email protected]> Co-authored-by: Alex Zinenko <[email protected]>
1 parent 7060d2a commit 1c067a5

File tree

7 files changed

+156
-12
lines changed

7 files changed

+156
-12
lines changed

mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ def LLVM_MemoryEffectsAttr : LLVM_Attr<"MemoryEffects", "memory_effects"> {
825825
def LLVM_AliasScopeDomainAttr : LLVM_Attr<"AliasScopeDomain",
826826
"alias_scope_domain"> {
827827
let parameters = (ins
828-
"DistinctAttr":$id,
828+
"Attribute":$id,
829829
OptionalParameter<"StringAttr">:$description
830830
);
831831

@@ -853,7 +853,7 @@ def LLVM_AliasScopeDomainAttr : LLVM_Attr<"AliasScopeDomain",
853853

854854
def LLVM_AliasScopeAttr : LLVM_Attr<"AliasScope", "alias_scope"> {
855855
let parameters = (ins
856-
"DistinctAttr":$id,
856+
"Attribute":$id,
857857
"AliasScopeDomainAttr":$domain,
858858
OptionalParameter<"StringAttr">:$description
859859
);
@@ -891,13 +891,17 @@ def LLVM_AliasScopeAttr : LLVM_Attr<"AliasScope", "alias_scope"> {
891891
}
892892
```
893893

894+
The first attribute can either be a DistinctAttr or a StringAttr.
895+
894896
See the following link for more details:
895897
https://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
896898
}];
897899

898900
let summary = "LLVM dialect alias scope";
899901

900902
let assemblyFormat = "`<` struct(params) `>`";
903+
904+
let genVerifyDecl = 1;
901905
}
902906

903907
def LLVM_AliasScopeArrayAttr

mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ void LLVMDialect::registerAttributes() {
5252
>();
5353
}
5454

55+
//===----------------------------------------------------------------------===//
56+
// AliasScopeAttr
57+
//===----------------------------------------------------------------------===//
58+
59+
LogicalResult
60+
AliasScopeAttr::verify(function_ref<InFlightDiagnostic()> emitError,
61+
Attribute id, AliasScopeDomainAttr domain,
62+
StringAttr description) {
63+
(void)domain;
64+
(void)description;
65+
if (!llvm::isa<StringAttr, DistinctAttr>(id))
66+
return emitError()
67+
<< "id of an alias scope must be a StringAttr or a DistrinctAttr";
68+
69+
return success();
70+
}
71+
5572
//===----------------------------------------------------------------------===//
5673
// DINodeAttr
5774
//===----------------------------------------------------------------------===//

mlir/lib/Target/LLVMIR/ModuleImport.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -427,19 +427,33 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
427427
return node->getNumOperands() != 0 &&
428428
node == dyn_cast<llvm::MDNode>(node->getOperand(0));
429429
};
430+
auto verifySelfRefOrString = [](const llvm::MDNode *node) {
431+
return node->getNumOperands() != 0 &&
432+
(node == dyn_cast<llvm::MDNode>(node->getOperand(0)) ||
433+
isa<llvm::MDString>(node->getOperand(0)));
434+
};
430435
// Helper that verifies the given operand is a string or does not exist.
431436
auto verifyDescription = [](const llvm::MDNode *node, unsigned idx) {
432437
return idx >= node->getNumOperands() ||
433438
isa<llvm::MDString>(node->getOperand(idx));
434439
};
440+
441+
auto getIdAttr = [&](const llvm::MDNode *node) -> Attribute {
442+
if (verifySelfRef(node))
443+
return DistinctAttr::create(builder.getUnitAttr());
444+
445+
auto name = cast<llvm::MDString>(node->getOperand(0));
446+
return builder.getStringAttr(name->getString());
447+
};
448+
435449
// Helper that creates an alias scope domain attribute.
436450
auto createAliasScopeDomainOp = [&](const llvm::MDNode *aliasDomain) {
437451
StringAttr description = nullptr;
438452
if (aliasDomain->getNumOperands() >= 2)
439453
if (auto *operand = dyn_cast<llvm::MDString>(aliasDomain->getOperand(1)))
440454
description = builder.getStringAttr(operand->getString());
441-
return builder.getAttr<AliasScopeDomainAttr>(
442-
DistinctAttr::create(builder.getUnitAttr()), description);
455+
Attribute idAttr = getIdAttr(aliasDomain);
456+
return builder.getAttr<AliasScopeDomainAttr>(idAttr, description);
443457
};
444458

445459
// Collect the alias scopes and domains to translate them.
@@ -452,10 +466,11 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
452466
// verifying its domain. Perform the verification before looking it up in
453467
// the alias scope mapping since it could have been inserted as a domain
454468
// node before.
455-
if (!verifySelfRef(scope) || !domain || !verifyDescription(scope, 2))
469+
if (!verifySelfRefOrString(scope) || !domain ||
470+
!verifyDescription(scope, 2))
456471
return emitError(loc) << "unsupported alias scope node: "
457472
<< diagMD(scope, llvmModule.get());
458-
if (!verifySelfRef(domain) || !verifyDescription(domain, 1))
473+
if (!verifySelfRefOrString(domain) || !verifyDescription(domain, 1))
459474
return emitError(loc) << "unsupported alias domain node: "
460475
<< diagMD(domain, llvmModule.get());
461476

@@ -473,9 +488,10 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
473488
StringAttr description = nullptr;
474489
if (!aliasScope.getName().empty())
475490
description = builder.getStringAttr(aliasScope.getName());
491+
Attribute idAttr = getIdAttr(scope);
476492
auto aliasScopeOp = builder.getAttr<AliasScopeAttr>(
477-
DistinctAttr::create(builder.getUnitAttr()),
478-
cast<AliasScopeDomainAttr>(it->second), description);
493+
idAttr, cast<AliasScopeDomainAttr>(it->second), description);
494+
479495
aliasScopeMapping.try_emplace(aliasScope.getNode(), aliasScopeOp);
480496
}
481497
}

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,25 +1724,36 @@ ModuleTranslation::getOrCreateAliasScope(AliasScopeAttr aliasScopeAttr) {
17241724
aliasScopeAttr.getDomain(), nullptr);
17251725
if (insertedDomain) {
17261726
llvm::SmallVector<llvm::Metadata *, 2> operands;
1727-
// Placeholder for self-reference.
1727+
// Placeholder for potential self-reference.
17281728
operands.push_back(dummy.get());
17291729
if (StringAttr description = aliasScopeAttr.getDomain().getDescription())
17301730
operands.push_back(llvm::MDString::get(ctx, description));
17311731
domainIt->second = llvm::MDNode::get(ctx, operands);
17321732
// Self-reference for uniqueness.
1733-
domainIt->second->replaceOperandWith(0, domainIt->second);
1733+
llvm::Metadata *replacement;
1734+
if (auto stringAttr =
1735+
dyn_cast<StringAttr>(aliasScopeAttr.getDomain().getId()))
1736+
replacement = llvm::MDString::get(ctx, stringAttr.getValue());
1737+
else
1738+
replacement = domainIt->second;
1739+
domainIt->second->replaceOperandWith(0, replacement);
17341740
}
17351741
// Convert the scope metadata node.
17361742
assert(domainIt->second && "Scope's domain should already be valid");
17371743
llvm::SmallVector<llvm::Metadata *, 3> operands;
1738-
// Placeholder for self-reference.
1744+
// Placeholder for potential self-reference.
17391745
operands.push_back(dummy.get());
17401746
operands.push_back(domainIt->second);
17411747
if (StringAttr description = aliasScopeAttr.getDescription())
17421748
operands.push_back(llvm::MDString::get(ctx, description));
17431749
scopeIt->second = llvm::MDNode::get(ctx, operands);
17441750
// Self-reference for uniqueness.
1745-
scopeIt->second->replaceOperandWith(0, scopeIt->second);
1751+
llvm::Metadata *replacement;
1752+
if (auto stringAttr = dyn_cast<StringAttr>(aliasScopeAttr.getId()))
1753+
replacement = llvm::MDString::get(ctx, stringAttr.getValue());
1754+
else
1755+
replacement = scopeIt->second;
1756+
scopeIt->second->replaceOperandWith(0, replacement);
17461757
return scopeIt->second;
17471758
}
17481759

mlir/test/Dialect/LLVMIR/roundtrip.mlir

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,16 @@ llvm.func @experimental_noalias_scope_decl() {
750750
llvm.return
751751
}
752752

753+
#alias_scope_domain2 = #llvm.alias_scope_domain<id = "domainid", description = "The domain">
754+
#alias_scope2 = #llvm.alias_scope<id = "stringid", domain = #alias_scope_domain2, description = "The domain">
755+
756+
// CHECK-LABEL: @experimental_noalias_scope_with_string_id
757+
llvm.func @experimental_noalias_scope_with_string_id() {
758+
// CHECK: llvm.intr.experimental.noalias.scope.decl #{{.*}}
759+
llvm.intr.experimental.noalias.scope.decl #alias_scope2
760+
llvm.return
761+
}
762+
753763
// CHECK-LABEL: @experimental_constrained_fptrunc
754764
llvm.func @experimental_constrained_fptrunc(%in: f64) {
755765
// CHECK: llvm.intr.experimental.constrained.fptrunc %{{.*}} towardzero ignore : f64 to f32

mlir/test/Target/LLVMIR/Import/metadata-alias-scopes.ll

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,38 @@ declare void @foo(ptr %arg1)
9292
!0 = distinct !{!0, !"The domain"}
9393
!1 = !{!1, !0}
9494
!2 = !{!1}
95+
96+
; // -----
97+
98+
; CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = "domain1">
99+
; CHECK: #[[$SCOPE0:.*]] = #llvm.alias_scope<id = "scopeid1", domain = #[[DOMAIN]], description = "The first scope">
100+
; CHECK: #[[$SCOPE1:.*]] = #llvm.alias_scope<id = "scopeid2", domain = #[[DOMAIN]]>
101+
; CHECK: #[[$SCOPE2:.*]] = #llvm.alias_scope<id = "scopeid3", domain = #[[DOMAIN]]>
102+
103+
; CHECK-LABEL: llvm.func @alias_scope
104+
define void @alias_scope(ptr %arg1) {
105+
; CHECK: llvm.load
106+
; CHECK-SAME: alias_scopes = [#[[$SCOPE0]]]
107+
; CHECK-SAME: noalias_scopes = [#[[$SCOPE1]], #[[$SCOPE2]]]
108+
%1 = load i32, ptr %arg1, !alias.scope !4, !noalias !7
109+
; CHECK: llvm.load
110+
; CHECK-SAME: alias_scopes = [#[[$SCOPE1]]]
111+
; CHECK-SAME: noalias_scopes = [#[[$SCOPE0]], #[[$SCOPE2]]]
112+
%2 = load i32, ptr %arg1, !alias.scope !5, !noalias !8
113+
; CHECK: llvm.load
114+
; CHECK-SAME: alias_scopes = [#[[$SCOPE2]]]
115+
; CHECK-SAME: noalias_scopes = [#[[$SCOPE0]], #[[$SCOPE1]]]
116+
%3 = load i32, ptr %arg1, !alias.scope !6, !noalias !9
117+
ret void
118+
}
119+
120+
!0 = !{!"domain1"}
121+
!1 = !{!"scopeid1", !0, !"The first scope"}
122+
!2 = !{!"scopeid2", !0}
123+
!3 = !{!"scopeid3", !0}
124+
!4 = !{!1}
125+
!5 = !{!2}
126+
!6 = !{!3}
127+
!7 = !{!2, !3}
128+
!8 = !{!1, !3}
129+
!9 = !{!1, !2}

mlir/test/Target/LLVMIR/attribute-alias-scopes.mlir

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,54 @@ llvm.func @self_reference() {
104104
// CHECK-DAG: ![[SCOPES]] = !{![[SCOPE]]}
105105
// CHECK-DAG: = !DISubroutineType(types: ![[TYPES:[0-9]+]])
106106
// CHECK-DAG: ![[TYPES]] = !{null}
107+
108+
// -----
109+
110+
llvm.func @foo(%arg0: !llvm.ptr)
111+
112+
#alias_scope_domain = #llvm.alias_scope_domain<id = "domain1", description = "The domain">
113+
#alias_scope1 = #llvm.alias_scope<id = "scope1", domain = #alias_scope_domain, description = "The first scope">
114+
#alias_scope2 = #llvm.alias_scope<id = "scope2", domain = #alias_scope_domain>
115+
#alias_scope3 = #llvm.alias_scope<id = "scope3", domain = #alias_scope_domain>
116+
117+
// CHECK-LABEL: @alias_scopes
118+
llvm.func @alias_scopes(%arg1 : !llvm.ptr) {
119+
%0 = llvm.mlir.constant(0 : i32) : i32
120+
// CHECK: call void @llvm.experimental.noalias.scope.decl(metadata ![[SCOPES1:[0-9]+]])
121+
llvm.intr.experimental.noalias.scope.decl #alias_scope1
122+
// CHECK: store {{.*}}, !alias.scope ![[SCOPES1]], !noalias ![[SCOPES23:[0-9]+]]
123+
llvm.store %0, %arg1 {alias_scopes = [#alias_scope1], noalias_scopes = [#alias_scope2, #alias_scope3]} : i32, !llvm.ptr
124+
// CHECK: load {{.*}}, !alias.scope ![[SCOPES2:[0-9]+]], !noalias ![[SCOPES13:[0-9]+]]
125+
%1 = llvm.load %arg1 {alias_scopes = [#alias_scope2], noalias_scopes = [#alias_scope1, #alias_scope3]} : !llvm.ptr -> i32
126+
// CHECK: atomicrmw {{.*}}, !alias.scope ![[SCOPES3:[0-9]+]], !noalias ![[SCOPES12:[0-9]+]]
127+
%2 = llvm.atomicrmw add %arg1, %0 monotonic {alias_scopes = [#alias_scope3], noalias_scopes = [#alias_scope1, #alias_scope2]} : !llvm.ptr, i32
128+
// CHECK: cmpxchg {{.*}}, !alias.scope ![[SCOPES3]]
129+
%3 = llvm.cmpxchg %arg1, %1, %2 acq_rel monotonic {alias_scopes = [#alias_scope3]} : !llvm.ptr, i32
130+
%5 = llvm.mlir.constant(42 : i8) : i8
131+
// CHECK: llvm.memcpy{{.*}}, !alias.scope ![[SCOPES3]]
132+
"llvm.intr.memcpy"(%arg1, %arg1, %0) <{isVolatile = false}> {alias_scopes = [#alias_scope3]} : (!llvm.ptr, !llvm.ptr, i32) -> ()
133+
// CHECK: llvm.memset{{.*}}, !noalias ![[SCOPES3]]
134+
"llvm.intr.memset"(%arg1, %5, %0) <{isVolatile = false}> {noalias_scopes = [#alias_scope3]} : (!llvm.ptr, i8, i32) -> ()
135+
// CHECK: call void @foo({{.*}} !alias.scope ![[SCOPES3]]
136+
llvm.call @foo(%arg1) {alias_scopes = [#alias_scope3]} : (!llvm.ptr) -> ()
137+
// CHECK: call void @foo({{.*}} !noalias ![[SCOPES3]]
138+
llvm.call @foo(%arg1) {noalias_scopes = [#alias_scope3]} : (!llvm.ptr) -> ()
139+
llvm.return
140+
}
141+
142+
// Check the intrinsic declarations.
143+
// CHECK-DAG: declare void @llvm.experimental.noalias.scope.decl(metadata)
144+
// CHECK-DAG: declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg)
145+
// CHECK-DAG: declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg)
146+
147+
// Check the translated metadata.
148+
// CHECK-DAG: ![[DOMAIN:[0-9]+]] = !{!"domain1", !"The domain"}
149+
// CHECK-DAG: ![[SCOPE1:[0-9]+]] = !{!"scope1", ![[DOMAIN]], !"The first scope"}
150+
// CHECK-DAG: ![[SCOPE2:[0-9]+]] = !{!"scope2", ![[DOMAIN]]}
151+
// CHECK-DAG: ![[SCOPE3:[0-9]+]] = !{!"scope3", ![[DOMAIN]]}
152+
// CHECK-DAG: ![[SCOPES1]] = !{![[SCOPE1]]}
153+
// CHECK-DAG: ![[SCOPES2]] = !{![[SCOPE2]]}
154+
// CHECK-DAG: ![[SCOPES3]] = !{![[SCOPE3]]}
155+
// CHECK-DAG: ![[SCOPES12]] = !{![[SCOPE1]], ![[SCOPE2]]}
156+
// CHECK-DAG: ![[SCOPES13]] = !{![[SCOPE1]], ![[SCOPE3]]}
157+
// CHECK-DAG: ![[SCOPES23]] = !{![[SCOPE2]], ![[SCOPE3]]}

0 commit comments

Comments
 (0)