//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H #define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H #include "clang/AST/CharUnits.h" #include "clang/Basic/AddressSpaces.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/Support/ErrorHandling.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Location.h" #include "mlir/IR/Types.h" namespace cir { enum class OverflowBehavior { None = 0, NoSignedWrap = 1 << 0, NoUnsignedWrap = 1 << 1, Saturated = 1 << 2, }; constexpr OverflowBehavior operator|(OverflowBehavior a, OverflowBehavior b) { return static_cast(llvm::to_underlying(a) | llvm::to_underlying(b)); } constexpr OverflowBehavior operator&(OverflowBehavior a, OverflowBehavior b) { return static_cast(llvm::to_underlying(a) & llvm::to_underlying(b)); } constexpr OverflowBehavior &operator|=(OverflowBehavior &a, OverflowBehavior b) { a = a | b; return a; } constexpr OverflowBehavior &operator&=(OverflowBehavior &a, OverflowBehavior b) { a = a & b; return a; } class CIRBaseBuilderTy : public mlir::OpBuilder { public: CIRBaseBuilderTy(mlir::MLIRContext &mlirContext) : mlir::OpBuilder(&mlirContext) {} CIRBaseBuilderTy(mlir::OpBuilder &builder) : mlir::OpBuilder(builder) {} mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ, const llvm::APInt &val) { return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(typ, val)); } cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr) { return cir::ConstantOp::create(*this, loc, attr); } cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, int64_t value) { return getConstant(loc, cir::IntAttr::get(ty, value)); } mlir::Value getSignedInt(mlir::Location loc, int64_t val, unsigned numBits) { auto type = cir::IntType::get(getContext(), numBits, /*isSigned=*/true); return getConstAPInt(loc, type, llvm::APInt(numBits, val, /*isSigned=*/true)); } mlir::Value getUnsignedInt(mlir::Location loc, uint64_t val, unsigned numBits) { auto type = cir::IntType::get(getContext(), numBits, /*isSigned=*/false); return getConstAPInt(loc, type, llvm::APInt(numBits, val)); } // Creates constant null value for integral type ty. cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) { return getConstant(loc, getZeroInitAttr(ty)); } mlir::TypedAttr getConstNullPtrAttr(mlir::Type t) { assert(mlir::isa(t) && "expected cir.ptr"); return getConstPtrAttr(t, 0); } mlir::TypedAttr getNullDataMemberAttr(cir::DataMemberType ty) { return cir::DataMemberAttr::get(ty); } mlir::TypedAttr getZeroInitAttr(mlir::Type ty) { if (mlir::isa(ty)) return cir::IntAttr::get(ty, 0); if (cir::isAnyFloatingPointType(ty)) return cir::FPAttr::getZero(ty); if (auto complexType = mlir::dyn_cast(ty)) return cir::ZeroAttr::get(complexType); if (auto arrTy = mlir::dyn_cast(ty)) return cir::ZeroAttr::get(arrTy); if (auto vecTy = mlir::dyn_cast(ty)) return cir::ZeroAttr::get(vecTy); if (auto ptrTy = mlir::dyn_cast(ty)) return getConstNullPtrAttr(ptrTy); if (auto recordTy = mlir::dyn_cast(ty)) return cir::ZeroAttr::get(recordTy); if (auto dataMemberTy = mlir::dyn_cast(ty)) return getNullDataMemberAttr(dataMemberTy); if (mlir::isa(ty)) { return getFalseAttr(); } llvm_unreachable("Zero initializer for given type is NYI"); } cir::ConstantOp getBool(bool state, mlir::Location loc) { return cir::ConstantOp::create(*this, loc, getCIRBoolAttr(state)); } cir::ConstantOp getFalse(mlir::Location loc) { return getBool(false, loc); } cir::ConstantOp getTrue(mlir::Location loc) { return getBool(true, loc); } cir::BoolType getBoolTy() { return cir::BoolType::get(getContext()); } cir::VoidType getVoidTy() { return cir::VoidType::get(getContext()); } cir::IntType getUIntNTy(int n) { return cir::IntType::get(getContext(), n, false); } static unsigned getCIRIntOrFloatBitWidth(mlir::Type eltTy) { if (auto intType = mlir::dyn_cast(eltTy)) return intType.getWidth(); if (auto floatType = mlir::dyn_cast(eltTy)) return floatType.getWidth(); llvm_unreachable("Unsupported type in getCIRIntOrFloatBitWidth"); } cir::IntType getSIntNTy(int n) { return cir::IntType::get(getContext(), n, true); } cir::PointerType getPointerTo(mlir::Type ty) { return cir::PointerType::get(ty); } cir::PointerType getPointerTo(mlir::Type ty, cir::TargetAddressSpaceAttr as) { return cir::PointerType::get(ty, as); } cir::PointerType getPointerTo(mlir::Type ty, clang::LangAS langAS) { if (langAS == clang::LangAS::Default) // Default address space. return getPointerTo(ty); if (clang::isTargetAddressSpace(langAS)) { unsigned addrSpace = clang::toTargetAddressSpace(langAS); auto asAttr = cir::TargetAddressSpaceAttr::get( getContext(), getUI32IntegerAttr(addrSpace)); return getPointerTo(ty, asAttr); } llvm_unreachable("language-specific address spaces NYI"); } cir::PointerType getVoidPtrTy(clang::LangAS langAS = clang::LangAS::Default) { return getPointerTo(cir::VoidType::get(getContext()), langAS); } cir::PointerType getVoidPtrTy(cir::TargetAddressSpaceAttr as) { return getPointerTo(cir::VoidType::get(getContext()), as); } cir::BoolAttr getCIRBoolAttr(bool state) { return cir::BoolAttr::get(getContext(), state); } cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); } cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); } mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real, mlir::Value imag) { auto resultComplexTy = cir::ComplexType::get(real.getType()); return cir::ComplexCreateOp::create(*this, loc, resultComplexTy, real, imag); } mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) { auto resultType = operand.getType(); if (auto complexResultType = mlir::dyn_cast(resultType)) resultType = complexResultType.getElementType(); return cir::ComplexRealOp::create(*this, loc, resultType, operand); } mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) { auto resultType = operand.getType(); if (auto complexResultType = mlir::dyn_cast(resultType)) resultType = complexResultType.getElementType(); return cir::ComplexImagOp::create(*this, loc, resultType, operand); } cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr, bool isVolatile = false, uint64_t alignment = 0) { mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment); return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false, isVolatile, alignmentAttr, cir::SyncScopeKindAttr{}, cir::MemOrderAttr{}); } mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr, uint64_t alignment) { return createLoad(loc, ptr, /*isVolatile=*/false, alignment); } mlir::Value createNot(mlir::Value value) { return cir::UnaryOp::create(*this, value.getLoc(), value.getType(), cir::UnaryOpKind::Not, value); } /// Create a do-while operation. cir::DoWhileOp createDoWhile( mlir::Location loc, llvm::function_ref condBuilder, llvm::function_ref bodyBuilder) { return cir::DoWhileOp::create(*this, loc, condBuilder, bodyBuilder); } /// Create a while operation. cir::WhileOp createWhile( mlir::Location loc, llvm::function_ref condBuilder, llvm::function_ref bodyBuilder) { return cir::WhileOp::create(*this, loc, condBuilder, bodyBuilder); } /// Create a for operation. cir::ForOp createFor( mlir::Location loc, llvm::function_ref condBuilder, llvm::function_ref bodyBuilder, llvm::function_ref stepBuilder) { return cir::ForOp::create(*this, loc, condBuilder, bodyBuilder, stepBuilder); } /// Create a break operation. cir::BreakOp createBreak(mlir::Location loc) { return cir::BreakOp::create(*this, loc); } /// Create a continue operation. cir::ContinueOp createContinue(mlir::Location loc) { return cir::ContinueOp::create(*this, loc); } mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind, mlir::Value operand) { return cir::UnaryOp::create(*this, loc, kind, operand); } mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) { return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value)); } mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, mlir::Type type, llvm::StringRef name, mlir::IntegerAttr alignment, mlir::Value dynAllocSize) { return cir::AllocaOp::create(*this, loc, addrType, type, name, alignment, dynAllocSize); } mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, mlir::Type type, llvm::StringRef name, clang::CharUnits alignment, mlir::Value dynAllocSize) { mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment); return createAlloca(loc, addrType, type, name, alignmentAttr, dynAllocSize); } mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, mlir::Type type, llvm::StringRef name, mlir::IntegerAttr alignment) { return cir::AllocaOp::create(*this, loc, addrType, type, name, alignment); } mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, mlir::Type type, llvm::StringRef name, clang::CharUnits alignment) { mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment); return createAlloca(loc, addrType, type, name, alignmentAttr); } /// Get constant address of a global variable as an MLIR attribute. /// This wrapper infers the attribute type through the global op. cir::GlobalViewAttr getGlobalViewAttr(cir::GlobalOp globalOp, mlir::ArrayAttr indices = {}) { cir::PointerType type = getPointerTo(globalOp.getSymType()); return getGlobalViewAttr(type, globalOp, indices); } /// Get constant address of a global variable as an MLIR attribute. cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type, cir::GlobalOp globalOp, mlir::ArrayAttr indices = {}) { auto symbol = mlir::FlatSymbolRefAttr::get(globalOp.getSymNameAttr()); return cir::GlobalViewAttr::get(type, symbol, indices); } mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global, bool threadLocal = false) { assert(!cir::MissingFeatures::addressSpace()); return cir::GetGlobalOp::create(*this, loc, getPointerTo(global.getSymType()), global.getSymNameAttr(), threadLocal); } mlir::Value createGetGlobal(cir::GlobalOp global, bool threadLocal = false) { return createGetGlobal(global.getLoc(), global, threadLocal); } /// Create a copy with inferred length. cir::CopyOp createCopy(mlir::Value dst, mlir::Value src, bool isVolatile = false) { return cir::CopyOp::create(*this, dst.getLoc(), dst, src, isVolatile); } cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst, bool isVolatile = false, mlir::IntegerAttr align = {}, cir::SyncScopeKindAttr scope = {}, cir::MemOrderAttr order = {}) { return cir::StoreOp::create(*this, loc, val, dst, isVolatile, align, scope, order); } /// Emit a load from an boolean flag variable. cir::LoadOp createFlagLoad(mlir::Location loc, mlir::Value addr) { mlir::Type boolTy = getBoolTy(); if (boolTy != mlir::cast(addr.getType()).getPointee()) addr = createPtrBitcast(addr, boolTy); return createLoad(loc, addr, /*isVolatile=*/false, /*alignment=*/1); } cir::StoreOp createFlagStore(mlir::Location loc, bool val, mlir::Value dst) { mlir::Value flag = getBool(val, loc); return CIRBaseBuilderTy::createStore(loc, flag, dst); } [[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule, mlir::Location loc, mlir::StringRef name, mlir::Type type, bool isConstant, cir::GlobalLinkageKind linkage) { mlir::OpBuilder::InsertionGuard guard(*this); setInsertionPointToStart(mlirModule.getBody()); return cir::GlobalOp::create(*this, loc, name, type, isConstant, linkage); } cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy, mlir::Value base, llvm::StringRef name, unsigned index) { return cir::GetMemberOp::create(*this, loc, resultTy, base, name, index); } mlir::Value createDummyValue(mlir::Location loc, mlir::Type type, clang::CharUnits alignment) { mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment); auto addr = createAlloca(loc, getPointerTo(type), type, {}, alignmentAttr); return cir::LoadOp::create(*this, loc, addr, /*isDeref=*/false, /*isVolatile=*/false, alignmentAttr, /*sync_scope=*/{}, /*mem_order=*/{}); } cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base, mlir::Value stride) { return cir::PtrStrideOp::create(*this, loc, base.getType(), base, stride); } //===--------------------------------------------------------------------===// // Call operators //===--------------------------------------------------------------------===// cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef attrs = {}) { auto op = cir::CallOp::create(*this, loc, callee, returnType, operands); op->setAttrs(attrs); return op; } cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands, llvm::ArrayRef attrs = {}) { return createCallOp(loc, mlir::SymbolRefAttr::get(callee), callee.getFunctionType().getReturnType(), operands, attrs); } cir::CallOp createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget, cir::FuncType funcType, mlir::ValueRange operands, llvm::ArrayRef attrs = {}) { llvm::SmallVector resOperands{indirectTarget}; resOperands.append(operands.begin(), operands.end()); return createCallOp(loc, mlir::SymbolRefAttr(), funcType.getReturnType(), resOperands, attrs); } cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::ValueRange operands = mlir::ValueRange(), llvm::ArrayRef attrs = {}) { return createCallOp(loc, callee, cir::VoidType(), operands, attrs); } //===--------------------------------------------------------------------===// // Cast/Conversion Operators //===--------------------------------------------------------------------===// mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy) { if (newTy == src.getType()) return src; return cir::CastOp::create(*this, loc, newTy, kind, src); } mlir::Value createCast(cir::CastKind kind, mlir::Value src, mlir::Type newTy) { if (newTy == src.getType()) return src; return createCast(src.getLoc(), kind, src, newTy); } mlir::Value createIntCast(mlir::Value src, mlir::Type newTy) { return createCast(cir::CastKind::integral, src, newTy); } mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy) { return createCast(cir::CastKind::int_to_ptr, src, newTy); } mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy) { return createCast(cir::CastKind::ptr_to_int, src, newTy); } mlir::Value createPtrToBoolCast(mlir::Value v) { return createCast(cir::CastKind::ptr_to_bool, v, getBoolTy()); } mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy) { return createCast(cir::CastKind::bool_to_int, src, newTy); } mlir::Value createBitcast(mlir::Value src, mlir::Type newTy) { return createCast(cir::CastKind::bitcast, src, newTy); } mlir::Value createBitcast(mlir::Location loc, mlir::Value src, mlir::Type newTy) { return createCast(loc, cir::CastKind::bitcast, src, newTy); } mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy) { assert(mlir::isa(src.getType()) && "expected ptr src"); return createBitcast(src, getPointerTo(newPointeeTy)); } mlir::Value createPtrIsNull(mlir::Value ptr) { mlir::Value nullPtr = getNullPtr(ptr.getType(), ptr.getLoc()); return createCompare(ptr.getLoc(), cir::CmpOpKind::eq, ptr, nullPtr); } mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src, mlir::Type newTy) { return createCast(loc, cir::CastKind::address_space, src, newTy); } mlir::Value createAddrSpaceCast(mlir::Value src, mlir::Type newTy) { return createAddrSpaceCast(src.getLoc(), src, newTy); } //===--------------------------------------------------------------------===// // Binary Operators //===--------------------------------------------------------------------===// mlir::Value createBinop(mlir::Location loc, mlir::Value lhs, cir::BinOpKind kind, mlir::Value rhs) { return cir::BinOp::create(*this, loc, lhs.getType(), kind, lhs, rhs); } mlir::Value createLowBitsSet(mlir::Location loc, unsigned size, unsigned bits) { llvm::APInt val = llvm::APInt::getLowBitsSet(size, bits); auto type = cir::IntType::get(getContext(), size, /*isSigned=*/false); return getConstAPInt(loc, type, val); } mlir::Value createAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createBinop(loc, lhs, cir::BinOpKind::And, rhs); } mlir::Value createOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createBinop(loc, lhs, cir::BinOpKind::Or, rhs); } mlir::Value createSelect(mlir::Location loc, mlir::Value condition, mlir::Value trueValue, mlir::Value falseValue) { assert(trueValue.getType() == falseValue.getType() && "trueValue and falseValue should have the same type"); return cir::SelectOp::create(*this, loc, trueValue.getType(), condition, trueValue, falseValue); } mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createSelect(loc, lhs, rhs, getBool(false, loc)); } mlir::Value createLogicalOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createSelect(loc, lhs, getBool(true, loc), rhs); } mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob = OverflowBehavior::None) { auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Mul, lhs, rhs); op.setNoUnsignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap)); op.setNoSignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap)); return op; } mlir::Value createNSWMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createMul(loc, lhs, rhs, OverflowBehavior::NoSignedWrap); } mlir::Value createNUWAMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createMul(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap); } mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob = OverflowBehavior::Saturated) { auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Sub, lhs, rhs); op.setNoUnsignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap)); op.setNoSignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap)); op.setSaturated(llvm::to_underlying(ob & OverflowBehavior::Saturated)); return op; } mlir::Value createNSWSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createSub(loc, lhs, rhs, OverflowBehavior::NoSignedWrap); } mlir::Value createNUWSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createSub(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap); } mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob = OverflowBehavior::None) { auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Add, lhs, rhs); op.setNoUnsignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap)); op.setNoSignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap)); op.setSaturated(llvm::to_underlying(ob & OverflowBehavior::Saturated)); return op; } mlir::Value createNSWAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createAdd(loc, lhs, rhs, OverflowBehavior::NoSignedWrap); } mlir::Value createNUWAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createAdd(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap); } cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs) { return cir::CmpOp::create(*this, loc, kind, lhs, rhs); } cir::VecCmpOp createVecCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs) { VectorType vecCast = mlir::cast(lhs.getType()); IntType integralTy = getSIntNTy(getCIRIntOrFloatBitWidth(vecCast.getElementType())); VectorType integralVecTy = cir::VectorType::get(integralTy, vecCast.getSize()); return cir::VecCmpOp::create(*this, loc, integralVecTy, kind, lhs, rhs); } mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) { return createCompare(loc, cir::CmpOpKind::ne, operand, operand); } mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, bool isShiftLeft) { return cir::ShiftOp::create(*this, loc, lhs.getType(), lhs, rhs, isShiftLeft); } mlir::Value createShift(mlir::Location loc, mlir::Value lhs, const llvm::APInt &rhs, bool isShiftLeft) { return createShift(loc, lhs, getConstAPInt(loc, lhs.getType(), rhs), isShiftLeft); } mlir::Value createShift(mlir::Location loc, mlir::Value lhs, unsigned bits, bool isShiftLeft) { auto width = mlir::dyn_cast(lhs.getType()).getWidth(); auto shift = llvm::APInt(width, bits); return createShift(loc, lhs, shift, isShiftLeft); } mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs, unsigned bits) { return createShift(loc, lhs, bits, true); } mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs, unsigned bits) { return createShift(loc, lhs, bits, false); } mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createShift(loc, lhs, rhs, true); } mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { return createShift(loc, lhs, rhs, false); } // // Block handling helpers // ---------------------- // static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block) { auto last = std::find_if(block->rbegin(), block->rend(), [](mlir::Operation &op) { return mlir::isa(&op); }); if (last != block->rend()) return OpBuilder::InsertPoint(block, ++mlir::Block::iterator(&*last)); return OpBuilder::InsertPoint(block, block->begin()); }; // // Alignment and size helpers // // Note that mlir::IntegerType is used instead of cir::IntType here because we // don't need sign information for these to be useful, so keep it simple. // For 0 alignment, any overload of `getAlignmentAttr` returns an empty // attribute. mlir::IntegerAttr getAlignmentAttr(clang::CharUnits alignment) { return getAlignmentAttr(alignment.getQuantity()); } mlir::IntegerAttr getAlignmentAttr(llvm::Align alignment) { return getAlignmentAttr(alignment.value()); } mlir::IntegerAttr getAlignmentAttr(int64_t alignment) { return alignment ? getI64IntegerAttr(alignment) : mlir::IntegerAttr(); } mlir::IntegerAttr getSizeFromCharUnits(clang::CharUnits size) { return getI64IntegerAttr(size.getQuantity()); } // Creates constant nullptr for pointer type ty. cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) { assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer()); return cir::ConstantOp::create(*this, loc, getConstPtrAttr(ty, 0)); } /// Create a loop condition. cir::ConditionOp createCondition(mlir::Value condition) { return cir::ConditionOp::create(*this, condition.getLoc(), condition); } /// Create a yield operation. cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) { return cir::YieldOp::create(*this, loc, value); } }; } // namespace cir #endif