Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 6 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,13 +891,17 @@ 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
}];

let summary = "LLVM dialect alias scope";

let assemblyFormat = "`<` struct(params) `>`";

let genVerifyDecl = 1;
}

def LLVM_AliasScopeArrayAttr
Expand Down
17 changes: 17 additions & 0 deletions mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ void LLVMDialect::registerAttributes() {
>();
}

//===----------------------------------------------------------------------===//
// AliasScopeAttr
//===----------------------------------------------------------------------===//

LogicalResult
AliasScopeAttr::verify(function_ref<InFlightDiagnostic()> emitError,
Attribute id, AliasScopeDomainAttr domain,
StringAttr description) {
(void)domain;
(void)description;
if (!llvm::isa<StringAttr, DistinctAttr>(id))
return emitError()
<< "id of an alias scope must be a StringAttr or a DistrinctAttr";

return success();
}

//===----------------------------------------------------------------------===//
// DINodeAttr
//===----------------------------------------------------------------------===//
Expand Down
28 changes: 22 additions & 6 deletions mlir/lib/Target/LLVMIR/ModuleImport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,19 +427,33 @@ 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() ||
isa<llvm::MDString>(node->getOperand(idx));
};

auto getIdAttr = [&](const llvm::MDNode *node) -> Attribute {
if (verifySelfRef(node))
return DistinctAttr::create(builder.getUnitAttr());

auto name = cast<llvm::MDString>(node->getOperand(0));
return builder.getStringAttr(name->getString());
};

// Helper that creates an alias scope domain attribute.
auto createAliasScopeDomainOp = [&](const llvm::MDNode *aliasDomain) {
StringAttr description = nullptr;
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 = getIdAttr(aliasDomain);
return builder.getAttr<AliasScopeDomainAttr>(idAttr, description);
};

// Collect the alias scopes and domains to translate them.
Expand All @@ -452,10 +466,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 +488,10 @@ ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {
StringAttr description = nullptr;
if (!aliasScope.getName().empty())
description = builder.getStringAttr(aliasScope.getName());
Attribute idAttr = getIdAttr(scope);
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
19 changes: 15 additions & 4 deletions mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1724,25 +1724,36 @@ 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_with_string_id
llvm.func @experimental_noalias_scope_with_string_id() {
// 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