Skip to content

[CIR] Upstream support for C++ member function calls #140290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 19, 2025

Conversation

andykaylor
Copy link
Contributor

This change adds the support needed to handle a C++ member function call, including arranging the function type with an argument added for the 'this' parameter. It was necessary to introduce the class to handle the CXXABI, but at this time no target-specific subclasses have been added.

This change adds the support needed to handle a C++ member function call,
including arranging the function type with an argument added for the
'this' parameter. It was necessary to introduce the class to handle the
CXXABI, but at this time no target-specific subclasses have been added.
@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels May 16, 2025
@llvmbot
Copy link
Member

llvmbot commented May 16, 2025

@llvm/pr-subscribers-clangir

Author: Andy Kaylor (andykaylor)

Changes

This change adds the support needed to handle a C++ member function call, including arranging the function type with an argument added for the 'this' parameter. It was necessary to introduce the class to handle the CXXABI, but at this time no target-specific subclasses have been added.


Patch is 32.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140290.diff

14 Files Affected:

  • (modified) clang/include/clang/CIR/MissingFeatures.h (+10-1)
  • (added) clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp (+45)
  • (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.h (+26-1)
  • (added) clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp (+186)
  • (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+92-5)
  • (modified) clang/lib/CIR/CodeGen/CIRGenCall.h (+8)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+32-5)
  • (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+8-2)
  • (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+15)
  • (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+11-4)
  • (modified) clang/lib/CIR/CodeGen/CIRGenTypes.cpp (+1-1)
  • (modified) clang/lib/CIR/CodeGen/CIRGenTypes.h (+22)
  • (modified) clang/lib/CIR/CodeGen/CMakeLists.txt (+2)
  • (added) clang/test/CIR/CodeGen/member-functions.cpp (+44)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 484822c351746..a4324053ba476 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -90,7 +90,6 @@ struct MissingFeatures {
   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; }
@@ -107,6 +106,13 @@ struct MissingFeatures {
   static bool opCallLandingPad() { return false; }
   static bool opCallContinueBlock() { return false; }
 
+  // FnInfoOpts -- This is used to track whether calls are chain calls or
+  // instance methods. Classic codegen uses chain call to track and extra free
+  // register for x86 and uses instance method as a condition for a thunk
+  // generation special case. It's not clear that we need either of these in
+  // pre-lowering CIR codegen.
+  static bool opCallFnInfoOpts() { return false; }
+
   // ScopeOp handling
   static bool opScopeCleanupRegion() { return false; }
 
@@ -189,6 +195,9 @@ struct MissingFeatures {
   static bool constEmitterArrayILE() { return false; }
   static bool constEmitterVectorILE() { return false; }
   static bool needsGlobalCtorDtor() { return false; }
+  static bool emitTypeCheck() { return false; }
+  static bool cxxabiThisDecl() { return false; }
+  static bool cxxabiThisAlignment() { return false; }
 
   // Missing types
   static bool dataMemberType() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
new file mode 100644
index 0000000000000..fcd45768656ff
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
@@ -0,0 +1,45 @@
+//===----- CirGenCXXABI.cpp - Interface to C++ ABIs -----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for C++ code generation. Concrete subclasses
+// of this implement code generation for specific C++ ABIs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenCXXABI.h"
+#include "CIRGenFunction.h"
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/GlobalDecl.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+CIRGenCXXABI::~CIRGenCXXABI() {}
+
+void CIRGenCXXABI::buildThisParam(CIRGenFunction &cgf,
+                                  FunctionArgList &params) {
+  const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
+
+  // FIXME: I'm not entirely sure I like using a fake decl just for code
+  // generation. Maybe we can come up with a better way?
+  auto *thisDecl =
+      ImplicitParamDecl::Create(cgm.getASTContext(), nullptr, md->getLocation(),
+                                &cgm.getASTContext().Idents.get("this"),
+                                md->getThisType(), ImplicitParamKind::CXXThis);
+  params.push_back(thisDecl);
+
+  // Classic codegen save thisDecl in CodeGenFunction::CXXABIThisDecl, but it
+  // doesn't seem to be needed in CIRGen.
+  assert(!cir::MissingFeatures::cxxabiThisDecl());
+
+  // Classic codegen computes the alignment of thisDecl and saves it in
+  // CodeGenFunction::CXXABIThisAlignment, but it doesn't seem to be needed in
+  // CIRGen.
+  assert(!cir::MissingFeatures::cxxabiThisAlignment());
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 5279307e19613..b5c33a29442c7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
 #define LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
 
+#include "CIRGenCall.h"
 #include "CIRGenModule.h"
 
 #include "clang/AST/Mangle.h"
@@ -31,9 +32,33 @@ class CIRGenCXXABI {
   // implemented.
   CIRGenCXXABI(CIRGenModule &cgm)
       : cgm(cgm), mangleContext(cgm.getASTContext().createMangleContext()) {}
-  ~CIRGenCXXABI();
+  virtual ~CIRGenCXXABI();
 
 public:
+  /// Get the type of the implicit "this" parameter used by a method. May return
+  /// zero if no specific type is applicable, e.g. if the ABI expects the "this"
+  /// parameter to point to some artificial offset in a complete object due to
+  /// vbases being reordered.
+  virtual const clang::CXXRecordDecl *
+  getThisArgumentTypeForMethod(const clang::CXXMethodDecl *md) {
+    return md->getParent();
+  }
+
+  /// Build a parameter variable suitable for 'this'.
+  void buildThisParam(CIRGenFunction &cgf, FunctionArgList &params);
+
+  /// Returns true if the given constructor or destructor is one of the kinds
+  /// that the ABI says returns 'this' (only applies when called non-virtually
+  /// for destructors).
+  ///
+  /// There currently is no way to indicate if a destructor returns 'this' when
+  /// called virtually, and CIR generation does not support this case.
+  virtual bool hasThisReturn(clang::GlobalDecl gd) const { return false; }
+
+  virtual bool hasMostDerivedReturn(clang::GlobalDecl gd) const {
+    return false;
+  }
+
   /// Gets the mangle context.
   clang::MangleContext &getMangleContext() { return *mangleContext; }
 };
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp
new file mode 100644
index 0000000000000..906c212f0fa8a
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp
@@ -0,0 +1,186 @@
+//===--- CIRGenExprCXX.cpp - Emit CIR Code for C++ expressions ------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with code generation of C++ expressions
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenCXXABI.h"
+#include "CIRGenFunction.h"
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/CIR/MissingFeatures.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+namespace {
+struct MemberCallInfo {
+  RequiredArgs reqArgs;
+  // Number of prefix arguments for the call. Ignores the `this` pointer.
+  unsigned prefixSize;
+};
+} // namespace
+
+static MemberCallInfo commonBuildCXXMemberOrOperatorCall(
+    CIRGenFunction &cgf, const CXXMethodDecl *md, mlir::Value thisPtr,
+    mlir::Value implicitParam, QualType implicitParamTy, const CallExpr *ce,
+    CallArgList &args, CallArgList *rtlArgs) {
+  assert(ce == nullptr || isa<CXXMemberCallExpr>(ce) ||
+         isa<CXXOperatorCallExpr>(ce));
+  assert(md->isInstance() &&
+         "Trying to emit a member or operator call expr on a static method!");
+
+  // Push the this ptr.
+  const CXXRecordDecl *rd =
+      cgf.cgm.getCXXABI().getThisArgumentTypeForMethod(md);
+  args.add(RValue::get(thisPtr), cgf.getTypes().deriveThisType(rd, md));
+
+  // If there is an implicit parameter (e.g. VTT), emit it.
+  if (implicitParam) {
+    args.add(RValue::get(implicitParam), implicitParamTy);
+  }
+
+  const auto *fpt = md->getType()->castAs<FunctionProtoType>();
+  RequiredArgs required =
+      RequiredArgs::getFromProtoWithExtraSlots(fpt, args.size());
+  unsigned prefixSize = args.size() - 1;
+
+  // Add the rest of the call args
+  if (rtlArgs) {
+    // Special case: if the caller emitted the arguments right-to-left already
+    // (prior to emitting the *this argument), we're done. This happens for
+    // assignment operators.
+    args.addFrom(*rtlArgs);
+  } else if (ce) {
+    // Special case: skip first argument of CXXOperatorCall (it is "this").
+    unsigned argsToSkip = isa<CXXOperatorCallExpr>(ce) ? 1 : 0;
+    cgf.emitCallArgs(args, fpt, drop_begin(ce->arguments(), argsToSkip),
+                     ce->getDirectCallee());
+  } else {
+    assert(
+        fpt->getNumParams() == 0 &&
+        "No CallExpr specified for function with non-zero number of arguments");
+  }
+
+  //  return {required, prefixSize};
+  return {required, prefixSize};
+}
+
+RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr(
+    const CallExpr *ce, const CXXMethodDecl *md, ReturnValueSlot returnValue,
+    bool hasQualifier, NestedNameSpecifier *qualifier, bool isArrow,
+    const Expr *base) {
+  assert(isa<CXXMemberCallExpr>(ce) || isa<CXXOperatorCallExpr>(ce));
+
+  if (md->isVirtual()) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: virtual call");
+    return RValue::get(nullptr);
+  }
+
+  bool trivialForCodegen =
+      md->isTrivial() || (md->isDefaulted() && md->getParent()->isUnion());
+  bool trivialAssignment =
+      trivialForCodegen &&
+      (md->isCopyAssignmentOperator() || md->isMoveAssignmentOperator()) &&
+      !md->getParent()->mayInsertExtraPadding();
+  (void)trivialAssignment;
+
+  // C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
+  // operator before the LHS.
+  CallArgList rtlArgStorage;
+  CallArgList *rtlArgs = nullptr;
+  if (auto *oce = dyn_cast<CXXOperatorCallExpr>(ce)) {
+    cgm.errorNYI(oce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: operator call");
+    return RValue::get(nullptr);
+  }
+
+  LValue thisPtr;
+  if (isArrow) {
+    LValueBaseInfo baseInfo;
+    assert(!cir::MissingFeatures::opTBAA());
+    Address thisValue = emitPointerWithAlignment(base, &baseInfo);
+    thisPtr = makeAddrLValue(thisValue, base->getType(), baseInfo);
+  } else {
+    thisPtr = emitLValue(base);
+  }
+
+  if (const CXXConstructorDecl *ctor = dyn_cast<CXXConstructorDecl>(md)) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: constructor call");
+    return RValue::get(nullptr);
+  }
+
+  if (trivialForCodegen) {
+    if (isa<CXXDestructorDecl>(md))
+      return RValue::get(nullptr);
+
+    if (trivialAssignment) {
+      cgm.errorNYI(ce->getSourceRange(),
+                   "emitCXXMemberOrOperatorMemberCallExpr: trivial assignment");
+      return RValue::get(nullptr);
+    } else {
+      assert(md->getParent()->mayInsertExtraPadding() &&
+             "unknown trivial member function");
+    }
+  }
+
+  // Compute the function type we're calling
+  const CXXMethodDecl *calleeDecl = md;
+  const CIRGenFunctionInfo *fInfo = nullptr;
+  if (const auto *dtor = dyn_cast<CXXDestructorDecl>(calleeDecl)) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: destructor call");
+    return RValue::get(nullptr);
+  } else {
+    fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(calleeDecl);
+  }
+
+  mlir::Type ty = cgm.getTypes().getFunctionType(*fInfo);
+
+  assert(!cir::MissingFeatures::sanitizers());
+  assert(!cir::MissingFeatures::emitTypeCheck());
+
+  if (const auto *dtor = dyn_cast<CXXDestructorDecl>(calleeDecl)) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: destructor call");
+    return RValue::get(nullptr);
+  }
+
+  assert(!cir::MissingFeatures::sanitizers());
+  if (getLangOpts().AppleKext) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: AppleKext");
+    return RValue::get(nullptr);
+  }
+  CIRGenCallee callee =
+      CIRGenCallee::forDirect(cgm.getAddrOfFunction(md, ty), GlobalDecl(md));
+
+  return emitCXXMemberOrOperatorCall(
+      calleeDecl, callee, returnValue, thisPtr.getPointer(),
+      /*ImplicitParam=*/nullptr, QualType(), ce, rtlArgs);
+}
+
+RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
+    const CXXMethodDecl *md, const CIRGenCallee &callee,
+    ReturnValueSlot returnValue, mlir::Value thisPtr, mlir::Value implicitParam,
+    QualType implicitParamTy, const CallExpr *ce, CallArgList *rtlArgs) {
+  const auto *fpt = md->getType()->castAs<FunctionProtoType>();
+  CallArgList args;
+  MemberCallInfo callInfo = commonBuildCXXMemberOrOperatorCall(
+      *this, md, thisPtr, implicitParam, implicitParamTy, ce, args, rtlArgs);
+  auto &fnInfo = cgm.getTypes().arrangeCXXMethodCall(
+      args, fpt, callInfo.reqArgs, callInfo.prefixSize);
+  assert((ce || currSrcLoc) && "expected source location");
+  mlir::Location loc = ce ? getLoc(ce->getExprLoc()) : *currSrcLoc;
+  assert(!cir::MissingFeatures::opCallMustTail());
+  return emitCall(fnInfo, callee, returnValue, args, nullptr, loc);
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 17bfa19f9fd63..7590153410747 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CIRGenCall.h"
+#include "CIRGenCXXABI.h"
 #include "CIRGenFunction.h"
 #include "CIRGenFunctionInfo.h"
 #include "clang/CIR/MissingFeatures.h"
@@ -76,11 +77,30 @@ static void appendParameterTypes(const CIRGenTypes &cgt,
   cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos");
 }
 
+/// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR
+/// qualification. Either or both of `rd` and `md` may be null. A null `rd`
+/// indicates that there is no meaningful 'this' type, and a null `md` can occur
+/// when calling a method pointer.
+CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd,
+                                        const CXXMethodDecl *md) {
+  QualType recTy;
+  if (rd)
+    recTy = getASTContext().getTagDeclType(rd)->getCanonicalTypeInternal();
+  else
+    recTy = getASTContext().VoidTy;
+
+  if (md)
+    recTy = getASTContext().getAddrSpaceQualType(
+        recTy, md->getMethodQualifiers().getAddressSpace());
+  return getASTContext().getPointerType(CanQualType::CreateUnsafe(recTy));
+}
+
 /// Arrange the CIR function layout for a value of the given function type, on
 /// top of any implicit parameters already stored.
 static const CIRGenFunctionInfo &
 arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl<CanQualType> &prefix,
                        CanQual<FunctionProtoType> ftp) {
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
   RequiredArgs required =
       RequiredArgs::getFromProtoWithExtraSlots(ftp, prefix.size());
   assert(!cir::MissingFeatures::opCallExtParameterInfo());
@@ -112,24 +132,88 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
   CanQualType retType = fnType->getReturnType()
                             ->getCanonicalTypeUnqualified()
                             .getUnqualifiedType();
+
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
   return cgt.arrangeCIRFunctionInfo(retType, argTypes, required);
 }
 
+/// Arrange a call to a C++ method, passing the given arguments.
+///
+/// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It
+/// does not count `this`.
+const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXMethodCall(
+    const CallArgList &args, const FunctionProtoType *proto,
+    RequiredArgs required, unsigned numPrefixArgs) {
+  assert(!cir::MissingFeatures::opCallExtParameterInfo());
+  assert(numPrefixArgs + 1 <= args.size() &&
+         "Emitting a call with less args than the required prefix?");
+
+  // FIXME: Kill copy.
+  llvm::SmallVector<CanQualType, 16> argTypes;
+  for (const CallArg &arg : args)
+    argTypes.push_back(astContext.getCanonicalParamType(arg.ty));
+
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
+  return arrangeCIRFunctionInfo(proto->getReturnType()
+                                    ->getCanonicalTypeUnqualified()
+                                    .getUnqualifiedType(),
+                                argTypes, required);
+}
+
 const CIRGenFunctionInfo &
 CIRGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
                                      const FunctionType *fnType) {
   return arrangeFreeFunctionLikeCall(*this, cgm, args, fnType);
 }
 
+/// Arrange the argument and result information for a declaration or definition
+/// of the given C++ non-static member function. The member function must be an
+/// ordinary function, i.e. not a constructor or destructor.
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *md) {
+  assert(!isa<CXXConstructorDecl>(md) && "wrong method for constructors!");
+  assert(!isa<CXXDestructorDecl>(md) && "wrong method for destructors!");
+
+  auto prototype =
+      md->getType()->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
+  assert(!cir::MissingFeatures::cudaSupport());
+
+  if (md->isInstance()) {
+    // The abstract case is perfectly fine.
+    auto *thisType = theCXXABI.getThisArgumentTypeForMethod(md);
+    return arrangeCXXMethodType(thisType, prototype.getTypePtr(), md);
+  }
+
+  return arrangeFreeFunctionType(prototype);
+}
+
+/// Arrange the argument and result information for a call to an unknown C++
+/// non-static member function of the given abstract type. (A null RD means we
+/// don't have any meaningful "this" argument type, so fall back to a generic
+/// pointer type). The member fucntion must be an ordinary function, i.e. not a
+/// constructor or destructor.
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd,
+                                  const FunctionProtoType *ftp,
+                                  const CXXMethodDecl *md) {
+  llvm::SmallVector<CanQualType, 16> argTypes;
+
+  // Add the 'this' pointer.
+  argTypes.push_back(deriveThisType(rd, md));
+
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
+  return ::arrangeCIRFunctionInfo(
+      *this, argTypes,
+      ftp->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
+}
+
 /// Arrange the argument and result information for the declaration or
 /// definition of the given function.
 const CIRGenFunctionInfo &
 CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {
-  if (const auto *md = dyn_cast<CXXMethodDecl>(fd)) {
-    if (md->isInstance()) {
-      cgm.errorNYI("arrangeFunctionDeclaration: instance method");
-    }
-  }
+  if (const auto *md = dyn_cast<CXXMethodDecl>(fd))
+    if (md->isInstance())
+      return arrangeCXXMethodDeclaration(md);
 
   CanQualType funcTy = fd->getType()->getCanonicalTypeUnqualified();
 
@@ -142,6 +226,7 @@ CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {
   if (CanQual<FunctionNoProtoType> noProto =
           funcTy.getAs<FunctionNoProtoType>()) {
     assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
+    assert(!cir::MissingFeatures::opCallFnInfoOpts());
     return arrangeCIRFunctionInfo(noProto->getReturnType(), std::nullopt,
                                   RequiredArgs::All);
   }
@@ -167,12 +252,14 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
 const CIRGenFunctionInfo &
 CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {
   SmallVector<CanQualType, 16> argTypes;
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
   return ::arrangeCIRFunctionInfo(*this, argTypes, fpt);
 }
 
 const CIRGenFunctionInfo &
 CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) {
   CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
   return arrangeCIRFunctionInfo(resultType, {}, RequiredArgs(0));
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h
index 2ba1676eb6b97..5156f78e562ad 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.h
@@ -109,6 +109,14 @@ struct CallArg {
 class CallArgList : public llvm::SmallVector<CallArg, 8> {
 public:
   void add(RValue rvalue, clang::QualType type) { emplace_back(rvalue, type); }
+
+  /// Add all the arguments from another CallArgList to this one. After doing
+  /// this, the old CallArgList retains its list of arguments, but must not
+  /// be used to emit a call.
+  void addFr...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 16, 2025

@llvm/pr-subscribers-clang

Author: Andy Kaylor (andykaylor)

Changes

This change adds the support needed to handle a C++ member function call, including arranging the function type with an argument added for the 'this' parameter. It was necessary to introduce the class to handle the CXXABI, but at this time no target-specific subclasses have been added.


Patch is 32.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140290.diff

14 Files Affected:

  • (modified) clang/include/clang/CIR/MissingFeatures.h (+10-1)
  • (added) clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp (+45)
  • (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.h (+26-1)
  • (added) clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp (+186)
  • (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+92-5)
  • (modified) clang/lib/CIR/CodeGen/CIRGenCall.h (+8)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+32-5)
  • (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+8-2)
  • (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+15)
  • (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+11-4)
  • (modified) clang/lib/CIR/CodeGen/CIRGenTypes.cpp (+1-1)
  • (modified) clang/lib/CIR/CodeGen/CIRGenTypes.h (+22)
  • (modified) clang/lib/CIR/CodeGen/CMakeLists.txt (+2)
  • (added) clang/test/CIR/CodeGen/member-functions.cpp (+44)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 484822c351746..a4324053ba476 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -90,7 +90,6 @@ struct MissingFeatures {
   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; }
@@ -107,6 +106,13 @@ struct MissingFeatures {
   static bool opCallLandingPad() { return false; }
   static bool opCallContinueBlock() { return false; }
 
+  // FnInfoOpts -- This is used to track whether calls are chain calls or
+  // instance methods. Classic codegen uses chain call to track and extra free
+  // register for x86 and uses instance method as a condition for a thunk
+  // generation special case. It's not clear that we need either of these in
+  // pre-lowering CIR codegen.
+  static bool opCallFnInfoOpts() { return false; }
+
   // ScopeOp handling
   static bool opScopeCleanupRegion() { return false; }
 
@@ -189,6 +195,9 @@ struct MissingFeatures {
   static bool constEmitterArrayILE() { return false; }
   static bool constEmitterVectorILE() { return false; }
   static bool needsGlobalCtorDtor() { return false; }
+  static bool emitTypeCheck() { return false; }
+  static bool cxxabiThisDecl() { return false; }
+  static bool cxxabiThisAlignment() { return false; }
 
   // Missing types
   static bool dataMemberType() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
new file mode 100644
index 0000000000000..fcd45768656ff
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
@@ -0,0 +1,45 @@
+//===----- CirGenCXXABI.cpp - Interface to C++ ABIs -----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for C++ code generation. Concrete subclasses
+// of this implement code generation for specific C++ ABIs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenCXXABI.h"
+#include "CIRGenFunction.h"
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/GlobalDecl.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+CIRGenCXXABI::~CIRGenCXXABI() {}
+
+void CIRGenCXXABI::buildThisParam(CIRGenFunction &cgf,
+                                  FunctionArgList &params) {
+  const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
+
+  // FIXME: I'm not entirely sure I like using a fake decl just for code
+  // generation. Maybe we can come up with a better way?
+  auto *thisDecl =
+      ImplicitParamDecl::Create(cgm.getASTContext(), nullptr, md->getLocation(),
+                                &cgm.getASTContext().Idents.get("this"),
+                                md->getThisType(), ImplicitParamKind::CXXThis);
+  params.push_back(thisDecl);
+
+  // Classic codegen save thisDecl in CodeGenFunction::CXXABIThisDecl, but it
+  // doesn't seem to be needed in CIRGen.
+  assert(!cir::MissingFeatures::cxxabiThisDecl());
+
+  // Classic codegen computes the alignment of thisDecl and saves it in
+  // CodeGenFunction::CXXABIThisAlignment, but it doesn't seem to be needed in
+  // CIRGen.
+  assert(!cir::MissingFeatures::cxxabiThisAlignment());
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 5279307e19613..b5c33a29442c7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
 #define LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
 
+#include "CIRGenCall.h"
 #include "CIRGenModule.h"
 
 #include "clang/AST/Mangle.h"
@@ -31,9 +32,33 @@ class CIRGenCXXABI {
   // implemented.
   CIRGenCXXABI(CIRGenModule &cgm)
       : cgm(cgm), mangleContext(cgm.getASTContext().createMangleContext()) {}
-  ~CIRGenCXXABI();
+  virtual ~CIRGenCXXABI();
 
 public:
+  /// Get the type of the implicit "this" parameter used by a method. May return
+  /// zero if no specific type is applicable, e.g. if the ABI expects the "this"
+  /// parameter to point to some artificial offset in a complete object due to
+  /// vbases being reordered.
+  virtual const clang::CXXRecordDecl *
+  getThisArgumentTypeForMethod(const clang::CXXMethodDecl *md) {
+    return md->getParent();
+  }
+
+  /// Build a parameter variable suitable for 'this'.
+  void buildThisParam(CIRGenFunction &cgf, FunctionArgList &params);
+
+  /// Returns true if the given constructor or destructor is one of the kinds
+  /// that the ABI says returns 'this' (only applies when called non-virtually
+  /// for destructors).
+  ///
+  /// There currently is no way to indicate if a destructor returns 'this' when
+  /// called virtually, and CIR generation does not support this case.
+  virtual bool hasThisReturn(clang::GlobalDecl gd) const { return false; }
+
+  virtual bool hasMostDerivedReturn(clang::GlobalDecl gd) const {
+    return false;
+  }
+
   /// Gets the mangle context.
   clang::MangleContext &getMangleContext() { return *mangleContext; }
 };
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp
new file mode 100644
index 0000000000000..906c212f0fa8a
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp
@@ -0,0 +1,186 @@
+//===--- CIRGenExprCXX.cpp - Emit CIR Code for C++ expressions ------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with code generation of C++ expressions
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenCXXABI.h"
+#include "CIRGenFunction.h"
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/CIR/MissingFeatures.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+namespace {
+struct MemberCallInfo {
+  RequiredArgs reqArgs;
+  // Number of prefix arguments for the call. Ignores the `this` pointer.
+  unsigned prefixSize;
+};
+} // namespace
+
+static MemberCallInfo commonBuildCXXMemberOrOperatorCall(
+    CIRGenFunction &cgf, const CXXMethodDecl *md, mlir::Value thisPtr,
+    mlir::Value implicitParam, QualType implicitParamTy, const CallExpr *ce,
+    CallArgList &args, CallArgList *rtlArgs) {
+  assert(ce == nullptr || isa<CXXMemberCallExpr>(ce) ||
+         isa<CXXOperatorCallExpr>(ce));
+  assert(md->isInstance() &&
+         "Trying to emit a member or operator call expr on a static method!");
+
+  // Push the this ptr.
+  const CXXRecordDecl *rd =
+      cgf.cgm.getCXXABI().getThisArgumentTypeForMethod(md);
+  args.add(RValue::get(thisPtr), cgf.getTypes().deriveThisType(rd, md));
+
+  // If there is an implicit parameter (e.g. VTT), emit it.
+  if (implicitParam) {
+    args.add(RValue::get(implicitParam), implicitParamTy);
+  }
+
+  const auto *fpt = md->getType()->castAs<FunctionProtoType>();
+  RequiredArgs required =
+      RequiredArgs::getFromProtoWithExtraSlots(fpt, args.size());
+  unsigned prefixSize = args.size() - 1;
+
+  // Add the rest of the call args
+  if (rtlArgs) {
+    // Special case: if the caller emitted the arguments right-to-left already
+    // (prior to emitting the *this argument), we're done. This happens for
+    // assignment operators.
+    args.addFrom(*rtlArgs);
+  } else if (ce) {
+    // Special case: skip first argument of CXXOperatorCall (it is "this").
+    unsigned argsToSkip = isa<CXXOperatorCallExpr>(ce) ? 1 : 0;
+    cgf.emitCallArgs(args, fpt, drop_begin(ce->arguments(), argsToSkip),
+                     ce->getDirectCallee());
+  } else {
+    assert(
+        fpt->getNumParams() == 0 &&
+        "No CallExpr specified for function with non-zero number of arguments");
+  }
+
+  //  return {required, prefixSize};
+  return {required, prefixSize};
+}
+
+RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr(
+    const CallExpr *ce, const CXXMethodDecl *md, ReturnValueSlot returnValue,
+    bool hasQualifier, NestedNameSpecifier *qualifier, bool isArrow,
+    const Expr *base) {
+  assert(isa<CXXMemberCallExpr>(ce) || isa<CXXOperatorCallExpr>(ce));
+
+  if (md->isVirtual()) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: virtual call");
+    return RValue::get(nullptr);
+  }
+
+  bool trivialForCodegen =
+      md->isTrivial() || (md->isDefaulted() && md->getParent()->isUnion());
+  bool trivialAssignment =
+      trivialForCodegen &&
+      (md->isCopyAssignmentOperator() || md->isMoveAssignmentOperator()) &&
+      !md->getParent()->mayInsertExtraPadding();
+  (void)trivialAssignment;
+
+  // C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
+  // operator before the LHS.
+  CallArgList rtlArgStorage;
+  CallArgList *rtlArgs = nullptr;
+  if (auto *oce = dyn_cast<CXXOperatorCallExpr>(ce)) {
+    cgm.errorNYI(oce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: operator call");
+    return RValue::get(nullptr);
+  }
+
+  LValue thisPtr;
+  if (isArrow) {
+    LValueBaseInfo baseInfo;
+    assert(!cir::MissingFeatures::opTBAA());
+    Address thisValue = emitPointerWithAlignment(base, &baseInfo);
+    thisPtr = makeAddrLValue(thisValue, base->getType(), baseInfo);
+  } else {
+    thisPtr = emitLValue(base);
+  }
+
+  if (const CXXConstructorDecl *ctor = dyn_cast<CXXConstructorDecl>(md)) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: constructor call");
+    return RValue::get(nullptr);
+  }
+
+  if (trivialForCodegen) {
+    if (isa<CXXDestructorDecl>(md))
+      return RValue::get(nullptr);
+
+    if (trivialAssignment) {
+      cgm.errorNYI(ce->getSourceRange(),
+                   "emitCXXMemberOrOperatorMemberCallExpr: trivial assignment");
+      return RValue::get(nullptr);
+    } else {
+      assert(md->getParent()->mayInsertExtraPadding() &&
+             "unknown trivial member function");
+    }
+  }
+
+  // Compute the function type we're calling
+  const CXXMethodDecl *calleeDecl = md;
+  const CIRGenFunctionInfo *fInfo = nullptr;
+  if (const auto *dtor = dyn_cast<CXXDestructorDecl>(calleeDecl)) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: destructor call");
+    return RValue::get(nullptr);
+  } else {
+    fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(calleeDecl);
+  }
+
+  mlir::Type ty = cgm.getTypes().getFunctionType(*fInfo);
+
+  assert(!cir::MissingFeatures::sanitizers());
+  assert(!cir::MissingFeatures::emitTypeCheck());
+
+  if (const auto *dtor = dyn_cast<CXXDestructorDecl>(calleeDecl)) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: destructor call");
+    return RValue::get(nullptr);
+  }
+
+  assert(!cir::MissingFeatures::sanitizers());
+  if (getLangOpts().AppleKext) {
+    cgm.errorNYI(ce->getSourceRange(),
+                 "emitCXXMemberOrOperatorMemberCallExpr: AppleKext");
+    return RValue::get(nullptr);
+  }
+  CIRGenCallee callee =
+      CIRGenCallee::forDirect(cgm.getAddrOfFunction(md, ty), GlobalDecl(md));
+
+  return emitCXXMemberOrOperatorCall(
+      calleeDecl, callee, returnValue, thisPtr.getPointer(),
+      /*ImplicitParam=*/nullptr, QualType(), ce, rtlArgs);
+}
+
+RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
+    const CXXMethodDecl *md, const CIRGenCallee &callee,
+    ReturnValueSlot returnValue, mlir::Value thisPtr, mlir::Value implicitParam,
+    QualType implicitParamTy, const CallExpr *ce, CallArgList *rtlArgs) {
+  const auto *fpt = md->getType()->castAs<FunctionProtoType>();
+  CallArgList args;
+  MemberCallInfo callInfo = commonBuildCXXMemberOrOperatorCall(
+      *this, md, thisPtr, implicitParam, implicitParamTy, ce, args, rtlArgs);
+  auto &fnInfo = cgm.getTypes().arrangeCXXMethodCall(
+      args, fpt, callInfo.reqArgs, callInfo.prefixSize);
+  assert((ce || currSrcLoc) && "expected source location");
+  mlir::Location loc = ce ? getLoc(ce->getExprLoc()) : *currSrcLoc;
+  assert(!cir::MissingFeatures::opCallMustTail());
+  return emitCall(fnInfo, callee, returnValue, args, nullptr, loc);
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 17bfa19f9fd63..7590153410747 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CIRGenCall.h"
+#include "CIRGenCXXABI.h"
 #include "CIRGenFunction.h"
 #include "CIRGenFunctionInfo.h"
 #include "clang/CIR/MissingFeatures.h"
@@ -76,11 +77,30 @@ static void appendParameterTypes(const CIRGenTypes &cgt,
   cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos");
 }
 
+/// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR
+/// qualification. Either or both of `rd` and `md` may be null. A null `rd`
+/// indicates that there is no meaningful 'this' type, and a null `md` can occur
+/// when calling a method pointer.
+CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd,
+                                        const CXXMethodDecl *md) {
+  QualType recTy;
+  if (rd)
+    recTy = getASTContext().getTagDeclType(rd)->getCanonicalTypeInternal();
+  else
+    recTy = getASTContext().VoidTy;
+
+  if (md)
+    recTy = getASTContext().getAddrSpaceQualType(
+        recTy, md->getMethodQualifiers().getAddressSpace());
+  return getASTContext().getPointerType(CanQualType::CreateUnsafe(recTy));
+}
+
 /// Arrange the CIR function layout for a value of the given function type, on
 /// top of any implicit parameters already stored.
 static const CIRGenFunctionInfo &
 arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl<CanQualType> &prefix,
                        CanQual<FunctionProtoType> ftp) {
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
   RequiredArgs required =
       RequiredArgs::getFromProtoWithExtraSlots(ftp, prefix.size());
   assert(!cir::MissingFeatures::opCallExtParameterInfo());
@@ -112,24 +132,88 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
   CanQualType retType = fnType->getReturnType()
                             ->getCanonicalTypeUnqualified()
                             .getUnqualifiedType();
+
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
   return cgt.arrangeCIRFunctionInfo(retType, argTypes, required);
 }
 
+/// Arrange a call to a C++ method, passing the given arguments.
+///
+/// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It
+/// does not count `this`.
+const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXMethodCall(
+    const CallArgList &args, const FunctionProtoType *proto,
+    RequiredArgs required, unsigned numPrefixArgs) {
+  assert(!cir::MissingFeatures::opCallExtParameterInfo());
+  assert(numPrefixArgs + 1 <= args.size() &&
+         "Emitting a call with less args than the required prefix?");
+
+  // FIXME: Kill copy.
+  llvm::SmallVector<CanQualType, 16> argTypes;
+  for (const CallArg &arg : args)
+    argTypes.push_back(astContext.getCanonicalParamType(arg.ty));
+
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
+  return arrangeCIRFunctionInfo(proto->getReturnType()
+                                    ->getCanonicalTypeUnqualified()
+                                    .getUnqualifiedType(),
+                                argTypes, required);
+}
+
 const CIRGenFunctionInfo &
 CIRGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
                                      const FunctionType *fnType) {
   return arrangeFreeFunctionLikeCall(*this, cgm, args, fnType);
 }
 
+/// Arrange the argument and result information for a declaration or definition
+/// of the given C++ non-static member function. The member function must be an
+/// ordinary function, i.e. not a constructor or destructor.
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *md) {
+  assert(!isa<CXXConstructorDecl>(md) && "wrong method for constructors!");
+  assert(!isa<CXXDestructorDecl>(md) && "wrong method for destructors!");
+
+  auto prototype =
+      md->getType()->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
+  assert(!cir::MissingFeatures::cudaSupport());
+
+  if (md->isInstance()) {
+    // The abstract case is perfectly fine.
+    auto *thisType = theCXXABI.getThisArgumentTypeForMethod(md);
+    return arrangeCXXMethodType(thisType, prototype.getTypePtr(), md);
+  }
+
+  return arrangeFreeFunctionType(prototype);
+}
+
+/// Arrange the argument and result information for a call to an unknown C++
+/// non-static member function of the given abstract type. (A null RD means we
+/// don't have any meaningful "this" argument type, so fall back to a generic
+/// pointer type). The member fucntion must be an ordinary function, i.e. not a
+/// constructor or destructor.
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd,
+                                  const FunctionProtoType *ftp,
+                                  const CXXMethodDecl *md) {
+  llvm::SmallVector<CanQualType, 16> argTypes;
+
+  // Add the 'this' pointer.
+  argTypes.push_back(deriveThisType(rd, md));
+
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
+  return ::arrangeCIRFunctionInfo(
+      *this, argTypes,
+      ftp->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
+}
+
 /// Arrange the argument and result information for the declaration or
 /// definition of the given function.
 const CIRGenFunctionInfo &
 CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {
-  if (const auto *md = dyn_cast<CXXMethodDecl>(fd)) {
-    if (md->isInstance()) {
-      cgm.errorNYI("arrangeFunctionDeclaration: instance method");
-    }
-  }
+  if (const auto *md = dyn_cast<CXXMethodDecl>(fd))
+    if (md->isInstance())
+      return arrangeCXXMethodDeclaration(md);
 
   CanQualType funcTy = fd->getType()->getCanonicalTypeUnqualified();
 
@@ -142,6 +226,7 @@ CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {
   if (CanQual<FunctionNoProtoType> noProto =
           funcTy.getAs<FunctionNoProtoType>()) {
     assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
+    assert(!cir::MissingFeatures::opCallFnInfoOpts());
     return arrangeCIRFunctionInfo(noProto->getReturnType(), std::nullopt,
                                   RequiredArgs::All);
   }
@@ -167,12 +252,14 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
 const CIRGenFunctionInfo &
 CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {
   SmallVector<CanQualType, 16> argTypes;
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
   return ::arrangeCIRFunctionInfo(*this, argTypes, fpt);
 }
 
 const CIRGenFunctionInfo &
 CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) {
   CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();
+  assert(!cir::MissingFeatures::opCallFnInfoOpts());
   return arrangeCIRFunctionInfo(resultType, {}, RequiredArgs(0));
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h
index 2ba1676eb6b97..5156f78e562ad 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.h
@@ -109,6 +109,14 @@ struct CallArg {
 class CallArgList : public llvm::SmallVector<CallArg, 8> {
 public:
   void add(RValue rvalue, clang::QualType type) { emplace_back(rvalue, type); }
+
+  /// Add all the arguments from another CallArgList to this one. After doing
+  /// this, the old CallArgList retains its list of arguments, but must not
+  /// be used to emit a call.
+  void addFr...
[truncated]

FunctionArgList &params) {
const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());

// FIXME: I'm not entirely sure I like using a fake decl just for code
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this seems pretty awful. we should probably figure out what info we need from the decl, and just save THAT instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That comment has been in the code since 2010. I'm starting to think no one is looking for a better way to do it. 😄

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, shoot :D Welp! IMO CIR should probably model 'member function' some day, but if this is that old/preexisting, we can just live with it.

I'm generally happy with this patch, but hoping the ot hers can do a more thorough review.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, this isn't great, and it's not the only instance in CodeGen/CIRGen where clang current creates AST nodes on the fly - one neat side effect of this is to rely on the pre-existing ImplicitParamDecl codegen, so it doesn't needed to be duplicated here (which usually involves handling the scalar/agg/complex versions), but in theory we could hoist the implementation of visitors into common helpers that could be used directly here.

I'm fine leaving this as-is for now.

Copy link
Member

@bcardosolopes bcardosolopes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nits / comments, but this LGTM to me: skeleton for member function calls added, errorNYI used for untested paths and some initial support for the more simple cases.

FunctionArgList &params) {
const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());

// FIXME: I'm not entirely sure I like using a fake decl just for code
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, this isn't great, and it's not the only instance in CodeGen/CIRGen where clang current creates AST nodes on the fly - one neat side effect of this is to rely on the pre-existing ImplicitParamDecl codegen, so it doesn't needed to be duplicated here (which usually involves handling the scalar/agg/complex versions), but in theory we could hoist the implementation of visitors into common helpers that could be used directly here.

I'm fine leaving this as-is for now.

@@ -0,0 +1,45 @@
//===----- CirGenCXXABI.cpp - Interface to C++ ABIs -----------------------===//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CIRGenCXXABI.cpp to match the name of the file? (Or I guess none because this isn't required anymore?)

/// be used to emit a call.
void addFrom(const CallArgList &other) {
insert(end(), other.begin(), other.end());
// TODO: Writebacks, CleanupsToDeactivate, StackBase???
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these deserve missing features?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably. Classic codegen has handling for these here, but we likely will want to defer it to lowering. Even so, we should insert a marker to track it until we know what's needed.

if (rd)
recTy = getASTContext().getTagDeclType(rd)->getCanonicalTypeInternal();
else
recTy = getASTContext().VoidTy;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this path covered in the tests below? Looks like it's not but I might be missing something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. It looks like this is an MS ABI thing. Would you prefer I put an errorNYI here until we can add a test for it?

Comment on lines +1164 to +1167
if (md->isStatic()) {
cgm.errorNYI(ce->getSourceRange(), "emitCXXMemberCallExpr: static method");
return RValue::get(nullptr);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we include static method calls in this PR? This looks like a direct invocation into existing function call CIRGen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is marked NYI in the incubator. The classic codegen only has a couple of lines of code here to handle it, but I'd prefer to leave it for a later PR so I can properly investigate why the incubator didn't implement it.

@andykaylor andykaylor merged commit a0c515a into llvm:main May 19, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented May 19, 2025

LLVM Buildbot has detected a new failure on builder clang-x64-windows-msvc running on windows-gcebot2 while building clang at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/63/builds/6385

Here is the relevant piece of the build log for the reference
Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/clang-windows.py ...' (failure)
...
  Passed           : 71057 (99.32%)
  Expectedly Failed:    37 (0.05%)
[76/77] Running the LLVM regression tests
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:57: note: using lit tools: C:\Program Files\Git\usr\bin
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:520: note: using ld.lld: c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\ld.lld.exe
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:520: note: using lld-link: c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\lld-link.exe
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:520: note: using ld64.lld: c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\ld64.lld.exe
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:520: note: using wasm-ld: c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\wasm-ld.exe
-- Testing: 58554 tests, 32 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60
FAIL: LLVM :: tools/dsymutil/X86/op-convert-offset.test (10668 of 58554)
******************** TEST 'LLVM :: tools/dsymutil/X86/op-convert-offset.test' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 23
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\dsymutil.exe -oso-prepend-path C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM 2>&1
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\dsymutil.exe' -oso-prepend-path 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset' -o 'C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM'
# .---command stdout------------
# | warning: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o: timestamp mismatch between object file (2024-07-13 08:43:29.277066200) and debug map (2022-07-12 20:49:30.000000000)
# `-----------------------------
# RUN: at line 24
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1 | c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test --check-prefix OBJ
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o'
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test' --check-prefix OBJ
# RUN: at line 25
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM 2>&1 | c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test --check-prefix DSYM
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe' 'C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM'
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test' --check-prefix DSYM
# RUN: at line 27
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\dsymutil.exe --linker parallel -oso-prepend-path C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs   C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset   -o C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM 2>&1
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\dsymutil.exe' --linker parallel -oso-prepend-path 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset' -o 'C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM'
# .---command stdout------------
# | warning: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o: timestamp mismatch between object file (2024-07-13 08:43:29.277066200) and debug map (2022-07-12 20:49:30.000000000)
# | warning: cann't read address attribute value.
# | note: while processing op-convert-offset1.c
# `-----------------------------
# RUN: at line 30
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe    C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1    | c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test --check-prefix OBJ
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o'
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test' --check-prefix OBJ
# RUN: at line 33
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM 2>&1 | c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test --check-prefix DSYM
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe' 'C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM'
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test' --check-prefix DSYM
# .---command stderr------------
# | C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test:45:7: error: DSYM: expected string not found in input
# | DSYM: 0x00000084: DW_TAG_base_type
Step 8 (stage 1 check) failure: stage 1 check (failure)
...
  Passed           : 71057 (99.32%)
  Expectedly Failed:    37 (0.05%)
[76/77] Running the LLVM regression tests
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:57: note: using lit tools: C:\Program Files\Git\usr\bin
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:520: note: using ld.lld: c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\ld.lld.exe
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:520: note: using lld-link: c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\lld-link.exe
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:520: note: using ld64.lld: c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\ld64.lld.exe
llvm-lit.py: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\utils\lit\lit\llvm\config.py:520: note: using wasm-ld: c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\wasm-ld.exe
-- Testing: 58554 tests, 32 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60
FAIL: LLVM :: tools/dsymutil/X86/op-convert-offset.test (10668 of 58554)
******************** TEST 'LLVM :: tools/dsymutil/X86/op-convert-offset.test' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 23
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\dsymutil.exe -oso-prepend-path C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM 2>&1
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\dsymutil.exe' -oso-prepend-path 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset' -o 'C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM'
# .---command stdout------------
# | warning: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o: timestamp mismatch between object file (2024-07-13 08:43:29.277066200) and debug map (2022-07-12 20:49:30.000000000)
# `-----------------------------
# RUN: at line 24
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1 | c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test --check-prefix OBJ
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o'
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test' --check-prefix OBJ
# RUN: at line 25
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM 2>&1 | c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test --check-prefix DSYM
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe' 'C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM'
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test' --check-prefix DSYM
# RUN: at line 27
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\dsymutil.exe --linker parallel -oso-prepend-path C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs   C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset   -o C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM 2>&1
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\dsymutil.exe' --linker parallel -oso-prepend-path 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset' -o 'C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM'
# .---command stdout------------
# | warning: C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o: timestamp mismatch between object file (2024-07-13 08:43:29.277066200) and debug map (2022-07-12 20:49:30.000000000)
# | warning: cann't read address attribute value.
# | note: while processing op-convert-offset1.c
# `-----------------------------
# RUN: at line 30
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe    C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1    | c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test --check-prefix OBJ
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o'
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test' --check-prefix OBJ
# RUN: at line 33
c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM 2>&1 | c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test --check-prefix DSYM
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\llvm-dwarfdump.exe' 'C:\b\slave\clang-x64-windows-msvc\build\stage1\test\tools\dsymutil\X86\Output\op-convert-offset.test.tmp.dSYM'
# executed command: 'c:\b\slave\clang-x64-windows-msvc\build\stage1\bin\filecheck.exe' 'C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test' --check-prefix DSYM
# .---command stderr------------
# | C:\b\slave\clang-x64-windows-msvc\llvm-project\llvm\test\tools\dsymutil\X86\op-convert-offset.test:45:7: error: DSYM: expected string not found in input
# | DSYM: 0x00000084: DW_TAG_base_type

@llvm-ci
Copy link
Collaborator

llvm-ci commented May 20, 2025

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building clang at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/11794

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: 1200 seconds without output running [b'ninja', b'-j 4', b'check-openmp'], attempting to kill
...
PASS: ompd-test :: openmp_examples/example_3.c (443 of 453)
PASS: ompd-test :: openmp_examples/example_4.c (444 of 453)
PASS: ompd-test :: openmp_examples/example_5.c (445 of 453)
PASS: ompd-test :: openmp_examples/example_task.c (446 of 453)
UNSUPPORTED: ompd-test :: openmp_examples/ompd_bt.c (447 of 453)
PASS: ompd-test :: openmp_examples/fibonacci.c (448 of 453)
UNSUPPORTED: ompd-test :: openmp_examples/ompd_parallel.c (449 of 453)
PASS: ompd-test :: openmp_examples/parallel.c (450 of 453)
PASS: ompd-test :: openmp_examples/nested.c (451 of 453)
PASS: ompd-test :: openmp_examples/ompd_icvs.c (452 of 453)
command timed out: 1200 seconds without output running [b'ninja', b'-j 4', b'check-openmp'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=1323.022374

@llvm-ci
Copy link
Collaborator

llvm-ci commented May 20, 2025

LLVM Buildbot has detected a new failure on builder clang-ppc64-aix running on aix-ppc64 while building clang at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/64/builds/3686

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'lit :: timeout-hang.py' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 13
not env -u FILECHECK_OPTS "/home/llvm/llvm-external-buildbots/workers/env/bin/python3.11" /home/llvm/llvm-external-buildbots/workers/aix-ppc64/clang-ppc64-aix/llvm-project/llvm/utils/lit/lit.py -j1 --order=lexical Inputs/timeout-hang/run-nonexistent.txt  --timeout=1 --param external=0 | "/home/llvm/llvm-external-buildbots/workers/env/bin/python3.11" /home/llvm/llvm-external-buildbots/workers/aix-ppc64/clang-ppc64-aix/build/utils/lit/tests/timeout-hang.py 1
# executed command: not env -u FILECHECK_OPTS /home/llvm/llvm-external-buildbots/workers/env/bin/python3.11 /home/llvm/llvm-external-buildbots/workers/aix-ppc64/clang-ppc64-aix/llvm-project/llvm/utils/lit/lit.py -j1 --order=lexical Inputs/timeout-hang/run-nonexistent.txt --timeout=1 --param external=0
# .---command stderr------------
# | lit.py: /home/llvm/llvm-external-buildbots/workers/aix-ppc64/clang-ppc64-aix/llvm-project/llvm/utils/lit/lit/main.py:72: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 1 seconds was requested on the command line. Forcing timeout to be 1 seconds.
# `-----------------------------
# executed command: /home/llvm/llvm-external-buildbots/workers/env/bin/python3.11 /home/llvm/llvm-external-buildbots/workers/aix-ppc64/clang-ppc64-aix/build/utils/lit/tests/timeout-hang.py 1
# .---command stdout------------
# | Testing took as long or longer than timeout
# `-----------------------------
# error: command failed with exit status: 1

--

********************


sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
This change adds the support needed to handle a C++ member function
call, including arranging the function type with an argument added for
the 'this' parameter. It was necessary to introduce the class to handle
the CXXABI, but at this time no target-specific subclasses have been
added.
ajaden-codes pushed a commit to Jaddyen/llvm-project that referenced this pull request Jun 6, 2025
This change adds the support needed to handle a C++ member function
call, including arranging the function type with an argument added for
the 'this' parameter. It was necessary to introduce the class to handle
the CXXABI, but at this time no target-specific subclasses have been
added.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants