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