[clang] [CIR] Add pass_object_size hidden parameter support (PR #191482)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 15 12:04:25 PDT 2026
https://github.com/adams381 updated https://github.com/llvm/llvm-project/pull/191482
>From 908e5f183e6eaa63670141cf80818f69857f53d9 Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Fri, 10 Apr 2026 11:10:38 -0700
Subject: [PATCH 1/3] [CIR] Add pass_object_size hidden parameter support
Implement hidden parameter insertion for
__attribute__((pass_object_size(N))). The compiler now emits an extra
i64 parameter per annotated param, filled with __builtin_object_size
at the call site (constant-folded when possible, otherwise via
cir.objsize / @llvm.objectsize).
Key changes:
- appendParameterTypes adds canonical size_t for each param with
hasPassObjectSize()
- RequiredArgs::getFromProtoWithExtraSlots counts pass_object_size
slots for variadic required-arg accounting
- maybeEmitImplicitObjectSize calls evaluateOrEmitBuiltinObjectSize
to fill the hidden param at call sites
- buildFunctionArgList creates ImplicitParamDecl entries so callee
bodies can load the passed size via sizeArguments
- emitBuiltinObjectSize checks sizeArguments before falling back to
cir.objsize, matching classic codegen behavior
Made-with: Cursor
---
clang/include/clang/CIR/MissingFeatures.h | 2 +-
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 24 +++++++-
clang/lib/CIR/CodeGen/CIRGenCall.cpp | 34 ++++++++---
clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 11 +++-
clang/lib/CIR/CodeGen/CIRGenFunction.h | 5 ++
clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h | 6 +-
clang/test/CIR/CodeGen/pass-object-size.c | 65 ++++++++++++++++++++++
7 files changed, 133 insertions(+), 14 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/pass-object-size.c
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index ac02433fb504a..ca857701b6b4f 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -109,7 +109,7 @@ struct MissingFeatures {
static bool opCallSurroundingTry() { return false; }
static bool opCallASTAttr() { return false; }
static bool opCallObjCMethod() { return false; }
- static bool opCallExtParameterInfo() { return false; }
+
static bool opCallCIRGenFuncInfoParamInfo() { return false; }
static bool opCallCIRGenFuncInfoExtParamInfo() { return false; }
static bool opCallChain() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 1a6aeef73fb79..62729839b6ae4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -2581,11 +2581,33 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
return cir::VAArgOp::create(builder, loc, type, vaList);
}
+/// Checks if using the result of __builtin_object_size(p, @p from) in place of
+/// __builtin_object_size(p, @p to) is correct.
+static bool areBOSTypesCompatible(int from, int to) {
+ return from == to || (from == 0 && to == 1) || (from == 3 && to == 2);
+}
+
mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type,
cir::IntType resType,
mlir::Value emittedE,
bool isDynamic) {
- assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs());
+ // If this is a pass_object_size parameter, load the implicit size arg.
+ if (auto *d = dyn_cast<DeclRefExpr>(e->IgnoreParenImpCasts())) {
+ auto *param = dyn_cast<ParmVarDecl>(d->getDecl());
+ auto *ps = d->getDecl()->getAttr<PassObjectSizeAttr>();
+ if (param && ps && areBOSTypesCompatible(ps->getType(), type)) {
+ auto iter = sizeArguments.find(param);
+ assert(iter != sizeArguments.end());
+
+ const ImplicitParamDecl *sizeDecl = iter->second;
+ auto dIter = localDeclMap.find(sizeDecl);
+ assert(dIter != localDeclMap.end());
+
+ return emitLoadOfScalar(dIter->second, /*volatile=*/false,
+ getContext().getSizeType(), e->getBeginLoc(),
+ LValueBaseInfo(AlignmentSource::Decl));
+ }
+ }
// LLVM can't handle type=3 appropriately, and __builtin_object_size shouldn't
// evaluate e for side-effects. In either case, just like original LLVM
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 10b4528ff2aac..dc074491b4582 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -710,20 +710,26 @@ static CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *md) {
.getAs<FunctionProtoType>();
}
-/// Adds the formal parameters in FPT to the given prefix. If any parameter in
-/// FPT has pass_object_size_attrs, then we'll add parameters for those, too.
+/// Adds the formal parameters in FPT to the given prefix. If any parameter in
+/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
/// TODO(cir): this should be shared with LLVM codegen
static void appendParameterTypes(const CIRGenTypes &cgt,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> fpt) {
- assert(!cir::MissingFeatures::opCallExtParameterInfo());
// Fast path: don't touch param info if we don't need to.
if (!fpt->hasExtParameterInfos()) {
prefix.append(fpt->param_type_begin(), fpt->param_type_end());
return;
}
- cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos");
+ prefix.reserve(prefix.size() + fpt->getNumParams());
+ auto extInfos = fpt->getExtParameterInfos();
+ for (unsigned i = 0, e = fpt->getNumParams(); i != e; ++i) {
+ prefix.push_back(fpt->getParamType(i));
+ if (extInfos[i].hasPassObjectSize())
+ prefix.push_back(cgt.getASTContext().getCanonicalType(
+ cgt.getASTContext().getSizeType()));
+ }
}
const CIRGenFunctionInfo &
@@ -858,10 +864,14 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
RequiredArgs required = RequiredArgs::All;
if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {
- if (proto->isVariadic())
- required = RequiredArgs::getFromProtoWithExtraSlots(proto, 0);
+ unsigned numExtraSlots = 0;
if (proto->hasExtParameterInfos())
- cgm.errorNYI("call to functions with extra parameter info");
+ for (const auto &info : proto->getExtParameterInfos())
+ if (info.hasPassObjectSize())
+ ++numExtraSlots;
+ if (proto->isVariadic())
+ required =
+ RequiredArgs::getFromProtoWithExtraSlots(proto, numExtraSlots);
} else if (cgm.getTargetCIRGenInfo().isNoProtoCallVariadic(
cast<FunctionNoProtoType>(fnType)))
cgm.errorNYI("call to function without a prototype");
@@ -1397,8 +1407,14 @@ void CIRGenFunction::emitCallArgs(
if (!ps)
return;
- assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs());
- cgm.errorNYI("emit implicit object size for call arg");
+ QualType sizeTy = getContext().getSizeType();
+ auto t = cast<cir::IntType>(cgm.sizeTy);
+ assert(emittedArg.getValue() && "We emitted nothing for the arg?");
+ mlir::Value v = evaluateOrEmitBuiltinObjectSize(
+ arg, ps->getType(), t, emittedArg.getValue(), ps->isDynamic());
+ args.add(RValue::get(v), sizeTy);
+ if (!leftToRight)
+ std::swap(args.back(), *(&args.back() - 1));
};
// Evaluate each argument in the appropriate order.
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index fcfbeb809371e..263641fe0023f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -999,8 +999,15 @@ clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,
if (passedParams) {
for (auto *param : fd->parameters()) {
args.push_back(param);
- if (param->hasAttr<PassObjectSizeAttr>())
- cgm.errorNYI(param->getSourceRange(), "pass-object-size attribute");
+ if (!param->hasAttr<PassObjectSizeAttr>())
+ continue;
+
+ auto *implicit = ImplicitParamDecl::Create(
+ getContext(), param->getDeclContext(), param->getLocation(),
+ /*Id=*/nullptr, getContext().getSizeType(),
+ ImplicitParamKind::Other);
+ sizeArguments[param] = implicit;
+ args.push_back(implicit);
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 4f0f33a933e01..5cfde7ac18066 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -174,6 +174,11 @@ class CIRGenFunction : public CIRGenTypeCache {
ImplicitParamDecl *cxxStructorImplicitParamDecl{};
mlir::Value cxxStructorImplicitParamValue{};
+ /// If a ParmVarDecl had the pass_object_size attribute, this will contain a
+ /// mapping from said ParmVarDecl to its implicit "object_size" parameter.
+ llvm::SmallDenseMap<const ParmVarDecl *, const ImplicitParamDecl *, 2>
+ sizeArguments;
+
/// The value of 'this' to sue when evaluating CXXDefaultInitExprs within this
/// expression.
Address cxxDefaultInitExprThis = Address::invalid();
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
index 00b107296d9fc..67a33d1e75401 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
@@ -51,7 +51,11 @@ class RequiredArgs {
return All;
if (prototype->hasExtParameterInfos())
- llvm_unreachable("NYI");
+ additional += llvm::count_if(
+ prototype->getExtParameterInfos(),
+ [](const clang::FunctionProtoType::ExtParameterInfo &extInfo) {
+ return extInfo.hasPassObjectSize();
+ });
return RequiredArgs(prototype->getNumParams() + additional);
}
diff --git a/clang/test/CIR/CodeGen/pass-object-size.c b/clang/test/CIR/CodeGen/pass-object-size.c
new file mode 100644
index 0000000000000..55337baa7e0c8
--- /dev/null
+++ b/clang/test/CIR/CodeGen/pass-object-size.c
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+void b(void *__attribute__((pass_object_size(0))));
+void e(void *__attribute__((pass_object_size(2))));
+
+// CIR: cir.func private @b(!cir.ptr<!void> {llvm.noundef}, !u64i {llvm.noundef})
+
+void test_constant() {
+ int a;
+ b(&a);
+}
+
+// CIR: cir.func {{.*}} @test_constant()
+// CIR: %[[ALLOCA:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>
+// CIR: %[[CAST:.*]] = cir.cast bitcast %[[ALLOCA]] : !cir.ptr<!s32i> -> !cir.ptr<!void>
+// CIR: %[[SIZE:.*]] = cir.const #cir.int<4> : !u64i
+// CIR: cir.call @b(%[[CAST]], %[[SIZE]]) : (!cir.ptr<!void> {{.*}}, !u64i {{.*}}) -> ()
+
+// CIR: cir.func private @e(!cir.ptr<!void> {llvm.noundef}, !u64i {llvm.noundef})
+
+// LLVM: declare void @b(ptr noundef, i64 noundef)
+
+// LLVM: define dso_local void @test_constant()
+// LLVM: %[[ALLOCA:.*]] = alloca i32
+// LLVM: call void @b(ptr noundef %[[ALLOCA]], i64 noundef 4)
+
+void test_vla(int n) {
+ int d[n];
+ b(d);
+ e(d);
+}
+
+// CIR: cir.func {{.*}} @test_vla
+// CIR: %[[VLA:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, %{{.*}} : !u64i, ["d"] {alignment = 16 : i64}
+// CIR: %[[CAST1:.*]] = cir.cast bitcast %[[VLA]] : !cir.ptr<!s32i> -> !cir.ptr<!void>
+// CIR: %[[SIZE1:.*]] = cir.objsize max nullunknown %[[CAST1]] : !cir.ptr<!void> -> !u64i
+// CIR: cir.call @b(%[[CAST1]], %[[SIZE1]]) : (!cir.ptr<!void> {{.*}}, !u64i {{.*}}) -> ()
+// CIR: %[[CAST2:.*]] = cir.cast bitcast %[[VLA]] : !cir.ptr<!s32i> -> !cir.ptr<!void>
+// CIR: %[[SIZE2:.*]] = cir.objsize min nullunknown %[[CAST2]] : !cir.ptr<!void> -> !u64i
+// CIR: cir.call @e(%[[CAST2]], %[[SIZE2]]) : (!cir.ptr<!void> {{.*}}, !u64i {{.*}}) -> ()
+
+// LLVM: define dso_local void @test_vla(i32 noundef %{{.*}})
+// LLVM: %[[VLA:.*]] = alloca i32, i64 %{{.*}}, align 16
+// LLVM: %[[SIZE1:.*]] = call i64 @llvm.objectsize.i64.p0(ptr %[[VLA]], i1 false, i1 true, i1 false)
+// LLVM: call void @b(ptr noundef %[[VLA]], i64 noundef %[[SIZE1]])
+// LLVM: %[[SIZE2:.*]] = call i64 @llvm.objectsize.i64.p0(ptr %[[VLA]], i1 true, i1 true, i1 false)
+// LLVM: call void @e(ptr noundef %[[VLA]], i64 noundef %[[SIZE2]])
+
+// OGCG: define dso_local void @test_constant()
+// OGCG: %[[A:.*]] = alloca i32
+// OGCG: call void @b(ptr noundef %[[A]], i64 noundef 4)
+
+// OGCG: declare void @b(ptr noundef, i64 noundef)
+
+// OGCG: define dso_local void @test_vla(i32 noundef %{{.*}})
+// OGCG: %[[VLA:.*]] = alloca i32, i64 %{{.*}}, align 16
+// OGCG: %[[SIZE1:.*]] = call i64 @llvm.objectsize.i64.p0(ptr %[[VLA]], i1 false, i1 true, i1 false)
+// OGCG: call void @b(ptr noundef %[[VLA]], i64 noundef %[[SIZE1]])
+// OGCG: %[[SIZE2:.*]] = call i64 @llvm.objectsize.i64.p0(ptr %[[VLA]], i1 true, i1 true, i1 false)
+// OGCG: call void @e(ptr noundef %[[VLA]], i64 noundef %[[SIZE2]])
>From 2049ec9c172ac0e71843c6a99f6179b15f39992d Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Mon, 13 Apr 2026 15:41:20 -0700
Subject: [PATCH 2/3] [CIR] Address review feedback on pass_object_size
- Add classic codegen comment explaining areBOSTypesCompatible
- Remove opCallImplicitObjectSizeArgs from MissingFeatures.h
- Use getCanonicalSizeType() in appendParameterTypes
- Add reserve comment from classic codegen
- Handle extParameterInfo at call sites: count pass_object_size
slots in RequiredArgs instead of errorNYI
- Use explicit types instead of auto
Addresses review feedback from @andykaylor.
Made-with: Cursor
---
clang/include/clang/CIR/MissingFeatures.h | 1 -
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 4 ++++
clang/lib/CIR/CodeGen/CIRGenCall.cpp | 13 +++++++------
3 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index ca857701b6b4f..6224924ceb1d5 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -98,7 +98,6 @@ struct MissingFeatures {
static bool opCallABIIndirectArg() { return false; }
static bool opCallWidenArg() { return false; }
static bool opCallBitcastArg() { return false; }
- static bool opCallImplicitObjectSizeArgs() { return false; }
static bool opCallReturn() { return false; }
static bool opCallArgEvaluationOrder() { return false; }
static bool opCallCallConv() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 62729839b6ae4..8e0410e7a1548 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -2583,6 +2583,10 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
/// Checks if using the result of __builtin_object_size(p, @p from) in place of
/// __builtin_object_size(p, @p to) is correct.
+///
+/// type=0 is the maximum object size; compatible with type=1 (maximum of the
+/// remaining bytes, which is always <= total size). type=3 is the minimum
+/// remaining bytes; compatible with type=2 (minimum object size).
static bool areBOSTypesCompatible(int from, int to) {
return from == to || (from == 0 && to == 1) || (from == 3 && to == 2);
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index dc074491b4582..7cf8157b44fda 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -722,13 +722,15 @@ static void appendParameterTypes(const CIRGenTypes &cgt,
return;
}
+ // In the vast majority of cases, we'll have precisely FPT->getNumParams()
+ // parameters; the only thing that can change this is the presence of
+ // pass_object_size. So, we preallocate for the common case.
prefix.reserve(prefix.size() + fpt->getNumParams());
auto extInfos = fpt->getExtParameterInfos();
for (unsigned i = 0, e = fpt->getNumParams(); i != e; ++i) {
prefix.push_back(fpt->getParamType(i));
if (extInfos[i].hasPassObjectSize())
- prefix.push_back(cgt.getASTContext().getCanonicalType(
- cgt.getASTContext().getSizeType()));
+ prefix.push_back(cgt.getASTContext().getCanonicalSizeType());
}
}
@@ -809,7 +811,6 @@ arrangeCIRFunctionInfo(CIRGenTypes &cgt, bool instanceMethod,
assert(!cir::MissingFeatures::opCallFnInfoOpts());
RequiredArgs required =
RequiredArgs::getFromProtoWithExtraSlots(fpt, prefix.size());
- assert(!cir::MissingFeatures::opCallExtParameterInfo());
appendParameterTypes(cgt, prefix, fpt);
CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
return cgt.arrangeCIRFunctionInfo(resultType, instanceMethod, prefix,
@@ -934,7 +935,6 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall(
const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXMethodCall(
const CallArgList &args, const FunctionProtoType *proto,
RequiredArgs required, unsigned numPrefixArgs) {
- assert(!cir::MissingFeatures::opCallExtParameterInfo());
assert(numPrefixArgs + 1 <= args.size() &&
"Emitting a call with less args than the required prefix?");
@@ -1408,10 +1408,11 @@ void CIRGenFunction::emitCallArgs(
return;
QualType sizeTy = getContext().getSizeType();
- auto t = cast<cir::IntType>(cgm.sizeTy);
+ auto cirSizeTy = cast<cir::IntType>(cgm.sizeTy);
assert(emittedArg.getValue() && "We emitted nothing for the arg?");
mlir::Value v = evaluateOrEmitBuiltinObjectSize(
- arg, ps->getType(), t, emittedArg.getValue(), ps->isDynamic());
+ arg, ps->getType(), cirSizeTy, emittedArg.getValue(),
+ ps->isDynamic());
args.add(RValue::get(v), sizeTy);
if (!leftToRight)
std::swap(args.back(), *(&args.back() - 1));
>From b857578d0adb3a221c17f159a67c32e42644503b Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Wed, 15 Apr 2026 11:58:49 -0700
Subject: [PATCH 3/3] [CIR] Address review feedback on pass_object_size
- Use named BOSType enum constants instead of raw 0/1/2/3
- Use structured bindings for map find results
- Revert unrelated formatting change on comment
- Fix comment case: fpt not FPT
- Use explicit type for getExtParameterInfos() return
- Inline cast<cir::IntType> instead of intermediate variable
- Remove SmallDenseMap size parameter
- Rename sizeArguments -> objectSizeArguments
Made-with: Cursor
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 31 +++++++++++++++++-------
clang/lib/CIR/CodeGen/CIRGenCall.cpp | 17 ++++++-------
clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 5 ++--
clang/lib/CIR/CodeGen/CIRGenFunction.h | 4 +--
4 files changed, 34 insertions(+), 23 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 8e0410e7a1548..9efa467cb2abc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -2581,14 +2581,26 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
return cir::VAArgOp::create(builder, loc, type, vaList);
}
+/// __builtin_object_size type constants.
+enum BOSType {
+ BOSMaxTotalSize = 0, // max total object size
+ BOSMaxRemainingSize = 1, // max remaining bytes in sub-object
+ BOSMinTotalSize = 2, // min total object size
+ BOSMinRemainingSize = 3 // min remaining bytes in sub-object
+};
+
/// Checks if using the result of __builtin_object_size(p, @p from) in place of
/// __builtin_object_size(p, @p to) is correct.
-///
-/// type=0 is the maximum object size; compatible with type=1 (maximum of the
-/// remaining bytes, which is always <= total size). type=3 is the minimum
-/// remaining bytes; compatible with type=2 (minimum object size).
static bool areBOSTypesCompatible(int from, int to) {
- return from == to || (from == 0 && to == 1) || (from == 3 && to == 2);
+ if (from == to)
+ return true;
+ // Max total size subsumes max remaining size.
+ if (from == BOSMaxTotalSize && to == BOSMaxRemainingSize)
+ return true;
+ // Min remaining size subsumes min total size.
+ if (from == BOSMinRemainingSize && to == BOSMinTotalSize)
+ return true;
+ return false;
}
mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type,
@@ -2600,14 +2612,15 @@ mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type,
auto *param = dyn_cast<ParmVarDecl>(d->getDecl());
auto *ps = d->getDecl()->getAttr<PassObjectSizeAttr>();
if (param && ps && areBOSTypesCompatible(ps->getType(), type)) {
- auto iter = sizeArguments.find(param);
- assert(iter != sizeArguments.end());
+ auto iter = objectSizeArguments.find(param);
+ assert(iter != objectSizeArguments.end());
+ auto &[paramDecl, sizeDecl] = *iter;
- const ImplicitParamDecl *sizeDecl = iter->second;
auto dIter = localDeclMap.find(sizeDecl);
assert(dIter != localDeclMap.end());
+ auto &[implDecl, sizeAddr] = *dIter;
- return emitLoadOfScalar(dIter->second, /*volatile=*/false,
+ return emitLoadOfScalar(sizeAddr, /*volatile=*/false,
getContext().getSizeType(), e->getBeginLoc(),
LValueBaseInfo(AlignmentSource::Decl));
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 7cf8157b44fda..af24200a48650 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -710,8 +710,8 @@ static CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *md) {
.getAs<FunctionProtoType>();
}
-/// Adds the formal parameters in FPT to the given prefix. If any parameter in
-/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
+/// Adds the formal parameters in FPT to the given prefix. If any parameter in
+/// FPT has pass_object_size_attrs, then we'll add parameters for those, too.
/// TODO(cir): this should be shared with LLVM codegen
static void appendParameterTypes(const CIRGenTypes &cgt,
SmallVectorImpl<CanQualType> &prefix,
@@ -722,11 +722,12 @@ static void appendParameterTypes(const CIRGenTypes &cgt,
return;
}
- // In the vast majority of cases, we'll have precisely FPT->getNumParams()
+ // In the vast majority of cases, we'll have precisely fpt->getNumParams()
// parameters; the only thing that can change this is the presence of
// pass_object_size. So, we preallocate for the common case.
prefix.reserve(prefix.size() + fpt->getNumParams());
- auto extInfos = fpt->getExtParameterInfos();
+ ArrayRef<FunctionProtoType::ExtParameterInfo> extInfos =
+ fpt->getExtParameterInfos();
for (unsigned i = 0, e = fpt->getNumParams(); i != e; ++i) {
prefix.push_back(fpt->getParamType(i));
if (extInfos[i].hasPassObjectSize())
@@ -871,8 +872,7 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
if (info.hasPassObjectSize())
++numExtraSlots;
if (proto->isVariadic())
- required =
- RequiredArgs::getFromProtoWithExtraSlots(proto, numExtraSlots);
+ required = RequiredArgs::getFromProtoWithExtraSlots(proto, numExtraSlots);
} else if (cgm.getTargetCIRGenInfo().isNoProtoCallVariadic(
cast<FunctionNoProtoType>(fnType)))
cgm.errorNYI("call to function without a prototype");
@@ -1408,11 +1408,10 @@ void CIRGenFunction::emitCallArgs(
return;
QualType sizeTy = getContext().getSizeType();
- auto cirSizeTy = cast<cir::IntType>(cgm.sizeTy);
assert(emittedArg.getValue() && "We emitted nothing for the arg?");
mlir::Value v = evaluateOrEmitBuiltinObjectSize(
- arg, ps->getType(), cirSizeTy, emittedArg.getValue(),
- ps->isDynamic());
+ arg, ps->getType(), cast<cir::IntType>(cgm.sizeTy),
+ emittedArg.getValue(), ps->isDynamic());
args.add(RValue::get(v), sizeTy);
if (!leftToRight)
std::swap(args.back(), *(&args.back() - 1));
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 263641fe0023f..5e020f1913225 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -1004,9 +1004,8 @@ clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,
auto *implicit = ImplicitParamDecl::Create(
getContext(), param->getDeclContext(), param->getLocation(),
- /*Id=*/nullptr, getContext().getSizeType(),
- ImplicitParamKind::Other);
- sizeArguments[param] = implicit;
+ /*Id=*/nullptr, getContext().getSizeType(), ImplicitParamKind::Other);
+ objectSizeArguments[param] = implicit;
args.push_back(implicit);
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 5cfde7ac18066..7cbd901a6511e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -176,8 +176,8 @@ class CIRGenFunction : public CIRGenTypeCache {
/// If a ParmVarDecl had the pass_object_size attribute, this will contain a
/// mapping from said ParmVarDecl to its implicit "object_size" parameter.
- llvm::SmallDenseMap<const ParmVarDecl *, const ImplicitParamDecl *, 2>
- sizeArguments;
+ llvm::SmallDenseMap<const ParmVarDecl *, const ImplicitParamDecl *>
+ objectSizeArguments;
/// The value of 'this' to sue when evaluating CXXDefaultInitExprs within this
/// expression.
More information about the cfe-commits
mailing list