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