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