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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits