Skip to content

Commit fd1d37e

Browse files
committed
[CIR] Cleanup support for C functions
1 parent d0cd6f3 commit fd1d37e

File tree

7 files changed

+232
-29
lines changed

7 files changed

+232
-29
lines changed

clang/lib/CIR/CodeGen/CIRGenCall.cpp

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,76 @@
1313

1414
#include "CIRGenCall.h"
1515
#include "CIRGenFunction.h"
16+
#include "CIRGenFunctionInfo.h"
1617
#include "clang/CIR/MissingFeatures.h"
1718

1819
using namespace clang;
1920
using namespace clang::CIRGen;
2021

21-
CIRGenFunctionInfo *CIRGenFunctionInfo::create(CanQualType resultType) {
22-
void *buffer = operator new(totalSizeToAlloc<ArgInfo>(1));
22+
CIRGenFunctionInfo *
23+
CIRGenFunctionInfo::create(CanQualType resultType,
24+
llvm::ArrayRef<CanQualType> argTypes,
25+
RequiredArgs required) {
26+
void *buffer = operator new(totalSizeToAlloc<ArgInfo>(argTypes.size() + 1));
2327

2428
CIRGenFunctionInfo *fi = new (buffer) CIRGenFunctionInfo();
29+
30+
fi->required = required;
31+
fi->numArgs = argTypes.size();
2532
fi->getArgsBuffer()[0].type = resultType;
33+
for (unsigned i = 0; i < argTypes.size(); ++i)
34+
fi->getArgsBuffer()[i + 1].type = argTypes[i];
2635

2736
return fi;
2837
}
2938

39+
cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &fi) {
40+
bool inserted = functionsBeingProcessed.insert(&fi).second;
41+
assert(inserted && "Recursively being processed?");
42+
43+
mlir::Type resultType = nullptr;
44+
const cir::ABIArgInfo &retAI = fi.getReturnInfo();
45+
46+
switch (retAI.getKind()) {
47+
case cir::ABIArgInfo::Ignore:
48+
// TODO(CIR): This should probably be the None type from the builtin
49+
// dialect.
50+
resultType = nullptr;
51+
break;
52+
53+
case cir::ABIArgInfo::Direct:
54+
resultType = retAI.getCoerceToType();
55+
break;
56+
57+
default:
58+
assert(false && "NYI");
59+
}
60+
61+
SmallVector<mlir::Type, 8> argTypes;
62+
unsigned argNo = 0;
63+
CIRGenFunctionInfo::const_arg_iterator it = fi.arg_begin(),
64+
ie = it + fi.getNumRequiredArgs();
65+
for (; it != ie; ++it, ++argNo) {
66+
const auto &argInfo = it->info;
67+
68+
switch (argInfo.getKind()) {
69+
default:
70+
llvm_unreachable("NYI");
71+
case cir::ABIArgInfo::Direct:
72+
mlir::Type argType = argInfo.getCoerceToType();
73+
argTypes.push_back(argType);
74+
break;
75+
}
76+
}
77+
78+
bool erased = functionsBeingProcessed.erase(&fi);
79+
assert(erased && "Not in set?");
80+
81+
return cir::FuncType::get(argTypes,
82+
(resultType ? resultType : builder.getVoidTy()),
83+
fi.isVariadic());
84+
}
85+
3086
CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
3187
assert(!cir::MissingFeatures::opCallVirtual());
3288
return *this;
@@ -35,6 +91,9 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
3591
static const CIRGenFunctionInfo &
3692
arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
3793
const FunctionType *fnType) {
94+
95+
RequiredArgs required = RequiredArgs::All;
96+
3897
if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {
3998
if (proto->isVariadic())
4099
cgm.errorNYI("call to variadic function");
@@ -49,7 +108,7 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
49108
CanQualType retType = fnType->getReturnType()
50109
->getCanonicalTypeUnqualified()
51110
.getUnqualifiedType();
52-
return cgt.arrangeCIRFunctionInfo(retType);
111+
return cgt.arrangeCIRFunctionInfo(retType, {}, required);
53112
}
54113

55114
const CIRGenFunctionInfo &
@@ -71,6 +130,23 @@ static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf,
71130
return builder.createCallOp(callLoc, directFuncOp);
72131
}
73132

133+
const CIRGenFunctionInfo &
134+
CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {
135+
SmallVector<CanQualType, 16> argTypes;
136+
for (unsigned i = 0, e = fpt->getNumParams(); i != e; ++i)
137+
argTypes.push_back(fpt->getParamType(i));
138+
RequiredArgs required = RequiredArgs::forPrototypePlus(fpt);
139+
140+
CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
141+
return arrangeCIRFunctionInfo(resultType, argTypes, required);
142+
}
143+
144+
const CIRGenFunctionInfo &
145+
CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) {
146+
CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();
147+
return arrangeCIRFunctionInfo(resultType, {}, RequiredArgs(0));
148+
}
149+
74150
RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
75151
const CIRGenCallee &callee,
76152
ReturnValueSlot returnValue,

clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,68 @@ struct CIRGenFunctionInfoArgInfo {
2727
cir::ABIArgInfo info;
2828
};
2929

30+
/// A class for recording the number of arguments that a function signature
31+
/// requires.
32+
class RequiredArgs {
33+
/// The number of required arguments, or ~0 if the signature does not permit
34+
/// optional arguments.
35+
unsigned numRequired;
36+
37+
public:
38+
enum All_t { All };
39+
40+
RequiredArgs(All_t _) : numRequired(~0U) {}
41+
explicit RequiredArgs(unsigned n) : numRequired(n) { assert(n != ~0U); }
42+
43+
unsigned getOpaqueData() const { return numRequired; }
44+
45+
bool allowsOptionalArgs() const { return numRequired != ~0U; }
46+
47+
/// Compute the arguments required by the given formal prototype, given that
48+
/// there may be some additional, non-formal arguments in play.
49+
///
50+
/// If FD is not null, this will consider pass_object_size params in FD.
51+
static RequiredArgs
52+
forPrototypePlus(const clang::FunctionProtoType *prototype) {
53+
if (!prototype->isVariadic())
54+
return All;
55+
56+
if (prototype->hasExtParameterInfos())
57+
llvm_unreachable("NYI");
58+
59+
return RequiredArgs(prototype->getNumParams());
60+
}
61+
62+
static RequiredArgs
63+
forPrototypePlus(clang::CanQual<clang::FunctionProtoType> prototype) {
64+
return forPrototypePlus(prototype.getTypePtr());
65+
}
66+
67+
unsigned getNumRequiredArgs() const {
68+
assert(allowsOptionalArgs());
69+
return numRequired;
70+
}
71+
};
72+
3073
class CIRGenFunctionInfo final
3174
: public llvm::FoldingSetNode,
3275
private llvm::TrailingObjects<CIRGenFunctionInfo,
3376
CIRGenFunctionInfoArgInfo> {
3477
using ArgInfo = CIRGenFunctionInfoArgInfo;
3578

79+
RequiredArgs required;
80+
81+
unsigned numArgs;
82+
3683
ArgInfo *getArgsBuffer() { return getTrailingObjects<ArgInfo>(); }
3784
const ArgInfo *getArgsBuffer() const { return getTrailingObjects<ArgInfo>(); }
3885

86+
CIRGenFunctionInfo() : required(RequiredArgs::All) {}
87+
3988
public:
40-
static CIRGenFunctionInfo *create(CanQualType resultType);
89+
static CIRGenFunctionInfo *create(CanQualType resultType,
90+
llvm::ArrayRef<CanQualType> argTypes,
91+
RequiredArgs required);
4192

4293
void operator delete(void *p) { ::operator delete(p); }
4394

@@ -47,18 +98,51 @@ class CIRGenFunctionInfo final
4798

4899
// This function has to be CamelCase because llvm::FoldingSet requires so.
49100
// NOLINTNEXTLINE(readability-identifier-naming)
50-
static void Profile(llvm::FoldingSetNodeID &id, CanQualType resultType) {
101+
static void Profile(llvm::FoldingSetNodeID &id, RequiredArgs required,
102+
CanQualType resultType,
103+
llvm::ArrayRef<CanQualType> argTypes) {
104+
id.AddBoolean(required.getOpaqueData());
51105
resultType.Profile(id);
106+
for (const auto &arg : argTypes)
107+
arg.Profile(id);
52108
}
53109

54-
void Profile(llvm::FoldingSetNodeID &id) { getReturnType().Profile(id); }
110+
// NOLINTNEXTLINE(readability-identifier-naming)
111+
void Profile(llvm::FoldingSetNodeID &id) {
112+
id.AddBoolean(required.getOpaqueData());
113+
getReturnType().Profile(id);
114+
for (const auto &i : arguments())
115+
i.type.Profile(id);
116+
}
55117

56118
CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
57119

58120
cir::ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
59121
const cir::ABIArgInfo &getReturnInfo() const {
60122
return getArgsBuffer()[0].info;
61123
}
124+
using const_arg_iterator = const ArgInfo *;
125+
using arg_iterator = ArgInfo *;
126+
127+
const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
128+
const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + numArgs; }
129+
arg_iterator arg_begin() { return getArgsBuffer() + 1; }
130+
arg_iterator arg_end() { return getArgsBuffer() + 1 + numArgs; }
131+
132+
unsigned arg_size() const { return numArgs; }
133+
134+
llvm::MutableArrayRef<ArgInfo> arguments() {
135+
return llvm::MutableArrayRef<ArgInfo>(arg_begin(), numArgs);
136+
}
137+
llvm::ArrayRef<ArgInfo> arguments() const {
138+
return llvm::ArrayRef<ArgInfo>(arg_begin(), numArgs);
139+
}
140+
141+
bool isVariadic() const { return required.allowsOptionalArgs(); }
142+
RequiredArgs getRequiredArgs() const { return required; }
143+
unsigned getNumRequiredArgs() const {
144+
return isVariadic() ? getRequiredArgs().getNumRequiredArgs() : arg_size();
145+
}
62146
};
63147

64148
} // namespace clang::CIRGen

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,21 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
212212
"function definition with a non-identifier for a name");
213213
return;
214214
}
215-
cir::FuncType funcType =
216-
cast<cir::FuncType>(convertType(funcDecl->getType()));
215+
216+
cir::FuncType funcType;
217+
// TODO: Move this to arrangeFunctionDeclaration when it is
218+
// implemented.
219+
// When declaring a function without a prototype, always use a
220+
// non-variadic type.
221+
if (CanQual<FunctionNoProtoType> noProto =
222+
funcDecl->getType()
223+
->getCanonicalTypeUnqualified()
224+
.getAs<FunctionNoProtoType>()) {
225+
auto &fi = getTypes().arrangeCIRFunctionInfo(noProto->getReturnType(), {},
226+
RequiredArgs::All);
227+
funcType = getTypes().getFunctionType(fi);
228+
} else
229+
funcType = cast<cir::FuncType>(convertType(funcDecl->getType()));
217230

218231
cir::FuncOp funcOp = dyn_cast_if_present<cir::FuncOp>(op);
219232
if (!funcOp || funcOp.getFunctionType() != funcType) {

clang/lib/CIR/CodeGen/CIRGenTypes.cpp

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,19 @@ mlir::Type CIRGenTypes::convertFunctionTypeInternal(QualType qft) {
7373
return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy);
7474
}
7575

76-
// TODO(CIR): This is a stub of what the final code will be. See the
77-
// implementation of this function and the implementation of class
78-
// CIRGenFunction in the ClangIR incubator project.
79-
76+
const CIRGenFunctionInfo *fi;
8077
if (const auto *fpt = dyn_cast<FunctionProtoType>(ft)) {
81-
SmallVector<mlir::Type> mlirParamTypes;
82-
for (unsigned i = 0; i < fpt->getNumParams(); ++i) {
83-
mlirParamTypes.push_back(convertType(fpt->getParamType(i)));
84-
}
85-
return cir::FuncType::get(
86-
mlirParamTypes, convertType(fpt->getReturnType().getUnqualifiedType()),
87-
fpt->isVariadic());
78+
fi = &arrangeFreeFunctionType(
79+
CanQual<FunctionProtoType>::CreateUnsafe(QualType(fpt, 0)));
80+
} else {
81+
const FunctionNoProtoType *fnpt = cast<FunctionNoProtoType>(ft);
82+
fi = &arrangeFreeFunctionType(
83+
CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(fnpt, 0)));
8884
}
89-
cgm.errorNYI(SourceLocation(), "non-prototype function type", qft);
90-
return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy);
85+
86+
mlir::Type resultType = getFunctionType(*fi);
87+
88+
return resultType;
9189
}
9290

9391
// This is CIR's version of CodeGenTypes::addRecordTypeName. It isn't shareable
@@ -494,10 +492,12 @@ bool CIRGenTypes::isZeroInitializable(clang::QualType t) {
494492
}
495493

496494
const CIRGenFunctionInfo &
497-
CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType) {
495+
CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType,
496+
llvm::ArrayRef<CanQualType> argTypes,
497+
RequiredArgs required) {
498498
// Lookup or create unique function info.
499499
llvm::FoldingSetNodeID id;
500-
CIRGenFunctionInfo::Profile(id, returnType);
500+
CIRGenFunctionInfo::Profile(id, required, returnType, argTypes);
501501

502502
void *insertPos = nullptr;
503503
CIRGenFunctionInfo *fi = functionInfos.FindNodeOrInsertPos(id, insertPos);
@@ -507,14 +507,13 @@ CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType) {
507507
assert(!cir::MissingFeatures::opCallCallConv());
508508

509509
// Construction the function info. We co-allocate the ArgInfos.
510-
fi = CIRGenFunctionInfo::create(returnType);
510+
fi = CIRGenFunctionInfo::create(returnType, argTypes, required);
511511
functionInfos.InsertNode(fi, insertPos);
512512

513513
bool inserted = functionsBeingProcessed.insert(fi).second;
514514
(void)inserted;
515515
assert(inserted && "Are functions being processed recursively?");
516516

517-
assert(!cir::MissingFeatures::opCallCallConv());
518517
getABIInfo().computeInfo(*fi);
519518

520519
// Loop over all of the computed argument and return value info. If any of
@@ -524,7 +523,9 @@ CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType) {
524523
if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr)
525524
retInfo.setCoerceToType(convertType(fi->getReturnType()));
526525

527-
assert(!cir::MissingFeatures::opCallArgs());
526+
for (auto &i : fi->arguments())
527+
if (i.info.canHaveCoerceToType() && i.info.getCoerceToType() == nullptr)
528+
i.info.setCoerceToType(convertType(i.type));
528529

529530
bool erased = functionsBeingProcessed.erase(fi);
530531
(void)erased;

clang/lib/CIR/CodeGen/CIRGenTypes.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,17 @@ class CIRGenTypes {
123123

124124
const CIRGenFunctionInfo &arrangeFreeFunctionCall(const FunctionType *fnType);
125125

126-
const CIRGenFunctionInfo &arrangeCIRFunctionInfo(CanQualType returnType);
126+
const CIRGenFunctionInfo &
127+
arrangeCIRFunctionInfo(CanQualType returnType,
128+
llvm::ArrayRef<CanQualType> argTypes,
129+
RequiredArgs required);
130+
131+
const CIRGenFunctionInfo &
132+
arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt);
133+
const CIRGenFunctionInfo &
134+
arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt);
135+
136+
cir::FuncType getFunctionType(const CIRGenFunctionInfo &fi);
127137
};
128138

129139
} // namespace clang::CIRGen

clang/lib/CIR/CodeGen/TargetInfo.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,14 @@ void X8664ABIInfo::computeInfo(CIRGenFunctionInfo &funcInfo) const {
3232
// Top level CIR has unlimited arguments and return types. Lowering for ABI
3333
// specific concerns should happen during a lowering phase. Assume everything
3434
// is direct for now.
35-
assert(!cir::MissingFeatures::opCallArgs());
36-
35+
for (CIRGenFunctionInfo::arg_iterator it = funcInfo.arg_begin(),
36+
ie = funcInfo.arg_end();
37+
it != ie; ++it) {
38+
if (testIfIsVoidTy(it->type))
39+
it->info = cir::ABIArgInfo::getIgnore();
40+
else
41+
it->info = cir::ABIArgInfo::getDirect(cgt.convertType(it->type));
42+
}
3743
CanQualType retTy = funcInfo.getReturnType();
3844
if (testIfIsVoidTy(retTy))
3945
funcInfo.getReturnInfo() = cir::ABIArgInfo::getIgnore();

0 commit comments

Comments
 (0)