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