aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/Lowering
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/Lowering')
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt5
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp494
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h2
3 files changed, 471 insertions, 30 deletions
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt
index 7baff34..2525e02 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt
@@ -18,7 +18,12 @@ add_clang_library(clangCIRLoweringDirectToLLVM
clangCIRLoweringCommon
${dialect_libs}
MLIRCIR
+ MLIRCIRTargetLowering
MLIRBuiltinToLLVMIRTranslation
MLIRLLVMToLLVMIRTranslation
MLIRIR
)
+
+target_include_directories(clangCIRLoweringDirectToLLVM PRIVATE
+ ${CLANG_SOURCE_DIR}/lib/CIR/Dialect/Transforms/TargetLowering
+ )
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 5a6193f..0ad3360 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -186,6 +186,14 @@ mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMSqrtOpLowering::matchAndRewrite(
+ cir::SqrtOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type resTy = typeConverter->convertType(op.getType());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::SqrtOp>(op, resTy, adaptor.getSrc());
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMCosOpLowering::matchAndRewrite(
cir::CosOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -194,6 +202,31 @@ mlir::LogicalResult CIRToLLVMCosOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMExpOpLowering::matchAndRewrite(
+ cir::ExpOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type resTy = typeConverter->convertType(op.getType());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ExpOp>(op, resTy, adaptor.getSrc());
+ return mlir::success();
+}
+
+mlir::LogicalResult CIRToLLVMExp2OpLowering::matchAndRewrite(
+ cir::Exp2Op op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type resTy = typeConverter->convertType(op.getType());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::Exp2Op>(op, resTy, adaptor.getSrc());
+ return mlir::success();
+}
+
+mlir::LogicalResult CIRToLLVMFloorOpLowering::matchAndRewrite(
+ cir::FloorOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type resTy = typeConverter->convertType(op.getType());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::FFloorOp>(op, resTy,
+ adaptor.getSrc());
+ return mlir::success();
+}
+
static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter,
mlir::Value llvmSrc, mlir::Type llvmDstIntTy,
bool isUnsigned, uint64_t cirSrcWidth,
@@ -224,7 +257,7 @@ public:
.Case<cir::IntAttr, cir::FPAttr, cir::ConstComplexAttr,
cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,
cir::ConstPtrAttr, cir::GlobalViewAttr, cir::TypeInfoAttr,
- cir::VTableAttr, cir::ZeroAttr>(
+ cir::UndefAttr, cir::VTableAttr, cir::ZeroAttr>(
[&](auto attrT) { return visitCirAttr(attrT); })
.Default([&](auto attrT) { return mlir::Value(); });
}
@@ -238,6 +271,7 @@ public:
mlir::Value visitCirAttr(cir::ConstVectorAttr attr);
mlir::Value visitCirAttr(cir::GlobalViewAttr attr);
mlir::Value visitCirAttr(cir::TypeInfoAttr attr);
+ mlir::Value visitCirAttr(cir::UndefAttr attr);
mlir::Value visitCirAttr(cir::VTableAttr attr);
mlir::Value visitCirAttr(cir::ZeroAttr attr);
@@ -276,7 +310,10 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(
callOp->getContext(), /*other=*/ModRefInfo::Ref,
/*argMem=*/ModRefInfo::Ref,
- /*inaccessibleMem=*/ModRefInfo::Ref);
+ /*inaccessibleMem=*/ModRefInfo::Ref,
+ /*errnoMem=*/ModRefInfo::Ref,
+ /*targetMem0=*/ModRefInfo::Ref,
+ /*targetMem1=*/ModRefInfo::Ref);
noUnwind = true;
willReturn = true;
break;
@@ -285,7 +322,10 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(
callOp->getContext(), /*other=*/ModRefInfo::NoModRef,
/*argMem=*/ModRefInfo::NoModRef,
- /*inaccessibleMem=*/ModRefInfo::NoModRef);
+ /*inaccessibleMem=*/ModRefInfo::NoModRef,
+ /*errnoMem=*/ModRefInfo::NoModRef,
+ /*targetMem0=*/ModRefInfo::NoModRef,
+ /*targetMem1=*/ModRefInfo::NoModRef);
noUnwind = true;
willReturn = true;
break;
@@ -312,6 +352,30 @@ static mlir::LLVM::CallIntrinsicOp replaceOpWithCallLLVMIntrinsicOp(
return callIntrinOp;
}
+mlir::LogicalResult CIRToLLVMLLVMIntrinsicCallOpLowering::matchAndRewrite(
+ cir::LLVMIntrinsicCallOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type llvmResTy =
+ getTypeConverter()->convertType(op->getResultTypes()[0]);
+ if (!llvmResTy)
+ return op.emitError("expected LLVM result type");
+ StringRef name = op.getIntrinsicName();
+
+ // Some LLVM intrinsics require ElementType attribute to be attached to
+ // the argument of pointer type. That prevents us from generating LLVM IR
+ // because from LLVM dialect, we have LLVM IR like the below which fails
+ // LLVM IR verification.
+ // %3 = call i64 @llvm.aarch64.ldxr.p0(ptr %2)
+ // The expected LLVM IR should be like
+ // %3 = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %2)
+ // TODO(cir): MLIR LLVM dialect should handle this part as CIR has no way
+ // to set LLVM IR attribute.
+ assert(!cir::MissingFeatures::intrinsicElementTypeSupport());
+ replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm." + name, llvmResTy,
+ adaptor.getOperands());
+ return mlir::success();
+}
+
/// IntAttr visitor.
mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) {
mlir::Location loc = parentOp->getLoc();
@@ -545,6 +609,13 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeInfoAttr) {
return result;
}
+/// UndefAttr visitor.
+mlir::Value CIRAttrToValue::visitCirAttr(cir::UndefAttr undefAttr) {
+ mlir::Location loc = parentOp->getLoc();
+ return mlir::LLVM::UndefOp::create(
+ rewriter, loc, converter->convertType(undefAttr.getType()));
+}
+
// VTableAttr visitor.
mlir::Value CIRAttrToValue::visitCirAttr(cir::VTableAttr vtableArr) {
mlir::Type llvmTy = converter->convertType(vtableArr.getType());
@@ -638,6 +709,18 @@ mlir::LogicalResult CIRToLLVMASinOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMIsFPClassOpLowering::matchAndRewrite(
+ cir::IsFPClassOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Value src = adaptor.getSrc();
+ cir::FPClassTest flags = adaptor.getFlags();
+ mlir::IntegerType retTy = rewriter.getI1Type();
+
+ rewriter.replaceOpWithNewOp<mlir::LLVM::IsFPClass>(
+ op, retTy, src, static_cast<uint32_t>(flags));
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
cir::AssumeOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -700,6 +783,15 @@ getLLVMMemOrder(std::optional<cir::MemOrder> memorder) {
llvm_unreachable("unknown memory order");
}
+static std::optional<llvm::StringRef>
+getLLVMSyncScope(std::optional<cir::SyncScopeKind> syncScope) {
+ if (syncScope.has_value())
+ return syncScope.value() == cir::SyncScopeKind::SingleThread
+ ? "singlethread"
+ : "";
+ return std::nullopt;
+}
+
mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite(
cir::AtomicCmpXchgOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -776,6 +868,19 @@ mlir::LogicalResult CIRToLLVMAtomicClearOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMAtomicFenceLowering::matchAndRewrite(
+ cir::AtomicFence op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(adaptor.getOrdering());
+
+ auto fence = mlir::LLVM::FenceOp::create(rewriter, op.getLoc(), llvmOrder);
+ fence.setSyncscope(getLLVMSyncScope(adaptor.getSyncscope()));
+
+ rewriter.replaceOp(op, fence);
+
+ return mlir::success();
+}
+
static mlir::LLVM::AtomicBinOp
getLLVMAtomicBinOp(cir::AtomicFetchKind k, bool isInt, bool isSignedInt) {
switch (k) {
@@ -1328,6 +1433,41 @@ mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMDerivedClassAddrOpLowering::matchAndRewrite(
+ cir::DerivedClassAddrOp derivedClassOp, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ const mlir::Type resultType =
+ getTypeConverter()->convertType(derivedClassOp.getType());
+ mlir::Value baseAddr = adaptor.getBaseAddr();
+ // The offset is set in the operation as an unsigned value, but it must be
+ // applied as a negative offset.
+ int64_t offsetVal = -(adaptor.getOffset().getZExtValue());
+ if (offsetVal == 0) {
+ // If the offset is zero, we can just return the base address,
+ rewriter.replaceOp(derivedClassOp, baseAddr);
+ return mlir::success();
+ }
+ llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = {offsetVal};
+ mlir::Type byteType = mlir::IntegerType::get(resultType.getContext(), 8,
+ mlir::IntegerType::Signless);
+ if (derivedClassOp.getAssumeNotNull()) {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
+ derivedClassOp, resultType, byteType, baseAddr, offset,
+ mlir::LLVM::GEPNoWrapFlags::inbounds);
+ } else {
+ mlir::Location loc = derivedClassOp.getLoc();
+ mlir::Value isNull = mlir::LLVM::ICmpOp::create(
+ rewriter, loc, mlir::LLVM::ICmpPredicate::eq, baseAddr,
+ mlir::LLVM::ZeroOp::create(rewriter, loc, baseAddr.getType()));
+ mlir::Value adjusted =
+ mlir::LLVM::GEPOp::create(rewriter, loc, resultType, byteType, baseAddr,
+ offset, mlir::LLVM::GEPNoWrapFlags::inbounds);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(derivedClassOp, isNull,
+ baseAddr, adjusted);
+ }
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMATanOpLowering::matchAndRewrite(
cir::ATanOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -1336,6 +1476,14 @@ mlir::LogicalResult CIRToLLVMATanOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMCeilOpLowering::matchAndRewrite(
+ cir::CeilOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type resTy = typeConverter->convertType(op.getType());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::FCeilOp>(op, resTy, adaptor.getSrc());
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(
cir::AllocaOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -1607,6 +1755,14 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(
return mlir::success();
}
attr = op.getValue();
+ } else if (mlir::isa<cir::DataMemberType>(op.getType())) {
+ assert(lowerMod && "lower module is not available");
+ auto dataMember = mlir::cast<cir::DataMemberAttr>(op.getValue());
+ mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
+ mlir::TypedAttr abiValue = lowerMod->getCXXABI().lowerDataMemberConstant(
+ dataMember, layout, *typeConverter);
+ rewriter.replaceOpWithNewOp<ConstantOp>(op, abiValue);
+ return mlir::success();
} else if (const auto arrTy = mlir::dyn_cast<cir::ArrayType>(op.getType())) {
const auto constArr = mlir::dyn_cast<cir::ConstArrayAttr>(op.getValue());
if (!constArr && !isa<cir::ZeroAttr, cir::UndefAttr>(op.getValue()))
@@ -1869,15 +2025,14 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
assert(!cir::MissingFeatures::opFuncMultipleReturnVals());
- if (auto inlineKind = op.getInlineKind()) {
- fn.setNoInline(inlineKind == cir::InlineKind::NoInline);
- fn.setInlineHint(inlineKind == cir::InlineKind::InlineHint);
- fn.setAlwaysInline(inlineKind == cir::InlineKind::AlwaysInline);
+ if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) {
+ fn.setNoInline(*inlineKind == cir::InlineKind::NoInline);
+ fn.setInlineHint(*inlineKind == cir::InlineKind::InlineHint);
+ fn.setAlwaysInline(*inlineKind == cir::InlineKind::AlwaysInline);
}
- fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(
- getContext(), lowerCIRVisibilityToLLVMVisibility(
- op.getGlobalVisibilityAttr().getValue())));
+ fn.setVisibility_(
+ lowerCIRVisibilityToLLVMVisibility(op.getGlobalVisibility()));
rewriter.inlineRegionBefore(op.getBody(), fn.getBody(), fn.end());
if (failed(rewriter.convertRegionTypes(&fn.getBody(), *typeConverter,
@@ -1903,7 +2058,11 @@ mlir::LogicalResult CIRToLLVMGetGlobalOpLowering::matchAndRewrite(
mlir::Operation *newop = mlir::LLVM::AddressOfOp::create(
rewriter, op.getLoc(), type, op.getName());
- assert(!cir::MissingFeatures::opGlobalThreadLocal());
+ if (op.getTls()) {
+ // Handle access to TLS via intrinsic.
+ newop = mlir::LLVM::ThreadlocalAddressOp::create(rewriter, op.getLoc(),
+ type, newop->getResult(0));
+ }
rewriter.replaceOp(op, newop);
return mlir::success();
@@ -1920,13 +2079,11 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
// attributes are available on cir.global ops. This duplicates code
// in CIRToLLVMGlobalOpLowering::matchAndRewrite() but that will go
// away when the placeholders are no longer needed.
- assert(!cir::MissingFeatures::opGlobalConstant());
const bool isConst = op.getConstant();
assert(!cir::MissingFeatures::addressSpace());
const unsigned addrSpace = 0;
const bool isDsoLocal = op.getDsoLocal();
- assert(!cir::MissingFeatures::opGlobalThreadLocal());
- const bool isThreadLocal = false;
+ const bool isThreadLocal = (bool)op.getTlsModelAttr();
const uint64_t alignment = op.getAlignment().value_or(0);
const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
const StringRef symbol = op.getSymName();
@@ -1946,9 +2103,11 @@ CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(
cir::GlobalOp op, mlir::Attribute init,
mlir::ConversionPatternRewriter &rewriter) const {
// TODO: Generalize this handling when more types are needed here.
- assert((isa<cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,
- cir::ConstPtrAttr, cir::ConstComplexAttr, cir::GlobalViewAttr,
- cir::TypeInfoAttr, cir::VTableAttr, cir::ZeroAttr>(init)));
+ assert(
+ (isa<cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,
+ cir::ConstPtrAttr, cir::ConstComplexAttr, cir::GlobalViewAttr,
+ cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr, cir::ZeroAttr>(
+ init)));
// TODO(cir): once LLVM's dialect has proper equivalent attributes this
// should be updated. For now, we use a custom op to initialize globals
@@ -1980,13 +2139,11 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
convertTypeForMemory(*getTypeConverter(), dataLayout, cirSymType);
// FIXME: These default values are placeholders until the the equivalent
// attributes are available on cir.global ops.
- assert(!cir::MissingFeatures::opGlobalConstant());
- const bool isConst = false;
+ const bool isConst = op.getConstant();
assert(!cir::MissingFeatures::addressSpace());
const unsigned addrSpace = 0;
const bool isDsoLocal = op.getDsoLocal();
- assert(!cir::MissingFeatures::opGlobalThreadLocal());
- const bool isThreadLocal = false;
+ const bool isThreadLocal = (bool)op.getTlsModelAttr();
const uint64_t alignment = op.getAlignment().value_or(0);
const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
const StringRef symbol = op.getSymName();
@@ -2007,8 +2164,8 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
} else if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
cir::ConstRecordAttr, cir::ConstPtrAttr,
cir::ConstComplexAttr, cir::GlobalViewAttr,
- cir::TypeInfoAttr, cir::VTableAttr, cir::ZeroAttr>(
- init.value())) {
+ cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr,
+ cir::ZeroAttr>(init.value())) {
// TODO(cir): once LLVM's dialect has proper equivalent attributes this
// should be updated. For now, we use a custom op to initialize globals
// to the appropriate value.
@@ -2021,14 +2178,13 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
}
}
- // Rewrite op.
+ mlir::LLVM::Visibility visibility =
+ lowerCIRVisibilityToLLVMVisibility(op.getGlobalVisibility());
mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);
auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
op, llvmType, isConst, linkage, symbol, init.value_or(mlir::Attribute()),
alignment, addrSpace, isDsoLocal, isThreadLocal, comdatAttr, attributes);
- newOp.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(
- getContext(), lowerCIRVisibilityToLLVMVisibility(
- op.getGlobalVisibilityAttr().getValue())));
+ newOp.setVisibility_(visibility);
return mlir::success();
}
@@ -2495,6 +2651,120 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(
return cmpOp.emitError() << "unsupported type for CmpOp: " << type;
}
+mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(
+ cir::BinOpOverflowOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Location loc = op.getLoc();
+ cir::BinOpOverflowKind arithKind = op.getKind();
+ cir::IntType operandTy = op.getLhs().getType();
+ cir::IntType resultTy = op.getResult().getType();
+
+ EncompassedTypeInfo encompassedTyInfo =
+ computeEncompassedTypeWidth(operandTy, resultTy);
+ mlir::IntegerType encompassedLLVMTy =
+ rewriter.getIntegerType(encompassedTyInfo.width);
+
+ mlir::Value lhs = adaptor.getLhs();
+ mlir::Value rhs = adaptor.getRhs();
+ if (operandTy.getWidth() < encompassedTyInfo.width) {
+ if (operandTy.isSigned()) {
+ lhs = mlir::LLVM::SExtOp::create(rewriter, loc, encompassedLLVMTy, lhs);
+ rhs = mlir::LLVM::SExtOp::create(rewriter, loc, encompassedLLVMTy, rhs);
+ } else {
+ lhs = mlir::LLVM::ZExtOp::create(rewriter, loc, encompassedLLVMTy, lhs);
+ rhs = mlir::LLVM::ZExtOp::create(rewriter, loc, encompassedLLVMTy, rhs);
+ }
+ }
+
+ std::string intrinName = getLLVMIntrinName(arithKind, encompassedTyInfo.sign,
+ encompassedTyInfo.width);
+ auto intrinNameAttr = mlir::StringAttr::get(op.getContext(), intrinName);
+
+ mlir::IntegerType overflowLLVMTy = rewriter.getI1Type();
+ auto intrinRetTy = mlir::LLVM::LLVMStructType::getLiteral(
+ rewriter.getContext(), {encompassedLLVMTy, overflowLLVMTy});
+
+ auto callLLVMIntrinOp = mlir::LLVM::CallIntrinsicOp::create(
+ rewriter, loc, intrinRetTy, intrinNameAttr, mlir::ValueRange{lhs, rhs});
+ mlir::Value intrinRet = callLLVMIntrinOp.getResult(0);
+
+ mlir::Value result = mlir::LLVM::ExtractValueOp::create(
+ rewriter, loc, intrinRet, ArrayRef<int64_t>{0})
+ .getResult();
+ mlir::Value overflow = mlir::LLVM::ExtractValueOp::create(
+ rewriter, loc, intrinRet, ArrayRef<int64_t>{1})
+ .getResult();
+
+ if (resultTy.getWidth() < encompassedTyInfo.width) {
+ mlir::Type resultLLVMTy = getTypeConverter()->convertType(resultTy);
+ auto truncResult =
+ mlir::LLVM::TruncOp::create(rewriter, loc, resultLLVMTy, result);
+
+ // Extend the truncated result back to the encompassing type to check for
+ // any overflows during the truncation.
+ mlir::Value truncResultExt;
+ if (resultTy.isSigned())
+ truncResultExt = mlir::LLVM::SExtOp::create(
+ rewriter, loc, encompassedLLVMTy, truncResult);
+ else
+ truncResultExt = mlir::LLVM::ZExtOp::create(
+ rewriter, loc, encompassedLLVMTy, truncResult);
+ auto truncOverflow = mlir::LLVM::ICmpOp::create(
+ rewriter, loc, mlir::LLVM::ICmpPredicate::ne, truncResultExt, result);
+
+ result = truncResult;
+ overflow = mlir::LLVM::OrOp::create(rewriter, loc, overflow, truncOverflow);
+ }
+
+ mlir::Type boolLLVMTy =
+ getTypeConverter()->convertType(op.getOverflow().getType());
+ if (boolLLVMTy != rewriter.getI1Type())
+ overflow = mlir::LLVM::ZExtOp::create(rewriter, loc, boolLLVMTy, overflow);
+
+ rewriter.replaceOp(op, mlir::ValueRange{result, overflow});
+
+ return mlir::success();
+}
+
+std::string CIRToLLVMBinOpOverflowOpLowering::getLLVMIntrinName(
+ cir::BinOpOverflowKind opKind, bool isSigned, unsigned width) {
+ // The intrinsic name is `@llvm.{s|u}{opKind}.with.overflow.i{width}`
+
+ std::string name = "llvm.";
+
+ if (isSigned)
+ name.push_back('s');
+ else
+ name.push_back('u');
+
+ switch (opKind) {
+ case cir::BinOpOverflowKind::Add:
+ name.append("add.");
+ break;
+ case cir::BinOpOverflowKind::Sub:
+ name.append("sub.");
+ break;
+ case cir::BinOpOverflowKind::Mul:
+ name.append("mul.");
+ break;
+ }
+
+ name.append("with.overflow.i");
+ name.append(std::to_string(width));
+
+ return name;
+}
+
+CIRToLLVMBinOpOverflowOpLowering::EncompassedTypeInfo
+CIRToLLVMBinOpOverflowOpLowering::computeEncompassedTypeWidth(
+ cir::IntType operandTy, cir::IntType resultTy) {
+ bool sign = operandTy.getIsSigned() || resultTy.getIsSigned();
+ unsigned width =
+ std::max(operandTy.getWidth() + (sign && operandTy.isUnsigned()),
+ resultTy.getWidth() + (sign && resultTy.isUnsigned()));
+ return {sign, width};
+}
+
mlir::LogicalResult CIRToLLVMShiftOpLowering::matchAndRewrite(
cir::ShiftOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -2579,8 +2849,20 @@ mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(
return mlir::success();
}
+std::unique_ptr<cir::LowerModule> prepareLowerModule(mlir::ModuleOp module) {
+ mlir::PatternRewriter rewriter{module->getContext()};
+ // If the triple is not present, e.g. CIR modules parsed from text, we
+ // cannot init LowerModule properly. This happens in some lowering tests,
+ // but it should not happen in real compilation.
+ assert(!cir::MissingFeatures::makeTripleAlwaysPresent());
+ if (!module->hasAttr(cir::CIRDialect::getTripleAttrName()))
+ return {};
+ return cir::createLowerModule(module, rewriter);
+}
+
static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
- mlir::DataLayout &dataLayout) {
+ mlir::DataLayout &dataLayout,
+ cir::LowerModule *lowerModule) {
converter.addConversion([&](cir::PointerType type) -> mlir::Type {
unsigned addrSpace =
type.getAddrSpace() ? type.getAddrSpace().getValue().getUInt() : 0;
@@ -2590,6 +2872,13 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
assert(!cir::MissingFeatures::addressSpace());
return mlir::LLVM::LLVMPointerType::get(type.getContext());
});
+ converter.addConversion(
+ [&, lowerModule](cir::DataMemberType type) -> mlir::Type {
+ assert(lowerModule && "CXXABI is not available");
+ mlir::Type abiType =
+ lowerModule->getCXXABI().lowerDataMemberType(type, converter);
+ return converter.convertType(abiType);
+ });
converter.addConversion([&](cir::ArrayType type) -> mlir::Type {
mlir::Type ty =
convertTypeForMemory(converter, dataLayout, type.getElementType());
@@ -2816,6 +3105,29 @@ static void collectUnreachable(mlir::Operation *parent,
}
}
+mlir::LogicalResult CIRToLLVMObjSizeOpLowering::matchAndRewrite(
+ cir::ObjSizeOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type llvmResTy = getTypeConverter()->convertType(op.getType());
+ mlir::Location loc = op->getLoc();
+
+ mlir::IntegerType i1Ty = rewriter.getI1Type();
+
+ auto i1Val = [&rewriter, &loc, &i1Ty](bool val) {
+ return mlir::LLVM::ConstantOp::create(rewriter, loc, i1Ty, val);
+ };
+
+ replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.objectsize", llvmResTy,
+ {
+ adaptor.getPtr(),
+ i1Val(op.getMin()),
+ i1Val(op.getNullunknown()),
+ i1Val(op.getDynamic()),
+ });
+
+ return mlir::LogicalResult::success();
+}
+
void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {
// Lower the module attributes to LLVM equivalents.
if (mlir::Attribute tripleAttr =
@@ -2835,7 +3147,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
mlir::ModuleOp module = getOperation();
mlir::DataLayout dl(module);
mlir::LLVMTypeConverter converter(&getContext());
- prepareTypeConverter(converter, dl);
+ std::unique_ptr<cir::LowerModule> lowerModule = prepareLowerModule(module);
+ prepareTypeConverter(converter, dl, lowerModule.get());
mlir::RewritePatternSet patterns(&getContext());
@@ -2843,7 +3156,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
#define GET_LLVM_LOWERING_PATTERNS_LIST
#include "clang/CIR/Dialect/IR/CIRLowering.inc"
#undef GET_LLVM_LOWERING_PATTERNS_LIST
- >(converter, patterns.getContext(), dl);
+ >(converter, patterns.getContext(), lowerModule.get(), dl);
processCIRAttrs(module);
@@ -3002,6 +3315,90 @@ mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite(
return mlir::success();
}
+static mlir::LLVM::LLVMStructType
+getLLVMLandingPadStructTy(mlir::ConversionPatternRewriter &rewriter) {
+ // Create the landing pad type: struct { ptr, i32 }
+ mlir::MLIRContext *ctx = rewriter.getContext();
+ auto llvmPtr = mlir::LLVM::LLVMPointerType::get(ctx);
+ llvm::SmallVector<mlir::Type> structFields = {llvmPtr, rewriter.getI32Type()};
+ return mlir::LLVM::LLVMStructType::getLiteral(ctx, structFields);
+}
+
+mlir::LogicalResult CIRToLLVMEhInflightOpLowering::matchAndRewrite(
+ cir::EhInflightOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ auto llvmFn = op->getParentOfType<mlir::LLVM::LLVMFuncOp>();
+ assert(llvmFn && "expected LLVM function parent");
+ mlir::Block *entryBlock = &llvmFn.getRegion().front();
+ assert(entryBlock->isEntryBlock());
+
+ mlir::ArrayAttr catchListAttr = op.getCatchTypeListAttr();
+ mlir::SmallVector<mlir::Value> catchSymAddrs;
+
+ auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
+ mlir::Location loc = op.getLoc();
+
+ // %landingpad = landingpad { ptr, i32 }
+ // Note that since llvm.landingpad has to be the first operation on the
+ // block, any needed value for its operands has to be added somewhere else.
+ if (catchListAttr) {
+ // catch ptr @_ZTIi
+ // catch ptr @_ZTIPKc
+ for (mlir::Attribute catchAttr : catchListAttr) {
+ auto symAttr = cast<mlir::FlatSymbolRefAttr>(catchAttr);
+ // Generate `llvm.mlir.addressof` for each symbol, and place those
+ // operations in the LLVM function entry basic block.
+ mlir::OpBuilder::InsertionGuard guard(rewriter);
+ rewriter.setInsertionPointToStart(entryBlock);
+ mlir::Value addrOp = mlir::LLVM::AddressOfOp::create(
+ rewriter, loc, llvmPtrTy, symAttr.getValue());
+ catchSymAddrs.push_back(addrOp);
+ }
+ } else if (!op.getCleanup()) {
+ // We need to emit catch-all only if cleanup is not set, because when we
+ // have catch-all handler, there is no case when we set would unwind past
+ // the handler
+ mlir::OpBuilder::InsertionGuard guard(rewriter);
+ rewriter.setInsertionPointToStart(entryBlock);
+ mlir::Value nullOp = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPtrTy);
+ catchSymAddrs.push_back(nullOp);
+ }
+
+ // %slot = extractvalue { ptr, i32 } %x, 0
+ // %selector = extractvalue { ptr, i32 } %x, 1
+ mlir::LLVM::LLVMStructType llvmLandingPadStructTy =
+ getLLVMLandingPadStructTy(rewriter);
+ auto landingPadOp = mlir::LLVM::LandingpadOp::create(
+ rewriter, loc, llvmLandingPadStructTy, catchSymAddrs);
+
+ if (op.getCleanup())
+ landingPadOp.setCleanup(true);
+
+ mlir::Value slot =
+ mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 0);
+ mlir::Value selector =
+ mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 1);
+ rewriter.replaceOp(op, mlir::ValueRange{slot, selector});
+
+ // Landing pads are required to be in LLVM functions with personality
+ // attribute.
+ // TODO(cir): for now hardcode personality creation in order to start
+ // adding exception tests, once we annotate CIR with such information,
+ // change it to be in FuncOp lowering instead.
+ mlir::OpBuilder::InsertionGuard guard(rewriter);
+ // Insert personality decl before the current function.
+ rewriter.setInsertionPoint(llvmFn);
+ auto personalityFnTy =
+ mlir::LLVM::LLVMFunctionType::get(rewriter.getI32Type(), {},
+ /*isVarArg=*/true);
+
+ const StringRef fnName = "__gxx_personality_v0";
+ createLLVMFuncOpIfNotExist(rewriter, op, fnName, personalityFnTy);
+ llvmFn.setPersonality(fnName);
+
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite(
cir::TrapOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -3640,6 +4037,13 @@ mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMIsConstantOpLowering::matchAndRewrite(
+ cir::IsConstantOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::IsConstantOp>(op, adaptor.getVal());
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite(
cir::InlineAsmOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -3722,6 +4126,18 @@ mlir::LogicalResult CIRToLLVMVAEndOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMVACopyOpLowering::matchAndRewrite(
+ cir::VACopyOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext());
+ auto dstList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,
+ adaptor.getDstList());
+ auto srcList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,
+ adaptor.getSrcList());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::VaCopyOp>(op, dstList, srcList);
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(
cir::VAArgOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -3739,6 +4155,24 @@ mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMBlockAddressOpLowering::matchAndRewrite(
+ cir::BlockAddressOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ return mlir::failure();
+}
+
+mlir::LogicalResult CIRToLLVMIndirectBrOpLowering::matchAndRewrite(
+ cir::IndirectBrOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ return mlir::failure();
+}
+
+mlir::LogicalResult CIRToLLVMAwaitOpLowering::matchAndRewrite(
+ cir::AwaitOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ return mlir::failure();
+}
+
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
return std::make_unique<ConvertCIRToLLVMPass>();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 0591de5..d32f860 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -12,6 +12,8 @@
#ifndef CLANG_CIR_LOWERTOLLVM_H
#define CLANG_CIR_LOWERTOLLVM_H
+#include "LowerModule.h"
+
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Transforms/DialectConversion.h"