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