clang 24.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/APFloat.h"
27#include "llvm/ADT/APInt.h"
28#include "llvm/ADT/APSInt.h"
29#include "llvm/ADT/TypeSwitch.h"
30#include "llvm/Support/MathExtras.h"
31
32//===----------------------------------------------------------------------===//
33// CIR Helpers
34//===----------------------------------------------------------------------===//
35bool cir::isSized(mlir::Type ty) {
36 if (auto sizedTy = mlir::dyn_cast<cir::SizedTypeInterface>(ty))
37 return sizedTy.isSized();
39 return false;
40}
41
42cir::FPTypeInterface cir::getFloatingPointType(const llvm::fltSemantics &sem,
43 mlir::MLIRContext *ctx) {
44 switch (llvm::APFloat::SemanticsToEnum(sem)) {
45 case llvm::APFloat::S_IEEEhalf:
46 return cir::FP16Type::get(ctx);
47 case llvm::APFloat::S_BFloat:
48 return cir::BF16Type::get(ctx);
49 case llvm::APFloat::S_IEEEsingle:
50 return cir::SingleType::get(ctx);
51 case llvm::APFloat::S_IEEEdouble:
52 return cir::DoubleType::get(ctx);
53 case llvm::APFloat::S_x87DoubleExtended:
54 return cir::FP80Type::get(ctx);
55 case llvm::APFloat::S_IEEEquad:
56 return cir::FP128Type::get(ctx);
57 default:
58 // CIR has no type for the remaining semantics (PPCDoubleDouble, the
59 // Float8 formats). Return null and let the caller report it.
60 return {};
61 }
62}
63
64//===----------------------------------------------------------------------===//
65// CIR Custom Parser/Printer Signatures
66//===----------------------------------------------------------------------===//
67
68static mlir::ParseResult
69parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
70 bool &isVarArg);
71static void printFuncTypeParams(mlir::AsmPrinter &p,
72 mlir::ArrayRef<mlir::Type> params,
73 bool isVarArg);
74//===----------------------------------------------------------------------===//
75// CIR Custom Parser/Printer Signatures
76//===----------------------------------------------------------------------===//
77
78static mlir::ParseResult
79parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
80 bool &isVarArg);
81
82static void printFuncTypeParams(mlir::AsmPrinter &p,
83 mlir::ArrayRef<mlir::Type> params,
84 bool isVarArg);
85
86//===----------------------------------------------------------------------===//
87// AddressSpace
88//===----------------------------------------------------------------------===//
89
90// Spells the address space of `!cir.ptr` and `cir.global` as either
91// `lang_address_space(x)` or `target_address_space(n)`.
92mlir::ParseResult parseMemorySpace(mlir::AsmParser &p,
93 mlir::ptr::MemorySpaceAttrInterface &attr);
94
95void printMemorySpace(mlir::AsmPrinter &printer,
96 mlir::ptr::MemorySpaceAttrInterface attr);
97
98//===----------------------------------------------------------------------===//
99// Get autogenerated stuff
100//===----------------------------------------------------------------------===//
101
102namespace cir {
103
104#include "clang/CIR/Dialect/IR/CIRTypeConstraints.cpp.inc"
105
106} // namespace cir
107
108#define GET_TYPEDEF_CLASSES
109#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
110
111using namespace mlir;
112using namespace cir;
113
114//===----------------------------------------------------------------------===//
115// General CIR parsing / printing
116//===----------------------------------------------------------------------===//
117
118Type CIRDialect::parseType(DialectAsmParser &parser) const {
119 llvm::SMLoc typeLoc = parser.getCurrentLocation();
120 llvm::StringRef mnemonic;
121 Type genType;
122
123 // Try to parse as a tablegen'd type.
124 OptionalParseResult parseResult =
125 generatedTypeParser(parser, &mnemonic, genType);
126 if (parseResult.has_value())
127 return genType;
128
129 // All CIR types are now tablegen'd; nothing left to dispatch here.
130 parser.emitError(typeLoc) << "unknown CIR type: " << mnemonic;
131 return Type();
132}
133
134void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
135 // Try to print as a tablegen'd type.
136 if (generatedTypePrinter(type, os).succeeded())
137 return;
138
139 // TODO(CIR) Attempt to print as a raw C++ type.
140 llvm::report_fatal_error("printer is missing a handler for this type");
141}
142
143//===----------------------------------------------------------------------===//
144// StructType
145//===----------------------------------------------------------------------===//
146
147// Shared helpers for StructType and UnionType parse/print.
148
151 return llvm::SmallVector<RecordMemberKind>(members.size(),
152 RecordMemberKind::Data);
153}
154
155/// An incomplete record has no members, so a kind for one is caught by the
156/// same check.
157static mlir::LogicalResult
158verifyRecordMemberKinds(function_ref<mlir::InFlightDiagnostic()> emitError,
159 size_t numMembers,
161 if (memberKinds.size() != numMembers)
162 return emitError() << "expected " << numMembers << " member kinds, got "
163 << memberKinds.size();
164 return mlir::success();
165}
166
167/// Members must be CIR types other than void, which has no layout.
168static mlir::LogicalResult
169verifyRecordMemberTypes(function_ref<mlir::InFlightDiagnostic()> emitError,
171 for (auto [idx, memberTy] : llvm::enumerate(members)) {
172 if (!cir::isCIRType(memberTy))
173 return emitError() << "record member at index " << idx
174 << " must be a CIR type, got " << memberTy;
175 if (mlir::isa<cir::VoidType>(memberTy))
176 return emitError() << "record member at index " << idx
177 << " cannot be void";
178 }
179 return mlir::success();
180}
181
182/// The keywords that spell a member kind. A union's tail-padding slot probes
183/// for one of these to reject it, since that slot is not a member.
184static const llvm::StringRef memberKindMarks[] = {"data", "pad", "empty",
185 "bitfield"};
186
187static std::optional<RecordMemberKind>
188parseMemberKind(mlir::AsmParser &parser) {
189 llvm::StringRef keyword;
190 const llvm::SMLoc loc = parser.getCurrentLocation();
191 if (parser.parseKeyword(&keyword).failed())
192 return std::nullopt;
193 std::optional<RecordMemberKind> kind = symbolizeRecordMemberKind(keyword);
194 if (!kind)
195 parser.emitError(loc, "expected a record member kind");
196 return kind;
197}
198
199/// Parse "incomplete" or "{mark type, mark type, ...}", writing results into
200/// \p incomplete, \p members and \p memberKinds. Returns failure if member
201/// parsing fails.
202static mlir::ParseResult
203parseRecordBody(mlir::AsmParser &parser, bool &incomplete,
206 assert(incomplete && "caller must pre-initialize incomplete to true");
207 if (parser.parseOptionalKeyword("incomplete").succeeded())
208 return mlir::success();
209 incomplete = false;
210 return parser.parseCommaSeparatedList(
211 AsmParser::Delimiter::Braces,
212 [&parser, &members, &memberKinds]() -> mlir::ParseResult {
213 std::optional<RecordMemberKind> kind = parseMemberKind(parser);
214 if (!kind)
215 return mlir::failure();
216 memberKinds.push_back(*kind);
217 return parser.parseType(members.emplace_back());
218 });
219}
220
221/// Print a complete CIR record body:
222/// '<' ['class '] [name] ['packed '] body '>'
223/// where body is "incomplete" or "{[mark] members}[, padding = {type}]".
224/// RecordTy must be a mutable MLIR type (StructType or UnionType).
225template <typename RecordTy>
226static void
227printRecordBody(mlir::AsmPrinter &printer, RecordTy self, mlir::StringAttr name,
228 bool hasClassPrefix, bool isPacked, bool isIncomplete,
229 llvm::ArrayRef<mlir::Type> members, mlir::Type padding,
231 printer << '<';
232 if (hasClassPrefix)
233 printer << "class ";
234 if (name)
235 printer << name;
236
237 FailureOr<AsmPrinter::CyclicPrintReset> cyclicPrintGuard =
238 printer.tryStartCyclicPrint(self);
239 if (failed(cyclicPrintGuard)) {
240 printer << '>';
241 return;
242 }
243
244 if (hasClassPrefix || name)
245 printer << ' ';
246 if (isPacked)
247 printer << "packed ";
248 if (isIncomplete) {
249 printer << "incomplete";
250 } else {
251 printer << "{";
252 for (auto [idx, member] : llvm::enumerate(members)) {
253 if (idx)
254 printer << ", ";
255 printer << stringifyRecordMemberKind(memberKinds[idx]) << ' ';
256 printer.printType(member);
257 }
258 printer << "}";
259 if (padding) {
260 printer << ", padding = {";
261 printer.printType(padding);
262 printer << '}';
263 }
264 }
265 printer << '>';
266}
267
268/// Parse the body of a !cir.struct<...> type.
269Type StructType::parse(mlir::AsmParser &parser) {
270 FailureOr<AsmParser::CyclicParseReset> cyclicParseGuard;
271 const llvm::SMLoc loc = parser.getCurrentLocation();
272 const mlir::Location eLoc = parser.getEncodedSourceLoc(loc);
273 bool packed = false;
274 mlir::MLIRContext *context = parser.getContext();
275
276 if (parser.parseLess())
277 return {};
278
279 // An optional "class" keyword distinguishes class from struct.
280 bool is_class = parser.parseOptionalKeyword("class").succeeded();
281
282 mlir::StringAttr name;
283 parser.parseOptionalAttribute(name);
284
285 // Self-reference: ensure the referenced type was already parsed.
286 if (name && parser.parseOptionalGreater().succeeded()) {
287 StructType type = StructType::getChecked(eLoc, context, name, is_class);
288 if (succeeded(parser.tryStartCyclicParse(type))) {
289 parser.emitError(loc, "invalid self-reference within record");
290 return {};
291 }
292 return type;
293 }
294
295 // Named definition: ensure name has not been parsed yet.
296 if (name) {
297 StructType type = StructType::getChecked(eLoc, context, name, is_class);
298 cyclicParseGuard = parser.tryStartCyclicParse(type);
299 if (failed(cyclicParseGuard)) {
300 parser.emitError(loc, "record already defined");
301 return {};
302 }
303 }
304
305 if (parser.parseOptionalKeyword("packed").succeeded())
306 packed = true;
307
308 bool incomplete = true;
309 llvm::SmallVector<mlir::Type> members;
310 llvm::SmallVector<RecordMemberKind> memberKinds;
311 if (parseRecordBody(parser, incomplete, members, memberKinds).failed())
312 return {};
313
314 if (parser.parseGreater())
315 return {};
316
317 ArrayRef<mlir::Type> membersRef(members);
318 ArrayRef<RecordMemberKind> kindsRef(memberKinds);
319 mlir::Type type = {};
320 if (name && incomplete) {
321 type = StructType::getChecked(eLoc, context, name, is_class);
322 } else if (!name && !incomplete) {
323 type = StructType::getChecked(eLoc, context, membersRef, packed, is_class,
324 kindsRef);
325 if (!type)
326 return {};
327 } else if (!incomplete) {
328 type = StructType::getChecked(eLoc, context, membersRef, name, packed,
329 is_class, kindsRef);
330 if (!type)
331 return {};
332 if (auto structTy = mlir::dyn_cast<StructType>(type)) {
333 if (failed(structTy.mutate(membersRef, packed, kindsRef))) {
334 parser.emitError(loc, "record '")
335 << name.getValue() << "' redefined with a different body";
336 return {};
337 }
338 }
340 } else {
341 parser.emitError(loc, "anonymous records must be complete");
342 return {};
343 }
344
345 return type;
346}
347
348void StructType::print(mlir::AsmPrinter &printer) const {
349 printRecordBody(printer, *this, getName(), isClass(), getPacked(),
350 isIncomplete(), getMembers(), /*padding=*/{},
351 getMemberKinds());
352}
353
354mlir::LogicalResult StructType::verify(
355 function_ref<mlir::InFlightDiagnostic()> emitError,
356 llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name, bool incomplete,
357 bool packed, llvm::ArrayRef<RecordMemberKind> member_kinds, bool is_class) {
358 if (name && name.getValue().empty())
359 return emitError() << "identified records cannot have an empty name";
360 if (failed(verifyRecordMemberTypes(emitError, members)))
361 return mlir::failure();
362 return verifyRecordMemberKinds(emitError, members.size(), member_kinds);
363}
364
365// Accessors are hand-written because genStorageClass = 0 suppresses generated
366// implementations.
367llvm::ArrayRef<mlir::Type> StructType::getMembers() const {
368 return getImpl()->members;
369}
370mlir::StringAttr StructType::getName() const { return getImpl()->name; }
371bool StructType::isIncomplete() const { return getImpl()->incomplete; }
372bool StructType::getIncomplete() const { return getImpl()->incomplete; }
373bool StructType::getPacked() const { return getImpl()->packed; }
374llvm::ArrayRef<RecordMemberKind> StructType::getMemberKinds() const {
375 return getImpl()->member_kinds;
376}
377bool StructType::getIsClass() const { return getImpl()->is_class; }
378
379bool StructType::getPadded() const {
380 return llvm::is_contained(getMemberKinds(), RecordMemberKind::Pad);
381}
382
383bool StructType::isABIConvertedRecord() const {
384 return getName() && getName().getValue().starts_with(abi_conversion_prefix);
385}
386
387mlir::StringAttr StructType::getABIConvertedName() const {
388 assert(!isABIConvertedRecord());
389 return StringAttr::get(getContext(),
390 abi_conversion_prefix + getName().getValue());
391}
392
393void StructType::removeABIConversionNamePrefix() {
394 mlir::StringAttr recordName = getName();
395 if (recordName && recordName.getValue().starts_with(abi_conversion_prefix))
396 getImpl()->name = mlir::StringAttr::get(
397 recordName.getValue().drop_front(sizeof(abi_conversion_prefix) - 1),
398 recordName.getType());
399}
400
401void StructType::complete(ArrayRef<Type> members, bool packed,
402 ArrayRef<RecordMemberKind> memberKinds) {
404 // mutate() bypasses the verifier, so check what get() would have checked.
405 assert(
406 succeeded(verifyInvariants(
407 mlir::detail::getDefaultDiagnosticEmitFn(getContext()), members,
408 getName(), /*incomplete=*/false, packed, memberKinds, isClass())) &&
409 "invalid struct completion");
410 if (mutate(members, packed, memberKinds).failed())
411 llvm_unreachable("failed to complete struct");
412}
413
414bool StructType::isLayoutIdentical(const StructType &other) {
415 if (getImpl() == other.getImpl())
416 return true;
417 if (getPacked() != other.getPacked())
418 return false;
419 return getMembers() == other.getMembers();
420}
421
422//===----------------------------------------------------------------------===//
423// UnionType
424//===----------------------------------------------------------------------===//
425
426Type UnionType::parse(mlir::AsmParser &parser) {
427 FailureOr<AsmParser::CyclicParseReset> cyclicParseGuard;
428 const llvm::SMLoc loc = parser.getCurrentLocation();
429 const mlir::Location eLoc = parser.getEncodedSourceLoc(loc);
430 bool packed = false;
431 mlir::Type padding;
432 mlir::MLIRContext *context = parser.getContext();
433
434 if (parser.parseLess())
435 return {};
436
437 mlir::StringAttr name;
438 parser.parseOptionalAttribute(name);
439
440 // Self-reference.
441 if (name && parser.parseOptionalGreater().succeeded()) {
442 UnionType type = UnionType::getChecked(eLoc, context, name);
443 if (succeeded(parser.tryStartCyclicParse(type))) {
444 parser.emitError(loc, "invalid self-reference within record");
445 return {};
446 }
447 return type;
448 }
449
450 // Named definition.
451 if (name) {
452 UnionType type = UnionType::getChecked(eLoc, context, name);
453 cyclicParseGuard = parser.tryStartCyclicParse(type);
454 if (failed(cyclicParseGuard)) {
455 parser.emitError(loc, "record already defined");
456 return {};
457 }
458 }
459
460 if (parser.parseOptionalKeyword("packed").succeeded())
461 packed = true;
462
463 bool incomplete = true;
464 llvm::SmallVector<mlir::Type> members;
465 llvm::SmallVector<RecordMemberKind> memberKinds;
466 if (parseRecordBody(parser, incomplete, members, memberKinds).failed())
467 return {};
468
469 // Optional tail-padding slot: ", padding = { <type> }". It is not a variant
470 // and so takes no mark.
471 if (!incomplete && parser.parseOptionalComma().succeeded()) {
472 if (parser.parseKeyword("padding").failed())
473 return {};
474 if (parser.parseEqual().failed())
475 return {};
476 if (parser.parseLBrace().failed())
477 return {};
478 const llvm::SMLoc paddingLoc = parser.getCurrentLocation();
479 llvm::StringRef paddingKeyword;
480 if (parser.parseOptionalKeyword(&paddingKeyword, memberKindMarks)
481 .succeeded()) {
482 parser.emitError(paddingLoc, "a union's tail padding takes no kind mark");
483 return {};
484 }
485 if (parser.parseType(padding).failed())
486 return {};
487 if (parser.parseRBrace().failed())
488 return {};
489 }
490
491 if (parser.parseGreater())
492 return {};
493
494 ArrayRef<mlir::Type> membersRef(members);
495 ArrayRef<RecordMemberKind> kindsRef(memberKinds);
496 mlir::Type type = {};
497 if (name && incomplete) {
498 type = UnionType::getChecked(eLoc, context, name);
499 } else if (!name && !incomplete) {
500 type = UnionType::getChecked(eLoc, context, membersRef, packed, padding,
501 kindsRef);
502 if (!type)
503 return {};
504 } else if (!incomplete) {
505 type = UnionType::getChecked(eLoc, context, membersRef, name, packed,
506 padding, kindsRef);
507 if (!type)
508 return {};
509 if (auto unionTy = mlir::dyn_cast<UnionType>(type)) {
510 if (failed(unionTy.mutate(membersRef, packed, padding, kindsRef))) {
511 parser.emitError(loc, "record '")
512 << name.getValue() << "' redefined with a different body";
513 return {};
514 }
515 }
517 } else {
518 parser.emitError(loc, "anonymous records must be complete");
519 return {};
520 }
521
522 return type;
523}
524
525void UnionType::print(mlir::AsmPrinter &printer) const {
526 printRecordBody(printer, *this, getName(), /*hasClassPrefix=*/false,
527 getPacked(), isIncomplete(), getMembers(), getPadding(),
528 getMemberKinds());
529}
530
531mlir::LogicalResult
532UnionType::verify(function_ref<mlir::InFlightDiagnostic()> emitError,
533 llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name,
534 bool incomplete, bool packed, mlir::Type padding,
535 llvm::ArrayRef<RecordMemberKind> member_kinds) {
536 if (name && name.getValue().empty())
537 return emitError() << "identified records cannot have an empty name";
538 // A union's variants all start at offset zero, so there is no inter-member
539 // padding for a pad mark to describe. Its tail padding lives in the separate
540 // padding slot.
541 if (llvm::is_contained(member_kinds, RecordMemberKind::Pad))
542 return emitError() << "a union member cannot be marked pad";
543 if (failed(verifyRecordMemberTypes(emitError, members)))
544 return mlir::failure();
545 // CIRGen pads a union's tail with a char or an array of chars.
546 if (padding) {
547 mlir::Type charTy = padding;
548 if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(padding))
549 charTy = arrTy.getElementType();
550 auto intTy = mlir::dyn_cast<cir::IntType>(charTy);
551 if (!intTy || intTy.getWidth() != 8 || intTy.isSigned() || intTy.isBitInt())
552 return emitError()
553 << "union padding must be !u8i or an array of !u8i, got "
554 << padding;
555 }
556 // Every variant starts at offset zero, so a bit-field variant is an access
557 // unit of its own. There is no run for a zero-width bit-field to end, so a
558 // variant always has storage.
559 for (auto [idx, memberTy] : llvm::enumerate(members))
560 if (auto bfTy = mlir::dyn_cast<cir::BitFieldType>(memberTy);
561 bfTy && !bfTy.ownsBytes())
562 return emitError() << "union bit-field member at index " << idx
563 << " must own its access unit storage";
564 return verifyRecordMemberKinds(emitError, members.size(), member_kinds);
565}
566
567// Accessors.
568llvm::ArrayRef<mlir::Type> UnionType::getMembers() const {
569 return getImpl()->members;
570}
571mlir::StringAttr UnionType::getName() const { return getImpl()->name; }
572bool UnionType::isIncomplete() const { return getImpl()->incomplete; }
573bool UnionType::getIncomplete() const { return getImpl()->incomplete; }
574bool UnionType::getPacked() const { return getImpl()->packed; }
575bool UnionType::getPadded() const { return getPadding() ? true : false; }
576mlir::Type UnionType::getPadding() const { return getImpl()->padding; }
577llvm::ArrayRef<RecordMemberKind> UnionType::getMemberKinds() const {
578 return getImpl()->member_kinds;
579}
580
581bool UnionType::isABIConvertedRecord() const {
582 return getName() && getName().getValue().starts_with(abi_conversion_prefix);
583}
584
585mlir::StringAttr UnionType::getABIConvertedName() const {
586 assert(!isABIConvertedRecord());
587 return StringAttr::get(getContext(),
588 abi_conversion_prefix + getName().getValue());
589}
590
591void UnionType::removeABIConversionNamePrefix() {
592 mlir::StringAttr recordName = getName();
593 if (recordName && recordName.getValue().starts_with(abi_conversion_prefix))
594 getImpl()->name = mlir::StringAttr::get(
595 recordName.getValue().drop_front(sizeof(abi_conversion_prefix) - 1),
596 recordName.getType());
597}
598
599void UnionType::complete(ArrayRef<Type> members, bool packed,
600 mlir::Type padding,
601 ArrayRef<RecordMemberKind> memberKinds) {
603 // mutate() bypasses the verifier, so check what get() would have checked.
604 assert(succeeded(verifyInvariants(
605 mlir::detail::getDefaultDiagnosticEmitFn(getContext()), members,
606 getName(), /*incomplete=*/false, packed, padding, memberKinds)) &&
607 "invalid union completion");
608 if (mutate(members, packed, padding, memberKinds).failed())
609 llvm_unreachable("failed to complete union");
610}
611
612mlir::Type
613UnionType::getUnionStorageType(const mlir::DataLayout &dataLayout) const {
614 return getUnionStorageType(dataLayout, getMembers());
615}
616
617mlir::Type UnionType::getUnionStorageType(const mlir::DataLayout &dataLayout,
618 llvm::ArrayRef<mlir::Type> members) {
619 if (members.empty())
620 return {};
621 mlir::Type largest = *std::max_element(
622 members.begin(), members.end(), [&](mlir::Type lhs, mlir::Type rhs) {
623 return dataLayout.getTypeABIAlignment(lhs) <
624 dataLayout.getTypeABIAlignment(rhs) ||
625 (dataLayout.getTypeABIAlignment(lhs) ==
626 dataLayout.getTypeABIAlignment(rhs) &&
627 dataLayout.getTypeAllocSize(lhs) <
628 dataLayout.getTypeAllocSize(rhs));
629 });
630 // A union's storage is bytes, and stands in for every variant rather than
631 // for the one bit-field that happened to be widest, so a bit-field variant
632 // contributes its access unit rather than itself.
633 return memberStorageType(largest);
634}
635
636bool UnionType::isLayoutIdentical(const UnionType &other) {
637 if (getImpl() == other.getImpl())
638 return true;
639 return getMembers() == other.getMembers() &&
640 getPadding() == other.getPadding();
641}
642
643//===----------------------------------------------------------------------===//
644// RecordType view-class method implementations
645//===----------------------------------------------------------------------===//
646
648 if (auto s = mlir::dyn_cast<StructType>(*this))
649 return s.getMembers();
650 return mlir::cast<UnionType>(*this).getMembers();
651}
652mlir::StringAttr RecordType::getName() const {
653 if (auto s = mlir::dyn_cast<StructType>(*this))
654 return s.getName();
655 return mlir::cast<UnionType>(*this).getName();
656}
658 if (auto s = mlir::dyn_cast<StructType>(*this))
659 return s.isIncomplete();
660 return mlir::cast<UnionType>(*this).isIncomplete();
661}
663 if (auto s = mlir::dyn_cast<StructType>(*this))
664 return s.getPacked();
665 return mlir::cast<UnionType>(*this).getPacked();
666}
668 if (auto s = mlir::dyn_cast<StructType>(*this))
669 return s.getPadded();
670 return mlir::cast<UnionType>(*this).getPadded();
671}
673 if (auto s = mlir::dyn_cast<StructType>(*this))
674 return s.getMemberKinds();
675 return mlir::cast<UnionType>(*this).getMemberKinds();
676}
678 if (auto s = mlir::dyn_cast<StructType>(*this))
679 return s.isClass();
680 return false;
681}
683 if (auto s = mlir::dyn_cast<StructType>(*this))
684 return s.isStruct();
685 return false;
686}
687std::string RecordType::getKindAsStr() const {
688 if (mlir::isa<UnionType>(*this))
689 return "union";
690 return mlir::cast<StructType>(*this).getKindAsStr();
691}
692std::string RecordType::getPrefixedName() const {
693 return getKindAsStr() + "." + getName().getValue().str();
694}
695void RecordType::complete(ArrayRef<Type> members, bool packed,
696 mlir::Type padding,
697 ArrayRef<RecordMemberKind> memberKinds) {
698 if (auto s = mlir::dyn_cast<StructType>(*this)) {
699 assert(!padding && "only a union takes a separate padding slot");
700 return s.complete(members, packed, memberKinds);
701 }
702 return mlir::cast<UnionType>(*this).complete(members, packed, padding,
703 memberKinds);
704}
705uint64_t RecordType::getElementOffset(const mlir::DataLayout &dataLayout,
706 unsigned idx) const {
707 if (mlir::isa<UnionType>(*this))
708 return 0;
709 return mlir::cast<StructType>(*this).getElementOffset(dataLayout, idx);
710}
712 if (auto s = mlir::dyn_cast<StructType>(*this)) {
713 if (auto so = mlir::dyn_cast<StructType>(other))
714 return s.isLayoutIdentical(so);
715 return false;
716 }
717 if (auto u = mlir::dyn_cast<UnionType>(*this)) {
718 if (auto uo = mlir::dyn_cast<UnionType>(other))
719 return u.isLayoutIdentical(uo);
720 return false;
721 }
722 return false;
723}
725 if (auto s = mlir::dyn_cast<StructType>(*this))
726 return s.isABIConvertedRecord();
727 return mlir::cast<UnionType>(*this).isABIConvertedRecord();
728}
729mlir::StringAttr RecordType::getABIConvertedName() const {
730 if (auto s = mlir::dyn_cast<StructType>(*this))
731 return s.getABIConvertedName();
732 return mlir::cast<UnionType>(*this).getABIConvertedName();
733}
735 if (auto s = mlir::dyn_cast<StructType>(*this))
736 return s.removeABIConversionNamePrefix();
737 return mlir::cast<UnionType>(*this).removeABIConversionNamePrefix();
738}
739
741 // An incomplete record has no members yet, which must not read as vacuously
742 // holding no data.
743 if (isIncomplete())
744 return false;
746 return false;
747 // An access unit of nothing but unnamed bit-fields is marked `empty`, since
748 // no field of the source reads it, but it is still storage that holds data
749 // for the ABI. This has to answer the way CIRGen's isEmptyFieldForABI does,
750 // which is where that rule lives.
751 return llvm::none_of(getMembers(), [](mlir::Type memberTy) {
752 auto bfTy = mlir::dyn_cast<cir::BitFieldType>(memberTy);
753 return bfTy && bfTy.ownsBytes();
754 });
755}
756
757//===----------------------------------------------------------------------===//
758// Data Layout information for types
759//===----------------------------------------------------------------------===//
760
761// The cir.ptr data-layout entry holds a #cir.ptr_spec attribute (see
762// cir::setMLIRDataLayout).
763namespace {
764constexpr static uint64_t kBitsInByte = 8;
765
766// Defaults used when the module carries no cir.ptr data-layout entry.
767constexpr static uint64_t kDefaultPointerSizeBits = 64;
768constexpr static uint64_t kDefaultPointerAlignment = 8;
769
770/// Returns the default-address-space #cir.ptr_spec entry, or a synthesized
771/// 64-bit default when there is none. Per-AS entries are not modeled yet.
772cir::PtrSpecAttr getPointerSpec(mlir::DataLayoutEntryListRef params,
773 cir::PointerType type) {
774 // FIXME: improve this in face of address spaces
776 for (mlir::DataLayoutEntryInterface entry : params) {
777 if (!entry.isTypeEntry())
778 continue;
779 auto key =
780 mlir::cast<cir::PointerType>(mlir::cast<mlir::Type>(entry.getKey()));
781 if (key.getAddrSpace())
782 continue;
783 if (auto spec = mlir::dyn_cast<cir::PtrSpecAttr>(entry.getValue()))
784 return spec;
785 }
786 return cir::PtrSpecAttr::get(type.getContext(), kDefaultPointerSizeBits,
787 kDefaultPointerAlignment * kBitsInByte,
788 kDefaultPointerAlignment * kBitsInByte,
789 kDefaultPointerSizeBits);
790}
791} // namespace
792
793llvm::TypeSize
794PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
795 ::mlir::DataLayoutEntryListRef params) const {
796 return llvm::TypeSize::getFixed(getPointerSpec(params, *this).getSize());
797}
798
800PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
801 ::mlir::DataLayoutEntryListRef params) const {
802 return getPointerSpec(params, *this).getAbi() / kBitsInByte;
803}
804
805uint64_t PointerType::getPreferredAlignment(
806 const ::mlir::DataLayout &dataLayout,
807 ::mlir::DataLayoutEntryListRef params) const {
808 return getPointerSpec(params, *this).getPreferred() / kBitsInByte;
809}
810
811std::optional<uint64_t>
812PointerType::getIndexBitwidth(const ::mlir::DataLayout &dataLayout,
813 ::mlir::DataLayoutEntryListRef params) const {
814 cir::PtrSpecAttr spec = getPointerSpec(params, *this);
815 if (spec.getIndex() == cir::PtrSpecAttr::kOptionalSpecValue)
816 return spec.getSize();
817 return spec.getIndex();
818}
819
820llvm::LogicalResult
821PointerType::verifyEntries(mlir::DataLayoutEntryListRef entries,
822 mlir::Location loc) const {
823 for (mlir::DataLayoutEntryInterface entry : entries) {
824 if (!entry.isTypeEntry())
825 continue;
826 auto key = mlir::cast<PointerType>(mlir::cast<mlir::Type>(entry.getKey()));
827 if (!mlir::isa<cir::PtrSpecAttr>(entry.getValue()))
828 return mlir::emitError(loc) << "expected layout attribute for " << key
829 << " to be a #cir.ptr_spec attribute";
830 if (!mlir::isa<cir::VoidType>(key.getPointee()))
831 return mlir::emitError(loc) << "expected !cir.ptr data layout entry for "
832 << key << " to use !cir.void as pointee";
833 // Per-address-space pointer layouts are not supported yet.
834 if (key.getAddrSpace())
835 return mlir::emitError(loc)
836 << "!cir.ptr data layout entries are currently limited to the "
837 "default address space";
838 }
839 return mlir::success();
840}
841
842bool PointerType::areCompatible(
843 mlir::DataLayoutEntryListRef oldLayout,
844 mlir::DataLayoutEntryListRef newLayout, mlir::DataLayoutSpecInterface,
845 const mlir::DataLayoutIdentifiedEntryMap &) const {
846 // A nested spec may only override with the same size and a compatible ABI
847 // alignment. TODO(cir): match by address space once per-AS specs exist.
848 cir::PtrSpecAttr oldSpec = getPointerSpec(oldLayout, *this);
849 uint64_t size = oldSpec.getSize();
850 uint64_t abi = oldSpec.getAbi();
851 for (mlir::DataLayoutEntryInterface newEntry : newLayout) {
852 if (!newEntry.isTypeEntry())
853 continue;
854 auto newSpec = mlir::cast<cir::PtrSpecAttr>(newEntry.getValue());
855 if (size != newSpec.getSize() || abi < newSpec.getAbi() ||
856 abi % newSpec.getAbi() != 0)
857 return false;
858 }
859 return true;
860}
861
862llvm::TypeSize
863StructType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
864 mlir::DataLayoutEntryListRef params) const {
865 auto recordSize = static_cast<uint64_t>(computeStructSize(dataLayout));
866 return llvm::TypeSize::getFixed(recordSize * 8);
867}
868
870StructType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
871 ::mlir::DataLayoutEntryListRef params) const {
872 // Packed structures always have an ABI alignment of 1.
873 if (getPacked())
874 return 1;
875 return computeStructAlignment(dataLayout);
876}
877
878// Sums the storage member's alloc size (if present) with the padding field's
879// size (if present).
880// A union whose member list came out empty has no storage type, so its whole
881// size lives in the padding, which lowerUnion sizes from the ASTRecordLayout.
882llvm::TypeSize
883UnionType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
884 mlir::DataLayoutEntryListRef params) const {
885 llvm::TypeSize size = llvm::TypeSize::getFixed(0);
886 if (mlir::Type storage = getUnionStorageType(dataLayout))
887 size += dataLayout.getTypeAllocSize(storage) * 8;
888 if (mlir::Type pad = getPadding())
889 size += dataLayout.getTypeSizeInBits(pad);
890 return size;
891}
892
894UnionType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
895 ::mlir::DataLayoutEntryListRef params) const {
896 if (getPacked())
897 return 1;
898 mlir::Type storage = getUnionStorageType(dataLayout);
899 if (!storage)
900 return 1;
901 return dataLayout.getTypeABIAlignment(storage);
902}
903
904unsigned
905StructType::computeStructSize(const mlir::DataLayout &dataLayout) const {
906 assert(isComplete() && "Cannot get layout of incomplete records");
907
908 // This is a similar algorithm to LLVM's StructLayout. A member that owns no
909 // bytes needs no special case: it reports size 0 and alignment 1, so the
910 // running size passes over it unchanged.
911 unsigned recordSize = 0;
912 uint64_t recordAlignment = 1;
913
914 for (mlir::Type ty : getMembers()) {
915 // This assumes that we're calculating size based on the ABI alignment, not
916 // the preferred alignment for each type.
917 const uint64_t tyAlign =
918 (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
919
920 // Add padding to the struct size to align it to the abi alignment of the
921 // element type before adding the element's alloc size.
922 recordSize = llvm::alignTo(recordSize, tyAlign);
923 recordSize += dataLayout.getTypeAllocSize(ty);
924
925 // The alignment requirement of a struct is equal to the strictest
926 // alignment requirement of its elements.
927 recordAlignment = std::max(tyAlign, recordAlignment);
928 }
929
930 // At the end, add padding to the struct to satisfy its own alignment
931 // requirement. Otherwise structs inside of arrays would be misaligned.
932 recordSize = llvm::alignTo(recordSize, recordAlignment);
933 return recordSize;
934}
935
936unsigned
937StructType::computeStructDataSize(const mlir::DataLayout &dataLayout) const {
938 assert(isComplete() && "Cannot get layout of incomplete records");
939
940 // Tail padding is the trailing run of pad members, which is what a derived
941 // class may reuse. A member that owns no bytes holds no storage, so it does
942 // not end that run. A member of any other kind stays inside the data size.
943 llvm::ArrayRef<mlir::Type> members = getMembers();
944 llvm::ArrayRef<RecordMemberKind> kinds = getMemberKinds();
945 assert(kinds.size() == members.size() &&
946 "the two drop_back calls below must stay in step");
947 while (!kinds.empty() && (kinds.back() == RecordMemberKind::Pad ||
948 !memberOwnsBytes(members.back()))) {
949 kinds = kinds.drop_back();
950 members = members.drop_back();
951 }
952
953 unsigned recordSize = 0;
954 for (mlir::Type ty : members) {
955 const uint64_t tyAlign =
956 (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
957 recordSize = llvm::alignTo(recordSize, tyAlign);
958 recordSize += dataLayout.getTypeAllocSize(ty);
959 }
960 return recordSize;
961}
962
963// We also compute the alignment as part of computeStructSize, but this is more
964// efficient. Ideally, we'd like to compute both at once and cache the result,
965// but that's not implemented yet.
966// TODO(CIR): Implement a way to cache the result.
968StructType::computeStructAlignment(const mlir::DataLayout &dataLayout) const {
969 assert(isComplete() && "Cannot get layout of incomplete records");
970
971 uint64_t recordAlignment = 1;
972 for (mlir::Type ty : getMembers())
973 recordAlignment =
974 std::max(dataLayout.getTypeABIAlignment(ty), recordAlignment);
975 return recordAlignment;
976}
977
978unsigned StructType::getLLVMFieldIndex(unsigned idx) const {
979 llvm::ArrayRef<mlir::Type> members = getMembers();
980 assert(idx < members.size() && "access not valid");
981 assert(memberOwnsBytes(members[idx]) &&
982 "a member that owns no bytes has no LLVM field");
983
984 unsigned llvmIdx = 0;
985 for (unsigned i = 0; i != idx; ++i)
986 if (memberOwnsBytes(members[i]))
987 ++llvmIdx;
988 return llvmIdx;
989}
990
991uint64_t StructType::getElementOffset(const ::mlir::DataLayout &dataLayout,
992 unsigned idx) const {
993 assert(idx < getMembers().size() && "access not valid");
994 if (idx == 0)
995 return 0;
996
997 assert(isComplete() && "Cannot get layout of incomplete records");
998 llvm::ArrayRef<mlir::Type> members = getMembers();
999
1000 // A zero-width bit-field reports alignment 1 and size 0, so the running
1001 // offset passes over it unchanged and lands on where the storage ahead of it
1002 // ends, which is the offset it was declared at.
1003 unsigned offset = 0;
1004 for (unsigned i = 0; i != idx; ++i) {
1005 const llvm::Align tyAlign = llvm::Align(
1006 getPacked() ? 1 : dataLayout.getTypeABIAlignment(members[i]));
1007 offset = llvm::alignTo(offset, tyAlign);
1008 offset += dataLayout.getTypeAllocSize(members[i]);
1009 }
1010
1011 const llvm::Align tyAlign = llvm::Align(
1012 getPacked() ? 1 : dataLayout.getTypeABIAlignment(members[idx]));
1013 return llvm::alignTo(offset, tyAlign);
1014}
1015
1016//===----------------------------------------------------------------------===//
1017// IntType Definitions
1018//===----------------------------------------------------------------------===//
1019
1020Type IntType::parse(mlir::AsmParser &parser) {
1021 mlir::MLIRContext *context = parser.getBuilder().getContext();
1022 llvm::SMLoc loc = parser.getCurrentLocation();
1023 bool isSigned;
1024 unsigned width;
1025
1026 if (parser.parseLess())
1027 return {};
1028
1029 // Fetch integer sign.
1030 llvm::StringRef sign;
1031 if (parser.parseKeyword(&sign))
1032 return {};
1033 if (sign == "s")
1034 isSigned = true;
1035 else if (sign == "u")
1036 isSigned = false;
1037 else {
1038 parser.emitError(loc, "expected 's' or 'u'");
1039 return {};
1040 }
1041
1042 if (parser.parseComma())
1043 return {};
1044
1045 // Fetch integer size.
1046 if (parser.parseInteger(width))
1047 return {};
1048 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
1049 parser.emitError(loc, "expected integer width to be from ")
1050 << IntType::minBitwidth() << " up to " << IntType::maxBitwidth();
1051 return {};
1052 }
1053
1054 bool isBitInt = false;
1055 if (succeeded(parser.parseOptionalComma())) {
1056 llvm::StringRef kw;
1057 if (parser.parseKeyword(&kw) || kw != "bitint") {
1058 parser.emitError(loc, "expected 'bitint'");
1059 return {};
1060 }
1061 isBitInt = true;
1062 }
1063
1064 if (parser.parseGreater())
1065 return {};
1066
1067 return IntType::get(context, width, isSigned, isBitInt);
1068}
1069
1070void IntType::print(mlir::AsmPrinter &printer) const {
1071 char sign = isSigned() ? 's' : 'u';
1072 printer << '<' << sign << ", " << getWidth();
1073 if (isBitInt())
1074 printer << ", bitint";
1075 printer << '>';
1076}
1077
1078llvm::TypeSize
1079IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1080 mlir::DataLayoutEntryListRef params) const {
1081 return llvm::TypeSize::getFixed(getStorageTypeWidth(dataLayout));
1082}
1083
1084unsigned
1085IntType::getStorageTypeWidth(const mlir::DataLayout &dataLayout) const {
1086 if (!isBitInt())
1087 return getWidth();
1088 uint64_t alignBits = getABIAlignment(dataLayout, {}) * 8;
1089 return static_cast<unsigned>(llvm::alignTo(getWidth(), alignBits));
1090}
1091
1093IntType::getStorageTypeAlignment(const mlir::DataLayout &dataLayout) const {
1094 if (!isBitInt())
1095 return getABIAlignment(dataLayout, {});
1096 auto storageTy =
1097 mlir::IntegerType::get(getContext(), getStorageTypeWidth(dataLayout));
1098 return dataLayout.getTypeABIAlignment(storageTy);
1099}
1100
1101uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
1102 mlir::DataLayoutEntryListRef params) const {
1103 unsigned width = getWidth();
1104 if (isBitInt()) {
1105 // _BitInt alignment: min(PowerOf2Ceil(width), 64 bits) in bytes.
1106 // Matches Clang's TargetInfo::getBitIntAlign with default max = 64.
1107 uint64_t alignBits =
1108 std::min(llvm::PowerOf2Ceil(width), static_cast<uint64_t>(64));
1109 return std::max(alignBits / 8, static_cast<uint64_t>(1));
1110 }
1111 // Round up to a power-of-two byte alignment. DataLayout consumers such as
1112 // llvm::Align require power-of-two alignments, and width / 8 is not a power
1113 // of two for non-fundamental widths (e.g. i24 -> 3). This leaves the
1114 // fundamental widths unchanged (i8 -> 1, i16 -> 2, i32 -> 4, i64 -> 8) and
1115 // keeps __int128 at 16.
1116 uint64_t alignBits = llvm::PowerOf2Ceil(width);
1117 return std::max(alignBits / 8, static_cast<uint64_t>(1));
1118}
1119
1120mlir::LogicalResult
1121IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1122 unsigned width, bool isSigned, bool isBitInt) {
1123 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth())
1124 return emitError() << "IntType only supports widths from "
1125 << IntType::minBitwidth() << " up to "
1126 << IntType::maxBitwidth();
1127 return mlir::success();
1128}
1129
1131 return width == 8 || width == 16 || width == 32 || width == 64;
1132}
1133
1134//===----------------------------------------------------------------------===//
1135// Floating-point type definitions
1136//===----------------------------------------------------------------------===//
1137
1138const llvm::fltSemantics &SingleType::getFloatSemantics() const {
1139 return llvm::APFloat::IEEEsingle();
1140}
1141
1142llvm::TypeSize
1143SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1144 mlir::DataLayoutEntryListRef params) const {
1145 return llvm::TypeSize::getFixed(getWidth());
1146}
1147
1149SingleType::getABIAlignment(const mlir::DataLayout &dataLayout,
1150 mlir::DataLayoutEntryListRef params) const {
1151 return (uint64_t)(getWidth() / 8);
1152}
1153
1154const llvm::fltSemantics &DoubleType::getFloatSemantics() const {
1155 return llvm::APFloat::IEEEdouble();
1156}
1157
1158llvm::TypeSize
1159DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1160 mlir::DataLayoutEntryListRef params) const {
1161 return llvm::TypeSize::getFixed(getWidth());
1162}
1163
1165DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
1166 mlir::DataLayoutEntryListRef params) const {
1167 return (uint64_t)(getWidth() / 8);
1168}
1169
1170const llvm::fltSemantics &FP16Type::getFloatSemantics() const {
1171 return llvm::APFloat::IEEEhalf();
1172}
1173
1174llvm::TypeSize
1175FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1176 mlir::DataLayoutEntryListRef params) const {
1177 return llvm::TypeSize::getFixed(getWidth());
1178}
1179
1180uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
1181 mlir::DataLayoutEntryListRef params) const {
1182 return (uint64_t)(getWidth() / 8);
1183}
1184
1185const llvm::fltSemantics &BF16Type::getFloatSemantics() const {
1186 return llvm::APFloat::BFloat();
1187}
1188
1189llvm::TypeSize
1190BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1191 mlir::DataLayoutEntryListRef params) const {
1192 return llvm::TypeSize::getFixed(getWidth());
1193}
1194
1195uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
1196 mlir::DataLayoutEntryListRef params) const {
1197 return (uint64_t)(getWidth() / 8);
1198}
1199
1200const llvm::fltSemantics &FP80Type::getFloatSemantics() const {
1201 return llvm::APFloat::x87DoubleExtended();
1202}
1203
1204llvm::TypeSize
1205FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1206 mlir::DataLayoutEntryListRef params) const {
1207 // Though only 80 bits are used for the value, the type is 128 bits in size.
1208 return llvm::TypeSize::getFixed(128);
1209}
1210
1211uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout,
1212 mlir::DataLayoutEntryListRef params) const {
1213 return 16;
1214}
1215
1216const llvm::fltSemantics &FP128Type::getFloatSemantics() const {
1217 return llvm::APFloat::IEEEquad();
1218}
1219
1220llvm::TypeSize
1221FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1222 mlir::DataLayoutEntryListRef params) const {
1223 return llvm::TypeSize::getFixed(getWidth());
1224}
1225
1226uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout,
1227 mlir::DataLayoutEntryListRef params) const {
1228 return 16;
1229}
1230
1231const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const {
1232 return mlir::cast<cir::FPTypeInterface>(getUnderlying()).getFloatSemantics();
1233}
1234
1235llvm::TypeSize
1236LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1237 mlir::DataLayoutEntryListRef params) const {
1238 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
1239 .getTypeSizeInBits(dataLayout, params);
1240}
1241
1243LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
1244 mlir::DataLayoutEntryListRef params) const {
1245 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
1246 .getABIAlignment(dataLayout, params);
1247}
1248
1249//===----------------------------------------------------------------------===//
1250// ComplexType Definitions
1251//===----------------------------------------------------------------------===//
1252
1253llvm::TypeSize
1254cir::ComplexType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1255 mlir::DataLayoutEntryListRef params) const {
1256 // C17 6.2.5p13:
1257 // Each complex type has the same representation and alignment requirements
1258 // as an array type containing exactly two elements of the corresponding
1259 // real type.
1260
1261 return dataLayout.getTypeSizeInBits(getElementType()) * 2;
1262}
1263
1265cir::ComplexType::getABIAlignment(const mlir::DataLayout &dataLayout,
1266 mlir::DataLayoutEntryListRef params) const {
1267 // C17 6.2.5p13:
1268 // Each complex type has the same representation and alignment requirements
1269 // as an array type containing exactly two elements of the corresponding
1270 // real type.
1271
1272 return dataLayout.getTypeABIAlignment(getElementType());
1273}
1274
1275FuncType FuncType::clone(TypeRange inputs, TypeRange results) const {
1276 assert(results.size() == 1 && "expected exactly one result type");
1277 return get(llvm::to_vector(inputs), results[0], isVarArg());
1278}
1279
1280// Custom parser that parses function parameters of form `(<type>*, ...)`.
1281static mlir::ParseResult
1283 bool &isVarArg) {
1284 isVarArg = false;
1285 return p.parseCommaSeparatedList(
1286 AsmParser::Delimiter::Paren, [&]() -> mlir::ParseResult {
1287 if (isVarArg)
1288 return p.emitError(p.getCurrentLocation(),
1289 "variadic `...` must be the last parameter");
1290 if (succeeded(p.parseOptionalEllipsis())) {
1291 isVarArg = true;
1292 return success();
1293 }
1294 mlir::Type type;
1295 if (failed(p.parseType(type)))
1296 return failure();
1297 params.push_back(type);
1298 return success();
1299 });
1300}
1301
1302static void printFuncTypeParams(mlir::AsmPrinter &p,
1303 mlir::ArrayRef<mlir::Type> params,
1304 bool isVarArg) {
1305 p << '(';
1306 llvm::interleaveComma(params, p,
1307 [&p](mlir::Type type) { p.printType(type); });
1308 if (isVarArg) {
1309 if (!params.empty())
1310 p << ", ";
1311 p << "...";
1312 }
1313 p << ')';
1314}
1315
1316/// Get the C-style return type of the function, which is !cir.void if the
1317/// function returns nothing and the actual return type otherwise.
1318mlir::Type FuncType::getReturnType() const {
1319 if (hasVoidReturn())
1320 return cir::VoidType::get(getContext());
1321 return getOptionalReturnType();
1322}
1323
1324/// Get the MLIR-style return type of the function, which is an empty
1325/// ArrayRef if the function returns nothing and a single-element ArrayRef
1326/// with the actual return type otherwise.
1327llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const {
1328 if (hasVoidReturn())
1329 return {};
1330 // Can't use getOptionalReturnType() here because llvm::ArrayRef hold a
1331 // pointer to its elements and doesn't do lifetime extension. That would
1332 // result in returning a pointer to a temporary that has gone out of scope.
1333 return getImpl()->optionalReturnType;
1334}
1335
1336// Does the fuction type return nothing?
1337bool FuncType::hasVoidReturn() const { return !getOptionalReturnType(); }
1338
1339mlir::LogicalResult
1340FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1341 llvm::ArrayRef<mlir::Type> argTypes, mlir::Type returnType,
1342 bool isVarArg) {
1343 if (mlir::isa_and_nonnull<cir::VoidType>(returnType))
1344 return emitError()
1345 << "!cir.func cannot have an explicit 'void' return type";
1346
1347 // The calling convention lowering pass expects all types in a function
1348 // signature to be CIR types. CIR types only nest CIR types, so checking the
1349 // signature's own types covers everything reachable from them.
1350 if (!llvm::all_of(argTypes, cir::isCIRType) ||
1351 (returnType && !cir::isCIRType(returnType)))
1352 return emitError()
1353 << "expected all types in the function signature to be CIR types";
1354
1355 return mlir::success();
1356}
1357
1358//===----------------------------------------------------------------------===//
1359// MethodType Definitions
1360//===----------------------------------------------------------------------===//
1361
1362static mlir::Type getMethodLayoutType(mlir::MLIRContext *ctx) {
1363 // With Itanium ABI, member function pointers have the same layout as the
1364 // following struct: struct { fnptr_t, ptrdiff_t }, where fnptr_t is a
1365 // function pointer type.
1366 // TODO: consider member function pointer layout in other ABIs
1367 auto voidPtrTy = cir::PointerType::get(cir::VoidType::get(ctx));
1368 mlir::Type fields[2]{voidPtrTy, voidPtrTy};
1369 return cir::StructType::get(ctx, fields, /*packed=*/false,
1370 /*is_class=*/false,
1372}
1373
1374llvm::TypeSize
1375MethodType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1376 mlir::DataLayoutEntryListRef params) const {
1377 return dataLayout.getTypeSizeInBits(getMethodLayoutType(getContext()));
1378}
1379
1381MethodType::getABIAlignment(const mlir::DataLayout &dataLayout,
1382 mlir::DataLayoutEntryListRef params) const {
1383 return cast<cir::StructType>(getMethodLayoutType(getContext()))
1384 .getABIAlignment(dataLayout, params);
1385}
1386
1387//===----------------------------------------------------------------------===//
1388// BoolType
1389//===----------------------------------------------------------------------===//
1390
1391llvm::TypeSize
1392BoolType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
1393 ::mlir::DataLayoutEntryListRef params) const {
1394 return llvm::TypeSize::getFixed(8);
1395}
1396
1398BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1399 ::mlir::DataLayoutEntryListRef params) const {
1400 return 1;
1401}
1402
1403//===----------------------------------------------------------------------===//
1404// DataMemberType Definitions
1405//===----------------------------------------------------------------------===//
1406
1407static mlir::Type getDataMemberLayoutType(const mlir::DataLayout &dataLayout,
1408 mlir::MLIRContext *ctx) {
1409 // Itanium ABI: a data member pointer is a ptrdiff_t, an integer of the
1410 // pointer index width.
1411 // TODO: consider data member pointer layout in other ABIs
1412 auto voidPtrTy = cir::PointerType::get(cir::VoidType::get(ctx));
1413 uint64_t width = dataLayout.getTypeIndexBitwidth(voidPtrTy).value_or(
1414 dataLayout.getTypeSizeInBits(voidPtrTy).getFixedValue());
1415 return cir::IntType::get(ctx, width, /*is_signed=*/true);
1416}
1417
1418llvm::TypeSize
1419DataMemberType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
1420 ::mlir::DataLayoutEntryListRef params) const {
1421 assert(!MissingFeatures::cxxABI());
1422 return dataLayout.getTypeSizeInBits(
1423 getDataMemberLayoutType(dataLayout, getContext()));
1424}
1425
1427DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1428 ::mlir::DataLayoutEntryListRef params) const {
1429 assert(!MissingFeatures::cxxABI());
1430 return dataLayout.getTypeABIAlignment(
1431 getDataMemberLayoutType(dataLayout, getContext()));
1432}
1433
1434//===----------------------------------------------------------------------===//
1435// VPtrType Definitions
1436//===----------------------------------------------------------------------===//
1437
1438llvm::TypeSize
1439VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1440 mlir::DataLayoutEntryListRef params) const {
1441 // A vtable pointer is an ordinary data pointer; size it as a cir.ptr.
1442 return dataLayout.getTypeSizeInBits(
1443 cir::PointerType::get(cir::VoidType::get(getContext())));
1444}
1445
1446uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout,
1447 mlir::DataLayoutEntryListRef params) const {
1448 return dataLayout.getTypeABIAlignment(
1449 cir::PointerType::get(cir::VoidType::get(getContext())));
1450}
1451
1452//===----------------------------------------------------------------------===//
1453// ArrayType Definitions
1454//===----------------------------------------------------------------------===//
1455
1456llvm::TypeSize
1457ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
1458 ::mlir::DataLayoutEntryListRef params) const {
1459 return getSize() * dataLayout.getTypeAllocSize(getElementType()) * 8;
1460}
1461
1463ArrayType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1464 ::mlir::DataLayoutEntryListRef params) const {
1465 return dataLayout.getTypeABIAlignment(getElementType());
1466}
1467
1468//===----------------------------------------------------------------------===//
1469// BitFieldType Definitions
1470//===----------------------------------------------------------------------===//
1471
1472mlir::LogicalResult
1473BitFieldType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1474 mlir::Type storageType,
1475 llvm::ArrayRef<cir::BitFieldDeclAttr> fields) {
1476 if (fields.empty())
1477 return emitError() << "bit-field member must hold at least one bit-field";
1478
1479 if (!storageType) {
1480 // Absent storage is the zero-width bit-field, which belongs to no access
1481 // unit and so keeps company with nothing.
1482 if (fields.size() != 1 || fields.front().getWidth() != 0)
1483 return emitError() << "a bit-field member without storage must hold a "
1484 "single zero-width bit-field";
1485 return mlir::success();
1486 }
1487
1488 if (!cir::isCIRType(storageType))
1489 return emitError() << "bit-field access unit storage must be a CIR type, "
1490 "got "
1491 << storageType;
1492
1493 if (mlir::isa<cir::BitFieldType>(storageType))
1494 return emitError() << "bit-field access unit storage cannot itself be a "
1495 "bit-field type";
1496
1497 if (!cir::isSized(storageType))
1498 return emitError() << "bit-field access unit storage must be sized, got "
1499 << storageType;
1500
1501 // A zero-width bit-field ends the run before it rather than joining a unit,
1502 // so it never appears alongside the fields that occupy one.
1503 if (llvm::any_of(fields, [](cir::BitFieldDeclAttr decl) {
1504 return decl.getWidth() == 0;
1505 }))
1506 return emitError() << "a zero-width bit-field cannot occupy an access unit";
1507
1508 return mlir::success();
1509}
1510
1511llvm::TypeSize
1512BitFieldType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1513 mlir::DataLayoutEntryListRef params) const {
1514 // A unit is stored as its storage type. A zero-width bit-field has none,
1515 // and holds no bits of its own.
1516 if (mlir::Type storage = getStorageType())
1517 return dataLayout.getTypeSizeInBits(storage);
1518 return llvm::TypeSize::getFixed(0);
1519}
1520
1522BitFieldType::getABIAlignment(const mlir::DataLayout &dataLayout,
1523 mlir::DataLayoutEntryListRef params) const {
1524 // A member that occupies no bytes imposes no alignment, which is what lets
1525 // the record layout walk a zero-width bit-field without skipping it.
1526 if (mlir::Type storage = getStorageType())
1527 return dataLayout.getTypeABIAlignment(storage);
1528 return 1;
1529}
1530
1531//===----------------------------------------------------------------------===//
1532// VectorType Definitions
1533//===----------------------------------------------------------------------===//
1534
1535llvm::TypeSize cir::VectorType::getTypeSizeInBits(
1536 const ::mlir::DataLayout &dataLayout,
1537 ::mlir::DataLayoutEntryListRef params) const {
1538 // Clang packs a fixed-length bool vector one bit per element and rounds the
1539 // vector's size up to a power of two of at least a byte.
1540 if (mlir::isa<cir::BoolType>(getElementType()) && getSize().isFixed()) {
1541 assert(!cir::MissingFeatures::hlsl());
1542 return llvm::TypeSize::getFixed(llvm::PowerOf2Ceil(getBoolStorageWidth()));
1543 }
1544
1545 llvm::TypeSize elementSize = dataLayout.getTypeSizeInBits(getElementType());
1546 return llvm::TypeSize::get(
1547 getSize().getKnownMinValue() * elementSize.getFixedValue(), isScalable());
1548}
1549
1550uint64_t cir::VectorType::getBoolStorageWidth() const {
1551 assert(mlir::isa<cir::BoolType>(getElementType()) &&
1552 "only a bool vector is stored as an integer");
1553 return std::max<uint64_t>(getFixedSize(), 8);
1554}
1555
1557cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1558 ::mlir::DataLayoutEntryListRef params) const {
1559 // This hook answers in bytes, not bits.
1560 return llvm::PowerOf2Ceil(llvm::divideCeil(
1561 dataLayout.getTypeSizeInBits(*this).getKnownMinValue(), uint64_t{8}));
1562}
1563
1564mlir::LogicalResult cir::VectorType::verify(
1565 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1566 mlir::Type elementType, llvm::ElementCount size) {
1567 if (size.isZero())
1568 return emitError() << "the number of vector elements must be non-zero";
1569 return success();
1570}
1571
1572mlir::Type cir::VectorType::parse(::mlir::AsmParser &odsParser) {
1573
1574 llvm::SMLoc odsLoc = odsParser.getCurrentLocation();
1575 mlir::Builder odsBuilder(odsParser.getContext());
1576 mlir::FailureOr<::mlir::Type> elementType;
1577 mlir::FailureOr<uint64_t> size;
1578 bool isScalable = false;
1579
1580 // Parse literal '<'
1581 if (odsParser.parseLess())
1582 return {};
1583
1584 // Parse literal '[', if present, and set the scalability flag accordingly
1585 if (odsParser.parseOptionalLSquare().succeeded())
1586 isScalable = true;
1587
1588 // Parse variable 'size'
1589 size = mlir::FieldParser<uint64_t>::parse(odsParser);
1590 if (mlir::failed(size)) {
1591 odsParser.emitError(odsParser.getCurrentLocation(),
1592 "failed to parse CIR_VectorType parameter 'size' which "
1593 "is to be a `uint64_t`");
1594 return {};
1595 }
1596
1597 // Parse literal ']', which is expected when dealing with scalable
1598 // dim sizes
1599 if (isScalable && odsParser.parseRSquare().failed()) {
1600 odsParser.emitError(odsParser.getCurrentLocation(),
1601 "missing closing `]` for scalable dim size");
1602 return {};
1603 }
1604
1605 // Parse literal 'x'
1606 if (odsParser.parseKeyword("x"))
1607 return {};
1608
1609 // Parse variable 'elementType'
1610 elementType = mlir::FieldParser<::mlir::Type>::parse(odsParser);
1611 if (mlir::failed(elementType)) {
1612 odsParser.emitError(odsParser.getCurrentLocation(),
1613 "failed to parse CIR_VectorType parameter "
1614 "'elementType' which is to be a `mlir::Type`");
1615 return {};
1616 }
1617
1618 // Parse literal '>'
1619 if (odsParser.parseGreater())
1620 return {};
1621 return odsParser.getChecked<VectorType>(
1622 odsLoc, odsParser.getContext(), mlir::Type((*elementType)),
1623 llvm::ElementCount::get(*size, isScalable));
1624}
1625
1626void cir::VectorType::print(mlir::AsmPrinter &odsPrinter) const {
1627 mlir::Builder odsBuilder(getContext());
1628 odsPrinter << "<";
1629 if (isScalable())
1630 odsPrinter << "[";
1631
1632 odsPrinter.printStrippedAttrOrType(getSize().getKnownMinValue());
1633 if (isScalable())
1634 odsPrinter << "]";
1635 odsPrinter << ' ' << "x";
1636 odsPrinter << ' ';
1637 odsPrinter.printStrippedAttrOrType(getElementType());
1638 odsPrinter << ">";
1639}
1640
1641//===----------------------------------------------------------------------===//
1642// MatrixType Definitions
1643//===----------------------------------------------------------------------===//
1644
1645llvm::TypeSize cir::MatrixType::getTypeSizeInBits(
1646 const ::mlir::DataLayout &dataLayout,
1647 ::mlir::DataLayoutEntryListRef params) const {
1648 return llvm::TypeSize::getFixed(
1649 getNumRows() * getNumColumns() *
1650 dataLayout.getTypeSizeInBits(getElementType()));
1651}
1652
1654cir::MatrixType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1655 ::mlir::DataLayoutEntryListRef params) const {
1656 return dataLayout.getTypeABIAlignment(getElementType());
1657}
1658
1659mlir::LogicalResult cir::MatrixType::verify(
1660 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1661 mlir::Type elementType, uint64_t row, uint64_t column) {
1662 if (row == 0)
1663 return emitError() << "the number of matrix rows must be non-zero";
1664 if (column == 0)
1665 return emitError() << "the number of matrix columns must be non-zero";
1666 return success();
1667}
1668
1669//===----------------------------------------------------------------------===//
1670// AddressSpace definitions
1671//===----------------------------------------------------------------------===//
1672
1674 mlir::ptr::MemorySpaceAttrInterface memorySpace) {
1675 return mlir::isa<cir::LangAddressSpaceAttr, cir::TargetAddressSpaceAttr>(
1676 memorySpace);
1677}
1678
1679cir::LangAddressSpace cir::toCIRLangAddressSpace(clang::LangAS langAS) {
1680 using clang::LangAS;
1681 switch (langAS) {
1682 case LangAS::Default:
1683 return LangAddressSpace::Default;
1684 case LangAS::opencl_global:
1685 case LangAS::sycl_global:
1686 return LangAddressSpace::OffloadGlobal;
1687 case LangAS::opencl_local:
1688 case LangAS::cuda_shared:
1689 case LangAS::sycl_local:
1690 // Local means local among the work-group (OpenCL, SYCL) or block (CUDA).
1691 // All threads inside the kernel can access local memory.
1692 return LangAddressSpace::OffloadLocal;
1693 case LangAS::cuda_device:
1694 return LangAddressSpace::OffloadGlobal;
1695 case LangAS::opencl_constant:
1696 case LangAS::cuda_constant:
1697 case LangAS::sycl_constant:
1698 return LangAddressSpace::OffloadConstant;
1699 case LangAS::opencl_private:
1700 case LangAS::sycl_private:
1701 return LangAddressSpace::OffloadPrivate;
1702 case LangAS::opencl_generic:
1703 case LangAS::sycl_generic:
1704 return LangAddressSpace::OffloadGeneric;
1705 case LangAS::opencl_global_device:
1706 case LangAS::sycl_global_device:
1707 return LangAddressSpace::OffloadGlobalDevice;
1708 case LangAS::opencl_global_host:
1709 case LangAS::sycl_global_host:
1710 return LangAddressSpace::OffloadGlobalHost;
1711 case LangAS::ptr32_sptr:
1712 case LangAS::ptr32_uptr:
1713 case LangAS::ptr64:
1714 case LangAS::hlsl_groupshared:
1715 case LangAS::wasm_funcref:
1716 llvm_unreachable("NYI");
1717 default:
1718 llvm_unreachable("unknown/unsupported clang language address space");
1719 }
1720}
1721
1722mlir::ParseResult parseMemorySpace(mlir::AsmParser &p,
1723 mlir::ptr::MemorySpaceAttrInterface &attr) {
1724
1725 llvm::SMLoc loc = p.getCurrentLocation();
1726
1727 // Try to parse target address space first.
1728 attr = nullptr;
1729 if (p.parseOptionalKeyword("target_address_space").succeeded()) {
1730 unsigned val;
1731 if (p.parseLParen())
1732 return p.emitError(loc, "expected '(' after 'target_address_space'");
1733
1734 if (p.parseInteger(val))
1735 return p.emitError(loc, "expected target address space value");
1736
1737 if (p.parseRParen())
1738 return p.emitError(loc, "expected ')'");
1739
1740 attr = cir::TargetAddressSpaceAttr::get(p.getContext(), val);
1741 return mlir::success();
1742 }
1743
1744 // Try to parse language specific address space.
1745 if (p.parseOptionalKeyword("lang_address_space").succeeded()) {
1746 if (p.parseLParen())
1747 return p.emitError(loc, "expected '(' after 'lang_address_space'");
1748
1749 mlir::FailureOr<cir::LangAddressSpace> result =
1750 mlir::FieldParser<cir::LangAddressSpace>::parse(p);
1751 if (mlir::failed(result))
1752 return mlir::failure();
1753
1754 if (p.parseRParen())
1755 return p.emitError(loc, "expected ')'");
1756
1757 attr = cir::LangAddressSpaceAttr::get(p.getContext(), result.value());
1758 return mlir::success();
1759 }
1760
1761 llvm::StringRef keyword;
1762 if (p.parseOptionalKeyword(&keyword).succeeded())
1763 return p.emitError(loc, "unknown address space specifier '")
1764 << keyword << "'; expected 'target_address_space' or "
1765 << "'lang_address_space'";
1766
1767 return mlir::success();
1768}
1769
1770void printMemorySpace(mlir::AsmPrinter &p,
1771 mlir::ptr::MemorySpaceAttrInterface attr) {
1772 if (!attr)
1773 return;
1774
1775 if (auto language = dyn_cast<cir::LangAddressSpaceAttr>(attr)) {
1776 p << "lang_address_space("
1777 << cir::stringifyLangAddressSpace(language.getValue()) << ')';
1778 return;
1779 }
1780
1781 if (auto target = dyn_cast<cir::TargetAddressSpaceAttr>(attr)) {
1782 p << "target_address_space(" << target.getValue() << ')';
1783 return;
1784 }
1785
1786 llvm_unreachable("unexpected address-space attribute kind");
1787}
1788
1789mlir::OptionalParseResult
1790parseGlobalMemorySpace(mlir::AsmParser &p,
1791 mlir::ptr::MemorySpaceAttrInterface &attr) {
1792
1793 mlir::SMLoc loc = p.getCurrentLocation();
1794 if (parseMemorySpace(p, attr).failed())
1795 return p.emitError(loc, "failed to parse Address Space Value for GlobalOp");
1796 return mlir::success();
1797}
1798
1799void printGlobalMemorySpace(mlir::AsmPrinter &printer, cir::GlobalOp,
1800 mlir::ptr::MemorySpaceAttrInterface attr) {
1801 printMemorySpace(printer, attr);
1802}
1803
1804mlir::ptr::MemorySpaceAttrInterface cir::normalizeDefaultAddressSpace(
1805 mlir::ptr::MemorySpaceAttrInterface addrSpace) {
1806 if (auto langAS =
1807 mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace))
1808 if (langAS.getValue() == cir::LangAddressSpace::Default)
1809 return {};
1810 return addrSpace;
1811}
1812
1813mlir::ptr::MemorySpaceAttrInterface
1814cir::toCIRAddressSpaceAttr(mlir::MLIRContext &ctx, clang::LangAS langAS) {
1815 using clang::LangAS;
1816
1817 if (langAS == LangAS::Default)
1818 return cir::LangAddressSpaceAttr::get(&ctx, cir::LangAddressSpace::Default);
1819
1820 if (clang::isTargetAddressSpace(langAS)) {
1821 unsigned targetAS = clang::toTargetAddressSpace(langAS);
1822 return cir::TargetAddressSpaceAttr::get(&ctx, targetAS);
1823 }
1824
1825 return cir::LangAddressSpaceAttr::get(&ctx, toCIRLangAddressSpace(langAS));
1826}
1827
1828bool cir::isMatchingAddressSpace(mlir::ptr::MemorySpaceAttrInterface cirAS,
1829 clang::LangAS as) {
1830 cirAS = normalizeDefaultAddressSpace(cirAS);
1831 if (!cirAS)
1832 return as == clang::LangAS::Default;
1833 mlir::ptr::MemorySpaceAttrInterface expected = normalizeDefaultAddressSpace(
1834 toCIRAddressSpaceAttr(*cirAS.getContext(), as));
1835 return expected == cirAS;
1836}
1837
1838//===----------------------------------------------------------------------===//
1839// PointerType Definitions
1840//===----------------------------------------------------------------------===//
1841
1842mlir::LogicalResult cir::PointerType::verify(
1843 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1844 mlir::Type pointee, mlir::ptr::MemorySpaceAttrInterface addrSpace) {
1845 if (addrSpace) {
1846 if (!isSupportedCIRMemorySpaceAttr(addrSpace)) {
1847 return emitError() << "unsupported address space attribute; expected "
1848 "'target_address_space' or 'lang_address_space'";
1849 }
1850 }
1851
1852 return success();
1853}
1854
1855//===----------------------------------------------------------------------===//
1856// CIR Dialect
1857//===----------------------------------------------------------------------===//
1858
1859void CIRDialect::registerTypes() {
1860 // Register tablegen'd types.
1861 addTypes<
1862#define GET_TYPEDEF_LIST
1863#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
1864 >();
1865
1866 // Register raw C++ types.
1867 // TODO(CIR) addTypes<RecordType>();
1868}
Provides definitions for the various language-specific address spaces.
mlir::OptionalParseResult parseGlobalMemorySpace(mlir::AsmParser &p, mlir::ptr::MemorySpaceAttrInterface &attr)
void printGlobalMemorySpace(mlir::AsmPrinter &printer, cir::GlobalOp op, mlir::ptr::MemorySpaceAttrInterface attr)
mlir::ParseResult parseMemorySpace(mlir::AsmParser &p, mlir::ptr::MemorySpaceAttrInterface &attr)
static mlir::LogicalResult verifyRecordMemberTypes(function_ref< mlir::InFlightDiagnostic()> emitError, llvm::ArrayRef< mlir::Type > members)
Members must be CIR types other than void, which has no layout.
Definition CIRTypes.cpp:169
static const llvm::StringRef memberKindMarks[]
The keywords that spell a member kind.
Definition CIRTypes.cpp:184
static void printRecordBody(mlir::AsmPrinter &printer, RecordTy self, mlir::StringAttr name, bool hasClassPrefix, bool isPacked, bool isIncomplete, llvm::ArrayRef< mlir::Type > members, mlir::Type padding, llvm::ArrayRef< RecordMemberKind > memberKinds)
Print a complete CIR record body: '<' ['class '] [name] ['packed '] body '>' where body is "incomplet...
Definition CIRTypes.cpp:227
static mlir::LogicalResult verifyRecordMemberKinds(function_ref< mlir::InFlightDiagnostic()> emitError, size_t numMembers, llvm::ArrayRef< RecordMemberKind > memberKinds)
An incomplete record has no members, so a kind for one is caught by the same check.
Definition CIRTypes.cpp:158
static mlir::ParseResult parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector< mlir::Type > &params, bool &isVarArg)
void printMemorySpace(mlir::AsmPrinter &printer, mlir::ptr::MemorySpaceAttrInterface attr)
static mlir::Type getMethodLayoutType(mlir::MLIRContext *ctx)
static void printFuncTypeParams(mlir::AsmPrinter &p, mlir::ArrayRef< mlir::Type > params, bool isVarArg)
static mlir::ParseResult parseRecordBody(mlir::AsmParser &parser, bool &incomplete, llvm::SmallVector< mlir::Type > &members, llvm::SmallVectorImpl< RecordMemberKind > &memberKinds)
Parse "incomplete" or "{mark type, mark type, ...}", writing results into incomplete,...
Definition CIRTypes.cpp:203
static std::optional< RecordMemberKind > parseMemberKind(mlir::AsmParser &parser)
Definition CIRTypes.cpp:188
static mlir::Type getDataMemberLayoutType(const mlir::DataLayout &dataLayout, mlir::MLIRContext *ctx)
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 isLayoutIdentical(const RecordType &other)
Definition CIRTypes.cpp:711
bool isABIConvertedRecord() const
Definition CIRTypes.cpp:724
bool isIncomplete() const
Definition CIRTypes.cpp:657
bool isEmptyForABI() const
Whether no member holds data.
Definition CIRTypes.cpp:740
std::string getPrefixedName() const
Definition CIRTypes.cpp:692
llvm::ArrayRef< mlir::Type > getMembers() const
Definition CIRTypes.cpp:647
bool isClass() const
Definition CIRTypes.cpp:677
void removeABIConversionNamePrefix()
Definition CIRTypes.cpp:734
bool getPacked() const
Definition CIRTypes.cpp:662
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
Definition CIRTypes.cpp:150
RecordType(StructType t)
Definition CIRTypes.h:158
mlir::StringAttr getName() const
Definition CIRTypes.cpp:652
void complete(llvm::ArrayRef< mlir::Type > members, bool packed, mlir::Type padding, llvm::ArrayRef< RecordMemberKind > memberKinds)
padding is union-only.
Definition CIRTypes.cpp:695
mlir::StringAttr getABIConvertedName() const
Definition CIRTypes.cpp:729
std::string getKindAsStr() const
Definition CIRTypes.cpp:687
bool isStruct() const
Definition CIRTypes.cpp:682
bool getPadded() const
Definition CIRTypes.cpp:667
llvm::ArrayRef< RecordMemberKind > getMemberKinds() const
Definition CIRTypes.cpp:672
uint64_t getElementOffset(const mlir::DataLayout &dataLayout, unsigned idx) const
Definition CIRTypes.cpp:705
bool isMatchingAddressSpace(mlir::ptr::MemorySpaceAttrInterface cirAS, clang::LangAS as)
cir::LangAddressSpace toCIRLangAddressSpace(clang::LangAS langAS)
mlir::Type memberStorageType(mlir::Type memberTy)
The storage a member is stored as: the access unit for a bit-field member, and the member type itself...
Definition CIRTypes.h:135
bool memberOwnsBytes(mlir::Type memberTy)
Whether a record member occupies bytes of its record.
Definition CIRTypes.h:126
bool isValidFundamentalIntWidth(unsigned width)
cir::FPTypeInterface getFloatingPointType(const llvm::fltSemantics &sem, mlir::MLIRContext *ctx)
Returns the CIR floating-point type for the given semantics, or a null type if CIR has no type for it...
Definition CIRTypes.cpp:42
mlir::ptr::MemorySpaceAttrInterface toCIRAddressSpaceAttr(mlir::MLIRContext &ctx, clang::LangAS langAS)
Convert an AST LangAS to the appropriate CIR address space attribute interface.
bool anyMemberHoldsDataForABI(llvm::ArrayRef< RecordMemberKind > kinds)
Whether any member holds data for argument passing on its mark alone.
Definition CIRTypes.h:53
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:35
bool isSupportedCIRMemorySpaceAttr(mlir::ptr::MemorySpaceAttrInterface memorySpace)
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
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.
#define true
Definition stdbool.h:25
static bool unsizedTypes()
static bool dataLayoutPtrHandlingBasedOnLangAS()
static bool astRecordDeclAttr()