llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: adams381

<details>
<summary>Changes</summary>

Emit the hidden `i64` parameter that `__attribute__((pass_object_size(N)))` 
requires.  At call sites the size is constant-folded when possible (e.g. 
`&amp;a` → 4) and falls back to `cir.objsize` / `@<!-- -->llvm.objectsize` 
otherwise (e.g. VLAs).

On the callee side, `buildFunctionArgList` now creates an `ImplicitParamDecl` 
for each annotated parameter so that `emitBuiltinObjectSize` can load the 
passed size instead of re-computing it.

This also fixes the `llvm_unreachable("NYI")` in 
`RequiredArgs::getFromProtoWithExtraSlots` and the `errorNYI` in 
`appendParameterTypes` / `arrangeFreeFunctionLikeCall` that fired whenever 
`hasExtParameterInfos()` was true.

New test: `clang/test/CIR/CodeGen/pass-object-size.c` (CIR / LLVM / OGCG).

Made with [Cursor](https://cursor.com)

---
Full diff: https://github.com/llvm/llvm-project/pull/191482.diff


6 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+23-1) 
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+20-8) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+10-1) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+5) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h (+5-1) 
- (added) clang/test/CIR/CodeGen/pass-object-size.c (+65) 


``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 523348a952775..0cee4832433cf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -2578,11 +2578,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 876fef687b477..5cf334b959f97 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -708,20 +708,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 &
@@ -859,8 +865,7 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule 
&cgm,
   if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {
     if (proto->isVariadic())
       required = RequiredArgs::getFromProtoWithExtraSlots(proto, 0);
-    if (proto->hasExtParameterInfos())
-      cgm.errorNYI("call to functions with extra parameter info");
+    assert(!cir::MissingFeatures::opCallExtParameterInfo());
   } else if (cgm.getTargetCIRGenInfo().isNoProtoCallVariadic(
                  cast<FunctionNoProtoType>(fnType)))
     cgm.errorNYI("call to function without a prototype");
@@ -1396,8 +1401,15 @@ void CIRGenFunction::emitCallArgs(
     if (!ps)
       return;
 
-    assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs());
-    cgm.errorNYI("emit implicit object size for call arg");
+    const ASTContext &astContext = getContext();
+    QualType sizeTy = astContext.getSizeType();
+    cir::IntType t = builder.getUIntNTy(astContext.getTypeSize(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 f7f9331060956..917a27d978030 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -995,8 +995,17 @@ clang::QualType 
CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,
       cgm.errorNYI(fd->getSourceRange(),
                    "buildFunctionArgList: inherited constructor");
 
-  for (auto *param : fd->parameters())
+  for (auto *param : fd->parameters()) {
     args.push_back(param);
+    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);
+  }
 
   if (md && (isa<CXXConstructorDecl>(md) || isa<CXXDestructorDecl>(md)))
     cgm.getCXXABI().addImplicitStructorParams(*this, retTy, args);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 88c7996eab569..faf6c0e787329 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -133,6 +133,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]])

``````````

</details>


https://github.com/llvm/llvm-project/pull/191482
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to