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