diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h @@ -48,12 +48,6 @@ 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 --- 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 @@ /// 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 --- 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 @@ 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 --- a/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp +++ b/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp @@ -126,11 +126,12 @@ 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 --- 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 @@ 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 @@ Location unknownLoc; /// Cached dialect. LLVMDialect *dialect; + /// The stateful type translator (contains named structs). + LLVM::TypeFromLLVMIRTranslator typeTranslator; }; } // namespace @@ -149,79 +153,16 @@ } 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 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -304,7 +304,8 @@ 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 @@ 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 --- 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 @@ /// 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 @@ /// 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 --- 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 --- 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 @@ // 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 --- a/mlir/test/lib/CMakeLists.txt +++ b/mlir/test/lib/CMakeLists.txt @@ -2,5 +2,4 @@ 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 --- 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 --- 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 --- a/mlir/tools/mlir-translate/mlir-translate.cpp +++ b/mlir/tools/mlir-translate/mlir-translate.cpp @@ -49,13 +49,11 @@ namespace mlir { // Defined in the test directory, no public header. -void registerTestLLVMTypeTranslation(); void registerTestRoundtripSPIRV(); void registerTestRoundtripDebugSPIRV(); } // namespace mlir static void registerTestTranslations() { - registerTestLLVMTypeTranslation(); registerTestRoundtripSPIRV(); registerTestRoundtripDebugSPIRV(); }