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/IR/Attributes.h"
16#include "mlir/IR/BuiltinAttributes.h"
17#include "mlir/Support/LLVM.h"
20
23#include "llvm/ADT/APFloat.h"
24#include "llvm/ADT/STLExtras.h"
25
26namespace clang::CIRGen {
27
29 const CIRGenTypeCache &typeCache;
30 llvm::StringMap<unsigned> recordNames;
31 llvm::StringMap<unsigned> globalsVersioning;
32
33public:
34 CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)
35 : CIRBaseBuilderTy(mlirContext), typeCache(tc) {}
36
37 /// Get a cir::ConstArrayAttr for a string literal.
38 /// Note: This is different from what is returned by
39 /// mlir::Builder::getStringAttr() which is an mlir::StringAttr.
40 mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy,
41 std::optional<size_t> size) {
42 size_t finalSize = size.value_or(str.size());
43
44 size_t lastNonZeroPos = str.find_last_not_of('\0');
45 // If the string is full of null bytes, emit a #cir.zero rather than
46 // a #cir.const_array.
47 if (lastNonZeroPos == llvm::StringRef::npos) {
48 auto arrayTy = cir::ArrayType::get(eltTy, finalSize);
49 return cir::ZeroAttr::get(arrayTy);
50 }
51 // We emit trailing zeros only if there are multiple trailing zeros.
52 size_t trailingZerosNum = 0;
53 if (finalSize > lastNonZeroPos + 2)
54 trailingZerosNum = finalSize - lastNonZeroPos - 1;
55 auto truncatedArrayTy =
56 cir::ArrayType::get(eltTy, finalSize - trailingZerosNum);
57 auto fullArrayTy = cir::ArrayType::get(eltTy, finalSize);
58 return cir::ConstArrayAttr::get(
59 fullArrayTy,
60 mlir::StringAttr::get(str.drop_back(trailingZerosNum),
61 truncatedArrayTy),
62 trailingZerosNum);
63 }
64
65 cir::ConstArrayAttr getConstArray(mlir::Attribute attrs,
66 cir::ArrayType arrayTy) const {
67 return cir::ConstArrayAttr::get(arrayTy, attrs);
68 }
69
70 mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr,
71 bool packed = false,
72 bool padded = false,
73 mlir::Type type = {});
74
75 cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr,
76 bool packed = false,
77 bool padded = false,
78 mlir::Type ty = {}) {
80 for (auto &f : arrayAttr) {
81 auto ta = mlir::cast<mlir::TypedAttr>(f);
82 members.push_back(ta.getType());
83 }
84
85 if (!ty)
86 ty = getAnonRecordTy(members, packed, padded);
87
88 auto sTy = mlir::cast<cir::RecordType>(ty);
89 return cir::ConstRecordAttr::get(sTy, arrayAttr);
90 }
91
92 cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr) {
93 cir::ConstRecordAttr anonRecord = getAnonConstRecord(fieldsAttr);
94 return cir::TypeInfoAttr::get(anonRecord.getType(), fieldsAttr);
95 }
96
97 std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }
98
99 std::string getUniqueRecordName(const std::string &baseName) {
100 auto it = recordNames.find(baseName);
101 if (it == recordNames.end()) {
102 recordNames[baseName] = 0;
103 return baseName;
104 }
105
106 return baseName + "." + std::to_string(recordNames[baseName]++);
107 }
108
109 cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {
110 if (&format == &llvm::APFloat::IEEEdouble())
111 return cir::LongDoubleType::get(getContext(), typeCache.doubleTy);
112 if (&format == &llvm::APFloat::x87DoubleExtended())
113 return cir::LongDoubleType::get(getContext(), typeCache.fP80Ty);
114 if (&format == &llvm::APFloat::IEEEquad())
115 return cir::LongDoubleType::get(getContext(), typeCache.fP128Ty);
116 if (&format == &llvm::APFloat::PPCDoubleDouble())
117 llvm_unreachable("NYI: PPC double-double format for long double");
118 llvm_unreachable("Unsupported format for long double");
119 }
120
121 mlir::Type getPtrToVPtrType() {
122 return getPointerTo(cir::VPtrType::get(getContext()));
123 }
124
125 cir::FuncType getFuncType(llvm::ArrayRef<mlir::Type> params, mlir::Type retTy,
126 bool isVarArg = false) {
127 return cir::FuncType::get(params, retTy, isVarArg);
128 }
129
130 /// Get a CIR record kind from a AST declaration tag.
131 cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) {
132 switch (kind) {
134 return cir::RecordType::Class;
136 return cir::RecordType::Struct;
138 return cir::RecordType::Union;
140 llvm_unreachable("interface records are NYI");
142 llvm_unreachable("enums are not records");
143 }
144 llvm_unreachable("Unsupported record kind");
145 }
146
147 /// Get a CIR named record type.
148 ///
149 /// If a record already exists and is complete, but the client tries to fetch
150 /// it with a different set of attributes, this method will crash.
152 bool packed, bool padded,
153 llvm::StringRef name) {
154 const auto nameAttr = getStringAttr(name);
155 auto kind = cir::RecordType::RecordKind::Struct;
157
158 // Create or get the record.
159 auto type =
160 getType<cir::RecordType>(members, nameAttr, packed, padded, kind);
161
162 // If we found an existing type, verify that either it is incomplete or
163 // it matches the requested attributes.
164 assert(!type.isIncomplete() ||
165 (type.getMembers() == members && type.getPacked() == packed &&
166 type.getPadded() == padded));
167
168 // Complete an incomplete record or ensure the existing complete record
169 // matches the requested attributes.
170 type.complete(members, packed, padded);
171
172 return type;
173 }
174
175 cir::RecordType getCompleteRecordType(mlir::ArrayAttr fields,
176 bool packed = false,
177 bool padded = false,
178 llvm::StringRef name = "");
179
180 /// Get an incomplete CIR struct type. If we have a complete record
181 /// declaration, we may create an incomplete type and then add the
182 /// members, so \p rd here may be complete.
183 cir::RecordType getIncompleteRecordTy(llvm::StringRef name,
184 const clang::RecordDecl *rd) {
185 const mlir::StringAttr nameAttr = getStringAttr(name);
186 cir::RecordType::RecordKind kind = cir::RecordType::RecordKind::Struct;
187 if (rd)
189 return getType<cir::RecordType>(nameAttr, kind);
190 }
191
192 //
193 // Operation creation helpers
194 // --------------------------
195 //
196 cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst,
197 mlir::Value src, mlir::Value len) {
198 return cir::MemCpyOp::create(*this, loc, dst, src, len);
199 }
200 // ---------------------------
201
202 cir::DataMemberAttr getDataMemberAttr(cir::DataMemberType ty,
203 unsigned memberIndex) {
204 return cir::DataMemberAttr::get(ty, memberIndex);
205 }
206
207 cir::DataMemberAttr getNullDataMemberAttr(cir::DataMemberType ty) {
208 return cir::DataMemberAttr::get(ty);
209 }
210
211 // Return true if the value is a null constant such as null pointer, (+0.0)
212 // for floating-point or zero initializer
213 bool isNullValue(mlir::Attribute attr) const {
214 if (mlir::isa<cir::ZeroAttr>(attr))
215 return true;
216
217 if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
218 return ptrVal.isNullValue();
219
220 if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))
221 return intVal.isNullValue();
222
223 if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))
224 return !boolVal.getValue();
225
226 if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {
227 auto fpVal = fpAttr.getValue();
228 bool ignored;
229 llvm::APFloat fv(+0.0);
230 fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
231 &ignored);
232 return fv.bitwiseIsEqual(fpVal);
233 }
234 if (const auto recordVal = mlir::dyn_cast<cir::ConstRecordAttr>(attr)) {
235 for (const auto elt : recordVal.getMembers()) {
236 // FIXME(cir): the record's ID should not be considered a member.
237 if (mlir::isa<mlir::StringAttr>(elt))
238 continue;
239 if (!isNullValue(elt))
240 return false;
241 }
242 return true;
243 }
244
245 if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {
246 if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))
247 return false;
248
249 return llvm::all_of(
250 mlir::cast<mlir::ArrayAttr>(arrayVal.getElts()),
251 [&](const mlir::Attribute &elt) { return isNullValue(elt); });
252 }
253 return false;
254 }
255
256 //
257 // Type helpers
258 // ------------
259 //
260 cir::IntType getUIntNTy(int n) {
261 switch (n) {
262 case 8:
263 return getUInt8Ty();
264 case 16:
265 return getUInt16Ty();
266 case 32:
267 return getUInt32Ty();
268 case 64:
269 return getUInt64Ty();
270 default:
271 return cir::IntType::get(getContext(), n, false);
272 }
273 }
274
275 cir::IntType getSIntNTy(int n) {
276 switch (n) {
277 case 8:
278 return getSInt8Ty();
279 case 16:
280 return getSInt16Ty();
281 case 32:
282 return getSInt32Ty();
283 case 64:
284 return getSInt64Ty();
285 default:
286 return cir::IntType::get(getContext(), n, true);
287 }
288 }
289
290 cir::VoidType getVoidTy() { return typeCache.voidTy; }
291
292 cir::IntType getSInt8Ty() { return typeCache.sInt8Ty; }
293 cir::IntType getSInt16Ty() { return typeCache.sInt16Ty; }
294 cir::IntType getSInt32Ty() { return typeCache.sInt32Ty; }
295 cir::IntType getSInt64Ty() { return typeCache.sInt64Ty; }
296
297 cir::IntType getUInt8Ty() { return typeCache.uInt8Ty; }
298 cir::IntType getUInt16Ty() { return typeCache.uInt16Ty; }
299 cir::IntType getUInt32Ty() { return typeCache.uInt32Ty; }
300 cir::IntType getUInt64Ty() { return typeCache.uInt64Ty; }
301
302 cir::FP16Type getFp16Ty() { return typeCache.fP16Ty; }
303 cir::BF16Type getBfloat6Ty() { return typeCache.bFloat16Ty; }
304 cir::SingleType getSingleTy() { return typeCache.floatTy; }
305 cir::DoubleType getDoubleTy() { return typeCache.doubleTy; }
306
307 cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal);
308
309 cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal,
310 bool isUnsigned = true);
311
312 cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c);
313
314 cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t,
315 llvm::APFloat fpVal);
316
317 bool isInt8Ty(mlir::Type i) {
318 return i == typeCache.uInt8Ty || i == typeCache.sInt8Ty;
319 }
320 bool isInt16Ty(mlir::Type i) {
321 return i == typeCache.uInt16Ty || i == typeCache.sInt16Ty;
322 }
323 bool isInt32Ty(mlir::Type i) {
324 return i == typeCache.uInt32Ty || i == typeCache.sInt32Ty;
325 }
326 bool isInt64Ty(mlir::Type i) {
327 return i == typeCache.uInt64Ty || i == typeCache.sInt64Ty;
328 }
329 bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
330
331 // Fetch the type representing a pointer to unsigned int8 values.
332 cir::PointerType getUInt8PtrTy() { return typeCache.uInt8PtrTy; }
333
334 /// Get a CIR anonymous record type.
336 bool packed = false, bool padded = false) {
338 auto kind = cir::RecordType::RecordKind::Struct;
339 return getType<cir::RecordType>(members, packed, padded, kind);
340 }
341
342 //
343 // Constant creation helpers
344 // -------------------------
345 //
346 cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) {
347 return getConstantInt(loc, getSInt32Ty(), c);
348 }
349 cir::ConstantOp getUInt32(uint32_t c, mlir::Location loc) {
350 return getConstantInt(loc, getUInt32Ty(), c);
351 }
352 cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc) {
353 return getConstantInt(loc, getSInt64Ty(), c);
354 }
355 cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc) {
356 return getConstantInt(loc, getUInt64Ty(), c);
357 }
358
359 mlir::Value createNeg(mlir::Value value) {
360
361 if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
362 // Source is a unsigned integer: first cast it to signed.
363 if (intTy.isUnsigned())
364 value = createIntCast(value, getSIntNTy(intTy.getWidth()));
365 return cir::UnaryOp::create(*this, value.getLoc(), value.getType(),
366 cir::UnaryOpKind::Minus, value);
367 }
368
369 llvm_unreachable("negation for the given type is NYI");
370 }
371
372 cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,
373 cir::FPClassTest flags) {
374 return cir::IsFPClassOp::create(*this, loc, src, flags);
375 }
376
377 /// Create constant nullptr for pointer-to-data-member type ty.
378 cir::ConstantOp getNullDataMemberPtr(cir::DataMemberType ty,
379 mlir::Location loc) {
380 return cir::ConstantOp::create(*this, loc, getNullDataMemberAttr(ty));
381 }
382
383 cir::ConstantOp getNullMethodPtr(cir::MethodType ty, mlir::Location loc) {
384 return cir::ConstantOp::create(*this, loc, getNullMethodAttr(ty));
385 }
386
387 // TODO: split this to createFPExt/createFPTrunc when we have dedicated cast
388 // operations.
389 mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {
391
392 return cir::CastOp::create(*this, v.getLoc(), destType,
393 cir::CastKind::floating, v);
394 }
395
396 mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
400
401 return cir::BinOp::create(*this, loc, cir::BinOpKind::Sub, lhs, rhs);
402 }
403
404 mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
408
409 return cir::BinOp::create(*this, loc, cir::BinOpKind::Add, lhs, rhs);
410 }
411 mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
415
416 return cir::BinOp::create(*this, loc, cir::BinOpKind::Mul, lhs, rhs);
417 }
418 mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
422
423 return cir::BinOp::create(*this, loc, cir::BinOpKind::Div, lhs, rhs);
424 }
425
426 mlir::Value createDynCast(mlir::Location loc, mlir::Value src,
427 cir::PointerType destType, bool isRefCast,
428 cir::DynamicCastInfoAttr info) {
429 auto castKind =
430 isRefCast ? cir::DynamicCastKind::Ref : cir::DynamicCastKind::Ptr;
431 return cir::DynamicCastOp::create(*this, loc, destType, castKind, src, info,
432 /*relative_layout=*/false);
433 }
434
435 mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src,
436 bool vtableUseRelativeLayout) {
437 // TODO(cir): consider address space here.
439 cir::PointerType destTy = getVoidPtrTy();
440 return cir::DynamicCastOp::create(
441 *this, loc, destTy, cir::DynamicCastKind::Ptr, src,
442 cir::DynamicCastInfoAttr{}, vtableUseRelativeLayout);
443 }
444
445 Address createBaseClassAddr(mlir::Location loc, Address addr,
446 mlir::Type destType, unsigned offset,
447 bool assumeNotNull) {
448 if (destType == addr.getElementType())
449 return addr;
450
451 auto ptrTy = getPointerTo(destType);
452 auto baseAddr =
453 cir::BaseClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),
454 mlir::APInt(64, offset), assumeNotNull);
455 return Address(baseAddr, destType, addr.getAlignment());
456 }
457
458 Address createDerivedClassAddr(mlir::Location loc, Address addr,
459 mlir::Type destType, unsigned offset,
460 bool assumeNotNull) {
461 if (destType == addr.getElementType())
462 return addr;
463
464 cir::PointerType ptrTy = getPointerTo(destType);
465 auto derivedAddr =
466 cir::DerivedClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),
467 mlir::APInt(64, offset), assumeNotNull);
468 return Address(derivedAddr, destType, addr.getAlignment());
469 }
470
471 mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,
472 mlir::Value addr, uint64_t offset) {
473 return cir::VTTAddrPointOp::create(*this, loc, retTy,
474 mlir::FlatSymbolRefAttr{}, addr, offset);
475 }
476
477 mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,
478 mlir::FlatSymbolRefAttr sym, uint64_t offset) {
479 return cir::VTTAddrPointOp::create(*this, loc, retTy, sym, mlir::Value{},
480 offset);
481 }
482
483 /// Cast the element type of the given address to a different type,
484 /// preserving information like the alignment.
485 Address createElementBitCast(mlir::Location loc, Address addr,
486 mlir::Type destType) {
487 if (destType == addr.getElementType())
488 return addr;
489
490 auto ptrTy = getPointerTo(destType);
491 return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType,
492 addr.getAlignment());
493 }
494
495 cir::LoadOp createLoad(mlir::Location loc, Address addr,
496 bool isVolatile = false) {
497 mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment());
498 return cir::LoadOp::create(*this, loc, addr.getPointer(), /*isDeref=*/false,
499 isVolatile, /*alignment=*/align,
500 /*sync_scope=*/cir::SyncScopeKindAttr{},
501 /*mem_order=*/cir::MemOrderAttr{});
502 }
503
504 cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty,
505 mlir::Value ptr, llvm::MaybeAlign align) {
506 if (ty != mlir::cast<cir::PointerType>(ptr.getType()).getPointee())
507 ptr = createPtrBitcast(ptr, ty);
508 uint64_t alignment = align ? align->value() : 0;
509 mlir::IntegerAttr alignAttr = getAlignmentAttr(alignment);
510 return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false,
511 /*isVolatile=*/false, alignAttr,
512 /*sync_scope=*/cir::SyncScopeKindAttr{},
513 /*mem_order=*/cir::MemOrderAttr{});
514 }
515
516 cir::LoadOp
517 createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr,
519 return createAlignedLoad(loc, ty, ptr, align.getAsAlign());
520 }
521
522 cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst,
523 bool isVolatile = false,
524 mlir::IntegerAttr align = {},
525 cir::SyncScopeKindAttr scope = {},
526 cir::MemOrderAttr order = {}) {
527 if (!align)
528 align = getAlignmentAttr(dst.getAlignment());
529 return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), isVolatile,
530 align, scope, order);
531 }
532
533 /// Create a cir.complex.real_ptr operation that derives a pointer to the real
534 /// part of the complex value pointed to by the specified pointer value.
535 mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {
536 auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
537 auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
538 return cir::ComplexRealPtrOp::create(
539 *this, loc, getPointerTo(srcComplexTy.getElementType()), value);
540 }
541
542 Address createComplexRealPtr(mlir::Location loc, Address addr) {
543 return Address{createComplexRealPtr(loc, addr.getPointer()),
544 addr.getAlignment()};
545 }
546
547 /// Create a cir.complex.imag_ptr operation that derives a pointer to the
548 /// imaginary part of the complex value pointed to by the specified pointer
549 /// value.
550 mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) {
551 auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
552 auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
553 return cir::ComplexImagPtrOp::create(
554 *this, loc, getPointerTo(srcComplexTy.getElementType()), value);
555 }
556
557 Address createComplexImagPtr(mlir::Location loc, Address addr) {
558 return Address{createComplexImagPtr(loc, addr.getPointer()),
559 addr.getAlignment()};
560 }
561
562 cir::GetRuntimeMemberOp createGetIndirectMember(mlir::Location loc,
563 mlir::Value objectPtr,
564 mlir::Value memberPtr) {
565 auto memberPtrTy = mlir::cast<cir::DataMemberType>(memberPtr.getType());
566
567 // TODO(cir): consider address space.
569 cir::PointerType resultTy = getPointerTo(memberPtrTy.getMemberTy());
570
571 return cir::GetRuntimeMemberOp::create(*this, loc, resultTy, objectPtr,
572 memberPtr);
573 }
574
575 /// Create a cir.ptr_stride operation to get access to an array element.
576 /// \p idx is the index of the element to access, \p shouldDecay is true if
577 /// the result should decay to a pointer to the element type.
578 mlir::Value getArrayElement(mlir::Location arrayLocBegin,
579 mlir::Location arrayLocEnd, mlir::Value arrayPtr,
580 mlir::Type eltTy, mlir::Value idx,
581 bool shouldDecay);
582
583 /// Returns a decayed pointer to the first element of the array
584 /// pointed to by \p arrayPtr.
585 mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,
586 mlir::Type eltTy);
587
588 // Convert byte offset to sequence of high-level indices suitable for
589 // GlobalViewAttr. Ideally we shouldn't deal with low-level offsets at all
590 // but currently some parts of Clang AST, which we don't want to touch just
591 // yet, return them.
593 int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,
595
596 /// Creates a versioned global variable. If the symbol is already taken, an ID
597 /// will be appended to the symbol. The returned global must always be queried
598 /// for its name so it can be referenced correctly.
599 [[nodiscard]] cir::GlobalOp
600 createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc,
601 mlir::StringRef name, mlir::Type type, bool isConstant,
602 cir::GlobalLinkageKind linkage) {
603 // Create a unique name if the given name is already taken.
604 std::string uniqueName;
605 if (unsigned version = globalsVersioning[name.str()]++)
606 uniqueName = name.str() + "." + std::to_string(version);
607 else
608 uniqueName = name.str();
609
610 return createGlobal(module, loc, uniqueName, type, isConstant, linkage);
611 }
612
613 cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {
614 return cir::StackSaveOp::create(*this, loc, ty);
615 }
616
617 cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v) {
618 return cir::StackRestoreOp::create(*this, loc, v);
619 }
620
621 mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
622 Address dstAddr, mlir::Type storageType,
623 mlir::Value src, const CIRGenBitFieldInfo &info,
624 bool isLvalueVolatile, bool useVolatile) {
625 unsigned offset = useVolatile ? info.volatileOffset : info.offset;
626
627 // If using AAPCS and the field is volatile, load with the size of the
628 // declared field
629 storageType =
630 useVolatile ? cir::IntType::get(storageType.getContext(),
631 info.volatileStorageSize, info.isSigned)
632 : storageType;
633 return cir::SetBitfieldOp::create(
634 *this, loc, resultType, dstAddr.getPointer(), storageType, src,
635 info.name, info.size, offset, info.isSigned, isLvalueVolatile,
636 dstAddr.getAlignment().getAsAlign().value());
637 }
638
639 mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,
640 Address addr, mlir::Type storageType,
641 const CIRGenBitFieldInfo &info,
642 bool isLvalueVolatile, bool useVolatile) {
643 unsigned offset = useVolatile ? info.volatileOffset : info.offset;
644
645 // If using AAPCS and the field is volatile, load with the size of the
646 // declared field
647 storageType =
648 useVolatile ? cir::IntType::get(storageType.getContext(),
649 info.volatileStorageSize, info.isSigned)
650 : storageType;
651 return cir::GetBitfieldOp::create(*this, loc, resultType, addr.getPointer(),
652 storageType, info.name, info.size, offset,
653 info.isSigned, isLvalueVolatile,
654 addr.getAlignment().getAsAlign().value());
655 }
656
657 cir::VecShuffleOp
658 createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2,
660 auto vecType = mlir::cast<cir::VectorType>(vec1.getType());
661 auto resultTy =
662 cir::VectorType::get(vecType.getElementType(), maskAttrs.size());
663 return cir::VecShuffleOp::create(*this, loc, resultTy, vec1, vec2,
664 getArrayAttr(maskAttrs));
665 }
666
667 cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
668 mlir::Value vec2,
670 auto maskAttrs = llvm::to_vector_of<mlir::Attribute>(
671 llvm::map_range(mask, [&](int32_t idx) {
672 return cir::IntAttr::get(getSInt32Ty(), idx);
673 }));
674 return createVecShuffle(loc, vec1, vec2, maskAttrs);
675 }
676
677 cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
679 /// Create a unary shuffle. The second vector operand of the IR instruction
680 /// is poison.
681 cir::ConstantOp poison =
682 getConstant(loc, cir::PoisonAttr::get(vec1.getType()));
683 return createVecShuffle(loc, vec1, poison, mask);
684 }
685
686 template <typename... Operands>
687 mlir::Value emitIntrinsicCallOp(mlir::Location loc, const llvm::StringRef str,
688 const mlir::Type &resTy, Operands &&...op) {
689 return cir::LLVMIntrinsicCallOp::create(*this, loc,
690 this->getStringAttr(str), resTy,
691 std::forward<Operands>(op)...)
692 .getResult();
693 }
694};
695
696} // namespace clang::CIRGen
697
698#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::MethodAttr getNullMethodAttr(cir::MethodType ty)
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)
cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule, mlir::Location loc, mlir::StringRef name, mlir::Type type, bool isConstant, cir::GlobalLinkageKind linkage)
mlir::IntegerAttr getAlignmentAttr(clang::CharUnits alignment)
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, int64_t value)
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
mlir::Value getPointer() const
Definition Address.h:95
mlir::Type getElementType() const
Definition Address.h:122
clang::CharUnits getAlignment() const
Definition Address.h:135
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)
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::RecordType getIncompleteRecordTy(llvm::StringRef name, const clang::RecordDecl *rd)
Get an incomplete CIR struct type.
cir::ConstantOp getUInt32(uint32_t c, mlir::Location loc)
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::GlobalOp createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc, mlir::StringRef name, mlir::Type type, bool isConstant, cir::GlobalLinkageKind linkage)
Creates a versioned global variable.
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::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)
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.
mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy, std::optional< size_t > size)
Get a cir::ConstArrayAttr for a string literal.
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)
mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
Address createDerivedClassAddr(mlir::Location loc, Address addr, mlir::Type destType, unsigned offset, bool assumeNotNull)
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::ConstantOp getNullDataMemberPtr(cir::DataMemberType ty, mlir::Location loc)
Create constant nullptr for pointer-to-data-member type ty.
mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src, bool vtableUseRelativeLayout)
cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1, llvm::ArrayRef< int64_t > mask)
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)
mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
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="")
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
void computeGlobalViewIndicesFromFlatOffset(int64_t offset, mlir::Type ty, cir::CIRDataLayout layout, llvm::SmallVectorImpl< int64_t > &indices)
cir::ConstantOp getNullMethodPtr(cir::MethodType ty, mlir::Location loc)
Address createComplexImagPtr(mlir::Location loc, Address addr)
mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
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::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:4324
TagKind getTagKind() const
Definition Decl.h:3914
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
TagTypeKind
The kind of a tag type.
Definition TypeBase.h:5893
@ Interface
The "__interface" keyword.
Definition TypeBase.h:5898
@ Struct
The "struct" keyword.
Definition TypeBase.h:5895
@ Class
The "class" keyword.
Definition TypeBase.h:5904
@ Union
The "union" keyword.
Definition TypeBase.h:5901
@ Enum
The "enum" keyword.
Definition TypeBase.h:5907
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.