[clang] [CIR] Upstream initial function call support (PR #134673)

Sirui Mu via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 8 08:13:04 PDT 2025


================
@@ -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());
+
----------------
Lancern wrote:

Updated.

BTW, I'm curious about the principles of handling NYI during the upstreaming process. In the incubator we typically put an `assert(false)` or a `MissingFeatures` check on the NYI paths. But during upstreaming it seems like:

1. We don't like the `assert(false)` approach apparently.
2. We are still using `MissingFeatures` to track the NYI parts.
3. We now have a new mechanism that emits a diagnostic upon NYI paths.

I'm actually a bit confused about how to choose between 2) and 3). Are there any guidelines or principles? Besides, both of 2) and 3) does not abort normal execution, is it possible that this may break some assumptions dependent by code that follows NYI check points, and eventually lead to clang crashing on strange program points?

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


More information about the cfe-commits mailing list