Skip to content

Commit fa2263b

Browse files
authored
[CIR][NFC] Use arrangeFunctionDeclaration to build function types (#139787)
This change replaces the simplified call that we were previously using to convert the function type provided by a global declaration to the CIR function type. We now go through 'arrangeGlobalDeclaration' which builds the function type in a more complicated manner. This change has no observable differences for the currently upstreamed CIR support, but it is necessary to prepare for C++ member function calls, which require the extra handling.
1 parent 9adcb4f commit fa2263b

File tree

5 files changed

+123
-35
lines changed

5 files changed

+123
-35
lines changed

clang/lib/CIR/CodeGen/CIRGenCall.cpp

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,11 @@ CIRGenFunctionInfo::create(CanQualType resultType,
4444

4545
cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &fi) {
4646
mlir::Type resultType = convertType(fi.getReturnType());
47+
SmallVector<mlir::Type, 8> argTypes;
48+
argTypes.reserve(fi.getNumRequiredArgs());
4749

48-
SmallVector<mlir::Type, 8> argTypes(fi.getNumRequiredArgs());
49-
50-
unsigned argNo = 0;
51-
llvm::ArrayRef<CIRGenFunctionInfoArgInfo> argInfos(fi.argInfoBegin(),
52-
fi.getNumRequiredArgs());
53-
for (const auto &argInfo : argInfos)
54-
argTypes[argNo++] = convertType(argInfo.type);
50+
for (const CIRGenFunctionInfoArgInfo &argInfo : fi.requiredArguments())
51+
argTypes.push_back(convertType(argInfo.type));
5552

5653
return cir::FuncType::get(argTypes,
5754
(resultType ? resultType : builder.getVoidTy()),
@@ -63,6 +60,35 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
6360
return *this;
6461
}
6562

63+
/// Adds the formal parameters in FPT to the given prefix. If any parameter in
64+
/// FPT has pass_object_size_attrs, then we'll add parameters for those, too.
65+
/// TODO(cir): this should be shared with LLVM codegen
66+
static void appendParameterTypes(const CIRGenTypes &cgt,
67+
SmallVectorImpl<CanQualType> &prefix,
68+
CanQual<FunctionProtoType> fpt) {
69+
assert(!cir::MissingFeatures::opCallExtParameterInfo());
70+
// Fast path: don't touch param info if we don't need to.
71+
if (!fpt->hasExtParameterInfos()) {
72+
prefix.append(fpt->param_type_begin(), fpt->param_type_end());
73+
return;
74+
}
75+
76+
cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos");
77+
}
78+
79+
/// Arrange the CIR function layout for a value of the given function type, on
80+
/// top of any implicit parameters already stored.
81+
static const CIRGenFunctionInfo &
82+
arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl<CanQualType> &prefix,
83+
CanQual<FunctionProtoType> ftp) {
84+
RequiredArgs required =
85+
RequiredArgs::getFromProtoWithExtraSlots(ftp, prefix.size());
86+
assert(!cir::MissingFeatures::opCallExtParameterInfo());
87+
appendParameterTypes(cgt, prefix, ftp);
88+
CanQualType resultType = ftp->getReturnType().getUnqualifiedType();
89+
return cgt.arrangeCIRFunctionInfo(resultType, prefix, required);
90+
}
91+
6692
static const CIRGenFunctionInfo &
6793
arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
6894
const CallArgList &args,
@@ -95,6 +121,34 @@ CIRGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
95121
return arrangeFreeFunctionLikeCall(*this, cgm, args, fnType);
96122
}
97123

124+
/// Arrange the argument and result information for the declaration or
125+
/// definition of the given function.
126+
const CIRGenFunctionInfo &
127+
CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {
128+
if (const auto *md = dyn_cast<CXXMethodDecl>(fd)) {
129+
if (md->isInstance()) {
130+
cgm.errorNYI("arrangeFunctionDeclaration: instance method");
131+
}
132+
}
133+
134+
CanQualType funcTy = fd->getType()->getCanonicalTypeUnqualified();
135+
136+
assert(isa<FunctionType>(funcTy));
137+
// TODO: setCUDAKernelCallingConvention
138+
assert(!cir::MissingFeatures::cudaSupport());
139+
140+
// When declaring a function without a prototype, always use a non-variadic
141+
// type.
142+
if (CanQual<FunctionNoProtoType> noProto =
143+
funcTy.getAs<FunctionNoProtoType>()) {
144+
assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
145+
return arrangeCIRFunctionInfo(noProto->getReturnType(), std::nullopt,
146+
RequiredArgs::All);
147+
}
148+
149+
return arrangeFreeFunctionType(funcTy.castAs<FunctionProtoType>());
150+
}
151+
98152
static cir::CIRCallOpInterface
99153
emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
100154
cir::FuncOp directFuncOp,
@@ -112,13 +166,8 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
112166

113167
const CIRGenFunctionInfo &
114168
CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {
115-
SmallVector<CanQualType, 8> argTypes;
116-
for (unsigned i = 0, e = fpt->getNumParams(); i != e; ++i)
117-
argTypes.push_back(fpt->getParamType(i));
118-
RequiredArgs required = RequiredArgs::forPrototypePlus(fpt);
119-
120-
CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
121-
return arrangeCIRFunctionInfo(resultType, argTypes, required);
169+
SmallVector<CanQualType, 16> argTypes;
170+
return ::arrangeCIRFunctionInfo(*this, argTypes, fpt);
122171
}
123172

124173
const CIRGenFunctionInfo &

clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,21 @@ class RequiredArgs {
4747
///
4848
/// If FD is not null, this will consider pass_object_size params in FD.
4949
static RequiredArgs
50-
forPrototypePlus(const clang::FunctionProtoType *prototype) {
50+
getFromProtoWithExtraSlots(const clang::FunctionProtoType *prototype,
51+
unsigned additional) {
5152
if (!prototype->isVariadic())
5253
return All;
5354

5455
if (prototype->hasExtParameterInfos())
5556
llvm_unreachable("NYI");
5657

57-
return RequiredArgs(prototype->getNumParams());
58+
return RequiredArgs(prototype->getNumParams() + additional);
5859
}
5960

6061
static RequiredArgs
61-
forPrototypePlus(clang::CanQual<clang::FunctionProtoType> prototype) {
62-
return forPrototypePlus(prototype.getTypePtr());
62+
getFromProtoWithExtraSlots(clang::CanQual<clang::FunctionProtoType> prototype,
63+
unsigned additional) {
64+
return getFromProtoWithExtraSlots(prototype.getTypePtr(), additional);
6365
}
6466

6567
unsigned getNumRequiredArgs() const {
@@ -114,6 +116,14 @@ class CIRGenFunctionInfo final
114116
getReturnType().Profile(id);
115117
}
116118

119+
llvm::ArrayRef<ArgInfo> arguments() const {
120+
return llvm::ArrayRef<ArgInfo>(argInfoBegin(), numArgs);
121+
}
122+
123+
llvm::ArrayRef<ArgInfo> requiredArguments() const {
124+
return llvm::ArrayRef<ArgInfo>(argInfoBegin(), getNumRequiredArgs());
125+
}
126+
117127
CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
118128

119129
const_arg_iterator argInfoBegin() const { return getArgsBuffer() + 1; }

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -249,21 +249,8 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
249249
return;
250250
}
251251

252-
cir::FuncType funcType;
253-
// TODO: Move this to arrangeFunctionDeclaration when it is
254-
// implemented.
255-
// When declaring a function without a prototype, always use a
256-
// non-variadic type.
257-
if (CanQual<FunctionNoProtoType> noProto =
258-
funcDecl->getType()
259-
->getCanonicalTypeUnqualified()
260-
.getAs<FunctionNoProtoType>()) {
261-
const CIRGenFunctionInfo &fi = getTypes().arrangeCIRFunctionInfo(
262-
noProto->getReturnType(), {}, RequiredArgs::All);
263-
funcType = getTypes().getFunctionType(fi);
264-
} else {
265-
funcType = cast<cir::FuncType>(convertType(funcDecl->getType()));
266-
}
252+
const CIRGenFunctionInfo &fi = getTypes().arrangeGlobalDeclaration(gd);
253+
cir::FuncType funcType = getTypes().getFunctionType(fi);
267254

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

clang/lib/CIR/CodeGen/CIRGenTypes.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,3 +553,17 @@ CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType,
553553

554554
return *fi;
555555
}
556+
557+
const CIRGenFunctionInfo &CIRGenTypes::arrangeGlobalDeclaration(GlobalDecl gd) {
558+
assert(!dyn_cast<ObjCMethodDecl>(gd.getDecl()) &&
559+
"This is reported as a FIXME in LLVM codegen");
560+
const auto *fd = cast<FunctionDecl>(gd.getDecl());
561+
562+
if (isa<CXXConstructorDecl>(gd.getDecl()) ||
563+
isa<CXXDestructorDecl>(gd.getDecl())) {
564+
cgm.errorNYI(SourceLocation(),
565+
"arrangeGlobalDeclaration for C++ constructor or destructor");
566+
}
567+
568+
return arrangeFunctionDeclaration(fd);
569+
}

clang/lib/CIR/CodeGen/CIRGenTypes.h

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,36 @@ class CIRGenTypes {
117117
// TODO: convert this comment to account for MLIR's equivalence
118118
mlir::Type convertTypeForMem(clang::QualType, bool forBitField = false);
119119

120+
/// Get the CIR function type for \arg Info.
121+
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info);
122+
123+
// The arrangement methods are split into three families:
124+
// - those meant to drive the signature and prologue/epilogue
125+
// of a function declaration or definition,
126+
// - those meant for the computation of the CIR type for an abstract
127+
// appearance of a function, and
128+
// - those meant for performing the CIR-generation of a call.
129+
// They differ mainly in how they deal with optional (i.e. variadic)
130+
// arguments, as well as unprototyped functions.
131+
//
132+
// Key points:
133+
// - The CIRGenFunctionInfo for emitting a specific call site must include
134+
// entries for the optional arguments.
135+
// - The function type used at the call site must reflect the formal
136+
// signature
137+
// of the declaration being called, or else the call will go away.
138+
// - For the most part, unprototyped functions are called by casting to a
139+
// formal signature inferred from the specific argument types used at the
140+
// call-site. However, some targets (e.g. x86-64) screw with this for
141+
// compatability reasons.
142+
143+
const CIRGenFunctionInfo &arrangeGlobalDeclaration(GlobalDecl gd);
144+
145+
/// Free functions are functions that are compatible with an ordinary C
146+
/// function pointer type.
147+
const CIRGenFunctionInfo &
148+
arrangeFunctionDeclaration(const clang::FunctionDecl *fd);
149+
120150
/// Return whether a type can be zero-initialized (in the C++ sense) with an
121151
/// LLVM zeroinitializer.
122152
bool isZeroInitializable(clang::QualType ty);
@@ -134,8 +164,6 @@ class CIRGenTypes {
134164
arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt);
135165
const CIRGenFunctionInfo &
136166
arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt);
137-
138-
cir::FuncType getFunctionType(const CIRGenFunctionInfo &fi);
139167
};
140168

141169
} // namespace clang::CIRGen

0 commit comments

Comments
 (0)