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