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