[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