[clang] [CIR] Call to variadic functions (PR #141942)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Thu May 29 20:56:58 PDT 2025
https://github.com/Lancern updated https://github.com/llvm/llvm-project/pull/141942
>From 862cb3bd98bc2ed6a6b01efe0f08ebfaf8ad63e0 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Thu, 29 May 2025 17:21:06 +0800
Subject: [PATCH] [CIR] Call to variadic functions
---
clang/include/clang/CIR/MissingFeatures.h | 1 -
clang/lib/CIR/CodeGen/CIRGenCall.cpp | 20 +++++++++++++++++---
clang/lib/CIR/CodeGen/CIRGenFunction.h | 4 ++++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 6 +++---
clang/test/CIR/CodeGen/call.cpp | 14 ++++++++++++++
clang/test/CIR/IR/invalid-call.cir | 12 ++++++++++++
6 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 56bf9b1130f12..f7385a672f6af 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -100,7 +100,6 @@ struct MissingFeatures {
static bool opCallAttrs() { return false; }
static bool opCallSurroundingTry() { return false; }
static bool opCallASTAttr() { return false; }
- static bool opCallVariadic() { return false; }
static bool opCallObjCMethod() { return false; }
static bool opCallExtParameterInfo() { return false; }
static bool opCallCIRGenFuncInfoParamInfo() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 1317f8c6c073a..b194a8670bfb9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -122,7 +122,7 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {
if (proto->isVariadic())
- cgm.errorNYI("call to variadic function");
+ required = RequiredArgs::getFromProtoWithExtraSlots(proto, 0);
if (proto->hasExtParameterInfos())
cgm.errorNYI("call to functions with extra parameter info");
} else if (cgm.getTargetCIRGenInfo().isNoProtoCallVariadic(
@@ -409,6 +409,18 @@ void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e,
args.add(emitAnyExprToTemp(e), argType);
}
+QualType CIRGenFunction::getVarArgType(const Expr *arg) {
+ // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC
+ // implicitly widens null pointer constants that are arguments to varargs
+ // functions to pointer-sized ints.
+ if (!getTarget().getTriple().isOSWindows())
+ return arg->getType();
+
+ assert(!cir::MissingFeatures::msabi());
+ cgm.errorNYI(arg->getSourceRange(), "getVarArgType: NYI for Windows target");
+ return arg->getType();
+}
+
/// Similar to emitAnyExpr(), however, the result will always be accessible
/// even if no aggregate location is provided.
RValue CIRGenFunction::emitAnyExprToTemp(const Expr *e) {
@@ -429,18 +441,20 @@ void CIRGenFunction::emitCallArgs(
assert(!cir::MissingFeatures::opCallCallConv());
// First, if a prototype was provided, use those argument types.
- assert(!cir::MissingFeatures::opCallVariadic());
+ bool isVariadic = false;
if (prototype.p) {
assert(!cir::MissingFeatures::opCallObjCMethod());
const auto *fpt = cast<const FunctionProtoType *>(prototype.p);
+ isVariadic = fpt->isVariadic();
+ assert(!cir::MissingFeatures::opCallCallConv());
argTypes.assign(fpt->param_type_begin() + paramsToSkip,
fpt->param_type_end());
}
// If we still have any arguments, emit them using the type of the argument.
for (const clang::Expr *a : llvm::drop_begin(argRange, argTypes.size()))
- argTypes.push_back(a->getType());
+ argTypes.push_back(isVariadic ? getVarArgType(a) : a->getType());
assert(argTypes.size() == (size_t)(argRange.end() - argRange.begin()));
// We must evaluate arguments from right to left in the MS C++ ABI, because
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 74f2e4043933d..0badde024b166 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -106,6 +106,7 @@ class CIRGenFunction : public CIRGenTypeCache {
CIRGenTypes &getTypes() const { return cgm.getTypes(); }
+ const TargetInfo &getTarget() const { return cgm.getTarget(); }
mlir::MLIRContext &getMLIRContext() { return cgm.getMLIRContext(); }
private:
@@ -791,6 +792,9 @@ class CIRGenFunction : public CIRGenTypeCache {
void emitOpenACCDeclare(const OpenACCDeclareDecl &d);
void emitOpenACCRoutine(const OpenACCRoutineDecl &d);
+
+private:
+ QualType getVarArgType(const Expr *arg);
};
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 9e2b2908b22d8..3e6d22879a78c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -601,10 +601,10 @@ verifyCallCommInSymbolUses(mlir::Operation *op,
unsigned numCallOperands = callIf.getNumArgOperands();
unsigned numFnOpOperands = fnType.getNumInputs();
- assert(!cir::MissingFeatures::opCallVariadic());
-
- if (numCallOperands != numFnOpOperands)
+ if (!fnType.isVarArg() && numCallOperands != numFnOpOperands)
return op->emitOpError("incorrect number of operands for callee");
+ if (fnType.isVarArg() && numCallOperands < numFnOpOperands)
+ return op->emitOpError("too few operands for callee");
for (unsigned i = 0, e = numFnOpOperands; i != e; ++i)
if (callIf.getArgOperand(i).getType() != fnType.getInput(i))
diff --git a/clang/test/CIR/CodeGen/call.cpp b/clang/test/CIR/CodeGen/call.cpp
index 792f57afd6bd1..741cadeb5c764 100644
--- a/clang/test/CIR/CodeGen/call.cpp
+++ b/clang/test/CIR/CodeGen/call.cpp
@@ -56,3 +56,17 @@ int f7(int (*ptr)(int, int)) {
// LLVM-LABEL: define i32 @_Z2f7PFiiiE
// LLVM: %[[#ptr:]] = load ptr, ptr %{{.+}}
// LLVM-NEXT: %{{.+}} = call i32 %[[#ptr]](i32 1, i32 2)
+
+void f8(int a, ...);
+void f9() {
+ f8(1);
+ f8(1, 2, 3, 4);
+}
+
+// CIR-LABEL: cir.func @_Z2f9v()
+// CIR: cir.call @_Z2f8iz(%{{.+}}) : (!s32i) -> ()
+// CIR: cir.call @_Z2f8iz(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) : (!s32i, !s32i, !s32i, !s32i) -> ()
+
+// LLVM-LABEL: define void @_Z2f9v()
+// LLVM: call void (i32, ...) @_Z2f8iz(i32 1)
+// LLVM: call void (i32, ...) @_Z2f8iz(i32 1, i32 2, i32 3, i32 4)
diff --git a/clang/test/CIR/IR/invalid-call.cir b/clang/test/CIR/IR/invalid-call.cir
index 8a584bae70878..3ebb771ed72e7 100644
--- a/clang/test/CIR/IR/invalid-call.cir
+++ b/clang/test/CIR/IR/invalid-call.cir
@@ -68,3 +68,15 @@ cir.func @f11() {
cir.call @f10(%0, %1) : (!s32i, !u32i) -> ()
cir.return
}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+cir.func @f12(!s32i, !s32i, ...)
+cir.func @f13() {
+ %0 = cir.const #cir.int<1> : !s32i
+ // expected-error @below {{too few operands for callee}}
+ cir.call @f12(%0) : (!s32i) -> ()
+ cir.return
+}
More information about the cfe-commits
mailing list