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 return getUnionStorageType(dataLayout, getMembers());
492}
493
494mlir::Type UnionType::getUnionStorageType(const mlir::DataLayout &dataLayout,
496 if (members.empty())
497 return {};
498 return *std::max_element(
499 members.begin(), members.end(), [&](mlir::Type lhs, mlir::Type rhs) {
500 return dataLayout.getTypeABIAlignment(lhs) <
501 dataLayout.getTypeABIAlignment(rhs) ||
502 (dataLayout.getTypeABIAlignment(lhs) ==
503 dataLayout.getTypeABIAlignment(rhs) &&
504 dataLayout.getTypeSize(lhs) < dataLayout.getTypeSize(rhs));
505 });
506}
507
508bool UnionType::isLayoutIdentical(const UnionType &other) {
509 if (getImpl() == other.getImpl())
510 return true;
511 return getMembers() == other.getMembers() &&
512 getPadding() == other.getPadding();
513}
514
515//===----------------------------------------------------------------------===//
516// RecordType view-class method implementations
517//===----------------------------------------------------------------------===//
518
520 if (auto s = mlir::dyn_cast<StructType>(*this))
521 return s.getMembers();
522 return mlir::cast<UnionType>(*this).getMembers();
523}
524mlir::StringAttr RecordType::getName() const {
525 if (auto s = mlir::dyn_cast<StructType>(*this))
526 return s.getName();
527 return mlir::cast<UnionType>(*this).getName();
528}
530 if (auto s = mlir::dyn_cast<StructType>(*this))
531 return s.isIncomplete();
532 return mlir::cast<UnionType>(*this).isIncomplete();
533}
535 if (auto s = mlir::dyn_cast<StructType>(*this))
536 return s.getPacked();
537 return mlir::cast<UnionType>(*this).getPacked();
538}
540 if (auto s = mlir::dyn_cast<StructType>(*this))
541 return s.getPadded();
542 return mlir::cast<UnionType>(*this).getPadded();
543}
545 if (auto s = mlir::dyn_cast<StructType>(*this))
546 return s.isClass();
547 return false;
548}
550 if (auto s = mlir::dyn_cast<StructType>(*this))
551 return s.isStruct();
552 return false;
553}
554std::string RecordType::getKindAsStr() const {
555 if (mlir::isa<UnionType>(*this))
556 return "union";
557 return mlir::cast<StructType>(*this).getKindAsStr();
558}
559std::string RecordType::getPrefixedName() const {
560 return getKindAsStr() + "." + getName().getValue().str();
561}
562void RecordType::complete(ArrayRef<Type> members, bool packed, bool padded,
563 mlir::Type padding) {
564 if (auto s = mlir::dyn_cast<StructType>(*this))
565 return s.complete(members, packed, padded);
566 // Unions derive padded from padding; assert the caller is consistent.
567 assert((!padded || padding) &&
568 "padded=true requires a non-null padding type");
569 return mlir::cast<UnionType>(*this).complete(members, packed, padding);
570}
571uint64_t RecordType::getElementOffset(const mlir::DataLayout &dataLayout,
572 unsigned idx) const {
573 if (mlir::isa<UnionType>(*this))
574 return 0;
575 return mlir::cast<StructType>(*this).getElementOffset(dataLayout, idx);
576}
578 if (auto s = mlir::dyn_cast<StructType>(*this)) {
579 if (auto so = mlir::dyn_cast<StructType>(other))
580 return s.isLayoutIdentical(so);
581 return false;
582 }
583 if (auto u = mlir::dyn_cast<UnionType>(*this)) {
584 if (auto uo = mlir::dyn_cast<UnionType>(other))
585 return u.isLayoutIdentical(uo);
586 return false;
587 }
588 return false;
589}
591 if (auto s = mlir::dyn_cast<StructType>(*this))
592 return s.isABIConvertedRecord();
593 return mlir::cast<UnionType>(*this).isABIConvertedRecord();
594}
595mlir::StringAttr RecordType::getABIConvertedName() const {
596 if (auto s = mlir::dyn_cast<StructType>(*this))
597 return s.getABIConvertedName();
598 return mlir::cast<UnionType>(*this).getABIConvertedName();
599}
601 if (auto s = mlir::dyn_cast<StructType>(*this))
602 return s.removeABIConversionNamePrefix();
603 return mlir::cast<UnionType>(*this).removeABIConversionNamePrefix();
604}
605
606//===----------------------------------------------------------------------===//
607// Data Layout information for types
608//===----------------------------------------------------------------------===//
609
610llvm::TypeSize
611PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
612 ::mlir::DataLayoutEntryListRef params) const {
613 // FIXME: improve this in face of address spaces
615 return llvm::TypeSize::getFixed(64);
616}
617
618uint64_t
619PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
620 ::mlir::DataLayoutEntryListRef params) const {
621 // FIXME: improve this in face of address spaces
623 return 8;
624}
625
626llvm::TypeSize
627StructType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
628 mlir::DataLayoutEntryListRef params) const {
629 auto recordSize = static_cast<uint64_t>(computeStructSize(dataLayout));
630 return llvm::TypeSize::getFixed(recordSize * 8);
631}
632
634StructType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
635 ::mlir::DataLayoutEntryListRef params) const {
636 // Packed structures always have an ABI alignment of 1.
637 if (getPacked())
638 return 1;
639 return computeStructAlignment(dataLayout);
640}
641
642llvm::TypeSize
643UnionType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
644 mlir::DataLayoutEntryListRef params) const {
645 mlir::Type storage = getUnionStorageType(dataLayout);
646 if (!storage)
647 return llvm::TypeSize::getFixed(0);
648 // The padding field holds enough bytes to bring the total up to the AST
649 // layout size (set by lowerUnion from the ASTRecordLayout). Include it so
650 // getTypeSize agrees with the {storage, padding} LLVM struct that
651 // LowerToLLVM emits; without it a containing record adds spurious tail
652 // padding via insertPadding, making sizeof and array GEPs wrong.
653 llvm::TypeSize size = dataLayout.getTypeSizeInBits(storage);
654 if (mlir::Type pad = getPadding())
655 size += dataLayout.getTypeSizeInBits(pad);
656 return size;
657}
658
660UnionType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
661 ::mlir::DataLayoutEntryListRef params) const {
662 mlir::Type storage = getUnionStorageType(dataLayout);
663 if (!storage)
664 return 1;
665 return dataLayout.getTypeABIAlignment(storage);
666}
667
668unsigned
669StructType::computeStructSize(const mlir::DataLayout &dataLayout) const {
670 assert(isComplete() && "Cannot get layout of incomplete records");
671
672 // This is a similar algorithm to LLVM's StructLayout.
673 unsigned recordSize = 0;
674 uint64_t recordAlignment = 1;
675
676 for (mlir::Type ty : getMembers()) {
677 // This assumes that we're calculating size based on the ABI alignment, not
678 // the preferred alignment for each type.
679 const uint64_t tyAlign =
680 (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
681
682 // Add padding to the struct size to align it to the abi alignment of the
683 // element type before adding the size of the element.
684 recordSize = llvm::alignTo(recordSize, tyAlign);
685 recordSize += dataLayout.getTypeSize(ty);
686
687 // The alignment requirement of a struct is equal to the strictest
688 // alignment requirement of its elements.
689 recordAlignment = std::max(tyAlign, recordAlignment);
690 }
691
692 // At the end, add padding to the struct to satisfy its own alignment
693 // requirement. Otherwise structs inside of arrays would be misaligned.
694 recordSize = llvm::alignTo(recordSize, recordAlignment);
695 return recordSize;
696}
697
698unsigned
699StructType::computeStructDataSize(const mlir::DataLayout &dataLayout) const {
700 assert(isComplete() && "Cannot get layout of incomplete records");
701
702 // Compute the data size (excluding tail padding) for this record type. For
703 // padded records, the last member is the tail padding array added by
704 // CIRGenRecordLayoutBuilder::appendPaddingBytes, so we exclude it. For
705 // non-padded records, data size equals the full struct size without
706 // alignment.
707 auto members = getMembers();
708 unsigned numMembers =
709 getPadded() && members.size() > 1 ? members.size() - 1 : members.size();
710 unsigned recordSize = 0;
711 for (unsigned i = 0; i < numMembers; ++i) {
712 mlir::Type ty = members[i];
713 const uint64_t tyAlign =
714 (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
715 recordSize = llvm::alignTo(recordSize, tyAlign);
716 recordSize += dataLayout.getTypeSize(ty);
717 }
718 return recordSize;
719}
720
721// We also compute the alignment as part of computeStructSize, but this is more
722// efficient. Ideally, we'd like to compute both at once and cache the result,
723// but that's not implemented yet.
724// TODO(CIR): Implement a way to cache the result.
726StructType::computeStructAlignment(const mlir::DataLayout &dataLayout) const {
727 assert(isComplete() && "Cannot get layout of incomplete records");
728
729 uint64_t recordAlignment = 1;
730 for (mlir::Type ty : getMembers())
731 recordAlignment =
732 std::max(dataLayout.getTypeABIAlignment(ty), recordAlignment);
733 return recordAlignment;
734}
735
736uint64_t StructType::getElementOffset(const ::mlir::DataLayout &dataLayout,
737 unsigned idx) const {
738 assert(idx < getMembers().size() && "access not valid");
739 if (idx == 0)
740 return 0;
741
742 assert(isComplete() && "Cannot get layout of incomplete records");
743 assert(idx < getNumElements());
744 llvm::ArrayRef<mlir::Type> members = getMembers();
745
746 unsigned offset = 0;
747 for (mlir::Type ty :
748 llvm::make_range(members.begin(), std::next(members.begin(), idx))) {
749 const llvm::Align tyAlign =
750 llvm::Align(getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
751 offset = llvm::alignTo(offset, tyAlign);
752 offset += dataLayout.getTypeSize(ty);
753 }
754
755 const llvm::Align tyAlign = llvm::Align(
756 getPacked() ? 1 : dataLayout.getTypeABIAlignment(members[idx]));
757 offset = llvm::alignTo(offset, tyAlign);
758 return offset;
759}
760
761//===----------------------------------------------------------------------===//
762// IntType Definitions
763//===----------------------------------------------------------------------===//
764
765Type IntType::parse(mlir::AsmParser &parser) {
766 mlir::MLIRContext *context = parser.getBuilder().getContext();
767 llvm::SMLoc loc = parser.getCurrentLocation();
768 bool isSigned;
769 unsigned width;
770
771 if (parser.parseLess())
772 return {};
773
774 // Fetch integer sign.
775 llvm::StringRef sign;
776 if (parser.parseKeyword(&sign))
777 return {};
778 if (sign == "s")
779 isSigned = true;
780 else if (sign == "u")
781 isSigned = false;
782 else {
783 parser.emitError(loc, "expected 's' or 'u'");
784 return {};
785 }
786
787 if (parser.parseComma())
788 return {};
789
790 // Fetch integer size.
791 if (parser.parseInteger(width))
792 return {};
793 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
794 parser.emitError(loc, "expected integer width to be from ")
795 << IntType::minBitwidth() << " up to " << IntType::maxBitwidth();
796 return {};
797 }
798
799 bool isBitInt = false;
800 if (succeeded(parser.parseOptionalComma())) {
801 llvm::StringRef kw;
802 if (parser.parseKeyword(&kw) || kw != "bitint") {
803 parser.emitError(loc, "expected 'bitint'");
804 return {};
805 }
806 isBitInt = true;
807 }
808
809 if (parser.parseGreater())
810 return {};
811
812 return IntType::get(context, width, isSigned, isBitInt);
813}
814
815void IntType::print(mlir::AsmPrinter &printer) const {
816 char sign = isSigned() ? 's' : 'u';
817 printer << '<' << sign << ", " << getWidth();
818 if (isBitInt())
819 printer << ", bitint";
820 printer << '>';
821}
822
823llvm::TypeSize
824IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
825 mlir::DataLayoutEntryListRef params) const {
826 return llvm::TypeSize::getFixed(getWidth());
827}
828
829uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
830 mlir::DataLayoutEntryListRef params) const {
831 unsigned width = getWidth();
832 if (isBitInt()) {
833 // _BitInt alignment: min(PowerOf2Ceil(width), 64 bits) in bytes.
834 // Matches Clang's TargetInfo::getBitIntAlign with default max = 64.
835 uint64_t alignBits =
836 std::min(llvm::PowerOf2Ceil(width), static_cast<uint64_t>(64));
837 return std::max(alignBits / 8, static_cast<uint64_t>(1));
838 }
839 // Round up to a power-of-two byte alignment. DataLayout consumers such as
840 // llvm::Align require power-of-two alignments, and width / 8 is not a power
841 // of two for non-fundamental widths (e.g. i24 -> 3). This leaves the
842 // fundamental widths unchanged (i8 -> 1, i16 -> 2, i32 -> 4, i64 -> 8) and
843 // keeps __int128 at 16.
844 uint64_t alignBits = llvm::PowerOf2Ceil(width);
845 return std::max(alignBits / 8, static_cast<uint64_t>(1));
846}
847
848mlir::LogicalResult
849IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
850 unsigned width, bool isSigned, bool isBitInt) {
851 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth())
852 return emitError() << "IntType only supports widths from "
853 << IntType::minBitwidth() << " up to "
854 << IntType::maxBitwidth();
855 return mlir::success();
856}
857
859 return width == 8 || width == 16 || width == 32 || width == 64;
860}
861
862//===----------------------------------------------------------------------===//
863// Floating-point type definitions
864//===----------------------------------------------------------------------===//
865
866const llvm::fltSemantics &SingleType::getFloatSemantics() const {
867 return llvm::APFloat::IEEEsingle();
868}
869
870llvm::TypeSize
871SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
872 mlir::DataLayoutEntryListRef params) const {
873 return llvm::TypeSize::getFixed(getWidth());
874}
875
877SingleType::getABIAlignment(const mlir::DataLayout &dataLayout,
878 mlir::DataLayoutEntryListRef params) const {
879 return (uint64_t)(getWidth() / 8);
880}
881
882const llvm::fltSemantics &DoubleType::getFloatSemantics() const {
883 return llvm::APFloat::IEEEdouble();
884}
885
886llvm::TypeSize
887DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
888 mlir::DataLayoutEntryListRef params) const {
889 return llvm::TypeSize::getFixed(getWidth());
890}
891
893DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
894 mlir::DataLayoutEntryListRef params) const {
895 return (uint64_t)(getWidth() / 8);
896}
897
898const llvm::fltSemantics &FP16Type::getFloatSemantics() const {
899 return llvm::APFloat::IEEEhalf();
900}
901
902llvm::TypeSize
903FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
904 mlir::DataLayoutEntryListRef params) const {
905 return llvm::TypeSize::getFixed(getWidth());
906}
907
908uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
909 mlir::DataLayoutEntryListRef params) const {
910 return (uint64_t)(getWidth() / 8);
911}
912
913const llvm::fltSemantics &BF16Type::getFloatSemantics() const {
914 return llvm::APFloat::BFloat();
915}
916
917llvm::TypeSize
918BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
919 mlir::DataLayoutEntryListRef params) const {
920 return llvm::TypeSize::getFixed(getWidth());
921}
922
923uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
924 mlir::DataLayoutEntryListRef params) const {
925 return (uint64_t)(getWidth() / 8);
926}
927
928const llvm::fltSemantics &FP80Type::getFloatSemantics() const {
929 return llvm::APFloat::x87DoubleExtended();
930}
931
932llvm::TypeSize
933FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
934 mlir::DataLayoutEntryListRef params) const {
935 // Though only 80 bits are used for the value, the type is 128 bits in size.
936 return llvm::TypeSize::getFixed(128);
937}
938
939uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout,
940 mlir::DataLayoutEntryListRef params) const {
941 return 16;
942}
943
944const llvm::fltSemantics &FP128Type::getFloatSemantics() const {
945 return llvm::APFloat::IEEEquad();
946}
947
948llvm::TypeSize
949FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
950 mlir::DataLayoutEntryListRef params) const {
951 return llvm::TypeSize::getFixed(getWidth());
952}
953
954uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout,
955 mlir::DataLayoutEntryListRef params) const {
956 return 16;
957}
958
959const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const {
960 return mlir::cast<cir::FPTypeInterface>(getUnderlying()).getFloatSemantics();
961}
962
963llvm::TypeSize
964LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
965 mlir::DataLayoutEntryListRef params) const {
966 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
967 .getTypeSizeInBits(dataLayout, params);
968}
969
971LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
972 mlir::DataLayoutEntryListRef params) const {
973 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
974 .getABIAlignment(dataLayout, params);
975}
976
977//===----------------------------------------------------------------------===//
978// ComplexType Definitions
979//===----------------------------------------------------------------------===//
980
981llvm::TypeSize
982cir::ComplexType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
983 mlir::DataLayoutEntryListRef params) const {
984 // C17 6.2.5p13:
985 // Each complex type has the same representation and alignment requirements
986 // as an array type containing exactly two elements of the corresponding
987 // real type.
988
989 return dataLayout.getTypeSizeInBits(getElementType()) * 2;
990}
991
993cir::ComplexType::getABIAlignment(const mlir::DataLayout &dataLayout,
994 mlir::DataLayoutEntryListRef params) const {
995 // C17 6.2.5p13:
996 // Each complex type has the same representation and alignment requirements
997 // as an array type containing exactly two elements of the corresponding
998 // real type.
999
1000 return dataLayout.getTypeABIAlignment(getElementType());
1001}
1002
1003FuncType FuncType::clone(TypeRange inputs, TypeRange results) const {
1004 assert(results.size() == 1 && "expected exactly one result type");
1005 return get(llvm::to_vector(inputs), results[0], isVarArg());
1006}
1007
1008// Custom parser that parses function parameters of form `(<type>*, ...)`.
1009static mlir::ParseResult
1011 bool &isVarArg) {
1012 isVarArg = false;
1013 return p.parseCommaSeparatedList(
1014 AsmParser::Delimiter::Paren, [&]() -> mlir::ParseResult {
1015 if (isVarArg)
1016 return p.emitError(p.getCurrentLocation(),
1017 "variadic `...` must be the last parameter");
1018 if (succeeded(p.parseOptionalEllipsis())) {
1019 isVarArg = true;
1020 return success();
1021 }
1022 mlir::Type type;
1023 if (failed(p.parseType(type)))
1024 return failure();
1025 params.push_back(type);
1026 return success();
1027 });
1028}
1029
1030static void printFuncTypeParams(mlir::AsmPrinter &p,
1031 mlir::ArrayRef<mlir::Type> params,
1032 bool isVarArg) {
1033 p << '(';
1034 llvm::interleaveComma(params, p,
1035 [&p](mlir::Type type) { p.printType(type); });
1036 if (isVarArg) {
1037 if (!params.empty())
1038 p << ", ";
1039 p << "...";
1040 }
1041 p << ')';
1042}
1043
1044/// Get the C-style return type of the function, which is !cir.void if the
1045/// function returns nothing and the actual return type otherwise.
1046mlir::Type FuncType::getReturnType() const {
1047 if (hasVoidReturn())
1048 return cir::VoidType::get(getContext());
1049 return getOptionalReturnType();
1050}
1051
1052/// Get the MLIR-style return type of the function, which is an empty
1053/// ArrayRef if the function returns nothing and a single-element ArrayRef
1054/// with the actual return type otherwise.
1055llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const {
1056 if (hasVoidReturn())
1057 return {};
1058 // Can't use getOptionalReturnType() here because llvm::ArrayRef hold a
1059 // pointer to its elements and doesn't do lifetime extension. That would
1060 // result in returning a pointer to a temporary that has gone out of scope.
1061 return getImpl()->optionalReturnType;
1062}
1063
1064// Does the fuction type return nothing?
1065bool FuncType::hasVoidReturn() const { return !getOptionalReturnType(); }
1066
1067mlir::LogicalResult
1068FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1069 llvm::ArrayRef<mlir::Type> argTypes, mlir::Type returnType,
1070 bool isVarArg) {
1071 if (mlir::isa_and_nonnull<cir::VoidType>(returnType))
1072 return emitError()
1073 << "!cir.func cannot have an explicit 'void' return type";
1074 return mlir::success();
1075}
1076
1077//===----------------------------------------------------------------------===//
1078// MethodType Definitions
1079//===----------------------------------------------------------------------===//
1080
1081static mlir::Type getMethodLayoutType(mlir::MLIRContext *ctx) {
1082 // With Itanium ABI, member function pointers have the same layout as the
1083 // following struct: struct { fnptr_t, ptrdiff_t }, where fnptr_t is a
1084 // function pointer type.
1085 // TODO: consider member function pointer layout in other ABIs
1086 auto voidPtrTy = cir::PointerType::get(cir::VoidType::get(ctx));
1087 mlir::Type fields[2]{voidPtrTy, voidPtrTy};
1088 return cir::StructType::get(ctx, fields, /*packed=*/false,
1089 /*padded=*/false, /*is_class=*/false);
1090}
1091
1092llvm::TypeSize
1093MethodType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1094 mlir::DataLayoutEntryListRef params) const {
1095 return dataLayout.getTypeSizeInBits(getMethodLayoutType(getContext()));
1096}
1097
1099MethodType::getABIAlignment(const mlir::DataLayout &dataLayout,
1100 mlir::DataLayoutEntryListRef params) const {
1101 return cast<cir::StructType>(getMethodLayoutType(getContext()))
1102 .getABIAlignment(dataLayout, params);
1103}
1104
1105//===----------------------------------------------------------------------===//
1106// BoolType
1107//===----------------------------------------------------------------------===//
1108
1109llvm::TypeSize
1110BoolType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
1111 ::mlir::DataLayoutEntryListRef params) const {
1112 return llvm::TypeSize::getFixed(8);
1113}
1114
1116BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1117 ::mlir::DataLayoutEntryListRef params) const {
1118 return 1;
1119}
1120
1121//===----------------------------------------------------------------------===//
1122// DataMemberType Definitions
1123//===----------------------------------------------------------------------===//
1124
1125llvm::TypeSize
1126DataMemberType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
1127 ::mlir::DataLayoutEntryListRef params) const {
1128 // FIXME: consider size differences under different ABIs
1129 assert(!MissingFeatures::cxxABI());
1130 return llvm::TypeSize::getFixed(64);
1131}
1132
1134DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1135 ::mlir::DataLayoutEntryListRef params) const {
1136 // FIXME: consider alignment differences under different ABIs
1137 assert(!MissingFeatures::cxxABI());
1138 return 8;
1139}
1140
1141//===----------------------------------------------------------------------===//
1142// VPtrType Definitions
1143//===----------------------------------------------------------------------===//
1144
1145llvm::TypeSize
1146VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
1147 mlir::DataLayoutEntryListRef params) const {
1148 // FIXME: consider size differences under different ABIs
1149 return llvm::TypeSize::getFixed(64);
1150}
1151
1152uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout,
1153 mlir::DataLayoutEntryListRef params) const {
1154 // FIXME: consider alignment differences under different ABIs
1155 return 8;
1156}
1157
1158//===----------------------------------------------------------------------===//
1159// ArrayType Definitions
1160//===----------------------------------------------------------------------===//
1161
1162llvm::TypeSize
1163ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
1164 ::mlir::DataLayoutEntryListRef params) const {
1165 return getSize() * dataLayout.getTypeSizeInBits(getElementType());
1166}
1167
1169ArrayType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1170 ::mlir::DataLayoutEntryListRef params) const {
1171 return dataLayout.getTypeABIAlignment(getElementType());
1172}
1173
1174//===----------------------------------------------------------------------===//
1175// VectorType Definitions
1176//===----------------------------------------------------------------------===//
1177
1178llvm::TypeSize cir::VectorType::getTypeSizeInBits(
1179 const ::mlir::DataLayout &dataLayout,
1180 ::mlir::DataLayoutEntryListRef params) const {
1181 return llvm::TypeSize::getFixed(
1182 getSize() * dataLayout.getTypeSizeInBits(getElementType()));
1183}
1184
1186cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
1187 ::mlir::DataLayoutEntryListRef params) const {
1188 return llvm::NextPowerOf2(dataLayout.getTypeSizeInBits(*this));
1189}
1190
1191mlir::LogicalResult cir::VectorType::verify(
1192 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1193 mlir::Type elementType, uint64_t size, bool scalable) {
1194 if (size == 0)
1195 return emitError() << "the number of vector elements must be non-zero";
1196 return success();
1197}
1198
1199mlir::Type cir::VectorType::parse(::mlir::AsmParser &odsParser) {
1200
1201 llvm::SMLoc odsLoc = odsParser.getCurrentLocation();
1202 mlir::Builder odsBuilder(odsParser.getContext());
1203 mlir::FailureOr<::mlir::Type> elementType;
1204 mlir::FailureOr<uint64_t> size;
1205 bool isScalabe = false;
1206
1207 // Parse literal '<'
1208 if (odsParser.parseLess())
1209 return {};
1210
1211 // Parse literal '[', if present, and set the scalability flag accordingly
1212 if (odsParser.parseOptionalLSquare().succeeded())
1213 isScalabe = true;
1214
1215 // Parse variable 'size'
1216 size = mlir::FieldParser<uint64_t>::parse(odsParser);
1217 if (mlir::failed(size)) {
1218 odsParser.emitError(odsParser.getCurrentLocation(),
1219 "failed to parse CIR_VectorType parameter 'size' which "
1220 "is to be a `uint64_t`");
1221 return {};
1222 }
1223
1224 // Parse literal ']', which is expected when dealing with scalable
1225 // dim sizes
1226 if (isScalabe && odsParser.parseRSquare().failed()) {
1227 odsParser.emitError(odsParser.getCurrentLocation(),
1228 "missing closing `]` for scalable dim size");
1229 return {};
1230 }
1231
1232 // Parse literal 'x'
1233 if (odsParser.parseKeyword("x"))
1234 return {};
1235
1236 // Parse variable 'elementType'
1237 elementType = mlir::FieldParser<::mlir::Type>::parse(odsParser);
1238 if (mlir::failed(elementType)) {
1239 odsParser.emitError(odsParser.getCurrentLocation(),
1240 "failed to parse CIR_VectorType parameter "
1241 "'elementType' which is to be a `mlir::Type`");
1242 return {};
1243 }
1244
1245 // Parse literal '>'
1246 if (odsParser.parseGreater())
1247 return {};
1248 return odsParser.getChecked<VectorType>(odsLoc, odsParser.getContext(),
1249 mlir::Type((*elementType)),
1250 uint64_t((*size)), isScalabe);
1251}
1252
1253void cir::VectorType::print(mlir::AsmPrinter &odsPrinter) const {
1254 mlir::Builder odsBuilder(getContext());
1255 odsPrinter << "<";
1256 if (this->getIsScalable())
1257 odsPrinter << "[";
1258
1259 odsPrinter.printStrippedAttrOrType(getSize());
1260 if (this->getIsScalable())
1261 odsPrinter << "]";
1262 odsPrinter << ' ' << "x";
1263 odsPrinter << ' ';
1264 odsPrinter.printStrippedAttrOrType(getElementType());
1265 odsPrinter << ">";
1266}
1267
1268//===----------------------------------------------------------------------===//
1269// AddressSpace definitions
1270//===----------------------------------------------------------------------===//
1271
1273 mlir::ptr::MemorySpaceAttrInterface memorySpace) {
1274 return mlir::isa<cir::LangAddressSpaceAttr, cir::TargetAddressSpaceAttr>(
1275 memorySpace);
1276}
1277
1278cir::LangAddressSpace cir::toCIRLangAddressSpace(clang::LangAS langAS) {
1279 using clang::LangAS;
1280 switch (langAS) {
1281 case LangAS::Default:
1282 return LangAddressSpace::Default;
1283 case LangAS::opencl_global:
1284 return LangAddressSpace::OffloadGlobal;
1285 case LangAS::opencl_local:
1286 case LangAS::cuda_shared:
1287 // Local means local among the work-group (OpenCL) or block (CUDA).
1288 // All threads inside the kernel can access local memory.
1289 return LangAddressSpace::OffloadLocal;
1290 case LangAS::cuda_device:
1291 return LangAddressSpace::OffloadGlobal;
1292 case LangAS::opencl_constant:
1293 case LangAS::cuda_constant:
1294 return LangAddressSpace::OffloadConstant;
1295 case LangAS::opencl_private:
1296 return LangAddressSpace::OffloadPrivate;
1297 case LangAS::opencl_generic:
1298 return LangAddressSpace::OffloadGeneric;
1299 case LangAS::opencl_global_device:
1300 return LangAddressSpace::OffloadGlobalDevice;
1301 case LangAS::opencl_global_host:
1302 return LangAddressSpace::OffloadGlobalHost;
1303 case LangAS::sycl_global:
1304 case LangAS::sycl_global_device:
1305 case LangAS::sycl_global_host:
1306 case LangAS::sycl_local:
1307 case LangAS::sycl_private:
1308 case LangAS::ptr32_sptr:
1309 case LangAS::ptr32_uptr:
1310 case LangAS::ptr64:
1311 case LangAS::hlsl_groupshared:
1312 case LangAS::wasm_funcref:
1313 llvm_unreachable("NYI");
1314 default:
1315 llvm_unreachable("unknown/unsupported clang language address space");
1316 }
1317}
1318
1319mlir::ParseResult
1320parseAddressSpaceValue(mlir::AsmParser &p,
1321 mlir::ptr::MemorySpaceAttrInterface &attr) {
1322
1323 llvm::SMLoc loc = p.getCurrentLocation();
1324
1325 // Try to parse target address space first.
1326 attr = nullptr;
1327 if (p.parseOptionalKeyword("target_address_space").succeeded()) {
1328 unsigned val;
1329 if (p.parseLParen())
1330 return p.emitError(loc, "expected '(' after 'target_address_space'");
1331
1332 if (p.parseInteger(val))
1333 return p.emitError(loc, "expected target address space value");
1334
1335 if (p.parseRParen())
1336 return p.emitError(loc, "expected ')'");
1337
1338 attr = cir::TargetAddressSpaceAttr::get(p.getContext(), val);
1339 return mlir::success();
1340 }
1341
1342 // Try to parse language specific address space.
1343 if (p.parseOptionalKeyword("lang_address_space").succeeded()) {
1344 if (p.parseLParen())
1345 return p.emitError(loc, "expected '(' after 'lang_address_space'");
1346
1347 mlir::FailureOr<cir::LangAddressSpace> result =
1348 mlir::FieldParser<cir::LangAddressSpace>::parse(p);
1349 if (mlir::failed(result))
1350 return mlir::failure();
1351
1352 if (p.parseRParen())
1353 return p.emitError(loc, "expected ')'");
1354
1355 attr = cir::LangAddressSpaceAttr::get(p.getContext(), result.value());
1356 return mlir::success();
1357 }
1358
1359 llvm::StringRef keyword;
1360 if (p.parseOptionalKeyword(&keyword).succeeded())
1361 return p.emitError(loc, "unknown address space specifier '")
1362 << keyword << "'; expected 'target_address_space' or "
1363 << "'lang_address_space'";
1364
1365 return mlir::success();
1366}
1367
1368void printAddressSpaceValue(mlir::AsmPrinter &p,
1369 mlir::ptr::MemorySpaceAttrInterface attr) {
1370 if (!attr)
1371 return;
1372
1373 if (auto language = dyn_cast<cir::LangAddressSpaceAttr>(attr)) {
1374 p << "lang_address_space("
1375 << cir::stringifyLangAddressSpace(language.getValue()) << ')';
1376 return;
1377 }
1378
1379 if (auto target = dyn_cast<cir::TargetAddressSpaceAttr>(attr)) {
1380 p << "target_address_space(" << target.getValue() << ')';
1381 return;
1382 }
1383
1384 llvm_unreachable("unexpected address-space attribute kind");
1385}
1386
1387mlir::OptionalParseResult
1389 mlir::ptr::MemorySpaceAttrInterface &attr) {
1390
1391 mlir::SMLoc loc = p.getCurrentLocation();
1392 if (parseAddressSpaceValue(p, attr).failed())
1393 return p.emitError(loc, "failed to parse Address Space Value for GlobalOp");
1394 return mlir::success();
1395}
1396
1397void printGlobalAddressSpaceValue(mlir::AsmPrinter &printer, cir::GlobalOp,
1398 mlir::ptr::MemorySpaceAttrInterface attr) {
1399 printAddressSpaceValue(printer, attr);
1400}
1401
1402mlir::ptr::MemorySpaceAttrInterface cir::normalizeDefaultAddressSpace(
1403 mlir::ptr::MemorySpaceAttrInterface addrSpace) {
1404 if (auto langAS =
1405 mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace))
1406 if (langAS.getValue() == cir::LangAddressSpace::Default)
1407 return {};
1408 return addrSpace;
1409}
1410
1411mlir::ptr::MemorySpaceAttrInterface
1412cir::toCIRAddressSpaceAttr(mlir::MLIRContext &ctx, clang::LangAS langAS) {
1413 using clang::LangAS;
1414
1415 if (langAS == LangAS::Default)
1416 return cir::LangAddressSpaceAttr::get(&ctx, cir::LangAddressSpace::Default);
1417
1418 if (clang::isTargetAddressSpace(langAS)) {
1419 unsigned targetAS = clang::toTargetAddressSpace(langAS);
1420 return cir::TargetAddressSpaceAttr::get(&ctx, targetAS);
1421 }
1422
1423 return cir::LangAddressSpaceAttr::get(&ctx, toCIRLangAddressSpace(langAS));
1424}
1425
1426bool cir::isMatchingAddressSpace(mlir::ptr::MemorySpaceAttrInterface cirAS,
1427 clang::LangAS as) {
1428 cirAS = normalizeDefaultAddressSpace(cirAS);
1429 if (!cirAS)
1430 return as == clang::LangAS::Default;
1431 mlir::ptr::MemorySpaceAttrInterface expected = normalizeDefaultAddressSpace(
1432 toCIRAddressSpaceAttr(*cirAS.getContext(), as));
1433 return expected == cirAS;
1434}
1435
1436//===----------------------------------------------------------------------===//
1437// PointerType Definitions
1438//===----------------------------------------------------------------------===//
1439
1440mlir::LogicalResult cir::PointerType::verify(
1441 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1442 mlir::Type pointee, mlir::ptr::MemorySpaceAttrInterface addrSpace) {
1443 if (addrSpace) {
1444 if (!isSupportedCIRMemorySpaceAttr(addrSpace)) {
1445 return emitError() << "unsupported address space attribute; expected "
1446 "'target_address_space' or 'lang_address_space'";
1447 }
1448 }
1449
1450 return success();
1451}
1452
1453//===----------------------------------------------------------------------===//
1454// CIR Dialect
1455//===----------------------------------------------------------------------===//
1456
1457void CIRDialect::registerTypes() {
1458 // Register tablegen'd types.
1459 addTypes<
1460#define GET_TYPEDEF_LIST
1461#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
1462 >();
1463
1464 // Register raw C++ types.
1465 // TODO(CIR) addTypes<RecordType>();
1466}
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:577
bool isABIConvertedRecord() const
Definition CIRTypes.cpp:590
bool isIncomplete() const
Definition CIRTypes.cpp:529
std::string getPrefixedName() const
Definition CIRTypes.cpp:559
llvm::ArrayRef< mlir::Type > getMembers() const
Definition CIRTypes.cpp:519
bool isClass() const
Definition CIRTypes.cpp:544
void removeABIConversionNamePrefix()
Definition CIRTypes.cpp:600
bool getPacked() const
Definition CIRTypes.cpp:534
RecordType(StructType t)
Definition CIRTypes.h:111
void complete(llvm::ArrayRef< mlir::Type > members, bool packed, bool padded, mlir::Type padding={})
Definition CIRTypes.cpp:562
mlir::StringAttr getName() const
Definition CIRTypes.cpp:524
mlir::StringAttr getABIConvertedName() const
Definition CIRTypes.cpp:595
std::string getKindAsStr() const
Definition CIRTypes.cpp:554
bool isStruct() const
Definition CIRTypes.cpp:549
bool getPadded() const
Definition CIRTypes.cpp:539
uint64_t getElementOffset(const mlir::DataLayout &dataLayout, unsigned idx) const
Definition CIRTypes.cpp:571
bool isMatchingAddressSpace(mlir::ptr::MemorySpaceAttrInterface cirAS, clang::LangAS as)
cir::LangAddressSpace toCIRLangAddressSpace(clang::LangAS langAS)
bool isValidFundamentalIntWidth(unsigned width)
Definition CIRTypes.cpp:858
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()