https://github.com/Lancern created 
https://github.com/llvm/llvm-project/pull/134673

This PR upstreams initial support for making function calls in CIR. Function 
arguments and return values are not included to keep the patch small for review.

Related to #132487

>From 82f6ce93ca22dd778173100231523706e2739546 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlanc...@gmail.com>
Date: Mon, 7 Apr 2025 22:54:49 +0800
Subject: [PATCH] [CIR] Upstream initial function call support

---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      | 13 +++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 37 +++++++
 .../clang/CIR/Interfaces/CIROpInterfaces.td   |  9 ++
 clang/include/clang/CIR/MissingFeatures.h     | 24 +++++
 clang/lib/CIR/CodeGen/CIRGenCall.cpp          | 95 ++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenCall.h            | 58 +++++++++++
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          | 97 +++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp    | 13 +++
 clang/lib/CIR/CodeGen/CIRGenFunction.h        | 20 ++++
 clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h    | 34 +++++++
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        | 13 ++-
 clang/lib/CIR/CodeGen/CIRGenModule.h          |  6 ++
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp         | 30 ++++++
 clang/lib/CIR/CodeGen/CIRGenTypes.h           | 11 +++
 clang/lib/CIR/CodeGen/CMakeLists.txt          |  1 +
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 81 ++++++++++++++++
 clang/test/CIR/CodeGen/call.cpp               |  9 ++
 17 files changed, 550 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/CIR/CodeGen/CIRGenCall.cpp
 create mode 100644 clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
 create mode 100644 clang/test/CIR/CodeGen/call.cpp

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index c1e93fe790c08..dda3ecf492506 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -201,6 +201,19 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return create<cir::PtrStrideOp>(loc, base.getType(), base, stride);
   }
 
+  
//===--------------------------------------------------------------------===//
+  // Call operators
+  
//===--------------------------------------------------------------------===//
+
+  cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee) {
+    auto op = create<cir::CallOp>(loc, callee);
+    return op;
+  }
+
+  cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee) {
+    return createCallOp(loc, mlir::SymbolRefAttr::get(callee));
+  }
+
   
//===--------------------------------------------------------------------===//
   // Cast/Conversion Operators
   
//===--------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 609e60ca74b49..aa805ee4108da 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1242,6 +1242,43 @@ def FuncOp : CIR_Op<"func", [
   let hasVerifier = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// CallOp
+//===----------------------------------------------------------------------===//
+
+class CIR_CallOp<string mnemonic, list<Trait> extra_traits = []>
+    : Op<CIR_Dialect, mnemonic,
+         !listconcat(extra_traits,
+                     [DeclareOpInterfaceMethods<CIRCallOpInterface>,
+                      DeclareOpInterfaceMethods<SymbolUserOpInterface>])> {
+  let hasCustomAssemblyFormat = 1;
+  let skipDefaultBuilders = 1;
+  let hasVerifier = 0;
+
+  dag commonArgs = (ins FlatSymbolRefAttr:$callee);
+}
+
+def CallOp : CIR_CallOp<"call", [NoRegionArguments]> {
+  let summary = "call a function";
+  let description = [{
+    The `cir.call` operation represents a direct call to a function that is
+    within the same symbol scope as the call. The callee is encoded as a symbol
+    reference attribute named `callee`.
+
+    Example:
+
+    ```mlir
+    %0 = cir.call @foo()
+    ```
+  }];
+
+  let arguments = commonArgs;
+
+  let builders = [OpBuilder<(ins "mlir::SymbolRefAttr":$callee), [{
+      $_state.addAttribute("callee", callee);
+    }]>];
+}
+
 
//===----------------------------------------------------------------------===//
 // UnreachableOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td 
b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
index 39ef402c59e43..c6c6356118ac6 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
@@ -15,8 +15,17 @@
 
 include "mlir/IR/OpBase.td"
 include "mlir/IR/SymbolInterfaces.td"
+include "mlir/Interfaces/CallInterfaces.td"
 
 let cppNamespace = "::cir" in {
+  // The CIRCallOpInterface must be used instead of CallOpInterface when 
looking
+  // at arguments and other bits of CallOp. This creates a level of abstraction
+  // that's useful for handling indirect calls and other details.
+  def CIRCallOpInterface : OpInterface<"CIRCallOpInterface", []> {
+    // Currently we don't have any methods defined in CIRCallOpInterface. We'll
+    // add more methods as the upstreaming proceeds.
+  }
+
   def CIRGlobalValueInterface
       : OpInterface<"CIRGlobalValueInterface", [Symbol]> {
 
diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 86fdaf1ddaf51..491fb31c4b7e2 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -72,6 +72,24 @@ struct MissingFeatures {
   static bool opFuncLinkage() { return false; }
   static bool opFuncVisibility() { return false; }
 
+  // CallOp handling
+  static bool opCallBuiltinFunc() { return false; }
+  static bool opCallPseudoDtor() { return false; }
+  static bool opCallArgs() { return false; }
+  static bool opCallReturn() { return false; }
+  static bool opCallArgEvaluationOrder() { return false; }
+  static bool opCallCallConv() { return false; }
+  static bool opCallSideEffect() { return false; }
+  static bool opCallChainCall() { return false; }
+  static bool opCallNoPrototypeFunc() { return false; }
+  static bool opCallMustTail() { return false; }
+  static bool opCallIndirect() { return false; }
+  static bool opCallVirtual() { return false; }
+  static bool opCallInAlloca() { return false; }
+  static bool opCallAttrs() { return false; }
+  static bool opCallSurroundingTry() { return false; }
+  static bool opCallASTAttr() { return false; }
+
   // ScopeOp handling
   static bool opScopeCleanupRegion() { return false; }
 
@@ -90,7 +108,10 @@ struct MissingFeatures {
   static bool opTBAA() { return false; }
   static bool opCmp() { return false; }
   static bool objCLifetime() { return false; }
+  static bool objCBlocks() { return false; }
   static bool emitNullabilityCheck() { return false; }
+  static bool emitLValueAlignmentAssumption() { return false; }
+  static bool emitLifetimeMarkers() { return false; }
   static bool astVarDeclInterface() { return false; }
   static bool stackSaveOp() { return false; }
   static bool aggValueSlot() { return false; }
@@ -108,6 +129,8 @@ struct MissingFeatures {
   static bool cgFPOptionsRAII() { return false; }
   static bool metaDataNode() { return false; }
   static bool fastMathFlags() { return false; }
+  static bool weakRefReference() { return false; }
+  static bool hip() { return false; }
 
   // Missing types
   static bool dataMemberType() { return false; }
@@ -127,6 +150,7 @@ struct MissingFeatures {
   static bool complexImagOp() { return false; }
   static bool complexRealOp() { return false; }
   static bool ifOp() { return false; }
+  static bool invokeOp() { return false; }
   static bool labelOp() { return false; }
   static bool ptrDiffOp() { return false; }
   static bool ptrStrideOp() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
new file mode 100644
index 0000000000000..1a936458782ea
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -0,0 +1,95 @@
+//===--- CIRGenCall.cpp - Encapsulate calling convention details 
----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function definition used
+// to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenCall.h"
+#include "CIRGenFunction.h"
+#include "clang/CIR/MissingFeatures.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+CIRGenFunctionInfo *CIRGenFunctionInfo::create() {
+  // For now we just create an empty CIRGenFunctionInfo.
+  CIRGenFunctionInfo *fi = new CIRGenFunctionInfo();
+  return fi;
+}
+
+CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
+  assert(!cir::MissingFeatures::opCallVirtual());
+  return *this;
+}
+
+static const CIRGenFunctionInfo &arrangeFreeFunctionLikeCall(CIRGenTypes &cgt) 
{
+  assert(!cir::MissingFeatures::opCallArgs());
+  return cgt.arrangeCIRFunctionInfo();
+}
+
+const CIRGenFunctionInfo &CIRGenTypes::arrangeFreeFunctionCall() {
+  return arrangeFreeFunctionLikeCall(*this);
+}
+
+static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf,
+                                              mlir::Location callLoc,
+                                              cir::FuncOp directFuncOp) {
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+
+  assert(!cir::MissingFeatures::opCallSurroundingTry());
+  assert(!cir::MissingFeatures::invokeOp());
+
+  assert(builder.getInsertionBlock() && "expected valid basic block");
+  assert(!cir::MissingFeatures::opCallIndirect());
+
+  return builder.createCallOp(callLoc, directFuncOp);
+}
+
+RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
+                                const CIRGenCallee &callee,
+                                cir::CIRCallOpInterface *callOp,
+                                mlir::Location loc) {
+  assert(!cir::MissingFeatures::opCallArgs());
+  assert(!cir::MissingFeatures::emitLifetimeMarkers());
+
+  const CIRGenCallee &concreteCallee = callee.prepareConcreteCallee(*this);
+  mlir::Operation *calleePtr = concreteCallee.getFunctionPointer();
+
+  assert(!cir::MissingFeatures::opCallInAlloca());
+
+  mlir::NamedAttrList attrs;
+  StringRef funcName;
+  if (auto calleeFuncOp = dyn_cast<cir::FuncOp>(calleePtr))
+    funcName = calleeFuncOp.getName();
+
+  assert(!cir::MissingFeatures::opCallCallConv());
+  assert(!cir::MissingFeatures::opCallSideEffect());
+  assert(!cir::MissingFeatures::opCallAttrs());
+
+  assert(!cir::MissingFeatures::invokeOp());
+
+  auto directFuncOp = dyn_cast<cir::FuncOp>(calleePtr);
+  assert(!cir::MissingFeatures::opCallIndirect());
+  assert(!cir::MissingFeatures::opCallAttrs());
+
+  cir::CIRCallOpInterface theCall = emitCallLikeOp(*this, loc, directFuncOp);
+
+  if (callOp)
+    *callOp = theCall;
+
+  assert(!cir::MissingFeatures::opCallMustTail());
+  assert(!cir::MissingFeatures::opCallReturn());
+
+  // For now we just return nothing because we don't have support for return
+  // values yet.
+  RValue ret = RValue::get(nullptr);
+
+  return ret;
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h 
b/clang/lib/CIR/CodeGen/CIRGenCall.h
index 0996167feeef6..76fefdca9e45e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.h
@@ -14,15 +14,73 @@
 #ifndef CLANG_LIB_CODEGEN_CIRGENCALL_H
 #define CLANG_LIB_CODEGEN_CIRGENCALL_H
 
+#include "mlir/IR/Operation.h"
 #include "clang/AST/GlobalDecl.h"
 #include "llvm/ADT/SmallVector.h"
 
 namespace clang::CIRGen {
 
+class CIRGenFunction;
+
+/// Abstract information about a function or function prototype.
+class CIRGenCalleeInfo {
+  clang::GlobalDecl calleeDecl;
+
+public:
+  explicit CIRGenCalleeInfo() : calleeDecl() {}
+  CIRGenCalleeInfo(clang::GlobalDecl calleeDecl) : calleeDecl(calleeDecl) {}
+};
+
+class CIRGenCallee {
+  enum class SpecialKind : uintptr_t {
+    Invalid,
+
+    Last = Invalid,
+  };
+
+  SpecialKind kindOrFunctionPtr;
+
+  union {
+    CIRGenCalleeInfo abstractInfo;
+  };
+
+public:
+  CIRGenCallee() : kindOrFunctionPtr(SpecialKind::Invalid) {}
+
+  CIRGenCallee(const CIRGenCalleeInfo &abstractInfo, mlir::Operation *funcPtr)
+      : kindOrFunctionPtr(SpecialKind(reinterpret_cast<uintptr_t>(funcPtr))),
+        abstractInfo(abstractInfo) {
+    assert(funcPtr && "configuring callee without function pointer");
+  }
+
+  static CIRGenCallee
+  forDirect(mlir::Operation *funcPtr,
+            const CIRGenCalleeInfo &abstractInfo = CIRGenCalleeInfo()) {
+    return CIRGenCallee(abstractInfo, funcPtr);
+  }
+
+  bool isOrdinary() const {
+    return uintptr_t(kindOrFunctionPtr) > uintptr_t(SpecialKind::Last);
+  }
+
+  /// If this is a delayed callee computation of some sort, prepare a concrete
+  /// callee
+  CIRGenCallee prepareConcreteCallee(CIRGenFunction &cgf) const;
+
+  mlir::Operation *getFunctionPointer() const {
+    assert(isOrdinary());
+    return reinterpret_cast<mlir::Operation *>(kindOrFunctionPtr);
+  }
+};
+
 /// Type for representing both the decl and type of parameters to a function.
 /// The decl must be either a ParmVarDecl or ImplicitParamDecl.
 class FunctionArgList : public llvm::SmallVector<const clang::VarDecl *, 16> 
{};
 
+struct CallArg {};
+
+class CallArgList : public llvm::SmallVector<CallArg, 8> {};
+
 } // namespace clang::CIRGen
 
 #endif // CLANG_LIB_CODEGEN_CIRGENCALL_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index f01e03a89981d..1e5fb985b0b8c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/MissingFeatures.h"
 
@@ -304,6 +305,102 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e) {
   llvm_unreachable("bad evaluation kind");
 }
 
+static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
+  assert(!cir::MissingFeatures::weakRefReference());
+  return cgm.getAddrOfFunction(gd);
+}
+
+static CIRGenCallee emitDirectCallee(CIRGenModule &cgm, GlobalDecl gd) {
+  assert(!cir::MissingFeatures::opCallBuiltinFunc());
+
+  cir::FuncOp callee = emitFunctionDeclPointer(cgm, gd);
+
+  assert(!cir::MissingFeatures::hip());
+
+  return CIRGenCallee::forDirect(callee, gd);
+}
+
+RValue CIRGenFunction::emitCall(clang::QualType calleeTy,
+                                const CIRGenCallee &callee,
+                                const clang::CallExpr *e) {
+  // Get the actual function type. The callee type will always be a pointer to
+  // function type or a block pointer type.
+  assert(calleeTy->isFunctionPointerType() &&
+         "Callee must have function pointer type!");
+
+  calleeTy = getContext().getCanonicalType(calleeTy);
+
+  if (getLangOpts().CPlusPlus)
+    assert(!cir::MissingFeatures::sanitizers());
+
+  assert(!cir::MissingFeatures::sanitizers());
+  assert(!cir::MissingFeatures::opCallArgs());
+
+  const CIRGenFunctionInfo &funcInfo = 
cgm.getTypes().arrangeFreeFunctionCall();
+
+  assert(!cir::MissingFeatures::opCallNoPrototypeFunc());
+  assert(!cir::MissingFeatures::opCallChainCall());
+  assert(!cir::MissingFeatures::hip());
+  assert(!cir::MissingFeatures::opCallMustTail());
+
+  cir::CIRCallOpInterface callOp;
+  RValue callResult =
+      emitCall(funcInfo, callee, &callOp, getLoc(e->getExprLoc()));
+
+  assert(!cir::MissingFeatures::generateDebugInfo());
+
+  return callResult;
+}
+
+CIRGenCallee CIRGenFunction::emitCallee(const clang::Expr *e) {
+  e = e->IgnoreParens();
+
+  // Look through function-to-pointer decay.
+  if (const auto *implicitCast = dyn_cast<ImplicitCastExpr>(e)) {
+    if (implicitCast->getCastKind() == CK_FunctionToPointerDecay ||
+        implicitCast->getCastKind() == CK_BuiltinFnToFnPtr) {
+      return emitCallee(implicitCast->getSubExpr());
+    }
+    // Resolve direct calls.
+  } else if (const auto *declRef = dyn_cast<DeclRefExpr>(e)) {
+    const auto *funcDecl = dyn_cast<FunctionDecl>(declRef->getDecl());
+    assert(
+        funcDecl &&
+        "DeclRef referring to FunctionDecl is the only thing supported so 
far");
+    return emitDirectCallee(cgm, funcDecl);
+  }
+
+  llvm_unreachable("Nothing else supported yet!");
+}
+
+RValue CIRGenFunction::emitCallExpr(const clang::CallExpr *e) {
+  assert(!cir::MissingFeatures::objCBlocks());
+
+  if (isa<CXXMemberCallExpr>(e)) {
+    cgm.errorNYI(e->getSourceRange(), "call to member function");
+    return RValue::get(nullptr);
+  }
+
+  if (isa<CUDAKernelCallExpr>(e)) {
+    cgm.errorNYI(e->getSourceRange(), "call to CUDA kernel");
+    return RValue::get(nullptr);
+  }
+
+  if (const auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(e)) {
+    if (isa_and_nonnull<CXXMethodDecl>(operatorCall->getCalleeDecl())) {
+      cgm.errorNYI(e->getSourceRange(), "call to member operator");
+      return RValue::get(nullptr);
+    }
+  }
+
+  CIRGenCallee callee = emitCallee(e->getCallee());
+
+  assert(!cir::MissingFeatures::opCallBuiltinFunc());
+  assert(!cir::MissingFeatures::opCallPseudoDtor());
+
+  return emitCall(e->getCallee()->getType(), callee, e);
+}
+
 /// Emit code to compute the specified expression, ignoring the result.
 void CIRGenFunction::emitIgnoredExpr(const Expr *e) {
   if (e->isPRValue()) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 3863d21487531..ca6f35e0f7319 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -156,6 +156,7 @@ class ScalarExprEmitter : public 
StmtVisitor<ScalarExprEmitter, mlir::Value> {
   }
 
   mlir::Value VisitCastExpr(CastExpr *e);
+  mlir::Value VisitCallExpr(const CallExpr *e);
 
   mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {
     return VisitCastExpr(e);
@@ -1345,6 +1346,18 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr 
*ce) {
   return {};
 }
 
+mlir::Value ScalarExprEmitter::VisitCallExpr(const CallExpr *e) {
+  if (e->getCallReturnType(cgf.getContext())->isReferenceType()) {
+    cgf.getCIRGenModule().errorNYI(
+        e->getSourceRange(), "call to function with non-void return type");
+    return {};
+  }
+
+  auto v = cgf.emitCallExpr(e).getScalarVal();
+  assert(!cir::MissingFeatures::emitLValueAlignmentAssumption());
+  return v;
+}
+
 mlir::Value CIRGenFunction::emitScalarConversion(mlir::Value src,
                                                  QualType srcTy, QualType 
dstTy,
                                                  SourceLocation loc) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 1bedbe28ae625..1a0ab51c759f5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -403,6 +403,26 @@ class CIRGenFunction : public CIRGenTypeCache {
   mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s);
   mlir::LogicalResult emitDoStmt(const clang::DoStmt &s);
 
+  /// An abstract representation of regular/ObjC call/message targets.
+  class AbstractCallee {
+    /// The function declaration of the callee.
+    const clang::Decl *calleeDecl;
+
+  public:
+    AbstractCallee() : calleeDecl(nullptr) {}
+    AbstractCallee(const clang::FunctionDecl *fd) : calleeDecl(fd) {}
+  };
+
+  RValue emitCall(const CIRGenFunctionInfo &funcInfo,
+                  const CIRGenCallee &callee, cir::CIRCallOpInterface *callOp,
+                  mlir::Location loc);
+  RValue emitCall(clang::QualType calleeTy, const CIRGenCallee &callee,
+                  const clang::CallExpr *e);
+
+  CIRGenCallee emitCallee(const clang::Expr *e);
+
+  RValue emitCallExpr(const clang::CallExpr *e);
+
   /// Emit an expression as an initializer for an object (variable, field, 
etc.)
   /// at the given location.  The expression is not necessarily the normal
   /// initializer for the object, and the address is not necessarily
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h 
b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
new file mode 100644
index 0000000000000..37191ee300eda
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
@@ -0,0 +1,34 @@
+//==-- CIRGenFunctionInfo.h - Representation of fn argument/return types 
---==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines CIRGenFunctionInfo and associated types used in representing the
+// CIR source types and ABI-coerced types for function arguments and
+// return values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CIR_CIRGENFUNCTIONINFO_H
+#define LLVM_CLANG_CIR_CIRGENFUNCTIONINFO_H
+
+#include "llvm/ADT/FoldingSet.h"
+
+namespace clang::CIRGen {
+
+class CIRGenFunctionInfo final : public llvm::FoldingSetNode {
+public:
+  static CIRGenFunctionInfo *create();
+
+  // NOLINTNEXTLINE(readability-identifier-naming)
+  static void Profile(llvm::FoldingSetNodeID &id) {
+    // We don't have anything to profile yet.
+  }
+};
+
+} // namespace clang::CIRGen
+
+#endif
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index d3b3b0632c2f0..a07a1e3d52e2c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -133,10 +133,12 @@ void 
CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
   }
 
   CIRGenFunction cgf(*this, builder);
+  curCGF = &cgf;
   {
     mlir::OpBuilder::InsertionGuard guard(builder);
     cgf.generateCode(gd, funcOp, funcType);
   }
+  curCGF = nullptr;
 }
 
 void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
@@ -466,8 +468,17 @@ CIRGenModule::createCIRFunction(mlir::Location loc, 
StringRef name,
   {
     mlir::OpBuilder::InsertionGuard guard(builder);
 
+    // Some global emissions are triggered while emitting a function, e.g.
+    // void s() { x.method() }
+    //
+    // Be sure to insert a new function before a current one.
+    if (curCGF)
+      builder.setInsertionPoint(curCGF->curFn);
+
     func = builder.create<cir::FuncOp>(loc, name, funcType);
-    theModule.push_back(func);
+
+    if (!curCGF)
+      theModule.push_back(func);
   }
   return func;
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 6ba1ccc4ddd9f..7ee24699b521e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -41,6 +41,8 @@ class VarDecl;
 
 namespace CIRGen {
 
+class CIRGenFunction;
+
 enum ForDefinition_t : bool { NotForDefinition = false, ForDefinition = true };
 
 /// This class organizes the cross-function state that is used while generating
@@ -75,6 +77,10 @@ class CIRGenModule : public CIRGenTypeCache {
 
   CIRGenTypes genTypes;
 
+  /// Per-function codegen information. Updated everytime emitCIR is called
+  /// for FunctionDecls's.
+  CIRGenFunction *curCGF = nullptr;
+
 public:
   mlir::ModuleOp getModule() const { return theModule; }
   CIRGenBuilderTy &getBuilder() { return builder; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 1e47ccc451b86..6be11a9d5a7ff 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -281,3 +281,33 @@ bool CIRGenTypes::isZeroInitializable(clang::QualType t) {
 
   return true;
 }
+
+const CIRGenFunctionInfo &CIRGenTypes::arrangeCIRFunctionInfo() {
+  // Lookup or create unique function info.
+  llvm::FoldingSetNodeID id;
+  CIRGenFunctionInfo::Profile(id);
+
+  void *insertPos = nullptr;
+  CIRGenFunctionInfo *fi = functionInfos.FindNodeOrInsertPos(id, insertPos);
+  if (fi)
+    return *fi;
+
+  assert(!cir::MissingFeatures::opCallCallConv());
+
+  // Construction the function info. We co-allocate the ArgInfos.
+  fi = CIRGenFunctionInfo::create();
+  functionInfos.InsertNode(fi, insertPos);
+
+  bool inserted = functionsBeingProcessed.insert(fi).second;
+  (void)inserted;
+  assert(inserted && "Recursively being processed?");
+
+  assert(!cir::MissingFeatures::opCallCallConv());
+  assert(!cir::MissingFeatures::opCallArgs());
+
+  bool erased = functionsBeingProcessed.erase(fi);
+  (void)erased;
+  assert(erased && "Not in set?");
+
+  return *fi;
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h 
b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index 73948f5c63e6a..ca43f96ed78a6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
 #define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
 
+#include "CIRGenFunctionInfo.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 
 #include "clang/AST/Type.h"
@@ -33,6 +34,7 @@ class Type;
 
 namespace clang::CIRGen {
 
+class CallArgList;
 class CIRGenBuilderTy;
 class CIRGenModule;
 
@@ -43,6 +45,11 @@ class CIRGenTypes {
   clang::ASTContext &astContext;
   CIRGenBuilderTy &builder;
 
+  /// Hold memoized CIRGenFunctionInfo results
+  llvm::FoldingSet<CIRGenFunctionInfo> functionInfos;
+
+  llvm::SmallPtrSet<const CIRGenFunctionInfo *, 4> functionsBeingProcessed;
+
   /// Heper for convertType.
   mlir::Type convertFunctionTypeInternal(clang::QualType ft);
 
@@ -75,6 +82,10 @@ class CIRGenTypes {
   /// Return whether a type can be zero-initialized (in the C++ sense) with an
   /// LLVM zeroinitializer.
   bool isZeroInitializable(clang::QualType t);
+
+  const CIRGenFunctionInfo &arrangeFreeFunctionCall();
+
+  const CIRGenFunctionInfo &arrangeCIRFunctionInfo();
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt 
b/clang/lib/CIR/CodeGen/CMakeLists.txt
index da8d63ca569af..794a63ba36d50 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -8,6 +8,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
 
 add_clang_library(clangCIR
   CIRGenerator.cpp
+  CIRGenCall.cpp
   CIRGenDecl.cpp
   CIRGenExpr.cpp
   CIRGenExprAggregate.cpp
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 798aca602c4e3..6ff798c46691e 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -441,6 +441,87 @@ OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {
   return tryFoldCastChain(*this);
 }
 
+//===----------------------------------------------------------------------===//
+// CallOp
+//===----------------------------------------------------------------------===//
+
+static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
+                                         mlir::OperationState &result) {
+  mlir::FlatSymbolRefAttr calleeAttr;
+
+  if (!parser.parseOptionalAttribute(calleeAttr, "callee", result.attributes)
+           .has_value())
+    return mlir::failure();
+
+  if (parser.parseLParen())
+    return mlir::failure();
+
+  // TODO(cir): parse argument list here
+
+  if (parser.parseRParen())
+    return mlir::failure();
+
+  if (parser.parseOptionalAttrDict(result.attributes))
+    return ::mlir::failure();
+
+  if (parser.parseColon())
+    return ::mlir::failure();
+
+  mlir::FunctionType opsFnTy;
+  if (parser.parseType(opsFnTy))
+    return mlir::failure();
+
+  return mlir::success();
+}
+
+static void printCallCommon(mlir::Operation *op,
+                            mlir::FlatSymbolRefAttr calleeSym,
+                            mlir::OpAsmPrinter &printer) {
+  printer << ' ';
+
+  printer.printAttributeWithoutType(calleeSym);
+  printer << "(";
+  // TODO(cir): print call args here
+  printer << ")";
+
+  printer.printOptionalAttrDict(op->getAttrs(), {"callee"});
+
+  printer << " : ";
+  printer.printFunctionalType(op->getOperands().getTypes(),
+                              op->getResultTypes());
+}
+
+mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser,
+                                     mlir::OperationState &result) {
+  return parseCallCommon(parser, result);
+}
+
+void cir::CallOp::print(mlir::OpAsmPrinter &p) {
+  printCallCommon(*this, getCalleeAttr(), p);
+}
+
+static LogicalResult
+verifyCallCommInSymbolUses(mlir::Operation *op,
+                           SymbolTableCollection &symbolTable) {
+  auto fnAttr = op->getAttrOfType<FlatSymbolRefAttr>("callee");
+  if (!fnAttr)
+    return mlir::failure();
+
+  auto fn = symbolTable.lookupNearestSymbolFrom<cir::FuncOp>(op, fnAttr);
+  if (!fn)
+    return op->emitOpError() << "'" << fnAttr.getValue()
+                             << "' does not reference a valid function";
+
+  // TODO(cir): verify function arguments and return type
+
+  return mlir::success();
+}
+
+LogicalResult
+cir::CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
+  return verifyCallCommInSymbolUses(*this, symbolTable);
+}
+
 
//===----------------------------------------------------------------------===//
 // ReturnOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/CodeGen/call.cpp b/clang/test/CIR/CodeGen/call.cpp
new file mode 100644
index 0000000000000..e69b347c2ca99
--- /dev/null
+++ b/clang/test/CIR/CodeGen/call.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir %s -o - 2>&1 | FileCheck %s
+
+void f1();
+void f2() {
+  f1();
+}
+
+// CHECK-LABEL: cir.func @f2
+// CHECK:         cir.call @f1() : () -> ()

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to