MLIR 24.0.0git
LLVMTypes.cpp
Go to the documentation of this file.
1//===- LLVMTypes.cpp - MLIR LLVM dialect types ------------------*- C++ -*-===//
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// This file implements the types for the LLVM dialect in MLIR. These MLIR types
10// correspond to the LLVM IR type system.
11//
12//===----------------------------------------------------------------------===//
13
14#include "TypeDetail.h"
15
21#include "mlir/IR/TypeSupport.h"
22
23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/Support/TypeSize.h"
25#include <optional>
26
27using namespace mlir;
28using namespace mlir::LLVM;
29
30constexpr const static uint64_t kBitsInByte = 8;
31
32//===----------------------------------------------------------------------===//
33// custom<FunctionTypes>
34//===----------------------------------------------------------------------===//
35
36static ParseResult parseFunctionTypes(AsmParser &p, SmallVector<Type> &params,
37 bool &isVarArg) {
38 isVarArg = false;
39 // `(` `)`
40 if (succeeded(p.parseOptionalRParen()))
41 return success();
42
43 // `(` `...` `)`
44 if (succeeded(p.parseOptionalEllipsis())) {
45 isVarArg = true;
46 return p.parseRParen();
47 }
48
49 // type (`,` type)* (`,` `...`)?
50 Type type;
51 if (parsePrettyLLVMType(p, type))
52 return failure();
53 params.push_back(type);
54 while (succeeded(p.parseOptionalComma())) {
55 if (succeeded(p.parseOptionalEllipsis())) {
56 isVarArg = true;
57 return p.parseRParen();
58 }
59 if (parsePrettyLLVMType(p, type))
60 return failure();
61 params.push_back(type);
62 }
63 return p.parseRParen();
64}
65
67 bool isVarArg) {
68 llvm::interleaveComma(params, p,
69 [&](Type type) { printPrettyLLVMType(p, type); });
70 if (isVarArg) {
71 if (!params.empty())
72 p << ", ";
73 p << "...";
74 }
75 p << ')';
76}
77
78//===----------------------------------------------------------------------===//
79// custom<ExtTypeParams>
80//===----------------------------------------------------------------------===//
81
82/// Parses the parameter list for a target extension type. The parameter list
83/// contains an optional list of type parameters, followed by an optional list
84/// of integer parameters. Type and integer parameters cannot be interleaved in
85/// the list.
86/// extTypeParams ::= typeList? | intList? | (typeList "," intList)
87/// typeList ::= type ("," type)*
88/// intList ::= integer ("," integer)*
89static ParseResult
92 bool parseType = true;
93 auto typeOrIntParser = [&]() -> ParseResult {
94 unsigned int i;
95 auto intResult = p.parseOptionalInteger(i);
96 if (intResult.has_value() && !failed(*intResult)) {
97 // Successfully parsed an integer.
98 intParams.push_back(i);
99 // After the first integer was successfully parsed, no
100 // more types can be parsed.
101 parseType = false;
102 return success();
103 }
104 if (parseType) {
105 Type t;
106 if (!parsePrettyLLVMType(p, t)) {
107 // Successfully parsed a type.
108 typeParams.push_back(t);
109 return success();
110 }
111 }
112 return failure();
113 };
114 if (p.parseCommaSeparatedList(typeOrIntParser)) {
116 "failed to parse parameter list for target extension type");
117 return failure();
118 }
119 return success();
120}
121
123 ArrayRef<unsigned int> intParams) {
124 p << typeParams;
125 if (!typeParams.empty() && !intParams.empty())
126 p << ", ";
127
128 p << intParams;
129}
130
131//===----------------------------------------------------------------------===//
132// ODS-Generated Definitions
133//===----------------------------------------------------------------------===//
134
135/// These are unused for now.
136/// TODO: Move over to these once more types have been migrated to TypeDef.
137[[maybe_unused]] static OptionalParseResult
138generatedTypeParser(AsmParser &parser, StringRef *mnemonic, Type &value);
139[[maybe_unused]] static LogicalResult generatedTypePrinter(Type def,
140 AsmPrinter &printer);
141
142#include "mlir/Dialect/LLVMIR/LLVMTypeInterfaces.cpp.inc"
143
144#define GET_TYPEDEF_CLASSES
145#include "mlir/Dialect/LLVMIR/LLVMTypes.cpp.inc"
146
147//===----------------------------------------------------------------------===//
148// LLVMArrayType
149//===----------------------------------------------------------------------===//
150
151bool LLVMArrayType::isValidElementType(Type type) {
152 return !llvm::isa<LLVMVoidType, LLVMLabelType, LLVMMetadataType,
153 LLVMFunctionType, TokenType>(type);
154}
155
156LLVMArrayType LLVMArrayType::get(Type elementType, uint64_t numElements) {
157 assert(elementType && "expected non-null subtype");
158 return Base::get(elementType.getContext(), elementType, numElements);
159}
160
161LLVMArrayType
162LLVMArrayType::getChecked(function_ref<InFlightDiagnostic()> emitError,
163 Type elementType, uint64_t numElements) {
164 assert(elementType && "expected non-null subtype");
165 return Base::getChecked(emitError, elementType.getContext(), elementType,
166 numElements);
167}
168
169LogicalResult
170LLVMArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
171 Type elementType, uint64_t numElements) {
172 if (!isValidElementType(elementType))
173 return emitError() << "invalid array element type: " << elementType;
174 return success();
175}
176
177//===----------------------------------------------------------------------===//
178// DataLayoutTypeInterface
179//===----------------------------------------------------------------------===//
180
181llvm::TypeSize
182LLVMArrayType::getTypeSizeInBits(const DataLayout &dataLayout,
183 DataLayoutEntryListRef params) const {
184 return llvm::TypeSize::getFixed(kBitsInByte *
185 getTypeSize(dataLayout, params));
186}
187
188llvm::TypeSize LLVMArrayType::getTypeSize(const DataLayout &dataLayout,
189 DataLayoutEntryListRef params) const {
190 return llvm::alignTo(dataLayout.getTypeSize(getElementType()),
191 dataLayout.getTypeABIAlignment(getElementType())) *
193}
194
195uint64_t LLVMArrayType::getABIAlignment(const DataLayout &dataLayout,
196 DataLayoutEntryListRef params) const {
197 return dataLayout.getTypeABIAlignment(getElementType());
198}
199
200uint64_t
201LLVMArrayType::getPreferredAlignment(const DataLayout &dataLayout,
202 DataLayoutEntryListRef params) const {
203 return dataLayout.getTypePreferredAlignment(getElementType());
204}
205
206//===----------------------------------------------------------------------===//
207// LLVMByteType
208//===----------------------------------------------------------------------===//
209
210llvm::TypeSize
211LLVMByteType::getTypeSizeInBits(const DataLayout &dataLayout,
212 DataLayoutEntryListRef params) const {
213 return llvm::TypeSize::getFixed(getBitWidth());
214}
215
216uint64_t LLVMByteType::getABIAlignment(const DataLayout &dataLayout,
217 DataLayoutEntryListRef params) const {
218 return llvm::PowerOf2Ceil(llvm::divideCeil(getBitWidth(), kBitsInByte));
219}
220
221LogicalResult LLVMByteType::verify(function_ref<InFlightDiagnostic()> emitError,
222 unsigned bitWidth) {
223 if (bitWidth == 0)
224 return emitError() << "bitwidth must be greater than 0";
225
226 // Mirror LLVM IR, which limits the bit width to fit in 23 bits.
227 constexpr unsigned kMaxBitWidth = 1 << 23;
228 if (bitWidth >= kMaxBitWidth)
229 return emitError() << "bitwidth must be less than " << kMaxBitWidth
230 << ", but got " << bitWidth;
231 return success();
232}
233
234//===----------------------------------------------------------------------===//
235// Function type.
236//===----------------------------------------------------------------------===//
237
238bool LLVMFunctionType::isValidArgumentType(Type type) {
239 if (auto structType = dyn_cast<LLVMStructType>(type))
240 return !structType.isOpaque();
241
242 return !llvm::isa<LLVMVoidType, LLVMFunctionType>(type);
243}
244
245bool LLVMFunctionType::isValidResultType(Type type) {
246 return !llvm::isa<LLVMFunctionType, LLVMMetadataType, LLVMLabelType>(type);
247}
248
249LLVMFunctionType LLVMFunctionType::get(Type result, ArrayRef<Type> arguments,
250 bool isVarArg) {
251 assert(result && "expected non-null result");
252 return Base::get(result.getContext(), result, arguments, isVarArg);
253}
254
255LLVMFunctionType
256LLVMFunctionType::getChecked(function_ref<InFlightDiagnostic()> emitError,
257 Type result, ArrayRef<Type> arguments,
258 bool isVarArg) {
259 assert(result && "expected non-null result");
260 return Base::getChecked(emitError, result.getContext(), result, arguments,
261 isVarArg);
262}
263
264LLVMFunctionType LLVMFunctionType::clone(TypeRange inputs,
265 TypeRange results) const {
266 // LLVM functions have exactly one return type. An empty results range
267 // corresponds to a void return type (as FunctionOpInterface represents void
268 // functions with 0 results). More than one result is not valid.
269 if (results.size() > 1)
270 return {};
271 Type resultType =
272 results.empty() ? LLVMVoidType::get(getContext()) : results[0];
273 if (!isValidResultType(resultType))
274 return {};
275 if (!llvm::all_of(inputs, isValidArgumentType))
276 return {};
277 return get(resultType, llvm::to_vector(inputs), isVarArg());
278}
279
280ArrayRef<Type> LLVMFunctionType::getReturnTypes() const {
281 return static_cast<detail::LLVMFunctionTypeStorage *>(getImpl())->returnType;
282}
283
284LogicalResult
285LLVMFunctionType::verify(function_ref<InFlightDiagnostic()> emitError,
286 Type result, ArrayRef<Type> arguments, bool) {
287 if (!isValidResultType(result))
288 return emitError() << "invalid function result type: " << result;
289
290 for (Type arg : arguments)
291 if (!isValidArgumentType(arg))
292 return emitError() << "invalid function argument type: " << arg;
293
294 return success();
295}
296
297//===----------------------------------------------------------------------===//
298// DataLayoutTypeInterface
299//===----------------------------------------------------------------------===//
300
301constexpr const static uint64_t kDefaultPointerSizeBits = 64;
302constexpr const static uint64_t kDefaultPointerAlignment = 8;
303
305 PtrDLEntryPos pos) {
306 auto spec = cast<DenseIntElementsAttr>(attr);
307 auto idx = static_cast<int64_t>(pos);
308 if (idx >= spec.size())
309 return std::nullopt;
310 return spec.getValues<uint64_t>()[idx];
311}
312
313/// Returns the part of the data layout entry that corresponds to `pos` for the
314/// given `type` by interpreting the list of entries `params`. For the pointer
315/// type in the default address space, returns the default value if the entries
316/// do not provide a custom one, for other address spaces returns std::nullopt.
317static std::optional<uint64_t>
319 PtrDLEntryPos pos) {
320 // First, look for the entry for the pointer in the current address space.
321 Attribute currentEntry;
322 for (DataLayoutEntryInterface entry : params) {
323 if (!entry.isTypeEntry())
324 continue;
325 if (cast<LLVMPointerType>(cast<Type>(entry.getKey())).getAddressSpace() ==
326 type.getAddressSpace()) {
327 currentEntry = entry.getValue();
328 break;
329 }
330 }
331 if (currentEntry) {
332 std::optional<uint64_t> value = extractPointerSpecValue(currentEntry, pos);
333 // If the optional `PtrDLEntryPos::Index` entry is not available, use the
334 // pointer size as the index bitwidth.
335 if (!value && pos == PtrDLEntryPos::Index)
336 value = extractPointerSpecValue(currentEntry, PtrDLEntryPos::Size);
337 bool isSizeOrIndex =
339 return *value / (isSizeOrIndex ? 1 : kBitsInByte);
340 }
341
342 // If not found, and this is the pointer to the default memory space, assume
343 // 64-bit pointers.
344 if (type.getAddressSpace() == 0) {
345 bool isSizeOrIndex =
347 return isSizeOrIndex ? kDefaultPointerSizeBits : kDefaultPointerAlignment;
348 }
349
350 return std::nullopt;
351}
352
353llvm::TypeSize
354LLVMPointerType::getTypeSizeInBits(const DataLayout &dataLayout,
355 DataLayoutEntryListRef params) const {
356 if (std::optional<uint64_t> size =
358 return llvm::TypeSize::getFixed(*size);
359
360 // For other memory spaces, use the size of the pointer to the default memory
361 // space.
362 return dataLayout.getTypeSizeInBits(get(getContext()));
363}
364
365uint64_t LLVMPointerType::getABIAlignment(const DataLayout &dataLayout,
366 DataLayoutEntryListRef params) const {
367 if (std::optional<uint64_t> alignment =
369 return *alignment;
370
371 return dataLayout.getTypeABIAlignment(get(getContext()));
372}
373
374uint64_t
375LLVMPointerType::getPreferredAlignment(const DataLayout &dataLayout,
376 DataLayoutEntryListRef params) const {
377 if (std::optional<uint64_t> alignment =
379 return *alignment;
380
381 return dataLayout.getTypePreferredAlignment(get(getContext()));
382}
383
384std::optional<uint64_t>
385LLVMPointerType::getIndexBitwidth(const DataLayout &dataLayout,
386 DataLayoutEntryListRef params) const {
387 if (std::optional<uint64_t> indexBitwidth =
389 return *indexBitwidth;
390
391 return dataLayout.getTypeIndexBitwidth(get(getContext()));
392}
393
394bool LLVMPointerType::areCompatible(
396 DataLayoutSpecInterface newSpec,
397 const DataLayoutIdentifiedEntryMap &map) const {
398 for (DataLayoutEntryInterface newEntry : newLayout) {
399 if (!newEntry.isTypeEntry())
400 continue;
401 uint64_t size = kDefaultPointerSizeBits;
402 uint64_t abi = kDefaultPointerAlignment;
403 auto newType =
404 llvm::cast<LLVMPointerType>(llvm::cast<Type>(newEntry.getKey()));
405 const auto *it =
406 llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
407 if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
408 return llvm::cast<LLVMPointerType>(type).getAddressSpace() ==
409 newType.getAddressSpace();
410 }
411 return false;
412 });
413 if (it == oldLayout.end()) {
414 llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
415 if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
416 return llvm::cast<LLVMPointerType>(type).getAddressSpace() == 0;
417 }
418 return false;
419 });
420 }
421 if (it != oldLayout.end()) {
424 }
425
426 Attribute newSpec = llvm::cast<DenseIntElementsAttr>(newEntry.getValue());
427 uint64_t newSize = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Size);
428 uint64_t newAbi = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Abi);
429 if (size != newSize || abi < newAbi || abi % newAbi != 0)
430 return false;
431 }
432 return true;
433}
434
435LogicalResult LLVMPointerType::verifyEntries(DataLayoutEntryListRef entries,
436 Location loc) const {
437 for (DataLayoutEntryInterface entry : entries) {
438 if (!entry.isTypeEntry())
439 continue;
440 auto key = llvm::cast<Type>(entry.getKey());
441 auto values = llvm::dyn_cast<DenseIntElementsAttr>(entry.getValue());
442 if (!values || (values.size() != 3 && values.size() != 4)) {
443 return emitError(loc)
444 << "expected layout attribute for " << key
445 << " to be a dense integer elements attribute with 3 or 4 "
446 "elements";
447 }
448 if (!values.getElementType().isInteger(64))
449 return emitError(loc) << "expected i64 parameters for " << key;
450
453 return emitError(loc) << "preferred alignment is expected to be at least "
454 "as large as ABI alignment";
455 }
456 }
457 return success();
458}
459
460//===----------------------------------------------------------------------===//
461// Struct type.
462//===----------------------------------------------------------------------===//
463
464bool LLVMStructType::isValidElementType(Type type) {
465 return !llvm::isa<LLVMVoidType, LLVMLabelType, LLVMMetadataType,
466 LLVMFunctionType, TokenType>(type);
467}
468
469LLVMStructType LLVMStructType::getIdentified(MLIRContext *context,
470 StringRef name) {
471 return Base::get(context, name, /*opaque=*/false);
472}
473
474LLVMStructType LLVMStructType::getIdentifiedChecked(
475 function_ref<InFlightDiagnostic()> emitError, MLIRContext *context,
476 StringRef name) {
477 return Base::getChecked(emitError, context, name, /*opaque=*/false);
478}
479
480LLVMStructType LLVMStructType::getNewIdentified(MLIRContext *context,
481 StringRef name,
482 ArrayRef<Type> elements,
483 bool isPacked) {
484 std::string stringName = name.str();
485 unsigned counter = 0;
486 do {
487 auto type = LLVMStructType::getIdentified(context, stringName);
488 if (type.isInitialized() || failed(type.setBody(elements, isPacked))) {
489 counter += 1;
490 stringName = (Twine(name) + "." + std::to_string(counter)).str();
491 continue;
492 }
493 return type;
494 } while (true);
495}
496
497LLVMStructType LLVMStructType::getLiteral(MLIRContext *context,
498 ArrayRef<Type> types, bool isPacked) {
499 return Base::get(context, types, isPacked);
500}
501
502LLVMStructType
503LLVMStructType::getLiteralChecked(function_ref<InFlightDiagnostic()> emitError,
504 MLIRContext *context, ArrayRef<Type> types,
505 bool isPacked) {
506 return Base::getChecked(emitError, context, types, isPacked);
507}
508
509LLVMStructType LLVMStructType::getOpaque(StringRef name, MLIRContext *context) {
510 return Base::get(context, name, /*opaque=*/true);
511}
512
513LLVMStructType
514LLVMStructType::getOpaqueChecked(function_ref<InFlightDiagnostic()> emitError,
515 MLIRContext *context, StringRef name) {
516 return Base::getChecked(emitError, context, name, /*opaque=*/true);
517}
518
519LogicalResult LLVMStructType::setBody(ArrayRef<Type> types, bool isPacked) {
520 assert(isIdentified() && "can only set bodies of identified structs");
521 assert(llvm::all_of(types, LLVMStructType::isValidElementType) &&
522 "expected valid body types");
523 return Base::mutate(types, isPacked);
524}
525
526bool LLVMStructType::isPacked() const { return getImpl()->isPacked(); }
527bool LLVMStructType::isIdentified() const { return getImpl()->isIdentified(); }
528bool LLVMStructType::isOpaque() const {
529 return getImpl()->isIdentified() &&
530 (getImpl()->isOpaque() || !getImpl()->isInitialized());
531}
532bool LLVMStructType::isInitialized() { return getImpl()->isInitialized(); }
533StringRef LLVMStructType::getName() const { return getImpl()->getIdentifier(); }
534ArrayRef<Type> LLVMStructType::getBody() const {
535 return isIdentified() ? getImpl()->getIdentifiedStructBody()
536 : getImpl()->getTypeList();
537}
538
539LogicalResult
540LLVMStructType::verifyInvariants(function_ref<InFlightDiagnostic()>, StringRef,
541 bool) {
542 return success();
543}
544
545LogicalResult
546LLVMStructType::verifyInvariants(function_ref<InFlightDiagnostic()> emitError,
547 ArrayRef<Type> types, bool) {
548 for (Type t : types)
549 if (!isValidElementType(t))
550 return emitError() << "invalid LLVM structure element type: " << t;
551
552 return success();
553}
554
555llvm::TypeSize
556LLVMStructType::getTypeSizeInBits(const DataLayout &dataLayout,
557 DataLayoutEntryListRef params) const {
558 auto structSize = llvm::TypeSize::getFixed(0);
559 uint64_t structAlignment = 1;
560 for (Type element : getBody()) {
561 uint64_t elementAlignment =
562 isPacked() ? 1 : dataLayout.getTypeABIAlignment(element);
563 // Add padding to align the element unless the struct is packed.
564 structSize = llvm::alignTo(structSize, elementAlignment);
565 // Elements occupy their allocation size, even in packed structs.
566 structSize += llvm::alignTo(dataLayout.getTypeSize(element),
567 dataLayout.getTypeABIAlignment(element));
568
569 // The alignment requirement of a struct is equal to the strictest alignment
570 // requirement of its elements.
571 structAlignment = std::max(elementAlignment, structAlignment);
572 }
573 // At the end, add padding to the struct to satisfy its own alignment
574 // requirement. Otherwise structs inside of arrays would be misaligned.
575 structSize = llvm::alignTo(structSize, structAlignment);
576 return structSize * kBitsInByte;
577}
578
579namespace {
580enum class StructDLEntryPos { Abi = 0, Preferred = 1 };
581} // namespace
582
583static std::optional<uint64_t>
585 StructDLEntryPos pos) {
586 const auto *currentEntry =
587 llvm::find_if(params, [](DataLayoutEntryInterface entry) {
588 return entry.isTypeEntry();
589 });
590 if (currentEntry == params.end())
591 return std::nullopt;
592
593 auto attr = llvm::cast<DenseIntElementsAttr>(currentEntry->getValue());
594 if (pos == StructDLEntryPos::Preferred &&
595 attr.size() <= static_cast<int64_t>(StructDLEntryPos::Preferred))
596 // If no preferred was specified, fall back to abi alignment
597 pos = StructDLEntryPos::Abi;
598
599 return attr.getValues<uint64_t>()[static_cast<size_t>(pos)];
600}
601
602static uint64_t calculateStructAlignment(const DataLayout &dataLayout,
604 LLVMStructType type,
605 StructDLEntryPos pos) {
606 // Packed structs always have an abi alignment of 1
607 if (pos == StructDLEntryPos::Abi && type.isPacked()) {
608 return 1;
609 }
610
611 // The alignment requirement of a struct is equal to the strictest alignment
612 // requirement of its elements.
613 uint64_t structAlignment = 1;
614 for (Type iter : type.getBody()) {
615 structAlignment =
616 std::max(dataLayout.getTypeABIAlignment(iter), structAlignment);
617 }
618
619 // Entries are only allowed to be stricter than the required alignment
620 if (std::optional<uint64_t> entryResult =
621 getStructDataLayoutEntry(params, type, pos))
622 return std::max(*entryResult / kBitsInByte, structAlignment);
623
624 return structAlignment;
625}
626
627uint64_t LLVMStructType::getABIAlignment(const DataLayout &dataLayout,
628 DataLayoutEntryListRef params) const {
629 return calculateStructAlignment(dataLayout, params, *this,
630 StructDLEntryPos::Abi);
631}
632
633uint64_t
634LLVMStructType::getPreferredAlignment(const DataLayout &dataLayout,
635 DataLayoutEntryListRef params) const {
636 return calculateStructAlignment(dataLayout, params, *this,
637 StructDLEntryPos::Preferred);
638}
639
640static uint64_t extractStructSpecValue(Attribute attr, StructDLEntryPos pos) {
641 return llvm::cast<DenseIntElementsAttr>(attr)
642 .getValues<uint64_t>()[static_cast<size_t>(pos)];
643}
644
645bool LLVMStructType::areCompatible(
647 DataLayoutSpecInterface newSpec,
648 const DataLayoutIdentifiedEntryMap &map) const {
649 for (DataLayoutEntryInterface newEntry : newLayout) {
650 if (!newEntry.isTypeEntry())
651 continue;
652
653 const auto *previousEntry =
654 llvm::find_if(oldLayout, [](DataLayoutEntryInterface entry) {
655 return entry.isTypeEntry();
656 });
657 if (previousEntry == oldLayout.end())
658 continue;
659
660 uint64_t abi = extractStructSpecValue(previousEntry->getValue(),
661 StructDLEntryPos::Abi);
662 uint64_t newAbi =
663 extractStructSpecValue(newEntry.getValue(), StructDLEntryPos::Abi);
664 if (abi < newAbi || abi % newAbi != 0)
665 return false;
666 }
667 return true;
668}
669
670LogicalResult LLVMStructType::verifyEntries(DataLayoutEntryListRef entries,
671 Location loc) const {
672 for (DataLayoutEntryInterface entry : entries) {
673 if (!entry.isTypeEntry())
674 continue;
675
676 auto key = llvm::cast<LLVMStructType>(llvm::cast<Type>(entry.getKey()));
677 auto values = llvm::dyn_cast<DenseIntElementsAttr>(entry.getValue());
678 if (!values || (values.size() != 2 && values.size() != 1)) {
679 return emitError(loc)
680 << "expected layout attribute for "
681 << llvm::cast<Type>(entry.getKey())
682 << " to be a dense integer elements attribute of 1 or 2 elements";
683 }
684 if (!values.getElementType().isInteger(64))
685 return emitError(loc) << "expected i64 entries for " << key;
686
687 if (key.isIdentified() || !key.getBody().empty()) {
688 return emitError(loc) << "unexpected layout attribute for struct " << key;
689 }
690
691 if (values.size() == 1)
692 continue;
693
694 if (extractStructSpecValue(values, StructDLEntryPos::Abi) >
695 extractStructSpecValue(values, StructDLEntryPos::Preferred)) {
696 return emitError(loc) << "preferred alignment is expected to be at least "
697 "as large as ABI alignment";
698 }
699 }
700 return mlir::success();
701}
702
703//===----------------------------------------------------------------------===//
704// LLVMTargetExtType.
705//===----------------------------------------------------------------------===//
706
707static constexpr llvm::StringRef kSpirvPrefix = "spirv.";
708static constexpr llvm::StringRef kArmSVCount = "aarch64.svcount";
709static constexpr llvm::StringRef kAMDGCNNamedBarrier = "amdgcn.named.barrier";
710
711bool LLVM::LLVMTargetExtType::hasProperty(Property prop) const {
712 // See llvm/lib/IR/Type.cpp for reference.
713 uint64_t properties = 0;
714
715 if (getExtTypeName().starts_with(kSpirvPrefix))
716 properties |=
717 (LLVMTargetExtType::HasZeroInit | LLVM::LLVMTargetExtType::CanBeGlobal);
718
719 if (getExtTypeName() == kAMDGCNNamedBarrier)
720 properties |= LLVMTargetExtType::CanBeGlobal;
721
722 return (properties & prop) == prop;
723}
724
725bool LLVM::LLVMTargetExtType::supportsMemOps() const {
726 // See llvm/lib/IR/Type.cpp for reference.
727 if (getExtTypeName().starts_with(kSpirvPrefix))
728 return true;
729
730 if (getExtTypeName() == kArmSVCount)
731 return true;
732
733 return false;
734}
735
736//===----------------------------------------------------------------------===//
737// LLVMPPCFP128Type
738//===----------------------------------------------------------------------===//
739
740const llvm::fltSemantics &LLVMPPCFP128Type::getFloatSemantics() const {
741 return APFloat::PPCDoubleDouble();
742}
743
744//===----------------------------------------------------------------------===//
745// Utility functions.
746//===----------------------------------------------------------------------===//
747
748/// Check whether type is a compatible ptr type. These are pointer-like types
749/// with no element type, no metadata, and using the LLVM
750/// LLVMAddrSpaceAttrInterface memory space.
751static bool isCompatiblePtrType(Type type) {
752 auto ptrTy = dyn_cast<PtrLikeTypeInterface>(type);
753 if (!ptrTy)
754 return false;
755 return !ptrTy.hasPtrMetadata() && ptrTy.getElementType() == nullptr &&
756 isa<LLVMAddrSpaceAttrInterface>(ptrTy.getMemorySpace());
757}
758
760 // clang-format off
761 if (llvm::isa<
762 BFloat16Type,
763 Float16Type,
764 Float32Type,
765 Float64Type,
766 Float80Type,
767 Float128Type,
768 LLVMArrayType,
769 LLVMByteType,
770 LLVMFunctionType,
771 LLVMLabelType,
772 LLVMMetadataType,
773 LLVMPPCFP128Type,
774 LLVMPointerType,
775 LLVMStructType,
776 LLVMTargetExtType,
777 LLVMVoidType,
778 LLVMX86AMXType,
779 TokenType
780 >(type)) {
781 // clang-format on
782 return true;
783 }
784
785 // Only signless integers are compatible.
786 if (auto intType = llvm::dyn_cast<IntegerType>(type))
787 return intType.isSignless();
788
789 // 1D vector types are compatible.
790 if (auto vecType = llvm::dyn_cast<VectorType>(type))
791 return vecType.getRank() == 1;
792
793 return isCompatiblePtrType(type);
794}
795
796static bool isCompatibleImpl(Type type, DenseSet<Type> &compatibleTypes) {
797 if (!compatibleTypes.insert(type).second)
798 return true;
799
800 auto isCompatible = [&](Type type) {
801 return isCompatibleImpl(type, compatibleTypes);
802 };
803
804 bool result =
806 .Case([&](LLVMStructType structType) {
807 return llvm::all_of(structType.getBody(), isCompatible);
808 })
809 .Case([&](LLVMFunctionType funcType) {
810 return isCompatible(funcType.getReturnType()) &&
811 llvm::all_of(funcType.getParams(), isCompatible);
812 })
813 .Case([](IntegerType intType) { return intType.isSignless(); })
814 .Case([&](VectorType vecType) {
815 return vecType.getRank() == 1 &&
816 isCompatible(vecType.getElementType());
817 })
818 .Case([&](LLVMPointerType pointerType) { return true; })
819 .Case([&](LLVMTargetExtType extType) {
820 return llvm::all_of(extType.getTypeParams(), isCompatible);
821 })
822 // clang-format off
823 .Case([&](LLVMArrayType containerType) {
824 return isCompatible(containerType.getElementType());
825 })
826 .Case<
827 BFloat16Type,
828 Float16Type,
829 Float32Type,
830 Float64Type,
831 Float80Type,
832 Float128Type,
833 LLVMByteType,
834 LLVMLabelType,
835 LLVMMetadataType,
836 LLVMPPCFP128Type,
837 LLVMVoidType,
838 LLVMX86AMXType,
839 TokenType
840 >([](Type) { return true; })
841 // clang-format on
842 .Case<PtrLikeTypeInterface>(
843 [](Type type) { return isCompatiblePtrType(type); })
844 .Default(false);
845
846 if (!result)
847 compatibleTypes.erase(type);
848
849 return result;
850}
851
852bool LLVMDialect::isCompatibleType(Type type) {
853 if (auto *llvmDialect =
854 type.getContext()->getLoadedDialect<LLVM::LLVMDialect>())
855 return isCompatibleImpl(type, llvmDialect->compatibleTypes.get());
856
857 DenseSet<Type> localCompatibleTypes;
858 return isCompatibleImpl(type, localCompatibleTypes);
859}
860
862 return LLVMDialect::isCompatibleType(type);
863}
864
866 return /*LLVM_PrimitiveType*/ (
868 !isa<LLVM::LLVMVoidType, LLVM::LLVMFunctionType>(type)) &&
869 /*LLVM_OpaqueStruct*/
870 !(isa<LLVM::LLVMStructType>(type) &&
871 cast<LLVM::LLVMStructType>(type).isOpaque()) &&
872 /*LLVM_AnyTargetExt*/
873 !(isa<LLVM::LLVMTargetExtType>(type) &&
874 !cast<LLVM::LLVMTargetExtType>(type).supportsMemOps());
875}
876
878 return llvm::isa<BFloat16Type, Float16Type, Float32Type, Float64Type,
879 Float80Type, Float128Type, LLVMPPCFP128Type>(type);
880}
881
883 if (auto vecType = llvm::dyn_cast<VectorType>(type)) {
884 if (vecType.getRank() != 1)
885 return false;
886 Type elementType = vecType.getElementType();
887 if (auto intType = llvm::dyn_cast<IntegerType>(elementType))
888 return intType.isSignless();
889 return llvm::isa<BFloat16Type, Float16Type, Float32Type, Float64Type,
890 Float80Type, Float128Type, LLVMByteType, LLVMPointerType>(
891 elementType) ||
892 isCompatiblePtrType(elementType);
893 }
894 return false;
895}
896
897llvm::ElementCount mlir::LLVM::getVectorNumElements(Type type) {
898 auto vecTy = dyn_cast<VectorType>(type);
899 assert(vecTy && "incompatible with LLVM vector type");
900 if (vecTy.isScalable())
901 return llvm::ElementCount::getScalable(vecTy.getNumElements());
902 return llvm::ElementCount::getFixed(vecTy.getNumElements());
903}
904
906 assert(llvm::isa<VectorType>(vectorType) &&
907 "expected LLVM-compatible vector type");
908 return llvm::cast<VectorType>(vectorType).isScalable();
909}
910
911Type mlir::LLVM::getVectorType(Type elementType, unsigned numElements,
912 bool isScalable) {
913 assert(VectorType::isValidElementType(elementType) &&
914 "incompatible element type");
915 return VectorType::get(numElements, elementType, {isScalable});
916}
917
919 const llvm::ElementCount &numElements) {
920 if (numElements.isScalable())
921 return getVectorType(elementType, numElements.getKnownMinValue(),
922 /*isScalable=*/true);
923 return getVectorType(elementType, numElements.getFixedValue(),
924 /*isScalable=*/false);
925}
926
928 assert(isCompatibleType(type) &&
929 "expected a type compatible with the LLVM dialect");
930
932 .Case<BFloat16Type, Float16Type>(
933 [](Type) { return llvm::TypeSize::getFixed(16); })
934 .Case<Float32Type>([](Type) { return llvm::TypeSize::getFixed(32); })
935 .Case<Float64Type>([](Type) { return llvm::TypeSize::getFixed(64); })
936 .Case<Float80Type>([](Type) { return llvm::TypeSize::getFixed(80); })
937 .Case<Float128Type>([](Type) { return llvm::TypeSize::getFixed(128); })
938 .Case([](IntegerType intTy) {
939 return llvm::TypeSize::getFixed(intTy.getWidth());
940 })
941 .Case([](LLVMByteType byteTy) {
942 return llvm::TypeSize::getFixed(byteTy.getBitWidth());
943 })
944 .Case<LLVMPPCFP128Type>(
945 [](Type) { return llvm::TypeSize::getFixed(128); })
946 .Case([](VectorType t) {
947 assert(isCompatibleVectorType(t) &&
948 "unexpected incompatible with LLVM vector type");
949 llvm::TypeSize elementSize =
950 getPrimitiveTypeSizeInBits(t.getElementType());
951 return llvm::TypeSize(elementSize.getFixedValue() * t.getNumElements(),
952 elementSize.isScalable());
953 })
954 .Default([](Type ty) {
955 assert(
956 (llvm::isa<LLVMVoidType, LLVMLabelType, LLVMMetadataType, TokenType,
957 LLVMStructType, LLVMArrayType, LLVMPointerType,
958 LLVMFunctionType, LLVMTargetExtType>(ty)) &&
959 "unexpected missing support for primitive type");
960 return llvm::TypeSize::getFixed(0);
961 });
962}
963
964//===----------------------------------------------------------------------===//
965// LLVMDialect
966//===----------------------------------------------------------------------===//
967
968void LLVMDialect::registerTypes() {
969 addTypes<
970#define GET_TYPEDEF_LIST
971#include "mlir/Dialect/LLVMIR/LLVMTypes.cpp.inc"
972
973 >();
974}
975
976Type LLVMDialect::parseType(DialectAsmParser &parser) const {
977 return detail::parseType(parser);
978}
979
980void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const {
981 return detail::printType(type, os);
982}
return success()
static unsigned getBitWidth(Type type)
Definition Pattern.cpp:407
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
constexpr static const uint64_t kDefaultPointerAlignment
static void printExtTypeParams(AsmPrinter &p, ArrayRef< Type > typeParams, ArrayRef< unsigned int > intParams)
constexpr static const uint64_t kDefaultPointerSizeBits
static void printFunctionTypes(AsmPrinter &p, ArrayRef< Type > params, bool isVarArg)
Definition LLVMTypes.cpp:66
static bool isCompatibleImpl(Type type, DenseSet< Type > &compatibleTypes)
static ParseResult parseExtTypeParams(AsmParser &p, SmallVectorImpl< Type > &typeParams, SmallVectorImpl< unsigned int > &intParams)
Parses the parameter list for a target extension type.
Definition LLVMTypes.cpp:90
static constexpr llvm::StringRef kSpirvPrefix
static std::optional< uint64_t > getPointerDataLayoutEntry(DataLayoutEntryListRef params, LLVMPointerType type, PtrDLEntryPos pos)
Returns the part of the data layout entry that corresponds to pos for the given type by interpreting ...
static bool isCompatiblePtrType(Type type)
Check whether type is a compatible ptr type.
static OptionalParseResult generatedTypeParser(AsmParser &parser, StringRef *mnemonic, Type &value)
These are unused for now.
static ParseResult parseFunctionTypes(AsmParser &p, SmallVector< Type > &params, bool &isVarArg)
Definition LLVMTypes.cpp:36
constexpr static const uint64_t kBitsInByte
Definition LLVMTypes.cpp:30
static constexpr llvm::StringRef kArmSVCount
static constexpr llvm::StringRef kAMDGCNNamedBarrier
static LogicalResult generatedTypePrinter(Type def, AsmPrinter &printer)
static std::optional< uint64_t > getStructDataLayoutEntry(DataLayoutEntryListRef params, LLVMStructType type, StructDLEntryPos pos)
static uint64_t extractStructSpecValue(Attribute attr, StructDLEntryPos pos)
static uint64_t calculateStructAlignment(const DataLayout &dataLayout, DataLayoutEntryListRef params, LLVMStructType type, StructDLEntryPos pos)
b getContext())
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
Definition SPIRVOps.cpp:229
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual OptionalParseResult parseOptionalInteger(APInt &result)=0
Parse an optional integer value from the stream.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseOptionalRParen()=0
Parse a ) token if present.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseOptionalEllipsis()=0
Parse a ... token if present;.
This base class exposes generic asm printer hooks, usable across the various derived printers.
Attributes are known-constant values of operations.
Definition Attributes.h:25
The main mechanism for performing data layout queries.
std::optional< uint64_t > getTypeIndexBitwidth(Type t) const
Returns the bitwidth that should be used when performing index computations for the given pointer-lik...
llvm::TypeSize getTypeSize(Type t) const
Returns the size of the given type in the current scope.
uint64_t getTypePreferredAlignment(Type t) const
Returns the preferred of the given type in the current scope.
uint64_t getTypeABIAlignment(Type t) const
Returns the required alignment of the given type in the current scope.
llvm::TypeSize getTypeSizeInBits(Type t) const
Returns the size in bits of the given type in the current scope.
The DialectAsmParser has methods for interacting with the asm parser when parsing attributes and type...
This class represents a diagnostic that is inflight and set to be reported.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
This class implements Optional functionality for ParseResult.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition Types.cpp:35
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
Type parseType(DialectAsmParser &parser)
Parses an LLVM dialect type.
Type getVectorType(Type elementType, unsigned numElements, bool isScalable=false)
Creates an LLVM dialect-compatible vector type with the given element type and length.
llvm::TypeSize getPrimitiveTypeSizeInBits(Type type)
Returns the size of the given primitive LLVM dialect-compatible type (including vectors) in bits,...
void printPrettyLLVMType(AsmPrinter &p, Type type)
Print any MLIR type or a concise syntax for LLVM types.
bool isLoadableType(Type type)
Returns true if the given type is a loadable type compatible with the LLVM dialect.
bool isScalableVectorType(Type vectorType)
Returns whether a vector type is scalable or not.
ParseResult parsePrettyLLVMType(AsmParser &p, Type &type)
Parse any MLIR type or a concise syntax for LLVM types.
bool isCompatibleVectorType(Type type)
Returns true if the given type is a vector type compatible with the LLVM dialect.
bool isCompatibleOuterType(Type type)
Returns true if the given outer type is compatible with the LLVM dialect without checking its potenti...
PtrDLEntryPos
The positions of different values in the data layout entry for pointers.
Definition LLVMTypes.h:145
std::optional< uint64_t > extractPointerSpecValue(Attribute attr, PtrDLEntryPos pos)
Returns the value that corresponds to named position pos from the data layout entry attr assuming it'...
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
bool isCompatibleFloatingPointType(Type type)
Returns true if the given type is a floating-point type compatible with the LLVM dialect.
llvm::ElementCount getVectorNumElements(Type type)
Returns the element count of any LLVM-compatible vector type.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:732
Include the generated interface declarations.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
Definition LLVM.h:122
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
::llvm::MapVector<::mlir::StringAttr, ::mlir::DataLayoutEntryInterface > DataLayoutIdentifiedEntryMap
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
llvm::ArrayRef< DataLayoutEntryInterface > DataLayoutEntryListRef
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147