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 getTypeSize(dataLayout, params) * kBitsInByte;
185}
186
187llvm::TypeSize LLVMArrayType::getTypeSize(const DataLayout &dataLayout,
188 DataLayoutEntryListRef params) const {
189 return dataLayout.getTypeAllocSize(getElementType()) * getNumElements();
190}
191
192uint64_t LLVMArrayType::getABIAlignment(const DataLayout &dataLayout,
193 DataLayoutEntryListRef params) const {
194 return dataLayout.getTypeABIAlignment(getElementType());
195}
196
197uint64_t
198LLVMArrayType::getPreferredAlignment(const DataLayout &dataLayout,
199 DataLayoutEntryListRef params) const {
200 return dataLayout.getTypePreferredAlignment(getElementType());
201}
202
203//===----------------------------------------------------------------------===//
204// LLVMByteType
205//===----------------------------------------------------------------------===//
206
207llvm::TypeSize
208LLVMByteType::getTypeSizeInBits(const DataLayout &dataLayout,
209 DataLayoutEntryListRef params) const {
210 return llvm::TypeSize::getFixed(getBitWidth());
211}
212
213uint64_t LLVMByteType::getABIAlignment(const DataLayout &dataLayout,
214 DataLayoutEntryListRef params) const {
215 return llvm::PowerOf2Ceil(llvm::divideCeil(getBitWidth(), kBitsInByte));
216}
217
218LogicalResult LLVMByteType::verify(function_ref<InFlightDiagnostic()> emitError,
219 unsigned bitWidth) {
220 if (bitWidth == 0)
221 return emitError() << "bitwidth must be greater than 0";
222
223 // Mirror LLVM IR, which limits the bit width to fit in 23 bits.
224 constexpr unsigned kMaxBitWidth = 1 << 23;
225 if (bitWidth >= kMaxBitWidth)
226 return emitError() << "bitwidth must be less than " << kMaxBitWidth
227 << ", but got " << bitWidth;
228 return success();
229}
230
231//===----------------------------------------------------------------------===//
232// Function type.
233//===----------------------------------------------------------------------===//
234
235bool LLVMFunctionType::isValidArgumentType(Type type) {
236 if (auto structType = dyn_cast<LLVMStructType>(type))
237 return !structType.isOpaque();
238
239 return !llvm::isa<LLVMVoidType, LLVMFunctionType>(type);
240}
241
242bool LLVMFunctionType::isValidResultType(Type type) {
243 return !llvm::isa<LLVMFunctionType, LLVMMetadataType, LLVMLabelType>(type);
244}
245
246LLVMFunctionType LLVMFunctionType::get(Type result, ArrayRef<Type> arguments,
247 bool isVarArg) {
248 assert(result && "expected non-null result");
249 return Base::get(result.getContext(), result, arguments, isVarArg);
250}
251
252LLVMFunctionType
253LLVMFunctionType::getChecked(function_ref<InFlightDiagnostic()> emitError,
254 Type result, ArrayRef<Type> arguments,
255 bool isVarArg) {
256 assert(result && "expected non-null result");
257 return Base::getChecked(emitError, result.getContext(), result, arguments,
258 isVarArg);
259}
260
261LLVMFunctionType LLVMFunctionType::clone(TypeRange inputs,
262 TypeRange results) const {
263 // LLVM functions have exactly one return type. An empty results range
264 // corresponds to a void return type (as FunctionOpInterface represents void
265 // functions with 0 results). More than one result is not valid.
266 if (results.size() > 1)
267 return {};
268 Type resultType =
269 results.empty() ? LLVMVoidType::get(getContext()) : results[0];
270 if (!isValidResultType(resultType))
271 return {};
272 if (!llvm::all_of(inputs, isValidArgumentType))
273 return {};
274 return get(resultType, llvm::to_vector(inputs), isVarArg());
275}
276
277ArrayRef<Type> LLVMFunctionType::getReturnTypes() const {
278 return static_cast<detail::LLVMFunctionTypeStorage *>(getImpl())->returnType;
279}
280
281LogicalResult
282LLVMFunctionType::verify(function_ref<InFlightDiagnostic()> emitError,
283 Type result, ArrayRef<Type> arguments, bool) {
284 if (!isValidResultType(result))
285 return emitError() << "invalid function result type: " << result;
286
287 for (Type arg : arguments)
288 if (!isValidArgumentType(arg))
289 return emitError() << "invalid function argument type: " << arg;
290
291 return success();
292}
293
294//===----------------------------------------------------------------------===//
295// DataLayoutTypeInterface
296//===----------------------------------------------------------------------===//
297
298constexpr const static uint64_t kDefaultPointerSizeBits = 64;
299constexpr const static uint64_t kDefaultPointerAlignment = 8;
300
302 PtrDLEntryPos pos) {
303 auto spec = cast<DenseIntElementsAttr>(attr);
304 auto idx = static_cast<int64_t>(pos);
305 if (idx >= spec.size())
306 return std::nullopt;
307 return spec.getValues<uint64_t>()[idx];
308}
309
310/// Returns the part of the data layout entry that corresponds to `pos` for the
311/// given `type` by interpreting the list of entries `params`. For the pointer
312/// type in the default address space, returns the default value if the entries
313/// do not provide a custom one, for other address spaces returns std::nullopt.
314static std::optional<uint64_t>
316 PtrDLEntryPos pos) {
317 // First, look for the entry for the pointer in the current address space.
318 Attribute currentEntry;
319 for (DataLayoutEntryInterface entry : params) {
320 if (!entry.isTypeEntry())
321 continue;
322 if (cast<LLVMPointerType>(cast<Type>(entry.getKey())).getAddressSpace() ==
323 type.getAddressSpace()) {
324 currentEntry = entry.getValue();
325 break;
326 }
327 }
328 if (currentEntry) {
329 std::optional<uint64_t> value = extractPointerSpecValue(currentEntry, pos);
330 // If the optional `PtrDLEntryPos::Index` entry is not available, use the
331 // pointer size as the index bitwidth.
332 if (!value && pos == PtrDLEntryPos::Index)
333 value = extractPointerSpecValue(currentEntry, PtrDLEntryPos::Size);
334 bool isSizeOrIndex =
336 return *value / (isSizeOrIndex ? 1 : kBitsInByte);
337 }
338
339 // If not found, and this is the pointer to the default memory space, assume
340 // 64-bit pointers.
341 if (type.getAddressSpace() == 0) {
342 bool isSizeOrIndex =
344 return isSizeOrIndex ? kDefaultPointerSizeBits : kDefaultPointerAlignment;
345 }
346
347 return std::nullopt;
348}
349
350llvm::TypeSize
351LLVMPointerType::getTypeSizeInBits(const DataLayout &dataLayout,
352 DataLayoutEntryListRef params) const {
353 if (std::optional<uint64_t> size =
355 return llvm::TypeSize::getFixed(*size);
356
357 // For other memory spaces, use the size of the pointer to the default memory
358 // space.
359 return dataLayout.getTypeSizeInBits(get(getContext()));
360}
361
362uint64_t LLVMPointerType::getABIAlignment(const DataLayout &dataLayout,
363 DataLayoutEntryListRef params) const {
364 if (std::optional<uint64_t> alignment =
366 return *alignment;
367
368 return dataLayout.getTypeABIAlignment(get(getContext()));
369}
370
371uint64_t
372LLVMPointerType::getPreferredAlignment(const DataLayout &dataLayout,
373 DataLayoutEntryListRef params) const {
374 if (std::optional<uint64_t> alignment =
376 return *alignment;
377
378 return dataLayout.getTypePreferredAlignment(get(getContext()));
379}
380
381std::optional<uint64_t>
382LLVMPointerType::getIndexBitwidth(const DataLayout &dataLayout,
383 DataLayoutEntryListRef params) const {
384 if (std::optional<uint64_t> indexBitwidth =
386 return *indexBitwidth;
387
388 return dataLayout.getTypeIndexBitwidth(get(getContext()));
389}
390
391bool LLVMPointerType::areCompatible(
393 DataLayoutSpecInterface newSpec,
394 const DataLayoutIdentifiedEntryMap &map) const {
395 for (DataLayoutEntryInterface newEntry : newLayout) {
396 if (!newEntry.isTypeEntry())
397 continue;
398 uint64_t size = kDefaultPointerSizeBits;
399 uint64_t abi = kDefaultPointerAlignment;
400 auto newType =
401 llvm::cast<LLVMPointerType>(llvm::cast<Type>(newEntry.getKey()));
402 const auto *it =
403 llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
404 if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
405 return llvm::cast<LLVMPointerType>(type).getAddressSpace() ==
406 newType.getAddressSpace();
407 }
408 return false;
409 });
410 if (it == oldLayout.end()) {
411 llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
412 if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
413 return llvm::cast<LLVMPointerType>(type).getAddressSpace() == 0;
414 }
415 return false;
416 });
417 }
418 if (it != oldLayout.end()) {
419 size = *extractPointerSpecValue(it->getValue(), PtrDLEntryPos::Size);
420 abi = *extractPointerSpecValue(it->getValue(), PtrDLEntryPos::Abi);
421 }
422
423 Attribute newSpec = llvm::cast<DenseIntElementsAttr>(newEntry.getValue());
424 uint64_t newSize = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Size);
425 uint64_t newAbi = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Abi);
426 if (size != newSize || abi < newAbi || abi % newAbi != 0)
427 return false;
428 }
429 return true;
430}
431
432LogicalResult LLVMPointerType::verifyEntries(DataLayoutEntryListRef entries,
433 Location loc) const {
434 for (DataLayoutEntryInterface entry : entries) {
435 if (!entry.isTypeEntry())
436 continue;
437 auto key = llvm::cast<Type>(entry.getKey());
438 auto values = llvm::dyn_cast<DenseIntElementsAttr>(entry.getValue());
439 if (!values || (values.size() != 3 && values.size() != 4)) {
440 return emitError(loc)
441 << "expected layout attribute for " << key
442 << " to be a dense integer elements attribute with 3 or 4 "
443 "elements";
444 }
445 if (!values.getElementType().isInteger(64))
446 return emitError(loc) << "expected i64 parameters for " << key;
447
450 return emitError(loc) << "preferred alignment is expected to be at least "
451 "as large as ABI alignment";
452 }
453 }
454 return success();
455}
456
457//===----------------------------------------------------------------------===//
458// Struct type.
459//===----------------------------------------------------------------------===//
460
461bool LLVMStructType::isValidElementType(Type type) {
462 return !llvm::isa<LLVMVoidType, LLVMLabelType, LLVMMetadataType,
463 LLVMFunctionType, TokenType>(type);
464}
465
466LLVMStructType LLVMStructType::getIdentified(MLIRContext *context,
467 StringRef name) {
468 return Base::get(context, name, /*opaque=*/false);
469}
470
471LLVMStructType LLVMStructType::getIdentifiedChecked(
472 function_ref<InFlightDiagnostic()> emitError, MLIRContext *context,
473 StringRef name) {
474 return Base::getChecked(emitError, context, name, /*opaque=*/false);
475}
476
477LLVMStructType LLVMStructType::getNewIdentified(MLIRContext *context,
478 StringRef name,
479 ArrayRef<Type> elements,
480 bool isPacked) {
481 std::string stringName = name.str();
482 unsigned counter = 0;
483 do {
484 auto type = LLVMStructType::getIdentified(context, stringName);
485 if (type.isInitialized() || failed(type.setBody(elements, isPacked))) {
486 counter += 1;
487 stringName = (Twine(name) + "." + std::to_string(counter)).str();
488 continue;
489 }
490 return type;
491 } while (true);
492}
493
494LLVMStructType LLVMStructType::getLiteral(MLIRContext *context,
495 ArrayRef<Type> types, bool isPacked) {
496 return Base::get(context, types, isPacked);
497}
498
499LLVMStructType
500LLVMStructType::getLiteralChecked(function_ref<InFlightDiagnostic()> emitError,
501 MLIRContext *context, ArrayRef<Type> types,
502 bool isPacked) {
503 return Base::getChecked(emitError, context, types, isPacked);
504}
505
506LLVMStructType LLVMStructType::getOpaque(StringRef name, MLIRContext *context) {
507 return Base::get(context, name, /*opaque=*/true);
508}
509
510LLVMStructType
511LLVMStructType::getOpaqueChecked(function_ref<InFlightDiagnostic()> emitError,
512 MLIRContext *context, StringRef name) {
513 return Base::getChecked(emitError, context, name, /*opaque=*/true);
514}
515
516LogicalResult LLVMStructType::setBody(ArrayRef<Type> types, bool isPacked) {
517 assert(isIdentified() && "can only set bodies of identified structs");
518 assert(llvm::all_of(types, LLVMStructType::isValidElementType) &&
519 "expected valid body types");
520 return Base::mutate(types, isPacked);
521}
522
523bool LLVMStructType::isPacked() const { return getImpl()->isPacked(); }
524bool LLVMStructType::isIdentified() const { return getImpl()->isIdentified(); }
525bool LLVMStructType::isOpaque() const {
526 return getImpl()->isIdentified() &&
527 (getImpl()->isOpaque() || !getImpl()->isInitialized());
528}
529bool LLVMStructType::isInitialized() { return getImpl()->isInitialized(); }
530StringRef LLVMStructType::getName() const { return getImpl()->getIdentifier(); }
531ArrayRef<Type> LLVMStructType::getBody() const {
532 return isIdentified() ? getImpl()->getIdentifiedStructBody()
533 : getImpl()->getTypeList();
534}
535
536LogicalResult
537LLVMStructType::verifyInvariants(function_ref<InFlightDiagnostic()>, StringRef,
538 bool) {
539 return success();
540}
541
542LogicalResult
543LLVMStructType::verifyInvariants(function_ref<InFlightDiagnostic()> emitError,
544 ArrayRef<Type> types, bool) {
545 for (Type t : types)
546 if (!isValidElementType(t))
547 return emitError() << "invalid LLVM structure element type: " << t;
548
549 return success();
550}
551
552/// Returns the byte offset of the element of the specified structure at the
553/// given index and the strictest alignment requirement of the elements up to
554/// the index. For the index past the last element it thus returns the size and
555/// alignment of the whole structure.
556static uint64_t getOffsetAndAlignment(const DataLayout &dataLayout,
557 LLVMStructType structType, unsigned index,
558 uint64_t &structAlignment) {
559 uint64_t offset = 0;
560 structAlignment = 1;
561 for (auto [i, element] : llvm::enumerate(structType.getBody())) {
562 // Align the element unless the structure is packed.
563 uint64_t elementAlignment = dataLayout.getTypeABIAlignment(element);
564 if (!structType.isPacked()) {
565 offset = llvm::alignTo(offset, elementAlignment);
566
567 // The structure alignment is the strictest alignment of its
568 // elements.
569 structAlignment = std::max(structAlignment, elementAlignment);
570 }
571 if (i == index)
572 return offset;
573
574 // Each element gets its allocation size, even in packed structures.
575 offset += dataLayout.getTypeAllocSize(element);
576 }
577 return offset;
578}
579
580uint64_t LLVMStructType::getElementOffset(const DataLayout &dataLayout,
581 unsigned index) const {
582 assert(index < getBody().size() && "expected a valid struct element index");
583 uint64_t structAlignment;
584 return getOffsetAndAlignment(dataLayout, *this, index, structAlignment);
585}
586
587llvm::TypeSize
588LLVMStructType::getTypeSizeInBits(const DataLayout &dataLayout,
589 DataLayoutEntryListRef params) const {
590 uint64_t structAlignment;
591 uint64_t structSize = getOffsetAndAlignment(
592 dataLayout, *this, getBody().size(), structAlignment);
593 // At the end, add padding to the struct to satisfy its own alignment
594 // requirement. Otherwise structs inside of arrays would be misaligned.
595 structSize = llvm::alignTo(structSize, structAlignment);
596 return llvm::TypeSize::getFixed(structSize * kBitsInByte);
597}
598
599namespace {
600enum class StructDLEntryPos { Abi = 0, Preferred = 1 };
601} // namespace
602
603static std::optional<uint64_t>
605 StructDLEntryPos pos) {
606 const auto *currentEntry =
607 llvm::find_if(params, [](DataLayoutEntryInterface entry) {
608 return entry.isTypeEntry();
609 });
610 if (currentEntry == params.end())
611 return std::nullopt;
612
613 auto attr = llvm::cast<DenseIntElementsAttr>(currentEntry->getValue());
614 if (pos == StructDLEntryPos::Preferred &&
615 attr.size() <= static_cast<int64_t>(StructDLEntryPos::Preferred))
616 // If no preferred was specified, fall back to abi alignment
617 pos = StructDLEntryPos::Abi;
618
619 return attr.getValues<uint64_t>()[static_cast<size_t>(pos)];
620}
621
622static uint64_t calculateStructAlignment(const DataLayout &dataLayout,
624 LLVMStructType type,
625 StructDLEntryPos pos) {
626 // Packed structs always have an abi alignment of 1
627 if (pos == StructDLEntryPos::Abi && type.isPacked()) {
628 return 1;
629 }
630
631 // The alignment requirement of a struct is equal to the strictest alignment
632 // requirement of its elements.
633 uint64_t structAlignment = 1;
634 for (Type iter : type.getBody()) {
635 structAlignment =
636 std::max(dataLayout.getTypeABIAlignment(iter), structAlignment);
637 }
638
639 // Entries are only allowed to be stricter than the required alignment
640 if (std::optional<uint64_t> entryResult =
641 getStructDataLayoutEntry(params, type, pos))
642 return std::max(*entryResult / kBitsInByte, structAlignment);
643
644 return structAlignment;
645}
646
647uint64_t LLVMStructType::getABIAlignment(const DataLayout &dataLayout,
648 DataLayoutEntryListRef params) const {
649 return calculateStructAlignment(dataLayout, params, *this,
650 StructDLEntryPos::Abi);
651}
652
653uint64_t
654LLVMStructType::getPreferredAlignment(const DataLayout &dataLayout,
655 DataLayoutEntryListRef params) const {
656 return calculateStructAlignment(dataLayout, params, *this,
657 StructDLEntryPos::Preferred);
658}
659
660static uint64_t extractStructSpecValue(Attribute attr, StructDLEntryPos pos) {
661 return llvm::cast<DenseIntElementsAttr>(attr)
662 .getValues<uint64_t>()[static_cast<size_t>(pos)];
663}
664
665bool LLVMStructType::areCompatible(
667 DataLayoutSpecInterface newSpec,
668 const DataLayoutIdentifiedEntryMap &map) const {
669 for (DataLayoutEntryInterface newEntry : newLayout) {
670 if (!newEntry.isTypeEntry())
671 continue;
672
673 const auto *previousEntry =
674 llvm::find_if(oldLayout, [](DataLayoutEntryInterface entry) {
675 return entry.isTypeEntry();
676 });
677 if (previousEntry == oldLayout.end())
678 continue;
679
680 uint64_t abi = extractStructSpecValue(previousEntry->getValue(),
681 StructDLEntryPos::Abi);
682 uint64_t newAbi =
683 extractStructSpecValue(newEntry.getValue(), StructDLEntryPos::Abi);
684 if (abi < newAbi || abi % newAbi != 0)
685 return false;
686 }
687 return true;
688}
689
690LogicalResult LLVMStructType::verifyEntries(DataLayoutEntryListRef entries,
691 Location loc) const {
692 for (DataLayoutEntryInterface entry : entries) {
693 if (!entry.isTypeEntry())
694 continue;
695
696 auto key = llvm::cast<LLVMStructType>(llvm::cast<Type>(entry.getKey()));
697 auto values = llvm::dyn_cast<DenseIntElementsAttr>(entry.getValue());
698 if (!values || (values.size() != 2 && values.size() != 1)) {
699 return emitError(loc)
700 << "expected layout attribute for "
701 << llvm::cast<Type>(entry.getKey())
702 << " to be a dense integer elements attribute of 1 or 2 elements";
703 }
704 if (!values.getElementType().isInteger(64))
705 return emitError(loc) << "expected i64 entries for " << key;
706
707 if (key.isIdentified() || !key.getBody().empty()) {
708 return emitError(loc) << "unexpected layout attribute for struct " << key;
709 }
710
711 if (values.size() == 1)
712 continue;
713
714 if (extractStructSpecValue(values, StructDLEntryPos::Abi) >
715 extractStructSpecValue(values, StructDLEntryPos::Preferred)) {
716 return emitError(loc) << "preferred alignment is expected to be at least "
717 "as large as ABI alignment";
718 }
719 }
720 return mlir::success();
721}
722
723//===----------------------------------------------------------------------===//
724// LLVMTargetExtType.
725//===----------------------------------------------------------------------===//
726
727static constexpr llvm::StringRef kSpirvPrefix = "spirv.";
728static constexpr llvm::StringRef kArmSVCount = "aarch64.svcount";
729static constexpr llvm::StringRef kAMDGCNNamedBarrier = "amdgcn.named.barrier";
730
731bool LLVM::LLVMTargetExtType::hasProperty(Property prop) const {
732 // See llvm/lib/IR/Type.cpp for reference.
733 uint64_t properties = 0;
734
735 if (getExtTypeName().starts_with(kSpirvPrefix))
736 properties |=
737 (LLVMTargetExtType::HasZeroInit | LLVM::LLVMTargetExtType::CanBeGlobal);
738
739 if (getExtTypeName() == kAMDGCNNamedBarrier)
740 properties |= LLVMTargetExtType::CanBeGlobal;
741
742 return (properties & prop) == prop;
743}
744
745bool LLVM::LLVMTargetExtType::supportsMemOps() const {
746 // See llvm/lib/IR/Type.cpp for reference.
747 if (getExtTypeName().starts_with(kSpirvPrefix))
748 return true;
749
750 if (getExtTypeName() == kArmSVCount)
751 return true;
752
753 return false;
754}
755
756//===----------------------------------------------------------------------===//
757// LLVMPPCFP128Type
758//===----------------------------------------------------------------------===//
759
760const llvm::fltSemantics &LLVMPPCFP128Type::getFloatSemantics() const {
761 return APFloat::PPCDoubleDouble();
762}
763
764//===----------------------------------------------------------------------===//
765// Utility functions.
766//===----------------------------------------------------------------------===//
767
768/// Check whether type is a compatible ptr type. These are pointer-like types
769/// with no element type, no metadata, and using the LLVM
770/// LLVMAddrSpaceAttrInterface memory space.
771static bool isCompatiblePtrType(Type type) {
772 auto ptrTy = dyn_cast<PtrLikeTypeInterface>(type);
773 if (!ptrTy)
774 return false;
775 return !ptrTy.hasPtrMetadata() && ptrTy.getElementType() == nullptr &&
776 isa<LLVMAddrSpaceAttrInterface>(ptrTy.getMemorySpace());
777}
778
780 // clang-format off
781 if (llvm::isa<
782 BFloat16Type,
783 Float16Type,
784 Float32Type,
785 Float64Type,
786 Float80Type,
787 Float128Type,
788 LLVMArrayType,
789 LLVMByteType,
790 LLVMFunctionType,
791 LLVMLabelType,
792 LLVMMetadataType,
793 LLVMPPCFP128Type,
794 LLVMPointerType,
795 LLVMStructType,
796 LLVMTargetExtType,
797 LLVMVoidType,
798 LLVMX86AMXType,
799 TokenType
800 >(type)) {
801 // clang-format on
802 return true;
803 }
804
805 // Only signless integers are compatible.
806 if (auto intType = llvm::dyn_cast<IntegerType>(type))
807 return intType.isSignless();
808
809 // 1D vector types are compatible.
810 if (auto vecType = llvm::dyn_cast<VectorType>(type))
811 return vecType.getRank() == 1;
812
813 return isCompatiblePtrType(type);
814}
815
816static bool isCompatibleImpl(Type type, DenseSet<Type> &compatibleTypes) {
817 if (!compatibleTypes.insert(type).second)
818 return true;
819
820 auto isCompatible = [&](Type type) {
821 return isCompatibleImpl(type, compatibleTypes);
822 };
823
824 bool result =
826 .Case([&](LLVMStructType structType) {
827 return llvm::all_of(structType.getBody(), isCompatible);
828 })
829 .Case([&](LLVMFunctionType funcType) {
830 return isCompatible(funcType.getReturnType()) &&
831 llvm::all_of(funcType.getParams(), isCompatible);
832 })
833 .Case([](IntegerType intType) { return intType.isSignless(); })
834 .Case([&](VectorType vecType) {
835 return vecType.getRank() == 1 &&
836 isCompatible(vecType.getElementType());
837 })
838 .Case([&](LLVMPointerType pointerType) { return true; })
839 .Case([&](LLVMTargetExtType extType) {
840 return llvm::all_of(extType.getTypeParams(), isCompatible);
841 })
842 // clang-format off
843 .Case([&](LLVMArrayType containerType) {
844 return isCompatible(containerType.getElementType());
845 })
846 .Case<
847 BFloat16Type,
848 Float16Type,
849 Float32Type,
850 Float64Type,
851 Float80Type,
852 Float128Type,
853 LLVMByteType,
854 LLVMLabelType,
855 LLVMMetadataType,
856 LLVMPPCFP128Type,
857 LLVMVoidType,
858 LLVMX86AMXType,
859 TokenType
860 >([](Type) { return true; })
861 // clang-format on
862 .Case<PtrLikeTypeInterface>(
863 [](Type type) { return isCompatiblePtrType(type); })
864 .Default(false);
865
866 if (!result)
867 compatibleTypes.erase(type);
868
869 return result;
870}
871
872bool LLVMDialect::isCompatibleType(Type type) {
873 if (auto *llvmDialect =
874 type.getContext()->getLoadedDialect<LLVM::LLVMDialect>())
875 return isCompatibleImpl(type, llvmDialect->compatibleTypes.get());
876
877 DenseSet<Type> localCompatibleTypes;
878 return isCompatibleImpl(type, localCompatibleTypes);
879}
880
882 return LLVMDialect::isCompatibleType(type);
883}
884
886 return /*LLVM_PrimitiveType*/ (
888 !isa<LLVM::LLVMVoidType, LLVM::LLVMFunctionType>(type)) &&
889 /*LLVM_OpaqueStruct*/
890 !(isa<LLVM::LLVMStructType>(type) &&
891 cast<LLVM::LLVMStructType>(type).isOpaque()) &&
892 /*LLVM_AnyTargetExt*/
893 !(isa<LLVM::LLVMTargetExtType>(type) &&
894 !cast<LLVM::LLVMTargetExtType>(type).supportsMemOps());
895}
896
898 return llvm::isa<BFloat16Type, Float16Type, Float32Type, Float64Type,
899 Float80Type, Float128Type, LLVMPPCFP128Type>(type);
900}
901
903 if (auto vecType = llvm::dyn_cast<VectorType>(type)) {
904 if (vecType.getRank() != 1)
905 return false;
906 Type elementType = vecType.getElementType();
907 if (auto intType = llvm::dyn_cast<IntegerType>(elementType))
908 return intType.isSignless();
909 return llvm::isa<BFloat16Type, Float16Type, Float32Type, Float64Type,
910 Float80Type, Float128Type, LLVMByteType, LLVMPointerType>(
911 elementType) ||
912 isCompatiblePtrType(elementType);
913 }
914 return false;
915}
916
917llvm::ElementCount mlir::LLVM::getVectorNumElements(Type type) {
918 auto vecTy = dyn_cast<VectorType>(type);
919 assert(vecTy && "incompatible with LLVM vector type");
920 if (vecTy.isScalable())
921 return llvm::ElementCount::getScalable(vecTy.getNumElements());
922 return llvm::ElementCount::getFixed(vecTy.getNumElements());
923}
924
926 assert(llvm::isa<VectorType>(vectorType) &&
927 "expected LLVM-compatible vector type");
928 return llvm::cast<VectorType>(vectorType).isScalable();
929}
930
931Type mlir::LLVM::getVectorType(Type elementType, unsigned numElements,
932 bool isScalable) {
933 assert(VectorType::isValidElementType(elementType) &&
934 "incompatible element type");
935 return VectorType::get(numElements, elementType, {isScalable});
936}
937
939 const llvm::ElementCount &numElements) {
940 if (numElements.isScalable())
941 return getVectorType(elementType, numElements.getKnownMinValue(),
942 /*isScalable=*/true);
943 return getVectorType(elementType, numElements.getFixedValue(),
944 /*isScalable=*/false);
945}
946
948 assert(isCompatibleType(type) &&
949 "expected a type compatible with the LLVM dialect");
950
952 .Case<BFloat16Type, Float16Type>(
953 [](Type) { return llvm::TypeSize::getFixed(16); })
954 .Case<Float32Type>([](Type) { return llvm::TypeSize::getFixed(32); })
955 .Case<Float64Type>([](Type) { return llvm::TypeSize::getFixed(64); })
956 .Case<Float80Type>([](Type) { return llvm::TypeSize::getFixed(80); })
957 .Case<Float128Type>([](Type) { return llvm::TypeSize::getFixed(128); })
958 .Case([](IntegerType intTy) {
959 return llvm::TypeSize::getFixed(intTy.getWidth());
960 })
961 .Case([](LLVMByteType byteTy) {
962 return llvm::TypeSize::getFixed(byteTy.getBitWidth());
963 })
964 .Case<LLVMPPCFP128Type>(
965 [](Type) { return llvm::TypeSize::getFixed(128); })
966 .Case([](VectorType t) {
967 assert(isCompatibleVectorType(t) &&
968 "unexpected incompatible with LLVM vector type");
969 llvm::TypeSize elementSize =
970 getPrimitiveTypeSizeInBits(t.getElementType());
971 return llvm::TypeSize(elementSize.getFixedValue() * t.getNumElements(),
972 elementSize.isScalable());
973 })
974 .Default([](Type ty) {
975 assert(
976 (llvm::isa<LLVMVoidType, LLVMLabelType, LLVMMetadataType, TokenType,
977 LLVMStructType, LLVMArrayType, LLVMPointerType,
978 LLVMFunctionType, LLVMTargetExtType>(ty)) &&
979 "unexpected missing support for primitive type");
980 return llvm::TypeSize::getFixed(0);
981 });
982}
983
984//===----------------------------------------------------------------------===//
985// LLVMDialect
986//===----------------------------------------------------------------------===//
987
988void LLVMDialect::registerTypes() {
989 addTypes<
990#define GET_TYPEDEF_LIST
991#include "mlir/Dialect/LLVMIR/LLVMTypes.cpp.inc"
992
993 >();
994}
995
996Type LLVMDialect::parseType(DialectAsmParser &parser) const {
997 return detail::parseType(parser);
998}
999
1000void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const {
1001 return detail::printType(type, os);
1002}
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 getOffsetAndAlignment(const DataLayout &dataLayout, LLVMStructType structType, unsigned index, uint64_t &structAlignment)
Returns the byte offset of the element of the specified structure at the given index and the strictes...
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 getTypeAllocSize(Type t) const
Returns the offset in bytes between successive objects 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:144
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:853
Include the generated interface declarations.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
Definition LLVM.h:125
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:155