[clang] fa072bd - [CIR] Add lowering for Func, Return, Alloca, Load, and Store (#129571)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 4 14:50:38 PST 2025
Author: Andy Kaylor
Date: 2025-03-04T14:50:34-08:00
New Revision: fa072bd29a109be424e6f4521823529750a55efe
URL: https://github.com/llvm/llvm-project/commit/fa072bd29a109be424e6f4521823529750a55efe
DIFF: https://github.com/llvm/llvm-project/commit/fa072bd29a109be424e6f4521823529750a55efe.diff
LOG: [CIR] Add lowering for Func, Return, Alloca, Load, and Store (#129571)
Add support for lowering recently upstreamed CIR ops to LLVM IR.
Added:
clang/test/CIR/Lowering/basic.cpp
clang/test/CIR/Lowering/func-simple.cpp
Modified:
clang/include/clang/CIR/MissingFeatures.h
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
clang/test/CIR/Lowering/global-var-simple.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 9b416ef61055e..6fbaa27bc7073 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -27,9 +27,6 @@ struct MissingFeatures {
// Address space related
static bool addressSpace() { return false; }
- // This isn't needed until we add support for bools.
- static bool convertTypeForMemory() { return false; }
-
// CIRGenFunction implementation details
static bool cgfSymbolTable() { return false; }
@@ -40,10 +37,14 @@ struct MissingFeatures {
static bool opGlobalAlignment() { return false; }
static bool opGlobalLinkage() { return false; }
- // Load attributes
+ // Load/store attributes
static bool opLoadThreadLocal() { return false; }
static bool opLoadEmitScalarRangeCheck() { return false; }
static bool opLoadBooleanRepresentation() { return false; }
+ static bool opLoadStoreTbaa() { return false; }
+ static bool opLoadStoreMemOrder() { return false; }
+ static bool opLoadStoreVolatile() { return false; }
+ static bool opLoadStoreAlignment() { return false; }
// AllocaOp handling
static bool opAllocaVarDeclContext() { return false; }
@@ -55,11 +56,23 @@ struct MissingFeatures {
static bool opAllocaOpenMPThreadPrivate() { return false; }
static bool opAllocaEscapeByReference() { return false; }
static bool opAllocaReference() { return false; }
+ static bool opAllocaAnnotations() { return false; }
+ static bool opAllocaDynAllocSize() { return false; }
+
+ // FuncOp handling
+ static bool opFuncOpenCLKernelMetadata() { return false; }
+ static bool opFuncCallingConv() { return false; }
+ static bool opFuncExtraAttrs() { return false; }
+ static bool opFuncDsolocal() { return false; }
+ static bool opFuncLinkage() { return false; }
+ static bool opFuncVisibility() { return false; }
// Misc
static bool scalarConversionOpts() { return false; }
static bool tryEmitAsConstant() { return false; }
static bool constructABIArgDirectExtend() { return false; }
+ static bool opGlobalViewAttr() { return false; }
+ static bool lowerModeOptLevel() { return false; }
};
} // namespace cir
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6f7cae8fa7fa3..f614c5d1db0c0 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -29,6 +29,7 @@
#include "clang/CIR/Passes.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/TimeProfiler.h"
using namespace cir;
@@ -37,6 +38,77 @@ using namespace llvm;
namespace cir {
namespace direct {
+/// Given a type convertor and a data layout, convert the given type to a type
+/// that is suitable for memory operations. For example, this can be used to
+/// lower cir.bool accesses to i8.
+static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,
+ mlir::DataLayout const &dataLayout,
+ mlir::Type type) {
+ // TODO(cir): Handle other types similarly to clang's codegen
+ // convertTypeForMemory
+ if (isa<cir::BoolType>(type)) {
+ return mlir::IntegerType::get(type.getContext(),
+ dataLayout.getTypeSizeInBits(type));
+ }
+
+ return converter.convertType(type);
+}
+
+static mlir::Value createIntCast(mlir::OpBuilder &bld, mlir::Value src,
+ mlir::IntegerType dstTy,
+ bool isSigned = false) {
+ mlir::Type srcTy = src.getType();
+ assert(mlir::isa<mlir::IntegerType>(srcTy));
+
+ unsigned srcWidth = mlir::cast<mlir::IntegerType>(srcTy).getWidth();
+ unsigned dstWidth = mlir::cast<mlir::IntegerType>(dstTy).getWidth();
+ mlir::Location loc = src.getLoc();
+
+ if (dstWidth > srcWidth && isSigned)
+ return bld.create<mlir::LLVM::SExtOp>(loc, dstTy, src);
+ else if (dstWidth > srcWidth)
+ return bld.create<mlir::LLVM::ZExtOp>(loc, dstTy, src);
+ else if (dstWidth < srcWidth)
+ return bld.create<mlir::LLVM::TruncOp>(loc, dstTy, src);
+ else
+ return bld.create<mlir::LLVM::BitcastOp>(loc, dstTy, src);
+}
+
+/// Emits the value from memory as expected by its users. Should be called when
+/// the memory represetnation of a CIR type is not equal to its scalar
+/// representation.
+static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter,
+ mlir::DataLayout const &dataLayout,
+ cir::LoadOp op, mlir::Value value) {
+
+ // TODO(cir): Handle other types similarly to clang's codegen EmitFromMemory
+ if (auto boolTy = mlir::dyn_cast<cir::BoolType>(op.getResult().getType())) {
+ // Create a cast value from specified size in datalayout to i1
+ assert(value.getType().isInteger(dataLayout.getTypeSizeInBits(boolTy)));
+ return createIntCast(rewriter, value, rewriter.getI1Type());
+ }
+
+ return value;
+}
+
+/// Emits a value to memory with the expected scalar type. Should be called when
+/// the memory represetnation of a CIR type is not equal to its scalar
+/// representation.
+static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter,
+ mlir::DataLayout const &dataLayout,
+ mlir::Type origType, mlir::Value value) {
+
+ // TODO(cir): Handle other types similarly to clang's codegen EmitToMemory
+ if (auto boolTy = mlir::dyn_cast<cir::BoolType>(origType)) {
+ // Create zext of value from i1 to i8
+ mlir::IntegerType memType =
+ rewriter.getIntegerType(dataLayout.getTypeSizeInBits(boolTy));
+ return createIntCast(rewriter, value, memType);
+ }
+
+ return value;
+}
+
class CIRAttrToValue {
public:
CIRAttrToValue(mlir::Operation *parentOp,
@@ -100,7 +172,7 @@ class GlobalInitAttrRewriter {
mlir::Attribute visit(mlir::Attribute attr) {
return llvm::TypeSwitch<mlir::Attribute, mlir::Attribute>(attr)
- .Case<cir::IntAttr, cir::FPAttr>(
+ .Case<cir::IntAttr, cir::FPAttr, cir::BoolAttr>(
[&](auto attrT) { return visitCirAttr(attrT); })
.Default([&](auto attrT) { return mlir::Attribute(); });
}
@@ -111,6 +183,9 @@ class GlobalInitAttrRewriter {
mlir::Attribute visitCirAttr(cir::FPAttr attr) {
return rewriter.getFloatAttr(llvmType, attr.getValue());
}
+ mlir::Attribute visitCirAttr(cir::BoolAttr attr) {
+ return rewriter.getBoolAttr(attr.getValue());
+ }
private:
mlir::Type llvmType;
@@ -139,12 +214,219 @@ struct ConvertCIRToLLVMPass
StringRef getArgument() const override { return "cir-flat-to-llvm"; }
};
+mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(
+ cir::AllocaOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ assert(!cir::MissingFeatures::opAllocaDynAllocSize());
+ mlir::Value size = rewriter.create<mlir::LLVM::ConstantOp>(
+ op.getLoc(), typeConverter->convertType(rewriter.getIndexType()),
+ rewriter.getIntegerAttr(rewriter.getIndexType(), 1));
+ mlir::Type elementTy =
+ convertTypeForMemory(*getTypeConverter(), dataLayout, op.getAllocaType());
+ mlir::Type resultTy = convertTypeForMemory(*getTypeConverter(), dataLayout,
+ op.getResult().getType());
+
+ assert(!cir::MissingFeatures::addressSpace());
+ assert(!cir::MissingFeatures::opAllocaAnnotations());
+
+ rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(
+ op, resultTy, elementTy, size, op.getAlignmentAttr().getInt());
+
+ return mlir::success();
+}
+
+mlir::LogicalResult CIRToLLVMReturnOpLowering::matchAndRewrite(
+ cir::ReturnOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op, adaptor.getOperands());
+ return mlir::LogicalResult::success();
+}
+
+mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite(
+ cir::LoadOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ const mlir::Type llvmTy = convertTypeForMemory(
+ *getTypeConverter(), dataLayout, op.getResult().getType());
+ assert(!cir::MissingFeatures::opLoadStoreMemOrder());
+ assert(!cir::MissingFeatures::opLoadStoreAlignment());
+ unsigned alignment = (unsigned)dataLayout.getTypeABIAlignment(llvmTy);
+
+ assert(!cir::MissingFeatures::lowerModeOptLevel());
+
+ // TODO: nontemporal, syncscope.
+ assert(!cir::MissingFeatures::opLoadStoreVolatile());
+ mlir::LLVM::LoadOp newLoad = rewriter.create<mlir::LLVM::LoadOp>(
+ op->getLoc(), llvmTy, adaptor.getAddr(), alignment,
+ /*volatile=*/false, /*nontemporal=*/false,
+ /*invariant=*/false, /*invariantGroup=*/false,
+ mlir::LLVM::AtomicOrdering::not_atomic);
+
+ // Convert adapted result to its original type if needed.
+ mlir::Value result =
+ emitFromMemory(rewriter, dataLayout, op, newLoad.getResult());
+ rewriter.replaceOp(op, result);
+ assert(!cir::MissingFeatures::opLoadStoreTbaa());
+ return mlir::LogicalResult::success();
+}
+
+mlir::LogicalResult CIRToLLVMStoreOpLowering::matchAndRewrite(
+ cir::StoreOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ assert(!cir::MissingFeatures::opLoadStoreMemOrder());
+ assert(!cir::MissingFeatures::opLoadStoreAlignment());
+ const mlir::Type llvmTy =
+ getTypeConverter()->convertType(op.getValue().getType());
+ unsigned alignment = (unsigned)dataLayout.getTypeABIAlignment(llvmTy);
+
+ assert(!cir::MissingFeatures::lowerModeOptLevel());
+
+ // Convert adapted value to its memory type if needed.
+ mlir::Value value = emitToMemory(rewriter, dataLayout,
+ op.getValue().getType(), adaptor.getValue());
+ // TODO: nontemporal, syncscope.
+ assert(!cir::MissingFeatures::opLoadStoreVolatile());
+ mlir::LLVM::StoreOp storeOp = rewriter.create<mlir::LLVM::StoreOp>(
+ op->getLoc(), value, adaptor.getAddr(), alignment, /*volatile=*/false,
+ /*nontemporal=*/false, /*invariantGroup=*/false,
+ mlir::LLVM::AtomicOrdering::not_atomic);
+ rewriter.replaceOp(op, storeOp);
+ assert(!cir::MissingFeatures::opLoadStoreTbaa());
+ return mlir::LogicalResult::success();
+}
+
+mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(
+ cir::ConstantOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Attribute attr = op.getValue();
+
+ if (mlir::isa<mlir::IntegerType>(op.getType())) {
+ // Verified cir.const operations cannot actually be of these types, but the
+ // lowering pass may generate temporary cir.const operations with these
+ // types. This is OK since MLIR allows unverified operations to be alive
+ // during a pass as long as they don't live past the end of the pass.
+ attr = op.getValue();
+ } else if (mlir::isa<cir::BoolType>(op.getType())) {
+ int value = (op.getValue() ==
+ cir::BoolAttr::get(getContext(),
+ cir::BoolType::get(getContext()), true));
+ attr = rewriter.getIntegerAttr(typeConverter->convertType(op.getType()),
+ value);
+ } else if (mlir::isa<cir::IntType>(op.getType())) {
+ assert(!cir::MissingFeatures::opGlobalViewAttr());
+
+ attr = rewriter.getIntegerAttr(
+ typeConverter->convertType(op.getType()),
+ mlir::cast<cir::IntAttr>(op.getValue()).getValue());
+ } else if (mlir::isa<cir::CIRFPTypeInterface>(op.getType())) {
+ attr = rewriter.getFloatAttr(
+ typeConverter->convertType(op.getType()),
+ mlir::cast<cir::FPAttr>(op.getValue()).getValue());
+ } else if (mlir::isa<cir::PointerType>(op.getType())) {
+ // Optimize with dedicated LLVM op for null pointers.
+ if (mlir::isa<cir::ConstPtrAttr>(op.getValue())) {
+ if (mlir::cast<cir::ConstPtrAttr>(op.getValue()).isNullValue()) {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ZeroOp>(
+ op, typeConverter->convertType(op.getType()));
+ return mlir::success();
+ }
+ }
+ assert(!cir::MissingFeatures::opGlobalViewAttr());
+ attr = op.getValue();
+ } else {
+ return op.emitError() << "unsupported constant type " << op.getType();
+ }
+
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
+ op, getTypeConverter()->convertType(op.getType()), attr);
+
+ return mlir::success();
+}
+
+/// Convert the `cir.func` attributes to `llvm.func` attributes.
+/// Only retain those attributes that are not constructed by
+/// `LLVMFuncOp::build`. If `filterArgAttrs` is set, also filter out
+/// argument attributes.
+void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
+ cir::FuncOp func, bool filterArgAndResAttrs,
+ SmallVectorImpl<mlir::NamedAttribute> &result) const {
+ assert(!cir::MissingFeatures::opFuncCallingConv());
+ for (mlir::NamedAttribute attr : func->getAttrs()) {
+ if (attr.getName() == mlir::SymbolTable::getSymbolAttrName() ||
+ attr.getName() == func.getFunctionTypeAttrName() ||
+ attr.getName() == getLinkageAttrNameString() ||
+ (filterArgAndResAttrs &&
+ (attr.getName() == func.getArgAttrsAttrName() ||
+ attr.getName() == func.getResAttrsAttrName())))
+ continue;
+
+ assert(!cir::MissingFeatures::opFuncExtraAttrs());
+ result.push_back(attr);
+ }
+}
+
+mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
+ cir::FuncOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+
+ cir::FuncType fnType = op.getFunctionType();
+ assert(!cir::MissingFeatures::opFuncDsolocal());
+ bool isDsoLocal = false;
+ mlir::TypeConverter::SignatureConversion signatureConversion(
+ fnType.getNumInputs());
+
+ for (const auto &argType : llvm::enumerate(fnType.getInputs())) {
+ mlir::Type convertedType = typeConverter->convertType(argType.value());
+ if (!convertedType)
+ return mlir::failure();
+ signatureConversion.addInputs(argType.index(), convertedType);
+ }
+
+ mlir::Type resultType =
+ getTypeConverter()->convertType(fnType.getReturnType());
+
+ // Create the LLVM function operation.
+ mlir::Type llvmFnTy = mlir::LLVM::LLVMFunctionType::get(
+ resultType ? resultType : mlir::LLVM::LLVMVoidType::get(getContext()),
+ signatureConversion.getConvertedTypes(),
+ /*isVarArg=*/fnType.isVarArg());
+ // LLVMFuncOp expects a single FileLine Location instead of a fused
+ // location.
+ mlir::Location loc = op.getLoc();
+ if (mlir::FusedLoc fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc))
+ loc = fusedLoc.getLocations()[0];
+ assert((mlir::isa<mlir::FileLineColLoc>(loc) ||
+ mlir::isa<mlir::UnknownLoc>(loc)) &&
+ "expected single location or unknown location here");
+
+ assert(!cir::MissingFeatures::opFuncLinkage());
+ mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External;
+ assert(!cir::MissingFeatures::opFuncCallingConv());
+ mlir::LLVM::CConv cconv = mlir::LLVM::CConv::C;
+ SmallVector<mlir::NamedAttribute, 4> attributes;
+ lowerFuncAttributes(op, /*filterArgAndResAttrs=*/false, attributes);
+
+ mlir::LLVM::LLVMFuncOp fn = rewriter.create<mlir::LLVM::LLVMFuncOp>(
+ loc, op.getName(), llvmFnTy, linkage, isDsoLocal, cconv,
+ mlir::SymbolRefAttr(), attributes);
+
+ assert(!cir::MissingFeatures::opFuncVisibility());
+
+ rewriter.inlineRegionBefore(op.getBody(), fn.getBody(), fn.end());
+ if (failed(rewriter.convertRegionTypes(&fn.getBody(), *typeConverter,
+ &signatureConversion)))
+ return mlir::failure();
+
+ rewriter.eraseOp(op);
+
+ return mlir::LogicalResult::success();
+}
+
/// Replace CIR global with a region initialized LLVM global and update
/// insertion point to the end of the initializer block.
void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {
- assert(!cir::MissingFeatures::convertTypeForMemory());
- const mlir::Type llvmType = getTypeConverter()->convertType(op.getSymType());
+ const mlir::Type llvmType =
+ convertTypeForMemory(*getTypeConverter(), dataLayout, op.getSymType());
// FIXME: These default values are placeholders until the the equivalent
// attributes are available on cir.global ops. This duplicates code
@@ -165,10 +447,11 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
const StringRef symbol = op.getSymName();
SmallVector<mlir::NamedAttribute> attributes;
- auto newGlobalOp = rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
- op, llvmType, isConst, linkage, symbol, nullptr, alignment, addrSpace,
- isDsoLocal, isThreadLocal,
- /*comdat=*/mlir::SymbolRefAttr(), attributes);
+ mlir::LLVM::GlobalOp newGlobalOp =
+ rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
+ op, llvmType, isConst, linkage, symbol, nullptr, alignment, addrSpace,
+ isDsoLocal, isThreadLocal,
+ /*comdat=*/mlir::SymbolRefAttr(), attributes);
newGlobalOp.getRegion().emplaceBlock();
rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());
}
@@ -201,8 +484,8 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
const mlir::Type cirSymType = op.getSymType();
// This is the LLVM dialect type.
- assert(!cir::MissingFeatures::convertTypeForMemory());
- const mlir::Type llvmType = getTypeConverter()->convertType(cirSymType);
+ const mlir::Type llvmType =
+ 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());
@@ -221,7 +504,7 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
SmallVector<mlir::NamedAttribute> attributes;
if (init.has_value()) {
- if (mlir::isa<cir::FPAttr, cir::IntAttr>(init.value())) {
+ if (mlir::isa<cir::FPAttr, cir::IntAttr, cir::BoolAttr>(init.value())) {
GlobalInitAttrRewriter initRewriter(llvmType, rewriter);
init = initRewriter.visit(init.value());
// If initRewriter returned a null attribute, init will have a value but
@@ -263,6 +546,10 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS);
});
+ converter.addConversion([&](cir::BoolType type) -> mlir::Type {
+ return mlir::IntegerType::get(type.getContext(), 1,
+ mlir::IntegerType::Signless);
+ });
converter.addConversion([&](cir::IntType type) -> mlir::Type {
// LLVM doesn't work with signed types, so we drop the CIR signs here.
return mlir::IntegerType::get(type.getContext(), type.getWidth());
@@ -292,7 +579,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {
// Lower the module attributes to LLVM equivalents.
- if (auto tripleAttr = module->getAttr(cir::CIRDialect::getTripleAttrName()))
+ if (mlir::Attribute tripleAttr =
+ module->getAttr(cir::CIRDialect::getTripleAttrName()))
module->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),
tripleAttr);
}
@@ -307,7 +595,16 @@ void ConvertCIRToLLVMPass::runOnOperation() {
mlir::RewritePatternSet patterns(&getContext());
+ patterns.add<CIRToLLVMReturnOpLowering>(patterns.getContext());
+ // This could currently be merged with the group below, but it will get more
+ // arguments later, so we'll keep it separate for now.
+ patterns.add<CIRToLLVMAllocaOpLowering>(converter, patterns.getContext(), dl);
+ patterns.add<CIRToLLVMLoadOpLowering>(converter, patterns.getContext(), dl);
+ patterns.add<CIRToLLVMStoreOpLowering>(converter, patterns.getContext(), dl);
patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl);
+ patterns.add<CIRToLLVMConstantOpLowering>(converter, patterns.getContext(),
+ dl);
+ patterns.add<CIRToLLVMFuncOpLowering>(converter, patterns.getContext());
processCIRAttrs(module);
@@ -317,8 +614,9 @@ void ConvertCIRToLLVMPass::runOnOperation() {
target.addIllegalDialect<mlir::BuiltinDialect, cir::CIRDialect,
mlir::func::FuncDialect>();
- if (failed(applyPartialConversion(module, target, std::move(patterns))))
+ if (failed(applyPartialConversion(module, target, std::move(patterns)))) {
signalPassFailure();
+ }
}
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index d1109bb7e1c08..ccb4065c3019e 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -19,6 +19,95 @@ namespace cir {
namespace direct {
+class CIRToLLVMReturnOpLowering
+ : public mlir::OpConversionPattern<cir::ReturnOp> {
+public:
+ using mlir::OpConversionPattern<cir::ReturnOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::ReturnOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMAllocaOpLowering
+ : public mlir::OpConversionPattern<cir::AllocaOp> {
+ mlir::DataLayout const &dataLayout;
+
+public:
+ CIRToLLVMAllocaOpLowering(mlir::TypeConverter const &typeConverter,
+ mlir::MLIRContext *context,
+ mlir::DataLayout const &dataLayout)
+ : OpConversionPattern<cir::AllocaOp>(typeConverter, context),
+ dataLayout(dataLayout) {}
+
+ using mlir::OpConversionPattern<cir::AllocaOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::AllocaOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMLoadOpLowering : public mlir::OpConversionPattern<cir::LoadOp> {
+ mlir::DataLayout const &dataLayout;
+
+public:
+ CIRToLLVMLoadOpLowering(const mlir::TypeConverter &typeConverter,
+ mlir::MLIRContext *context,
+ mlir::DataLayout const &dataLayout)
+ : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {}
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::LoadOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMStoreOpLowering
+ : public mlir::OpConversionPattern<cir::StoreOp> {
+ mlir::DataLayout const &dataLayout;
+
+public:
+ CIRToLLVMStoreOpLowering(const mlir::TypeConverter &typeConverter,
+ mlir::MLIRContext *context,
+ mlir::DataLayout const &dataLayout)
+ : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {}
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::StoreOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMConstantOpLowering
+ : public mlir::OpConversionPattern<cir::ConstantOp> {
+ mlir::DataLayout const &dataLayout;
+
+public:
+ CIRToLLVMConstantOpLowering(const mlir::TypeConverter &typeConverter,
+ mlir::MLIRContext *context,
+ mlir::DataLayout const &dataLayout)
+ : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {
+ setHasBoundedRewriteRecursion();
+ }
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::ConstantOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMFuncOpLowering : public mlir::OpConversionPattern<cir::FuncOp> {
+ static mlir::StringRef getLinkageAttrNameString() { return "linkage"; }
+
+ void lowerFuncAttributes(
+ cir::FuncOp func, bool filterArgAndResAttrs,
+ mlir::SmallVectorImpl<mlir::NamedAttribute> &result) const;
+
+public:
+ using mlir::OpConversionPattern<cir::FuncOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::FuncOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMGlobalOpLowering
: public mlir::OpConversionPattern<cir::GlobalOp> {
const mlir::DataLayout &dataLayout;
diff --git a/clang/test/CIR/Lowering/basic.cpp b/clang/test/CIR/Lowering/basic.cpp
new file mode 100644
index 0000000000000..2c29368bd5835
--- /dev/null
+++ b/clang/test/CIR/Lowering/basic.cpp
@@ -0,0 +1,46 @@
+// RUN: not %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - 2>&1 | FileCheck %s
+
+// This error is caused by the "const int i = 2" line in f2(). When
+// initaliziers are implemented, the checks there should be updated
+// and the "not" should be removed from the run line.
+// CHECK: error: ClangIR code gen Not Yet Implemented: emitAutoVarInit
+
+int f1() {
+ int i;
+ return i;
+}
+
+// CHECK: define{{.*}} i32 @f1() {
+// CHECK: %[[I_PTR:.*]] = alloca i32, i64 1, align 4
+// CHECK: %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
+// CHECK: ret i32 %[[I]]
+
+int f2() {
+ const int i = 2;
+ return i;
+}
+
+// CHECK: define{{.*}} i32 @f2() {
+// CHECK: %[[I_PTR:.*]] = alloca i32, i64 1, align 4
+// CHECK: %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
+// CHECK: ret i32 %[[I]]
+
+int f3(int i) {
+ return i;
+ }
+
+// CHECK: define{{.*}} i32 @f3(i32 %[[ARG:.*]])
+// CHECK: %[[ARG_ALLOCA:.*]] = alloca i32, i64 1, align 4
+// CHECK: store i32 %[[ARG]], ptr %[[ARG_ALLOCA]], align 4
+// CHECK: %[[ARG_VAL:.*]] = load i32, ptr %[[ARG_ALLOCA]], align 4
+// CHECK: ret i32 %[[ARG_VAL]]
+
+int f4(const int i) {
+ return i;
+}
+
+// CHECK: define{{.*}} i32 @f4(i32 %[[ARG:.*]])
+// CHECK: %[[ARG_ALLOCA:.*]] = alloca i32, i64 1, align 4
+// CHECK: store i32 %[[ARG]], ptr %[[ARG_ALLOCA]], align 4
+// CHECK: %[[ARG_VAL:.*]] = load i32, ptr %[[ARG_ALLOCA]], align 4
+// CHECK: ret i32 %[[ARG_VAL]]
diff --git a/clang/test/CIR/Lowering/func-simple.cpp b/clang/test/CIR/Lowering/func-simple.cpp
new file mode 100644
index 0000000000000..1429ec270774b
--- /dev/null
+++ b/clang/test/CIR/Lowering/func-simple.cpp
@@ -0,0 +1,34 @@
+// Simple functions
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s
+
+void empty() { }
+// CHECK: define{{.*}} void @empty()
+// CHECK: ret void
+
+void voidret() { return; }
+// CHECK: define{{.*}} void @voidret()
+// CHECK: ret void
+
+int intfunc() { return 42; }
+// CHECK: define{{.*}} i32 @intfunc()
+// CHECK: ret i32 42
+
+long longfunc() { return 42l; }
+// CHECK: define{{.*}} i64 @longfunc() {
+// CHECK: ret i64 42
+// CHECK: }
+
+unsigned unsignedfunc() { return 42u; }
+// CHECK: define{{.*}} i32 @unsignedfunc() {
+// CHECK: ret i32 42
+// CHECK: }
+
+unsigned long long ullfunc() { return 42ull; }
+// CHECK: define{{.*}} i64 @ullfunc() {
+// CHECK: ret i64 42
+// CHECK: }
+
+bool boolfunc() { return true; }
+// CHECK: define{{.*}} i1 @boolfunc() {
+// CHECK: ret i1 true
+// CHECK: }
diff --git a/clang/test/CIR/Lowering/global-var-simple.cpp b/clang/test/CIR/Lowering/global-var-simple.cpp
index a5adb4011931a..ab8c6660a311b 100644
--- a/clang/test/CIR/Lowering/global-var-simple.cpp
+++ b/clang/test/CIR/Lowering/global-var-simple.cpp
@@ -62,6 +62,9 @@ _BitInt(20) sb20;
unsigned _BitInt(48) ub48;
// CHECK: @ub48 = external dso_local global i48
+bool boolfalse = false;
+// CHECK: @boolfalse = dso_local global i8 0
+
_Float16 f16;
// CHECK: @f16 = external dso_local global half
More information about the cfe-commits
mailing list