https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/136854
>From 9e6c30658f628e736567f57589a6534cfe060902 Mon Sep 17 00:00:00 2001 From: Iris Shi <0...@owo.li> Date: Thu, 8 May 2025 23:40:15 +0800 Subject: [PATCH 1/2] [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 6899e49d990db..157ea1fd87287 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 eecd29cf953cf..097d14b370940 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 @@ -531,14 +530,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); @@ -548,7 +548,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 916246eb6e661..5f5c15a923313 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; >From f17a38e6dc1096594b62ff2dfb0ac90bca22424d Mon Sep 17 00:00:00 2001 From: Iris Shi <0...@owo.li> Date: Tue, 13 May 2025 15:29:27 +0800 Subject: [PATCH 2/2] Address review comments --- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 3 ++- clang/test/CIR/CodeGen/basic.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 157ea1fd87287..b4e27bc5fec6a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -261,8 +261,9 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd, const CIRGenFunctionInfo &fi = getTypes().arrangeCIRFunctionInfo( noProto->getReturnType(), {}, RequiredArgs::All); funcType = getTypes().getFunctionType(fi); - } else + } 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/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c index 5f5c15a923313..d0e241cdc5ae9 100644 --- a/clang/test/CIR/CodeGen/basic.c +++ b/clang/test/CIR/CodeGen/basic.c @@ -246,6 +246,24 @@ void f9() {} // OGCG-NEXT: entry: // OGCG-NEXT: ret void +void f10(int arg0, ...) {} + +// CIR: cir.func @f10(%[[ARG0:.*]]: !s32i loc({{.*}}), ...) +// CIR-NEXT: %[[ARG0_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["arg0", init] {alignment = 4 : i64} +// CIR-NEXT: cir.store %[[ARG0]], %[[ARG0_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR-NEXT: cir.return + +// LLVM: define void @f10(i32 %[[ARG0:.*]], ...) +// LLVM-NEXT: %[[ARG0_PTR:.*]] = alloca i32, i64 1, align 4 +// LLVM-NEXT: store i32 %[[ARG0]], ptr %[[ARG0_PTR]], align 4 +// LLVM-NEXT: ret void + +// OGCG: define{{.*}} void @f10(i32 noundef %[[ARG0:.*]], ...) +// OGCG-NEXT: entry: +// OGCG-NEXT: %[[ARG0_PTR:.*]] = alloca i32, align 4 +// OGCG-NEXT: store i32 %[[ARG0]], ptr %[[ARG0_PTR]], align 4 +// OGCG-NEXT: ret void + typedef unsigned long size_type; typedef unsigned long _Tp; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits