From 54941942c82f3a1640d50c0e354d29a3cf5535f6 Mon Sep 17 00:00:00 2001 From: Christian Ulmann Date: Mon, 30 Jan 2023 08:27:14 +0100 Subject: [PATCH] [mlir][LLVM] Add all LLVM parameter attributes This commit adds name accessors and verifiers for all LLVM parameter attributes excluding the swift specific ones to the LLVM dialect. Additionally, these attributes are now also imported and exported. Reviewed By: gysit Differential Revision: https://reviews.llvm.org/D142635 --- mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td | 40 ++++-- mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 38 ++++-- mlir/lib/Target/LLVMIR/AttrKindDetail.cpp | 42 ++++++ mlir/lib/Target/LLVMIR/AttrKindDetail.h | 28 ++++ mlir/lib/Target/LLVMIR/CMakeLists.txt | 3 + mlir/lib/Target/LLVMIR/ModuleImport.cpp | 19 +-- mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 53 +++----- .../Dialect/LLVMIR/parameter-attrs-invalid.mlir | 149 +++++++++++++++++++-- .../Target/LLVMIR/Import/function-attributes.ll | 70 ++++++++-- mlir/test/Target/LLVMIR/llvmir.mlir | 49 +++++++ 10 files changed, 402 insertions(+), 89 deletions(-) create mode 100644 mlir/lib/Target/LLVMIR/AttrKindDetail.cpp create mode 100644 mlir/lib/Target/LLVMIR/AttrKindDetail.h diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td index 9166ae7..3f99dcb 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -36,9 +36,6 @@ def LLVM_Dialect : Dialect { let extraClassDeclaration = [{ /// Name of the data layout attributes. static StringRef getDataLayoutAttrName() { return "llvm.data_layout"; } - static StringRef getAlignAttrName() { return "llvm.align"; } - static StringRef getNoAliasAttrName() { return "llvm.noalias"; } - static StringRef getReadonlyAttrName() { return "llvm.readonly"; } static StringRef getNoAliasScopesAttrName() { return "noalias_scopes"; } static StringRef getAliasScopesAttrName() { return "alias_scopes"; } static StringRef getLoopAttrName() { return "llvm.loop"; } @@ -46,15 +43,37 @@ def LLVM_Dialect : Dialect { static StringRef getLoopOptionsAttrName() { return "options"; } static StringRef getAccessGroupsAttrName() { return "access_groups"; } static StringRef getStructAttrsAttrName() { return "llvm.struct_attrs"; } + static StringRef getTBAAAttrName() { return "llvm.tbaa"; } + + /// Names of llvm parameter attributes. + static StringRef getAlignAttrName() { return "llvm.align"; } + static StringRef getAllocAlignAttrName() { return "llvm.allocalign"; } + static StringRef getAllocatedPointerAttrName() { return "llvm.allocptr"; } static StringRef getByValAttrName() { return "llvm.byval"; } static StringRef getByRefAttrName() { return "llvm.byref"; } - static StringRef getStructRetAttrName() { return "llvm.sret"; } - static StringRef getInAllocaAttrName() { return "llvm.inalloca"; } static StringRef getNoUndefAttrName() { return "llvm.noundef"; } + static StringRef getDereferenceableAttrName() { return "llvm.dereferenceable"; } + static StringRef getDereferenceableOrNullAttrName() { return "llvm.dereferenceable_or_null"; } + static StringRef getInAllocaAttrName() { return "llvm.inalloca"; } + static StringRef getInRegAttrName() { return "llvm.inreg"; } + static StringRef getNestAttrName() { return "llvm.nest"; } + static StringRef getNoAliasAttrName() { return "llvm.noalias"; } + static StringRef getNoCaptureAttrName() { return "llvm.nocapture"; } + static StringRef getNoFreeAttrName() { return "llvm.nofree"; } + static StringRef getNonNullAttrName() { return "llvm.nonnull"; } + static StringRef getPreallocatedAttrName() { return "llvm.preallocated"; } + static StringRef getReadonlyAttrName() { return "llvm.readonly"; } + static StringRef getReturnedAttrName() { return "llvm.returned"; } static StringRef getSExtAttrName() { return "llvm.signext"; } + static StringRef getStackAlignmentAttrName() { return "llvm.alignstack"; } + static StringRef getStructRetAttrName() { return "llvm.sret"; } + static StringRef getWriteOnlyAttrName() { return "llvm.writeonly"; } static StringRef getZExtAttrName() { return "llvm.zeroext"; } - static StringRef getTBAAAttrName() { return "llvm.tbaa"; } - static StringRef getNestAttrName() { return "llvm.nest"; } + // TODO Restrict the usage of this to parameter attributes once there is an + // alternative way of modeling memory effects on FunctionOpInterface. + /// Name of the attribute that will cause the creation of a readnone memory + /// effect when lowering to the LLVMDialect. + static StringRef getReadnoneAttrName() { return "llvm.readnone"; } /// Verifies if the attribute is a well-formed value for "llvm.struct_attrs" static LogicalResult verifyStructAttr( @@ -76,13 +95,6 @@ def LLVM_Dialect : Dialect { /// Returns `true` if the given type is compatible with the LLVM dialect. static bool isCompatibleType(Type); - /// TODO Remove this once there is an alternative way of modeling memory - /// effects on FunctionOpInterface. - /// Name of the attribute that will cause the creation of a readnone memory - /// effect when lowering to the LLVMDialect. - static StringRef getReadnoneAttrName() { - return "llvm.readnone"; - } Type parseType(DialectAsmParser &p) const override; void printType(Type, DialectAsmPrinter &p) const override; diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index 017a59b..de6551f 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -3226,7 +3226,12 @@ LogicalResult LLVMDialect::verifyParameterAttribute(Operation *op, // Check a unit attribute that is attached to a pointer value. if (name == LLVMDialect::getNoAliasAttrName() || name == LLVMDialect::getReadonlyAttrName() || - name == LLVMDialect::getNestAttrName()) { + name == LLVMDialect::getReadnoneAttrName() || + name == LLVMDialect::getWriteOnlyAttrName() || + name == LLVMDialect::getNestAttrName() || + name == LLVMDialect::getNoCaptureAttrName() || + name == LLVMDialect::getNoFreeAttrName() || + name == LLVMDialect::getNonNullAttrName()) { if (failed(checkUnitAttrType())) return failure(); if (verifyValueType && failed(checkPointerType())) @@ -3238,7 +3243,8 @@ LogicalResult LLVMDialect::verifyParameterAttribute(Operation *op, if (name == LLVMDialect::getStructRetAttrName() || name == LLVMDialect::getByValAttrName() || name == LLVMDialect::getByRefAttrName() || - name == LLVMDialect::getInAllocaAttrName()) { + name == LLVMDialect::getInAllocaAttrName() || + name == LLVMDialect::getPreallocatedAttrName()) { if (failed(checkTypeAttrType())) return failure(); if (verifyValueType && failed(checkPointerTypeMatches())) @@ -3257,7 +3263,10 @@ LogicalResult LLVMDialect::verifyParameterAttribute(Operation *op, } // Check an integer attribute that is attached to a pointer value. - if (name == LLVMDialect::getAlignAttrName()) { + if (name == LLVMDialect::getAlignAttrName() || + name == LLVMDialect::getDereferenceableAttrName() || + name == LLVMDialect::getDereferenceableOrNullAttrName() || + name == LLVMDialect::getStackAlignmentAttrName()) { if (failed(checkIntegerAttrType())) return failure(); if (verifyValueType && failed(checkPointerType())) @@ -3265,8 +3274,12 @@ LogicalResult LLVMDialect::verifyParameterAttribute(Operation *op, return success(); } - if (name == LLVMDialect::getNoUndefAttrName()) + // Check a unit attribute that can be attached to arbitrary types. + if (name == LLVMDialect::getNoUndefAttrName() || + name == LLVMDialect::getInRegAttrName() || + name == LLVMDialect::getReturnedAttrName()) return checkUnitAttrType(); + return success(); } @@ -3301,12 +3314,21 @@ LogicalResult LLVMDialect::verifyRegionResultAttribute(Operation *op, // Check to see if this attribute is allowed as a result attribute. Only // explicitly forbidden LLVM attributes will cause an error. auto name = resAttr.getName(); - if (name == LLVMDialect::getReadonlyAttrName() || - name == LLVMDialect::getNestAttrName() || - name == LLVMDialect::getStructRetAttrName() || + if (name == LLVMDialect::getAllocAlignAttrName() || + name == LLVMDialect::getAllocatedPointerAttrName() || name == LLVMDialect::getByValAttrName() || name == LLVMDialect::getByRefAttrName() || - name == LLVMDialect::getInAllocaAttrName()) + name == LLVMDialect::getInAllocaAttrName() || + name == LLVMDialect::getNestAttrName() || + name == LLVMDialect::getNoCaptureAttrName() || + name == LLVMDialect::getNoFreeAttrName() || + name == LLVMDialect::getPreallocatedAttrName() || + name == LLVMDialect::getReadnoneAttrName() || + name == LLVMDialect::getReadonlyAttrName() || + name == LLVMDialect::getReturnedAttrName() || + name == LLVMDialect::getStackAlignmentAttrName() || + name == LLVMDialect::getStructRetAttrName() || + name == LLVMDialect::getWriteOnlyAttrName()) return op->emitError() << name << " is not a valid result attribute"; return verifyParameterAttribute(op, resType, resAttr); } diff --git a/mlir/lib/Target/LLVMIR/AttrKindDetail.cpp b/mlir/lib/Target/LLVMIR/AttrKindDetail.cpp new file mode 100644 index 0000000..2b41a73 --- /dev/null +++ b/mlir/lib/Target/LLVMIR/AttrKindDetail.cpp @@ -0,0 +1,42 @@ +#include "AttrKindDetail.h" + +llvm::ArrayRef> +mlir::LLVM::detail::getAttrKindToNameMapping() { + using ElemTy = std::pair; + // Mapping from llvm attribute kinds to their corresponding MLIR name. + static const llvm::SmallVector kindNamePairs = { + {llvm::Attribute::AttrKind::Alignment, LLVMDialect::getAlignAttrName()}, + {llvm::Attribute::AttrKind::AllocAlign, + LLVMDialect::getAllocAlignAttrName()}, + {llvm::Attribute::AttrKind::AllocatedPointer, + LLVMDialect::getAllocatedPointerAttrName()}, + {llvm::Attribute::AttrKind::ByVal, LLVMDialect::getByValAttrName()}, + {llvm::Attribute::AttrKind::ByRef, LLVMDialect::getByRefAttrName()}, + {llvm::Attribute::AttrKind::NoUndef, LLVMDialect::getNoUndefAttrName()}, + {llvm::Attribute::AttrKind::Dereferenceable, + LLVMDialect::getDereferenceableAttrName()}, + {llvm::Attribute::AttrKind::DereferenceableOrNull, + LLVMDialect::getDereferenceableOrNullAttrName()}, + {llvm::Attribute::AttrKind::InAlloca, LLVMDialect::getInAllocaAttrName()}, + {llvm::Attribute::AttrKind::InReg, LLVMDialect::getInRegAttrName()}, + {llvm::Attribute::AttrKind::Nest, LLVMDialect::getNestAttrName()}, + {llvm::Attribute::AttrKind::NoAlias, LLVMDialect::getNoAliasAttrName()}, + {llvm::Attribute::AttrKind::NoCapture, + LLVMDialect::getNoCaptureAttrName()}, + {llvm::Attribute::AttrKind::NoFree, LLVMDialect::getNoFreeAttrName()}, + {llvm::Attribute::AttrKind::NonNull, LLVMDialect::getNonNullAttrName()}, + {llvm::Attribute::AttrKind::Preallocated, + LLVMDialect::getPreallocatedAttrName()}, + {llvm::Attribute::AttrKind::ReadOnly, LLVMDialect::getReadonlyAttrName()}, + {llvm::Attribute::AttrKind::ReadNone, LLVMDialect::getReadnoneAttrName()}, + {llvm::Attribute::AttrKind::Returned, LLVMDialect::getReturnedAttrName()}, + {llvm::Attribute::AttrKind::SExt, LLVMDialect::getSExtAttrName()}, + {llvm::Attribute::AttrKind::StackAlignment, + LLVMDialect::getStackAlignmentAttrName()}, + {llvm::Attribute::AttrKind::StructRet, + LLVMDialect::getStructRetAttrName()}, + {llvm::Attribute::AttrKind::WriteOnly, + LLVMDialect::getWriteOnlyAttrName()}, + {llvm::Attribute::AttrKind::ZExt, LLVMDialect::getZExtAttrName()}}; + return kindNamePairs; +} diff --git a/mlir/lib/Target/LLVMIR/AttrKindDetail.h b/mlir/lib/Target/LLVMIR/AttrKindDetail.h new file mode 100644 index 0000000..b4259f3 --- /dev/null +++ b/mlir/lib/Target/LLVMIR/AttrKindDetail.h @@ -0,0 +1,28 @@ +//===- AttrKindDetail.h - AttrKind conversion details -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef ATTRKINDDETAIL_H_ +#define ATTRKINDDETAIL_H_ + +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "llvm/IR/Attributes.h" + +namespace mlir { +namespace LLVM { +namespace detail { + +/// Returns a list of pairs that each hold a mapping from LLVM attribute kinds +/// to their corresponding string name in LLVM IR dialect. +llvm::ArrayRef> +getAttrKindToNameMapping(); + +} // namespace detail +} // namespace LLVM +} // namespace mlir + +#endif // ATTRKINDDETAIL_H_ diff --git a/mlir/lib/Target/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/CMakeLists.txt index 97577c0..257a258 100644 --- a/mlir/lib/Target/LLVMIR/CMakeLists.txt +++ b/mlir/lib/Target/LLVMIR/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(Dialect) set(LLVM_OPTIONAL_SOURCES + AttrKindDetail.cpp ConvertFromLLVMIR.cpp ConvertToLLVMIR.cpp DebugTranslation.cpp @@ -13,6 +14,7 @@ set(LLVM_OPTIONAL_SOURCES add_mlir_translation_library(MLIRTargetLLVMIRExport + AttrKindDetail.cpp DebugTranslation.cpp ModuleTranslation.cpp TypeToLLVM.cpp @@ -52,6 +54,7 @@ add_mlir_translation_library(MLIRToLLVMIRTranslationRegistration ) add_mlir_translation_library(MLIRTargetLLVMIRImport + AttrKindDetail.cpp DebugImporter.cpp ModuleImport.cpp TypeFromLLVM.cpp diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index 5391d2e..f86e2e7 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -14,6 +14,7 @@ #include "mlir/Target/LLVMIR/ModuleImport.h" #include "mlir/Target/LLVMIR/Import.h" +#include "AttrKindDetail.h" #include "DebugImporter.h" #include "mlir/Dialect/DLTI/DLTI.h" @@ -1490,24 +1491,8 @@ void ModuleImport::processFunctionAttributes(llvm::Function *func, DictionaryAttr ModuleImport::convertParameterAttribute(llvm::AttributeSet llvmParamAttrs, OpBuilder &builder) { - using ElemTy = std::pair; - // Mapping from llvm attribute kinds to their corresponding MLIR name. - static const SmallVector kindNamePairs = { - {llvm::Attribute::AttrKind::NoAlias, LLVMDialect::getNoAliasAttrName()}, - {llvm::Attribute::AttrKind::ReadOnly, LLVMDialect::getReadonlyAttrName()}, - {llvm::Attribute::AttrKind::Nest, LLVMDialect::getNestAttrName()}, - {llvm::Attribute::AttrKind::SExt, LLVMDialect::getSExtAttrName()}, - {llvm::Attribute::AttrKind::ZExt, LLVMDialect::getZExtAttrName()}, - {llvm::Attribute::AttrKind::NoUndef, LLVMDialect::getNoUndefAttrName()}, - {llvm::Attribute::AttrKind::StructRet, - LLVMDialect::getStructRetAttrName()}, - {llvm::Attribute::AttrKind::ByVal, LLVMDialect::getByValAttrName()}, - {llvm::Attribute::AttrKind::ByRef, LLVMDialect::getByRefAttrName()}, - {llvm::Attribute::AttrKind::InAlloca, LLVMDialect::getInAllocaAttrName()}, - {llvm::Attribute::AttrKind::Alignment, LLVMDialect::getAlignAttrName()}}; - SmallVector paramAttrs; - for (auto [llvmKind, mlirName] : kindNamePairs) { + for (auto [llvmKind, mlirName] : getAttrKindToNameMapping()) { auto llvmAttr = llvmParamAttrs.getAttribute(llvmKind); // Skip attributes that are not attached. if (!llvmAttr.isValid()) diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index b5323de..5f48332 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -13,6 +13,7 @@ #include "mlir/Target/LLVMIR/ModuleTranslation.h" +#include "AttrKindDetail.h" #include "DebugTranslation.h" #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" @@ -29,6 +30,7 @@ #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/TypeSwitch.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" @@ -899,42 +901,27 @@ static void convertFunctionAttributes(LLVMFuncOp func, llvm::AttrBuilder ModuleTranslation::convertParameterAttrs(DictionaryAttr paramAttrs) { llvm::AttrBuilder attrBuilder(llvmModule->getContext()); - if (auto attr = paramAttrs.getAs(LLVMDialect::getNoAliasAttrName())) - attrBuilder.addAttribute(llvm::Attribute::AttrKind::NoAlias); - - if (auto attr = - paramAttrs.getAs(LLVMDialect::getReadonlyAttrName())) - attrBuilder.addAttribute(llvm::Attribute::AttrKind::ReadOnly); - - if (auto attr = - paramAttrs.getAs(LLVMDialect::getAlignAttrName())) - attrBuilder.addAlignmentAttr(llvm::Align(attr.getInt())); - - if (auto attr = - paramAttrs.getAs(LLVMDialect::getStructRetAttrName())) - attrBuilder.addStructRetAttr(convertType(attr.getValue())); - - if (auto attr = paramAttrs.getAs(LLVMDialect::getByValAttrName())) - attrBuilder.addByValAttr(convertType(attr.getValue())); - if (auto attr = paramAttrs.getAs(LLVMDialect::getByRefAttrName())) - attrBuilder.addByRefAttr(convertType(attr.getValue())); - - if (auto attr = - paramAttrs.getAs(LLVMDialect::getInAllocaAttrName())) - attrBuilder.addInAllocaAttr(convertType(attr.getValue())); - - if (auto attr = paramAttrs.getAs(LLVMDialect::getNestAttrName())) - attrBuilder.addAttribute(llvm::Attribute::Nest); - - if (auto attr = paramAttrs.getAs(LLVMDialect::getNoUndefAttrName())) - attrBuilder.addAttribute(llvm::Attribute::NoUndef); + for (auto [llvmKind, mlirName] : getAttrKindToNameMapping()) { + Attribute attr = paramAttrs.get(mlirName); + // Skip attributes that are not present. + if (!attr) + continue; - if (auto attr = paramAttrs.getAs(LLVMDialect::getSExtAttrName())) - attrBuilder.addAttribute(llvm::Attribute::SExt); + // NOTE: C++17 does not support capturing structured bindings. + llvm::Attribute::AttrKind llvmKindCap = llvmKind; + + llvm::TypeSwitch(attr) + .Case([&](auto typeAttr) { + attrBuilder.addTypeAttr(llvmKindCap, + convertType(typeAttr.getValue())); + }) + .Case([&](auto intAttr) { + attrBuilder.addRawIntAttr(llvmKindCap, intAttr.getInt()); + }) + .Case([&](auto) { attrBuilder.addAttribute(llvmKindCap); }); + } - if (auto attr = paramAttrs.getAs(LLVMDialect::getZExtAttrName())) - attrBuilder.addAttribute(llvm::Attribute::ZExt); return attrBuilder; } diff --git a/mlir/test/Dialect/LLVMIR/parameter-attrs-invalid.mlir b/mlir/test/Dialect/LLVMIR/parameter-attrs-invalid.mlir index f6305f1..72bf450 100644 --- a/mlir/test/Dialect/LLVMIR/parameter-attrs-invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/parameter-attrs-invalid.mlir @@ -107,6 +107,97 @@ llvm.func @invalid_noundef_attr_type(%0 : i32 {llvm.noundef = !llvm.ptr}) // ----- +// expected-error@below {{"llvm.dereferenceable" attribute attached to non-pointer LLVM type}} +llvm.func @invalid_dereferenceable_arg_type(%0 : f32 {llvm.dereferenceable = 12 : i64}) + +// ----- + +// expected-error@below {{"llvm.dereferenceable" should be an integer attribute}} +llvm.func @invalid_dereferenceable_attr_type(%0 : !llvm.ptr {llvm.dereferenceable = !llvm.struct<(i32)>}) + +// ----- + +// expected-error@below {{"llvm.dereferenceable_or_null" attribute attached to non-pointer LLVM type}} +llvm.func @invalid_dereferenceable_or_null_arg_type(%0 : f32 {llvm.dereferenceable_or_null = 12 : i64}) + +// ----- + +// expected-error@below {{"llvm.dereferenceable_or_null" should be an integer attribute}} +llvm.func @invalid_dereferenceable_or_null_attr_type(%0 : !llvm.ptr {llvm.dereferenceable_or_null = !llvm.struct<(i32)>}) + +// ----- + +// expected-error@below {{"llvm.inreg" should be a unit attribute}} +llvm.func @invalid_inreg_attr_type(%0 : i32 {llvm.inreg = !llvm.ptr}) + +// ----- + +// expected-error@below {{"llvm.nocapture" attribute attached to non-pointer LLVM type}} +llvm.func @invalid_nocapture_arg_type(%0 : f32 {llvm.nocapture}) + +// ----- + +// expected-error@below {{"llvm.nocapture" should be a unit attribute}} +llvm.func @invalid_nocapture_attr_type(%0 : !llvm.ptr {llvm.nocapture = f32}) + +// ----- + +// expected-error@below {{"llvm.nofree" attribute attached to non-pointer LLVM type}} +llvm.func @invalid_nofree_arg_type(%0 : f32 {llvm.nofree}) + +// ----- + +// expected-error@below {{"llvm.nofree" should be a unit attribute}} +llvm.func @invalid_nofree_attr_type(%0 : !llvm.ptr {llvm.nofree = f32}) + +// ----- + +// expected-error@below {{"llvm.nonnull" attribute attached to non-pointer LLVM type}} +llvm.func @invalid_nonnull_arg_type(%0 : f32 {llvm.nonnull}) + +// ----- + +// expected-error@below {{"llvm.nonnull" should be a unit attribute}} +llvm.func @invalid_nonnull_attr_type(%0 : !llvm.ptr {llvm.nonnull = f32}) + +// ----- + +// expected-error@below {{"llvm.preallocated" attribute attached to non-pointer LLVM type}} +llvm.func @invalid_preallocated_arg_type(%0 : f32 {llvm.preallocated = i64}) + +// ----- + +// expected-error@below {{"llvm.preallocated" should be a type attribute}} +llvm.func @invalid_preallocated_attr_type(%0 : !llvm.ptr {llvm.preallocated}) + +// ----- + +// expected-error@below {{"llvm.returned" should be a unit attribute}} +llvm.func @invalid_returned_attr_type(%0 : i32 {llvm.returned = !llvm.ptr}) + +// ----- + +// expected-error@below {{"llvm.alignstack" attribute attached to non-pointer LLVM type}} +llvm.func @invalid_alignstack_arg_type(%0 : i32 {llvm.alignstack = 10 : i32}) + +// ----- + +// expected-error@below {{"llvm.alignstack" should be an integer attribute}} +llvm.func @invalid_alignstack_attr_type(%0 : i32 {llvm.alignstack = "foo"}) + +// ----- + +// expected-error@below {{"llvm.writeonly" attribute attached to non-pointer LLVM type}} +llvm.func @invalid_writeonly_arg_type(%0 : i32 {llvm.writeonly}) + +// ----- + +// expected-error@below {{"llvm.writeonly" should be a unit attribute}} +llvm.func @invalid_writeonly_attr_type(%0 : i32 {llvm.writeonly = i32}) + +// ----- + + // Result attributes // expected-error@below {{cannot attach result attributes to functions with a void return}} @@ -159,18 +250,13 @@ llvm.func @zeroextattr_ret() -> (f32 {llvm.zeroext}) // ----- -// expected-error @below{{"llvm.readonly" is not a valid result attribute}} -llvm.func @readonly_ret() -> (f32 {llvm.readonly}) +// expected-error @below{{"llvm.allocalign" is not a valid result attribute}} +llvm.func @allocalign_ret() -> (f32 {llvm.allocalign}) // ----- -// expected-error @below{{"llvm.nest" is not a valid result attribute}} -llvm.func @nest_ret() -> (f32 {llvm.nest}) - -// ----- - -// expected-error @below{{"llvm.sret" is not a valid result attribute}} -llvm.func @sret_ret() -> (!llvm.ptr {llvm.sret = i64}) +// expected-error @below{{"llvm.allocptr" is not a valid result attribute}} +llvm.func @allocptr_ret() -> (!llvm.ptr {llvm.allocptr}) // ----- @@ -186,3 +272,48 @@ llvm.func @byref_ret() -> (!llvm.ptr {llvm.byref = i64}) // expected-error @below{{"llvm.inalloca" is not a valid result attribute}} llvm.func @inalloca_ret() -> (!llvm.ptr {llvm.inalloca = i64}) + +// ----- + +// expected-error @below{{"llvm.nest" is not a valid result attribute}} +llvm.func @nest_ret() -> (!llvm.ptr {llvm.nest}) + +// ----- + +// expected-error @below{{"llvm.nocapture" is not a valid result attribute}} +llvm.func @nocapture_ret() -> (!llvm.ptr {llvm.nocapture}) + +// ----- + +// expected-error @below{{"llvm.nofree" is not a valid result attribute}} +llvm.func @nofree_ret() -> (!llvm.ptr {llvm.nofree}) + +// ----- + +// expected-error @below{{"llvm.preallocated" is not a valid result attribute}} +llvm.func @preallocated_ret() -> (!llvm.ptr {llvm.preallocated = i64}) + +// ----- + +// expected-error @below{{"llvm.readnone" is not a valid result attribute}} +llvm.func @readnone_ret() -> (!llvm.ptr {llvm.readnone}) + +// ----- + +// expected-error @below{{"llvm.readonly" is not a valid result attribute}} +llvm.func @readonly_ret() -> (!llvm.ptr {llvm.readonly}) + +// ----- + +// expected-error @below{{"llvm.alignstack" is not a valid result attribute}} +llvm.func @alignstack_ret() -> (!llvm.ptr {llvm.alignstack = 16 : i64}) + +// ----- + +// expected-error @below{{"llvm.sret" is not a valid result attribute}} +llvm.func @sret_ret() -> (!llvm.ptr {llvm.sret = i64}) + +// ----- + +// expected-error @below{{"llvm.writeonly" is not a valid result attribute}} +llvm.func @writeonly_ret() -> (!llvm.ptr {llvm.writeonly}) diff --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll b/mlir/test/Target/LLVMIR/Import/function-attributes.ll index ed38a16..1d21b70 100644 --- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll +++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll @@ -37,7 +37,17 @@ attributes #0 = { readnone } ; CHECK-SAME: i32 {llvm.signext} ; CHECK-SAME: i64 {llvm.zeroext} ; CHECK-SAME: !llvm.ptr {llvm.align = 64 : i64, llvm.noundef} -define void @func_arg_attrs( +; CHECK-SAME: !llvm.ptr {llvm.dereferenceable = 12 : i64} +; CHECK-SAME: !llvm.ptr {llvm.dereferenceable_or_null = 42 : i64} +; CHECK-SAME: f64 {llvm.inreg} +; CHECK-SAME: !llvm.ptr {llvm.nocapture} +; CHECK-SAME: !llvm.ptr {llvm.nofree} +; CHECK-SAME: !llvm.ptr {llvm.nonnull} +; CHECK-SAME: !llvm.ptr {llvm.preallocated = f64} +; CHECK-SAME: !llvm.ptr {llvm.returned} +; CHECK-SAME: !llvm.ptr {llvm.alignstack = 32 : i64} +; CHECK-SAME: !llvm.ptr {llvm.writeonly} +define ptr @func_arg_attrs( ptr byval(i64) %arg0, ptr byref(i64) %arg1, ptr sret(i64) %arg2, @@ -47,15 +57,24 @@ define void @func_arg_attrs( ptr nest %arg6, i32 signext %arg7, i64 zeroext %arg8, - ptr align(64) noundef %arg9) { - ret void + ptr align(64) noundef %arg9, + ptr dereferenceable(12) %arg10, + ptr dereferenceable_or_null(42) %arg11, + double inreg %arg12, + ptr nocapture %arg13, + ptr nofree %arg14, + ptr nonnull %arg15, + ptr preallocated(double) %arg16, + ptr returned %arg17, + ptr alignstack(32) %arg18, + ptr writeonly %arg19) { + ret ptr %arg17 } -; // ----- - -; CHECK-LABEL: @func_res_attr_align -; CHECK-SAME: !llvm.ptr {llvm.align = 16 : i64} -declare align(16) ptr @func_res_attr_align() +; CHECK-LABEL: @allocator +; CHECK-SAME: i64 {llvm.allocalign} +; CHECK-SAME: ptr {llvm.allocptr} +declare ptr @allocator(i64 allocalign, ptr allocptr) ; // ----- @@ -65,6 +84,12 @@ declare noalias ptr @func_res_attr_noalias() ; // ----- +; CHECK-LABEL: @func_res_attr_nonnull +; CHECK-SAME: !llvm.ptr {llvm.nonnull} +declare nonnull ptr @func_res_attr_nonnull() + +; // ----- + ; CHECK-LABEL: @func_res_attr_signext ; CHECK-DAG: llvm.noundef ; CHECK-DAG: llvm.signext @@ -76,6 +101,35 @@ declare noundef signext i32 @func_res_attr_signext() ; CHECK-SAME: i32 {llvm.zeroext} declare zeroext i32 @func_res_attr_zeroext() +; // ----- + +; CHECK-LABEL: @func_res_attr_align +; CHECK-SAME: !llvm.ptr {llvm.align = 16 : i64} +declare align(16) ptr @func_res_attr_align() + +; // ----- + +; CHECK-LABEL: @func_res_attr_noundef +; CHECK-SAME: !llvm.ptr {llvm.noundef} +declare noundef ptr @func_res_attr_noundef() + +; // ----- + +; CHECK-LABEL: @func_res_attr_dereferenceable +; CHECK-SAME: !llvm.ptr {llvm.dereferenceable = 42 : i64} +declare dereferenceable(42) ptr @func_res_attr_dereferenceable() + +; // ----- + +; CHECK-LABEL: @func_res_attr_dereferenceable_or_null +; CHECK-SAME: !llvm.ptr {llvm.dereferenceable_or_null = 42 : i64} +declare dereferenceable_or_null(42) ptr @func_res_attr_dereferenceable_or_null() + +; // ----- + +; CHECK-LABEL: @func_res_attr_inreg +; CHECK-SAME: !llvm.ptr {llvm.inreg} +declare inreg ptr @func_res_attr_inreg() ; // ----- diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index dde4bb3..4c4e85c 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1124,17 +1124,66 @@ llvm.func @zeroextattr(%arg0: i1 {llvm.zeroext}) { // CHECK-LABEL: declare void @zeroextattr_decl(i1 zeroext) llvm.func @zeroextattr_decl(i1 {llvm.zeroext}) +// CHECK-LABEL: declare void @alignattr_decl(ptr align 64) +llvm.func @alignattr_decl(!llvm.ptr {llvm.align = 64 : i64}) + +// CHECK-LABEL: declare void @dereferenceableattr_decl(ptr dereferenceable(32)) +llvm.func @dereferenceableattr_decl(!llvm.ptr {llvm.dereferenceable = 32 : i64}) + +// CHECK-LABEL: declare void @dereferenceableornullattr_decl(ptr dereferenceable_or_null(32)) +llvm.func @dereferenceableornullattr_decl(!llvm.ptr {llvm.dereferenceable_or_null = 32 : i64}) + +// CHECK-LABEL: declare void @inregattr_decl(ptr inreg) +llvm.func @inregattr_decl(!llvm.ptr {llvm.inreg}) + +// CHECK-LABEL: declare void @nocaptureattr_decl(ptr nocapture) +llvm.func @nocaptureattr_decl(!llvm.ptr {llvm.nocapture}) + +// CHECK-LABEL: declare void @nofreeattr_decl(ptr nofree) +llvm.func @nofreeattr_decl(!llvm.ptr {llvm.nofree}) + +// CHECK-LABEL: declare void @nonnullattr_decl(ptr nonnull) +llvm.func @nonnullattr_decl(!llvm.ptr {llvm.nonnull}) + +// CHECK-LABEL: declare void @preallocatedattr_decl(ptr preallocated(float)) +llvm.func @preallocatedattr_decl(!llvm.ptr {llvm.preallocated = f32}) + +// CHECK-LABEL: declare ptr @returnedattr_decl(ptr returned) +llvm.func @returnedattr_decl(!llvm.ptr {llvm.returned}) -> !llvm.ptr + +// CHECK-LABEL: declare void @alignstackattr_decl(ptr alignstack(32)) +llvm.func @alignstackattr_decl(!llvm.ptr {llvm.alignstack = 32 : i64}) + +// CHECK-LABEL: declare void @writeonlyattr_decl(ptr writeonly) +llvm.func @writeonlyattr_decl(!llvm.ptr {llvm.writeonly}) + // CHECK-LABEL: declare align 4 ptr @alignattr_ret_decl() llvm.func @alignattr_ret_decl() -> (!llvm.ptr {llvm.align = 4}) + // CHECK-LABEL: declare noalias ptr @noaliasattr_ret_decl() llvm.func @noaliasattr_ret_decl() -> (!llvm.ptr {llvm.noalias}) + // CHECK-LABEL: declare noundef ptr @noundefattr_ret_decl() llvm.func @noundefattr_ret_decl() -> (!llvm.ptr {llvm.noundef}) + // CHECK-LABEL: declare signext i1 @signextattr_ret_decl() llvm.func @signextattr_ret_decl() -> (i1 {llvm.signext}) + // CHECK-LABEL: declare zeroext i1 @zeroextattr_ret_decl() llvm.func @zeroextattr_ret_decl() -> (i1 {llvm.zeroext}) +// CHECK-LABEL: declare nonnull ptr @nonnullattr_ret_decl() +llvm.func @nonnullattr_ret_decl() -> (!llvm.ptr {llvm.nonnull}) + +// CHECK-LABEL: declare dereferenceable(32) ptr @dereferenceableattr_ret_decl() +llvm.func @dereferenceableattr_ret_decl() -> (!llvm.ptr {llvm.dereferenceable = 32 : i64}) + +// CHECK-LABEL: declare dereferenceable_or_null(16) ptr @dereferenceableornullattr_ret_decl() +llvm.func @dereferenceableornullattr_ret_decl() -> (!llvm.ptr {llvm.dereferenceable_or_null = 16 : i64}) + +// CHECK-LABEL: declare inreg ptr @inregattr_ret_decl() +llvm.func @inregattr_ret_decl() -> (!llvm.ptr {llvm.inreg}) + // CHECK-LABEL: @llvm_varargs(...) llvm.func @llvm_varargs(...) -- 2.7.4