Compare commits
2 commits
main
...
upstream/u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
396eb66627 | ||
|
|
c938d3b85f |
9 changed files with 257 additions and 18 deletions
|
|
@ -1810,6 +1810,28 @@ def LLVM_MDNodeArrayAttr
|
|||
: TypedArrayAttrBase<LLVM_MDNodeAttr,
|
||||
"array of #llvm.md_node attributes">;
|
||||
|
||||
def LLVM_FunctionMetadataAttr
|
||||
: LLVM_Attr<"FunctionMetadata", "func_metadata"> {
|
||||
let summary = "LLVM function metadata attachment";
|
||||
let description = [{
|
||||
Models one LLVM IR function metadata attachment. LLVM IR allows several
|
||||
attachments with the same metadata kind, so function metadata is represented
|
||||
as an ordered list of these entries instead of a dictionary.
|
||||
|
||||
Example:
|
||||
```mlir
|
||||
#llvm.func_metadata<"type", <#llvm.md_string<"id">>>
|
||||
```
|
||||
}];
|
||||
let parameters = (ins "StringAttr":$metadataName, "MDNodeAttr":$node);
|
||||
let assemblyFormat = "`<` $metadataName `,` $node `>`";
|
||||
let genVerifyDecl = 1;
|
||||
}
|
||||
|
||||
def LLVM_FunctionMetadataArrayAttr
|
||||
: TypedArrayAttrBase<LLVM_FunctionMetadataAttr,
|
||||
"array of #llvm.func_metadata attributes">;
|
||||
|
||||
def LLVM_AnyMDAttr : AnyAttrOf<[
|
||||
LLVM_MDStringAttr, LLVM_MDConstantAttr, LLVM_MDGlobalValueAttr,
|
||||
LLVM_MDNodeAttr],
|
||||
|
|
|
|||
|
|
@ -2077,6 +2077,7 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
|
|||
OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint,
|
||||
OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size,
|
||||
OptionalAttr<I32Attr>:$intel_reqd_sub_group_size,
|
||||
OptionalAttr<LLVM_FunctionMetadataArrayAttr>:$function_metadata,
|
||||
OptionalAttr<UWTableKindAttr>:$uwtable_kind,
|
||||
OptionalAttr<BoolAttr>:$use_sample_profile
|
||||
);
|
||||
|
|
|
|||
|
|
@ -135,6 +135,24 @@ bool AddressSpaceAttr::isValidPtrIntCast(
|
|||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FunctionMetadataAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
LogicalResult
|
||||
FunctionMetadataAttr::verify(function_ref<InFlightDiagnostic()> emitError,
|
||||
StringAttr metadataName, MDNodeAttr node) {
|
||||
(void)node;
|
||||
StringRef name = metadataName.getValue();
|
||||
if (name.empty())
|
||||
return emitError() << "function_metadata entry name must not be empty";
|
||||
if (name == "dbg" || name == "prof") {
|
||||
return emitError() << "reserved function_metadata entry '" << name
|
||||
<< "' must use a dedicated LLVM dialect representation";
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AliasScopeAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -150,6 +150,29 @@ static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
|
|||
return failure();
|
||||
}
|
||||
|
||||
static FlatSymbolRefAttr getMetadataGlobalValueSymbolRef(
|
||||
MLIRContext *ctx, LLVMImportInterface &iface, llvm::GlobalValue *global,
|
||||
llvm::function_ref<FlatSymbolRefAttr(llvm::GlobalVariable *)>
|
||||
getNamelessGlobalSymbol) {
|
||||
if (auto *globalVar = dyn_cast<llvm::GlobalVariable>(global)) {
|
||||
StringRef name = globalVar->getName();
|
||||
if (name.empty())
|
||||
return getNamelessGlobalSymbol(globalVar);
|
||||
if (name == getGlobalCtorsVarName() || name == getGlobalDtorsVarName())
|
||||
return {};
|
||||
}
|
||||
|
||||
if (auto *func = dyn_cast<llvm::Function>(global)) {
|
||||
if (func->isIntrinsic() &&
|
||||
iface.isConvertibleIntrinsic(func->getIntrinsicID()))
|
||||
return {};
|
||||
}
|
||||
|
||||
if (global->getName().empty())
|
||||
return {};
|
||||
return FlatSymbolRefAttr::get(ctx, global->getName());
|
||||
}
|
||||
|
||||
/// Depth-first conversion of the metadata node `md` to the matching LLVM
|
||||
/// dialect metadata attribute. Returns a null attribute for shapes that the
|
||||
/// dialect's metadata-attribute hierarchy does not currently model. `path`
|
||||
|
|
@ -162,24 +185,31 @@ static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
|
|||
static Attribute convertMetadataToAttrImpl(
|
||||
MLIRContext *ctx, const llvm::Metadata *md,
|
||||
SmallPtrSetImpl<const llvm::Metadata *> &path,
|
||||
DenseMap<const llvm::Metadata *, Attribute> &attrMap) {
|
||||
DenseMap<const llvm::Metadata *, Attribute> &attrMap,
|
||||
LLVMImportInterface &iface,
|
||||
llvm::function_ref<FlatSymbolRefAttr(llvm::GlobalVariable *)>
|
||||
getNamelessGlobalSymbol) {
|
||||
if (!md)
|
||||
return {};
|
||||
if (auto *mdStr = dyn_cast<llvm::MDString>(md))
|
||||
return MDStringAttr::get(ctx, StringAttr::get(ctx, mdStr->getString()));
|
||||
if (auto *cam = dyn_cast<llvm::ConstantAsMetadata>(md)) {
|
||||
auto *ci = dyn_cast<llvm::ConstantInt>(cam->getValue());
|
||||
llvm::Constant *constant = cam->getValue();
|
||||
if (auto *global = dyn_cast<llvm::GlobalValue>(constant)) {
|
||||
if (FlatSymbolRefAttr symbolRef = getMetadataGlobalValueSymbolRef(
|
||||
ctx, iface, global, getNamelessGlobalSymbol))
|
||||
return MDGlobalValueAttr::get(ctx, symbolRef);
|
||||
}
|
||||
auto *ci = dyn_cast<llvm::ConstantInt>(constant);
|
||||
if (!ci)
|
||||
return {};
|
||||
auto intType = IntegerType::get(ctx, ci->getBitWidth());
|
||||
return MDConstantAttr::get(ctx, IntegerAttr::get(intType, ci->getValue()));
|
||||
}
|
||||
if (auto *vam = dyn_cast<llvm::ValueAsMetadata>(md)) {
|
||||
auto *fn = dyn_cast<llvm::Function>(vam->getValue());
|
||||
if (!fn)
|
||||
return {};
|
||||
return MDGlobalValueAttr::get(ctx,
|
||||
FlatSymbolRefAttr::get(ctx, fn->getName()));
|
||||
if (isa<llvm::GlobalValue>(vam->getValue()))
|
||||
llvm_unreachable("global values should be ConstantAsMetadata");
|
||||
return {};
|
||||
}
|
||||
if (auto *node = dyn_cast<llvm::MDNode>(md)) {
|
||||
// Metadata attributes cannot preserve distinctness, so bail out.
|
||||
|
|
@ -194,8 +224,8 @@ static Attribute convertMetadataToAttrImpl(
|
|||
SmallVector<Attribute> operands;
|
||||
operands.reserve(node->getNumOperands());
|
||||
for (const llvm::MDOperand &op : node->operands()) {
|
||||
Attribute opAttr =
|
||||
convertMetadataToAttrImpl(ctx, op.get(), path, attrMap);
|
||||
Attribute opAttr = convertMetadataToAttrImpl(
|
||||
ctx, op.get(), path, attrMap, iface, getNamelessGlobalSymbol);
|
||||
if (!opAttr)
|
||||
return {};
|
||||
operands.push_back(opAttr);
|
||||
|
|
@ -213,11 +243,14 @@ static Attribute convertMetadataToAttrImpl(
|
|||
/// metadata-attribute hierarchy does not currently model, including distinct
|
||||
/// nodes and cyclic metadata graphs that the immutable metadata attributes
|
||||
/// cannot express.
|
||||
static Attribute convertMetadataToAttr(MLIRContext *ctx,
|
||||
const llvm::Metadata *md) {
|
||||
static Attribute convertMetadataToAttr(
|
||||
MLIRContext *ctx, const llvm::Metadata *md, LLVMImportInterface &iface,
|
||||
llvm::function_ref<FlatSymbolRefAttr(llvm::GlobalVariable *)>
|
||||
getNamelessGlobalSymbol) {
|
||||
SmallPtrSet<const llvm::Metadata *, 8> path;
|
||||
DenseMap<const llvm::Metadata *, Attribute> attrMap;
|
||||
return convertMetadataToAttrImpl(ctx, md, path, attrMap);
|
||||
return convertMetadataToAttrImpl(ctx, md, path, attrMap, iface,
|
||||
getNamelessGlobalSymbol);
|
||||
}
|
||||
|
||||
/// Get a topologically sorted list of blocks for the given basic blocks.
|
||||
|
|
@ -1990,7 +2023,12 @@ FailureOr<Value> ModuleImport::convertValue(llvm::Value *value) {
|
|||
// attribute.
|
||||
if (auto *mdAsVal = dyn_cast<llvm::MetadataAsValue>(value)) {
|
||||
llvm::Metadata *md = mdAsVal->getMetadata();
|
||||
Attribute mdAttr = convertMetadataToAttr(context, md);
|
||||
auto getNamelessGlobalSymbol =
|
||||
[this](llvm::GlobalVariable *globalVar) -> FlatSymbolRefAttr {
|
||||
return getOrCreateNamelessSymbolName(globalVar);
|
||||
};
|
||||
Attribute mdAttr =
|
||||
convertMetadataToAttr(context, md, iface, getNamelessGlobalSymbol);
|
||||
if (!mdAttr)
|
||||
return emitError(mlirModule.getLoc())
|
||||
<< "unsupported metadata: " << diagMD(md, llvmModule.get());
|
||||
|
|
|
|||
|
|
@ -2063,6 +2063,9 @@ LogicalResult ModuleTranslation::convertFunctionSignatures() {
|
|||
llvmFunc->setLinkage(convertLinkageToLLVM(function.getLinkage()));
|
||||
llvmFunc->setCallingConv(convertCConvToLLVM(function.getCConv()));
|
||||
mapFunction(function.getName(), llvmFunc);
|
||||
if (function.getFunctionMetadataAttr())
|
||||
return function.emitError()
|
||||
<< "not yet implemented: translating function_metadata to LLVM IR";
|
||||
addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
|
||||
|
||||
// Convert function attributes.
|
||||
|
|
|
|||
|
|
@ -1847,6 +1847,26 @@ llvm.mlir.alias external @y5 : i32 {
|
|||
|
||||
// -----
|
||||
|
||||
// expected-error@+1{{attribute 'function_metadata' failed to satisfy constraint: array of #llvm.func_metadata attributes}}
|
||||
llvm.func @function_metadata_value() attributes {function_metadata = [#llvm.md_string<"int">]}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error@+1{{function_metadata entry name must not be empty}}
|
||||
llvm.func @empty_function_metadata_name() attributes {function_metadata = [#llvm.func_metadata<"", #llvm.md_node<#llvm.md_string<"x">>>]}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error@+1{{reserved function_metadata entry 'dbg' must use a dedicated LLVM dialect representation}}
|
||||
llvm.func @reserved_dbg_function_metadata() attributes {function_metadata = [#llvm.func_metadata<"dbg", #llvm.md_node<#llvm.md_string<"x">>>]}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error@+1{{reserved function_metadata entry 'prof' must use a dedicated LLVM dialect representation}}
|
||||
llvm.func @reserved_prof_function_metadata() attributes {function_metadata = [#llvm.func_metadata<"prof", #llvm.md_node<#llvm.md_string<"function_entry_count">, #llvm.md_const<1 : i64>>>]}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error@+1{{attribute 'nodes' failed to satisfy constraint: array of #llvm.md_node attributes}}
|
||||
llvm.named_metadata "not_node" [#llvm.md_string<"int">]
|
||||
|
||||
|
|
|
|||
|
|
@ -1244,3 +1244,25 @@ llvm.named_metadata "foo.kernel" [
|
|||
>
|
||||
>
|
||||
]
|
||||
|
||||
// CHECK-LABEL: llvm.func @generic_function_metadata
|
||||
// CHECK-SAME: function_metadata
|
||||
// CHECK-SAME: #llvm.func_metadata<"annotation", <#llvm.md_string<"function annotation">>>
|
||||
// CHECK-SAME: #llvm.func_metadata<"type", <#llvm.md_const<0 : i64>, #llvm.md_string<"typeid">>>
|
||||
llvm.func @generic_function_metadata() attributes {
|
||||
function_metadata = [
|
||||
#llvm.func_metadata<"annotation", #llvm.md_node<#llvm.md_string<"function annotation">>>,
|
||||
#llvm.func_metadata<"type", #llvm.md_node<#llvm.md_const<0 : i64>, #llvm.md_string<"typeid">>>
|
||||
]
|
||||
}
|
||||
|
||||
// CHECK-LABEL: llvm.func @repeated_function_metadata
|
||||
// CHECK-SAME: function_metadata
|
||||
// CHECK-SAME: #llvm.func_metadata<"type", <#llvm.md_const<0 : i64>, #llvm.md_string<"typeid0">>>
|
||||
// CHECK-SAME: #llvm.func_metadata<"type", <#llvm.md_const<0 : i64>, #llvm.md_string<"typeid1">>>
|
||||
llvm.func @repeated_function_metadata() attributes {
|
||||
function_metadata = [
|
||||
#llvm.func_metadata<"type", #llvm.md_node<#llvm.md_const<0 : i64>, #llvm.md_string<"typeid0">>>,
|
||||
#llvm.func_metadata<"type", #llvm.md_node<#llvm.md_const<0 : i64>, #llvm.md_string<"typeid1">>>
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,3 +493,48 @@ define i32 @cyclic_metadata_as_value() {
|
|||
}
|
||||
|
||||
!0 = distinct !{!0}
|
||||
|
||||
; // -----
|
||||
|
||||
; CHECK: error: unsupported metadata: ptr @llvm.memcpy.p0.p0.i64
|
||||
declare i32 @llvm.read_register.i32(metadata)
|
||||
declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly, ptr noalias readonly, i64, i1 immarg)
|
||||
|
||||
define i32 @skipped_intrinsic_metadata() {
|
||||
%r = call i32 @llvm.read_register.i32(metadata !0)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
!0 = !{ptr @llvm.memcpy.p0.p0.i64}
|
||||
|
||||
; // -----
|
||||
|
||||
; CHECK: error: unsupported metadata: ptr @llvm.global_ctors
|
||||
declare i32 @llvm.read_register.i32(metadata)
|
||||
define void @ctor() {
|
||||
ret void
|
||||
}
|
||||
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @ctor, ptr null }]
|
||||
|
||||
define i32 @metadata_ref_global_ctors() {
|
||||
%r = call i32 @llvm.read_register.i32(metadata !0)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
!0 = !{ptr @llvm.global_ctors}
|
||||
|
||||
; // -----
|
||||
|
||||
; CHECK: error: unsupported metadata: ptr @llvm.global_dtors
|
||||
declare i32 @llvm.read_register.i32(metadata)
|
||||
define void @dtor() {
|
||||
ret void
|
||||
}
|
||||
@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @dtor, ptr null }]
|
||||
|
||||
define i32 @metadata_ref_global_dtors() {
|
||||
%r = call i32 @llvm.read_register.i32(metadata !0)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
!0 = !{ptr @llvm.global_dtors}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ define dso_local void @t0(ptr %a) {
|
|||
; CHECK-LABEL: llvm.func @t0
|
||||
; CHECK: llvm.call_intrinsic "llvm.aarch64.ldxr.p0"({{.*}}) : (!llvm.ptr {llvm.elementtype = i8}) -> i64
|
||||
; CHECK: llvm.return
|
||||
; CHECK: }
|
||||
|
||||
; // -----
|
||||
|
||||
|
|
@ -22,10 +21,9 @@ define dso_local <8 x i8> @t1(<8 x i8> %lhs, <8 x i8> %rhs) {
|
|||
ret <8 x i8> %r
|
||||
}
|
||||
|
||||
; CHECK: llvm.func @t1(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>) -> vector<8xi8> {{.*}} {
|
||||
; CHECK: llvm.func @t1(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>) -> vector<8xi8> {{.*}}
|
||||
; CHECK: %[[R:.*]] = llvm.call_intrinsic "llvm.aarch64.neon.uabd.v8i8"(%[[A0]], %[[A1]]) : (vector<8xi8>, vector<8xi8>) -> vector<8xi8>
|
||||
; CHECK: llvm.return %[[R]] : vector<8xi8>
|
||||
; CHECK: }
|
||||
|
||||
; // -----
|
||||
|
||||
|
|
@ -36,10 +34,9 @@ define dso_local void @t2(<8 x i8> %lhs, <8 x i8> %rhs, ptr %a) {
|
|||
ret void
|
||||
}
|
||||
|
||||
; CHECK: llvm.func @t2(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>, %[[A2:.*]]: !llvm.ptr) {{.*}} {
|
||||
; CHECK: llvm.func @t2(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>, %[[A2:.*]]: !llvm.ptr) {{.*}}
|
||||
; CHECK: llvm.call_intrinsic "llvm.aarch64.neon.st2.v8i8.p0"(%[[A0]], %[[A1]], %[[A2]]) : (vector<8xi8>, vector<8xi8>, !llvm.ptr) -> ()
|
||||
; CHECK: llvm.return
|
||||
; CHECK: }
|
||||
|
||||
; // -----
|
||||
|
||||
|
|
@ -115,3 +112,76 @@ define i32 @read_named_register() {
|
|||
}
|
||||
|
||||
!0 = !{!"sp"}
|
||||
|
||||
; // -----
|
||||
|
||||
declare i32 @llvm.read_register.i32(metadata)
|
||||
|
||||
@global = global i32 0
|
||||
|
||||
; CHECK-LABEL: llvm.func @read_global_metadata
|
||||
define i32 @read_global_metadata() {
|
||||
; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_global_value<@global>
|
||||
; CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
|
||||
%r = call i32 @llvm.read_register.i32(metadata !0)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
!0 = !{ptr @global}
|
||||
|
||||
; // -----
|
||||
|
||||
declare i32 @llvm.read_register.i32(metadata)
|
||||
|
||||
define void @alias_target() {
|
||||
ret void
|
||||
}
|
||||
@alias = alias void (), ptr @alias_target
|
||||
|
||||
; CHECK-LABEL: llvm.func @read_alias_metadata
|
||||
define i32 @read_alias_metadata() {
|
||||
; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_global_value<@alias>
|
||||
; CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
|
||||
%r = call i32 @llvm.read_register.i32(metadata !0)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
!0 = !{ptr @alias}
|
||||
|
||||
; // -----
|
||||
|
||||
declare i32 @llvm.read_register.i32(metadata)
|
||||
|
||||
@ifunc = ifunc void (), ptr @ifunc_resolver
|
||||
define ptr @ifunc_resolver() {
|
||||
ret ptr @ifunc_target
|
||||
}
|
||||
define void @ifunc_target() {
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: llvm.func @read_ifunc_metadata
|
||||
define i32 @read_ifunc_metadata() {
|
||||
; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_global_value<@ifunc>
|
||||
; CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
|
||||
%r = call i32 @llvm.read_register.i32(metadata !0)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
!0 = !{ptr @ifunc}
|
||||
|
||||
; // -----
|
||||
|
||||
declare i32 @llvm.read_register.i32(metadata)
|
||||
|
||||
@0 = global i32 0
|
||||
|
||||
; CHECK-LABEL: llvm.func @read_nameless_global_metadata
|
||||
define i32 @read_nameless_global_metadata() {
|
||||
; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_global_value<@{{mlir\.llvm\.nameless_global_[0-9]+}}>
|
||||
; CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
|
||||
%r = call i32 @llvm.read_register.i32(metadata !0)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
!0 = !{ptr @0}
|
||||
|
|
|
|||
Loading…
Reference in a new issue