From b2ab375d1f08ab0faecc20f0340cb972f31010a7 Mon Sep 17 00:00:00 2001 From: Alex Zinenko Date: Wed, 5 Aug 2020 14:44:03 +0200 Subject: [PATCH] [mlir] use the new stateful LLVM type translator by default Previous type model in the LLVM dialect did not support identified structure types properly and therefore could use stateless translations implemented as free functions. The new model supports identified structs and must keep track of the identified structure types present in the target context (LLVMContext or MLIRContext) to avoid creating duplicate structs due to LLVM's type auto-renaming. Expose the stateful type translation classes and use them during translation, storing the state as part of ModuleTranslation. Drop the test type translation mechanism that is no longer necessary and update the tests to exercise type translation as part of the main translation flow. Update the code in vector-to-LLVM dialect conversion that relied on stateless translation to use the new class in a stateless manner. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D85297 --- .../include/mlir/Dialect/LLVMIR/LLVMDialect.h | 6 - .../mlir/Target/LLVMIR/ModuleTranslation.h | 4 + .../mlir/Target/LLVMIR/TypeTranslation.h | 48 ++- .../VectorToLLVM/ConvertVectorToLLVM.cpp | 11 +- mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp | 87 +--- mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 5 +- mlir/lib/Target/LLVMIR/TypeTranslation.cpp | 57 ++- mlir/test/Target/import.ll | 2 +- mlir/test/Target/llvmir-types.mlir | 376 ++++++++---------- mlir/test/lib/CMakeLists.txt | 1 - mlir/test/lib/Target/CMakeLists.txt | 13 - .../lib/Target/TestLLVMTypeTranslation.cpp | 79 ---- mlir/tools/mlir-translate/mlir-translate.cpp | 2 - 13 files changed, 277 insertions(+), 414 deletions(-) delete mode 100644 mlir/test/lib/Target/CMakeLists.txt delete mode 100644 mlir/test/lib/Target/TestLLVMTypeTranslation.cpp diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h index 6b771f8e9123..2853ef631761 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h @@ -48,12 +48,6 @@ struct LLVMTypeStorage; struct LLVMDialectImpl; } // namespace detail -/// Converts an MLIR LLVM dialect type to LLVM IR type. Note that this function -/// exists exclusively for the purpose of gradual transition to the first-party -/// modeling of LLVM types. It should not be used outside MLIR-to-LLVM -/// translation. -llvm::Type *convertLLVMType(LLVMType type); - ///// Ops ///// #define GET_OP_CLASSES #include "mlir/Dialect/LLVMIR/LLVMOps.h.inc" diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index 61f8f9fce64c..8b67c249c099 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -19,6 +19,7 @@ #include "mlir/IR/Block.h" #include "mlir/IR/Module.h" #include "mlir/IR/Value.h" +#include "mlir/Target/LLVMIR/TypeTranslation.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/BasicBlock.h" @@ -127,6 +128,9 @@ class ModuleTranslation { /// Mappings between llvm.mlir.global definitions and corresponding globals. DenseMap globalsMapping; + /// A stateful object used to translate types. + TypeToLLVMIRTranslator typeTranslator; + protected: /// Mappings between original and translated values, used for lookups. llvm::StringMap functionMapping; diff --git a/mlir/include/mlir/Target/LLVMIR/TypeTranslation.h b/mlir/include/mlir/Target/LLVMIR/TypeTranslation.h index 3ab962b9ab11..71924b0c61ca 100644 --- a/mlir/include/mlir/Target/LLVMIR/TypeTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/TypeTranslation.h @@ -14,7 +14,10 @@ #ifndef MLIR_TARGET_LLVMIR_TYPETRANSLATION_H #define MLIR_TARGET_LLVMIR_TYPETRANSLATION_H +#include + namespace llvm { +class DataLayout; class LLVMContext; class Type; } // namespace llvm @@ -27,8 +30,49 @@ namespace LLVM { class LLVMType; -llvm::Type *translateTypeToLLVMIR(LLVMType type, llvm::LLVMContext &context); -LLVMType translateTypeFromLLVMIR(llvm::Type *type, MLIRContext &context); +namespace detail { +class TypeToLLVMIRTranslatorImpl; +class TypeFromLLVMIRTranslatorImpl; +} // namespace detail + +/// Utility class to translate MLIR LLVM dialect types to LLVM IR. Stores the +/// translation state, in particular any identified structure types that can be +/// reused in further translation. +class TypeToLLVMIRTranslator { +public: + TypeToLLVMIRTranslator(llvm::LLVMContext &context); + ~TypeToLLVMIRTranslator(); + + /// Returns the perferred alignment for the type given the data layout. Note + /// that this will perform type conversion and store its results for future + /// uses. + // TODO: this should be removed when MLIR has proper data layout. + unsigned getPreferredAlignment(LLVM::LLVMType type, + const llvm::DataLayout &layout); + + /// Translates the given MLIR LLVM dialect type to LLVM IR. + llvm::Type *translateType(LLVM::LLVMType type); + +private: + /// Private implementation. + std::unique_ptr impl; +}; + +/// Utility class to translate LLVM IR types to the MLIR LLVM dialect. Stores +/// the translation state, in particular any identified structure types that are +/// reused across translations. +class TypeFromLLVMIRTranslator { +public: + TypeFromLLVMIRTranslator(MLIRContext &context); + ~TypeFromLLVMIRTranslator(); + + /// Translates the given LLVM IR type to the MLIR LLVM dialect. + LLVM::LLVMType translateType(llvm::Type *type); + +private: + /// Private implementation. + std::unique_ptr impl; +}; } // namespace LLVM } // namespace mlir diff --git a/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp b/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp index 23373f5c7edf..8f5ec9e785dc 100644 --- a/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp +++ b/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp @@ -126,11 +126,12 @@ LogicalResult getMemRefAlignment(LLVMTypeConverter &typeConverter, T op, if (!elementTy) return failure(); - auto dataLayout = typeConverter.getDialect()->getLLVMModule().getDataLayout(); - // TODO: this should be abstracted away to avoid depending on translation. - align = dataLayout.getPrefTypeAlignment(LLVM::translateTypeToLLVMIR( - elementTy.cast(), - typeConverter.getDialect()->getLLVMContext())); + // TODO: this should use the MLIR data layout when it becomes available and + // stop depending on translation. + LLVM::LLVMDialect *dialect = typeConverter.getDialect(); + align = LLVM::TypeToLLVMIRTranslator(dialect->getLLVMContext()) + .getPreferredAlignment(elementTy.cast(), + dialect->getLLVMModule().getDataLayout()); return success(); } diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp index 77897d65e1a5..54d527510398 100644 --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -16,6 +16,7 @@ #include "mlir/IR/Module.h" #include "mlir/IR/StandardTypes.h" #include "mlir/Target/LLVMIR.h" +#include "mlir/Target/LLVMIR/TypeTranslation.h" #include "mlir/Translation.h" #include "llvm/IR/Attributes.h" @@ -48,7 +49,8 @@ class Importer { public: Importer(MLIRContext *context, ModuleOp module) : b(context), context(context), module(module), - unknownLoc(FileLineColLoc::get("imported-bitcode", 0, 0, context)) { + unknownLoc(FileLineColLoc::get("imported-bitcode", 0, 0, context)), + typeTranslator(*context) { b.setInsertionPointToStart(module.getBody()); dialect = context->getRegisteredDialect(); } @@ -129,6 +131,8 @@ class Importer { Location unknownLoc; /// Cached dialect. LLVMDialect *dialect; + /// The stateful type translator (contains named structs). + LLVM::TypeFromLLVMIRTranslator typeTranslator; }; } // namespace @@ -149,79 +153,16 @@ Location Importer::processDebugLoc(const llvm::DebugLoc &loc, } LLVMType Importer::processType(llvm::Type *type) { - switch (type->getTypeID()) { - case llvm::Type::FloatTyID: - return LLVMType::getFloatTy(dialect); - case llvm::Type::DoubleTyID: - return LLVMType::getDoubleTy(dialect); - case llvm::Type::IntegerTyID: - return LLVMType::getIntNTy(dialect, type->getIntegerBitWidth()); - case llvm::Type::PointerTyID: { - LLVMType elementType = processType(type->getPointerElementType()); - if (!elementType) - return nullptr; - return elementType.getPointerTo(type->getPointerAddressSpace()); - } - case llvm::Type::ArrayTyID: { - LLVMType elementType = processType(type->getArrayElementType()); - if (!elementType) - return nullptr; - return LLVMType::getArrayTy(elementType, type->getArrayNumElements()); - } - case llvm::Type::ScalableVectorTyID: { - emitError(unknownLoc) << "scalable vector types not supported"; - return nullptr; - } - case llvm::Type::FixedVectorTyID: { - auto *typeVTy = llvm::cast(type); - LLVMType elementType = processType(typeVTy->getElementType()); - if (!elementType) - return nullptr; - return LLVMType::getVectorTy(elementType, typeVTy->getNumElements()); - } - case llvm::Type::VoidTyID: - return LLVMType::getVoidTy(dialect); - case llvm::Type::FP128TyID: - return LLVMType::getFP128Ty(dialect); - case llvm::Type::X86_FP80TyID: - return LLVMType::getX86_FP80Ty(dialect); - case llvm::Type::StructTyID: { - SmallVector elementTypes; - elementTypes.reserve(type->getStructNumElements()); - for (unsigned i = 0, e = type->getStructNumElements(); i != e; ++i) { - LLVMType ty = processType(type->getStructElementType(i)); - if (!ty) - return nullptr; - elementTypes.push_back(ty); - } - return LLVMType::getStructTy(dialect, elementTypes, - cast(type)->isPacked()); - } - case llvm::Type::FunctionTyID: { - llvm::FunctionType *fty = cast(type); - SmallVector paramTypes; - for (unsigned i = 0, e = fty->getNumParams(); i != e; ++i) { - LLVMType ty = processType(fty->getParamType(i)); - if (!ty) - return nullptr; - paramTypes.push_back(ty); - } - LLVMType result = processType(fty->getReturnType()); - if (!result) - return nullptr; + if (LLVMType result = typeTranslator.translateType(type)) + return result; - return LLVMType::getFunctionTy(result, paramTypes, fty->isVarArg()); - } - default: { - // FIXME: Diagnostic should be able to natively handle types that have - // operator<<(raw_ostream&) defined. - std::string s; - llvm::raw_string_ostream os(s); - os << *type; - emitError(unknownLoc) << "unhandled type: " << os.str(); - return nullptr; - } - } + // FIXME: Diagnostic should be able to natively handle types that have + // operator<<(raw_ostream&) defined. + std::string s; + llvm::raw_string_ostream os(s); + os << *type; + emitError(unknownLoc) << "unhandled type: " << os.str(); + return nullptr; } // We only need integers, floats, doubles, and vectors and tensors thereof for diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index 5107efe28971..9275875e2560 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -304,7 +304,8 @@ ModuleTranslation::ModuleTranslation(Operation *module, std::make_unique(module, *this->llvmModule)), ompDialect( module->getContext()->getRegisteredDialect()), - llvmDialect(module->getContext()->getRegisteredDialect()) { + llvmDialect(module->getContext()->getRegisteredDialect()), + typeTranslator(this->llvmModule->getContext()) { assert(satisfiesLLVMModule(mlirModule) && "mlirModule should honor LLVM's module semantics."); } @@ -935,7 +936,7 @@ LogicalResult ModuleTranslation::convertFunctions() { llvm::Type *ModuleTranslation::convertType(LLVMType type) { // Lock the LLVM context as we create types in it. llvm::sys::SmartScopedLock lock(llvmDialect->getLLVMContextMutex()); - return LLVM::translateTypeToLLVMIR(type, llvmDialect->getLLVMContext()); + return typeTranslator.translateType(type); } /// A helper to look up remapped operands in the value remapping table.` diff --git a/mlir/lib/Target/LLVMIR/TypeTranslation.cpp b/mlir/lib/Target/LLVMIR/TypeTranslation.cpp index b327e9ed8d2c..2a4325f0df97 100644 --- a/mlir/lib/Target/LLVMIR/TypeTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/TypeTranslation.cpp @@ -11,17 +11,20 @@ #include "mlir/IR/MLIRContext.h" #include "llvm/ADT/TypeSwitch.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Type.h" using namespace mlir; -namespace { +namespace mlir { +namespace LLVM { +namespace detail { /// Support for translating MLIR LLVM dialect types to LLVM IR. -class TypeToLLVMIRTranslator { +class TypeToLLVMIRTranslatorImpl { public: /// Constructs a class creating types in the given LLVM context. - TypeToLLVMIRTranslator(llvm::LLVMContext &context) : context(context) {} + TypeToLLVMIRTranslatorImpl(llvm::LLVMContext &context) : context(context) {} /// Translates a single type. llvm::Type *translateType(LLVM::LLVMType type) { @@ -160,22 +163,32 @@ class TypeToLLVMIRTranslator { /// type instead of creating a new type. llvm::DenseMap knownTranslations; }; -} // end namespace - -/// Translates a type from MLIR LLVM dialect to LLVM IR. This does not maintain -/// the mapping for identified structs so new structs will be created with -/// auto-renaming on each call. This is intended exclusively for testing. -llvm::Type *mlir::LLVM::translateTypeToLLVMIR(LLVM::LLVMType type, - llvm::LLVMContext &context) { - return TypeToLLVMIRTranslator(context).translateType(type); +} // end namespace detail +} // end namespace LLVM +} // end namespace mlir + +LLVM::TypeToLLVMIRTranslator::TypeToLLVMIRTranslator(llvm::LLVMContext &context) + : impl(new detail::TypeToLLVMIRTranslatorImpl(context)) {} + +LLVM::TypeToLLVMIRTranslator::~TypeToLLVMIRTranslator() {} + +llvm::Type *LLVM::TypeToLLVMIRTranslator::translateType(LLVM::LLVMType type) { + return impl->translateType(type); } -namespace { +unsigned LLVM::TypeToLLVMIRTranslator::getPreferredAlignment( + LLVM::LLVMType type, const llvm::DataLayout &layout) { + return layout.getPrefTypeAlignment(translateType(type)); +} + +namespace mlir { +namespace LLVM { +namespace detail { /// Support for translating LLVM IR types to MLIR LLVM dialect types. -class TypeFromLLVMIRTranslator { +class TypeFromLLVMIRTranslatorImpl { public: /// Constructs a class creating types in the given MLIR context. - TypeFromLLVMIRTranslator(MLIRContext &context) : context(context) {} + TypeFromLLVMIRTranslatorImpl(MLIRContext &context) : context(context) {} /// Translates the given type. LLVM::LLVMType translateType(llvm::Type *type) { @@ -299,11 +312,15 @@ class TypeFromLLVMIRTranslator { /// The context in which MLIR types are created. MLIRContext &context; }; -} // end namespace +} // end namespace detail +} // end namespace LLVM +} // end namespace mlir + +LLVM::TypeFromLLVMIRTranslator::TypeFromLLVMIRTranslator(MLIRContext &context) + : impl(new detail::TypeFromLLVMIRTranslatorImpl(context)) {} + +LLVM::TypeFromLLVMIRTranslator::~TypeFromLLVMIRTranslator() {} -/// Translates a type from LLVM IR to MLIR LLVM dialect. This is intended -/// exclusively for testing. -LLVM::LLVMType mlir::LLVM::translateTypeFromLLVMIR(llvm::Type *type, - MLIRContext &context) { - return TypeFromLLVMIRTranslator(context).translateType(type); +LLVM::LLVMType LLVM::TypeFromLLVMIRTranslator::translateType(llvm::Type *type) { + return impl->translateType(type); } diff --git a/mlir/test/Target/import.ll b/mlir/test/Target/import.ll index d67bbb029f8a..b3cfad9de427 100644 --- a/mlir/test/Target/import.ll +++ b/mlir/test/Target/import.ll @@ -3,7 +3,7 @@ %struct.t = type {} %struct.s = type { %struct.t, i64 } -; CHECK: llvm.mlir.global external @g1() : !llvm.struct<(struct<()>, i64)> +; CHECK: llvm.mlir.global external @g1() : !llvm.struct<"struct.s", (struct<"struct.t", ()>, i64)> @g1 = external global %struct.s, align 8 ; CHECK: llvm.mlir.global external @g2() : !llvm.double @g2 = external global double, align 8 diff --git a/mlir/test/Target/llvmir-types.mlir b/mlir/test/Target/llvmir-types.mlir index a3026e5515c3..77f7800d8e53 100644 --- a/mlir/test/Target/llvmir-types.mlir +++ b/mlir/test/Target/llvmir-types.mlir @@ -1,184 +1,143 @@ -// RUN: mlir-translate -test-mlir-to-llvmir -split-input-file %s | FileCheck %s - -llvm.func @primitives() { - // CHECK: declare void @return_void() - // CHECK: declare void @return_void_round() - "llvm.test_introduce_func"() { name = "return_void", type = !llvm.void } : () -> () - // CHECK: declare half @return_half() - // CHECK: declare half @return_half_round() - "llvm.test_introduce_func"() { name = "return_half", type = !llvm.half } : () -> () - // CHECK: declare bfloat @return_bfloat() - // CHECK: declare bfloat @return_bfloat_round() - "llvm.test_introduce_func"() { name = "return_bfloat", type = !llvm.bfloat } : () -> () - // CHECK: declare float @return_float() - // CHECK: declare float @return_float_round() - "llvm.test_introduce_func"() { name = "return_float", type = !llvm.float } : () -> () - // CHECK: declare double @return_double() - // CHECK: declare double @return_double_round() - "llvm.test_introduce_func"() { name = "return_double", type = !llvm.double } : () -> () - // CHECK: declare fp128 @return_fp128() - // CHECK: declare fp128 @return_fp128_round() - "llvm.test_introduce_func"() { name = "return_fp128", type = !llvm.fp128 } : () -> () - // CHECK: declare x86_fp80 @return_x86_fp80() - // CHECK: declare x86_fp80 @return_x86_fp80_round() - "llvm.test_introduce_func"() { name = "return_x86_fp80", type = !llvm.x86_fp80 } : () -> () - // CHECK: declare ppc_fp128 @return_ppc_fp128() - // CHECK: declare ppc_fp128 @return_ppc_fp128_round() - "llvm.test_introduce_func"() { name = "return_ppc_fp128", type = !llvm.ppc_fp128 } : () -> () - // CHECK: declare x86_mmx @return_x86_mmx() - // CHECK: declare x86_mmx @return_x86_mmx_round() - "llvm.test_introduce_func"() { name = "return_x86_mmx", type = !llvm.x86_mmx } : () -> () - llvm.return -} - -llvm.func @funcs() { - // CHECK: declare void @f_void_i32(i32) - // CHECK: declare void @f_void_i32_round(i32) - "llvm.test_introduce_func"() { name ="f_void_i32", type = !llvm.func } : () -> () - // CHECK: declare i32 @f_i32_empty() - // CHECK: declare i32 @f_i32_empty_round() - "llvm.test_introduce_func"() { name ="f_i32_empty", type = !llvm.func } : () -> () - // CHECK: declare i32 @f_i32_half_bfloat_float_double(half, bfloat, float, double) - // CHECK: declare i32 @f_i32_half_bfloat_float_double_round(half, bfloat, float, double) - "llvm.test_introduce_func"() { name ="f_i32_half_bfloat_float_double", type = !llvm.func } : () -> () - // CHECK: declare i32 @f_i32_i32_i32(i32, i32) - // CHECK: declare i32 @f_i32_i32_i32_round(i32, i32) - "llvm.test_introduce_func"() { name ="f_i32_i32_i32", type = !llvm.func } : () -> () - // CHECK: declare void @f_void_variadic(...) - // CHECK: declare void @f_void_variadic_round(...) - "llvm.test_introduce_func"() { name ="f_void_variadic", type = !llvm.func } : () -> () - // CHECK: declare void @f_void_i32_i32_variadic(i32, i32, ...) - // CHECK: declare void @f_void_i32_i32_variadic_round(i32, i32, ...) - "llvm.test_introduce_func"() { name ="f_void_i32_i32_variadic", type = !llvm.func } : () -> () - llvm.return -} - -llvm.func @ints() { - // CHECK: declare i1 @return_i1() - // CHECK: declare i1 @return_i1_round() - "llvm.test_introduce_func"() { name = "return_i1", type = !llvm.i1 } : () -> () - // CHECK: declare i8 @return_i8() - // CHECK: declare i8 @return_i8_round() - "llvm.test_introduce_func"() { name = "return_i8", type = !llvm.i8 } : () -> () - // CHECK: declare i16 @return_i16() - // CHECK: declare i16 @return_i16_round() - "llvm.test_introduce_func"() { name = "return_i16", type = !llvm.i16 } : () -> () - // CHECK: declare i32 @return_i32() - // CHECK: declare i32 @return_i32_round() - "llvm.test_introduce_func"() { name = "return_i32", type = !llvm.i32 } : () -> () - // CHECK: declare i64 @return_i64() - // CHECK: declare i64 @return_i64_round() - "llvm.test_introduce_func"() { name = "return_i64", type = !llvm.i64 } : () -> () - // CHECK: declare i57 @return_i57() - // CHECK: declare i57 @return_i57_round() - "llvm.test_introduce_func"() { name = "return_i57", type = !llvm.i57 } : () -> () - // CHECK: declare i129 @return_i129() - // CHECK: declare i129 @return_i129_round() - "llvm.test_introduce_func"() { name = "return_i129", type = !llvm.i129 } : () -> () - llvm.return -} - -llvm.func @pointers() { - // CHECK: declare i8* @return_pi8() - // CHECK: declare i8* @return_pi8_round() - "llvm.test_introduce_func"() { name = "return_pi8", type = !llvm.ptr } : () -> () - // CHECK: declare float* @return_pfloat() - // CHECK: declare float* @return_pfloat_round() - "llvm.test_introduce_func"() { name = "return_pfloat", type = !llvm.ptr } : () -> () - // CHECK: declare i8** @return_ppi8() - // CHECK: declare i8** @return_ppi8_round() - "llvm.test_introduce_func"() { name = "return_ppi8", type = !llvm.ptr> } : () -> () - // CHECK: declare i8***** @return_pppppi8() - // CHECK: declare i8***** @return_pppppi8_round() - "llvm.test_introduce_func"() { name = "return_pppppi8", type = !llvm.ptr>>>> } : () -> () - // CHECK: declare i8* @return_pi8_0() - // CHECK: declare i8* @return_pi8_0_round() - "llvm.test_introduce_func"() { name = "return_pi8_0", type = !llvm.ptr } : () -> () - // CHECK: declare i8 addrspace(1)* @return_pi8_1() - // CHECK: declare i8 addrspace(1)* @return_pi8_1_round() - "llvm.test_introduce_func"() { name = "return_pi8_1", type = !llvm.ptr } : () -> () - // CHECK: declare i8 addrspace(42)* @return_pi8_42() - // CHECK: declare i8 addrspace(42)* @return_pi8_42_round() - "llvm.test_introduce_func"() { name = "return_pi8_42", type = !llvm.ptr } : () -> () - // CHECK: declare i8 addrspace(42)* addrspace(9)* @return_ppi8_42_9() - // CHECK: declare i8 addrspace(42)* addrspace(9)* @return_ppi8_42_9_round() - "llvm.test_introduce_func"() { name = "return_ppi8_42_9", type = !llvm.ptr, 9> } : () -> () - llvm.return -} - -llvm.func @vectors() { - // CHECK: declare <4 x i32> @return_v4_i32() - // CHECK: declare <4 x i32> @return_v4_i32_round() - "llvm.test_introduce_func"() { name = "return_v4_i32", type = !llvm.vec<4 x i32> } : () -> () - // CHECK: declare <4 x float> @return_v4_float() - // CHECK: declare <4 x float> @return_v4_float_round() - "llvm.test_introduce_func"() { name = "return_v4_float", type = !llvm.vec<4 x float> } : () -> () - // CHECK: declare @return_vs_4_i32() - // CHECK: declare @return_vs_4_i32_round() - "llvm.test_introduce_func"() { name = "return_vs_4_i32", type = !llvm.vec } : () -> () - // CHECK: declare @return_vs_8_half() - // CHECK: declare @return_vs_8_half_round() - "llvm.test_introduce_func"() { name = "return_vs_8_half", type = !llvm.vec } : () -> () - // CHECK: declare <4 x i8*> @return_v_4_pi8() - // CHECK: declare <4 x i8*> @return_v_4_pi8_round() - "llvm.test_introduce_func"() { name = "return_v_4_pi8", type = !llvm.vec<4 x ptr> } : () -> () - llvm.return -} - -llvm.func @arrays() { - // CHECK: declare [10 x i32] @return_a10_i32() - // CHECK: declare [10 x i32] @return_a10_i32_round() - "llvm.test_introduce_func"() { name = "return_a10_i32", type = !llvm.array<10 x i32> } : () -> () - // CHECK: declare [8 x float] @return_a8_float() - // CHECK: declare [8 x float] @return_a8_float_round() - "llvm.test_introduce_func"() { name = "return_a8_float", type = !llvm.array<8 x float> } : () -> () - // CHECK: declare [10 x i32 addrspace(4)*] @return_a10_pi32_4() - // CHECK: declare [10 x i32 addrspace(4)*] @return_a10_pi32_4_round() - "llvm.test_introduce_func"() { name = "return_a10_pi32_4", type = !llvm.array<10 x ptr> } : () -> () - // CHECK: declare [10 x [4 x float]] @return_a10_a4_float() - // CHECK: declare [10 x [4 x float]] @return_a10_a4_float_round() - "llvm.test_introduce_func"() { name = "return_a10_a4_float", type = !llvm.array<10 x array<4 x float>> } : () -> () - llvm.return -} - -llvm.func @literal_structs() { - // CHECK: declare {} @return_struct_empty() - // CHECK: declare {} @return_struct_empty_round() - "llvm.test_introduce_func"() { name = "return_struct_empty", type = !llvm.struct<()> } : () -> () - // CHECK: declare { i32 } @return_s_i32() - // CHECK: declare { i32 } @return_s_i32_round() - "llvm.test_introduce_func"() { name = "return_s_i32", type = !llvm.struct<(i32)> } : () -> () - // CHECK: declare { float, i32 } @return_s_float_i32() - // CHECK: declare { float, i32 } @return_s_float_i32_round() - "llvm.test_introduce_func"() { name = "return_s_float_i32", type = !llvm.struct<(float, i32)> } : () -> () - // CHECK: declare { { i32 } } @return_s_s_i32() - // CHECK: declare { { i32 } } @return_s_s_i32_round() - "llvm.test_introduce_func"() { name = "return_s_s_i32", type = !llvm.struct<(struct<(i32)>)> } : () -> () - // CHECK: declare { i32, { i32 }, float } @return_s_i32_s_i32_float() - // CHECK: declare { i32, { i32 }, float } @return_s_i32_s_i32_float_round() - "llvm.test_introduce_func"() { name = "return_s_i32_s_i32_float", type = !llvm.struct<(i32, struct<(i32)>, float)> } : () -> () - - // CHECK: declare <{}> @return_sp_empty() - // CHECK: declare <{}> @return_sp_empty_round() - "llvm.test_introduce_func"() { name = "return_sp_empty", type = !llvm.struct } : () -> () - // CHECK: declare <{ i32 }> @return_sp_i32() - // CHECK: declare <{ i32 }> @return_sp_i32_round() - "llvm.test_introduce_func"() { name = "return_sp_i32", type = !llvm.struct } : () -> () - // CHECK: declare <{ float, i32 }> @return_sp_float_i32() - // CHECK: declare <{ float, i32 }> @return_sp_float_i32_round() - "llvm.test_introduce_func"() { name = "return_sp_float_i32", type = !llvm.struct } : () -> () - // CHECK: declare <{ i32, { i32, i1 }, float }> @return_sp_i32_s_i31_1_float() - // CHECK: declare <{ i32, { i32, i1 }, float }> @return_sp_i32_s_i31_1_float_round() - "llvm.test_introduce_func"() { name = "return_sp_i32_s_i31_1_float", type = !llvm.struct, float)> } : () -> () - - // CHECK: declare { <{ i32 }> } @return_s_sp_i32() - // CHECK: declare { <{ i32 }> } @return_s_sp_i32_round() - "llvm.test_introduce_func"() { name = "return_s_sp_i32", type = !llvm.struct<(struct)> } : () -> () - // CHECK: declare <{ { i32 } }> @return_sp_s_i32() - // CHECK: declare <{ { i32 } }> @return_sp_s_i32_round() - "llvm.test_introduce_func"() { name = "return_sp_s_i32", type = !llvm.struct)> } : () -> () - llvm.return -} +// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s + +// +// Primitives. +// + +// CHECK: declare void @return_void() +llvm.func @return_void() -> !llvm.void +// CHECK: declare half @return_half() +llvm.func @return_half() -> !llvm.half +// CHECK: declare bfloat @return_bfloat() +llvm.func @return_bfloat() -> !llvm.bfloat +// CHECK: declare float @return_float() +llvm.func @return_float() -> !llvm.float +// CHECK: declare double @return_double() +llvm.func @return_double() -> !llvm.double +// CHECK: declare fp128 @return_fp128() +llvm.func @return_fp128() -> !llvm.fp128 +// CHECK: declare x86_fp80 @return_x86_fp80() +llvm.func @return_x86_fp80() -> !llvm.x86_fp80 +// CHECK: declare ppc_fp128 @return_ppc_fp128() +llvm.func @return_ppc_fp128() -> !llvm.ppc_fp128 +// CHECK: declare x86_mmx @return_x86_mmx() +llvm.func @return_x86_mmx() -> !llvm.x86_mmx + +// +// Functions. +// + +// CHECK: declare void @f_void_i32(i32) +llvm.func @f_void_i32(!llvm.i32) -> !llvm.void +// CHECK: declare i32 @f_i32_empty() +llvm.func @f_i32_empty() -> !llvm.i32 +// CHECK: declare i32 @f_i32_half_bfloat_float_double(half, bfloat, float, double) +llvm.func @f_i32_half_bfloat_float_double(!llvm.half, !llvm.bfloat, !llvm.float, !llvm.double) -> !llvm.i32 +// CHECK: declare i32 @f_i32_i32_i32(i32, i32) +llvm.func @f_i32_i32_i32(!llvm.i32, !llvm.i32) -> !llvm.i32 +// CHECK: declare void @f_void_variadic(...) +llvm.func @f_void_variadic(...) +// CHECK: declare void @f_void_i32_i32_variadic(i32, i32, ...) +llvm.func @f_void_i32_i32_variadic(!llvm.i32, !llvm.i32, ...) +// CHECK: declare i32 (i32)* @f_f_i32_i32() +llvm.func @f_f_i32_i32() -> !llvm.ptr> + +// +// Integers. +// + +// CHECK: declare i1 @return_i1() +llvm.func @return_i1() -> !llvm.i1 +// CHECK: declare i8 @return_i8() +llvm.func @return_i8() -> !llvm.i8 +// CHECK: declare i16 @return_i16() +llvm.func @return_i16() -> !llvm.i16 +// CHECK: declare i32 @return_i32() +llvm.func @return_i32() -> !llvm.i32 +// CHECK: declare i64 @return_i64() +llvm.func @return_i64() -> !llvm.i64 +// CHECK: declare i57 @return_i57() +llvm.func @return_i57() -> !llvm.i57 +// CHECK: declare i129 @return_i129() +llvm.func @return_i129() -> !llvm.i129 + +// +// Pointers. +// + +// CHECK: declare i8* @return_pi8() +llvm.func @return_pi8() -> !llvm.ptr +// CHECK: declare float* @return_pfloat() +llvm.func @return_pfloat() -> !llvm.ptr +// CHECK: declare i8** @return_ppi8() +llvm.func @return_ppi8() -> !llvm.ptr> +// CHECK: declare i8***** @return_pppppi8() +llvm.func @return_pppppi8() -> !llvm.ptr>>>> +// CHECK: declare i8* @return_pi8_0() +llvm.func @return_pi8_0() -> !llvm.ptr +// CHECK: declare i8 addrspace(1)* @return_pi8_1() +llvm.func @return_pi8_1() -> !llvm.ptr +// CHECK: declare i8 addrspace(42)* @return_pi8_42() +llvm.func @return_pi8_42() -> !llvm.ptr +// CHECK: declare i8 addrspace(42)* addrspace(9)* @return_ppi8_42_9() +llvm.func @return_ppi8_42_9() -> !llvm.ptr, 9> + +// +// Vectors. +// + +// CHECK: declare <4 x i32> @return_v4_i32() +llvm.func @return_v4_i32() -> !llvm.vec<4 x i32> +// CHECK: declare <4 x float> @return_v4_float() +llvm.func @return_v4_float() -> !llvm.vec<4 x float> +// CHECK: declare @return_vs_4_i32() +llvm.func @return_vs_4_i32() -> !llvm.vec +// CHECK: declare @return_vs_8_half() +llvm.func @return_vs_8_half() -> !llvm.vec +// CHECK: declare <4 x i8*> @return_v_4_pi8() +llvm.func @return_v_4_pi8() -> !llvm.vec<4 x ptr> + +// +// Arrays. +// + +// CHECK: declare [10 x i32] @return_a10_i32() +llvm.func @return_a10_i32() -> !llvm.array<10 x i32> +// CHECK: declare [8 x float] @return_a8_float() +llvm.func @return_a8_float() -> !llvm.array<8 x float> +// CHECK: declare [10 x i32 addrspace(4)*] @return_a10_pi32_4() +llvm.func @return_a10_pi32_4() -> !llvm.array<10 x ptr> +// CHECK: declare [10 x [4 x float]] @return_a10_a4_float() +llvm.func @return_a10_a4_float() -> !llvm.array<10 x array<4 x float>> + +// +// Literal structures. +// + +// CHECK: declare {} @return_struct_empty() +llvm.func @return_struct_empty() -> !llvm.struct<()> +// CHECK: declare { i32 } @return_s_i32() +llvm.func @return_s_i32() -> !llvm.struct<(i32)> +// CHECK: declare { float, i32 } @return_s_float_i32() +llvm.func @return_s_float_i32() -> !llvm.struct<(float, i32)> +// CHECK: declare { { i32 } } @return_s_s_i32() +llvm.func @return_s_s_i32() -> !llvm.struct<(struct<(i32)>)> +// CHECK: declare { i32, { i32 }, float } @return_s_i32_s_i32_float() +llvm.func @return_s_i32_s_i32_float() -> !llvm.struct<(i32, struct<(i32)>, float)> + +// CHECK: declare <{}> @return_sp_empty() +llvm.func @return_sp_empty() -> !llvm.struct +// CHECK: declare <{ i32 }> @return_sp_i32() +llvm.func @return_sp_i32() -> !llvm.struct +// CHECK: declare <{ float, i32 }> @return_sp_float_i32() +llvm.func @return_sp_float_i32() -> !llvm.struct +// CHECK: declare <{ i32, { i32, i1 }, float }> @return_sp_i32_s_i31_1_float() +llvm.func @return_sp_i32_s_i31_1_float() -> !llvm.struct, float)> + +// CHECK: declare { <{ i32 }> } @return_s_sp_i32() +llvm.func @return_s_sp_i32() -> !llvm.struct<(struct)> +// CHECK: declare <{ { i32 } }> @return_sp_s_i32() +llvm.func @return_sp_s_i32() -> !llvm.struct)> // ----- // Put structs into a separate split so that we can match their declarations @@ -197,32 +156,29 @@ llvm.func @literal_structs() { // CHECK: %array-of-structs = type { i32 } // CHECK: %ptr-to-struct = type { i8 } -llvm.func @identified_structs() { - // CHECK: declare %empty - "llvm.test_introduce_func"() { name = "return_s_empty", type = !llvm.struct<"empty", ()> } : () -> () - // CHECK: declare %opaque - "llvm.test_introduce_func"() { name = "return_s_opaque", type = !llvm.struct<"opaque", opaque> } : () -> () - // CHECK: declare %long - "llvm.test_introduce_func"() { name = "return_s_long", type = !llvm.struct<"long", (i32, struct<(i32, i1)>, float, ptr>)> } : () -> () - // CHECK: declare %self-recursive - "llvm.test_introduce_func"() { name = "return_s_self_recurisve", type = !llvm.struct<"self-recursive", (ptr>)> } : () -> () - // CHECK: declare %unpacked - "llvm.test_introduce_func"() { name = "return_s_unpacked", type = !llvm.struct<"unpacked", (i32)> } : () -> () - // CHECK: declare %packed - "llvm.test_introduce_func"() { name = "return_s_packed", type = !llvm.struct<"packed", packed (i32)> } : () -> () - // CHECK: declare %"name with spaces and !^$@$#" - "llvm.test_introduce_func"() { name = "return_s_symbols", type = !llvm.struct<"name with spaces and !^$@$#", packed (i32)> } : () -> () - - // CHECK: declare %mutually-a - "llvm.test_introduce_func"() { name = "return_s_mutually_a", type = !llvm.struct<"mutually-a", (ptr, 3>)>>)> } : () -> () - // CHECK: declare %mutually-b - "llvm.test_introduce_func"() { name = "return_s_mutually_b", type = !llvm.struct<"mutually-b", (ptr>)>, 3>)> } : () -> () - - // CHECK: declare %struct-of-arrays - "llvm.test_introduce_func"() { name = "return_s_struct_of_arrays", type = !llvm.struct<"struct-of-arrays", (array<10 x i32>)> } : () -> () - // CHECK: declare [10 x %array-of-structs] - "llvm.test_introduce_func"() { name = "return_s_array_of_structs", type = !llvm.array<10 x struct<"array-of-structs", (i32)>> } : () -> () - // CHECK: declare %ptr-to-struct* - "llvm.test_introduce_func"() { name = "return_s_ptr_to_struct", type = !llvm.ptr> } : () -> () - llvm.return -} +// CHECK: declare %empty +llvm.func @return_s_empty() -> !llvm.struct<"empty", ()> +// CHECK: declare %opaque +llvm.func @return_s_opaque() -> !llvm.struct<"opaque", opaque> +// CHECK: declare %long +llvm.func @return_s_long() -> !llvm.struct<"long", (i32, struct<(i32, i1)>, float, ptr>)> +// CHECK: declare %self-recursive +llvm.func @return_s_self_recurisve() -> !llvm.struct<"self-recursive", (ptr>)> +// CHECK: declare %unpacked +llvm.func @return_s_unpacked() -> !llvm.struct<"unpacked", (i32)> +// CHECK: declare %packed +llvm.func @return_s_packed() -> !llvm.struct<"packed", packed (i32)> +// CHECK: declare %"name with spaces and !^$@$#" +llvm.func @return_s_symbols() -> !llvm.struct<"name with spaces and !^$@$#", packed (i32)> + +// CHECK: declare %mutually-a +llvm.func @return_s_mutually_a() -> !llvm.struct<"mutually-a", (ptr, 3>)>>)> +// CHECK: declare %mutually-b +llvm.func @return_s_mutually_b() -> !llvm.struct<"mutually-b", (ptr>)>, 3>)> + +// CHECK: declare %struct-of-arrays +llvm.func @return_s_struct_of_arrays() -> !llvm.struct<"struct-of-arrays", (array<10 x i32>)> +// CHECK: declare [10 x %array-of-structs] +llvm.func @return_s_array_of_structs() -> !llvm.array<10 x struct<"array-of-structs", (i32)>> +// CHECK: declare %ptr-to-struct* +llvm.func @return_s_ptr_to_struct() -> !llvm.ptr> diff --git a/mlir/test/lib/CMakeLists.txt b/mlir/test/lib/CMakeLists.txt index ec9e5cd99801..0df357c8c355 100644 --- a/mlir/test/lib/CMakeLists.txt +++ b/mlir/test/lib/CMakeLists.txt @@ -2,5 +2,4 @@ add_subdirectory(Dialect) add_subdirectory(IR) add_subdirectory(Pass) add_subdirectory(Reducer) -add_subdirectory(Target) add_subdirectory(Transforms) diff --git a/mlir/test/lib/Target/CMakeLists.txt b/mlir/test/lib/Target/CMakeLists.txt deleted file mode 100644 index cb8f206469ae..000000000000 --- a/mlir/test/lib/Target/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_mlir_translation_library(MLIRTestLLVMTypeTranslation - TestLLVMTypeTranslation.cpp - - LINK_COMPONENTS - Core - TransformUtils - - LINK_LIBS PUBLIC - MLIRLLVMIR - MLIRTargetLLVMIRModuleTranslation - MLIRTestIR - MLIRTranslation - ) diff --git a/mlir/test/lib/Target/TestLLVMTypeTranslation.cpp b/mlir/test/lib/Target/TestLLVMTypeTranslation.cpp deleted file mode 100644 index e51734308aa6..000000000000 --- a/mlir/test/lib/Target/TestLLVMTypeTranslation.cpp +++ /dev/null @@ -1,79 +0,0 @@ -//===- TestLLVMTypeTranslation.cpp - Test MLIR/LLVM IR type translation ---===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "mlir/Dialect/LLVMIR/LLVMTypes.h" -#include "mlir/Target/LLVMIR/ModuleTranslation.h" -#include "mlir/Target/LLVMIR/TypeTranslation.h" -#include "mlir/Translation.h" - -using namespace mlir; - -namespace { -class TestLLVMTypeTranslation : public LLVM::ModuleTranslation { - // Allow access to the constructors under MSVC. - friend LLVM::ModuleTranslation; - -public: - using LLVM::ModuleTranslation::ModuleTranslation; - -protected: - /// Simple test facility for translating types from MLIR LLVM dialect to LLVM - /// IR. This converts the "llvm.test_introduce_func" operation into an LLVM IR - /// function with the name extracted from the `name` attribute that returns - /// the type contained in the `type` attribute if it is a non-function type or - /// that has the signature obtained by converting `type` if it is a function - /// type. This is a temporary check before type translation is substituted - /// into the main translation flow and exercised here. - LogicalResult convertOperation(Operation &op, - llvm::IRBuilder<> &builder) override { - if (op.getName().getStringRef() == "llvm.test_introduce_func") { - auto attr = op.getAttrOfType("type"); - assert(attr && "expected 'type' attribute"); - auto type = attr.getValue().cast(); - - auto nameAttr = op.getAttrOfType("name"); - assert(nameAttr && "expected 'name' attributes"); - - llvm::Type *translated = - LLVM::translateTypeToLLVMIR(type, builder.getContext()); - - llvm::Module *module = builder.GetInsertBlock()->getModule(); - if (auto *funcType = dyn_cast(translated)) - module->getOrInsertFunction(nameAttr.getValue(), funcType); - else - module->getOrInsertFunction(nameAttr.getValue(), translated); - - std::string roundtripName = (Twine(nameAttr.getValue()) + "_round").str(); - LLVM::LLVMType translatedBack = - LLVM::translateTypeFromLLVMIR(translated, *op.getContext()); - llvm::Type *translatedBackAndForth = - LLVM::translateTypeToLLVMIR(translatedBack, builder.getContext()); - if (auto *funcType = dyn_cast(translatedBackAndForth)) - module->getOrInsertFunction(roundtripName, funcType); - else - module->getOrInsertFunction(roundtripName, translatedBackAndForth); - return success(); - } - - return LLVM::ModuleTranslation::convertOperation(op, builder); - } -}; -} // namespace - -namespace mlir { -void registerTestLLVMTypeTranslation() { - TranslateFromMLIRRegistration reg( - "test-mlir-to-llvmir", [](ModuleOp module, raw_ostream &output) { - std::unique_ptr llvmModule = - LLVM::ModuleTranslation::translateModule( - module.getOperation()); - llvmModule->print(output, nullptr); - return success(); - }); -} -} // namespace mlir diff --git a/mlir/tools/mlir-translate/mlir-translate.cpp b/mlir/tools/mlir-translate/mlir-translate.cpp index 1f2ddca8c856..914bd340b3f5 100644 --- a/mlir/tools/mlir-translate/mlir-translate.cpp +++ b/mlir/tools/mlir-translate/mlir-translate.cpp @@ -49,13 +49,11 @@ static llvm::cl::opt verifyDiagnostics( namespace mlir { // Defined in the test directory, no public header. -void registerTestLLVMTypeTranslation(); void registerTestRoundtripSPIRV(); void registerTestRoundtripDebugSPIRV(); } // namespace mlir static void registerTestTranslations() { - registerTestLLVMTypeTranslation(); registerTestRoundtripSPIRV(); registerTestRoundtripDebugSPIRV(); }