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