clang 22.0.0git
CIRTypes.cpp
Go to the documentation of this file.
1//===- CIRTypes.cpp - MLIR CIR Types --------------------------------------===//
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 defines the types in the CIR dialect.
10//
11//===----------------------------------------------------------------------===//
12
14
15#include "mlir/IR/DialectImplementation.h"
20#include "llvm/ADT/TypeSwitch.h"
21
22//===----------------------------------------------------------------------===//
23// CIR Helpers
24//===----------------------------------------------------------------------===//
25bool cir::isSized(mlir::Type ty) {
26 if (auto sizedTy = mlir::dyn_cast<cir::SizedTypeInterface>(ty))
27 return sizedTy.isSized();
29 return false;
30}
31
32//===----------------------------------------------------------------------===//
33// CIR Custom Parser/Printer Signatures
34//===----------------------------------------------------------------------===//
35
36static mlir::ParseResult
37parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
38 bool &isVarArg);
39static void printFuncTypeParams(mlir::AsmPrinter &p,
40 mlir::ArrayRef<mlir::Type> params,
41 bool isVarArg);
42//===----------------------------------------------------------------------===//
43// CIR Custom Parser/Printer Signatures
44//===----------------------------------------------------------------------===//
45
46static mlir::ParseResult
47parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
48 bool &isVarArg);
49
50static void printFuncTypeParams(mlir::AsmPrinter &p,
51 mlir::ArrayRef<mlir::Type> params,
52 bool isVarArg);
53
54//===----------------------------------------------------------------------===//
55// AddressSpace
56//===----------------------------------------------------------------------===//
57
58mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
59 cir::TargetAddressSpaceAttr &attr);
60
61void printTargetAddressSpace(mlir::AsmPrinter &p,
62 cir::TargetAddressSpaceAttr attr);
63
64//===----------------------------------------------------------------------===//
65// Get autogenerated stuff
66//===----------------------------------------------------------------------===//
67
68namespace cir {
69
70#include "clang/CIR/Dialect/IR/CIRTypeConstraints.cpp.inc"
71
72} // namespace cir
73
74#define GET_TYPEDEF_CLASSES
75#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
76
77using namespace mlir;
78using namespace cir;
79
80//===----------------------------------------------------------------------===//
81// General CIR parsing / printing
82//===----------------------------------------------------------------------===//
83
84Type CIRDialect::parseType(DialectAsmParser &parser) const {
85 llvm::SMLoc typeLoc = parser.getCurrentLocation();
86 llvm::StringRef mnemonic;
87 Type genType;
88
89 // Try to parse as a tablegen'd type.
90 OptionalParseResult parseResult =
91 generatedTypeParser(parser, &mnemonic, genType);
92 if (parseResult.has_value())
93 return genType;
94
95 // Type is not tablegen'd: try to parse as a raw C++ type.
96 return StringSwitch<function_ref<Type()>>(mnemonic)
97 .Case("record", [&] { return RecordType::parse(parser); })
98 .Default([&] {
99 parser.emitError(typeLoc) << "unknown CIR type: " << mnemonic;
100 return Type();
101 })();
102}
103
104void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
105 // Try to print as a tablegen'd type.
106 if (generatedTypePrinter(type, os).succeeded())
107 return;
108
109 // TODO(CIR) Attempt to print as a raw C++ type.
110 llvm::report_fatal_error("printer is missing a handler for this type");
111}
112
113//===----------------------------------------------------------------------===//
114// RecordType Definitions
115//===----------------------------------------------------------------------===//
116
117Type RecordType::parse(mlir::AsmParser &parser) {
118 FailureOr<AsmParser::CyclicParseReset> cyclicParseGuard;
119 const llvm::SMLoc loc = parser.getCurrentLocation();
120 const mlir::Location eLoc = parser.getEncodedSourceLoc(loc);
121 bool packed = false;
122 bool padded = false;
123 RecordKind kind;
124 mlir::MLIRContext *context = parser.getContext();
125
126 if (parser.parseLess())
127 return {};
128
129 // TODO(cir): in the future we should probably separate types for different
130 // source language declarations such as cir.record and cir.union
131 if (parser.parseOptionalKeyword("struct").succeeded())
132 kind = RecordKind::Struct;
133 else if (parser.parseOptionalKeyword("union").succeeded())
134 kind = RecordKind::Union;
135 else if (parser.parseOptionalKeyword("class").succeeded())
136 kind = RecordKind::Class;
137 else {
138 parser.emitError(loc, "unknown record type");
139 return {};
140 }
141
142 mlir::StringAttr name;
143 parser.parseOptionalAttribute(name);
144
145 // Is a self reference: ensure referenced type was parsed.
146 if (name && parser.parseOptionalGreater().succeeded()) {
147 RecordType type = getChecked(eLoc, context, name, kind);
148 if (succeeded(parser.tryStartCyclicParse(type))) {
149 parser.emitError(loc, "invalid self-reference within record");
150 return {};
151 }
152 return type;
153 }
154
155 // Is a named record definition: ensure name has not been parsed yet.
156 if (name) {
157 RecordType type = getChecked(eLoc, context, name, kind);
158 cyclicParseGuard = parser.tryStartCyclicParse(type);
159 if (failed(cyclicParseGuard)) {
160 parser.emitError(loc, "record already defined");
161 return {};
162 }
163 }
164
165 if (parser.parseOptionalKeyword("packed").succeeded())
166 packed = true;
167
168 if (parser.parseOptionalKeyword("padded").succeeded())
169 padded = true;
170
171 // Parse record members or lack thereof.
172 bool incomplete = true;
173 llvm::SmallVector<mlir::Type> members;
174 if (parser.parseOptionalKeyword("incomplete").failed()) {
175 incomplete = false;
176 const auto delimiter = AsmParser::Delimiter::Braces;
177 const auto parseElementFn = [&parser, &members]() {
178 return parser.parseType(members.emplace_back());
179 };
180 if (parser.parseCommaSeparatedList(delimiter, parseElementFn).failed())
181 return {};
182 }
183
184 if (parser.parseGreater())
185 return {};
186
187 // Try to create the proper record type.
188 ArrayRef<mlir::Type> membersRef(members); // Needed for template deduction.
189 mlir::Type type = {};
190 if (name && incomplete) { // Identified & incomplete
191 type = getChecked(eLoc, context, name, kind);
192 } else if (!name && !incomplete) { // Anonymous & complete
193 type = getChecked(eLoc, context, membersRef, packed, padded, kind);
194 } else if (!incomplete) { // Identified & complete
195 type = getChecked(eLoc, context, membersRef, name, packed, padded, kind);
196 // If the record has a self-reference, its type already exists in a
197 // incomplete state. In this case, we must complete it.
198 if (mlir::cast<RecordType>(type).isIncomplete())
199 mlir::cast<RecordType>(type).complete(membersRef, packed, padded);
201 } else { // anonymous & incomplete
202 parser.emitError(loc, "anonymous records must be complete");
203 return {};
204 }
205
206 return type;
207}
208
209void RecordType::print(mlir::AsmPrinter &printer) const {
210 FailureOr<AsmPrinter::CyclicPrintReset> cyclicPrintGuard;
211 printer << '<';
212
213 switch (getKind()) {
214 case RecordKind::Struct:
215 printer << "struct ";
216 break;
217 case RecordKind::Union:
218 printer << "union ";
219 break;
220 case RecordKind::Class:
221 printer << "class ";
222 break;
223 }
224
225 if (getName())
226 printer << getName();
227
228 // Current type has already been printed: print as self reference.
229 cyclicPrintGuard = printer.tryStartCyclicPrint(*this);
230 if (failed(cyclicPrintGuard)) {
231 printer << '>';
232 return;
233 }
234
235 // Type not yet printed: continue printing the entire record.
236 printer << ' ';
237
238 if (getPacked())
239 printer << "packed ";
240
241 if (getPadded())
242 printer << "padded ";
243
244 if (isIncomplete()) {
245 printer << "incomplete";
246 } else {
247 printer << "{";
248 llvm::interleaveComma(getMembers(), printer);
249 printer << "}";
250 }
251
252 printer << '>';
253}
254
255mlir::LogicalResult
256RecordType::verify(function_ref<mlir::InFlightDiagnostic()> emitError,
257 llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name,
258 bool incomplete, bool packed, bool padded,
259 RecordType::RecordKind kind) {
260 if (name && name.getValue().empty())
261 return emitError() << "identified records cannot have an empty name";
262 return mlir::success();
263}
264
265::llvm::ArrayRef<mlir::Type> RecordType::getMembers() const {
266 return getImpl()->members;
267}
268
269bool RecordType::isIncomplete() const { return getImpl()->incomplete; }
270
271mlir::StringAttr RecordType::getName() const { return getImpl()->name; }
272
273bool RecordType::getIncomplete() const { return getImpl()->incomplete; }
274
275bool RecordType::getPacked() const { return getImpl()->packed; }
276
277bool RecordType::getPadded() const { return getImpl()->padded; }
278
279cir::RecordType::RecordKind RecordType::getKind() const {
280 return getImpl()->kind;
281}
282
283void RecordType::complete(ArrayRef<Type> members, bool packed, bool padded) {
285 if (mutate(members, packed, padded).failed())
286 llvm_unreachable("failed to complete record");
287}
288
289/// Return the largest member of in the type.
290///
291/// Recurses into union members never returning a union as the largest member.
292Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const {
293 assert(isUnion() && "Only call getLargestMember on unions");
294 llvm::ArrayRef<Type> members = getMembers();
295 // If the union is padded, we need to ignore the last member,
296 // which is the padding.
297 return *std::max_element(
298 members.begin(), getPadded() ? members.end() - 1 : members.end(),
299 [&](Type lhs, Type rhs) {
300 return dataLayout.getTypeABIAlignment(lhs) <
301 dataLayout.getTypeABIAlignment(rhs) ||
302 (dataLayout.getTypeABIAlignment(lhs) ==
303 dataLayout.getTypeABIAlignment(rhs) &&
304 dataLayout.getTypeSize(lhs) < dataLayout.getTypeSize(rhs));
305 });
306}
307
308bool RecordType::isLayoutIdentical(const RecordType &other) {
309 if (getImpl() == other.getImpl())
310 return true;
311
312 if (getPacked() != other.getPacked())
313 return false;
314
315 return getMembers() == other.getMembers();
316}
317
318//===----------------------------------------------------------------------===//
319// Data Layout information for types
320//===----------------------------------------------------------------------===//
321
322llvm::TypeSize
323PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
324 ::mlir::DataLayoutEntryListRef params) const {
325 // FIXME: improve this in face of address spaces
327 return llvm::TypeSize::getFixed(64);
328}
329
331PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
332 ::mlir::DataLayoutEntryListRef params) const {
333 // FIXME: improve this in face of address spaces
335 return 8;
336}
337
338llvm::TypeSize
339RecordType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
340 mlir::DataLayoutEntryListRef params) const {
341 if (isUnion())
342 return dataLayout.getTypeSize(getLargestMember(dataLayout));
343
344 unsigned recordSize = computeStructSize(dataLayout);
345 return llvm::TypeSize::getFixed(recordSize * 8);
346}
347
349RecordType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
350 ::mlir::DataLayoutEntryListRef params) const {
351 if (isUnion())
352 return dataLayout.getTypeABIAlignment(getLargestMember(dataLayout));
353
354 // Packed structures always have an ABI alignment of 1.
355 if (getPacked())
356 return 1;
357 return computeStructAlignment(dataLayout);
358}
359
360unsigned
361RecordType::computeStructSize(const mlir::DataLayout &dataLayout) const {
362 assert(isComplete() && "Cannot get layout of incomplete records");
363
364 // This is a similar algorithm to LLVM's StructLayout.
365 unsigned recordSize = 0;
366 uint64_t recordAlignment = 1;
367
368 for (mlir::Type ty : getMembers()) {
369 // This assumes that we're calculating size based on the ABI alignment, not
370 // the preferred alignment for each type.
371 const uint64_t tyAlign =
372 (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
373
374 // Add padding to the struct size to align it to the abi alignment of the
375 // element type before than adding the size of the element.
376 recordSize = llvm::alignTo(recordSize, tyAlign);
377 recordSize += dataLayout.getTypeSize(ty);
378
379 // The alignment requirement of a struct is equal to the strictest alignment
380 // requirement of its elements.
381 recordAlignment = std::max(tyAlign, recordAlignment);
382 }
383
384 // At the end, add padding to the struct to satisfy its own alignment
385 // requirement. Otherwise structs inside of arrays would be misaligned.
386 recordSize = llvm::alignTo(recordSize, recordAlignment);
387 return recordSize;
388}
389
390// We also compute the alignment as part of computeStructSize, but this is more
391// efficient. Ideally, we'd like to compute both at once and cache the result,
392// but that's implemented yet.
393// TODO(CIR): Implement a way to cache the result.
395RecordType::computeStructAlignment(const mlir::DataLayout &dataLayout) const {
396 assert(isComplete() && "Cannot get layout of incomplete records");
397
398 // This is a similar algorithm to LLVM's StructLayout.
399 uint64_t recordAlignment = 1;
400 for (mlir::Type ty : getMembers())
401 recordAlignment =
402 std::max(dataLayout.getTypeABIAlignment(ty), recordAlignment);
403
404 return recordAlignment;
405}
406
407uint64_t RecordType::getElementOffset(const ::mlir::DataLayout &dataLayout,
408 unsigned idx) const {
409 assert(idx < getMembers().size() && "access not valid");
410
411 // All union elements are at offset zero.
412 if (isUnion() || idx == 0)
413 return 0;
414
415 assert(isComplete() && "Cannot get layout of incomplete records");
416 assert(idx < getNumElements());
417 llvm::ArrayRef<mlir::Type> members = getMembers();
418
419 unsigned offset = 0;
420
421 for (mlir::Type ty :
422 llvm::make_range(members.begin(), std::next(members.begin(), idx))) {
423 // This matches LLVM since it uses the ABI instead of preferred alignment.
424 const llvm::Align tyAlign =
425 llvm::Align(getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
426
427 // Add padding if necessary to align the data element properly.
428 offset = llvm::alignTo(offset, tyAlign);
429
430 // Consume space for this data item
431 offset += dataLayout.getTypeSize(ty);
432 }
433
434 // Account for padding, if necessary, for the alignment of the field whose
435 // offset we are calculating.
436 const llvm::Align tyAlign = llvm::Align(
437 getPacked() ? 1 : dataLayout.getTypeABIAlignment(members[idx]));
438 offset = llvm::alignTo(offset, tyAlign);
439
440 return offset;
441}
442
443//===----------------------------------------------------------------------===//
444// IntType Definitions
445//===----------------------------------------------------------------------===//
446
447Type IntType::parse(mlir::AsmParser &parser) {
448 mlir::MLIRContext *context = parser.getBuilder().getContext();
449 llvm::SMLoc loc = parser.getCurrentLocation();
450 bool isSigned;
451 unsigned width;
452
453 if (parser.parseLess())
454 return {};
455
456 // Fetch integer sign.
457 llvm::StringRef sign;
458 if (parser.parseKeyword(&sign))
459 return {};
460 if (sign == "s")
461 isSigned = true;
462 else if (sign == "u")
463 isSigned = false;
464 else {
465 parser.emitError(loc, "expected 's' or 'u'");
466 return {};
467 }
468
469 if (parser.parseComma())
470 return {};
471
472 // Fetch integer size.
473 if (parser.parseInteger(width))
474 return {};
475 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
476 parser.emitError(loc, "expected integer width to be from ")
477 << IntType::minBitwidth() << " up to " << IntType::maxBitwidth();
478 return {};
479 }
480
481 if (parser.parseGreater())
482 return {};
483
484 return IntType::get(context, width, isSigned);
485}
486
487void IntType::print(mlir::AsmPrinter &printer) const {
488 char sign = isSigned() ? 's' : 'u';
489 printer << '<' << sign << ", " << getWidth() << '>';
490}
491
492llvm::TypeSize
493IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
494 mlir::DataLayoutEntryListRef params) const {
495 return llvm::TypeSize::getFixed(getWidth());
496}
497
498uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
499 mlir::DataLayoutEntryListRef params) const {
500 return (uint64_t)(getWidth() / 8);
501}
502
503mlir::LogicalResult
504IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
505 unsigned width, bool isSigned) {
506 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth())
507 return emitError() << "IntType only supports widths from "
508 << IntType::minBitwidth() << " up to "
509 << IntType::maxBitwidth();
510 return mlir::success();
511}
512
514 return width == 8 || width == 16 || width == 32 || width == 64;
515}
516
517//===----------------------------------------------------------------------===//
518// Floating-point type definitions
519//===----------------------------------------------------------------------===//
520
521const llvm::fltSemantics &SingleType::getFloatSemantics() const {
522 return llvm::APFloat::IEEEsingle();
523}
524
525llvm::TypeSize
526SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
527 mlir::DataLayoutEntryListRef params) const {
528 return llvm::TypeSize::getFixed(getWidth());
529}
530
532SingleType::getABIAlignment(const mlir::DataLayout &dataLayout,
533 mlir::DataLayoutEntryListRef params) const {
534 return (uint64_t)(getWidth() / 8);
535}
536
537const llvm::fltSemantics &DoubleType::getFloatSemantics() const {
538 return llvm::APFloat::IEEEdouble();
539}
540
541llvm::TypeSize
542DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
543 mlir::DataLayoutEntryListRef params) const {
544 return llvm::TypeSize::getFixed(getWidth());
545}
546
548DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
549 mlir::DataLayoutEntryListRef params) const {
550 return (uint64_t)(getWidth() / 8);
551}
552
553const llvm::fltSemantics &FP16Type::getFloatSemantics() const {
554 return llvm::APFloat::IEEEhalf();
555}
556
557llvm::TypeSize
558FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
559 mlir::DataLayoutEntryListRef params) const {
560 return llvm::TypeSize::getFixed(getWidth());
561}
562
563uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
564 mlir::DataLayoutEntryListRef params) const {
565 return (uint64_t)(getWidth() / 8);
566}
567
568const llvm::fltSemantics &BF16Type::getFloatSemantics() const {
569 return llvm::APFloat::BFloat();
570}
571
572llvm::TypeSize
573BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
574 mlir::DataLayoutEntryListRef params) const {
575 return llvm::TypeSize::getFixed(getWidth());
576}
577
578uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
579 mlir::DataLayoutEntryListRef params) const {
580 return (uint64_t)(getWidth() / 8);
581}
582
583const llvm::fltSemantics &FP80Type::getFloatSemantics() const {
584 return llvm::APFloat::x87DoubleExtended();
585}
586
587llvm::TypeSize
588FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
589 mlir::DataLayoutEntryListRef params) const {
590 // Though only 80 bits are used for the value, the type is 128 bits in size.
591 return llvm::TypeSize::getFixed(128);
592}
593
594uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout,
595 mlir::DataLayoutEntryListRef params) const {
596 return 16;
597}
598
599const llvm::fltSemantics &FP128Type::getFloatSemantics() const {
600 return llvm::APFloat::IEEEquad();
601}
602
603llvm::TypeSize
604FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
605 mlir::DataLayoutEntryListRef params) const {
606 return llvm::TypeSize::getFixed(getWidth());
607}
608
609uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout,
610 mlir::DataLayoutEntryListRef params) const {
611 return 16;
612}
613
614const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const {
615 return mlir::cast<cir::FPTypeInterface>(getUnderlying()).getFloatSemantics();
616}
617
618llvm::TypeSize
619LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
620 mlir::DataLayoutEntryListRef params) const {
621 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
622 .getTypeSizeInBits(dataLayout, params);
623}
624
626LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
627 mlir::DataLayoutEntryListRef params) const {
628 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
629 .getABIAlignment(dataLayout, params);
630}
631
632//===----------------------------------------------------------------------===//
633// ComplexType Definitions
634//===----------------------------------------------------------------------===//
635
636llvm::TypeSize
637cir::ComplexType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
638 mlir::DataLayoutEntryListRef params) const {
639 // C17 6.2.5p13:
640 // Each complex type has the same representation and alignment requirements
641 // as an array type containing exactly two elements of the corresponding
642 // real type.
643
644 return dataLayout.getTypeSizeInBits(getElementType()) * 2;
645}
646
648cir::ComplexType::getABIAlignment(const mlir::DataLayout &dataLayout,
649 mlir::DataLayoutEntryListRef params) const {
650 // C17 6.2.5p13:
651 // Each complex type has the same representation and alignment requirements
652 // as an array type containing exactly two elements of the corresponding
653 // real type.
654
655 return dataLayout.getTypeABIAlignment(getElementType());
656}
657
658FuncType FuncType::clone(TypeRange inputs, TypeRange results) const {
659 assert(results.size() == 1 && "expected exactly one result type");
660 return get(llvm::to_vector(inputs), results[0], isVarArg());
661}
662
663// Custom parser that parses function parameters of form `(<type>*, ...)`.
664static mlir::ParseResult
666 bool &isVarArg) {
667 isVarArg = false;
668 return p.parseCommaSeparatedList(
669 AsmParser::Delimiter::Paren, [&]() -> mlir::ParseResult {
670 if (isVarArg)
671 return p.emitError(p.getCurrentLocation(),
672 "variadic `...` must be the last parameter");
673 if (succeeded(p.parseOptionalEllipsis())) {
674 isVarArg = true;
675 return success();
676 }
677 mlir::Type type;
678 if (failed(p.parseType(type)))
679 return failure();
680 params.push_back(type);
681 return success();
682 });
683}
684
685static void printFuncTypeParams(mlir::AsmPrinter &p,
686 mlir::ArrayRef<mlir::Type> params,
687 bool isVarArg) {
688 p << '(';
689 llvm::interleaveComma(params, p,
690 [&p](mlir::Type type) { p.printType(type); });
691 if (isVarArg) {
692 if (!params.empty())
693 p << ", ";
694 p << "...";
695 }
696 p << ')';
697}
698
699/// Get the C-style return type of the function, which is !cir.void if the
700/// function returns nothing and the actual return type otherwise.
701mlir::Type FuncType::getReturnType() const {
702 if (hasVoidReturn())
703 return cir::VoidType::get(getContext());
704 return getOptionalReturnType();
705}
706
707/// Get the MLIR-style return type of the function, which is an empty
708/// ArrayRef if the function returns nothing and a single-element ArrayRef
709/// with the actual return type otherwise.
710llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const {
711 if (hasVoidReturn())
712 return {};
713 // Can't use getOptionalReturnType() here because llvm::ArrayRef hold a
714 // pointer to its elements and doesn't do lifetime extension. That would
715 // result in returning a pointer to a temporary that has gone out of scope.
716 return getImpl()->optionalReturnType;
717}
718
719// Does the fuction type return nothing?
720bool FuncType::hasVoidReturn() const { return !getOptionalReturnType(); }
721
722mlir::LogicalResult
723FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
724 llvm::ArrayRef<mlir::Type> argTypes, mlir::Type returnType,
725 bool isVarArg) {
726 if (mlir::isa_and_nonnull<cir::VoidType>(returnType))
727 return emitError()
728 << "!cir.func cannot have an explicit 'void' return type";
729 return mlir::success();
730}
731
732//===----------------------------------------------------------------------===//
733// BoolType
734//===----------------------------------------------------------------------===//
735
736llvm::TypeSize
737BoolType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
738 ::mlir::DataLayoutEntryListRef params) const {
739 return llvm::TypeSize::getFixed(8);
740}
741
743BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
744 ::mlir::DataLayoutEntryListRef params) const {
745 return 1;
746}
747
748//===----------------------------------------------------------------------===//
749// VPtrType Definitions
750//===----------------------------------------------------------------------===//
751
752llvm::TypeSize
753VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
754 mlir::DataLayoutEntryListRef params) const {
755 // FIXME: consider size differences under different ABIs
756 return llvm::TypeSize::getFixed(64);
757}
758
759uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout,
760 mlir::DataLayoutEntryListRef params) const {
761 // FIXME: consider alignment differences under different ABIs
762 return 8;
763}
764
765//===----------------------------------------------------------------------===//
766// ArrayType Definitions
767//===----------------------------------------------------------------------===//
768
769llvm::TypeSize
770ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
771 ::mlir::DataLayoutEntryListRef params) const {
772 return getSize() * dataLayout.getTypeSizeInBits(getElementType());
773}
774
776ArrayType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
777 ::mlir::DataLayoutEntryListRef params) const {
778 return dataLayout.getTypeABIAlignment(getElementType());
779}
780
781//===----------------------------------------------------------------------===//
782// VectorType Definitions
783//===----------------------------------------------------------------------===//
784
785llvm::TypeSize cir::VectorType::getTypeSizeInBits(
786 const ::mlir::DataLayout &dataLayout,
787 ::mlir::DataLayoutEntryListRef params) const {
788 return llvm::TypeSize::getFixed(
789 getSize() * dataLayout.getTypeSizeInBits(getElementType()));
790}
791
793cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
794 ::mlir::DataLayoutEntryListRef params) const {
795 return llvm::NextPowerOf2(dataLayout.getTypeSizeInBits(*this));
796}
797
798mlir::LogicalResult cir::VectorType::verify(
799 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
800 mlir::Type elementType, uint64_t size) {
801 if (size == 0)
802 return emitError() << "the number of vector elements must be non-zero";
803 return success();
804}
805
806//===----------------------------------------------------------------------===//
807// TargetAddressSpace definitions
808//===----------------------------------------------------------------------===//
809
810mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
811 cir::TargetAddressSpaceAttr &attr) {
812 if (failed(p.parseKeyword("target_address_space")))
813 return mlir::failure();
814
815 if (failed(p.parseLParen()))
816 return mlir::failure();
817
818 int32_t targetValue;
819 if (failed(p.parseInteger(targetValue)))
820 return p.emitError(p.getCurrentLocation(),
821 "expected integer address space value");
822
823 if (failed(p.parseRParen()))
824 return p.emitError(p.getCurrentLocation(),
825 "expected ')' after address space value");
826
827 mlir::MLIRContext *context = p.getBuilder().getContext();
828 attr = cir::TargetAddressSpaceAttr::get(
829 context, p.getBuilder().getUI32IntegerAttr(targetValue));
830 return mlir::success();
831}
832
833// The custom printer for the `addrspace` parameter in `!cir.ptr`.
834// in the format of `target_address_space(N)`.
835void printTargetAddressSpace(mlir::AsmPrinter &p,
836 cir::TargetAddressSpaceAttr attr) {
837 p << "target_address_space(" << attr.getValue().getUInt() << ")";
838}
839
840//===----------------------------------------------------------------------===//
841// CIR Dialect
842//===----------------------------------------------------------------------===//
843
844void CIRDialect::registerTypes() {
845 // Register tablegen'd types.
846 addTypes<
847#define GET_TYPEDEF_LIST
848#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
849 >();
850
851 // Register raw C++ types.
852 // TODO(CIR) addTypes<RecordType>();
853}
mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr)
Definition CIRTypes.cpp:810
void printTargetAddressSpace(mlir::AsmPrinter &p, cir::TargetAddressSpaceAttr attr)
Definition CIRTypes.cpp:835
mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr)
Definition CIRTypes.cpp:810
static mlir::ParseResult parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector< mlir::Type > &params, bool &isVarArg)
Definition CIRTypes.cpp:665
static void printFuncTypeParams(mlir::AsmPrinter &p, mlir::ArrayRef< mlir::Type > params, bool isVarArg)
Definition CIRTypes.cpp:685
void printTargetAddressSpace(mlir::AsmPrinter &p, cir::TargetAddressSpaceAttr attr)
Definition CIRTypes.cpp:835
static Decl::Kind getKind(const Decl *D)
static LiveVariablesImpl & getImpl(void *x)
bool isValidFundamentalIntWidth(unsigned width)
Definition CIRTypes.cpp:513
bool isSized(mlir::Type ty)
Returns true if the type is a CIR sized type.
Definition CIRTypes.cpp:25
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
StringRef getName(const HeaderType T)
Definition HeaderFile.h:38
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
unsigned long uint64_t
float __ovld __cnfn sign(float)
Returns 1.0 if x > 0, -0.0 if x = -0.0, +0.0 if x = +0.0, or -1.0 if x < 0.
static bool unsizedTypes()
static bool dataLayoutPtrHandlingBasedOnLangAS()
static bool astRecordDeclAttr()