Skip to content

[CIR] Cleanup support for C functions #136854

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 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions clang/lib/CIR/CodeGen/CIRGenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,51 @@

#include "CIRGenCall.h"
#include "CIRGenFunction.h"
#include "CIRGenFunctionInfo.h"
#include "clang/CIR/MissingFeatures.h"

using namespace clang;
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;
Expand All @@ -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");
Expand All @@ -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 &
Expand All @@ -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,
Expand All @@ -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());

Expand Down
97 changes: 80 additions & 17 deletions clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); }

Expand All @@ -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
Expand Down
19 changes: 17 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -247,8 +248,22 @@ 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) {
Expand Down
38 changes: 19 additions & 19 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "CIRGenTypes.h"

#include "CIRGenFunctionInfo.h"
#include "CIRGenModule.h"

#include "clang/AST/ASTContext.h"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 0 additions & 8 deletions clang/lib/CIR/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
Loading