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