clang 24.0.0git
CIRBaseBuilder.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_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
10#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
11
12#include "clang/AST/CharUnits.h"
19#include "llvm/ADT/STLForwardCompat.h"
20#include "llvm/IR/FPEnv.h"
21#include "llvm/Support/ErrorHandling.h"
22
23#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
24#include "mlir/IR/Builders.h"
25#include "mlir/IR/BuiltinAttributes.h"
26#include "mlir/IR/Location.h"
27#include "mlir/IR/OperationSupport.h"
28#include "mlir/IR/Types.h"
29
30namespace cir {
31
32enum class OverflowBehavior {
33 None = 0,
34 NoSignedWrap = 1 << 0,
36 Saturated = 1 << 2,
37};
38
40 return static_cast<OverflowBehavior>(llvm::to_underlying(a) |
41 llvm::to_underlying(b));
42}
43
45 return static_cast<OverflowBehavior>(llvm::to_underlying(a) &
46 llvm::to_underlying(b));
47}
48
51 a = a | b;
52 return a;
53}
54
57 a = a & b;
58 return a;
59}
60
61constexpr bool testFlag(OverflowBehavior ob, OverflowBehavior flag) {
62 return (ob & flag) != OverflowBehavior::None;
63}
64
65class CIRBaseBuilderTy : public mlir::OpBuilder {
66
67public:
68 CIRBaseBuilderTy(mlir::MLIRContext &mlirContext)
69 : mlir::OpBuilder(&mlirContext) {}
70 CIRBaseBuilderTy(mlir::OpBuilder &builder) : mlir::OpBuilder(builder) {}
71
72 // mlir::Builder's float getters return builtin types, which CIR types don't
73 // accept as elements. Use CIR float types, such as cir::SingleType.
74 mlir::FloatType getBF16Type() = delete;
75 mlir::FloatType getF16Type() = delete;
76 mlir::FloatType getTF32Type() = delete;
77 mlir::FloatType getF32Type() = delete;
78 mlir::FloatType getF64Type() = delete;
79 mlir::FloatType getF80Type() = delete;
80 mlir::FloatType getF128Type() = delete;
81
82 bool isFPConstrained = false;
85 llvm::RoundingMode defaultConstrainedRounding =
86 llvm::RoundingMode::NearestTiesToEven;
87 cir::FastMathFlags fastMathFlags = cir::FastMathFlags::none;
88
89 mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
90 const llvm::APInt &val) {
91 return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(typ, val));
92 }
93
94 cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr) {
95 return cir::ConstantOp::create(*this, loc, attr);
96 }
97
98 cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty,
99 int64_t value) {
100 return getConstant(loc, cir::IntAttr::get(ty, value));
101 }
102
103 mlir::Value getSignedInt(mlir::Location loc, int64_t val, unsigned numBits) {
104 auto type = cir::IntType::get(getContext(), numBits, /*isSigned=*/true);
105 return getConstAPInt(loc, type,
106 llvm::APInt(numBits, val, /*isSigned=*/true));
107 }
108
109 mlir::Value getUnsignedInt(mlir::Location loc, uint64_t val,
110 unsigned numBits) {
111 auto type = cir::IntType::get(getContext(), numBits, /*isSigned=*/false);
112 return getConstAPInt(loc, type, llvm::APInt(numBits, val));
113 }
114
115 // Creates constant null value for integral type ty.
116 cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) {
117 return getConstant(loc, getZeroInitAttr(ty));
118 }
119
120 mlir::TypedAttr getConstNullPtrAttr(mlir::Type t) {
121 assert(mlir::isa<cir::PointerType>(t) && "expected cir.ptr");
122 return getConstPtrAttr(t, 0);
123 }
124
125 mlir::TypedAttr getNullDataMemberAttr(cir::DataMemberType ty) {
126 return cir::DataMemberAttr::get(ty);
127 }
128
129 mlir::TypedAttr getZeroInitAttr(mlir::Type ty) {
130 if (auto bitFieldTy = mlir::dyn_cast<cir::BitFieldType>(ty)) {
131 assert(bitFieldTy.ownsBytes() &&
132 "a zero-width bit-field takes no initializer");
133 return getZeroInitAttr(bitFieldTy.getStorageType());
134 }
135 if (mlir::isa<cir::IntType>(ty))
136 return cir::IntAttr::get(ty, 0);
137 if (cir::isAnyFloatingPointType(ty))
138 return cir::FPAttr::getZero(ty);
139 if (auto complexType = mlir::dyn_cast<cir::ComplexType>(ty))
140 return cir::ZeroAttr::get(complexType);
141 if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty))
142 return cir::ZeroAttr::get(arrTy);
143 if (auto vecTy = mlir::dyn_cast<cir::VectorType>(ty))
144 return cir::ZeroAttr::get(vecTy);
145 if (auto matrixTy = mlir::dyn_cast<cir::MatrixType>(ty))
146 return cir::ZeroAttr::get(matrixTy);
147 if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty))
148 return getConstNullPtrAttr(ptrTy);
149 if (auto recordTy = mlir::dyn_cast<cir::RecordType>(ty))
150 return cir::ZeroAttr::get(recordTy);
151 if (auto dataMemberTy = mlir::dyn_cast<cir::DataMemberType>(ty))
152 return getNullDataMemberAttr(dataMemberTy);
153 if (auto methodTy = mlir::dyn_cast<cir::MethodType>(ty))
154 return getNullMethodAttr(methodTy);
155 if (auto vptrTy = mlir::dyn_cast<cir::VPtrType>(ty))
156 return cir::ZeroAttr::get(vptrTy);
157 if (mlir::isa<cir::BoolType>(ty)) {
158 return getFalseAttr();
159 }
160
161 llvm_unreachable("Zero initializer for given type is NYI");
162 }
163
164 cir::ConstantOp getBool(bool state, mlir::Location loc) {
165 return cir::ConstantOp::create(*this, loc, getCIRBoolAttr(state));
166 }
167 cir::ConstantOp getFalse(mlir::Location loc) { return getBool(false, loc); }
168 cir::ConstantOp getTrue(mlir::Location loc) { return getBool(true, loc); }
169
170 cir::BoolType getBoolTy() { return cir::BoolType::get(getContext()); }
171 cir::VoidType getVoidTy() { return cir::VoidType::get(getContext()); }
172
173 cir::IntType getUIntNTy(int n) {
174 return cir::IntType::get(getContext(), n, false);
175 }
176
177 static unsigned getCIRIntOrFloatBitWidth(mlir::Type eltTy) {
178 if (auto intType = mlir::dyn_cast<cir::IntTypeInterface>(eltTy))
179 return intType.getWidth();
180 if (auto floatType = mlir::dyn_cast<cir::FPTypeInterface>(eltTy))
181 return floatType.getWidth();
182
183 llvm_unreachable("Unsupported type in getCIRIntOrFloatBitWidth");
184 }
185 cir::IntType getSIntNTy(int n) {
186 return cir::IntType::get(getContext(), n, true);
187 }
188
189 cir::PointerType getPointerTo(mlir::Type ty) {
190 return cir::PointerType::get(ty);
191 }
192
193 cir::PointerType getPointerTo(mlir::Type ty,
194 mlir::ptr::MemorySpaceAttrInterface as) {
195 return cir::PointerType::get(ty, as);
196 }
197
198 cir::PointerType getPointerTo(mlir::Type ty, clang::LangAS langAS) {
199 if (langAS == clang::LangAS::Default)
200 return getPointerTo(ty);
201
202 mlir::ptr::MemorySpaceAttrInterface addrSpaceAttr =
203 cir::toCIRAddressSpaceAttr(*getContext(), langAS);
204 return getPointerTo(ty, addrSpaceAttr);
205 }
206
208 return getPointerTo(cir::VoidType::get(getContext()), langAS);
209 }
210
211 cir::PointerType getVoidPtrTy(mlir::ptr::MemorySpaceAttrInterface as) {
212 return getPointerTo(cir::VoidType::get(getContext()), as);
213 }
214
215 cir::MethodAttr getMethodAttr(cir::MethodType ty, cir::FuncOp methodFuncOp) {
216 auto methodFuncSymbolRef = mlir::FlatSymbolRefAttr::get(methodFuncOp);
217 return cir::MethodAttr::get(ty, methodFuncSymbolRef);
218 }
219
220 cir::MethodAttr getNullMethodAttr(cir::MethodType ty) {
221 return cir::MethodAttr::get(ty);
222 }
223
224 cir::BoolAttr getCIRBoolAttr(bool state) {
225 return cir::BoolAttr::get(getContext(), state);
226 }
227
228 cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }
229 cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }
230
231 //
232 // Floating point specific helpers
233 // -------------------------------
234 //
235
236 /// Enable/Disable use of constrained floating point math. When enabled the
237 /// CreateF<op>() calls instead create constrained floating point intrinsic
238 /// calls. Fast math flags are unaffected by this setting.
239 void setIsFPConstrained(bool isCon) { isFPConstrained = isCon; }
240
241 /// Query for the use of constrained floating point math
242 bool getIsFPConstrained() const { return isFPConstrained; }
243
244 /// Set the exception handling to be used with constrained floating point
249
250 /// Get the exception handling used with constrained floating point
254
255 /// Set the rounding mode handling to be used with constrained floating point
256 void setDefaultConstrainedRounding(llvm::RoundingMode newRounding) {
257 defaultConstrainedRounding = newRounding;
258 }
259
260 /// Get the rounding mode handling used with constrained floating point
261 llvm::RoundingMode getDefaultConstrainedRounding() const {
263 }
264
265 /// Set the fast-math flags attached to floating-point operations.
266 void setFastMathFlags(cir::FastMathFlags flags) { fastMathFlags = flags; }
267
268 /// Get the fast-math flags attached to floating-point operations.
269 cir::FastMathFlags getFastMathFlags() const { return fastMathFlags; }
270
271 /// Returns a null attribute when no fast-math flags are set.
272 cir::FastMathFlagsAttr getFastMathFlagsAttr() {
273 if (fastMathFlags == cir::FastMathFlags::none)
274 return {};
275 return cir::FastMathFlagsAttr::get(getContext(), fastMathFlags);
276 }
277
278 /// Build the `#cir.fenv` attribute describing the constrained floating-point
279 /// environment currently in effect. This is attached to floating-point
280 /// operations that support it to capture the rounding and exception
281 /// behavior. Returns a null attribute when constrained floating-point is not
282 /// enabled, in which case no attribute should be attached.
283 cir::FenvAttr getConstrainedFPAttr() {
284 if (!isFPConstrained)
285 return {};
286
287 cir::FPDynamicRoundingMode roundingMode;
289 case llvm::RoundingMode::NearestTiesToEven:
290 roundingMode = cir::FPDynamicRoundingMode::ToNearest;
291 break;
292 case llvm::RoundingMode::TowardNegative:
293 roundingMode = cir::FPDynamicRoundingMode::Downward;
294 break;
295 case llvm::RoundingMode::TowardPositive:
296 roundingMode = cir::FPDynamicRoundingMode::Upward;
297 break;
298 case llvm::RoundingMode::TowardZero:
299 roundingMode = cir::FPDynamicRoundingMode::UpwardZero;
300 break;
301 case llvm::RoundingMode::NearestTiesToAway:
302 roundingMode = cir::FPDynamicRoundingMode::ToNearestAway;
303 break;
304 case llvm::RoundingMode::Dynamic:
305 roundingMode = cir::FPDynamicRoundingMode::Unknown;
306 break;
307 default:
308 llvm_unreachable("unexpected constrained rounding mode");
309 }
310
311 cir::FPExceptionMode exceptMode;
312 bool strictExcept;
313 switch (defaultConstrainedExcept) {
315 exceptMode = cir::FPExceptionMode::Masked;
316 strictExcept = false;
317 break;
319 exceptMode = cir::FPExceptionMode::Unknown;
320 strictExcept = false;
321 break;
323 exceptMode = cir::FPExceptionMode::Unknown;
324 strictExcept = true;
325 break;
326 default:
327 llvm_unreachable("unexpected constrained exception mode");
328 }
329
330 return cir::FenvAttr::get(getContext(), roundingMode, exceptMode,
331 mlir::BoolAttr::get(getContext(), strictExcept));
332 }
333
334 mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
335 mlir::Value imag) {
336 auto resultComplexTy = cir::ComplexType::get(real.getType());
337 return cir::ComplexCreateOp::create(*this, loc, resultComplexTy, real,
338 imag);
339 }
340
341 mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
342 auto resultType = operand.getType();
343 if (auto complexResultType = mlir::dyn_cast<cir::ComplexType>(resultType))
344 resultType = complexResultType.getElementType();
345 return cir::ComplexRealOp::create(*this, loc, resultType, operand);
346 }
347
348 mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
349 auto resultType = operand.getType();
350 if (auto complexResultType = mlir::dyn_cast<cir::ComplexType>(resultType))
351 resultType = complexResultType.getElementType();
352 return cir::ComplexImagOp::create(*this, loc, resultType, operand);
353 }
354
355 mlir::Value createComplexAdd(mlir::Location loc, mlir::Value lhs,
356 mlir::Value rhs) {
357 auto complexTy = mlir::cast<cir::ComplexType>(lhs.getType());
358 if (cir::isAnyFloatingPointType(complexTy.getElementType())) {
359 cir::FenvAttr fenv = getConstrainedFPAttr();
360 return cir::ComplexFAddOp::create(*this, loc, lhs, rhs, fenv);
361 }
362 return cir::ComplexAddOp::create(*this, loc, lhs, rhs);
363 }
364
365 mlir::Value createComplexSub(mlir::Location loc, mlir::Value lhs,
366 mlir::Value rhs) {
367 auto complexTy = mlir::cast<cir::ComplexType>(lhs.getType());
368 if (cir::isAnyFloatingPointType(complexTy.getElementType())) {
369 cir::FenvAttr fenv = getConstrainedFPAttr();
370 return cir::ComplexFSubOp::create(*this, loc, lhs, rhs, fenv);
371 }
372 return cir::ComplexSubOp::create(*this, loc, lhs, rhs);
373 }
374
375 mlir::Value createComplexMul(mlir::Location loc, mlir::Value lhs,
376 mlir::Value rhs,
377 cir::ComplexRangeKind rangeKind) {
378 auto complexTy = mlir::cast<cir::ComplexType>(lhs.getType());
379 if (cir::isAnyFloatingPointType(complexTy.getElementType()))
380 return cir::ComplexFMulOp::create(*this, loc, lhs, rhs, rangeKind);
381 return cir::ComplexMulOp::create(*this, loc, lhs, rhs);
382 }
383
384 mlir::Value createComplexDiv(mlir::Location loc, mlir::Value lhs,
385 mlir::Value rhs,
386 cir::ComplexRangeKind rangeKind) {
387 auto complexTy = mlir::cast<cir::ComplexType>(lhs.getType());
388 if (cir::isAnyFloatingPointType(complexTy.getElementType()))
389 return cir::ComplexFDivOp::create(*this, loc, lhs, rhs, rangeKind);
390 return cir::ComplexDivOp::create(*this, loc, lhs, rhs);
391 }
392
393 mlir::Value createComplexConj(mlir::Location loc, mlir::Value operand) {
394 return cir::ComplexConjOp::create(*this, loc, operand.getType(), operand);
395 }
396
397 cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr,
398 bool isVolatile = false, uint64_t alignment = 0,
399 bool isNontemporal = false) {
400 mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
401 return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false, isVolatile,
402 isNontemporal, alignmentAttr,
403 cir::SyncScopeKindAttr{}, cir::MemOrderAttr{},
404 /*invariant=*/false);
405 }
406
407 mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr,
408 uint64_t alignment) {
409 return createLoad(loc, ptr, /*isVolatile=*/false, alignment);
410 }
411
412 mlir::Value createNot(mlir::Location loc, mlir::Value value) {
413 return cir::NotOp::create(*this, loc, value);
414 }
415
416 mlir::Value createNot(mlir::Value value) {
417 return createNot(value.getLoc(), value);
418 }
419
420 /// Create a do-while operation.
421 cir::DoWhileOp createDoWhile(
422 mlir::Location loc,
423 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
424 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
425 return cir::DoWhileOp::create(*this, loc, condBuilder, bodyBuilder);
426 }
427
428 /// Create a while operation.
429 cir::WhileOp createWhile(
430 mlir::Location loc,
431 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
432 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
433 return cir::WhileOp::create(*this, loc, condBuilder, bodyBuilder);
434 }
435
436 /// Create a while operation with a per-iteration cleanup region.
437 cir::WhileOp createWhile(
438 mlir::Location loc,
439 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
440 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder,
441 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>
442 cleanupBuilder,
443 cir::CleanupKind cleanupKind) {
444 return cir::WhileOp::create(*this, loc, condBuilder, bodyBuilder,
445 cleanupBuilder, cleanupKind);
446 }
447
448 /// Create a for operation.
449 cir::ForOp createFor(
450 mlir::Location loc,
451 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
452 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder,
453 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> stepBuilder) {
454 return cir::ForOp::create(*this, loc, condBuilder, bodyBuilder,
455 stepBuilder);
456 }
457
458 /// Create a for operation with a per-iteration cleanup region.
459 cir::ForOp createFor(
460 mlir::Location loc,
461 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
462 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder,
463 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> stepBuilder,
464 llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>
465 cleanupBuilder,
466 cir::CleanupKind cleanupKind) {
467 return cir::ForOp::create(*this, loc, condBuilder, bodyBuilder, stepBuilder,
468 cleanupBuilder, cleanupKind);
469 }
470
471 /// Create a break operation.
472 cir::BreakOp createBreak(mlir::Location loc) {
473 return cir::BreakOp::create(*this, loc);
474 }
475
476 /// Create a continue operation.
477 cir::ContinueOp createContinue(mlir::Location loc) {
478 return cir::ContinueOp::create(*this, loc);
479 }
480
481 mlir::Value createInc(mlir::Location loc, mlir::Value input,
482 bool nsw = false) {
483 return cir::IncOp::create(*this, loc, input, nsw);
484 }
485
486 mlir::Value createDec(mlir::Location loc, mlir::Value input,
487 bool nsw = false) {
488 return cir::DecOp::create(*this, loc, input, nsw);
489 }
490
491 mlir::Value createMinus(mlir::Location loc, mlir::Value input,
492 bool nsw = false) {
493 return cir::MinusOp::create(*this, loc, input, nsw);
494 }
495
496 mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
497 return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));
498 }
499
500 mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
501 llvm::StringRef name, mlir::IntegerAttr alignment,
502 mlir::Value dynAllocSize) {
503 return cir::AllocaOp::create(*this, loc, addrType, name, alignment,
504 dynAllocSize);
505 }
506
507 mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
508 mlir::Type type, llvm::StringRef name,
509 clang::CharUnits alignment,
510 mlir::Value dynAllocSize) {
511 mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
512 return createAlloca(loc, addrType, name, alignmentAttr, dynAllocSize);
513 }
514
515 mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
516 llvm::StringRef name, mlir::IntegerAttr alignment) {
517 return cir::AllocaOp::create(*this, loc, addrType, name, alignment);
518 }
519
520 mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
521 llvm::StringRef name, clang::CharUnits alignment) {
522 mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
523 return createAlloca(loc, addrType, name, alignmentAttr);
524 }
525
526 /// Get constant address of a global variable as an MLIR attribute.
527 /// This wrapper infers the attribute type through the global op.
528 cir::GlobalViewAttr getGlobalViewAttr(cir::GlobalOp globalOp,
529 mlir::ArrayAttr indices = {}) {
530 cir::PointerType type = getPointerTo(globalOp.getSymType());
531 return getGlobalViewAttr(type, globalOp, indices);
532 }
533
534 /// Get constant address of a global variable as an MLIR attribute.
535 cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type,
536 cir::GlobalOp globalOp,
537 mlir::ArrayAttr indices = {},
538 bool addressPoint = false) {
539 auto symbol = mlir::FlatSymbolRefAttr::get(globalOp.getSymNameAttr());
540 return cir::GlobalViewAttr::get(type, symbol, indices, addressPoint);
541 }
542
543 /// Get constant address of a global variable as an MLIR attribute.
544 /// This overload converts raw int64_t indices to an ArrayAttr.
545 cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type,
546 cir::GlobalOp globalOp,
548 bool addressPoint = false) {
550 for (int64_t ind : indices)
551 attrs.push_back(getI64IntegerAttr(ind));
552 mlir::ArrayAttr arAttr = mlir::ArrayAttr::get(getContext(), attrs);
553 return getGlobalViewAttr(type, globalOp, arAttr, addressPoint);
554 }
555
556 cir::GetGlobalOp createGetGlobal(mlir::Location loc, cir::GlobalOp global,
557 bool threadLocal = false) {
558 return cir::GetGlobalOp::create(
559 *this, loc,
560 getPointerTo(global.getSymType(), global.getAddrSpaceAttr()),
561 global.getSymNameAttr(), threadLocal);
562 }
563
564 cir::GetGlobalOp createGetGlobal(cir::GlobalOp global,
565 bool threadLocal = false) {
566 return createGetGlobal(global.getLoc(), global, threadLocal);
567 }
568
569 /// Create a copy with inferred length.
570 cir::CopyOp createCopy(mlir::Value dst, mlir::Value src,
571 bool isVolatile = false,
572 bool skipTailPadding = false) {
573 return cir::CopyOp::create(*this, dst.getLoc(), dst, src,
574 /*dst_alignment=*/{}, /*src_alignment=*/{},
575 isVolatile, skipTailPadding);
576 }
577
578 cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst,
579 bool isVolatile = false, bool isNontemporal = false,
580 mlir::IntegerAttr align = {},
581 cir::SyncScopeKindAttr scope = {},
582 cir::MemOrderAttr order = {}) {
583 if (mlir::cast<cir::PointerType>(dst.getType()).getPointee() !=
584 val.getType())
585 dst = createPtrBitcast(dst, val.getType());
586 return cir::StoreOp::create(*this, loc, val, dst, isVolatile, isNontemporal,
587 align, scope, order);
588 }
589
590 /// Emit a load from an boolean flag variable.
591 cir::LoadOp createFlagLoad(mlir::Location loc, mlir::Value addr) {
592 mlir::Type boolTy = getBoolTy();
593 if (boolTy != mlir::cast<cir::PointerType>(addr.getType()).getPointee())
594 addr = createPtrBitcast(addr, boolTy);
595 return createLoad(loc, addr, /*isVolatile=*/false, /*alignment=*/1);
596 }
597
598 cir::StoreOp createFlagStore(mlir::Location loc, bool val, mlir::Value dst) {
599 mlir::Value flag = getBool(val, loc);
600 return CIRBaseBuilderTy::createStore(loc, flag, dst);
601 }
602
603 [[nodiscard]] cir::GlobalOp
604 createGlobal(mlir::ModuleOp mlirModule, mlir::Location loc,
605 mlir::StringRef name, mlir::Type type, bool isConstant,
606 cir::GlobalLinkageKind linkage,
607 mlir::ptr::MemorySpaceAttrInterface addrSpace) {
608 mlir::OpBuilder::InsertionGuard guard(*this);
609 setInsertionPointToStart(mlirModule.getBody());
610 return cir::GlobalOp::create(*this, loc, name, type, isConstant, addrSpace,
611 linkage);
612 }
613
614 cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy,
615 mlir::Value base, llvm::StringRef name,
616 unsigned index) {
617 return cir::GetMemberOp::create(*this, loc, resultTy, base, name, index);
618 }
619
620 mlir::Value createDummyValue(mlir::Location loc, mlir::Type type,
621 clang::CharUnits alignment) {
622 mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
623 auto addr = createAlloca(loc, getPointerTo(type), {}, alignmentAttr);
624 return cir::LoadOp::create(*this, loc, addr, /*isDeref=*/false,
625 /*isVolatile=*/false, /*nontemporal=*/false,
626 alignmentAttr,
627 /*sync_scope=*/{}, /*mem_order=*/{},
628 /*invariant=*/false);
629 }
630
631 cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base,
632 mlir::Value stride) {
633 return cir::PtrStrideOp::create(*this, loc, base.getType(), base, stride);
634 }
635
636 //===--------------------------------------------------------------------===//
637 // Call operators
638 //===--------------------------------------------------------------------===//
639
640 cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee,
641 mlir::Type returnType, mlir::ValueRange operands,
645 cir::CallingConv callingConv = cir::CallingConv::C) {
646 auto op = cir::CallOp::create(*this, loc, callee, returnType, operands);
647 op->setAttrs(attrs);
648 if (callingConv != cir::CallingConv::C)
649 op.setCallingConv(callingConv);
650
651 if (!argAttrs.empty()) {
652 llvm::SmallVector<mlir::Attribute> argDictAttrs;
653 argDictAttrs.reserve(argAttrs.size());
654
655 llvm::transform(
656 argAttrs, std::back_inserter(argDictAttrs),
657 [this](llvm::ArrayRef<mlir::NamedAttribute> singleArgAttrs) {
658 return mlir::DictionaryAttr::get(getContext(), singleArgAttrs);
659 });
660
661 op.setArgAttrsAttr(mlir::ArrayAttr::get(getContext(), argDictAttrs));
662 }
663
664 if (!resAttrs.empty()) {
665 auto resultDictAttr = mlir::DictionaryAttr::get(getContext(), resAttrs);
666 op.setResAttrsAttr(mlir::ArrayAttr::get(getContext(), resultDictAttr));
667 }
668 return op;
669 }
670
671 cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee,
672 mlir::ValueRange operands,
676 cir::CallingConv callingConv = cir::CallingConv::C) {
677 return createCallOp(loc, mlir::SymbolRefAttr::get(callee),
678 callee.getFunctionType().getReturnType(), operands,
679 attrs, argAttrs, resAttrs, callingConv);
680 }
681
682 cir::CallOp
683 createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget,
684 cir::FuncType funcType, mlir::ValueRange operands,
688 cir::CallingConv callingConv = cir::CallingConv::C) {
689 llvm::SmallVector<mlir::Value> resOperands{indirectTarget};
690 resOperands.append(operands.begin(), operands.end());
691
692 return createCallOp(loc, mlir::SymbolRefAttr(), funcType.getReturnType(),
693 resOperands, attrs, argAttrs, resAttrs, callingConv);
694 }
695
696 cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee,
697 mlir::ValueRange operands = mlir::ValueRange(),
701 return createCallOp(loc, callee, cir::VoidType(), operands, attrs, argAttrs,
702 resAttrs);
703 }
704
705 //===--------------------------------------------------------------------===//
706 // Cast/Conversion Operators
707 //===--------------------------------------------------------------------===//
708
709 mlir::Value createCast(mlir::Location loc, cir::CastKind kind,
710 mlir::Value src, mlir::Type newTy) {
711 if (newTy == src.getType())
712 return src;
713 return cir::CastOp::create(*this, loc, newTy, kind, src);
714 }
715
716 mlir::Value createCast(cir::CastKind kind, mlir::Value src,
717 mlir::Type newTy) {
718 if (newTy == src.getType())
719 return src;
720 return createCast(src.getLoc(), kind, src, newTy);
721 }
722
723 // Creates a cast from bool or int to an integer type.
724 mlir::Value createBoolIntToIntCast(mlir::Value src, mlir::Type newTy) {
725 if (newTy == src.getType())
726 return src;
727 if (src.getType() == getBoolTy())
728 return createBoolToInt(src, newTy);
729 return createIntCast(src, newTy);
730 }
731
732 mlir::Value createIntCast(mlir::Value src, mlir::Type newTy) {
733 return createCast(cir::CastKind::integral, src, newTy);
734 }
735
736 mlir::Value createBuiltinIntCast(mlir::Location loc, mlir::Value src,
737 mlir::Type newTy) {
738 return cir::BuiltinIntCastOp::create(*this, loc, newTy, src);
739 }
740
741 mlir::Value createBuiltinIntCast(mlir::Value src, mlir::Type newTy) {
742 return createBuiltinIntCast(src.getLoc(), src, newTy);
743 }
744
745 mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy) {
746 return createCast(cir::CastKind::int_to_ptr, src, newTy);
747 }
748
749 mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy) {
750 return createCast(cir::CastKind::ptr_to_int, src, newTy);
751 }
752
753 mlir::Value createPtrToBoolCast(mlir::Value v) {
754 return createCast(cir::CastKind::ptr_to_bool, v, getBoolTy());
755 }
756
757 mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy) {
758 return createCast(cir::CastKind::bool_to_int, src, newTy);
759 }
760
761 mlir::Value createBitcast(mlir::Value src, mlir::Type newTy) {
762 return createCast(cir::CastKind::bitcast, src, newTy);
763 }
764
765 mlir::Value createBitcast(mlir::Location loc, mlir::Value src,
766 mlir::Type newTy) {
767 return createCast(loc, cir::CastKind::bitcast, src, newTy);
768 }
769
770 mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy) {
771 assert(mlir::isa<cir::PointerType>(src.getType()) && "expected ptr src");
772 cir::PointerType srcPtrTy = mlir::cast<cir::PointerType>(src.getType());
773 return createBitcast(src,
774 getPointerTo(newPointeeTy, srcPtrTy.getAddrSpace()));
775 }
776
777 mlir::Value createPtrIsNull(mlir::Value ptr) {
778 mlir::Value nullPtr = getNullPtr(ptr.getType(), ptr.getLoc());
779 return createCompare(ptr.getLoc(), cir::CmpOpKind::eq, ptr, nullPtr);
780 }
781
782 mlir::Value createPtrIsNotNull(mlir::Value ptr) {
783 mlir::Value nullPtr = getNullPtr(ptr.getType(), ptr.getLoc());
784 return createCompare(ptr.getLoc(), cir::CmpOpKind::ne, ptr, nullPtr);
785 }
786
787 mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src,
788 mlir::Type newTy) {
789 return createCast(loc, cir::CastKind::address_space, src, newTy);
790 }
791
792 mlir::Value createAddrSpaceCast(mlir::Value src, mlir::Type newTy) {
793 return createAddrSpaceCast(src.getLoc(), src, newTy);
794 }
795
796 //===--------------------------------------------------------------------===//
797 // Other Instructions
798 //===--------------------------------------------------------------------===//
799
800 mlir::Value createExtractElement(mlir::Location loc, mlir::Value vec,
801 uint64_t idx) {
802 mlir::Value idxVal =
803 getConstAPInt(loc, getUIntNTy(64), llvm::APInt(64, idx));
804 return cir::VecExtractOp::create(*this, loc, vec, idxVal);
805 }
806
807 mlir::Value createInsertElement(mlir::Location loc, mlir::Value vec,
808 mlir::Value newElt, uint64_t idx) {
809 mlir::Value idxVal =
810 getConstAPInt(loc, getUIntNTy(64), llvm::APInt(64, idx));
811 return cir::VecInsertOp::create(*this, loc, vec, newElt, idxVal);
812 }
813
814 cir::SignBitOp createSignBit(mlir::Location loc, mlir::Value val) {
815 auto resTy = cir::BoolType::get(getContext());
816 return cir::SignBitOp::create(*this, loc, resTy, val);
817 }
818
819 //===--------------------------------------------------------------------===//
820 // Binary Operators
821 //===--------------------------------------------------------------------===//
822
823 mlir::Value createLowBitsSet(mlir::Location loc, unsigned size,
824 unsigned bits) {
825 llvm::APInt val = llvm::APInt::getLowBitsSet(size, bits);
826 auto type = cir::IntType::get(getContext(), size, /*isSigned=*/false);
827 return getConstAPInt(loc, type, val);
828 }
829
830 mlir::Value createAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
831 return cir::AndOp::create(*this, loc, lhs, rhs);
832 }
833
834 mlir::Value createOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
835 return cir::OrOp::create(*this, loc, lhs, rhs);
836 }
837
838 mlir::Value createSelect(mlir::Location loc, mlir::Value condition,
839 mlir::Value trueValue, mlir::Value falseValue) {
840 assert(trueValue.getType() == falseValue.getType() &&
841 "trueValue and falseValue should have the same type");
842 return cir::SelectOp::create(*this, loc, trueValue.getType(), condition,
843 trueValue, falseValue);
844 }
845
846 mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs,
847 mlir::Value rhs) {
848 return createSelect(loc, lhs, rhs, getBool(false, loc));
849 }
850
851 mlir::Value createLogicalOr(mlir::Location loc, mlir::Value lhs,
852 mlir::Value rhs) {
853 return createSelect(loc, lhs, getBool(true, loc), rhs);
854 }
855
856 mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
858 auto op = cir::MulOp::create(*this, loc, lhs, rhs);
859 op.setNoUnsignedWrap(testFlag(ob, OverflowBehavior::NoUnsignedWrap));
860 op.setNoSignedWrap(testFlag(ob, OverflowBehavior::NoSignedWrap));
861 return op;
862 }
863 mlir::Value createNSWMul(mlir::Location loc, mlir::Value lhs,
864 mlir::Value rhs) {
865 return createMul(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
866 }
867 mlir::Value createNUWAMul(mlir::Location loc, mlir::Value lhs,
868 mlir::Value rhs) {
869 return createMul(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
870 }
871
872 mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
874 auto op = cir::SubOp::create(*this, loc, lhs, rhs);
875 op.setNoUnsignedWrap(testFlag(ob, OverflowBehavior::NoUnsignedWrap));
876 op.setNoSignedWrap(testFlag(ob, OverflowBehavior::NoSignedWrap));
877 op.setSaturated(testFlag(ob, OverflowBehavior::Saturated));
878 return op;
879 }
880
881 mlir::Value createNSWSub(mlir::Location loc, mlir::Value lhs,
882 mlir::Value rhs) {
883 return createSub(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
884 }
885
886 mlir::Value createNUWSub(mlir::Location loc, mlir::Value lhs,
887 mlir::Value rhs) {
888 return createSub(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
889 }
890
891 mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
893 auto op = cir::AddOp::create(*this, loc, lhs, rhs);
894 op.setNoUnsignedWrap(testFlag(ob, OverflowBehavior::NoUnsignedWrap));
895 op.setNoSignedWrap(testFlag(ob, OverflowBehavior::NoSignedWrap));
896 op.setSaturated(testFlag(ob, OverflowBehavior::Saturated));
897 return op;
898 }
899
900 mlir::Value createNSWAdd(mlir::Location loc, mlir::Value lhs,
901 mlir::Value rhs) {
902 return createAdd(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
903 }
904
905 mlir::Value createNUWAdd(mlir::Location loc, mlir::Value lhs,
906 mlir::Value rhs) {
907 return createAdd(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
908 }
909
910 mlir::Value createDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
911 return cir::DivOp::create(*this, loc, lhs, rhs);
912 }
913
914 mlir::Value createRem(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
915 return cir::RemOp::create(*this, loc, lhs, rhs);
916 }
917
918 template <typename OpTy>
919 mlir::Value createFPBinOp(mlir::Location loc, mlir::Value lhs,
920 mlir::Value rhs) {
922 return OpTy::create(*this, loc, lhs, rhs, getConstrainedFPAttr(),
924 }
925
926 mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
927 return createFPBinOp<cir::FAddOp>(loc, lhs, rhs);
928 }
929
930 mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
931 return createFPBinOp<cir::FSubOp>(loc, lhs, rhs);
932 }
933
934 mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
935 return createFPBinOp<cir::FMulOp>(loc, lhs, rhs);
936 }
937
938 mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
939 return createFPBinOp<cir::FDivOp>(loc, lhs, rhs);
940 }
941
942 mlir::Value createFRem(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
943 return createFPBinOp<cir::FRemOp>(loc, lhs, rhs);
944 }
945
946 mlir::Value createFNeg(mlir::Location loc, mlir::Value operand) {
947 assert(cir::isFPOrVectorOfFPType(operand.getType()) &&
948 "expected floating-point or vector-of-float type");
951 // fneg does not raise FP exceptions or depend on the rounding mode, so it
952 // never carries an fenv attribute.
953 return cir::FNegOp::create(*this, loc, operand);
954 }
955
956 mlir::Value createXor(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
957 return cir::XorOp::create(*this, loc, lhs, rhs);
958 }
959
960 mlir::Value createMax(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
961 return cir::MaxOp::create(*this, loc, lhs, rhs);
962 }
963
964 mlir::Value createMin(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
965 return cir::MinOp::create(*this, loc, lhs, rhs);
966 }
967
968 cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind,
969 mlir::Value lhs, mlir::Value rhs) {
970 cir::FenvAttr fenv;
971 if (cir::isAnyFloatingPointType(lhs.getType()))
972 fenv = getConstrainedFPAttr();
973 return cir::CmpOp::create(*this, loc, kind, lhs, rhs, fenv);
974 }
975
976 /// Compares \p lhs and \p rhs element-wise. Each result element is a
977 /// signed integer of the operand element's bit width. That is not the
978 /// result an FP80 element needs, so an FP80 compare names its result type
979 /// with the overload below.
980 cir::VecCmpOp createVecCompare(mlir::Location loc, cir::CmpOpKind kind,
981 mlir::Value lhs, mlir::Value rhs) {
982 VectorType vecCast = mlir::cast<VectorType>(lhs.getType());
983 mlir::Type elemTy = vecCast.getElementType();
984 assert(!(mlir::isa<cir::FPTypeInterface>(elemTy) &&
985 &mlir::cast<cir::FPTypeInterface>(elemTy).getFloatSemantics() ==
986 &llvm::APFloat::x87DoubleExtended()) &&
987 "an FP80 vector compare must name its result type");
988 IntType integralTy = getSIntNTy(getCIRIntOrFloatBitWidth(elemTy));
989 return createVecCompare(loc,
990 cir::VectorType::get(integralTy, vecCast.getSize()),
991 kind, lhs, rhs);
992 }
993
994 /// Compares \p lhs and \p rhs element-wise, producing \p resultTy, which
995 /// must be a vector of integers or bools with as many elements as \p lhs.
996 /// The result element width can then differ from the operand element's
997 /// bit width, as for FP80, whose result elements are 128 bits.
998 cir::VecCmpOp createVecCompare(mlir::Location loc, VectorType resultTy,
999 cir::CmpOpKind kind, mlir::Value lhs,
1000 mlir::Value rhs) {
1001 assert(mlir::cast<VectorType>(lhs.getType()).getSize() ==
1002 resultTy.getSize() &&
1003 cir::isIntOrBoolType(resultTy.getElementType()) &&
1004 "vector compare result must be an int or bool vector of the "
1005 "operand length");
1006 cir::FenvAttr fenv;
1007 if (cir::isFPOrVectorOfFPType(lhs.getType()))
1008 fenv = getConstrainedFPAttr();
1009 return cir::VecCmpOp::create(*this, loc, resultTy, kind, lhs, rhs, fenv);
1010 }
1011
1012 mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) {
1013 return createCompare(loc, cir::CmpOpKind::ne, operand, operand);
1014 }
1015
1016 mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
1017 bool isShiftLeft) {
1018 return cir::ShiftOp::create(*this, loc, lhs.getType(), lhs, rhs,
1019 isShiftLeft);
1020 }
1021
1022 mlir::Value createShift(mlir::Location loc, mlir::Value lhs,
1023 const llvm::APInt &rhs, bool isShiftLeft) {
1024 return createShift(loc, lhs, getConstAPInt(loc, lhs.getType(), rhs),
1025 isShiftLeft);
1026 }
1027
1028 mlir::Value createShift(mlir::Location loc, mlir::Value lhs, unsigned bits,
1029 bool isShiftLeft) {
1030 auto width = mlir::dyn_cast<cir::IntType>(lhs.getType()).getWidth();
1031 auto shift = llvm::APInt(width, bits);
1032 return createShift(loc, lhs, shift, isShiftLeft);
1033 }
1034
1035 mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs,
1036 unsigned bits) {
1037 return createShift(loc, lhs, bits, true);
1038 }
1039
1040 mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs,
1041 unsigned bits) {
1042 return createShift(loc, lhs, bits, false);
1043 }
1044
1045 mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs,
1046 mlir::Value rhs) {
1047 return createShift(loc, lhs, rhs, true);
1048 }
1049
1050 mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs,
1051 mlir::Value rhs) {
1052 return createShift(loc, lhs, rhs, false);
1053 }
1054
1055 /// Returns `void (T...)` as a cir::FuncType.
1056 cir::FuncType getVoidFnTy(mlir::TypeRange argTypes = {}) {
1057 return cir::FuncType::get(llvm::to_vector(argTypes), getVoidTy());
1058 }
1059
1060 /// Returns `void (*)(T...)` as a cir::PointerType.
1061 cir::PointerType getVoidFnPtrTy(mlir::TypeRange argTypes = {}) {
1062 return getPointerTo(getVoidFnTy(argTypes));
1063 }
1064
1065 //
1066 // Block handling helpers
1067 // ----------------------
1068 //
1069 static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block) {
1070 auto last =
1071 std::find_if(block->rbegin(), block->rend(), [](mlir::Operation &op) {
1072 return mlir::isa<cir::AllocaOp, cir::LabelOp>(&op);
1073 });
1074
1075 if (last != block->rend())
1076 return OpBuilder::InsertPoint(block, ++mlir::Block::iterator(&*last));
1077 return OpBuilder::InsertPoint(block, block->begin());
1078 };
1079
1080 //
1081 // Alignment and size helpers
1082 //
1083
1084 // Note that mlir::IntegerType is used instead of cir::IntType here because we
1085 // don't need sign information for these to be useful, so keep it simple.
1086
1087 // For 0 alignment, any overload of `getAlignmentAttr` returns an empty
1088 // attribute.
1089 mlir::IntegerAttr getAlignmentAttr(clang::CharUnits alignment) {
1090 return getAlignmentAttr(alignment.getQuantity());
1091 }
1092
1093 mlir::IntegerAttr getAlignmentAttr(llvm::Align alignment) {
1094 return getAlignmentAttr(alignment.value());
1095 }
1096
1097 mlir::IntegerAttr getAlignmentAttr(int64_t alignment) {
1098 return alignment ? getI64IntegerAttr(alignment) : mlir::IntegerAttr();
1099 }
1100
1101 // Materialize an alignment value as a CIR integer constant of the given
1102 // integer type.
1103 cir::ConstantOp getAlignment(mlir::Location loc, mlir::Type t,
1104 clang::CharUnits alignment) {
1105 return getConstantInt(loc, t, alignment.getQuantity());
1106 }
1107
1108 mlir::IntegerAttr getSizeFromCharUnits(clang::CharUnits size) {
1109 return getI64IntegerAttr(size.getQuantity());
1110 }
1111
1112 // Creates constant nullptr for pointer type ty.
1113 cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
1115 return cir::ConstantOp::create(*this, loc, getConstPtrAttr(ty, 0));
1116 }
1117
1118 /// Create a loop condition.
1119 cir::ConditionOp createCondition(mlir::Value condition) {
1120 return cir::ConditionOp::create(*this, condition.getLoc(), condition);
1121 }
1122
1123 /// Create a yield operation.
1124 cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) {
1125 return cir::YieldOp::create(*this, loc, value);
1126 }
1127
1129 mlir::Value callee;
1130 mlir::Value adjustedThis;
1131 };
1132
1133 GetMethodResults createGetMethod(mlir::Location loc, mlir::Value method,
1134 mlir::Value objectPtr) {
1135 // Build the callee function type.
1136 auto methodFuncTy =
1137 mlir::cast<cir::MethodType>(method.getType()).getMemberFuncTy();
1138 auto methodFuncInputTypes = methodFuncTy.getInputs();
1139
1140 auto objectPtrTy = mlir::cast<cir::PointerType>(objectPtr.getType());
1141 mlir::Type adjustedThisTy = getVoidPtrTy(objectPtrTy.getAddrSpace());
1142
1143 llvm::SmallVector<mlir::Type> calleeFuncInputTypes{adjustedThisTy};
1144 // The member function type's first parameter is the implicit 'this'
1145 // pointer. The callee takes an adjusted void* receiver instead.
1146 if (methodFuncInputTypes.size() > 1)
1147 calleeFuncInputTypes.insert(calleeFuncInputTypes.end(),
1148 methodFuncInputTypes.begin() + 1,
1149 methodFuncInputTypes.end());
1150 cir::FuncType calleeFuncTy =
1151 methodFuncTy.clone(calleeFuncInputTypes, methodFuncTy.getReturnType());
1152 // TODO(cir): consider the address space of the callee.
1154 cir::PointerType calleeTy = getPointerTo(calleeFuncTy);
1155
1156 auto op = cir::GetMethodOp::create(*this, loc, calleeTy, adjustedThisTy,
1157 method, objectPtr);
1158 return {op.getCallee(), op.getAdjustedThis()};
1159 }
1160};
1161
1162} // namespace cir
1163
1164#endif
Provides definitions for the various language-specific address spaces.
Defines the clang::LangOptions interface.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a an optional score condition
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
mlir::FloatType getTF32Type()=delete
mlir::Value createNSWSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::ConstantOp getBool(bool state, mlir::Location loc)
mlir::Value createShift(mlir::Location loc, mlir::Value lhs, unsigned bits, bool isShiftLeft)
cir::StoreOp createFlagStore(mlir::Location loc, bool val, mlir::Value dst)
cir::WhileOp createWhile(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder)
Create a while operation.
mlir::Value createDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, llvm::StringRef name, mlir::IntegerAttr alignment)
mlir::Value createComplexMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, cir::ComplexRangeKind rangeKind)
cir::VecCmpOp createVecCompare(mlir::Location loc, VectorType resultTy, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
Compares lhs and rhs element-wise, producing resultTy, which must be a vector of integers or bools wi...
cir::BreakOp createBreak(mlir::Location loc)
Create a break operation.
mlir::TypedAttr getConstNullPtrAttr(mlir::Type t)
cir::FenvAttr getConstrainedFPAttr()
Build the #cir.fenv attribute describing the constrained floating-point environment currently in effe...
cir::PointerType getVoidPtrTy(mlir::ptr::MemorySpaceAttrInterface as)
mlir::IntegerAttr getAlignmentAttr(int64_t alignment)
mlir::Value createDec(mlir::Location loc, mlir::Value input, bool nsw=false)
mlir::Value createShift(mlir::Location loc, mlir::Value lhs, const llvm::APInt &rhs, bool isShiftLeft)
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ, const llvm::APInt &val)
mlir::Value createBuiltinIntCast(mlir::Value src, mlir::Type newTy)
mlir::Value createCast(cir::CastKind kind, mlir::Value src, mlir::Type newTy)
mlir::Value createLogicalOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, bool isShiftLeft)
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
cir::ConditionOp createCondition(mlir::Value condition)
Create a loop condition.
clang::LangOptions::FPExceptionModeKind getDefaultConstrainedExcept() const
Get the exception handling used with constrained floating point.
mlir::Value createLowBitsSet(mlir::Location loc, unsigned size, unsigned bits)
mlir::Value createInc(mlir::Location loc, mlir::Value input, bool nsw=false)
cir::CopyOp createCopy(mlir::Value dst, mlir::Value src, bool isVolatile=false, bool skipTailPadding=false)
Create a copy with inferred length.
mlir::Value createNSWAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::GlobalViewAttr getGlobalViewAttr(cir::GlobalOp globalOp, mlir::ArrayAttr indices={})
Get constant address of a global variable as an MLIR attribute.
cir::MethodAttr getMethodAttr(cir::MethodType ty, cir::FuncOp methodFuncOp)
cir::FastMathFlags getFastMathFlags() const
Get the fast-math flags attached to floating-point operations.
cir::VoidType getVoidTy()
cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc)
cir::BoolAttr getCIRBoolAttr(bool state)
mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy)
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
cir::MethodAttr getNullMethodAttr(cir::MethodType ty)
mlir::Value createNUWAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::FloatType getF80Type()=delete
mlir::Value createPtrIsNull(mlir::Value ptr)
mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createFPBinOp(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::SignBitOp createSignBit(mlir::Location loc, mlir::Value val)
mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy)
mlir::IntegerAttr getSizeFromCharUnits(clang::CharUnits size)
cir::PointerType getVoidFnPtrTy(mlir::TypeRange argTypes={})
Returns void (*)(T...) as a cir::PointerType.
cir::ForOp createFor(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> stepBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> cleanupBuilder, cir::CleanupKind cleanupKind)
Create a for operation with a per-iteration cleanup region.
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base, mlir::Value stride)
mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy)
mlir::Value createRem(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::ForOp createFor(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> stepBuilder)
Create a for operation.
cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type, cir::GlobalOp globalOp, mlir::ArrayAttr indices={}, bool addressPoint=false)
Get constant address of a global variable as an MLIR attribute.
mlir::FloatType getF64Type()=delete
static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block)
mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy)
mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createNUWSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::ConstantOp getFalse(mlir::Location loc)
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::ValueRange operands=mlir::ValueRange(), llvm::ArrayRef< mlir::NamedAttribute > attrs={}, llvm::ArrayRef< mlir::NamedAttrList > argAttrs={}, llvm::ArrayRef< mlir::NamedAttribute > resAttrs={})
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy, mlir::Value base, llvm::StringRef name, unsigned index)
cir::PointerType getPointerTo(mlir::Type ty)
mlir::Value createFNeg(mlir::Location loc, mlir::Value operand)
mlir::Value createComplexSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, llvm::StringRef name, clang::CharUnits alignment)
mlir::Value createNot(mlir::Value value)
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={}, llvm::ArrayRef< mlir::NamedAttrList > argAttrs={}, llvm::ArrayRef< mlir::NamedAttribute > resAttrs={}, cir::CallingConv callingConv=cir::CallingConv::C)
mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand)
cir::ConstantOp getTrue(mlir::Location loc)
mlir::Value createNSWMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={}, llvm::ArrayRef< mlir::NamedAttrList > argAttrs={}, llvm::ArrayRef< mlir::NamedAttribute > resAttrs={}, cir::CallingConv callingConv=cir::CallingConv::C)
cir::GetGlobalOp createGetGlobal(cir::GlobalOp global, bool threadLocal=false)
cir::IntType getUIntNTy(int n)
mlir::Value createComplexDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, cir::ComplexRangeKind rangeKind)
cir::DoWhileOp createDoWhile(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder)
Create a do-while operation.
mlir::Value createNUWAMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
cir::GetGlobalOp createGetGlobal(mlir::Location loc, cir::GlobalOp global, bool threadLocal=false)
mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs, unsigned bits)
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, llvm::StringRef name, mlir::IntegerAttr alignment, mlir::Value dynAllocSize)
cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr, bool isVolatile=false, uint64_t alignment=0, bool isNontemporal=false)
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, mlir::Type type, llvm::StringRef name, clang::CharUnits alignment, mlir::Value dynAllocSize)
mlir::Value getSignedInt(mlir::Location loc, int64_t val, unsigned numBits)
cir::WhileOp createWhile(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> cleanupBuilder, cir::CleanupKind cleanupKind)
Create a while operation with a per-iteration cleanup region.
mlir::Value createMax(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::FloatType getF16Type()=delete
cir::PointerType getPointerTo(mlir::Type ty, clang::LangAS langAS)
mlir::Value createExtractElement(mlir::Location loc, mlir::Value vec, uint64_t idx)
cir::VecCmpOp createVecCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
Compares lhs and rhs element-wise.
mlir::Value createIntCast(mlir::Value src, mlir::Type newTy)
mlir::Value createInsertElement(mlir::Location loc, mlir::Value vec, mlir::Value newElt, uint64_t idx)
cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type, cir::GlobalOp globalOp, llvm::ArrayRef< int64_t > indices, bool addressPoint=false)
Get constant address of a global variable as an MLIR attribute.
llvm::RoundingMode defaultConstrainedRounding
cir::FastMathFlagsAttr getFastMathFlagsAttr()
Returns a null attribute when no fast-math flags are set.
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
CIRBaseBuilderTy(mlir::MLIRContext &mlirContext)
mlir::Value createBitcast(mlir::Location loc, mlir::Value src, mlir::Type newTy)
cir::FuncType getVoidFnTy(mlir::TypeRange argTypes={})
Returns void (T...) as a cir::FuncType.
mlir::TypedAttr getNullDataMemberAttr(cir::DataMemberType ty)
mlir::Value createBuiltinIntCast(mlir::Location loc, mlir::Value src, mlir::Type newTy)
clang::LangOptions::FPExceptionModeKind defaultConstrainedExcept
cir::CallOp createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget, cir::FuncType funcType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={}, llvm::ArrayRef< mlir::NamedAttrList > argAttrs={}, llvm::ArrayRef< mlir::NamedAttribute > resAttrs={}, cir::CallingConv callingConv=cir::CallingConv::C)
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
mlir::IntegerAttr getAlignmentAttr(clang::CharUnits alignment)
mlir::Value createNot(mlir::Location loc, mlir::Value value)
void setIsFPConstrained(bool isCon)
Enable/Disable use of constrained floating point math.
mlir::Value createMin(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createSelect(mlir::Location loc, mlir::Value condition, mlir::Value trueValue, mlir::Value falseValue)
cir::ContinueOp createContinue(mlir::Location loc)
Create a continue operation.
llvm::RoundingMode getDefaultConstrainedRounding() const
Get the rounding mode handling used with constrained floating point.
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
cir::PointerType getPointerTo(mlir::Type ty, mlir::ptr::MemorySpaceAttrInterface as)
mlir::FloatType getF32Type()=delete
mlir::TypedAttr getZeroInitAttr(mlir::Type ty)
mlir::Value createMinus(mlir::Location loc, mlir::Value input, bool nsw=false)
CIRBaseBuilderTy(mlir::OpBuilder &builder)
mlir::Value createPtrIsNotNull(mlir::Value ptr)
static unsigned getCIRIntOrFloatBitWidth(mlir::Type eltTy)
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, int64_t value)
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real, mlir::Value imag)
mlir::Value createBoolIntToIntCast(mlir::Value src, mlir::Type newTy)
mlir::Value createAddrSpaceCast(mlir::Value src, mlir::Type newTy)
mlir::Value createComplexConj(mlir::Location loc, mlir::Value operand)
mlir::Value createPtrToBoolCast(mlir::Value v)
cir::BoolAttr getTrueAttr()
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
mlir::Value createFRem(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs, unsigned bits)
mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand)
cir::IntType getSIntNTy(int n)
void setDefaultConstrainedExcept(clang::LangOptions::FPExceptionModeKind newExcept)
Set the exception handling to be used with constrained floating point.
mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr, uint64_t alignment)
bool getIsFPConstrained() const
Query for the use of constrained floating point math.
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value)
mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src, mlir::Type newTy)
cir::FastMathFlags fastMathFlags
mlir::Value createDummyValue(mlir::Location loc, mlir::Type type, clang::CharUnits alignment)
cir::BoolAttr getFalseAttr()
void setDefaultConstrainedRounding(llvm::RoundingMode newRounding)
Set the rounding mode handling to be used with constrained floating point.
mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::FloatType getBF16Type()=delete
mlir::Value createXor(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::FloatType getF128Type()=delete
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
cir::ConstantOp getAlignment(mlir::Location loc, mlir::Type t, clang::CharUnits alignment)
mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule, mlir::Location loc, mlir::StringRef name, mlir::Type type, bool isConstant, cir::GlobalLinkageKind linkage, mlir::ptr::MemorySpaceAttrInterface addrSpace)
void setFastMathFlags(cir::FastMathFlags flags)
Set the fast-math flags attached to floating-point operations.
mlir::IntegerAttr getAlignmentAttr(llvm::Align alignment)
mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
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::LoadOp createFlagLoad(mlir::Location loc, mlir::Value addr)
Emit a load from an boolean flag variable.
cir::BoolType getBoolTy()
mlir::Value createComplexAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value getUnsignedInt(mlir::Location loc, uint64_t val, unsigned numBits)
GetMethodResults createGetMethod(mlir::Location loc, mlir::Value method, mlir::Value objectPtr)
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand)
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
Definition CharUnits.h:155
FPExceptionModeKind
Possible floating point exception behavior.
@ FPE_Strict
Strictly preserve the floating-point exception semantics.
@ FPE_MayTrap
Transformations do not cause new exceptions but may hide some.
@ FPE_Ignore
Assume that floating-point exceptions are masked.
constexpr OverflowBehavior operator|(OverflowBehavior a, OverflowBehavior b)
constexpr OverflowBehavior operator&(OverflowBehavior a, OverflowBehavior b)
constexpr OverflowBehavior & operator|=(OverflowBehavior &a, OverflowBehavior b)
constexpr OverflowBehavior & operator&=(OverflowBehavior &a, OverflowBehavior b)
mlir::ptr::MemorySpaceAttrInterface toCIRAddressSpaceAttr(mlir::MLIRContext &ctx, clang::LangAS langAS)
Convert an AST LangAS to the appropriate CIR address space attribute interface.
OverflowBehavior
constexpr bool testFlag(OverflowBehavior ob, OverflowBehavior flag)
LangAS
Defines the address space values used by the address space qualifier of QualType.
__builtin_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 int64_t
static bool metaDataNode()
static bool addressSpace()
static bool targetCodeGenInfoGetNullPointer()
static bool fastMathFlags()