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#include "llvm/IR/FPEnv.h"
26
27namespace clang::CIRGen {
28
30 const CIRGenTypeCache &typeCache;
31 bool isFPConstrained = false;
32 llvm::fp::ExceptionBehavior defaultConstrainedExcept = llvm::fp::ebStrict;
33 llvm::RoundingMode defaultConstrainedRounding = llvm::RoundingMode::Dynamic;
34
35 llvm::StringMap<unsigned> recordNames;
36 llvm::StringMap<unsigned> globalsVersioning;
37
38public:
39 CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)
40 : CIRBaseBuilderTy(mlirContext), typeCache(tc) {}
41
42 /// Get a cir::ConstArrayAttr for a string literal.
43 /// Note: This is different from what is returned by
44 /// mlir::Builder::getStringAttr() which is an mlir::StringAttr.
45 mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy,
46 std::optional<size_t> size) {
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 // We emit trailing zeros only if there are multiple trailing zeros.
57 size_t trailingZerosNum = 0;
58 if (finalSize > lastNonZeroPos + 2)
59 trailingZerosNum = finalSize - lastNonZeroPos - 1;
60 auto truncatedArrayTy =
61 cir::ArrayType::get(eltTy, finalSize - trailingZerosNum);
62 auto fullArrayTy = cir::ArrayType::get(eltTy, finalSize);
63 return cir::ConstArrayAttr::get(
64 fullArrayTy,
65 mlir::StringAttr::get(str.drop_back(trailingZerosNum),
66 truncatedArrayTy),
67 trailingZerosNum);
68 }
69
70 cir::ConstArrayAttr getConstArray(mlir::Attribute attrs,
71 cir::ArrayType arrayTy) const {
72 return cir::ConstArrayAttr::get(arrayTy, attrs);
73 }
74
75 mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr,
76 bool packed = false,
77 bool padded = false,
78 mlir::Type type = {});
79
80 cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr,
81 bool packed = false,
82 bool padded = false,
83 mlir::Type ty = {}) {
85 for (auto &f : arrayAttr) {
86 auto ta = mlir::cast<mlir::TypedAttr>(f);
87 members.push_back(ta.getType());
88 }
89
90 if (!ty)
91 ty = getAnonRecordTy(members, packed, padded);
92
93 auto sTy = mlir::cast<cir::RecordType>(ty);
94 return cir::ConstRecordAttr::get(sTy, arrayAttr);
95 }
96
97 cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr) {
98 cir::ConstRecordAttr anonRecord = getAnonConstRecord(fieldsAttr);
99 return cir::TypeInfoAttr::get(anonRecord.getType(), fieldsAttr);
100 }
101
102 std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }
103
104 std::string getUniqueRecordName(const std::string &baseName) {
105 auto it = recordNames.find(baseName);
106 if (it == recordNames.end()) {
107 recordNames[baseName] = 0;
108 return baseName;
109 }
110
111 return baseName + "." + std::to_string(recordNames[baseName]++);
112 }
113
114 //
115 // Floating point specific helpers
116 // -------------------------------
117 //
118
119 /// Enable/Disable use of constrained floating point math. When enabled the
120 /// CreateF<op>() calls instead create constrained floating point intrinsic
121 /// calls. Fast math flags are unaffected by this setting.
122 void setIsFPConstrained(bool isCon) { isFPConstrained = isCon; }
123
124 /// Query for the use of constrained floating point math
125 bool getIsFPConstrained() const { return isFPConstrained; }
126
127 /// Set the exception handling to be used with constrained floating point
128 void setDefaultConstrainedExcept(llvm::fp::ExceptionBehavior newExcept) {
129 assert(llvm::convertExceptionBehaviorToStr(newExcept) &&
130 "Garbage strict exception behavior!");
131 defaultConstrainedExcept = newExcept;
132 }
133
134 /// Get the exception handling used with constrained floating point
135 llvm::fp::ExceptionBehavior getDefaultConstrainedExcept() const {
136 return defaultConstrainedExcept;
137 }
138
139 /// Set the rounding mode handling to be used with constrained floating point
140 void setDefaultConstrainedRounding(llvm::RoundingMode newRounding) {
141 assert(llvm::convertRoundingModeToStr(newRounding) &&
142 "Garbage strict rounding mode!");
143 defaultConstrainedRounding = newRounding;
144 }
145
146 /// Get the rounding mode handling used with constrained floating point
147 llvm::RoundingMode getDefaultConstrainedRounding() const {
148 return defaultConstrainedRounding;
149 }
150
151 cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {
152 if (&format == &llvm::APFloat::IEEEdouble())
153 return cir::LongDoubleType::get(getContext(), typeCache.doubleTy);
154 if (&format == &llvm::APFloat::x87DoubleExtended())
155 return cir::LongDoubleType::get(getContext(), typeCache.fP80Ty);
156 if (&format == &llvm::APFloat::IEEEquad())
157 return cir::LongDoubleType::get(getContext(), typeCache.fP128Ty);
158 if (&format == &llvm::APFloat::PPCDoubleDouble())
159 llvm_unreachable("NYI: PPC double-double format for long double");
160 llvm_unreachable("Unsupported format for long double");
161 }
162
163 mlir::Type getPtrToVPtrType() {
164 return getPointerTo(cir::VPtrType::get(getContext()));
165 }
166
167 cir::FuncType getFuncType(llvm::ArrayRef<mlir::Type> params, mlir::Type retTy,
168 bool isVarArg = false) {
169 return cir::FuncType::get(params, retTy, isVarArg);
170 }
171
172 /// Get a CIR record kind from a AST declaration tag.
173 cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) {
174 switch (kind) {
176 return cir::RecordType::Class;
178 return cir::RecordType::Struct;
180 return cir::RecordType::Union;
182 llvm_unreachable("interface records are NYI");
184 llvm_unreachable("enums are not records");
185 }
186 llvm_unreachable("Unsupported record kind");
187 }
188
189 /// Get a CIR named record type.
190 ///
191 /// If a record already exists and is complete, but the client tries to fetch
192 /// it with a different set of attributes, this method will crash.
194 bool packed, bool padded,
195 llvm::StringRef name) {
196 const auto nameAttr = getStringAttr(name);
197 auto kind = cir::RecordType::RecordKind::Struct;
199
200 // Create or get the record.
201 auto type =
202 getType<cir::RecordType>(members, nameAttr, packed, padded, kind);
203
204 // If we found an existing type, verify that either it is incomplete or
205 // it matches the requested attributes.
206 assert(!type.isIncomplete() ||
207 (type.getMembers() == members && type.getPacked() == packed &&
208 type.getPadded() == padded));
209
210 // Complete an incomplete record or ensure the existing complete record
211 // matches the requested attributes.
212 type.complete(members, packed, padded);
213
214 return type;
215 }
216
217 cir::RecordType getCompleteRecordType(mlir::ArrayAttr fields,
218 bool packed = false,
219 bool padded = false,
220 llvm::StringRef name = "");
221
222 /// Get an incomplete CIR struct type. If we have a complete record
223 /// declaration, we may create an incomplete type and then add the
224 /// members, so \p rd here may be complete.
225 cir::RecordType getIncompleteRecordTy(llvm::StringRef name,
226 const clang::RecordDecl *rd) {
227 const mlir::StringAttr nameAttr = getStringAttr(name);
228 cir::RecordType::RecordKind kind = cir::RecordType::RecordKind::Struct;
229 if (rd)
231 return getType<cir::RecordType>(nameAttr, kind);
232 }
233
234 //
235 // Operation creation helpers
236 // --------------------------
237 //
238 cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst,
239 mlir::Value src, mlir::Value len) {
240 return cir::MemCpyOp::create(*this, loc, dst, src, len);
241 }
242
243 cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst,
244 mlir::Value val, mlir::Value len) {
245 assert(val.getType() == getUInt8Ty());
246 return cir::MemSetOp::create(*this, loc, dst, val, len);
247 }
248 // ---------------------------
249
250 cir::DataMemberAttr getDataMemberAttr(cir::DataMemberType ty,
251 unsigned memberIndex) {
252 return cir::DataMemberAttr::get(ty, memberIndex);
253 }
254
255 cir::DataMemberAttr getNullDataMemberAttr(cir::DataMemberType ty) {
256 return cir::DataMemberAttr::get(ty);
257 }
258
259 // Return true if the value is a null constant such as null pointer, (+0.0)
260 // for floating-point or zero initializer
261 bool isNullValue(mlir::Attribute attr) const {
262 if (mlir::isa<cir::ZeroAttr>(attr))
263 return true;
264
265 if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
266 return ptrVal.isNullValue();
267
268 if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))
269 return intVal.isNullValue();
270
271 if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))
272 return !boolVal.getValue();
273
274 if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {
275 auto fpVal = fpAttr.getValue();
276 bool ignored;
277 llvm::APFloat fv(+0.0);
278 fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
279 &ignored);
280 return fv.bitwiseIsEqual(fpVal);
281 }
282 if (const auto recordVal = mlir::dyn_cast<cir::ConstRecordAttr>(attr)) {
283 for (const auto elt : recordVal.getMembers()) {
284 // FIXME(cir): the record's ID should not be considered a member.
285 if (mlir::isa<mlir::StringAttr>(elt))
286 continue;
287 if (!isNullValue(elt))
288 return false;
289 }
290 return true;
291 }
292
293 if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {
294 if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))
295 return false;
296
297 return llvm::all_of(
298 mlir::cast<mlir::ArrayAttr>(arrayVal.getElts()),
299 [&](const mlir::Attribute &elt) { return isNullValue(elt); });
300 }
301 return false;
302 }
303
304 //
305 // Type helpers
306 // ------------
307 //
308 cir::IntType getUIntNTy(int n) {
309 switch (n) {
310 case 8:
311 return getUInt8Ty();
312 case 16:
313 return getUInt16Ty();
314 case 32:
315 return getUInt32Ty();
316 case 64:
317 return getUInt64Ty();
318 default:
319 return cir::IntType::get(getContext(), n, false);
320 }
321 }
322
323 cir::IntType getSIntNTy(int n) {
324 switch (n) {
325 case 8:
326 return getSInt8Ty();
327 case 16:
328 return getSInt16Ty();
329 case 32:
330 return getSInt32Ty();
331 case 64:
332 return getSInt64Ty();
333 default:
334 return cir::IntType::get(getContext(), n, true);
335 }
336 }
337
338 cir::VoidType getVoidTy() { return typeCache.voidTy; }
339
340 cir::IntType getSInt8Ty() { return typeCache.sInt8Ty; }
341 cir::IntType getSInt16Ty() { return typeCache.sInt16Ty; }
342 cir::IntType getSInt32Ty() { return typeCache.sInt32Ty; }
343 cir::IntType getSInt64Ty() { return typeCache.sInt64Ty; }
344
345 cir::IntType getUInt8Ty() { return typeCache.uInt8Ty; }
346 cir::IntType getUInt16Ty() { return typeCache.uInt16Ty; }
347 cir::IntType getUInt32Ty() { return typeCache.uInt32Ty; }
348 cir::IntType getUInt64Ty() { return typeCache.uInt64Ty; }
349
350 cir::FP16Type getFp16Ty() { return typeCache.fP16Ty; }
351 cir::BF16Type getBfloat6Ty() { return typeCache.bFloat16Ty; }
352 cir::SingleType getSingleTy() { return typeCache.floatTy; }
353 cir::DoubleType getDoubleTy() { return typeCache.doubleTy; }
354
355 cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal);
356
357 cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal,
358 bool isUnsigned = true);
359
360 cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c);
361
362 cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t,
363 llvm::APFloat fpVal);
364
365 bool isInt8Ty(mlir::Type i) {
366 return i == typeCache.uInt8Ty || i == typeCache.sInt8Ty;
367 }
368 bool isInt16Ty(mlir::Type i) {
369 return i == typeCache.uInt16Ty || i == typeCache.sInt16Ty;
370 }
371 bool isInt32Ty(mlir::Type i) {
372 return i == typeCache.uInt32Ty || i == typeCache.sInt32Ty;
373 }
374 bool isInt64Ty(mlir::Type i) {
375 return i == typeCache.uInt64Ty || i == typeCache.sInt64Ty;
376 }
377 bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
378
379 // Fetch the type representing a pointer to unsigned int8 values.
380 cir::PointerType getUInt8PtrTy() { return typeCache.uInt8PtrTy; }
381
382 /// Get a CIR anonymous record type.
384 bool packed = false, bool padded = false) {
386 auto kind = cir::RecordType::RecordKind::Struct;
387 return getType<cir::RecordType>(members, packed, padded, kind);
388 }
389
390 //===--------------------------------------------------------------------===//
391 // Constant creation helpers
392 //===--------------------------------------------------------------------===//
393 cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) {
394 return getConstantInt(loc, getSInt32Ty(), c);
395 }
396 cir::ConstantOp getUInt32(uint32_t c, mlir::Location loc) {
397 return getConstantInt(loc, getUInt32Ty(), c);
398 }
399 cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc) {
400 return getConstantInt(loc, getSInt64Ty(), c);
401 }
402 cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc) {
403 return getConstantInt(loc, getUInt64Ty(), c);
404 }
405
406 /// Create constant nullptr for pointer-to-data-member type ty.
407 cir::ConstantOp getNullDataMemberPtr(cir::DataMemberType ty,
408 mlir::Location loc) {
409 return cir::ConstantOp::create(*this, loc, getNullDataMemberAttr(ty));
410 }
411
412 cir::ConstantOp getNullMethodPtr(cir::MethodType ty, mlir::Location loc) {
413 return cir::ConstantOp::create(*this, loc, getNullMethodAttr(ty));
414 }
415
416 //===--------------------------------------------------------------------===//
417 // UnaryOp creation helpers
418 //===--------------------------------------------------------------------===//
419 mlir::Value createNeg(mlir::Value value) {
420
421 if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
422 // Source is a unsigned integer: first cast it to signed.
423 if (intTy.isUnsigned())
424 value = createIntCast(value, getSIntNTy(intTy.getWidth()));
425 return cir::UnaryOp::create(*this, value.getLoc(), value.getType(),
426 cir::UnaryOpKind::Minus, value);
427 }
428
429 llvm_unreachable("negation for the given type is NYI");
430 }
431
432 mlir::Value createFNeg(mlir::Value value) {
433 assert(mlir::isa<cir::FPTypeInterface>(value.getType()) &&
434 "Non-fp input type!");
435
439
440 return cir::UnaryOp::create(*this, value.getLoc(), value.getType(),
441 cir::UnaryOpKind::Minus, value);
442 }
443
444 //===--------------------------------------------------------------------===//
445 // BinaryOp creation helpers
446 //===--------------------------------------------------------------------===//
447 mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
451
452 return cir::BinOp::create(*this, loc, cir::BinOpKind::Sub, lhs, rhs);
453 }
454
455 mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
459
460 return cir::BinOp::create(*this, loc, cir::BinOpKind::Add, lhs, rhs);
461 }
462
463 mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
467
468 return cir::BinOp::create(*this, loc, cir::BinOpKind::Mul, lhs, rhs);
469 }
470 mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
474
475 return cir::BinOp::create(*this, loc, cir::BinOpKind::Div, lhs, rhs);
476 }
477
478 //===--------------------------------------------------------------------===//
479 // CastOp creation helpers
480 //===--------------------------------------------------------------------===//
481
482 // TODO: split this to createFPExt/createFPTrunc when we have dedicated cast
483 // operations.
484 mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {
486
487 return cir::CastOp::create(*this, v.getLoc(), destType,
488 cir::CastKind::floating, v);
489 }
490
491 mlir::Value createDynCast(mlir::Location loc, mlir::Value src,
492 cir::PointerType destType, bool isRefCast,
493 cir::DynamicCastInfoAttr info) {
494 auto castKind =
495 isRefCast ? cir::DynamicCastKind::Ref : cir::DynamicCastKind::Ptr;
496 return cir::DynamicCastOp::create(*this, loc, destType, castKind, src, info,
497 /*relative_layout=*/false);
498 }
499
500 mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src,
501 bool vtableUseRelativeLayout) {
502 // TODO(cir): consider address space here.
504 cir::PointerType destTy = getVoidPtrTy();
505 return cir::DynamicCastOp::create(
506 *this, loc, destTy, cir::DynamicCastKind::Ptr, src,
507 cir::DynamicCastInfoAttr{}, vtableUseRelativeLayout);
508 }
509
510 //===--------------------------------------------------------------------===//
511 // Address creation helpers
512 //===--------------------------------------------------------------------===//
513 Address createBaseClassAddr(mlir::Location loc, Address addr,
514 mlir::Type destType, unsigned offset,
515 bool assumeNotNull) {
516 if (destType == addr.getElementType())
517 return addr;
518
519 auto ptrTy = getPointerTo(destType);
520 auto baseAddr =
521 cir::BaseClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),
522 mlir::APInt(64, offset), assumeNotNull);
523 return Address(baseAddr, destType, addr.getAlignment());
524 }
525
526 Address createDerivedClassAddr(mlir::Location loc, Address addr,
527 mlir::Type destType, unsigned offset,
528 bool assumeNotNull) {
529 if (destType == addr.getElementType())
530 return addr;
531
532 cir::PointerType ptrTy = getPointerTo(destType);
533 auto derivedAddr =
534 cir::DerivedClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),
535 mlir::APInt(64, offset), assumeNotNull);
536 return Address(derivedAddr, destType, addr.getAlignment());
537 }
538
539 //===--------------------------------------------------------------------===//
540 // Virtual Address creation helpers
541 //===--------------------------------------------------------------------===//
542 mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,
543 mlir::Value addr, uint64_t offset) {
544 return cir::VTTAddrPointOp::create(*this, loc, retTy,
545 mlir::FlatSymbolRefAttr{}, addr, offset);
546 }
547
548 mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,
549 mlir::FlatSymbolRefAttr sym, uint64_t offset) {
550 return cir::VTTAddrPointOp::create(*this, loc, retTy, sym, mlir::Value{},
551 offset);
552 }
553
554 //===--------------------------------------------------------------------===//
555 // Other creation helpers
556 //===--------------------------------------------------------------------===//
557 cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,
558 cir::FPClassTest flags) {
559 return cir::IsFPClassOp::create(*this, loc, src, flags);
560 }
561
562 /// Cast the element type of the given address to a different type,
563 /// preserving information like the alignment.
564 Address createElementBitCast(mlir::Location loc, Address addr,
565 mlir::Type destType) {
566 if (destType == addr.getElementType())
567 return addr;
568
569 auto ptrTy = getPointerTo(destType);
570 return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType,
571 addr.getAlignment());
572 }
573
574 cir::LoadOp createLoad(mlir::Location loc, Address addr,
575 bool isVolatile = false) {
576 mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment());
577 return cir::LoadOp::create(*this, loc, addr.getPointer(), /*isDeref=*/false,
578 isVolatile, /*alignment=*/align,
579 /*sync_scope=*/cir::SyncScopeKindAttr{},
580 /*mem_order=*/cir::MemOrderAttr{});
581 }
582
583 cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty,
584 mlir::Value ptr, llvm::MaybeAlign align) {
585 if (ty != mlir::cast<cir::PointerType>(ptr.getType()).getPointee())
586 ptr = createPtrBitcast(ptr, ty);
587 uint64_t alignment = align ? align->value() : 0;
588 mlir::IntegerAttr alignAttr = getAlignmentAttr(alignment);
589 return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false,
590 /*isVolatile=*/false, alignAttr,
591 /*sync_scope=*/cir::SyncScopeKindAttr{},
592 /*mem_order=*/cir::MemOrderAttr{});
593 }
594
595 cir::LoadOp
596 createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr,
598 return createAlignedLoad(loc, ty, ptr, align.getAsAlign());
599 }
600
601 cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst,
602 bool isVolatile = false,
603 mlir::IntegerAttr align = {},
604 cir::SyncScopeKindAttr scope = {},
605 cir::MemOrderAttr order = {}) {
606 if (!align)
607 align = getAlignmentAttr(dst.getAlignment());
608 return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), isVolatile,
609 align, scope, order);
610 }
611
612 /// Create a cir.complex.real_ptr operation that derives a pointer to the real
613 /// part of the complex value pointed to by the specified pointer value.
614 mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {
615 auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
616 auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
617 return cir::ComplexRealPtrOp::create(
618 *this, loc, getPointerTo(srcComplexTy.getElementType()), value);
619 }
620
621 Address createComplexRealPtr(mlir::Location loc, Address addr) {
622 return Address{createComplexRealPtr(loc, addr.getPointer()),
623 addr.getAlignment()};
624 }
625
626 /// Create a cir.complex.imag_ptr operation that derives a pointer to the
627 /// imaginary part of the complex value pointed to by the specified pointer
628 /// value.
629 mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) {
630 auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
631 auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
632 return cir::ComplexImagPtrOp::create(
633 *this, loc, getPointerTo(srcComplexTy.getElementType()), value);
634 }
635
636 Address createComplexImagPtr(mlir::Location loc, Address addr) {
637 return Address{createComplexImagPtr(loc, addr.getPointer()),
638 addr.getAlignment()};
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.
672 int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,
674
675 /// Creates a versioned global variable. If the symbol is already taken, an ID
676 /// will be appended to the symbol. The returned global must always be queried
677 /// for its name so it can be referenced correctly.
678 [[nodiscard]] cir::GlobalOp
679 createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc,
680 mlir::StringRef name, mlir::Type type, bool isConstant,
681 cir::GlobalLinkageKind linkage) {
682 // Create a unique name if the given name is already taken.
683 std::string uniqueName;
684 if (unsigned version = globalsVersioning[name.str()]++)
685 uniqueName = name.str() + "." + std::to_string(version);
686 else
687 uniqueName = name.str();
688
689 return createGlobal(module, loc, uniqueName, type, isConstant, linkage);
690 }
691
692 cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {
693 return cir::StackSaveOp::create(*this, loc, ty);
694 }
695
696 cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v) {
697 return cir::StackRestoreOp::create(*this, loc, v);
698 }
699
700 mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
701 Address dstAddr, mlir::Type storageType,
702 mlir::Value src, const CIRGenBitFieldInfo &info,
703 bool isLvalueVolatile, bool useVolatile) {
704 unsigned offset = useVolatile ? info.volatileOffset : info.offset;
705
706 // If using AAPCS and the field is volatile, load with the size of the
707 // declared field
708 storageType =
709 useVolatile ? cir::IntType::get(storageType.getContext(),
710 info.volatileStorageSize, info.isSigned)
711 : storageType;
712 return cir::SetBitfieldOp::create(
713 *this, loc, resultType, dstAddr.getPointer(), storageType, src,
714 info.name, info.size, offset, info.isSigned, isLvalueVolatile,
715 dstAddr.getAlignment().getAsAlign().value());
716 }
717
718 mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,
719 Address addr, mlir::Type storageType,
720 const CIRGenBitFieldInfo &info,
721 bool isLvalueVolatile, bool useVolatile) {
722 unsigned offset = useVolatile ? info.volatileOffset : info.offset;
723
724 // If using AAPCS and the field is volatile, load with the size of the
725 // declared field
726 storageType =
727 useVolatile ? cir::IntType::get(storageType.getContext(),
728 info.volatileStorageSize, info.isSigned)
729 : storageType;
730 return cir::GetBitfieldOp::create(*this, loc, resultType, addr.getPointer(),
731 storageType, info.name, info.size, offset,
732 info.isSigned, isLvalueVolatile,
733 addr.getAlignment().getAsAlign().value());
734 }
735
736 mlir::Value createMaskedLoad(mlir::Location loc, mlir::Type ty,
737 mlir::Value ptr, llvm::Align alignment,
738 mlir::Value mask, mlir::Value passThru) {
739 assert(mlir::isa<cir::VectorType>(ty) && "Type should be vector");
740 assert(mask && "Mask should not be all-ones (null)");
741
742 if (!passThru)
743 passThru = this->getConstant(loc, cir::PoisonAttr::get(ty));
744
745 auto alignAttr =
746 this->getI64IntegerAttr(static_cast<int64_t>(alignment.value()));
747
748 return cir::VecMaskedLoadOp::create(*this, loc, ty, ptr, mask, passThru,
749 alignAttr);
750 }
751
752 cir::VecShuffleOp
753 createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2,
755 auto vecType = mlir::cast<cir::VectorType>(vec1.getType());
756 auto resultTy =
757 cir::VectorType::get(vecType.getElementType(), maskAttrs.size());
758 return cir::VecShuffleOp::create(*this, loc, resultTy, vec1, vec2,
759 getArrayAttr(maskAttrs));
760 }
761
762 cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
763 mlir::Value vec2,
765 auto maskAttrs = llvm::to_vector_of<mlir::Attribute>(
766 llvm::map_range(mask, [&](int32_t idx) {
767 return cir::IntAttr::get(getSInt32Ty(), idx);
768 }));
769 return createVecShuffle(loc, vec1, vec2, maskAttrs);
770 }
771
772 cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
774 /// Create a unary shuffle. The second vector operand of the IR instruction
775 /// is poison.
776 cir::ConstantOp poison =
777 getConstant(loc, cir::PoisonAttr::get(vec1.getType()));
778 return createVecShuffle(loc, vec1, poison, mask);
779 }
780
781 template <typename... Operands>
782 mlir::Value emitIntrinsicCallOp(mlir::Location loc, const llvm::StringRef str,
783 const mlir::Type &resTy, Operands &&...op) {
784 return cir::LLVMIntrinsicCallOp::create(*this, loc,
785 this->getStringAttr(str), resTy,
786 std::forward<Operands>(op)...)
787 .getResult();
788 }
789};
790
791} // namespace clang::CIRGen
792
793#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:96
mlir::Type getElementType() const
Definition Address.h:123
clang::CharUnits getAlignment() const
Definition Address.h:136
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)
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::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)
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.
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)
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.
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 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::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="")
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)
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::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:4327
TagKind getTagKind() const
Definition Decl.h:3917
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
TagTypeKind
The kind of a tag type.
Definition TypeBase.h:5939
@ Interface
The "__interface" keyword.
Definition TypeBase.h:5944
@ Struct
The "struct" keyword.
Definition TypeBase.h:5941
@ Class
The "class" keyword.
Definition TypeBase.h:5950
@ Union
The "union" keyword.
Definition TypeBase.h:5947
@ Enum
The "enum" keyword.
Definition TypeBase.h:5953
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.