[clang] [CIR] Cleanup support for C functions (PR #136854)
Iris Shi via cfe-commits
cfe-commits at lists.llvm.org
Thu May 8 08:40:33 PDT 2025
https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/136854
>From dbe66e5e48f769589592e22bcfb8c122910d91d1 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 | 110 ++++++++++++++++++---
clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h | 103 +++++++++++++++----
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 18 +++-
clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 40 ++++----
clang/lib/CIR/CodeGen/CIRGenTypes.h | 10 +-
clang/lib/CIR/CodeGen/TargetInfo.cpp | 8 +-
clang/test/CIR/CodeGen/basic.c | 13 +++
7 files changed, 244 insertions(+), 58 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index bed0db28818f1..c8c12b509dca8 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,20 +21,22 @@ 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;
@@ -45,7 +48,7 @@ namespace {
/// CIRGenFunctionInfo should be passed to actual CIR function.
class ClangToCIRArgMapping {
static constexpr unsigned invalidIndex = ~0U;
- unsigned totalNumCIRArgs;
+ unsigned totalNumCIRArgs = 0;
/// Arguments of CIR function corresponding to single Clang argument.
struct CIRArgs {
@@ -61,14 +64,20 @@ class ClangToCIRArgMapping {
public:
ClangToCIRArgMapping(const ASTContext &astContext,
- const CIRGenFunctionInfo &funcInfo)
- : totalNumCIRArgs(0), argInfo(funcInfo.arg_size()) {
+ const CIRGenFunctionInfo &funcInfo,
+ bool onlyRequiredArgs)
+ : argInfo(onlyRequiredArgs ? funcInfo.getNumRequiredArgs()
+ : funcInfo.argInfoSize()) {
unsigned cirArgNo = 0;
assert(!cir::MissingFeatures::opCallABIIndirectArg());
unsigned argNo = 0;
- for (const CIRGenFunctionInfoArgInfo &i : funcInfo.arguments()) {
+ llvm::ArrayRef<CIRGenFunctionInfoArgInfo> argInfos(
+ funcInfo.argInfoBegin(), onlyRequiredArgs
+ ? funcInfo.getNumRequiredArgs()
+ : funcInfo.argInfoSize());
+ for (const CIRGenFunctionInfoArgInfo &i : argInfos) {
// Collect data about CIR arguments corresponding to Clang argument ArgNo.
CIRArgs &cirArgs = argInfo[argNo];
@@ -119,6 +128,63 @@ class ClangToCIRArgMapping {
} // namespace
+cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &fi) {
+ bool inserted = functionsBeingProcessed.insert(&fi).second;
+ (void)inserted;
+ assert(inserted && "Recursively being processed?");
+
+ mlir::Type resultType;
+ const cir::ABIArgInfo &retInfo = fi.getReturnInfo();
+
+ switch (retInfo.getKind()) {
+ case cir::ABIArgInfo::Ignore:
+ // TODO(CIR): This should probably be the None type from the builtin
+ // dialect.
+ resultType = nullptr;
+ break;
+ case cir::ABIArgInfo::Direct:
+ resultType = retInfo.getCoerceToType();
+ break;
+ }
+
+ ClangToCIRArgMapping cirFunctionArgs(getASTContext(), fi, true);
+ SmallVector<mlir::Type, 8> argTypes(cirFunctionArgs.totalCIRArgs());
+
+ unsigned argNo = 0;
+ llvm::ArrayRef<CIRGenFunctionInfoArgInfo> argInfos(fi.argInfoBegin(),
+ fi.getNumRequiredArgs());
+ for (const auto &argInfo : argInfos) {
+ const auto &abiArgInfo = argInfo.info;
+
+ unsigned firstCIRArg, numCIRArgs;
+ std::tie(firstCIRArg, numCIRArgs) = cirFunctionArgs.getCIRArgs(argNo);
+
+ switch (abiArgInfo.getKind()) {
+ case cir::ABIArgInfo::Direct: {
+ mlir::Type argType = abiArgInfo.getCoerceToType();
+ // TODO: handle the test against llvm::RecordType from codegen
+ assert(numCIRArgs == 1);
+ argTypes[firstCIRArg] = argType;
+ break;
+ }
+ default:
+ cgm.errorNYI("getFunctionType: unhandled argument kind");
+ }
+
+ ++argNo;
+ }
+ assert(argNo == fi.argInfoSize() &&
+ "Mismatch between function info and args");
+
+ bool erased = functionsBeingProcessed.erase(&fi);
+ (void)erased;
+ assert(erased && "Not in set?");
+
+ return cir::FuncType::get(argTypes,
+ (resultType ? resultType : builder.getVoidTy()),
+ fi.isVariadic());
+}
+
CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
assert(!cir::MissingFeatures::opCallVirtual());
return *this;
@@ -128,6 +194,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");
@@ -144,7 +213,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 &
@@ -168,6 +237,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,
@@ -177,16 +263,16 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
QualType retTy = funcInfo.getReturnType();
const cir::ABIArgInfo &retInfo = funcInfo.getReturnInfo();
- ClangToCIRArgMapping cirFuncArgs(cgm.getASTContext(), funcInfo);
+ ClangToCIRArgMapping cirFuncArgs(cgm.getASTContext(), funcInfo, false);
SmallVector<mlir::Value, 16> cirCallArgs(cirFuncArgs.totalCIRArgs());
assert(!cir::MissingFeatures::emitLifetimeMarkers());
// Translate all of the arguments as necessary to match the CIR lowering.
- assert(funcInfo.arg_size() == args.size() &&
+ assert(funcInfo.argInfoSize() == args.size() &&
"Mismatch between function signature & arguments.");
unsigned argNo = 0;
- for (const auto &[arg, argInfo] : llvm::zip(args, funcInfo.arguments())) {
+ for (const auto &[arg, argInfo] : llvm::zip(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 4319f7a2be225..50be94dd7ee6f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
@@ -27,20 +27,68 @@ struct CIRGenFunctionInfoArgInfo {
cir::ABIArgInfo info;
};
+/// 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); }
@@ -53,35 +101,52 @@ 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);
- }
- llvm::ArrayRef<ArgInfo> arguments() const {
- return llvm::ArrayRef<ArgInfo>(arg_begin(), numArgs);
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ void Profile(llvm::FoldingSetNodeID &id) {
+ id.AddBoolean(required.getOpaqueData());
+ getReturnType().Profile(id);
+ for (const ArgInfo &argInfo : argInfos())
+ argInfo.type.Profile(id);
}
- 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 arg_size() const { return numArgs; }
-
CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
cir::ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
const cir::ABIArgInfo &getReturnInfo() const {
return getArgsBuffer()[0].info;
}
+
+ 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; }
+
+ unsigned argInfoSize() const { return numArgs; }
+
+ llvm::MutableArrayRef<ArgInfo> argInfos() {
+ return llvm::MutableArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+ }
+ llvm::ArrayRef<ArgInfo> argInfos() const {
+ return llvm::ArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+ }
+
+ 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 89dc5eea7f028..ea25aca8e6ff8 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);
bool inserted = functionsBeingProcessed.insert(fi).second;
@@ -552,7 +552,7 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeCIRFunctionInfo(
if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr)
retInfo.setCoerceToType(convertType(fi->getReturnType()));
- for (CIRGenFunctionInfoArgInfo &i : fi->arguments())
+ for (CIRGenFunctionInfoArgInfo &i : fi->argInfos())
if (i.info.canHaveCoerceToType() && i.info.getCoerceToType() == nullptr)
i.info.setCoerceToType(convertType(i.type));
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 0b70170cadb69..a2b71876026c9 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp
@@ -32,11 +32,11 @@ void X8664ABIInfo::computeInfo(CIRGenFunctionInfo &funcInfo) const {
// Top level CIR has unlimited arguments and return types. Lowering for ABI
// specific concerns should happen during a lowering phase. Assume everything
// is direct for now.
- for (CIRGenFunctionInfoArgInfo &info : funcInfo.arguments()) {
- if (testIfIsVoidTy(info.type))
- info.info = cir::ABIArgInfo::getIgnore();
+ for (CIRGenFunctionInfoArgInfo &argInfo : funcInfo.argInfos()) {
+ if (testIfIsVoidTy(argInfo.type))
+ argInfo.info = cir::ABIArgInfo::getIgnore();
else
- info.info = cir::ABIArgInfo::getDirect(cgt.convertType(info.type));
+ argInfo.info = cir::ABIArgInfo::getDirect(cgt.convertType(argInfo.type));
}
CanQualType retTy = funcInfo.getReturnType();
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