clang 23.0.0git
CIRAttrs.cpp
Go to the documentation of this file.
1//===- CIRAttrs.cpp - MLIR CIR Attributes ---------------------------------===//
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 attributes in the CIR dialect.
10//
11//===----------------------------------------------------------------------===//
12
13#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
15
16#include "mlir/IR/DialectImplementation.h"
17#include "llvm/ADT/TypeSwitch.h"
18
19//===-----------------------------------------------------------------===//
20// RecordMembers
21//===-----------------------------------------------------------------===//
22
23static void printRecordMembers(mlir::AsmPrinter &p, mlir::ArrayAttr members);
24static mlir::ParseResult parseRecordMembers(mlir::AsmParser &parser,
25 mlir::ArrayAttr &members);
26
27//===-----------------------------------------------------------------===//
28// IntLiteral
29//===-----------------------------------------------------------------===//
30
31static void printIntLiteral(mlir::AsmPrinter &p, llvm::APInt value,
32 cir::IntTypeInterface ty);
33static mlir::ParseResult parseIntLiteral(mlir::AsmParser &parser,
34 llvm::APInt &value,
35 cir::IntTypeInterface ty);
36//===-----------------------------------------------------------------===//
37// FloatLiteral
38//===-----------------------------------------------------------------===//
39
40static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value,
41 mlir::Type ty);
42static mlir::ParseResult
43parseFloatLiteral(mlir::AsmParser &parser,
44 mlir::FailureOr<llvm::APFloat> &value,
45 cir::FPTypeInterface fpType);
46
47//===----------------------------------------------------------------------===//
48// AddressSpaceAttr
49//===----------------------------------------------------------------------===//
50
51mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
52 cir::LangAddressSpace &addrSpace) {
53 llvm::SMLoc loc = p.getCurrentLocation();
54 mlir::FailureOr<cir::LangAddressSpace> result =
55 mlir::FieldParser<cir::LangAddressSpace>::parse(p);
56 if (mlir::failed(result))
57 return p.emitError(loc, "expected address space keyword");
58 addrSpace = result.value();
59 return mlir::success();
60}
61
62void printAddressSpaceValue(mlir::AsmPrinter &p,
63 cir::LangAddressSpace addrSpace) {
64 p << cir::stringifyEnum(addrSpace);
65}
66
67static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
68 mlir::IntegerAttr &value);
69
70static void printConstPtr(mlir::AsmPrinter &p, mlir::IntegerAttr value);
71
72#define GET_ATTRDEF_CLASSES
73#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
74
75using namespace mlir;
76using namespace cir;
77
78//===----------------------------------------------------------------------===//
79// MemorySpaceAttrInterface implementations for Lang and Target address space
80// attributes
81//===----------------------------------------------------------------------===//
82
83bool LangAddressSpaceAttr::isValidLoad(
84 mlir::Type type, mlir::ptr::AtomicOrdering ordering,
85 std::optional<int64_t> alignment, const mlir::DataLayout *dataLayout,
86 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
87 llvm_unreachable("isValidLoad for LangAddressSpaceAttr NYI");
88}
89
90bool LangAddressSpaceAttr::isValidStore(
91 mlir::Type type, mlir::ptr::AtomicOrdering ordering,
92 std::optional<int64_t> alignment, const mlir::DataLayout *dataLayout,
93 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
94 llvm_unreachable("isValidStore for LangAddressSpaceAttr NYI");
95}
96
97bool LangAddressSpaceAttr::isValidAtomicOp(
98 mlir::ptr::AtomicBinOp op, mlir::Type type,
99 mlir::ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
100 const mlir::DataLayout *dataLayout,
101 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
102 llvm_unreachable("isValidAtomicOp for LangAddressSpaceAttr NYI");
103}
104
105bool LangAddressSpaceAttr::isValidAtomicXchg(
106 mlir::Type type, mlir::ptr::AtomicOrdering successOrdering,
107 mlir::ptr::AtomicOrdering failureOrdering, std::optional<int64_t> alignment,
108 const mlir::DataLayout *dataLayout,
109 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
110 llvm_unreachable("isValidAtomicXchg for LangAddressSpaceAttr NYI");
111}
112
113bool LangAddressSpaceAttr::isValidAddrSpaceCast(
114 mlir::Type tgt, mlir::Type src,
115 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
116 llvm_unreachable("isValidAddrSpaceCast for LangAddressSpaceAttr NYI");
117}
118
119bool LangAddressSpaceAttr::isValidPtrIntCast(
120 mlir::Type intLikeTy, mlir::Type ptrLikeTy,
121 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
122 llvm_unreachable("isValidPtrIntCast for LangAddressSpaceAttr NYI");
123}
124
125bool TargetAddressSpaceAttr::isValidLoad(
126 mlir::Type type, mlir::ptr::AtomicOrdering ordering,
127 std::optional<int64_t> alignment, const mlir::DataLayout *dataLayout,
128 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
129 llvm_unreachable("isValidLoad for TargetAddressSpaceAttr NYI");
130}
131
132bool TargetAddressSpaceAttr::isValidStore(
133 mlir::Type type, mlir::ptr::AtomicOrdering ordering,
134 std::optional<int64_t> alignment, const mlir::DataLayout *dataLayout,
135 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
136 llvm_unreachable("isValidStore for TargetAddressSpaceAttr NYI");
137}
138
139bool TargetAddressSpaceAttr::isValidAtomicOp(
140 mlir::ptr::AtomicBinOp op, mlir::Type type,
141 mlir::ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
142 const mlir::DataLayout *dataLayout,
143 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
144 llvm_unreachable("isValidAtomicOp for TargetAddressSpaceAttr NYI");
145}
146
147bool TargetAddressSpaceAttr::isValidAtomicXchg(
148 mlir::Type type, mlir::ptr::AtomicOrdering successOrdering,
149 mlir::ptr::AtomicOrdering failureOrdering, std::optional<int64_t> alignment,
150 const mlir::DataLayout *dataLayout,
151 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
152 llvm_unreachable("isValidAtomicXchg for TargetAddressSpaceAttr NYI");
153}
154
155bool TargetAddressSpaceAttr::isValidAddrSpaceCast(
156 mlir::Type tgt, mlir::Type src,
157 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
158 llvm_unreachable("isValidAddrSpaceCast for TargetAddressSpaceAttr NYI");
159}
160
161bool TargetAddressSpaceAttr::isValidPtrIntCast(
162 mlir::Type intLikeTy, mlir::Type ptrLikeTy,
163 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const {
164 llvm_unreachable("isValidPtrIntCast for TargetAddressSpaceAttr NYI");
165}
166
167//===----------------------------------------------------------------------===//
168// General CIR parsing / printing
169//===----------------------------------------------------------------------===//
170
171static void printRecordMembers(mlir::AsmPrinter &printer,
172 mlir::ArrayAttr members) {
173 printer << '{';
174 llvm::interleaveComma(members, printer);
175 printer << '}';
176}
177
178static ParseResult parseRecordMembers(mlir::AsmParser &parser,
179 mlir::ArrayAttr &members) {
181
182 auto delimiter = AsmParser::Delimiter::Braces;
183 auto result = parser.parseCommaSeparatedList(delimiter, [&]() {
184 mlir::TypedAttr attr;
185 if (parser.parseAttribute(attr).failed())
186 return mlir::failure();
187 elts.push_back(attr);
188 return mlir::success();
189 });
190
191 if (result.failed())
192 return mlir::failure();
193
194 members = mlir::ArrayAttr::get(parser.getContext(), elts);
195 return mlir::success();
196}
197
198//===----------------------------------------------------------------------===//
199// ConstRecordAttr definitions
200//===----------------------------------------------------------------------===//
201
202LogicalResult
203ConstRecordAttr::verify(function_ref<InFlightDiagnostic()> emitError,
204 mlir::Type type, ArrayAttr members) {
205 auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
206 if (!sTy)
207 return emitError() << "expected !cir.record type";
208
209 if (sTy.getMembers().size() != members.size())
210 return emitError() << "number of elements must match";
211
212 unsigned attrIdx = 0;
213 for (auto &member : sTy.getMembers()) {
214 auto m = mlir::cast<mlir::TypedAttr>(members[attrIdx]);
215 if (member != m.getType())
216 return emitError() << "element at index " << attrIdx << " has type "
217 << m.getType()
218 << " but the expected type for this element is "
219 << member;
220 attrIdx++;
221 }
222
223 return success();
224}
225
226//===----------------------------------------------------------------------===//
227// OptInfoAttr definitions
228//===----------------------------------------------------------------------===//
229
230LogicalResult OptInfoAttr::verify(function_ref<InFlightDiagnostic()> emitError,
231 unsigned level, unsigned size) {
232 if (level > 3)
233 return emitError()
234 << "optimization level must be between 0 and 3 inclusive";
235 if (size > 2)
236 return emitError()
237 << "size optimization level must be between 0 and 2 inclusive";
238 return success();
239}
240
241//===----------------------------------------------------------------------===//
242// ConstPtrAttr definitions
243//===----------------------------------------------------------------------===//
244
245// TODO(CIR): Consider encoding the null value differently and use conditional
246// assembly format instead of custom parsing/printing.
247static ParseResult parseConstPtr(AsmParser &parser, mlir::IntegerAttr &value) {
248
249 if (parser.parseOptionalKeyword("null").succeeded()) {
250 value = parser.getBuilder().getI64IntegerAttr(0);
251 return success();
252 }
253
254 return parser.parseAttribute(value);
255}
256
257static void printConstPtr(AsmPrinter &p, mlir::IntegerAttr value) {
258 if (!value.getInt())
259 p << "null";
260 else
261 p << value;
262}
263
264//===----------------------------------------------------------------------===//
265// IntAttr definitions
266//===----------------------------------------------------------------------===//
267
268template <typename IntT>
269static bool isTooLargeForType(const mlir::APInt &value, IntT expectedValue) {
270 if constexpr (std::is_signed_v<IntT>) {
271 return value.getSExtValue() != expectedValue;
272 } else {
273 return value.getZExtValue() != expectedValue;
274 }
275}
276
277template <typename IntT>
278static mlir::ParseResult parseIntLiteralImpl(mlir::AsmParser &p,
279 llvm::APInt &value,
280 cir::IntTypeInterface ty) {
281 IntT ivalue;
282 const bool isSigned = ty.isSigned();
283 if (p.parseInteger(ivalue))
284 return p.emitError(p.getCurrentLocation(), "expected integer value");
285
286 value = mlir::APInt(ty.getWidth(), ivalue, isSigned, /*implicitTrunc=*/true);
287 if (isTooLargeForType(value, ivalue))
288 return p.emitError(p.getCurrentLocation(),
289 "integer value too large for the given type");
290
291 return success();
292}
293
294mlir::ParseResult parseIntLiteral(mlir::AsmParser &parser, llvm::APInt &value,
295 cir::IntTypeInterface ty) {
296 if (ty.isSigned())
297 return parseIntLiteralImpl<int64_t>(parser, value, ty);
298 return parseIntLiteralImpl<uint64_t>(parser, value, ty);
299}
300
301void printIntLiteral(mlir::AsmPrinter &p, llvm::APInt value,
302 cir::IntTypeInterface ty) {
303 if (ty.isSigned())
304 p << value.getSExtValue();
305 else
306 p << value.getZExtValue();
307}
308
309LogicalResult IntAttr::verify(function_ref<InFlightDiagnostic()> emitError,
310 cir::IntTypeInterface type, llvm::APInt value) {
311 if (value.getBitWidth() != type.getWidth())
312 return emitError() << "type and value bitwidth mismatch: "
313 << type.getWidth() << " != " << value.getBitWidth();
314 return success();
315}
316
317//===----------------------------------------------------------------------===//
318// FPAttr definitions
319//===----------------------------------------------------------------------===//
320
321static void printFloatLiteral(AsmPrinter &p, APFloat value, Type ty) {
322 p << value;
323}
324
325static ParseResult parseFloatLiteral(AsmParser &parser,
326 FailureOr<APFloat> &value,
327 cir::FPTypeInterface fpType) {
328
329 APFloat parsedValue(0.0);
330 if (parser.parseFloat(fpType.getFloatSemantics(), parsedValue))
331 return failure();
332
333 value.emplace(parsedValue);
334 return success();
335}
336
337FPAttr FPAttr::getZero(Type type) {
338 return get(type,
339 APFloat::getZero(
340 mlir::cast<cir::FPTypeInterface>(type).getFloatSemantics()));
341}
342
343LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
344 cir::FPTypeInterface fpType, APFloat value) {
345 if (APFloat::SemanticsToEnum(fpType.getFloatSemantics()) !=
346 APFloat::SemanticsToEnum(value.getSemantics()))
347 return emitError() << "floating-point semantics mismatch";
348
349 return success();
350}
351
352//===----------------------------------------------------------------------===//
353// CmpThreeWayInfoAttr definitions
354//===----------------------------------------------------------------------===//
355
356std::string CmpThreeWayInfoAttr::getAlias() const {
357 std::string alias = "cmpinfo";
358
359 switch (getOrdering()) {
360 case CmpOrdering::Strong:
361 alias.append("_strong_");
362 break;
363 case CmpOrdering::Weak:
364 alias.append("_weak_");
365 break;
366 case CmpOrdering::Partial:
367 alias.append("_partial_");
368 break;
369 }
370
371 auto appendInt = [&](int64_t value) {
372 if (value < 0) {
373 alias.push_back('n');
374 value = -value;
375 }
376 alias.append(std::to_string(value));
377 };
378
379 alias.append("lt");
380 appendInt(getLt());
381 alias.append("eq");
382 appendInt(getEq());
383 alias.append("gt");
384 appendInt(getGt());
385
386 if (std::optional<int> unordered = getUnordered()) {
387 alias.append("un");
388 appendInt(unordered.value());
389 }
390
391 return alias;
392}
393
394LogicalResult
395CmpThreeWayInfoAttr::verify(function_ref<InFlightDiagnostic()> emitError,
396 CmpOrdering ordering, int64_t lt, int64_t eq,
397 int64_t gt, std::optional<int64_t> unordered) {
398 // The presence of unordered must match the value of ordering.
399 if ((ordering == CmpOrdering::Strong || ordering == CmpOrdering::Weak) &&
400 unordered) {
401 emitError() << "strong and weak ordering do not include unordered";
402 return failure();
403 }
404 if (ordering == CmpOrdering::Partial && !unordered) {
405 emitError() << "partial ordering requires unordered value";
406 return failure();
407 }
408
409 return success();
410}
411
412//===----------------------------------------------------------------------===//
413// ConstComplexAttr definitions
414//===----------------------------------------------------------------------===//
415
416LogicalResult
417ConstComplexAttr::verify(function_ref<InFlightDiagnostic()> emitError,
418 cir::ComplexType type, mlir::TypedAttr real,
419 mlir::TypedAttr imag) {
420 mlir::Type elemType = type.getElementType();
421 if (real.getType() != elemType)
422 return emitError()
423 << "type of the real part does not match the complex type";
424
425 if (imag.getType() != elemType)
426 return emitError()
427 << "type of the imaginary part does not match the complex type";
428
429 return success();
430}
431
432//===----------------------------------------------------------------------===//
433// DataMemberAttr definitions
434//===----------------------------------------------------------------------===//
435
436LogicalResult
437DataMemberAttr::verify(function_ref<InFlightDiagnostic()> emitError,
438 cir::DataMemberType ty,
439 std::optional<unsigned> memberIndex) {
440 // DataMemberAttr without a given index represents a null value.
441 if (!memberIndex.has_value())
442 return success();
443
444 cir::RecordType recTy = ty.getClassTy();
445 if (recTy.isIncomplete())
446 return emitError()
447 << "incomplete 'cir.record' cannot be used to build a non-null "
448 "data member pointer";
449
450 unsigned memberIndexValue = memberIndex.value();
451 if (memberIndexValue >= recTy.getNumElements())
452 return emitError()
453 << "member index of a #cir.data_member attribute is out of range";
454
455 mlir::Type memberTy = recTy.getMembers()[memberIndexValue];
456 if (memberTy != ty.getMemberTy())
457 return emitError()
458 << "member type of a #cir.data_member attribute must match the "
459 "attribute type";
460
461 return success();
462}
463
464//===----------------------------------------------------------------------===//
465// MethodAttr definitions
466//===----------------------------------------------------------------------===//
467
468LogicalResult MethodAttr::verify(function_ref<InFlightDiagnostic()> emitError,
469 cir::MethodType type,
470 std::optional<FlatSymbolRefAttr> symbol,
471 std::optional<uint64_t> vtable_offset) {
472 if (symbol.has_value() && vtable_offset.has_value())
473 return emitError()
474 << "at most one of symbol and vtable_offset can be present "
475 "in #cir.method";
476
477 return success();
478}
479
480Attribute MethodAttr::parse(AsmParser &parser, Type odsType) {
481 auto ty = mlir::cast<cir::MethodType>(odsType);
482
483 if (parser.parseLess().failed())
484 return {};
485
486 // Try to parse the null pointer constant.
487 if (parser.parseOptionalKeyword("null").succeeded()) {
488 if (parser.parseGreater().failed())
489 return {};
490 return get(ty);
491 }
492
493 // Try to parse a flat symbol ref for a pointer to non-virtual member
494 // function.
495 FlatSymbolRefAttr symbol;
496 mlir::OptionalParseResult parseSymbolRefResult =
497 parser.parseOptionalAttribute(symbol);
498 if (parseSymbolRefResult.has_value()) {
499 if (parseSymbolRefResult.value().failed())
500 return {};
501 if (parser.parseGreater().failed())
502 return {};
503 return get(ty, symbol);
504 }
505
506 // Parse a uint64 that represents the vtable offset.
507 std::uint64_t vtableOffset = 0;
508 if (parser.parseKeyword("vtable_offset"))
509 return {};
510 if (parser.parseEqual())
511 return {};
512 if (parser.parseInteger(vtableOffset))
513 return {};
514
515 if (parser.parseGreater())
516 return {};
517
518 return get(ty, vtableOffset);
519}
520
521void MethodAttr::print(AsmPrinter &printer) const {
522 auto symbol = getSymbol();
523 auto vtableOffset = getVtableOffset();
524
525 printer << '<';
526 if (symbol.has_value()) {
527 printer << *symbol;
528 } else if (vtableOffset.has_value()) {
529 printer << "vtable_offset = " << *vtableOffset;
530 } else {
531 printer << "null";
532 }
533 printer << '>';
534}
535
536//===----------------------------------------------------------------------===//
537// CIR ConstArrayAttr
538//===----------------------------------------------------------------------===//
539
540LogicalResult
541ConstArrayAttr::verify(function_ref<InFlightDiagnostic()> emitError, Type type,
542 Attribute elts, int trailingZerosNum) {
543
544 if (!(mlir::isa<ArrayAttr, StringAttr>(elts)))
545 return emitError() << "constant array expects ArrayAttr or StringAttr";
546
547 if (auto strAttr = mlir::dyn_cast<StringAttr>(elts)) {
548 const auto arrayTy = mlir::cast<ArrayType>(type);
549 const auto intTy = mlir::dyn_cast<IntType>(arrayTy.getElementType());
550
551 // TODO: add CIR type for char.
552 if (!intTy || intTy.getWidth() != 8)
553 return emitError()
554 << "constant array element for string literals expects "
555 "!cir.int<u, 8> element type";
556 return success();
557 }
558
559 assert(mlir::isa<ArrayAttr>(elts));
560 const auto arrayAttr = mlir::cast<mlir::ArrayAttr>(elts);
561 const auto arrayTy = mlir::cast<ArrayType>(type);
562
563 // Make sure both number of elements and subelement types match type.
564 if (arrayAttr.size() > arrayTy.getSize())
565 return emitError() << "constant array has " << arrayAttr.size()
566 << " values but array type has size "
567 << arrayTy.getSize();
568 if (arrayTy.getSize() != arrayAttr.size() + trailingZerosNum)
569 return emitError() << "constant array size should match type size";
570 return success();
571}
572
573Attribute ConstArrayAttr::parse(AsmParser &parser, Type type) {
574 mlir::FailureOr<Type> resultTy;
575 mlir::FailureOr<Attribute> resultVal;
576
577 // Parse literal '<'
578 if (parser.parseLess())
579 return {};
580
581 // Parse variable 'value'
582 resultVal = FieldParser<Attribute>::parse(parser);
583 if (failed(resultVal)) {
584 parser.emitError(
585 parser.getCurrentLocation(),
586 "failed to parse ConstArrayAttr parameter 'value' which is "
587 "to be a `Attribute`");
588 return {};
589 }
590
591 // ArrayAttrrs have per-element type, not the type of the array...
592 if (mlir::isa<ArrayAttr>(*resultVal)) {
593 // Array has implicit type: infer from const array type.
594 if (parser.parseOptionalColon().failed()) {
595 resultTy = type;
596 } else { // Array has explicit type: parse it.
597 resultTy = FieldParser<Type>::parse(parser);
598 if (failed(resultTy)) {
599 parser.emitError(
600 parser.getCurrentLocation(),
601 "failed to parse ConstArrayAttr parameter 'type' which is "
602 "to be a `::mlir::Type`");
603 return {};
604 }
605 }
606 } else {
607 auto ta = mlir::cast<TypedAttr>(*resultVal);
608 resultTy = ta.getType();
609 if (mlir::isa<mlir::NoneType>(*resultTy)) {
610 parser.emitError(parser.getCurrentLocation(),
611 "expected type declaration for string literal");
612 return {};
613 }
614 }
615
616 unsigned zeros = 0;
617 if (parser.parseOptionalComma().succeeded()) {
618 if (parser.parseOptionalKeyword("trailing_zeros").succeeded()) {
619 unsigned typeSize =
620 mlir::cast<cir::ArrayType>(resultTy.value()).getSize();
621 mlir::Attribute elts = resultVal.value();
622 if (auto str = mlir::dyn_cast<mlir::StringAttr>(elts))
623 zeros = typeSize - str.size();
624 else
625 zeros = typeSize - mlir::cast<mlir::ArrayAttr>(elts).size();
626 } else {
627 return {};
628 }
629 }
630
631 // Parse literal '>'
632 if (parser.parseGreater())
633 return {};
634
635 return parser.getChecked<ConstArrayAttr>(
636 parser.getCurrentLocation(), parser.getContext(), resultTy.value(),
637 resultVal.value(), zeros);
638}
639
640void ConstArrayAttr::print(AsmPrinter &printer) const {
641 printer << "<";
642 printer.printStrippedAttrOrType(getElts());
643 if (getTrailingZerosNum())
644 printer << ", trailing_zeros";
645 printer << ">";
646}
647
648//===----------------------------------------------------------------------===//
649// CIR ConstVectorAttr
650//===----------------------------------------------------------------------===//
651
652LogicalResult
653cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
654 Type type, ArrayAttr elts) {
655
656 if (!mlir::isa<cir::VectorType>(type))
657 return emitError() << "type of cir::ConstVectorAttr is not a "
658 "cir::VectorType: "
659 << type;
660
661 const auto vecType = mlir::cast<cir::VectorType>(type);
662
663 if (vecType.getSize() != elts.size())
664 return emitError()
665 << "number of constant elements should match vector size";
666
667 // Check if the types of the elements match
668 LogicalResult elementTypeCheck = success();
669 elts.walkImmediateSubElements(
670 [&](Attribute element) {
671 if (elementTypeCheck.failed()) {
672 // An earlier element didn't match
673 return;
674 }
675 auto typedElement = mlir::dyn_cast<TypedAttr>(element);
676 if (!typedElement ||
677 typedElement.getType() != vecType.getElementType()) {
678 elementTypeCheck = failure();
679 emitError() << "constant type should match vector element type";
680 }
681 },
682 [&](Type) {});
683
684 return elementTypeCheck;
685}
686
687//===----------------------------------------------------------------------===//
688// CIR VTableAttr
689//===----------------------------------------------------------------------===//
690
691LogicalResult cir::VTableAttr::verify(
692 llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::Type type,
693 mlir::ArrayAttr data) {
694 auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
695 if (!sTy)
696 return emitError() << "expected !cir.record type result";
697 if (sTy.getMembers().empty() || data.empty())
698 return emitError() << "expected record type with one or more subtype";
699
700 if (cir::ConstRecordAttr::verify(emitError, type, data).failed())
701 return failure();
702
703 for (const auto &element : data.getAsRange<mlir::Attribute>()) {
704 const auto &constArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(element);
705 if (!constArrayAttr)
706 return emitError() << "expected constant array subtype";
707
708 LogicalResult eltTypeCheck = success();
709 auto arrayElts = mlir::cast<ArrayAttr>(constArrayAttr.getElts());
710 arrayElts.walkImmediateSubElements(
711 [&](mlir::Attribute attr) {
712 if (mlir::isa<ConstPtrAttr, GlobalViewAttr>(attr))
713 return;
714
715 eltTypeCheck = emitError()
716 << "expected GlobalViewAttr or ConstPtrAttr";
717 },
718 [&](mlir::Type type) {});
719 if (eltTypeCheck.failed())
720 return eltTypeCheck;
721 }
722 return success();
723}
724
725//===----------------------------------------------------------------------===//
726// DynamicCastInfoAtttr definitions
727//===----------------------------------------------------------------------===//
728
729std::string DynamicCastInfoAttr::getAlias() const {
730 // The alias looks like: `dyn_cast_info_<src>_<dest>`
731
732 std::string alias = "dyn_cast_info_";
733
734 alias.append(getSrcRtti().getSymbol().getValue());
735 alias.push_back('_');
736 alias.append(getDestRtti().getSymbol().getValue());
737
738 return alias;
739}
740
741LogicalResult DynamicCastInfoAttr::verify(
742 function_ref<InFlightDiagnostic()> emitError, cir::GlobalViewAttr srcRtti,
743 cir::GlobalViewAttr destRtti, mlir::FlatSymbolRefAttr runtimeFunc,
744 mlir::FlatSymbolRefAttr badCastFunc, cir::IntAttr offsetHint) {
745 auto isRttiPtr = [](mlir::Type ty) {
746 // RTTI pointers are !cir.ptr<!u8i>.
747
748 auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty);
749 if (!ptrTy)
750 return false;
751
752 auto pointeeIntTy = mlir::dyn_cast<cir::IntType>(ptrTy.getPointee());
753 if (!pointeeIntTy)
754 return false;
755
756 return pointeeIntTy.isUnsigned() && pointeeIntTy.getWidth() == 8;
757 };
758
759 if (!isRttiPtr(srcRtti.getType()))
760 return emitError() << "srcRtti must be an RTTI pointer";
761
762 if (!isRttiPtr(destRtti.getType()))
763 return emitError() << "destRtti must be an RTTI pointer";
764
765 return success();
766}
767
768//===----------------------------------------------------------------------===//
769// CIR Dialect
770//===----------------------------------------------------------------------===//
771
772void CIRDialect::registerAttributes() {
773 addAttributes<
774#define GET_ATTRDEF_LIST
775#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
776 >();
777}
static mlir::ParseResult parseFloatLiteral(mlir::AsmParser &parser, mlir::FailureOr< llvm::APFloat > &value, cir::FPTypeInterface fpType)
static mlir::ParseResult parseIntLiteralImpl(mlir::AsmParser &p, llvm::APInt &value, cir::IntTypeInterface ty)
Definition CIRAttrs.cpp:278
void printAddressSpaceValue(mlir::AsmPrinter &p, cir::LangAddressSpace addrSpace)
Definition CIRAttrs.cpp:62
static void printConstPtr(mlir::AsmPrinter &p, mlir::IntegerAttr value)
static void printRecordMembers(mlir::AsmPrinter &p, mlir::ArrayAttr members)
Definition CIRAttrs.cpp:171
static mlir::ParseResult parseIntLiteral(mlir::AsmParser &parser, llvm::APInt &value, cir::IntTypeInterface ty)
Definition CIRAttrs.cpp:294
static void printIntLiteral(mlir::AsmPrinter &p, llvm::APInt value, cir::IntTypeInterface ty)
Definition CIRAttrs.cpp:301
static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser, mlir::IntegerAttr &value)
static bool isTooLargeForType(const mlir::APInt &value, IntT expectedValue)
Definition CIRAttrs.cpp:269
static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value, mlir::Type ty)
static mlir::ParseResult parseRecordMembers(mlir::AsmParser &parser, mlir::ArrayAttr &members)
Definition CIRAttrs.cpp:178
mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p, cir::LangAddressSpace &addrSpace)
Definition CIRAttrs.cpp:51
RangeSelector member(std::string ID)
Given a MemberExpr, selects the member token. ID is the node's binding in the match result.