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