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