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