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