clang 23.0.0git
CIRGenBuilder.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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#ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H
10#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H
11
12#include "Address.h"
13#include "CIRGenRecordLayout.h"
14#include "CIRGenTypeCache.h"
15#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
16#include "mlir/IR/Attributes.h"
17#include "mlir/IR/Builders.h"
18#include "mlir/IR/BuiltinAttributes.h"
19#include "mlir/Support/LLVM.h"
22
25#include "llvm/ADT/APFloat.h"
26#include "llvm/ADT/STLExtras.h"
27#include "llvm/IR/FPEnv.h"
28
29namespace clang::CIRGen {
30
32 const CIRGenTypeCache &typeCache;
33 bool isFPConstrained = false;
34 llvm::fp::ExceptionBehavior defaultConstrainedExcept = llvm::fp::ebStrict;
35 llvm::RoundingMode defaultConstrainedRounding = llvm::RoundingMode::Dynamic;
36
37 llvm::StringMap<unsigned> recordNames;
38 llvm::StringMap<unsigned> globalsVersioning;
39
40public:
41 CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)
42 : CIRBaseBuilderTy(mlirContext), typeCache(tc) {}
43
44 /// Get a cir::ConstArrayAttr for a string literal.
45 /// Note: This is different from what is returned by
46 /// mlir::Builder::getStringAttr() which is an mlir::StringAttr.
47 mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy,
48 std::optional<size_t> size,
49 bool ensureNullTerm = true) {
50 size_t finalSize = size.value_or(str.size());
51
52 size_t lastNonZeroPos = str.find_last_not_of('\0');
53 // If the string is full of null bytes, emit a #cir.zero rather than
54 // a #cir.const_array.
55 if (lastNonZeroPos == llvm::StringRef::npos) {
56 auto arrayTy = cir::ArrayType::get(eltTy, finalSize);
57 return cir::ZeroAttr::get(arrayTy);
58 }
59
60 // We emit trailing zeros for all trailing zeros, so the null-terminator in
61 // a constant is always in trailing zeros, and the null-terminator is
62 // skipped in the CIR representation.
63 size_t trailingZerosNum = finalSize - lastNonZeroPos - 1;
64 auto truncatedArrayTy =
65 cir::ArrayType::get(eltTy, finalSize - trailingZerosNum);
66 auto strAttr = mlir::StringAttr::get(str.drop_back(trailingZerosNum),
67 truncatedArrayTy);
68
69 // Most C strings are null terminated, so if we are ensuring there is one,
70 // grow the array size by 1 to add a trailing zero if necessary. The 'auto'
71 // calculation of trailing zeros (the difference between the provided string
72 // and the type) will ensure we get the count correct.
73 finalSize += (ensureNullTerm && trailingZerosNum == 0);
74
75 auto fullArrayTy = cir::ArrayType::get(eltTy, finalSize);
76 return cir::ConstArrayAttr::get(fullArrayTy, strAttr);
77 }
78
79 cir::ConstArrayAttr getConstArray(mlir::Attribute attrs,
80 cir::ArrayType arrayTy) const {
81 return cir::ConstArrayAttr::get(arrayTy, attrs);
82 }
83
84 mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr,
85 bool packed = false,
86 bool padded = false,
87 mlir::Type type = {});
88
89 cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr,
90 bool packed = false,
91 bool padded = false,
92 mlir::Type ty = {}) {
94 for (auto &f : arrayAttr) {
95 auto ta = mlir::cast<mlir::TypedAttr>(f);
96 members.push_back(ta.getType());
97 }
98
99 if (!ty)
100 ty = getAnonRecordTy(members, packed, padded);
101
102 auto sTy = mlir::cast<cir::RecordType>(ty);
103 return cir::ConstRecordAttr::get(sTy, arrayAttr);
104 }
105
106 cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr) {
107 cir::ConstRecordAttr anonRecord = getAnonConstRecord(fieldsAttr);
108 return cir::TypeInfoAttr::get(anonRecord.getType(), fieldsAttr);
109 }
110
111 std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }
112
113 std::string getUniqueRecordName(const std::string &baseName) {
114 auto it = recordNames.find(baseName);
115 if (it == recordNames.end()) {
116 recordNames[baseName] = 0;
117 return baseName;
118 }
119
120 return baseName + "." + std::to_string(recordNames[baseName]++);
121 }
122
123 //
124 // Floating point specific helpers
125 // -------------------------------
126 //
127
128 /// Enable/Disable use of constrained floating point math. When enabled the
129 /// CreateF<op>() calls instead create constrained floating point intrinsic
130 /// calls. Fast math flags are unaffected by this setting.
131 void setIsFPConstrained(bool isCon) { isFPConstrained = isCon; }
132
133 /// Query for the use of constrained floating point math
134 bool getIsFPConstrained() const { return isFPConstrained; }
135
136 /// Set the exception handling to be used with constrained floating point
137 void setDefaultConstrainedExcept(llvm::fp::ExceptionBehavior newExcept) {
138 assert(llvm::convertExceptionBehaviorToStr(newExcept) &&
139 "Garbage strict exception behavior!");
140 defaultConstrainedExcept = newExcept;
141 }
142
143 /// Get the exception handling used with constrained floating point
144 llvm::fp::ExceptionBehavior getDefaultConstrainedExcept() const {
145 return defaultConstrainedExcept;
146 }
147
148 /// Set the rounding mode handling to be used with constrained floating point
149 void setDefaultConstrainedRounding(llvm::RoundingMode newRounding) {
150 assert(llvm::convertRoundingModeToStr(newRounding) &&
151 "Garbage strict rounding mode!");
152 defaultConstrainedRounding = newRounding;
153 }
154
155 /// Get the rounding mode handling used with constrained floating point
156 llvm::RoundingMode getDefaultConstrainedRounding() const {
157 return defaultConstrainedRounding;
158 }
159
160 cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {
161 if (&format == &llvm::APFloat::IEEEdouble())
162 return cir::LongDoubleType::get(getContext(), typeCache.doubleTy);
163 if (&format == &llvm::APFloat::x87DoubleExtended())
164 return cir::LongDoubleType::get(getContext(), typeCache.fP80Ty);
165 if (&format == &llvm::APFloat::IEEEquad())
166 return cir::LongDoubleType::get(getContext(), typeCache.fP128Ty);
167 if (&format == &llvm::APFloat::PPCDoubleDouble())
168 llvm_unreachable("NYI: PPC double-double format for long double");
169 llvm_unreachable("Unsupported format for long double");
170 }
171
172 mlir::Type getPtrToVPtrType() {
173 return getPointerTo(cir::VPtrType::get(getContext()));
174 }
175
176 cir::FuncType getFuncType(llvm::ArrayRef<mlir::Type> params, mlir::Type retTy,
177 bool isVarArg = false) {
178 return cir::FuncType::get(params, retTy, isVarArg);
179 }
180
181 /// Get a CIR record kind from a AST declaration tag.
182 cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) {
183 switch (kind) {
185 return cir::RecordType::Class;
187 return cir::RecordType::Struct;
189 return cir::RecordType::Union;
191 llvm_unreachable("interface records are NYI");
193 llvm_unreachable("enums are not records");
194 }
195 llvm_unreachable("Unsupported record kind");
196 }
197
198 /// Get a CIR named record type.
199 ///
200 /// If a record already exists and is complete, but the client tries to fetch
201 /// it with a different set of attributes, this method will crash.
203 bool packed, bool padded,
204 llvm::StringRef name) {
205 const auto nameAttr = getStringAttr(name);
206 auto kind = cir::RecordType::RecordKind::Struct;
208
209 // Create or get the record.
210 auto type =
211 getType<cir::RecordType>(members, nameAttr, packed, padded, kind);
212
213 // If we found an existing type, verify that either it is incomplete or
214 // it matches the requested attributes.
215 assert(!type.isIncomplete() ||
216 (type.getMembers() == members && type.getPacked() == packed &&
217 type.getPadded() == padded));
218
219 // Complete an incomplete record or ensure the existing complete record
220 // matches the requested attributes.
221 type.complete(members, packed, padded);
222
223 return type;
224 }
225
226 cir::RecordType getCompleteRecordType(mlir::ArrayAttr fields,
227 bool packed = false,
228 bool padded = false,
229 llvm::StringRef name = "");
230
231 /// Get an incomplete CIR struct type. If we have a complete record
232 /// declaration, we may create an incomplete type and then add the
233 /// members, so \p rd here may be complete.
234 cir::RecordType getIncompleteRecordTy(llvm::StringRef name,
235 const clang::RecordDecl *rd) {
236 const mlir::StringAttr nameAttr = getStringAttr(name);
237 cir::RecordType::RecordKind kind = cir::RecordType::RecordKind::Struct;
238 if (rd)
240 return getType<cir::RecordType>(nameAttr, kind);
241 }
242
243 //
244 // Operation creation helpers
245 // --------------------------
246 //
247 cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst,
248 mlir::Value src, mlir::Value len) {
249 return cir::MemCpyOp::create(*this, loc, dst, src, len);
250 }
251
252 cir::MemMoveOp createMemMove(mlir::Location loc, mlir::Value dst,
253 mlir::Value src, mlir::Value len) {
254 return cir::MemMoveOp::create(*this, loc, dst, src, len);
255 }
256
257 cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst,
258 mlir::Value val, mlir::Value len) {
259 assert(val.getType() == getUInt8Ty());
260 return cir::MemSetOp::create(*this, loc, dst, {}, val, len);
261 }
262
263 cir::MemSetOp createMemSet(mlir::Location loc, Address dst, mlir::Value val,
264 mlir::Value len) {
265 mlir::IntegerAttr align = getAlignmentAttr(dst.getAlignment());
266 assert(val.getType() == getUInt8Ty());
267 return cir::MemSetOp::create(*this, loc, dst.getPointer(), align, val, len);
268 }
269 // ---------------------------
270
271 cir::DataMemberAttr getDataMemberAttr(cir::DataMemberType ty,
272 unsigned memberIndex) {
273 return cir::DataMemberAttr::get(ty, memberIndex);
274 }
275
276 cir::DataMemberAttr getNullDataMemberAttr(cir::DataMemberType ty) {
277 return cir::DataMemberAttr::get(ty);
278 }
279
280 // Return true if the value is a null constant such as null pointer, (+0.0)
281 // for floating-point or zero initializer
282 bool isNullValue(mlir::Attribute attr) const {
283 if (mlir::isa<cir::ZeroAttr>(attr))
284 return true;
285
286 if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
287 return ptrVal.isNullValue();
288
289 if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))
290 return intVal.isNullValue();
291
292 if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))
293 return !boolVal.getValue();
294
295 if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {
296 auto fpVal = fpAttr.getValue();
297 bool ignored;
298 llvm::APFloat fv(+0.0);
299 fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
300 &ignored);
301 return fv.bitwiseIsEqual(fpVal);
302 }
303 if (const auto recordVal = mlir::dyn_cast<cir::ConstRecordAttr>(attr)) {
304 for (const auto elt : recordVal.getMembers()) {
305 // FIXME(cir): the record's ID should not be considered a member.
306 if (mlir::isa<mlir::StringAttr>(elt))
307 continue;
308 if (!isNullValue(elt))
309 return false;
310 }
311 return true;
312 }
313
314 if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {
315 if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))
316 return false;
317
318 return llvm::all_of(
319 mlir::cast<mlir::ArrayAttr>(arrayVal.getElts()),
320 [&](const mlir::Attribute &elt) { return isNullValue(elt); });
321 }
322 return false;
323 }
324
325 //
326 // Type helpers
327 // ------------
328 //
329 cir::IntType getUIntNTy(int n) {
330 switch (n) {
331 case 8:
332 return getUInt8Ty();
333 case 16:
334 return getUInt16Ty();
335 case 32:
336 return getUInt32Ty();
337 case 64:
338 return getUInt64Ty();
339 default:
340 return cir::IntType::get(getContext(), n, false);
341 }
342 }
343
344 cir::IntType getSIntNTy(int n) {
345 switch (n) {
346 case 8:
347 return getSInt8Ty();
348 case 16:
349 return getSInt16Ty();
350 case 32:
351 return getSInt32Ty();
352 case 64:
353 return getSInt64Ty();
354 default:
355 return cir::IntType::get(getContext(), n, true);
356 }
357 }
358
359 cir::VoidType getVoidTy() { return typeCache.voidTy; }
360
361 cir::IntType getSInt8Ty() { return typeCache.sInt8Ty; }
362 cir::IntType getSInt16Ty() { return typeCache.sInt16Ty; }
363 cir::IntType getSInt32Ty() { return typeCache.sInt32Ty; }
364 cir::IntType getSInt64Ty() { return typeCache.sInt64Ty; }
365
366 cir::IntType getUInt8Ty() { return typeCache.uInt8Ty; }
367 cir::IntType getUInt16Ty() { return typeCache.uInt16Ty; }
368 cir::IntType getUInt32Ty() { return typeCache.uInt32Ty; }
369 cir::IntType getUInt64Ty() { return typeCache.uInt64Ty; }
370
371 cir::FP16Type getFp16Ty() { return typeCache.fP16Ty; }
372 cir::BF16Type getBfloat6Ty() { return typeCache.bFloat16Ty; }
373 cir::SingleType getSingleTy() { return typeCache.floatTy; }
374 cir::DoubleType getDoubleTy() { return typeCache.doubleTy; }
375
376 cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal);
377
378 cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal,
379 bool isUnsigned = true);
380
381 cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c);
382
383 cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t,
384 llvm::APFloat fpVal);
385
386 bool isInt8Ty(mlir::Type i) {
387 return i == typeCache.uInt8Ty || i == typeCache.sInt8Ty;
388 }
389 bool isInt16Ty(mlir::Type i) {
390 return i == typeCache.uInt16Ty || i == typeCache.sInt16Ty;
391 }
392 bool isInt32Ty(mlir::Type i) {
393 return i == typeCache.uInt32Ty || i == typeCache.sInt32Ty;
394 }
395 bool isInt64Ty(mlir::Type i) {
396 return i == typeCache.uInt64Ty || i == typeCache.sInt64Ty;
397 }
398 bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
399
400 cir::IntType getExtendedIntTy(cir::IntType ty, bool isSigned) {
401 switch (ty.getWidth()) {
402 case 8:
403 return isSigned ? typeCache.sInt16Ty : typeCache.uInt16Ty;
404 case 16:
405 return isSigned ? typeCache.sInt32Ty : typeCache.uInt32Ty;
406 case 32:
407 return isSigned ? typeCache.sInt64Ty : typeCache.uInt64Ty;
408 default:
409 llvm_unreachable("NYI");
410 }
411 }
412
413 cir::IntType getTruncatedIntTy(cir::IntType ty, bool isSigned) {
414 switch (ty.getWidth()) {
415 case 16:
416 return isSigned ? typeCache.sInt8Ty : typeCache.uInt8Ty;
417 case 32:
418 return isSigned ? typeCache.sInt16Ty : typeCache.uInt16Ty;
419 case 64:
420 return isSigned ? typeCache.sInt32Ty : typeCache.uInt32Ty;
421 default:
422 llvm_unreachable("NYI");
423 }
424 }
425
426 cir::VectorType
427 getExtendedOrTruncatedElementVectorType(cir::VectorType vt, bool isExtended,
428 bool isSigned = false) {
429 auto elementTy = mlir::dyn_cast_or_null<cir::IntType>(vt.getElementType());
430 assert(elementTy && "expected int vector");
431 return cir::VectorType::get(isExtended
432 ? getExtendedIntTy(elementTy, isSigned)
433 : getTruncatedIntTy(elementTy, isSigned),
434 vt.getSize());
435 }
436
437 // Fetch the type representing a pointer to unsigned int8 values.
438 cir::PointerType getUInt8PtrTy() { return typeCache.uInt8PtrTy; }
439
440 /// Get a CIR anonymous record type.
442 bool packed = false, bool padded = false) {
444 auto kind = cir::RecordType::RecordKind::Struct;
445 return getType<cir::RecordType>(members, packed, padded, kind);
446 }
447
448 //===--------------------------------------------------------------------===//
449 // Constant creation helpers
450 //===--------------------------------------------------------------------===//
451 cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) {
452 return getConstantInt(loc, getSInt32Ty(), c);
453 }
454 cir::ConstantOp getUInt32(uint32_t c, mlir::Location loc) {
455 return getConstantInt(loc, getUInt32Ty(), c);
456 }
457 cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc) {
458 return getConstantInt(loc, getSInt64Ty(), c);
459 }
460 cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc) {
461 return getConstantInt(loc, getUInt64Ty(), c);
462 }
463
464 cir::ConstantOp getZero(mlir::Location loc, mlir::Type ty) {
465 // TODO: dispatch creation for primitive types.
466 assert((mlir::isa<cir::RecordType>(ty) || mlir::isa<cir::ArrayType>(ty) ||
467 mlir::isa<cir::VectorType>(ty)) &&
468 "NYI for other types");
469 return cir::ConstantOp::create(*this, loc, cir::ZeroAttr::get(ty));
470 }
471
472 //===--------------------------------------------------------------------===//
473 // UnaryOp creation helpers
474 //===--------------------------------------------------------------------===//
475 mlir::Value createNeg(mlir::Value value) {
476
477 if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
478 // Source is a unsigned integer: first cast it to signed.
479 if (intTy.isUnsigned())
480 value = createIntCast(value, getSIntNTy(intTy.getWidth()));
481 return createMinus(value.getLoc(), value);
482 }
483
484 llvm_unreachable("negation for the given type is NYI");
485 }
486
487 mlir::Value createFNeg(mlir::Value value) {
488 assert(mlir::isa<cir::FPTypeInterface>(value.getType()) &&
489 "Non-fp input type!");
490
494
495 return createMinus(value.getLoc(), value);
496 }
497
498 //===--------------------------------------------------------------------===//
499 // BinaryOp creation helpers
500 //===--------------------------------------------------------------------===//
501 mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
505
506 return cir::SubOp::create(*this, loc, lhs, rhs);
507 }
508
509 mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
513
514 return cir::AddOp::create(*this, loc, lhs, rhs);
515 }
516
517 mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
521
522 return cir::MulOp::create(*this, loc, lhs, rhs);
523 }
524 mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
528
529 return cir::DivOp::create(*this, loc, lhs, rhs);
530 }
531
532 //===--------------------------------------------------------------------===//
533 // CastOp creation helpers
534 //===--------------------------------------------------------------------===//
535
536 // TODO: split this to createFPExt/createFPTrunc when we have dedicated cast
537 // operations.
538 mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {
540
541 return cir::CastOp::create(*this, v.getLoc(), destType,
542 cir::CastKind::floating, v);
543 }
544
545 mlir::Value createDynCast(mlir::Location loc, mlir::Value src,
546 cir::PointerType destType, bool isRefCast,
547 cir::DynamicCastInfoAttr info) {
548 auto castKind =
549 isRefCast ? cir::DynamicCastKind::Ref : cir::DynamicCastKind::Ptr;
550 return cir::DynamicCastOp::create(*this, loc, destType, castKind, src, info,
551 /*relative_layout=*/false);
552 }
553
554 mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src,
555 bool vtableUseRelativeLayout) {
556 // TODO(cir): consider address space here.
558 cir::PointerType destTy = getVoidPtrTy();
559 return cir::DynamicCastOp::create(
560 *this, loc, destTy, cir::DynamicCastKind::Ptr, src,
561 cir::DynamicCastInfoAttr{}, vtableUseRelativeLayout);
562 }
563
564 //===--------------------------------------------------------------------===//
565 // Address creation helpers
566 //===--------------------------------------------------------------------===//
567 Address createBaseClassAddr(mlir::Location loc, Address addr,
568 mlir::Type destType, unsigned offset,
569 bool assumeNotNull) {
570 if (destType == addr.getElementType())
571 return addr;
572
573 auto ptrTy = getPointerTo(destType);
574 auto baseAddr =
575 cir::BaseClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),
576 mlir::APInt(64, offset), assumeNotNull);
577 return Address(baseAddr, destType, addr.getAlignment());
578 }
579
580 Address createDerivedClassAddr(mlir::Location loc, Address addr,
581 mlir::Type destType, unsigned offset,
582 bool assumeNotNull) {
583 if (destType == addr.getElementType())
584 return addr;
585
586 cir::PointerType ptrTy = getPointerTo(destType);
587 auto derivedAddr =
588 cir::DerivedClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),
589 mlir::APInt(64, offset), assumeNotNull);
590 return Address(derivedAddr, destType, addr.getAlignment());
591 }
592
593 //===--------------------------------------------------------------------===//
594 // Virtual Address creation helpers
595 //===--------------------------------------------------------------------===//
596 mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,
597 mlir::Value addr, uint64_t offset) {
598 return cir::VTTAddrPointOp::create(*this, loc, retTy,
599 mlir::FlatSymbolRefAttr{}, addr, offset);
600 }
601
602 mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,
603 mlir::FlatSymbolRefAttr sym, uint64_t offset) {
604 return cir::VTTAddrPointOp::create(*this, loc, retTy, sym, mlir::Value{},
605 offset);
606 }
607
608 //===--------------------------------------------------------------------===//
609 // Other creation helpers
610 //===--------------------------------------------------------------------===//
611 cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,
612 cir::FPClassTest flags) {
613 return cir::IsFPClassOp::create(*this, loc, src, flags);
614 }
615
616 /// Cast the element type of the given address to a different type,
617 /// preserving information like the alignment.
618 Address createElementBitCast(mlir::Location loc, Address addr,
619 mlir::Type destType) {
620 if (destType == addr.getElementType())
621 return addr;
622
623 auto ptrTy = getPointerTo(destType);
624 return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType,
625 addr.getAlignment());
626 }
627
628 cir::LoadOp createLoad(mlir::Location loc, Address addr,
629 bool isVolatile = false) {
630 mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment());
631 return cir::LoadOp::create(*this, loc, addr.getPointer(), /*isDeref=*/false,
632 isVolatile, /*alignment=*/align,
633 /*sync_scope=*/cir::SyncScopeKindAttr{},
634 /*mem_order=*/cir::MemOrderAttr{});
635 }
636
637 cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty,
638 mlir::Value ptr, llvm::MaybeAlign align) {
639 if (ty != mlir::cast<cir::PointerType>(ptr.getType()).getPointee())
640 ptr = createPtrBitcast(ptr, ty);
641 uint64_t alignment = align ? align->value() : 0;
642 mlir::IntegerAttr alignAttr = getAlignmentAttr(alignment);
643 return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false,
644 /*isVolatile=*/false, alignAttr,
645 /*sync_scope=*/cir::SyncScopeKindAttr{},
646 /*mem_order=*/cir::MemOrderAttr{});
647 }
648
649 cir::LoadOp
650 createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr,
652 return createAlignedLoad(loc, ty, ptr, align.getAsAlign());
653 }
654
655 cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst,
656 bool isVolatile = false,
657 mlir::IntegerAttr align = {},
658 cir::SyncScopeKindAttr scope = {},
659 cir::MemOrderAttr order = {}) {
660 if (!align)
661 align = getAlignmentAttr(dst.getAlignment());
662 return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), isVolatile,
663 align, scope, order);
664 }
665
666 /// Create a cir.complex.real_ptr operation that derives a pointer to the real
667 /// part of the complex value pointed to by the specified pointer value.
668 mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {
669 auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
670 auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
671 return cir::ComplexRealPtrOp::create(
672 *this, loc, getPointerTo(srcComplexTy.getElementType()), value);
673 }
674
675 Address createComplexRealPtr(mlir::Location loc, Address addr) {
676 return Address{createComplexRealPtr(loc, addr.getPointer()),
677 addr.getAlignment()};
678 }
679
680 /// Create a cir.complex.imag_ptr operation that derives a pointer to the
681 /// imaginary part of the complex value pointed to by the specified pointer
682 /// value.
683 mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) {
684 auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
685 auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
686 return cir::ComplexImagPtrOp::create(
687 *this, loc, getPointerTo(srcComplexTy.getElementType()), value);
688 }
689
690 Address createComplexImagPtr(mlir::Location loc, Address addr) {
691 return Address{createComplexImagPtr(loc, addr.getPointer()),
692 addr.getAlignment()};
693 }
694
695 cir::GetRuntimeMemberOp createGetIndirectMember(mlir::Location loc,
696 mlir::Value objectPtr,
697 mlir::Value memberPtr) {
698 auto memberPtrTy = mlir::cast<cir::DataMemberType>(memberPtr.getType());
699
700 // TODO(cir): consider address space.
702 cir::PointerType resultTy = getPointerTo(memberPtrTy.getMemberTy());
703
704 return cir::GetRuntimeMemberOp::create(*this, loc, resultTy, objectPtr,
705 memberPtr);
706 }
707
708 /// Create a cir.ptr_stride operation to get access to an array element.
709 /// \p idx is the index of the element to access, \p shouldDecay is true if
710 /// the result should decay to a pointer to the element type.
711 mlir::Value getArrayElement(mlir::Location arrayLocBegin,
712 mlir::Location arrayLocEnd, mlir::Value arrayPtr,
713 mlir::Type eltTy, mlir::Value idx,
714 bool shouldDecay);
715
716 /// Returns a decayed pointer to the first element of the array
717 /// pointed to by \p arrayPtr.
718 mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,
719 mlir::Type eltTy);
720
721 // Convert byte offset to sequence of high-level indices suitable for
722 // GlobalViewAttr. Ideally we shouldn't deal with low-level offsets at all
723 // but currently some parts of Clang AST, which we don't want to touch just
724 // yet, return them.
726 int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,
728
729 // Convert high-level indices (e.g. from GlobalViewAttr) to byte offset.
731 mlir::Type ty,
733
734 /// Creates a versioned global variable. If the symbol is already taken, an ID
735 /// will be appended to the symbol. The returned global must always be queried
736 /// for its name so it can be referenced correctly.
737 [[nodiscard]] cir::GlobalOp
738 createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc,
739 mlir::StringRef name, mlir::Type type, bool isConstant,
740 cir::GlobalLinkageKind linkage,
741 mlir::ptr::MemorySpaceAttrInterface addrSpace = {}) {
742 // Create a unique name if the given name is already taken.
743 std::string uniqueName;
744 if (unsigned version = globalsVersioning[name.str()]++)
745 uniqueName = name.str() + "." + std::to_string(version);
746 else
747 uniqueName = name.str();
748
749 return createGlobal(module, loc, uniqueName, type, isConstant, linkage,
750 addrSpace);
751 }
752
753 cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {
754 return cir::StackSaveOp::create(*this, loc, ty);
755 }
756
757 cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v) {
758 return cir::StackRestoreOp::create(*this, loc, v);
759 }
760
762 mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
763 const llvm::APSInt &ltRes, const llvm::APSInt &eqRes,
764 const llvm::APSInt &gtRes, cir::CmpOrdering ordering) {
765 assert(ltRes.getBitWidth() == eqRes.getBitWidth() &&
766 ltRes.getBitWidth() == gtRes.getBitWidth() &&
767 "the three comparison results must have the same bit width");
768 assert((ordering == cir::CmpOrdering::Strong ||
769 ordering == cir::CmpOrdering::Weak) &&
770 "total ordering must be strong or weak");
771 cir::IntType cmpResultTy = getSIntNTy(ltRes.getBitWidth());
772 auto infoAttr = cir::CmpThreeWayInfoAttr::get(
773 getContext(), ordering, ltRes.getSExtValue(), eqRes.getSExtValue(),
774 gtRes.getSExtValue());
775 return cir::CmpThreeWayOp::create(*this, loc, cmpResultTy, lhs, rhs,
776 infoAttr);
777 }
778
780 mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
781 const llvm::APSInt &ltRes, const llvm::APSInt &eqRes,
782 const llvm::APSInt &gtRes, const llvm::APSInt &unorderedRes) {
783 assert(ltRes.getBitWidth() == eqRes.getBitWidth() &&
784 ltRes.getBitWidth() == gtRes.getBitWidth() &&
785 ltRes.getBitWidth() == unorderedRes.getBitWidth() &&
786 "the four comparison results must have the same bit width");
787 cir::IntType cmpResultTy = getSIntNTy(ltRes.getBitWidth());
788 auto infoAttr = cir::CmpThreeWayInfoAttr::get(
789 getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(),
790 gtRes.getSExtValue(), unorderedRes.getSExtValue());
791 return cir::CmpThreeWayOp::create(*this, loc, cmpResultTy, lhs, rhs,
792 infoAttr);
793 }
794
795 mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
796 Address dstAddr, mlir::Type storageType,
797 mlir::Value src, const CIRGenBitFieldInfo &info,
798 bool isLvalueVolatile, bool useVolatile) {
799 unsigned offset = useVolatile ? info.volatileOffset : info.offset;
800
801 // If using AAPCS and the field is volatile, load with the size of the
802 // declared field
803 storageType =
804 useVolatile ? cir::IntType::get(storageType.getContext(),
805 info.volatileStorageSize, info.isSigned)
806 : storageType;
807 return cir::SetBitfieldOp::create(
808 *this, loc, resultType, dstAddr.getPointer(), storageType, src,
809 info.name, info.size, offset, info.isSigned, isLvalueVolatile,
810 dstAddr.getAlignment().getAsAlign().value());
811 }
812
813 mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,
814 Address addr, mlir::Type storageType,
815 const CIRGenBitFieldInfo &info,
816 bool isLvalueVolatile, bool useVolatile) {
817 unsigned offset = useVolatile ? info.volatileOffset : info.offset;
818
819 // If using AAPCS and the field is volatile, load with the size of the
820 // declared field
821 storageType =
822 useVolatile ? cir::IntType::get(storageType.getContext(),
823 info.volatileStorageSize, info.isSigned)
824 : storageType;
825 return cir::GetBitfieldOp::create(*this, loc, resultType, addr.getPointer(),
826 storageType, info.name, info.size, offset,
827 info.isSigned, isLvalueVolatile,
828 addr.getAlignment().getAsAlign().value());
829 }
830
831 mlir::Value createMaskedLoad(mlir::Location loc, mlir::Type ty,
832 mlir::Value ptr, llvm::Align alignment,
833 mlir::Value mask, mlir::Value passThru) {
834 assert(mlir::isa<cir::VectorType>(ty) && "Type should be vector");
835 assert(mask && "Mask should not be all-ones (null)");
836
837 if (!passThru)
838 passThru = this->getConstant(loc, cir::PoisonAttr::get(ty));
839
840 auto alignAttr =
841 this->getI64IntegerAttr(static_cast<int64_t>(alignment.value()));
842
843 return cir::VecMaskedLoadOp::create(*this, loc, ty, ptr, mask, passThru,
844 alignAttr);
845 }
846
847 cir::VecShuffleOp
848 createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2,
850 auto vecType = mlir::cast<cir::VectorType>(vec1.getType());
851 auto resultTy =
852 cir::VectorType::get(vecType.getElementType(), maskAttrs.size());
853 return cir::VecShuffleOp::create(*this, loc, resultTy, vec1, vec2,
854 getArrayAttr(maskAttrs));
855 }
856
857 cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
858 mlir::Value vec2,
860 auto maskAttrs = llvm::to_vector_of<mlir::Attribute>(
861 llvm::map_range(mask, [&](int32_t idx) {
862 return cir::IntAttr::get(getSInt32Ty(), idx);
863 }));
864 return createVecShuffle(loc, vec1, vec2, maskAttrs);
865 }
866
867 cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
869 /// Create a unary shuffle. The second vector operand of the IR instruction
870 /// is poison.
871 cir::ConstantOp poison =
872 getConstant(loc, cir::PoisonAttr::get(vec1.getType()));
873 return createVecShuffle(loc, vec1, poison, mask);
874 }
875
876 template <typename... Operands>
877 mlir::Value emitIntrinsicCallOp(mlir::Location loc, const llvm::StringRef str,
878 const mlir::Type &resTy, Operands &&...op) {
879 return cir::LLVMIntrinsicCallOp::create(*this, loc,
880 this->getStringAttr(str), resTy,
881 std::forward<Operands>(op)...)
882 .getResult();
883 }
884};
885
886} // namespace clang::CIRGen
887
888#endif
static bool isUnsigned(SValBuilder &SVB, NonLoc Value)
TokenType getType() const
Returns the token's type, e.g.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
__device__ __2f16 float c
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
cir::PointerType getPointerTo(mlir::Type ty)
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
mlir::Value createIntCast(mlir::Value src, mlir::Type newTy)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
CIRBaseBuilderTy(mlir::MLIRContext &mlirContext)
mlir::IntegerAttr getAlignmentAttr(clang::CharUnits alignment)
mlir::Value createMinus(mlir::Location loc, mlir::Value input, bool nsw=false)
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, int64_t value)
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule, mlir::Location loc, mlir::StringRef name, mlir::Type type, bool isConstant, cir::GlobalLinkageKind linkage, mlir::ptr::MemorySpaceAttrInterface addrSpace)
mlir::Value getPointer() const
Definition Address.h:96
mlir::Type getElementType() const
Definition Address.h:123
clang::CharUnits getAlignment() const
Definition Address.h:136
cir::MemMoveOp createMemMove(mlir::Location loc, mlir::Value dst, mlir::Value src, mlir::Value len)
cir::RecordType getCompleteNamedRecordType(llvm::ArrayRef< mlir::Type > members, bool packed, bool padded, llvm::StringRef name)
Get a CIR named record type.
cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty)
cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr)
cir::CmpThreeWayOp createThreeWayCmpTotalOrdering(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, const llvm::APSInt &ltRes, const llvm::APSInt &eqRes, const llvm::APSInt &gtRes, cir::CmpOrdering ordering)
mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value)
Create a cir.complex.real_ptr operation that derives a pointer to the real part of the complex value ...
cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2, llvm::ArrayRef< int64_t > mask)
cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc)
cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind)
Get a CIR record kind from a AST declaration tag.
mlir::Value emitIntrinsicCallOp(mlir::Location loc, const llvm::StringRef str, const mlir::Type &resTy, Operands &&...op)
cir::IntType getSIntNTy(int n)
cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr, bool packed=false, bool padded=false, mlir::Type ty={})
cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc)
cir::IntType getTruncatedIntTy(cir::IntType ty, bool isSigned)
cir::RecordType getIncompleteRecordTy(llvm::StringRef name, const clang::RecordDecl *rd)
Get an incomplete CIR struct type.
cir::ConstantOp getUInt32(uint32_t c, mlir::Location loc)
void setDefaultConstrainedRounding(llvm::RoundingMode newRounding)
Set the rounding mode handling to be used with constrained floating point.
cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst, mlir::Value src, mlir::Value len)
cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2, llvm::ArrayRef< mlir::Attribute > maskAttrs)
cir::PointerType getUInt8PtrTy()
std::string getUniqueRecordName(const std::string &baseName)
mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr, bool packed=false, bool padded=false, mlir::Type type={})
cir::CmpThreeWayOp createThreeWayCmpPartialOrdering(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, const llvm::APSInt &ltRes, const llvm::APSInt &eqRes, const llvm::APSInt &gtRes, const llvm::APSInt &unorderedRes)
cir::RecordType getAnonRecordTy(llvm::ArrayRef< mlir::Type > members, bool packed=false, bool padded=false)
Get a CIR anonymous record type.
mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy, mlir::FlatSymbolRefAttr sym, uint64_t offset)
mlir::Value createMaskedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr, llvm::Align alignment, mlir::Value mask, mlir::Value passThru)
Address createBaseClassAddr(mlir::Location loc, Address addr, mlir::Type destType, unsigned offset, bool assumeNotNull)
mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value)
Create a cir.complex.imag_ptr operation that derives a pointer to the imaginary part of the complex v...
mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr, mlir::Type eltTy)
Returns a decayed pointer to the first element of the array pointed to by arrayPtr.
cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr, llvm::MaybeAlign align)
cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t, llvm::APFloat fpVal)
mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType)
cir::FuncType getFuncType(llvm::ArrayRef< mlir::Type > params, mlir::Type retTy, bool isVarArg=false)
cir::MemSetOp createMemSet(mlir::Location loc, Address dst, mlir::Value val, mlir::Value len)
mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::IntType getExtendedIntTy(cir::IntType ty, bool isSigned)
Address createDerivedClassAddr(mlir::Location loc, Address addr, mlir::Type destType, unsigned offset, bool assumeNotNull)
uint64_t computeOffsetFromGlobalViewIndices(const cir::CIRDataLayout &layout, mlir::Type ty, llvm::ArrayRef< int64_t > indices)
cir::GetRuntimeMemberOp createGetIndirectMember(mlir::Location loc, mlir::Value objectPtr, mlir::Value memberPtr)
llvm::RoundingMode getDefaultConstrainedRounding() const
Get the rounding mode handling used with constrained floating point.
Address createElementBitCast(mlir::Location loc, Address addr, mlir::Type destType)
Cast the element type of the given address to a different type, preserving information like the align...
void setDefaultConstrainedExcept(llvm::fp::ExceptionBehavior newExcept)
Set the exception handling to be used with constrained floating point.
mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src, bool vtableUseRelativeLayout)
cir::ConstantOp getZero(mlir::Location loc, mlir::Type ty)
cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1, llvm::ArrayRef< int64_t > mask)
mlir::Value createFNeg(mlir::Value value)
mlir::Value createDynCast(mlir::Location loc, mlir::Value src, cir::PointerType destType, bool isRefCast, cir::DynamicCastInfoAttr info)
llvm::fp::ExceptionBehavior getDefaultConstrainedExcept() const
Get the exception handling used with constrained floating point.
mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType, Address addr, mlir::Type storageType, const CIRGenBitFieldInfo &info, bool isLvalueVolatile, bool useVolatile)
bool isNullValue(mlir::Attribute attr) const
cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v)
mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType, Address dstAddr, mlir::Type storageType, mlir::Value src, const CIRGenBitFieldInfo &info, bool isLvalueVolatile, bool useVolatile)
Address createComplexRealPtr(mlir::Location loc, Address addr)
mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::GlobalOp createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc, mlir::StringRef name, mlir::Type type, bool isConstant, cir::GlobalLinkageKind linkage, mlir::ptr::MemorySpaceAttrInterface addrSpace={})
Creates a versioned global variable.
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
bool getIsFPConstrained() const
Query for the use of constrained floating point math.
CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)
cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src, cir::FPClassTest flags)
cir::RecordType getCompleteRecordType(mlir::ArrayAttr fields, bool packed=false, bool padded=false, llvm::StringRef name="")
mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy, std::optional< size_t > size, bool ensureNullTerm=true)
Get a cir::ConstArrayAttr for a string literal.
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
void setIsFPConstrained(bool isCon)
Enable/Disable use of constrained floating point math.
void computeGlobalViewIndicesFromFlatOffset(int64_t offset, mlir::Type ty, cir::CIRDataLayout layout, llvm::SmallVectorImpl< int64_t > &indices)
Address createComplexImagPtr(mlir::Location loc, Address addr)
mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::VectorType getExtendedOrTruncatedElementVectorType(cir::VectorType vt, bool isExtended, bool isSigned=false)
cir::DataMemberAttr getNullDataMemberAttr(cir::DataMemberType ty)
cir::ConstantOp getSInt32(int32_t c, mlir::Location loc)
mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy, mlir::Value addr, uint64_t offset)
cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst, mlir::Value val, mlir::Value len)
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false)
cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const
cir::ConstArrayAttr getConstArray(mlir::Attribute attrs, cir::ArrayType arrayTy) const
mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::IntType getUIntNTy(int n)
mlir::Value getArrayElement(mlir::Location arrayLocBegin, mlir::Location arrayLocEnd, mlir::Value arrayPtr, mlir::Type eltTy, mlir::Value idx, bool shouldDecay)
Create a cir.ptr_stride operation to get access to an array element.
mlir::Value createNeg(mlir::Value value)
cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr, clang::CharUnits align=clang::CharUnits::One())
cir::DataMemberAttr getDataMemberAttr(cir::DataMemberType ty, unsigned memberIndex)
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
Definition CharUnits.h:189
static CharUnits One()
One - Construct a CharUnits quantity of one.
Definition CharUnits.h:58
Represents a struct/union/class.
Definition Decl.h:4342
TagKind getTagKind() const
Definition Decl.h:3932
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
TagTypeKind
The kind of a tag type.
Definition TypeBase.h:5981
@ Interface
The "__interface" keyword.
Definition TypeBase.h:5986
@ Struct
The "struct" keyword.
Definition TypeBase.h:5983
@ Class
The "class" keyword.
Definition TypeBase.h:5992
@ Union
The "union" keyword.
Definition TypeBase.h:5989
@ Enum
The "enum" keyword.
Definition TypeBase.h:5995
static bool metaDataNode()
static bool addressSpace()
static bool fpConstraints()
static bool astRecordDeclAttr()
static bool fastMathFlags()
Record with information about how a bitfield should be accessed.
unsigned offset
The offset within a contiguous run of bitfields that are represented as a single "field" within the c...
unsigned volatileStorageSize
The storage size in bits which should be used when accessing this bitfield.
unsigned size
The total size of the bit-field, in bits.
unsigned isSigned
Whether the bit-field is signed.
unsigned volatileOffset
The offset within a contiguous run of bitfields that are represented as a single "field" within the c...
llvm::StringRef name
The name of a bitfield.
This structure provides a set of types that are commonly used during IR emission.