Skip to content

Commit cf01a1b

Browse files
committed
[MLIR] Enable import of non self referential alias scopes
1 parent 6192faf commit cf01a1b

File tree

5 files changed

+128
-8
lines changed

5 files changed

+128
-8
lines changed

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

Lines changed: 4 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,6 +891,8 @@ def LLVM_AliasScopeAttr : LLVM_Attr<"AliasScope", "alias_scope"> {
891891
}
892892
```
893893

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

mlir/lib/Target/LLVMIR/ModuleImport.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,13 @@ 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+
if (node->getNumOperands() != 0 &&
432+
node == dyn_cast<llvm::MDNode>(node->getOperand(0)))
433+
return true;
434+
return node->getNumOperands() != 0 &&
435+
isa<llvm::MDNode>(node->getOperand(0));
436+
};
430437
// Helper that verifies the given operand is a string or does not exist.
431438
auto verifyDescription = [](const llvm::MDNode *node, unsigned idx) {
432439
return idx >= node->getNumOperands() ||
@@ -438,8 +445,14 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
438445
if (aliasDomain->getNumOperands() >= 2)
439446
if (auto *operand = dyn_cast<llvm::MDString>(aliasDomain->getOperand(1)))
440447
description = builder.getStringAttr(operand->getString());
441-
return builder.getAttr<AliasScopeDomainAttr>(
442-
DistinctAttr::create(builder.getUnitAttr()), description);
448+
Attribute idattr;
449+
if (verifySelfRef(aliasDomain))
450+
idattr = DistinctAttr::create(builder.getUnitAttr());
451+
else {
452+
auto Name = cast<llvm::MDString>(aliasDomain->getOperand(0));
453+
idattr = builder.getStringAttr(Name->getString());
454+
}
455+
return builder.getAttr<AliasScopeDomainAttr>(idattr, description);
443456
};
444457

445458
// Collect the alias scopes and domains to translate them.
@@ -452,10 +465,11 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
452465
// verifying its domain. Perform the verification before looking it up in
453466
// the alias scope mapping since it could have been inserted as a domain
454467
// node before.
455-
if (!verifySelfRef(scope) || !domain || !verifyDescription(scope, 2))
468+
if (!verifySelfRefOrString(scope) || !domain ||
469+
!verifyDescription(scope, 2))
456470
return emitError(loc) << "unsupported alias scope node: "
457471
<< diagMD(scope, llvmModule.get());
458-
if (!verifySelfRef(domain) || !verifyDescription(domain, 1))
472+
if (!verifySelfRefOrString(domain) || !verifyDescription(domain, 1))
459473
return emitError(loc) << "unsupported alias domain node: "
460474
<< diagMD(domain, llvmModule.get());
461475

@@ -473,9 +487,17 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
473487
StringAttr description = nullptr;
474488
if (!aliasScope.getName().empty())
475489
description = builder.getStringAttr(aliasScope.getName());
490+
Attribute idattr;
491+
if (verifySelfRef(scope))
492+
idattr = DistinctAttr::create(builder.getUnitAttr());
493+
else {
494+
auto Name = cast<llvm::MDString>(scope->getOperand(0));
495+
idattr = builder.getStringAttr(Name->getString());
496+
}
497+
476498
auto aliasScopeOp = builder.getAttr<AliasScopeAttr>(
477-
DistinctAttr::create(builder.getUnitAttr()),
478-
cast<AliasScopeDomainAttr>(it->second), description);
499+
idattr, cast<AliasScopeDomainAttr>(it->second), description);
500+
479501
aliasScopeMapping.try_emplace(aliasScope.getNode(), aliasScopeOp);
480502
}
481503
}

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_decl
757+
llvm.func @experimental_noalias_scope_decl2() {
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)