[clang] [CIR] Cleanup support for C functions (PR #136854)
Iris Shi via cfe-commits
cfe-commits at lists.llvm.org
Fri May 9 20:58:25 PDT 2025
https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/136854
>From 2350ca543f77d91c05db3d985f72e2cb10be3292 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Thu, 8 May 2025 23:40:15 +0800
Subject: [PATCH] [CIR] Cleanup support for C functions
---
clang/lib/CIR/CodeGen/CIRGenCall.cpp | 52 ++++++++++--
clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h | 97 ++++++++++++++++++----
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 18 +++-
clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 38 ++++-----
clang/lib/CIR/CodeGen/CIRGenTypes.h | 10 ++-
clang/lib/CIR/CodeGen/TargetInfo.cpp | 8 --
clang/test/CIR/CodeGen/basic.c | 13 +++
7 files changed, 183 insertions(+), 53 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 70d45dc383fd1..5c65a43641844 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -13,6 +13,7 @@
#include "CIRGenCall.h"
#include "CIRGenFunction.h"
+#include "CIRGenFunctionInfo.h"
#include "clang/CIR/MissingFeatures.h"
using namespace clang;
@@ -20,25 +21,43 @@ using namespace clang::CIRGen;
CIRGenFunctionInfo *
CIRGenFunctionInfo::create(CanQualType resultType,
- llvm::ArrayRef<CanQualType> argTypes) {
+ llvm::ArrayRef<CanQualType> argTypes,
+ RequiredArgs required) {
// The first slot allocated for ArgInfo is for the return value.
void *buffer = operator new(totalSizeToAlloc<ArgInfo>(argTypes.size() + 1));
+ assert(!cir::MissingFeatures::opCallCIRGenFuncInfoParamInfo());
+
CIRGenFunctionInfo *fi = new (buffer) CIRGenFunctionInfo();
- fi->numArgs = argTypes.size();
- assert(!cir::MissingFeatures::opCallCIRGenFuncInfoParamInfo());
+ fi->required = required;
+ fi->numArgs = argTypes.size();
ArgInfo *argsBuffer = fi->getArgsBuffer();
(argsBuffer++)->type = resultType;
for (CanQualType ty : argTypes)
(argsBuffer++)->type = ty;
-
assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
return fi;
}
+cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &fi) {
+ mlir::Type resultType = convertType(fi.getReturnType());
+
+ SmallVector<mlir::Type, 8> argTypes(fi.getNumRequiredArgs());
+
+ unsigned argNo = 0;
+ llvm::ArrayRef<CIRGenFunctionInfoArgInfo> argInfos(fi.argInfoBegin(),
+ fi.getNumRequiredArgs());
+ for (const auto &argInfo : argInfos)
+ argTypes[argNo++] = convertType(argInfo.type);
+
+ return cir::FuncType::get(argTypes,
+ (resultType ? resultType : builder.getVoidTy()),
+ fi.isVariadic());
+}
+
CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
assert(!cir::MissingFeatures::opCallVirtual());
return *this;
@@ -48,6 +67,9 @@ static const CIRGenFunctionInfo &
arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
const CallArgList &args,
const FunctionType *fnType) {
+
+ RequiredArgs required = RequiredArgs::All;
+
if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {
if (proto->isVariadic())
cgm.errorNYI("call to variadic function");
@@ -64,7 +86,7 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
CanQualType retType = fnType->getReturnType()
->getCanonicalTypeUnqualified()
.getUnqualifiedType();
- return cgt.arrangeCIRFunctionInfo(retType, argTypes);
+ return cgt.arrangeCIRFunctionInfo(retType, argTypes, required);
}
const CIRGenFunctionInfo &
@@ -88,6 +110,23 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
return builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
}
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {
+ SmallVector<CanQualType, 8> argTypes;
+ for (unsigned i = 0, e = fpt->getNumParams(); i != e; ++i)
+ argTypes.push_back(fpt->getParamType(i));
+ RequiredArgs required = RequiredArgs::forPrototypePlus(fpt);
+
+ CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
+ return arrangeCIRFunctionInfo(resultType, argTypes, required);
+}
+
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) {
+ CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();
+ return arrangeCIRFunctionInfo(resultType, {}, RequiredArgs(0));
+}
+
RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
const CIRGenCallee &callee,
ReturnValueSlot returnValue,
@@ -102,7 +141,8 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
// Translate all of the arguments as necessary to match the CIR lowering.
for (auto [argNo, arg, argInfo] :
- llvm::enumerate(args, funcInfo.arguments())) {
+ llvm::enumerate(args, funcInfo.argInfos())) {
+
// Insert a padding argument to ensure proper alignment.
assert(!cir::MissingFeatures::opCallPaddingArgs());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
index 645e6b23c4f76..0556408fb98d1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
@@ -25,20 +25,68 @@ struct CIRGenFunctionInfoArgInfo {
CanQualType type;
};
+/// A class for recording the number of arguments that a function signature
+/// requires.
+class RequiredArgs {
+ /// The number of required arguments, or ~0 if the signature does not permit
+ /// optional arguments.
+ unsigned numRequired;
+
+public:
+ enum All_t { All };
+
+ RequiredArgs(All_t _) : numRequired(~0U) {}
+ explicit RequiredArgs(unsigned n) : numRequired(n) { assert(n != ~0U); }
+
+ unsigned getOpaqueData() const { return numRequired; }
+
+ bool allowsOptionalArgs() const { return numRequired != ~0U; }
+
+ /// Compute the arguments required by the given formal prototype, given that
+ /// there may be some additional, non-formal arguments in play.
+ ///
+ /// If FD is not null, this will consider pass_object_size params in FD.
+ static RequiredArgs
+ forPrototypePlus(const clang::FunctionProtoType *prototype) {
+ if (!prototype->isVariadic())
+ return All;
+
+ if (prototype->hasExtParameterInfos())
+ llvm_unreachable("NYI");
+
+ return RequiredArgs(prototype->getNumParams());
+ }
+
+ static RequiredArgs
+ forPrototypePlus(clang::CanQual<clang::FunctionProtoType> prototype) {
+ return forPrototypePlus(prototype.getTypePtr());
+ }
+
+ unsigned getNumRequiredArgs() const {
+ assert(allowsOptionalArgs());
+ return numRequired;
+ }
+};
+
class CIRGenFunctionInfo final
: public llvm::FoldingSetNode,
private llvm::TrailingObjects<CIRGenFunctionInfo,
CIRGenFunctionInfoArgInfo> {
using ArgInfo = CIRGenFunctionInfoArgInfo;
+ RequiredArgs required;
+
unsigned numArgs;
ArgInfo *getArgsBuffer() { return getTrailingObjects<ArgInfo>(); }
const ArgInfo *getArgsBuffer() const { return getTrailingObjects<ArgInfo>(); }
+ CIRGenFunctionInfo() : required(RequiredArgs::All) {}
+
public:
static CIRGenFunctionInfo *create(CanQualType resultType,
- llvm::ArrayRef<CanQualType> argTypes);
+ llvm::ArrayRef<CanQualType> argTypes,
+ RequiredArgs required);
void operator delete(void *p) { ::operator delete(p); }
@@ -51,30 +99,45 @@ class CIRGenFunctionInfo final
// This function has to be CamelCase because llvm::FoldingSet requires so.
// NOLINTNEXTLINE(readability-identifier-naming)
- static void Profile(llvm::FoldingSetNodeID &id, CanQualType resultType,
- llvm::ArrayRef<clang::CanQualType> argTypes) {
+ static void Profile(llvm::FoldingSetNodeID &id, RequiredArgs required,
+ CanQualType resultType,
+ llvm::ArrayRef<CanQualType> argTypes) {
+ id.AddBoolean(required.getOpaqueData());
resultType.Profile(id);
- for (auto i : argTypes)
- i.Profile(id);
+ for (const CanQualType &arg : argTypes)
+ arg.Profile(id);
}
- void Profile(llvm::FoldingSetNodeID &id) { getReturnType().Profile(id); }
-
- llvm::MutableArrayRef<ArgInfo> arguments() {
- return llvm::MutableArrayRef<ArgInfo>(arg_begin(), numArgs);
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ void Profile(llvm::FoldingSetNodeID &id) {
+ id.AddBoolean(required.getOpaqueData());
+ getReturnType().Profile(id);
}
- llvm::ArrayRef<ArgInfo> arguments() const {
- return llvm::ArrayRef<ArgInfo>(arg_begin(), numArgs);
+
+ CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
+
+ const_arg_iterator argInfoBegin() const { return getArgsBuffer() + 1; }
+ const_arg_iterator argInfoEnd() const {
+ return getArgsBuffer() + 1 + numArgs;
}
+ arg_iterator argInfoBegin() { return getArgsBuffer() + 1; }
+ arg_iterator argInfoEnd() { return getArgsBuffer() + 1 + numArgs; }
- const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
- const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + numArgs; }
- arg_iterator arg_begin() { return getArgsBuffer() + 1; }
- arg_iterator arg_end() { return getArgsBuffer() + 1 + numArgs; }
+ unsigned argInfoSize() const { return numArgs; }
- unsigned arg_size() const { return numArgs; }
+ llvm::MutableArrayRef<ArgInfo> argInfos() {
+ return llvm::MutableArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+ }
+ llvm::ArrayRef<ArgInfo> argInfos() const {
+ return llvm::ArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+ }
- CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
+ bool isVariadic() const { return required.allowsOptionalArgs(); }
+ RequiredArgs getRequiredArgs() const { return required; }
+ unsigned getNumRequiredArgs() const {
+ return isVariadic() ? getRequiredArgs().getNumRequiredArgs()
+ : argInfoSize();
+ }
};
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 82bd139295b10..61ba5aa16a5a0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -23,6 +23,7 @@
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/MissingFeatures.h"
+#include "CIRGenFunctionInfo.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/MLIRContext.h"
@@ -247,8 +248,21 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
"function definition with a non-identifier for a name");
return;
}
- cir::FuncType funcType =
- cast<cir::FuncType>(convertType(funcDecl->getType()));
+
+ cir::FuncType funcType;
+ // TODO: Move this to arrangeFunctionDeclaration when it is
+ // implemented.
+ // When declaring a function without a prototype, always use a
+ // non-variadic type.
+ if (CanQual<FunctionNoProtoType> noProto =
+ funcDecl->getType()
+ ->getCanonicalTypeUnqualified()
+ .getAs<FunctionNoProtoType>()) {
+ const CIRGenFunctionInfo &fi = getTypes().arrangeCIRFunctionInfo(
+ noProto->getReturnType(), {}, RequiredArgs::All);
+ funcType = getTypes().getFunctionType(fi);
+ } else
+ funcType = cast<cir::FuncType>(convertType(funcDecl->getType()));
cir::FuncOp funcOp = dyn_cast_if_present<cir::FuncOp>(op);
if (!funcOp || funcOp.getFunctionType() != funcType) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 313a6a0edc8ef..ad93e683bf357 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -1,5 +1,6 @@
#include "CIRGenTypes.h"
+#include "CIRGenFunctionInfo.h"
#include "CIRGenModule.h"
#include "clang/AST/ASTContext.h"
@@ -73,21 +74,19 @@ mlir::Type CIRGenTypes::convertFunctionTypeInternal(QualType qft) {
return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy);
}
- // TODO(CIR): This is a stub of what the final code will be. See the
- // implementation of this function and the implementation of class
- // CIRGenFunction in the ClangIR incubator project.
-
+ const CIRGenFunctionInfo *fi;
if (const auto *fpt = dyn_cast<FunctionProtoType>(ft)) {
- SmallVector<mlir::Type> mlirParamTypes;
- for (unsigned i = 0; i < fpt->getNumParams(); ++i) {
- mlirParamTypes.push_back(convertType(fpt->getParamType(i)));
- }
- return cir::FuncType::get(
- mlirParamTypes, convertType(fpt->getReturnType().getUnqualifiedType()),
- fpt->isVariadic());
+ fi = &arrangeFreeFunctionType(
+ CanQual<FunctionProtoType>::CreateUnsafe(QualType(fpt, 0)));
+ } else {
+ const FunctionNoProtoType *fnpt = cast<FunctionNoProtoType>(ft);
+ fi = &arrangeFreeFunctionType(
+ CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(fnpt, 0)));
}
- cgm.errorNYI(SourceLocation(), "non-prototype function type", qft);
- return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy);
+
+ mlir::Type resultType = getFunctionType(*fi);
+
+ return resultType;
}
// This is CIR's version of CodeGenTypes::addRecordTypeName. It isn't shareable
@@ -518,14 +517,15 @@ bool CIRGenTypes::isZeroInitializable(const RecordDecl *rd) {
return getCIRGenRecordLayout(rd).isZeroInitializable();
}
-const CIRGenFunctionInfo &CIRGenTypes::arrangeCIRFunctionInfo(
- CanQualType returnType, llvm::ArrayRef<clang::CanQualType> argTypes) {
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType,
+ llvm::ArrayRef<CanQualType> argTypes,
+ RequiredArgs required) {
assert(llvm::all_of(argTypes,
- [](CanQualType T) { return T.isCanonicalAsParam(); }));
-
+ [](CanQualType t) { return t.isCanonicalAsParam(); }));
// Lookup or create unique function info.
llvm::FoldingSetNodeID id;
- CIRGenFunctionInfo::Profile(id, returnType, argTypes);
+ CIRGenFunctionInfo::Profile(id, required, returnType, argTypes);
void *insertPos = nullptr;
CIRGenFunctionInfo *fi = functionInfos.FindNodeOrInsertPos(id, insertPos);
@@ -535,7 +535,7 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeCIRFunctionInfo(
assert(!cir::MissingFeatures::opCallCallConv());
// Construction the function info. We co-allocate the ArgInfos.
- fi = CIRGenFunctionInfo::create(returnType, argTypes);
+ fi = CIRGenFunctionInfo::create(returnType, argTypes, required);
functionInfos.InsertNode(fi, insertPos);
return *fi;
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index cf94375d17e12..ff8ce3f87f362 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -127,7 +127,15 @@ class CIRGenTypes {
const CIRGenFunctionInfo &
arrangeCIRFunctionInfo(CanQualType returnType,
- llvm::ArrayRef<clang::CanQualType> argTypes);
+ llvm::ArrayRef<CanQualType> argTypes,
+ RequiredArgs required);
+
+ const CIRGenFunctionInfo &
+ arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt);
+ const CIRGenFunctionInfo &
+ arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt);
+
+ cir::FuncType getFunctionType(const CIRGenFunctionInfo &fi);
};
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp
index 4a4edb4248447..551341ff20c00 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp
@@ -1,16 +1,8 @@
#include "TargetInfo.h"
#include "ABIInfo.h"
-#include "CIRGenFunctionInfo.h"
-#include "clang/CIR/MissingFeatures.h"
using namespace clang;
using namespace clang::CIRGen;
-
-static bool testIfIsVoidTy(QualType ty) {
- const auto *builtinTy = ty->getAs<BuiltinType>();
- return builtinTy && builtinTy->getKind() == BuiltinType::Void;
-}
-
namespace {
class X8664ABIInfo : public ABIInfo {
diff --git a/clang/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c
index 1845d3b64bf68..70dd885f4f6d7 100644
--- a/clang/test/CIR/CodeGen/basic.c
+++ b/clang/test/CIR/CodeGen/basic.c
@@ -233,6 +233,19 @@ int f8(int *p) {
// OGCG: %[[P2:.*]] = load ptr, ptr %[[P_PTR]], align 8
// OGCG: %[[STAR_P:.*]] = load i32, ptr %[[P2]], align 4
+
+void f9() {}
+
+// CIR: cir.func @f9()
+// CIR-NEXT: cir.return
+
+// LLVM: define void @f9()
+// LLVM-NEXT: ret void
+
+// OGCG: define{{.*}} void @f9()
+// OGCG-NEXT: entry:
+// OGCG-NEXT: ret void
+
typedef unsigned long size_type;
typedef unsigned long _Tp;
More information about the cfe-commits
mailing list