1//===- TypeToLLVM.cpp - type translation from MLIR to LLVM IR -===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "mlir/Target/LLVMIR/TypeToLLVM.h"
10#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
11#include "mlir/IR/BuiltinTypes.h"
12
13#include "llvm/ADT/TypeSwitch.h"
14#include "llvm/IR/DataLayout.h"
15#include "llvm/IR/DerivedTypes.h"
16#include "llvm/IR/Type.h"
17
18using namespace mlir;
19
20namespace mlir {
21namespace LLVM {
22namespace detail {
23/// Support for translating MLIR LLVM dialect types to LLVM IR.
24class TypeToLLVMIRTranslatorImpl {
25public:
26 /// Constructs a class creating types in the given LLVM context.
27 TypeToLLVMIRTranslatorImpl(llvm::LLVMContext &context) : context(context) {}
28
29 /// Translates a single type.
30 llvm::Type *translateType(Type type) {
31 // If the conversion is already known, just return it.
32 if (knownTranslations.count(Val: type))
33 return knownTranslations.lookup(Val: type);
34
35 // Dispatch to an appropriate function.
36 llvm::Type *translated =
37 llvm::TypeSwitch<Type, llvm::Type *>(type)
38 .Case(caseFn: [this](LLVM::LLVMVoidType) {
39 return llvm::Type::getVoidTy(C&: context);
40 })
41 .Case(
42 caseFn: [this](Float16Type) { return llvm::Type::getHalfTy(C&: context); })
43 .Case(caseFn: [this](BFloat16Type) {
44 return llvm::Type::getBFloatTy(C&: context);
45 })
46 .Case(
47 caseFn: [this](Float32Type) { return llvm::Type::getFloatTy(C&: context); })
48 .Case(caseFn: [this](Float64Type) {
49 return llvm::Type::getDoubleTy(C&: context);
50 })
51 .Case(caseFn: [this](Float80Type) {
52 return llvm::Type::getX86_FP80Ty(C&: context);
53 })
54 .Case(caseFn: [this](Float128Type) {
55 return llvm::Type::getFP128Ty(C&: context);
56 })
57 .Case(caseFn: [this](LLVM::LLVMPPCFP128Type) {
58 return llvm::Type::getPPC_FP128Ty(C&: context);
59 })
60 .Case(caseFn: [this](LLVM::LLVMTokenType) {
61 return llvm::Type::getTokenTy(C&: context);
62 })
63 .Case(caseFn: [this](LLVM::LLVMLabelType) {
64 return llvm::Type::getLabelTy(C&: context);
65 })
66 .Case(caseFn: [this](LLVM::LLVMMetadataType) {
67 return llvm::Type::getMetadataTy(C&: context);
68 })
69 .Case(caseFn: [this](LLVM::LLVMX86AMXType) {
70 return llvm::Type::getX86_AMXTy(C&: context);
71 })
72 .Case<LLVM::LLVMArrayType, IntegerType, LLVM::LLVMFunctionType,
73 LLVM::LLVMPointerType, LLVM::LLVMStructType, VectorType,
74 LLVM::LLVMTargetExtType>(
75 caseFn: [this](auto type) { return this->translate(type); })
76 .Default(defaultFn: [](Type t) -> llvm::Type * {
77 llvm_unreachable("unknown LLVM dialect type");
78 });
79
80 // Cache the result of the conversion and return.
81 knownTranslations.try_emplace(Key: type, Args&: translated);
82 return translated;
83 }
84
85private:
86 /// Translates the given array type.
87 llvm::Type *translate(LLVM::LLVMArrayType type) {
88 return llvm::ArrayType::get(ElementType: translateType(type: type.getElementType()),
89 NumElements: type.getNumElements());
90 }
91
92 /// Translates the given function type.
93 llvm::Type *translate(LLVM::LLVMFunctionType type) {
94 SmallVector<llvm::Type *, 8> paramTypes;
95 translateTypes(types: type.getParams(), result&: paramTypes);
96 return llvm::FunctionType::get(Result: translateType(type: type.getReturnType()),
97 Params: paramTypes, isVarArg: type.isVarArg());
98 }
99
100 /// Translates the given integer type.
101 llvm::Type *translate(IntegerType type) {
102 return llvm::IntegerType::get(C&: context, NumBits: type.getWidth());
103 }
104
105 /// Translates the given pointer type.
106 llvm::Type *translate(LLVM::LLVMPointerType type) {
107 return llvm::PointerType::get(C&: context, AddressSpace: type.getAddressSpace());
108 }
109
110 /// Translates the given structure type, supports both identified and literal
111 /// structs. This will _create_ a new identified structure every time, use
112 /// `convertType` if a structure with the same name must be looked up instead.
113 llvm::Type *translate(LLVM::LLVMStructType type) {
114 SmallVector<llvm::Type *, 8> subtypes;
115 if (!type.isIdentified()) {
116 translateTypes(types: type.getBody(), result&: subtypes);
117 return llvm::StructType::get(Context&: context, Elements: subtypes, isPacked: type.isPacked());
118 }
119
120 llvm::StructType *structType =
121 llvm::StructType::create(Context&: context, Name: type.getName());
122 // Mark the type we just created as known so that recursive calls can pick
123 // it up and use directly.
124 knownTranslations.try_emplace(Key: type, Args&: structType);
125 if (type.isOpaque())
126 return structType;
127
128 translateTypes(types: type.getBody(), result&: subtypes);
129 structType->setBody(Elements: subtypes, isPacked: type.isPacked());
130 return structType;
131 }
132
133 /// Translates the given built-in vector type compatible with LLVM.
134 llvm::Type *translate(VectorType type) {
135 assert(LLVM::isCompatibleVectorType(type) &&
136 "expected compatible with LLVM vector type");
137 if (type.isScalable())
138 return llvm::ScalableVectorType::get(ElementType: translateType(type: type.getElementType()),
139 MinNumElts: type.getNumElements());
140 return llvm::FixedVectorType::get(ElementType: translateType(type: type.getElementType()),
141 NumElts: type.getNumElements());
142 }
143
144 /// Translates the given target extension type.
145 llvm::Type *translate(LLVM::LLVMTargetExtType type) {
146 SmallVector<llvm::Type *> typeParams;
147 translateTypes(types: type.getTypeParams(), result&: typeParams);
148 return llvm::TargetExtType::get(Context&: context, Name: type.getExtTypeName(), Types: typeParams,
149 Ints: type.getIntParams());
150 }
151
152 /// Translates a list of types.
153 void translateTypes(ArrayRef<Type> types,
154 SmallVectorImpl<llvm::Type *> &result) {
155 result.reserve(N: result.size() + types.size());
156 for (auto type : types)
157 result.push_back(Elt: translateType(type));
158 }
159
160 /// Reference to the context in which the LLVM IR types are created.
161 llvm::LLVMContext &context;
162
163 /// Map of known translation. This serves a double purpose: caches translation
164 /// results to avoid repeated recursive calls and makes sure identified
165 /// structs with the same name (that is, equal) are resolved to an existing
166 /// type instead of creating a new type.
167 llvm::DenseMap<Type, llvm::Type *> knownTranslations;
168};
169} // namespace detail
170} // namespace LLVM
171} // namespace mlir
172
173LLVM::TypeToLLVMIRTranslator::TypeToLLVMIRTranslator(llvm::LLVMContext &context)
174 : impl(new detail::TypeToLLVMIRTranslatorImpl(context)) {}
175
176LLVM::TypeToLLVMIRTranslator::~TypeToLLVMIRTranslator() = default;
177
178llvm::Type *LLVM::TypeToLLVMIRTranslator::translateType(Type type) {
179 return impl->translateType(type);
180}
181
182unsigned LLVM::TypeToLLVMIRTranslator::getPreferredAlignment(
183 Type type, const llvm::DataLayout &layout) {
184 return layout.getPrefTypeAlign(Ty: translateType(type)).value();
185}
186

source code of mlir/lib/Target/LLVMIR/TypeToLLVM.cpp