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