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