Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ def LLVM_MemoryEffectsAttr : LLVM_Attr<"MemoryEffects", "memory_effects"> {
def LLVM_AliasScopeDomainAttr : LLVM_Attr<"AliasScopeDomain",
"alias_scope_domain"> {
let parameters = (ins
"DistinctAttr":$id,
"Attribute":$id,
OptionalParameter<"StringAttr">:$description
);

Expand Down Expand Up @@ -853,7 +853,7 @@ def LLVM_AliasScopeDomainAttr : LLVM_Attr<"AliasScopeDomain",

def LLVM_AliasScopeAttr : LLVM_Attr<"AliasScope", "alias_scope"> {
let parameters = (ins
"DistinctAttr":$id,
"Attribute":$id,
"AliasScopeDomainAttr":$domain,
OptionalParameter<"StringAttr">:$description
);
Expand Down Expand Up @@ -891,6 +891,8 @@ def LLVM_AliasScopeAttr : LLVM_Attr<"AliasScope", "alias_scope"> {
}
```

The first attribute can either be a DistinctAttr or a StringAttr.

See the following link for more details:
https://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
}];
Expand Down
32 changes: 26 additions & 6 deletions mlir/lib/Target/LLVMIR/ModuleImport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,11 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
return node->getNumOperands() != 0 &&
node == dyn_cast<llvm::MDNode>(node->getOperand(0));
};
auto verifySelfRefOrString = [](const llvm::MDNode *node) {
return node->getNumOperands() != 0 &&
(node == dyn_cast<llvm::MDNode>(node->getOperand(0)) ||
isa<llvm::MDString>(node->getOperand(0)));
};
// Helper that verifies the given operand is a string or does not exist.
auto verifyDescription = [](const llvm::MDNode *node, unsigned idx) {
return idx >= node->getNumOperands() ||
Expand All @@ -438,8 +443,14 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
if (aliasDomain->getNumOperands() >= 2)
if (auto *operand = dyn_cast<llvm::MDString>(aliasDomain->getOperand(1)))
description = builder.getStringAttr(operand->getString());
return builder.getAttr<AliasScopeDomainAttr>(
DistinctAttr::create(builder.getUnitAttr()), description);
Attribute idAttr;
if (verifySelfRef(aliasDomain)) {
idAttr = DistinctAttr::create(builder.getUnitAttr());
} else {
auto name = cast<llvm::MDString>(aliasDomain->getOperand(0));
idAttr = builder.getStringAttr(name->getString());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe consider to also move this to a lambda, as this is exact snippet is duplicated.

return builder.getAttr<AliasScopeDomainAttr>(idAttr, description);
};

// Collect the alias scopes and domains to translate them.
Expand All @@ -452,10 +463,11 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
// verifying its domain. Perform the verification before looking it up in
// the alias scope mapping since it could have been inserted as a domain
// node before.
if (!verifySelfRef(scope) || !domain || !verifyDescription(scope, 2))
if (!verifySelfRefOrString(scope) || !domain ||
!verifyDescription(scope, 2))
return emitError(loc) << "unsupported alias scope node: "
<< diagMD(scope, llvmModule.get());
if (!verifySelfRef(domain) || !verifyDescription(domain, 1))
if (!verifySelfRefOrString(domain) || !verifyDescription(domain, 1))
return emitError(loc) << "unsupported alias domain node: "
<< diagMD(domain, llvmModule.get());

Expand All @@ -473,9 +485,17 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
StringAttr description = nullptr;
if (!aliasScope.getName().empty())
description = builder.getStringAttr(aliasScope.getName());
Attribute idAttr;
if (verifySelfRef(scope)) {
idAttr = DistinctAttr::create(builder.getUnitAttr());
} else {
auto Name = cast<llvm::MDString>(scope->getOperand(0));
idAttr = builder.getStringAttr(Name->getString());
}

auto aliasScopeOp = builder.getAttr<AliasScopeAttr>(
DistinctAttr::create(builder.getUnitAttr()),
cast<AliasScopeDomainAttr>(it->second), description);
idAttr, cast<AliasScopeDomainAttr>(it->second), description);

aliasScopeMapping.try_emplace(aliasScope.getNode(), aliasScopeOp);
}
}
Expand Down
21 changes: 17 additions & 4 deletions mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1724,25 +1724,38 @@ ModuleTranslation::getOrCreateAliasScope(AliasScopeAttr aliasScopeAttr) {
aliasScopeAttr.getDomain(), nullptr);
if (insertedDomain) {
llvm::SmallVector<llvm::Metadata *, 2> operands;
// Placeholder for self-reference.
// Placeholder for potential self-reference.
operands.push_back(dummy.get());
if (StringAttr description = aliasScopeAttr.getDomain().getDescription())
operands.push_back(llvm::MDString::get(ctx, description));
domainIt->second = llvm::MDNode::get(ctx, operands);
// Self-reference for uniqueness.
domainIt->second->replaceOperandWith(0, domainIt->second);
llvm::Metadata *replacement;
if (auto stringAttr =
dyn_cast<StringAttr>(aliasScopeAttr.getDomain().getId())) {
replacement = llvm::MDString::get(ctx, stringAttr.getValue());
} else {
replacement = domainIt->second;
}
domainIt->second->replaceOperandWith(0, replacement);
}
// Convert the scope metadata node.
assert(domainIt->second && "Scope's domain should already be valid");
llvm::SmallVector<llvm::Metadata *, 3> operands;
// Placeholder for self-reference.
// Placeholder for potential self-reference.
operands.push_back(dummy.get());
operands.push_back(domainIt->second);
if (StringAttr description = aliasScopeAttr.getDescription())
operands.push_back(llvm::MDString::get(ctx, description));
scopeIt->second = llvm::MDNode::get(ctx, operands);
// Self-reference for uniqueness.
scopeIt->second->replaceOperandWith(0, scopeIt->second);
llvm::Metadata *replacement;
if (auto stringAttr = dyn_cast<StringAttr>(aliasScopeAttr.getId())) {
replacement = llvm::MDString::get(ctx, stringAttr.getValue());
} else {
replacement = scopeIt->second;
}
scopeIt->second->replaceOperandWith(0, replacement);
return scopeIt->second;
}

Expand Down
10 changes: 10 additions & 0 deletions mlir/test/Dialect/LLVMIR/roundtrip.mlir
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed in this PR: We should consider to introduce splits in these files, as debugging issues in this file is a menace.

Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,16 @@ llvm.func @experimental_noalias_scope_decl() {
llvm.return
}

#alias_scope_domain2 = #llvm.alias_scope_domain<id = "domainid", description = "The domain">
#alias_scope2 = #llvm.alias_scope<id = "stringid", domain = #alias_scope_domain2, description = "The domain">

// CHECK-LABEL: @experimental_noalias_scope_decl
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// CHECK-LABEL: @experimental_noalias_scope_decl
// CHECK-LABEL: @experimental_noalias_scope_decl2

nit: I would probably rename to @experimental_noalias_scope_decl_with_string_id rather than postfixing with a number. In any case the check line should match the function name.

llvm.func @experimental_noalias_scope_decl2() {
// CHECK: llvm.intr.experimental.noalias.scope.decl #{{.*}}
llvm.intr.experimental.noalias.scope.decl #alias_scope2
llvm.return
}

// CHECK-LABEL: @experimental_constrained_fptrunc
llvm.func @experimental_constrained_fptrunc(%in: f64) {
// CHECK: llvm.intr.experimental.constrained.fptrunc %{{.*}} towardzero ignore : f64 to f32
Expand Down
35 changes: 35 additions & 0 deletions mlir/test/Target/LLVMIR/Import/metadata-alias-scopes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,38 @@ declare void @foo(ptr %arg1)
!0 = distinct !{!0, !"The domain"}
!1 = !{!1, !0}
!2 = !{!1}

; // -----

; CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = "domain1">
; CHECK: #[[$SCOPE0:.*]] = #llvm.alias_scope<id = "scopeid1", domain = #[[DOMAIN]], description = "The first scope">
; CHECK: #[[$SCOPE1:.*]] = #llvm.alias_scope<id = "scopeid2", domain = #[[DOMAIN]]>
; CHECK: #[[$SCOPE2:.*]] = #llvm.alias_scope<id = "scopeid3", domain = #[[DOMAIN]]>

; CHECK-LABEL: llvm.func @alias_scope
define void @alias_scope(ptr %arg1) {
; CHECK: llvm.load
; CHECK-SAME: alias_scopes = [#[[$SCOPE0]]]
; CHECK-SAME: noalias_scopes = [#[[$SCOPE1]], #[[$SCOPE2]]]
%1 = load i32, ptr %arg1, !alias.scope !4, !noalias !7
; CHECK: llvm.load
; CHECK-SAME: alias_scopes = [#[[$SCOPE1]]]
; CHECK-SAME: noalias_scopes = [#[[$SCOPE0]], #[[$SCOPE2]]]
%2 = load i32, ptr %arg1, !alias.scope !5, !noalias !8
; CHECK: llvm.load
; CHECK-SAME: alias_scopes = [#[[$SCOPE2]]]
; CHECK-SAME: noalias_scopes = [#[[$SCOPE0]], #[[$SCOPE1]]]
%3 = load i32, ptr %arg1, !alias.scope !6, !noalias !9
ret void
}

!0 = !{!"domain1"}
!1 = !{!"scopeid1", !0, !"The first scope"}
!2 = !{!"scopeid2", !0}
!3 = !{!"scopeid3", !0}
!4 = !{!1}
!5 = !{!2}
!6 = !{!3}
!7 = !{!2, !3}
!8 = !{!1, !3}
!9 = !{!1, !2}
51 changes: 51 additions & 0 deletions mlir/test/Target/LLVMIR/attribute-alias-scopes.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,54 @@ llvm.func @self_reference() {
// CHECK-DAG: ![[SCOPES]] = !{![[SCOPE]]}
// CHECK-DAG: = !DISubroutineType(types: ![[TYPES:[0-9]+]])
// CHECK-DAG: ![[TYPES]] = !{null}

// -----

llvm.func @foo(%arg0: !llvm.ptr)

#alias_scope_domain = #llvm.alias_scope_domain<id = "domain1", description = "The domain">
#alias_scope1 = #llvm.alias_scope<id = "scope1", domain = #alias_scope_domain, description = "The first scope">
#alias_scope2 = #llvm.alias_scope<id = "scope2", domain = #alias_scope_domain>
#alias_scope3 = #llvm.alias_scope<id = "scope3", domain = #alias_scope_domain>

// CHECK-LABEL: @alias_scopes
llvm.func @alias_scopes(%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 #alias_scope1
// CHECK: store {{.*}}, !alias.scope ![[SCOPES1]], !noalias ![[SCOPES23:[0-9]+]]
llvm.store %0, %arg1 {alias_scopes = [#alias_scope1], noalias_scopes = [#alias_scope2, #alias_scope3]} : i32, !llvm.ptr
// CHECK: load {{.*}}, !alias.scope ![[SCOPES2:[0-9]+]], !noalias ![[SCOPES13:[0-9]+]]
%1 = llvm.load %arg1 {alias_scopes = [#alias_scope2], noalias_scopes = [#alias_scope1, #alias_scope3]} : !llvm.ptr -> i32
// CHECK: atomicrmw {{.*}}, !alias.scope ![[SCOPES3:[0-9]+]], !noalias ![[SCOPES12:[0-9]+]]
%2 = llvm.atomicrmw add %arg1, %0 monotonic {alias_scopes = [#alias_scope3], noalias_scopes = [#alias_scope1, #alias_scope2]} : !llvm.ptr, i32
// CHECK: cmpxchg {{.*}}, !alias.scope ![[SCOPES3]]
%3 = llvm.cmpxchg %arg1, %1, %2 acq_rel monotonic {alias_scopes = [#alias_scope3]} : !llvm.ptr, i32
%5 = llvm.mlir.constant(42 : i8) : i8
// CHECK: llvm.memcpy{{.*}}, !alias.scope ![[SCOPES3]]
"llvm.intr.memcpy"(%arg1, %arg1, %0) <{isVolatile = false}> {alias_scopes = [#alias_scope3]} : (!llvm.ptr, !llvm.ptr, i32) -> ()
// CHECK: llvm.memset{{.*}}, !noalias ![[SCOPES3]]
"llvm.intr.memset"(%arg1, %5, %0) <{isVolatile = false}> {noalias_scopes = [#alias_scope3]} : (!llvm.ptr, i8, i32) -> ()
// CHECK: call void @foo({{.*}} !alias.scope ![[SCOPES3]]
llvm.call @foo(%arg1) {alias_scopes = [#alias_scope3]} : (!llvm.ptr) -> ()
// CHECK: call void @foo({{.*}} !noalias ![[SCOPES3]]
llvm.call @foo(%arg1) {noalias_scopes = [#alias_scope3]} : (!llvm.ptr) -> ()
llvm.return
}

// 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]+]] = !{!"domain1", !"The domain"}
// CHECK-DAG: ![[SCOPE1:[0-9]+]] = !{!"scope1", ![[DOMAIN]], !"The first scope"}
// CHECK-DAG: ![[SCOPE2:[0-9]+]] = !{!"scope2", ![[DOMAIN]]}
// CHECK-DAG: ![[SCOPE3:[0-9]+]] = !{!"scope3", ![[DOMAIN]]}
// CHECK-DAG: ![[SCOPES1]] = !{![[SCOPE1]]}
// CHECK-DAG: ![[SCOPES2]] = !{![[SCOPE2]]}
// CHECK-DAG: ![[SCOPES3]] = !{![[SCOPE3]]}
// CHECK-DAG: ![[SCOPES12]] = !{![[SCOPE1]], ![[SCOPE2]]}
// CHECK-DAG: ![[SCOPES13]] = !{![[SCOPE1]], ![[SCOPE3]]}
// CHECK-DAG: ![[SCOPES23]] = !{![[SCOPE2]], ![[SCOPE3]]}
Loading