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(members.begin(), endIt, [&](Type lhs, Type rhs) {
340 return dataLayout.getTypeABIAlignment(lhs) <
341 dataLayout.getTypeABIAlignment(rhs) ||
342 (dataLayout.getTypeABIAlignment(lhs) ==
343 dataLayout.getTypeABIAlignment(rhs) &&
344 dataLayout.getTypeSize(lhs) < dataLayout.getTypeSize(rhs));
345 });
346}
347
348bool RecordType::isLayoutIdentical(const RecordType &other) {
349 if (getImpl() == other.getImpl())
350 return true;
351
352 if (getPacked() != other.getPacked())
353 return false;
354
355 return getMembers() == other.getMembers();
356}
357
358//===----------------------------------------------------------------------===//
359// Data Layout information for types
360//===----------------------------------------------------------------------===//
361
362llvm::TypeSize
363PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
364 ::mlir::DataLayoutEntryListRef params) const {
365 // FIXME: improve this in face of address spaces
367 return llvm::TypeSize::getFixed(64);
368}
369
371PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
372 ::mlir::DataLayoutEntryListRef params) const {
373 // FIXME: improve this in face of address spaces
375 return 8;
376}
377
378llvm::TypeSize
379RecordType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
380 mlir::DataLayoutEntryListRef params) const {
381 if (isUnion())
382 return dataLayout.getTypeSize(getLargestMember(dataLayout));
383
384 auto recordSize = static_cast<uint64_t>(computeStructSize(dataLayout));
385 return llvm::TypeSize::getFixed(recordSize * 8);
386}
387
389RecordType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
390 ::mlir::DataLayoutEntryListRef params) const {
391 if (isUnion())
392 return dataLayout.getTypeABIAlignment(getLargestMember(dataLayout));
393
394 // Packed structures always have an ABI alignment of 1.
395 if (getPacked())
396 return 1;
397 return computeStructAlignment(dataLayout);
398}
399
400unsigned
401RecordType::computeStructSize(const mlir::DataLayout &dataLayout) const {
402 assert(isComplete() && "Cannot get layout of incomplete records");
403
404 // This is a similar algorithm to LLVM's StructLayout.
405 unsigned recordSize = 0;
406 uint64_t recordAlignment = 1;
407
408 for (mlir::Type ty : getMembers()) {
409 // This assumes that we're calculating size based on the ABI alignment, not
410 // the preferred alignment for each type.
411 const uint64_t tyAlign =
412 (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
413
414 // Add padding to the struct size to align it to the abi alignment of the
415 // element type before than adding the size of the element.
416 recordSize = llvm::alignTo(recordSize, tyAlign);
417 recordSize += dataLayout.getTypeSize(ty);
418
419 // The alignment requirement of a struct is equal to the strictest alignment
420 // requirement of its elements.
421 recordAlignment = std::max(tyAlign, recordAlignment);
422 }
423
424 // At the end, add padding to the struct to satisfy its own alignment
425 // requirement. Otherwise structs inside of arrays would be misaligned.
426 recordSize = llvm::alignTo(recordSize, recordAlignment);
427 return recordSize;
428}
429
430unsigned
431RecordType::computeStructDataSize(const mlir::DataLayout &dataLayout) const {
432 assert(isComplete() && "Cannot get layout of incomplete records");
433
434 // Compute the data size (excluding tail padding) for this record type. For
435 // padded records, the last member is the tail padding array added by
436 // CIRGenRecordLayoutBuilder::appendPaddingBytes, so we exclude it. For
437 // non-padded records, data size equals the full struct size without
438 // alignment.
439 auto members = getMembers();
440 unsigned numMembers =
441 getPadded() && members.size() > 1 ? members.size() - 1 : members.size();
442 unsigned recordSize = 0;
443 for (unsigned i = 0; i < numMembers; ++i) {
444 mlir::Type ty = members[i];
445 const uint64_t tyAlign =
446 (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
447 recordSize = llvm::alignTo(recordSize, tyAlign);
448 recordSize += dataLayout.getTypeSize(ty);
449 }
450 return recordSize;
451}
452
453// We also compute the alignment as part of computeStructSize, but this is more
454// efficient. Ideally, we'd like to compute both at once and cache the result,
455// but that's implemented yet.
456// TODO(CIR): Implement a way to cache the result.
458RecordType::computeStructAlignment(const mlir::DataLayout &dataLayout) const {
459 assert(isComplete() && "Cannot get layout of incomplete records");
460
461 // This is a similar algorithm to LLVM's StructLayout.
462 uint64_t recordAlignment = 1;
463 for (mlir::Type ty : getMembers())
464 recordAlignment =
465 std::max(dataLayout.getTypeABIAlignment(ty), recordAlignment);
466
467 return recordAlignment;
468}
469
470uint64_t RecordType::getElementOffset(const ::mlir::DataLayout &dataLayout,
471 unsigned idx) const {
472 assert(idx < getMembers().size() && "access not valid");
473
474 // All union elements are at offset zero.
475 if (isUnion() || idx == 0)
476 return 0;
477
478 assert(isComplete() && "Cannot get layout of incomplete records");
479 assert(idx < getNumElements());
480 llvm::ArrayRef<mlir::Type> members = getMembers();
481
482 unsigned offset = 0;
483
484 for (mlir::Type ty :
485 llvm::make_range(members.begin(), std::next(members.begin(), idx))) {
486 // This matches LLVM since it uses the ABI instead of preferred alignment.
487 const llvm::Align tyAlign =
488 llvm::Align(getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
489
490 // Add padding if necessary to align the data element properly.
491 offset = llvm::alignTo(offset, tyAlign);
492
493 // Consume space for this data item
494 offset += dataLayout.getTypeSize(ty);
495 }
496
497 // Account for padding, if necessary, for the alignment of the field whose
498 // offset we are calculating.
499 const llvm::Align tyAlign = llvm::Align(
500 getPacked() ? 1 : dataLayout.getTypeABIAlignment(members[idx]));
501 offset = llvm::alignTo(offset, tyAlign);
502
503 return offset;
504}
505
506//===----------------------------------------------------------------------===//
507// IntType Definitions
508//===----------------------------------------------------------------------===//
509
510Type IntType::parse(mlir::AsmParser &parser) {
511 mlir::MLIRContext *context = parser.getBuilder().getContext();
512 llvm::SMLoc loc = parser.getCurrentLocation();
513 bool isSigned;
514 unsigned width;
515
516 if (parser.parseLess())
517 return {};
518
519 // Fetch integer sign.
520 llvm::StringRef sign;
521 if (parser.parseKeyword(&sign))
522 return {};
523 if (sign == "s")
524 isSigned = true;
525 else if (sign == "u")
526 isSigned = false;
527 else {
528 parser.emitError(loc, "expected 's' or 'u'");
529 return {};
530 }
531
532 if (parser.parseComma())
533 return {};
534
535 // Fetch integer size.
536 if (parser.parseInteger(width))
537 return {};
538 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
539 parser.emitError(loc, "expected integer width to be from ")
540 << IntType::minBitwidth() << " up to " << IntType::maxBitwidth();
541 return {};
542 }
543
544 bool isBitInt = false;
545 if (succeeded(parser.parseOptionalComma())) {
546 llvm::StringRef kw;
547 if (parser.parseKeyword(&kw) || kw != "bitint") {
548 parser.emitError(loc, "expected 'bitint'");
549 return {};
550 }
551 isBitInt = true;
552 }
553
554 if (parser.parseGreater())
555 return {};
556
557 return IntType::get(context, width, isSigned, isBitInt);
558}
559
560void IntType::print(mlir::AsmPrinter &printer) const {
561 char sign = isSigned() ? 's' : 'u';
562 printer << '<' << sign << ", " << getWidth();
563 if (isBitInt())
564 printer << ", bitint";
565 printer << '>';
566}
567
568llvm::TypeSize
569IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
570 mlir::DataLayoutEntryListRef params) const {
571 return llvm::TypeSize::getFixed(getWidth());
572}
573
574uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
575 mlir::DataLayoutEntryListRef params) const {
576 unsigned width = getWidth();
577 if (isBitInt()) {
578 // _BitInt alignment: min(PowerOf2Ceil(width), 64 bits) in bytes.
579 // Matches Clang's TargetInfo::getBitIntAlign with default max = 64.
580 uint64_t alignBits =
581 std::min(llvm::PowerOf2Ceil(width), static_cast<uint64_t>(64));
582 return std::max(alignBits / 8, static_cast<uint64_t>(1));
583 }
584 return (uint64_t)(width / 8);
585}
586
587mlir::LogicalResult
588IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
589 unsigned width, bool isSigned, bool isBitInt) {
590 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth())
591 return emitError() << "IntType only supports widths from "
592 << IntType::minBitwidth() << " up to "
593 << IntType::maxBitwidth();
594 return mlir::success();
595}
596
598 return width == 8 || width == 16 || width == 32 || width == 64;
599}
600
601//===----------------------------------------------------------------------===//
602// Floating-point type definitions
603//===----------------------------------------------------------------------===//
604
605const llvm::fltSemantics &SingleType::getFloatSemantics() const {
606 return llvm::APFloat::IEEEsingle();
607}
608
609llvm::TypeSize
610SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
611 mlir::DataLayoutEntryListRef params) const {
612 return llvm::TypeSize::getFixed(getWidth());
613}
614
616SingleType::getABIAlignment(const mlir::DataLayout &dataLayout,
617 mlir::DataLayoutEntryListRef params) const {
618 return (uint64_t)(getWidth() / 8);
619}
620
621const llvm::fltSemantics &DoubleType::getFloatSemantics() const {
622 return llvm::APFloat::IEEEdouble();
623}
624
625llvm::TypeSize
626DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
627 mlir::DataLayoutEntryListRef params) const {
628 return llvm::TypeSize::getFixed(getWidth());
629}
630
632DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
633 mlir::DataLayoutEntryListRef params) const {
634 return (uint64_t)(getWidth() / 8);
635}
636
637const llvm::fltSemantics &FP16Type::getFloatSemantics() const {
638 return llvm::APFloat::IEEEhalf();
639}
640
641llvm::TypeSize
642FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
643 mlir::DataLayoutEntryListRef params) const {
644 return llvm::TypeSize::getFixed(getWidth());
645}
646
647uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
648 mlir::DataLayoutEntryListRef params) const {
649 return (uint64_t)(getWidth() / 8);
650}
651
652const llvm::fltSemantics &BF16Type::getFloatSemantics() const {
653 return llvm::APFloat::BFloat();
654}
655
656llvm::TypeSize
657BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
658 mlir::DataLayoutEntryListRef params) const {
659 return llvm::TypeSize::getFixed(getWidth());
660}
661
662uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
663 mlir::DataLayoutEntryListRef params) const {
664 return (uint64_t)(getWidth() / 8);
665}
666
667const llvm::fltSemantics &FP80Type::getFloatSemantics() const {
668 return llvm::APFloat::x87DoubleExtended();
669}
670
671llvm::TypeSize
672FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
673 mlir::DataLayoutEntryListRef params) const {
674 // Though only 80 bits are used for the value, the type is 128 bits in size.
675 return llvm::TypeSize::getFixed(128);
676}
677
678uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout,
679 mlir::DataLayoutEntryListRef params) const {
680 return 16;
681}
682
683const llvm::fltSemantics &FP128Type::getFloatSemantics() const {
684 return llvm::APFloat::IEEEquad();
685}
686
687llvm::TypeSize
688FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
689 mlir::DataLayoutEntryListRef params) const {
690 return llvm::TypeSize::getFixed(getWidth());
691}
692
693uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout,
694 mlir::DataLayoutEntryListRef params) const {
695 return 16;
696}
697
698const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const {
699 return mlir::cast<cir::FPTypeInterface>(getUnderlying()).getFloatSemantics();
700}
701
702llvm::TypeSize
703LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
704 mlir::DataLayoutEntryListRef params) const {
705 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
706 .getTypeSizeInBits(dataLayout, params);
707}
708
710LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
711 mlir::DataLayoutEntryListRef params) const {
712 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
713 .getABIAlignment(dataLayout, params);
714}
715
716//===----------------------------------------------------------------------===//
717// ComplexType Definitions
718//===----------------------------------------------------------------------===//
719
720llvm::TypeSize
721cir::ComplexType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
722 mlir::DataLayoutEntryListRef params) const {
723 // C17 6.2.5p13:
724 // Each complex type has the same representation and alignment requirements
725 // as an array type containing exactly two elements of the corresponding
726 // real type.
727
728 return dataLayout.getTypeSizeInBits(getElementType()) * 2;
729}
730
732cir::ComplexType::getABIAlignment(const mlir::DataLayout &dataLayout,
733 mlir::DataLayoutEntryListRef params) const {
734 // C17 6.2.5p13:
735 // Each complex type has the same representation and alignment requirements
736 // as an array type containing exactly two elements of the corresponding
737 // real type.
738
739 return dataLayout.getTypeABIAlignment(getElementType());
740}
741
742FuncType FuncType::clone(TypeRange inputs, TypeRange results) const {
743 assert(results.size() == 1 && "expected exactly one result type");
744 return get(llvm::to_vector(inputs), results[0], isVarArg());
745}
746
747// Custom parser that parses function parameters of form `(<type>*, ...)`.
748static mlir::ParseResult
750 bool &isVarArg) {
751 isVarArg = false;
752 return p.parseCommaSeparatedList(
753 AsmParser::Delimiter::Paren, [&]() -> mlir::ParseResult {
754 if (isVarArg)
755 return p.emitError(p.getCurrentLocation(),
756 "variadic `...` must be the last parameter");
757 if (succeeded(p.parseOptionalEllipsis())) {
758 isVarArg = true;
759 return success();
760 }
761 mlir::Type type;
762 if (failed(p.parseType(type)))
763 return failure();
764 params.push_back(type);
765 return success();
766 });
767}
768
769static void printFuncTypeParams(mlir::AsmPrinter &p,
770 mlir::ArrayRef<mlir::Type> params,
771 bool isVarArg) {
772 p << '(';
773 llvm::interleaveComma(params, p,
774 [&p](mlir::Type type) { p.printType(type); });
775 if (isVarArg) {
776 if (!params.empty())
777 p << ", ";
778 p << "...";
779 }
780 p << ')';
781}
782
783/// Get the C-style return type of the function, which is !cir.void if the
784/// function returns nothing and the actual return type otherwise.
785mlir::Type FuncType::getReturnType() const {
786 if (hasVoidReturn())
787 return cir::VoidType::get(getContext());
788 return getOptionalReturnType();
789}
790
791/// Get the MLIR-style return type of the function, which is an empty
792/// ArrayRef if the function returns nothing and a single-element ArrayRef
793/// with the actual return type otherwise.
794llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const {
795 if (hasVoidReturn())
796 return {};
797 // Can't use getOptionalReturnType() here because llvm::ArrayRef hold a
798 // pointer to its elements and doesn't do lifetime extension. That would
799 // result in returning a pointer to a temporary that has gone out of scope.
800 return getImpl()->optionalReturnType;
801}
802
803// Does the fuction type return nothing?
804bool FuncType::hasVoidReturn() const { return !getOptionalReturnType(); }
805
806mlir::LogicalResult
807FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
808 llvm::ArrayRef<mlir::Type> argTypes, mlir::Type returnType,
809 bool isVarArg) {
810 if (mlir::isa_and_nonnull<cir::VoidType>(returnType))
811 return emitError()
812 << "!cir.func cannot have an explicit 'void' return type";
813 return mlir::success();
814}
815
816//===----------------------------------------------------------------------===//
817// MethodType Definitions
818//===----------------------------------------------------------------------===//
819
820static mlir::Type getMethodLayoutType(mlir::MLIRContext *ctx) {
821 // With Itanium ABI, member function pointers have the same layout as the
822 // following struct: struct { fnptr_t, ptrdiff_t }, where fnptr_t is a
823 // function pointer type.
824 // TODO: consider member function pointer layout in other ABIs
825 auto voidPtrTy = cir::PointerType::get(cir::VoidType::get(ctx));
826 mlir::Type fields[2]{voidPtrTy, voidPtrTy};
827 return cir::RecordType::get(ctx, fields, /*packed=*/false,
828 /*padded=*/false, cir::RecordType::Struct);
829}
830
831llvm::TypeSize
832MethodType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
833 mlir::DataLayoutEntryListRef params) const {
834 return dataLayout.getTypeSizeInBits(getMethodLayoutType(getContext()));
835}
836
838MethodType::getABIAlignment(const mlir::DataLayout &dataLayout,
839 mlir::DataLayoutEntryListRef params) const {
840 return cast<cir::RecordType>(getMethodLayoutType(getContext()))
841 .getABIAlignment(dataLayout, params);
842}
843
844//===----------------------------------------------------------------------===//
845// BoolType
846//===----------------------------------------------------------------------===//
847
848llvm::TypeSize
849BoolType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
850 ::mlir::DataLayoutEntryListRef params) const {
851 return llvm::TypeSize::getFixed(8);
852}
853
855BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
856 ::mlir::DataLayoutEntryListRef params) const {
857 return 1;
858}
859
860//===----------------------------------------------------------------------===//
861// DataMemberType Definitions
862//===----------------------------------------------------------------------===//
863
864llvm::TypeSize
865DataMemberType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
866 ::mlir::DataLayoutEntryListRef params) const {
867 // FIXME: consider size differences under different ABIs
868 assert(!MissingFeatures::cxxABI());
869 return llvm::TypeSize::getFixed(64);
870}
871
873DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
874 ::mlir::DataLayoutEntryListRef params) const {
875 // FIXME: consider alignment differences under different ABIs
876 assert(!MissingFeatures::cxxABI());
877 return 8;
878}
879
880//===----------------------------------------------------------------------===//
881// VPtrType Definitions
882//===----------------------------------------------------------------------===//
883
884llvm::TypeSize
885VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
886 mlir::DataLayoutEntryListRef params) const {
887 // FIXME: consider size differences under different ABIs
888 return llvm::TypeSize::getFixed(64);
889}
890
891uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout,
892 mlir::DataLayoutEntryListRef params) const {
893 // FIXME: consider alignment differences under different ABIs
894 return 8;
895}
896
897//===----------------------------------------------------------------------===//
898// ArrayType Definitions
899//===----------------------------------------------------------------------===//
900
901llvm::TypeSize
902ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
903 ::mlir::DataLayoutEntryListRef params) const {
904 return getSize() * dataLayout.getTypeSizeInBits(getElementType());
905}
906
908ArrayType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
909 ::mlir::DataLayoutEntryListRef params) const {
910 return dataLayout.getTypeABIAlignment(getElementType());
911}
912
913//===----------------------------------------------------------------------===//
914// VectorType Definitions
915//===----------------------------------------------------------------------===//
916
917llvm::TypeSize cir::VectorType::getTypeSizeInBits(
918 const ::mlir::DataLayout &dataLayout,
919 ::mlir::DataLayoutEntryListRef params) const {
920 return llvm::TypeSize::getFixed(
921 getSize() * dataLayout.getTypeSizeInBits(getElementType()));
922}
923
925cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
926 ::mlir::DataLayoutEntryListRef params) const {
927 return llvm::NextPowerOf2(dataLayout.getTypeSizeInBits(*this));
928}
929
930mlir::LogicalResult cir::VectorType::verify(
931 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
932 mlir::Type elementType, uint64_t size, bool scalable) {
933 if (size == 0)
934 return emitError() << "the number of vector elements must be non-zero";
935 return success();
936}
937
938mlir::Type cir::VectorType::parse(::mlir::AsmParser &odsParser) {
939
940 llvm::SMLoc odsLoc = odsParser.getCurrentLocation();
941 mlir::Builder odsBuilder(odsParser.getContext());
942 mlir::FailureOr<::mlir::Type> elementType;
943 mlir::FailureOr<uint64_t> size;
944 bool isScalabe = false;
945
946 // Parse literal '<'
947 if (odsParser.parseLess())
948 return {};
949
950 // Parse literal '[', if present, and set the scalability flag accordingly
951 if (odsParser.parseOptionalLSquare().succeeded())
952 isScalabe = true;
953
954 // Parse variable 'size'
955 size = mlir::FieldParser<uint64_t>::parse(odsParser);
956 if (mlir::failed(size)) {
957 odsParser.emitError(odsParser.getCurrentLocation(),
958 "failed to parse CIR_VectorType parameter 'size' which "
959 "is to be a `uint64_t`");
960 return {};
961 }
962
963 // Parse literal ']', which is expected when dealing with scalable
964 // dim sizes
965 if (isScalabe && odsParser.parseRSquare().failed()) {
966 odsParser.emitError(odsParser.getCurrentLocation(),
967 "missing closing `]` for scalable dim size");
968 return {};
969 }
970
971 // Parse literal 'x'
972 if (odsParser.parseKeyword("x"))
973 return {};
974
975 // Parse variable 'elementType'
976 elementType = mlir::FieldParser<::mlir::Type>::parse(odsParser);
977 if (mlir::failed(elementType)) {
978 odsParser.emitError(odsParser.getCurrentLocation(),
979 "failed to parse CIR_VectorType parameter "
980 "'elementType' which is to be a `mlir::Type`");
981 return {};
982 }
983
984 // Parse literal '>'
985 if (odsParser.parseGreater())
986 return {};
987 return odsParser.getChecked<VectorType>(odsLoc, odsParser.getContext(),
988 mlir::Type((*elementType)),
989 uint64_t((*size)), isScalabe);
990}
991
992void cir::VectorType::print(mlir::AsmPrinter &odsPrinter) const {
993 mlir::Builder odsBuilder(getContext());
994 odsPrinter << "<";
995 if (this->getIsScalable())
996 odsPrinter << "[";
997
998 odsPrinter.printStrippedAttrOrType(getSize());
999 if (this->getIsScalable())
1000 odsPrinter << "]";
1001 odsPrinter << ' ' << "x";
1002 odsPrinter << ' ';
1003 odsPrinter.printStrippedAttrOrType(getElementType());
1004 odsPrinter << ">";
1005}
1006
1007//===----------------------------------------------------------------------===//
1008// AddressSpace definitions
1009//===----------------------------------------------------------------------===//
1010
1012 mlir::ptr::MemorySpaceAttrInterface memorySpace) {
1013 return mlir::isa<cir::LangAddressSpaceAttr, cir::TargetAddressSpaceAttr>(
1014 memorySpace);
1015}
1016
1017cir::LangAddressSpace cir::toCIRLangAddressSpace(clang::LangAS langAS) {
1018 using clang::LangAS;
1019 switch (langAS) {
1020 case LangAS::Default:
1021 return LangAddressSpace::Default;
1022 case LangAS::opencl_global:
1023 return LangAddressSpace::OffloadGlobal;
1024 case LangAS::opencl_local:
1025 case LangAS::cuda_shared:
1026 // Local means local among the work-group (OpenCL) or block (CUDA).
1027 // All threads inside the kernel can access local memory.
1028 return LangAddressSpace::OffloadLocal;
1029 case LangAS::cuda_device:
1030 return LangAddressSpace::OffloadGlobal;
1031 case LangAS::opencl_constant:
1032 case LangAS::cuda_constant:
1033 return LangAddressSpace::OffloadConstant;
1034 case LangAS::opencl_private:
1035 return LangAddressSpace::OffloadPrivate;
1036 case LangAS::opencl_generic:
1037 return LangAddressSpace::OffloadGeneric;
1038 case LangAS::opencl_global_device:
1039 case LangAS::opencl_global_host:
1040 case LangAS::sycl_global:
1041 case LangAS::sycl_global_device:
1042 case LangAS::sycl_global_host:
1043 case LangAS::sycl_local:
1044 case LangAS::sycl_private:
1045 case LangAS::ptr32_sptr:
1046 case LangAS::ptr32_uptr:
1047 case LangAS::ptr64:
1048 case LangAS::hlsl_groupshared:
1049 case LangAS::wasm_funcref:
1050 llvm_unreachable("NYI");
1051 default:
1052 llvm_unreachable("unknown/unsupported clang language address space");
1053 }
1054}
1055
1056mlir::ParseResult
1057parseAddressSpaceValue(mlir::AsmParser &p,
1058 mlir::ptr::MemorySpaceAttrInterface &attr) {
1059
1060 llvm::SMLoc loc = p.getCurrentLocation();
1061
1062 // Try to parse target address space first.
1063 attr = nullptr;
1064 if (p.parseOptionalKeyword("target_address_space").succeeded()) {
1065 unsigned val;
1066 if (p.parseLParen())
1067 return p.emitError(loc, "expected '(' after 'target_address_space'");
1068
1069 if (p.parseInteger(val))
1070 return p.emitError(loc, "expected target address space value");
1071
1072 if (p.parseRParen())
1073 return p.emitError(loc, "expected ')'");
1074
1075 attr = cir::TargetAddressSpaceAttr::get(p.getContext(), val);
1076 return mlir::success();
1077 }
1078
1079 // Try to parse language specific address space.
1080 if (p.parseOptionalKeyword("lang_address_space").succeeded()) {
1081 if (p.parseLParen())
1082 return p.emitError(loc, "expected '(' after 'lang_address_space'");
1083
1084 mlir::FailureOr<cir::LangAddressSpace> result =
1085 mlir::FieldParser<cir::LangAddressSpace>::parse(p);
1086 if (mlir::failed(result))
1087 return mlir::failure();
1088
1089 if (p.parseRParen())
1090 return p.emitError(loc, "expected ')'");
1091
1092 attr = cir::LangAddressSpaceAttr::get(p.getContext(), result.value());
1093 return mlir::success();
1094 }
1095
1096 llvm::StringRef keyword;
1097 if (p.parseOptionalKeyword(&keyword).succeeded())
1098 return p.emitError(loc, "unknown address space specifier '")
1099 << keyword << "'; expected 'target_address_space' or "
1100 << "'lang_address_space'";
1101
1102 return mlir::success();
1103}
1104
1105void printAddressSpaceValue(mlir::AsmPrinter &p,
1106 mlir::ptr::MemorySpaceAttrInterface attr) {
1107 if (!attr)
1108 return;
1109
1110 if (auto language = dyn_cast<cir::LangAddressSpaceAttr>(attr)) {
1111 p << "lang_address_space("
1112 << cir::stringifyLangAddressSpace(language.getValue()) << ')';
1113 return;
1114 }
1115
1116 if (auto target = dyn_cast<cir::TargetAddressSpaceAttr>(attr)) {
1117 p << "target_address_space(" << target.getValue() << ')';
1118 return;
1119 }
1120
1121 llvm_unreachable("unexpected address-space attribute kind");
1122}
1123
1124mlir::OptionalParseResult
1126 mlir::ptr::MemorySpaceAttrInterface &attr) {
1127
1128 mlir::SMLoc loc = p.getCurrentLocation();
1129 if (parseAddressSpaceValue(p, attr).failed())
1130 return p.emitError(loc, "failed to parse Address Space Value for GlobalOp");
1131 return mlir::success();
1132}
1133
1134void printGlobalAddressSpaceValue(mlir::AsmPrinter &printer, cir::GlobalOp,
1135 mlir::ptr::MemorySpaceAttrInterface attr) {
1136 printAddressSpaceValue(printer, attr);
1137}
1138
1139mlir::ptr::MemorySpaceAttrInterface cir::normalizeDefaultAddressSpace(
1140 mlir::ptr::MemorySpaceAttrInterface addrSpace) {
1141 if (auto langAS =
1142 mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace))
1143 if (langAS.getValue() == cir::LangAddressSpace::Default)
1144 return {};
1145 return addrSpace;
1146}
1147
1148mlir::ptr::MemorySpaceAttrInterface
1149cir::toCIRAddressSpaceAttr(mlir::MLIRContext &ctx, clang::LangAS langAS) {
1150 using clang::LangAS;
1151
1152 if (langAS == LangAS::Default)
1153 return cir::LangAddressSpaceAttr::get(&ctx, cir::LangAddressSpace::Default);
1154
1155 if (clang::isTargetAddressSpace(langAS)) {
1156 unsigned targetAS = clang::toTargetAddressSpace(langAS);
1157 return cir::TargetAddressSpaceAttr::get(&ctx, targetAS);
1158 }
1159
1160 return cir::LangAddressSpaceAttr::get(&ctx, toCIRLangAddressSpace(langAS));
1161}
1162
1163bool cir::isMatchingAddressSpace(mlir::ptr::MemorySpaceAttrInterface cirAS,
1164 clang::LangAS as) {
1165 cirAS = normalizeDefaultAddressSpace(cirAS);
1166 if (!cirAS)
1167 return as == clang::LangAS::Default;
1168 mlir::ptr::MemorySpaceAttrInterface expected = normalizeDefaultAddressSpace(
1169 toCIRAddressSpaceAttr(*cirAS.getContext(), as));
1170 return expected == cirAS;
1171}
1172
1173//===----------------------------------------------------------------------===//
1174// PointerType Definitions
1175//===----------------------------------------------------------------------===//
1176
1177mlir::LogicalResult cir::PointerType::verify(
1178 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1179 mlir::Type pointee, mlir::ptr::MemorySpaceAttrInterface addrSpace) {
1180 if (addrSpace) {
1181 if (!isSupportedCIRMemorySpaceAttr(addrSpace)) {
1182 return emitError() << "unsupported address space attribute; expected "
1183 "'target_address_space' or 'lang_address_space'";
1184 }
1185 }
1186
1187 return success();
1188}
1189
1190//===----------------------------------------------------------------------===//
1191// CIR Dialect
1192//===----------------------------------------------------------------------===//
1193
1194void CIRDialect::registerTypes() {
1195 // Register tablegen'd types.
1196 addTypes<
1197#define GET_TYPEDEF_LIST
1198#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
1199 >();
1200
1201 // Register raw C++ types.
1202 // TODO(CIR) addTypes<RecordType>();
1203}
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:749
static mlir::Type getMethodLayoutType(mlir::MLIRContext *ctx)
Definition CIRTypes.cpp:820
static void printFuncTypeParams(mlir::AsmPrinter &p, mlir::ArrayRef< mlir::Type > params, bool isVarArg)
Definition CIRTypes.cpp:769
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:597
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()