xref: /freebsd/contrib/llvm-project/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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"
13 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
14 #include "clang/CIR/Dialect/IR/CIRDialect.h"
15 #include "clang/CIR/Dialect/IR/CIRTypes.h"
16 #include "clang/CIR/MissingFeatures.h"
17 #include "llvm/ADT/STLForwardCompat.h"
18 #include "llvm/Support/ErrorHandling.h"
19 
20 #include "mlir/IR/Builders.h"
21 #include "mlir/IR/BuiltinAttributes.h"
22 #include "mlir/IR/BuiltinTypes.h"
23 #include "mlir/IR/Location.h"
24 #include "mlir/IR/Types.h"
25 
26 namespace cir {
27 
28 enum class OverflowBehavior {
29   None = 0,
30   NoSignedWrap = 1 << 0,
31   NoUnsignedWrap = 1 << 1,
32   Saturated = 1 << 2,
33 };
34 
35 constexpr OverflowBehavior operator|(OverflowBehavior a, OverflowBehavior b) {
36   return static_cast<OverflowBehavior>(llvm::to_underlying(a) |
37                                        llvm::to_underlying(b));
38 }
39 
40 constexpr OverflowBehavior operator&(OverflowBehavior a, OverflowBehavior b) {
41   return static_cast<OverflowBehavior>(llvm::to_underlying(a) &
42                                        llvm::to_underlying(b));
43 }
44 
45 constexpr OverflowBehavior &operator|=(OverflowBehavior &a,
46                                        OverflowBehavior b) {
47   a = a | b;
48   return a;
49 }
50 
51 constexpr OverflowBehavior &operator&=(OverflowBehavior &a,
52                                        OverflowBehavior b) {
53   a = a & b;
54   return a;
55 }
56 
57 class CIRBaseBuilderTy : public mlir::OpBuilder {
58 
59 public:
CIRBaseBuilderTy(mlir::MLIRContext & mlirContext)60   CIRBaseBuilderTy(mlir::MLIRContext &mlirContext)
61       : mlir::OpBuilder(&mlirContext) {}
CIRBaseBuilderTy(mlir::OpBuilder & builder)62   CIRBaseBuilderTy(mlir::OpBuilder &builder) : mlir::OpBuilder(builder) {}
63 
getConstAPInt(mlir::Location loc,mlir::Type typ,const llvm::APInt & val)64   mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
65                             const llvm::APInt &val) {
66     return create<cir::ConstantOp>(loc, cir::IntAttr::get(typ, val));
67   }
68 
getConstant(mlir::Location loc,mlir::TypedAttr attr)69   cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr) {
70     return create<cir::ConstantOp>(loc, attr);
71   }
72 
getConstantInt(mlir::Location loc,mlir::Type ty,int64_t value)73   cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty,
74                                  int64_t value) {
75     return getConstant(loc, cir::IntAttr::get(ty, value));
76   }
77 
78   // Creates constant null value for integral type ty.
getNullValue(mlir::Type ty,mlir::Location loc)79   cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) {
80     return getConstant(loc, getZeroInitAttr(ty));
81   }
82 
getConstNullPtrAttr(mlir::Type t)83   mlir::TypedAttr getConstNullPtrAttr(mlir::Type t) {
84     assert(mlir::isa<cir::PointerType>(t) && "expected cir.ptr");
85     return getConstPtrAttr(t, 0);
86   }
87 
getZeroInitAttr(mlir::Type ty)88   mlir::TypedAttr getZeroInitAttr(mlir::Type ty) {
89     if (mlir::isa<cir::IntType>(ty))
90       return cir::IntAttr::get(ty, 0);
91     if (cir::isAnyFloatingPointType(ty))
92       return cir::FPAttr::getZero(ty);
93     if (auto complexType = mlir::dyn_cast<cir::ComplexType>(ty))
94       return cir::ZeroAttr::get(complexType);
95     if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty))
96       return cir::ZeroAttr::get(arrTy);
97     if (auto vecTy = mlir::dyn_cast<cir::VectorType>(ty))
98       return cir::ZeroAttr::get(vecTy);
99     if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty))
100       return getConstNullPtrAttr(ptrTy);
101     if (auto recordTy = mlir::dyn_cast<cir::RecordType>(ty))
102       return cir::ZeroAttr::get(recordTy);
103     if (mlir::isa<cir::BoolType>(ty)) {
104       return getFalseAttr();
105     }
106     llvm_unreachable("Zero initializer for given type is NYI");
107   }
108 
getBool(bool state,mlir::Location loc)109   cir::ConstantOp getBool(bool state, mlir::Location loc) {
110     return create<cir::ConstantOp>(loc, getCIRBoolAttr(state));
111   }
getFalse(mlir::Location loc)112   cir::ConstantOp getFalse(mlir::Location loc) { return getBool(false, loc); }
getTrue(mlir::Location loc)113   cir::ConstantOp getTrue(mlir::Location loc) { return getBool(true, loc); }
114 
getBoolTy()115   cir::BoolType getBoolTy() { return cir::BoolType::get(getContext()); }
116 
getPointerTo(mlir::Type ty)117   cir::PointerType getPointerTo(mlir::Type ty) {
118     return cir::PointerType::get(ty);
119   }
120 
getVoidPtrTy()121   cir::PointerType getVoidPtrTy() {
122     return getPointerTo(cir::VoidType::get(getContext()));
123   }
124 
getCIRBoolAttr(bool state)125   cir::BoolAttr getCIRBoolAttr(bool state) {
126     return cir::BoolAttr::get(getContext(), state);
127   }
128 
getTrueAttr()129   cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }
getFalseAttr()130   cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }
131 
createNot(mlir::Value value)132   mlir::Value createNot(mlir::Value value) {
133     return create<cir::UnaryOp>(value.getLoc(), value.getType(),
134                                 cir::UnaryOpKind::Not, value);
135   }
136 
137   /// Create a do-while operation.
createDoWhile(mlir::Location loc,llvm::function_ref<void (mlir::OpBuilder &,mlir::Location)> condBuilder,llvm::function_ref<void (mlir::OpBuilder &,mlir::Location)> bodyBuilder)138   cir::DoWhileOp createDoWhile(
139       mlir::Location loc,
140       llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
141       llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
142     return create<cir::DoWhileOp>(loc, condBuilder, bodyBuilder);
143   }
144 
145   /// Create a while operation.
createWhile(mlir::Location loc,llvm::function_ref<void (mlir::OpBuilder &,mlir::Location)> condBuilder,llvm::function_ref<void (mlir::OpBuilder &,mlir::Location)> bodyBuilder)146   cir::WhileOp createWhile(
147       mlir::Location loc,
148       llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
149       llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
150     return create<cir::WhileOp>(loc, condBuilder, bodyBuilder);
151   }
152 
153   /// Create a for operation.
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)154   cir::ForOp createFor(
155       mlir::Location loc,
156       llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
157       llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder,
158       llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> stepBuilder) {
159     return create<cir::ForOp>(loc, condBuilder, bodyBuilder, stepBuilder);
160   }
161 
162   /// Create a break operation.
createBreak(mlir::Location loc)163   cir::BreakOp createBreak(mlir::Location loc) {
164     return create<cir::BreakOp>(loc);
165   }
166 
167   /// Create a continue operation.
createContinue(mlir::Location loc)168   cir::ContinueOp createContinue(mlir::Location loc) {
169     return create<cir::ContinueOp>(loc);
170   }
171 
getConstPtrAttr(mlir::Type type,int64_t value)172   mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
173     return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));
174   }
175 
createAlloca(mlir::Location loc,cir::PointerType addrType,mlir::Type type,llvm::StringRef name,mlir::IntegerAttr alignment)176   mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
177                            mlir::Type type, llvm::StringRef name,
178                            mlir::IntegerAttr alignment) {
179     return create<cir::AllocaOp>(loc, addrType, type, name, alignment);
180   }
181 
createGetGlobal(mlir::Location loc,cir::GlobalOp global)182   mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global) {
183     assert(!cir::MissingFeatures::addressSpace());
184     return create<cir::GetGlobalOp>(loc, getPointerTo(global.getSymType()),
185                                     global.getSymName());
186   }
187 
createGetGlobal(cir::GlobalOp global)188   mlir::Value createGetGlobal(cir::GlobalOp global) {
189     return createGetGlobal(global.getLoc(), global);
190   }
191 
192   cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst,
193                            mlir::IntegerAttr align = {}) {
194     return create<cir::StoreOp>(loc, val, dst, align);
195   }
196 
createGlobal(mlir::ModuleOp mlirModule,mlir::Location loc,mlir::StringRef name,mlir::Type type,cir::GlobalLinkageKind linkage)197   [[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule,
198                                            mlir::Location loc,
199                                            mlir::StringRef name,
200                                            mlir::Type type,
201                                            cir::GlobalLinkageKind linkage) {
202     mlir::OpBuilder::InsertionGuard guard(*this);
203     setInsertionPointToStart(mlirModule.getBody());
204     return create<cir::GlobalOp>(loc, name, type, linkage);
205   }
206 
createGetMember(mlir::Location loc,mlir::Type resultTy,mlir::Value base,llvm::StringRef name,unsigned index)207   cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy,
208                                    mlir::Value base, llvm::StringRef name,
209                                    unsigned index) {
210     return create<cir::GetMemberOp>(loc, resultTy, base, name, index);
211   }
212 
createDummyValue(mlir::Location loc,mlir::Type type,clang::CharUnits alignment)213   mlir::Value createDummyValue(mlir::Location loc, mlir::Type type,
214                                clang::CharUnits alignment) {
215     mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
216     auto addr = createAlloca(loc, getPointerTo(type), type, {}, alignmentAttr);
217     return create<cir::LoadOp>(loc, addr, /*isDeref=*/false, alignmentAttr);
218   }
219 
createPtrStride(mlir::Location loc,mlir::Value base,mlir::Value stride)220   cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base,
221                                    mlir::Value stride) {
222     return create<cir::PtrStrideOp>(loc, base.getType(), base, stride);
223   }
224 
225   //===--------------------------------------------------------------------===//
226   // Call operators
227   //===--------------------------------------------------------------------===//
228 
229   cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee,
230                            mlir::Type returnType, mlir::ValueRange operands,
231                            llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
232     auto op = create<cir::CallOp>(loc, callee, returnType, operands);
233     op->setAttrs(attrs);
234     return op;
235   }
236 
237   cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee,
238                            mlir::ValueRange operands,
239                            llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
240     return createCallOp(loc, mlir::SymbolRefAttr::get(callee),
241                         callee.getFunctionType().getReturnType(), operands,
242                         attrs);
243   }
244 
245   cir::CallOp
246   createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget,
247                        cir::FuncType funcType, mlir::ValueRange operands,
248                        llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
249     llvm::SmallVector<mlir::Value> resOperands{indirectTarget};
250     resOperands.append(operands.begin(), operands.end());
251     return createCallOp(loc, mlir::SymbolRefAttr(), funcType.getReturnType(),
252                         resOperands, attrs);
253   }
254 
255   //===--------------------------------------------------------------------===//
256   // Cast/Conversion Operators
257   //===--------------------------------------------------------------------===//
258 
createCast(mlir::Location loc,cir::CastKind kind,mlir::Value src,mlir::Type newTy)259   mlir::Value createCast(mlir::Location loc, cir::CastKind kind,
260                          mlir::Value src, mlir::Type newTy) {
261     if (newTy == src.getType())
262       return src;
263     return create<cir::CastOp>(loc, newTy, kind, src);
264   }
265 
createCast(cir::CastKind kind,mlir::Value src,mlir::Type newTy)266   mlir::Value createCast(cir::CastKind kind, mlir::Value src,
267                          mlir::Type newTy) {
268     if (newTy == src.getType())
269       return src;
270     return createCast(src.getLoc(), kind, src, newTy);
271   }
272 
createIntCast(mlir::Value src,mlir::Type newTy)273   mlir::Value createIntCast(mlir::Value src, mlir::Type newTy) {
274     return createCast(cir::CastKind::integral, src, newTy);
275   }
276 
createIntToPtr(mlir::Value src,mlir::Type newTy)277   mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy) {
278     return createCast(cir::CastKind::int_to_ptr, src, newTy);
279   }
280 
createPtrToInt(mlir::Value src,mlir::Type newTy)281   mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy) {
282     return createCast(cir::CastKind::ptr_to_int, src, newTy);
283   }
284 
createPtrToBoolCast(mlir::Value v)285   mlir::Value createPtrToBoolCast(mlir::Value v) {
286     return createCast(cir::CastKind::ptr_to_bool, v, getBoolTy());
287   }
288 
createBoolToInt(mlir::Value src,mlir::Type newTy)289   mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy) {
290     return createCast(cir::CastKind::bool_to_int, src, newTy);
291   }
292 
createBitcast(mlir::Value src,mlir::Type newTy)293   mlir::Value createBitcast(mlir::Value src, mlir::Type newTy) {
294     return createCast(cir::CastKind::bitcast, src, newTy);
295   }
296 
createBitcast(mlir::Location loc,mlir::Value src,mlir::Type newTy)297   mlir::Value createBitcast(mlir::Location loc, mlir::Value src,
298                             mlir::Type newTy) {
299     return createCast(loc, cir::CastKind::bitcast, src, newTy);
300   }
301 
createPtrBitcast(mlir::Value src,mlir::Type newPointeeTy)302   mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy) {
303     assert(mlir::isa<cir::PointerType>(src.getType()) && "expected ptr src");
304     return createBitcast(src, getPointerTo(newPointeeTy));
305   }
306 
307   //===--------------------------------------------------------------------===//
308   // Binary Operators
309   //===--------------------------------------------------------------------===//
310 
createBinop(mlir::Location loc,mlir::Value lhs,cir::BinOpKind kind,mlir::Value rhs)311   mlir::Value createBinop(mlir::Location loc, mlir::Value lhs,
312                           cir::BinOpKind kind, mlir::Value rhs) {
313     return create<cir::BinOp>(loc, lhs.getType(), kind, lhs, rhs);
314   }
315 
createLowBitsSet(mlir::Location loc,unsigned size,unsigned bits)316   mlir::Value createLowBitsSet(mlir::Location loc, unsigned size,
317                                unsigned bits) {
318     llvm::APInt val = llvm::APInt::getLowBitsSet(size, bits);
319     auto type = cir::IntType::get(getContext(), size, /*isSigned=*/false);
320     return getConstAPInt(loc, type, val);
321   }
322 
createAnd(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)323   mlir::Value createAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
324     return createBinop(loc, lhs, cir::BinOpKind::And, rhs);
325   }
326 
createOr(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)327   mlir::Value createOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
328     return createBinop(loc, lhs, cir::BinOpKind::Or, rhs);
329   }
330 
createSelect(mlir::Location loc,mlir::Value condition,mlir::Value trueValue,mlir::Value falseValue)331   mlir::Value createSelect(mlir::Location loc, mlir::Value condition,
332                            mlir::Value trueValue, mlir::Value falseValue) {
333     assert(trueValue.getType() == falseValue.getType() &&
334            "trueValue and falseValue should have the same type");
335     return create<cir::SelectOp>(loc, trueValue.getType(), condition, trueValue,
336                                  falseValue);
337   }
338 
createLogicalAnd(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)339   mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs,
340                                mlir::Value rhs) {
341     return createSelect(loc, lhs, rhs, getBool(false, loc));
342   }
343 
createLogicalOr(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)344   mlir::Value createLogicalOr(mlir::Location loc, mlir::Value lhs,
345                               mlir::Value rhs) {
346     return createSelect(loc, lhs, getBool(true, loc), rhs);
347   }
348 
349   mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
350                         OverflowBehavior ob = OverflowBehavior::None) {
351     auto op =
352         create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Mul, lhs, rhs);
353     op.setNoUnsignedWrap(
354         llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
355     op.setNoSignedWrap(
356         llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap));
357     return op;
358   }
createNSWMul(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)359   mlir::Value createNSWMul(mlir::Location loc, mlir::Value lhs,
360                            mlir::Value rhs) {
361     return createMul(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
362   }
createNUWAMul(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)363   mlir::Value createNUWAMul(mlir::Location loc, mlir::Value lhs,
364                             mlir::Value rhs) {
365     return createMul(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
366   }
367 
368   mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
369                         OverflowBehavior ob = OverflowBehavior::Saturated) {
370     auto op =
371         create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Sub, lhs, rhs);
372     op.setNoUnsignedWrap(
373         llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
374     op.setNoSignedWrap(
375         llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap));
376     op.setSaturated(llvm::to_underlying(ob & OverflowBehavior::Saturated));
377     return op;
378   }
379 
createNSWSub(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)380   mlir::Value createNSWSub(mlir::Location loc, mlir::Value lhs,
381                            mlir::Value rhs) {
382     return createSub(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
383   }
384 
createNUWSub(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)385   mlir::Value createNUWSub(mlir::Location loc, mlir::Value lhs,
386                            mlir::Value rhs) {
387     return createSub(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
388   }
389 
390   mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
391                         OverflowBehavior ob = OverflowBehavior::None) {
392     auto op =
393         create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Add, lhs, rhs);
394     op.setNoUnsignedWrap(
395         llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
396     op.setNoSignedWrap(
397         llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap));
398     op.setSaturated(llvm::to_underlying(ob & OverflowBehavior::Saturated));
399     return op;
400   }
401 
createNSWAdd(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)402   mlir::Value createNSWAdd(mlir::Location loc, mlir::Value lhs,
403                            mlir::Value rhs) {
404     return createAdd(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
405   }
406 
createNUWAdd(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)407   mlir::Value createNUWAdd(mlir::Location loc, mlir::Value lhs,
408                            mlir::Value rhs) {
409     return createAdd(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
410   }
411 
createCompare(mlir::Location loc,cir::CmpOpKind kind,mlir::Value lhs,mlir::Value rhs)412   cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind,
413                            mlir::Value lhs, mlir::Value rhs) {
414     return create<cir::CmpOp>(loc, getBoolTy(), kind, lhs, rhs);
415   }
416 
createShift(mlir::Location loc,mlir::Value lhs,mlir::Value rhs,bool isShiftLeft)417   mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
418                           bool isShiftLeft) {
419     return create<cir::ShiftOp>(loc, lhs.getType(), lhs, rhs, isShiftLeft);
420   }
421 
createShift(mlir::Location loc,mlir::Value lhs,const llvm::APInt & rhs,bool isShiftLeft)422   mlir::Value createShift(mlir::Location loc, mlir::Value lhs,
423                           const llvm::APInt &rhs, bool isShiftLeft) {
424     return createShift(loc, lhs, getConstAPInt(loc, lhs.getType(), rhs),
425                        isShiftLeft);
426   }
427 
createShift(mlir::Location loc,mlir::Value lhs,unsigned bits,bool isShiftLeft)428   mlir::Value createShift(mlir::Location loc, mlir::Value lhs, unsigned bits,
429                           bool isShiftLeft) {
430     auto width = mlir::dyn_cast<cir::IntType>(lhs.getType()).getWidth();
431     auto shift = llvm::APInt(width, bits);
432     return createShift(loc, lhs, shift, isShiftLeft);
433   }
434 
createShiftLeft(mlir::Location loc,mlir::Value lhs,unsigned bits)435   mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs,
436                               unsigned bits) {
437     return createShift(loc, lhs, bits, true);
438   }
439 
createShiftRight(mlir::Location loc,mlir::Value lhs,unsigned bits)440   mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs,
441                                unsigned bits) {
442     return createShift(loc, lhs, bits, false);
443   }
444 
createShiftLeft(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)445   mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs,
446                               mlir::Value rhs) {
447     return createShift(loc, lhs, rhs, true);
448   }
449 
createShiftRight(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)450   mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs,
451                                mlir::Value rhs) {
452     return createShift(loc, lhs, rhs, false);
453   }
454 
455   //
456   // Block handling helpers
457   // ----------------------
458   //
getBestAllocaInsertPoint(mlir::Block * block)459   static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block) {
460     auto last =
461         std::find_if(block->rbegin(), block->rend(), [](mlir::Operation &op) {
462           // TODO: Add LabelOp missing feature here
463           return mlir::isa<cir::AllocaOp>(&op);
464         });
465 
466     if (last != block->rend())
467       return OpBuilder::InsertPoint(block, ++mlir::Block::iterator(&*last));
468     return OpBuilder::InsertPoint(block, block->begin());
469   };
470 
471   //
472   // Alignment and size helpers
473   //
474 
475   // Note that mlir::IntegerType is used instead of cir::IntType here because we
476   // don't need sign information for these to be useful, so keep it simple.
477 
478   // For 0 alignment, any overload of `getAlignmentAttr` returns an empty
479   // attribute.
getAlignmentAttr(clang::CharUnits alignment)480   mlir::IntegerAttr getAlignmentAttr(clang::CharUnits alignment) {
481     return getAlignmentAttr(alignment.getQuantity());
482   }
483 
getAlignmentAttr(llvm::Align alignment)484   mlir::IntegerAttr getAlignmentAttr(llvm::Align alignment) {
485     return getAlignmentAttr(alignment.value());
486   }
487 
getAlignmentAttr(int64_t alignment)488   mlir::IntegerAttr getAlignmentAttr(int64_t alignment) {
489     return alignment ? getI64IntegerAttr(alignment) : mlir::IntegerAttr();
490   }
491 
getSizeFromCharUnits(clang::CharUnits size)492   mlir::IntegerAttr getSizeFromCharUnits(clang::CharUnits size) {
493     return getI64IntegerAttr(size.getQuantity());
494   }
495 
496   /// Create a loop condition.
createCondition(mlir::Value condition)497   cir::ConditionOp createCondition(mlir::Value condition) {
498     return create<cir::ConditionOp>(condition.getLoc(), condition);
499   }
500 
501   /// Create a yield operation.
502   cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) {
503     return create<cir::YieldOp>(loc, value);
504   }
505 };
506 
507 } // namespace cir
508 
509 #endif
510