https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/166191

>From 30c9a5cf5f2ca7192f16eaae0eb37e13425b39b4 Mon Sep 17 00:00:00 2001
From: Morris Hafner <[email protected]>
Date: Tue, 4 Nov 2025 01:00:07 +0800
Subject: [PATCH 1/5] [CIR] Implement __builtin_object_size and
 __builtin_dynamic_object_size

* Add cir.objsize operation to CIR dialect
* Add lowering for cir.objsize operation to LLVM dialect
* Add codegen for __builtin_object_size and __builtin_dynamic_object_size

Note that this does not support the pass_object_size attribute yet.
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 42 +++++++++++++
 clang/include/clang/CIR/MissingFeatures.h     |  1 +
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       | 60 +++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  8 +++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 23 +++++++
 .../test/CIR/CodeGen/builtin-object-size.cpp  | 38 ++++++++++++
 6 files changed, 172 insertions(+)
 create mode 100644 clang/test/CIR/CodeGen/builtin-object-size.cpp

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2b361ed0982c6..4cf0b817e8056 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4089,6 +4089,48 @@ def CIR_PrefetchOp : CIR_Op<"prefetch"> {
     }];
 }
 
+//===----------------------------------------------------------------------===//
+// ObjSizeOp
+//===----------------------------------------------------------------------===//
+
+def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> {
+  let summary = "Implements the llvm.objsize builtin";
+  let description = [{
+    The `cir.objsize` operation models the behavior of the `llvm.objectsize`
+    intrinsic in Clang. It returns the number of accessible bytes past ptr.
+
+    When the `min` attribute is present, the operation returns the minimum
+    guaranteed accessible size. When absent (max mode), it returns the maximum
+    possible object size. Additionally, when the object size is unknown, min
+    mode returns 0 while max mode returns -1. Corresponds to 
`llvm.objectsize`'s
+    `min` argument.
+    
+    The `dynamic` attribute determines if the value should be evaluated at
+    runtime. Corresponds to `llvm.objectsize`'s `dynamic` argument.
+
+    Example:
+
+    ```mlir
+    %size = cir.objsize min %ptr : !cir.ptr<i32> -> i64
+    %dsize = cir.objsize max dynamic %ptr : !cir.ptr<i32> -> i64
+    ```
+  }];
+
+  let arguments = (ins
+    CIR_PointerType:$ptr,
+    UnitAttr:$min,
+    UnitAttr:$dynamic
+  );
+
+  let results = (outs CIR_AnyFundamentalIntType:$result);
+
+  let assemblyFormat = [{
+      (`min` $min^) : (`max`)?
+      (`dynamic` $dynamic^)?
+      $ptr `:` qualified(type($ptr)) `->` qualified(type($result)) attr-dict
+  }];
+}
+
 
//===----------------------------------------------------------------------===//
 // PtrDiffOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 48ef8be9fb782..ae96f6b932571 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -213,6 +213,7 @@ struct MissingFeatures {
   static bool builtinCallMathErrno() { return false; }
   static bool builtinCheckKind() { return false; }
   static bool cgCapturedStmtInfo() { return false; }
+  static bool countedBySize() { return false; }
   static bool cgFPOptionsRAII() { return false; }
   static bool checkBitfieldClipping() { return false; }
   static bool cirgenABIInfo() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index e35100ffe4b6b..6617895fa8832 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -459,6 +459,19 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp), 
e,
                     returnValue);
   }
+  case Builtin::BI__builtin_dynamic_object_size:
+  case Builtin::BI__builtin_object_size: {
+    unsigned type =
+        e->getArg(1)->EvaluateKnownConstInt(getContext()).getZExtValue();
+    auto resType = mlir::cast<cir::IntType>(convertType(e->getType()));
+
+    // We pass this builtin onto the optimizer so that it can figure out the
+    // object size in more complex cases.
+    bool isDynamic = builtinID == Builtin::BI__builtin_dynamic_object_size;
+    return RValue::get(emitBuiltinObjectSize(e->getArg(0), type, resType,
+                                             /*EmittedE=*/nullptr, isDynamic));
+  }
+
   case Builtin::BI__builtin_prefetch: {
     auto evaluateOperandAsInt = [&](const Expr *arg) {
       Expr::EvalResult res;
@@ -641,3 +654,50 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
   mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer();
   return cir::VAArgOp::create(builder, loc, type, vaList);
 }
+
+/// Returns a Value corresponding to the size of the given expression.
+/// This Value may be either of the following:
+///
+///   - Reference an argument if `pass_object_size` is used.
+///   - A call to a `cir.objsize`.
+///
+/// emittedE is the result of emitting `e` as a scalar expr. If it's non-null
+/// and we wouldn't otherwise try to reference a pass_object_size parameter,
+/// we'll call `cir.objsize` on emittedE, rather than emitting e.
+mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type,
+                                                  cir::IntType resType,
+                                                  mlir::Value emittedE,
+                                                  bool isDynamic) {
+  assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs());
+
+  // 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
+  // lowering, we shouldn't lower to `cir.objsize`.
+  if (type == 3 || (!emittedE && e->HasSideEffects(getContext())))
+    return builder.getConstInt(getLoc(e->getSourceRange()), resType,
+                                (type & 2) ? 0 : -1);
+
+  mlir::Value ptr = emittedE ? emittedE : emitScalarExpr(e);
+  assert(mlir::isa<cir::PointerType>(ptr.getType()) &&
+         "Non-pointer passed to __builtin_object_size?");
+
+  assert(!cir::MissingFeatures::countedBySize());
+
+  // LLVM intrinsics (which CIR lowers to at some point, only supports 0
+  // and 2, account for that right now.
+  const bool min = ((type & 2) != 0);
+  // TODO(cir): Heads up for LLVM lowering, For GCC compatibility,
+  // __builtin_object_size treat NULL as unknown size.
+  auto op = cir::ObjSizeOp::create(builder, getLoc(e->getSourceRange()),
+                                   resType, ptr, min, isDynamic);
+  return op.getResult();
+}
+
+mlir::Value CIRGenFunction::evaluateOrEmitBuiltinObjectSize(
+    const Expr *e, unsigned type, cir::IntType resType, mlir::Value emittedE,
+    bool isDynamic) {
+  uint64_t objectSize;
+  if (!e->tryEvaluateObjectSize(objectSize, getContext(), type))
+    return emitBuiltinObjectSize(e, type, resType, emittedE, isDynamic);
+  return builder.getConstInt(getLoc(e->getSourceRange()), resType, objectSize);
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index e5cecaa573a6e..3d3d4fa410d1a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1304,6 +1304,14 @@ class CIRGenFunction : public CIRGenTypeCache {
   RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID,
                          const clang::CallExpr *e, ReturnValueSlot 
returnValue);
 
+  mlir::Value emitBuiltinObjectSize(const clang::Expr *e, unsigned type,
+                                     cir::IntType resType, mlir::Value 
emittedE,
+                                     bool isDynamic);
+
+  mlir::Value evaluateOrEmitBuiltinObjectSize(const clang::Expr *e,
+                                               unsigned type, cir::IntType 
resType,
+                                               mlir::Value emittedE, bool 
isDynamic);
+
   RValue emitCall(const CIRGenFunctionInfo &funcInfo,
                   const CIRGenCallee &callee, ReturnValueSlot returnValue,
                   const CallArgList &args, cir::CIRCallOpInterface *callOp,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 5a6193fa8d840..6322b2979fa31 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2816,6 +2816,29 @@ static void collectUnreachable(mlir::Operation *parent,
   }
 }
 
+mlir::LogicalResult CIRToLLVMObjSizeOpLowering::matchAndRewrite(
+    cir::ObjSizeOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  mlir::Type llvmResTy = getTypeConverter()->convertType(op.getType());
+  mlir::Location loc = op->getLoc();
+
+  mlir::IntegerType i1Ty = rewriter.getI1Type();
+
+  auto i1Val = [&rewriter, &loc, &i1Ty](bool val) {
+    return mlir::LLVM::ConstantOp::create(rewriter, loc, i1Ty, val);
+  };
+
+  replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.objectsize", llvmResTy,
+                                   {
+                                       adaptor.getPtr(),
+                                       i1Val(op.getMin()),
+                                       i1Val(true),
+                                       i1Val(op.getDynamic()),
+                                   });
+
+  return mlir::LogicalResult::success();
+}
+
 void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {
   // Lower the module attributes to LLVM equivalents.
   if (mlir::Attribute tripleAttr =
diff --git a/clang/test/CIR/CodeGen/builtin-object-size.cpp 
b/clang/test/CIR/CodeGen/builtin-object-size.cpp
new file mode 100644
index 0000000000000..e077a2b57bf1d
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtin-object-size.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+typedef unsigned long size_t;
+
+// CIR-LABEL: @_Z4testPc
+// LLVM-LABEL: define {{.*}} i64 @_Z4testPc
+// OGCG-LABEL: define {{.*}} i64 @_Z4testPc
+size_t test(char *ptr) {
+  // CIR: cir.objsize max {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
+  return __builtin_object_size(ptr, 0);
+}
+
+// CIR-LABEL: @_Z8test_minPc
+// LLVM-LABEL: define {{.*}} i64 @_Z8test_minPc
+// OGCG-LABEL: define {{.*}} i64 @_Z8test_minPc
+size_t test_min(char *ptr) {
+  // CIR: cir.objsize min {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 
false)
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 
false)
+  return __builtin_object_size(ptr, 2);
+}
+
+// CIR-LABEL: @_Z17test_dynamic_sizePc
+// LLVM-LABEL: define {{.*}} i64 @_Z17test_dynamic_sizePc
+// OGCG-LABEL: define {{.*}} i64 @_Z17test_dynamic_sizePc
+size_t test_dynamic_size(char *ptr) {
+  // CIR: cir.objsize max dynamic {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
true)
+  return __builtin_dynamic_object_size(ptr, 0);
+}

>From 4d4fe2ae34d7b8516e71a203fa56bb5ff466ef97 Mon Sep 17 00:00:00 2001
From: Morris Hafner <[email protected]>
Date: Tue, 4 Nov 2025 01:09:13 +0800
Subject: [PATCH 2/5] clang-format, comment updates

---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp         | 14 ++++----------
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp   | 17 ++++++++++-------
 2 files changed, 14 insertions(+), 17 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 6617895fa8832..ef58b8c592c63 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -655,14 +655,10 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
   return cir::VAArgOp::create(builder, loc, type, vaList);
 }
 
-/// Returns a Value corresponding to the size of the given expression.
-/// This Value may be either of the following:
+/// Returns a Value corresponding to the size of the given expression by
+/// emitting a `cir.objsize` operation.
 ///
-///   - Reference an argument if `pass_object_size` is used.
-///   - A call to a `cir.objsize`.
-///
-/// emittedE is the result of emitting `e` as a scalar expr. If it's non-null
-/// and we wouldn't otherwise try to reference a pass_object_size parameter,
+/// emittedE is the result of emitting `e` as a scalar expr. If it's non-null,
 /// we'll call `cir.objsize` on emittedE, rather than emitting e.
 mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type,
                                                   cir::IntType resType,
@@ -675,7 +671,7 @@ mlir::Value CIRGenFunction::emitBuiltinObjectSize(const 
Expr *e, unsigned type,
   // lowering, we shouldn't lower to `cir.objsize`.
   if (type == 3 || (!emittedE && e->HasSideEffects(getContext())))
     return builder.getConstInt(getLoc(e->getSourceRange()), resType,
-                                (type & 2) ? 0 : -1);
+                               (type & 2) ? 0 : -1);
 
   mlir::Value ptr = emittedE ? emittedE : emitScalarExpr(e);
   assert(mlir::isa<cir::PointerType>(ptr.getType()) &&
@@ -686,8 +682,6 @@ mlir::Value CIRGenFunction::emitBuiltinObjectSize(const 
Expr *e, unsigned type,
   // LLVM intrinsics (which CIR lowers to at some point, only supports 0
   // and 2, account for that right now.
   const bool min = ((type & 2) != 0);
-  // TODO(cir): Heads up for LLVM lowering, For GCC compatibility,
-  // __builtin_object_size treat NULL as unknown size.
   auto op = cir::ObjSizeOp::create(builder, getLoc(e->getSourceRange()),
                                    resType, ptr, min, isDynamic);
   return op.getResult();
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6322b2979fa31..470c22631d8e5 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2828,13 +2828,16 @@ mlir::LogicalResult 
CIRToLLVMObjSizeOpLowering::matchAndRewrite(
     return mlir::LLVM::ConstantOp::create(rewriter, loc, i1Ty, val);
   };
 
-  replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.objectsize", llvmResTy,
-                                   {
-                                       adaptor.getPtr(),
-                                       i1Val(op.getMin()),
-                                       i1Val(true),
-                                       i1Val(op.getDynamic()),
-                                   });
+  replaceOpWithCallLLVMIntrinsicOp(
+      rewriter, op, "llvm.objectsize", llvmResTy,
+      {
+          adaptor.getPtr(),
+          i1Val(op.getMin()),
+          // For GCC compatibility, __builtin_object_size treat NULL as unknown
+          // size.
+          i1Val(true),
+          i1Val(op.getDynamic()),
+      });
 
   return mlir::LogicalResult::success();
 }

>From 2dc7585dd6a1b80d4cef03c0144b8fa6127c50c2 Mon Sep 17 00:00:00 2001
From: Morris Hafner <[email protected]>
Date: Tue, 4 Nov 2025 01:10:19 +0800
Subject: [PATCH 3/5] more clang-format

---
 clang/lib/CIR/CodeGen/CIRGenFunction.h | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 3d3d4fa410d1a..115fa6dba2aeb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1305,12 +1305,14 @@ class CIRGenFunction : public CIRGenTypeCache {
                          const clang::CallExpr *e, ReturnValueSlot 
returnValue);
 
   mlir::Value emitBuiltinObjectSize(const clang::Expr *e, unsigned type,
-                                     cir::IntType resType, mlir::Value 
emittedE,
-                                     bool isDynamic);
+                                    cir::IntType resType, mlir::Value emittedE,
+                                    bool isDynamic);
 
   mlir::Value evaluateOrEmitBuiltinObjectSize(const clang::Expr *e,
-                                               unsigned type, cir::IntType 
resType,
-                                               mlir::Value emittedE, bool 
isDynamic);
+                                              unsigned type,
+                                              cir::IntType resType,
+                                              mlir::Value emittedE,
+                                              bool isDynamic);
 
   RValue emitCall(const CIRGenFunctionInfo &funcInfo,
                   const CIRGenCallee &callee, ReturnValueSlot returnValue,

>From 6627147a921a26863f905b9f229c6ac36c8825f6 Mon Sep 17 00:00:00 2001
From: Morris Hafner <[email protected]>
Date: Tue, 4 Nov 2025 16:27:36 +0800
Subject: [PATCH 4/5] Apply suggestions from code review

Co-authored-by: Andy Kaylor <[email protected]>
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 7 +++++--
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp      | 4 ++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4cf0b817e8056..5eca682027c65 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4096,8 +4096,11 @@ def CIR_PrefetchOp : CIR_Op<"prefetch"> {
 def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> {
   let summary = "Implements the llvm.objsize builtin";
   let description = [{
-    The `cir.objsize` operation models the behavior of the `llvm.objectsize`
-    intrinsic in Clang. It returns the number of accessible bytes past ptr.
+    The `cir.objsize` operation is designed to provide information to the
+    optimizer to determine whether a) an operation (like memcpy) will
+    overflow a buffer that corresponds to an object, or b) that a runtime
+    check for overflow isn’t necessary. An object in this context means an
+    allocation of a specific class, structure, array, or other object.
 
     When the `min` attribute is present, the operation returns the minimum
     guaranteed accessible size. When absent (max mode), it returns the maximum
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index ef58b8c592c63..2115a261385f0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -666,7 +666,7 @@ mlir::Value CIRGenFunction::emitBuiltinObjectSize(const 
Expr *e, unsigned type,
                                                   bool isDynamic) {
   assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs());
 
-  // LLVM can't handle Type=3 appropriately, and __builtin_object_size 
shouldn't
+  // 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
   // lowering, we shouldn't lower to `cir.objsize`.
   if (type == 3 || (!emittedE && e->HasSideEffects(getContext())))
@@ -679,7 +679,7 @@ mlir::Value CIRGenFunction::emitBuiltinObjectSize(const 
Expr *e, unsigned type,
 
   assert(!cir::MissingFeatures::countedBySize());
 
-  // LLVM intrinsics (which CIR lowers to at some point, only supports 0
+  // `cir.objectsize` only supports 0
   // and 2, account for that right now.
   const bool min = ((type & 2) != 0);
   auto op = cir::ObjSizeOp::create(builder, getLoc(e->getSourceRange()),

>From bdf053c019388eaedfb54e970a7155c7cbd3f57f Mon Sep 17 00:00:00 2001
From: Morris Hafner <[email protected]>
Date: Wed, 5 Nov 2025 11:18:23 +0300
Subject: [PATCH 5/5] Add nullunknown attribute Add CIR round trip test Reuse
 classic codegen tests

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  12 +-
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |  18 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  12 +
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  17 +-
 .../test/CIR/CodeGen/builtin-object-size.cpp  |  38 -
 .../test/CIR/CodeGen/object-size-flex-array.c | 317 +++++++
 clang/test/CIR/CodeGen/object-size.c          | 877 ++++++++++++++++++
 clang/test/CIR/CodeGen/object-size.cpp        | 108 +++
 clang/test/CIR/IR/objsize.cir                 |  89 ++
 9 files changed, 1427 insertions(+), 61 deletions(-)
 delete mode 100644 clang/test/CIR/CodeGen/builtin-object-size.cpp
 create mode 100644 clang/test/CIR/CodeGen/object-size-flex-array.c
 create mode 100644 clang/test/CIR/CodeGen/object-size.c
 create mode 100644 clang/test/CIR/CodeGen/object-size.cpp
 create mode 100644 clang/test/CIR/IR/objsize.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 5eca682027c65..3e890490d7097 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4104,24 +4104,29 @@ def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> {
 
     When the `min` attribute is present, the operation returns the minimum
     guaranteed accessible size. When absent (max mode), it returns the maximum
-    possible object size. Additionally, when the object size is unknown, min
-    mode returns 0 while max mode returns -1. Corresponds to 
`llvm.objectsize`'s
-    `min` argument.
+    possible object size. Corresponds to `llvm.objectsize`'s `min` argument.
     
     The `dynamic` attribute determines if the value should be evaluated at
     runtime. Corresponds to `llvm.objectsize`'s `dynamic` argument.
 
+    The `nullunknown` attribute controls how null pointers are handled. When
+    present, null pointers are treated as having unknown size. When absent,
+    null pointers are treated as having 0 size (in min mode) or -1 size
+    (in max mode). Corresponds to `llvm.objectsize`'s `nullunknown` argument.
+
     Example:
 
     ```mlir
     %size = cir.objsize min %ptr : !cir.ptr<i32> -> i64
     %dsize = cir.objsize max dynamic %ptr : !cir.ptr<i32> -> i64
+    %nsize = cir.objsize min nullunknown %ptr : !cir.ptr<i32> -> i64
     ```
   }];
 
   let arguments = (ins
     CIR_PointerType:$ptr,
     UnitAttr:$min,
+    UnitAttr:$nullunknown,
     UnitAttr:$dynamic
   );
 
@@ -4129,6 +4134,7 @@ def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> {
 
   let assemblyFormat = [{
       (`min` $min^) : (`max`)?
+      (`nullunknown` $nullunknown^)?
       (`dynamic` $dynamic^)?
       $ptr `:` qualified(type($ptr)) `->` qualified(type($result)) attr-dict
   }];
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 2115a261385f0..5fa7d83b1a0e5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -655,11 +655,6 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
   return cir::VAArgOp::create(builder, loc, type, vaList);
 }
 
-/// Returns a Value corresponding to the size of the given expression by
-/// emitting a `cir.objsize` operation.
-///
-/// emittedE is the result of emitting `e` as a scalar expr. If it's non-null,
-/// we'll call `cir.objsize` on emittedE, rather than emitting e.
 mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type,
                                                   cir::IntType resType,
                                                   mlir::Value emittedE,
@@ -668,7 +663,7 @@ mlir::Value CIRGenFunction::emitBuiltinObjectSize(const 
Expr *e, unsigned type,
 
   // 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
-  // lowering, we shouldn't lower to `cir.objsize`.
+  // lowering, we shouldn't lower to `cir.objsize` but to a constant instead.
   if (type == 3 || (!emittedE && e->HasSideEffects(getContext())))
     return builder.getConstInt(getLoc(e->getSourceRange()), resType,
                                (type & 2) ? 0 : -1);
@@ -679,11 +674,14 @@ mlir::Value CIRGenFunction::emitBuiltinObjectSize(const 
Expr *e, unsigned type,
 
   assert(!cir::MissingFeatures::countedBySize());
 
-  // `cir.objectsize` only supports 0
-  // and 2, account for that right now.
+  // Extract the min/max mode from type. CIR only supports type 0
+  // (max, whole object) and type 2 (min, whole object), not type 1 or 3
+  // (closest subobject variants).
   const bool min = ((type & 2) != 0);
-  auto op = cir::ObjSizeOp::create(builder, getLoc(e->getSourceRange()),
-                                   resType, ptr, min, isDynamic);
+  // For GCC compatibility, __builtin_object_size treats NULL as unknown size.
+  auto op =
+      cir::ObjSizeOp::create(builder, getLoc(e->getSourceRange()), resType, 
ptr,
+                             min, /*nullUnknown=*/true, isDynamic);
   return op.getResult();
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 115fa6dba2aeb..e3d42c4067cc5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1304,6 +1304,18 @@ class CIRGenFunction : public CIRGenTypeCache {
   RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID,
                          const clang::CallExpr *e, ReturnValueSlot 
returnValue);
 
+  /// Returns a Value corresponding to the size of the given expression by
+  /// emitting a `cir.objsize` operation.
+  ///
+  /// \param e The expression whose object size to compute
+  /// \param type Determines the semantics of the object size computation.
+  ///   The type parameter is a 2-bit value where:
+  ///     bit 0 (type & 1): 0 = whole object, 1 = closest subobject
+  ///     bit 1 (type & 2): 0 = maximum size, 2 = minimum size
+  /// \param resType The result type for the size value
+  /// \param emittedE Optional pre-emitted pointer value. If non-null, we'll
+  ///   call `cir.objsize` on this value rather than emitting e.
+  /// \param isDynamic If true, allows runtime evaluation via dynamic mode
   mlir::Value emitBuiltinObjectSize(const clang::Expr *e, unsigned type,
                                     cir::IntType resType, mlir::Value emittedE,
                                     bool isDynamic);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 470c22631d8e5..5c56ebba17e4b 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2828,16 +2828,13 @@ mlir::LogicalResult 
CIRToLLVMObjSizeOpLowering::matchAndRewrite(
     return mlir::LLVM::ConstantOp::create(rewriter, loc, i1Ty, val);
   };
 
-  replaceOpWithCallLLVMIntrinsicOp(
-      rewriter, op, "llvm.objectsize", llvmResTy,
-      {
-          adaptor.getPtr(),
-          i1Val(op.getMin()),
-          // For GCC compatibility, __builtin_object_size treat NULL as unknown
-          // size.
-          i1Val(true),
-          i1Val(op.getDynamic()),
-      });
+  replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.objectsize", llvmResTy,
+                                   {
+                                       adaptor.getPtr(),
+                                       i1Val(op.getMin()),
+                                       i1Val(op.getNullunknown()),
+                                       i1Val(op.getDynamic()),
+                                   });
 
   return mlir::LogicalResult::success();
 }
diff --git a/clang/test/CIR/CodeGen/builtin-object-size.cpp 
b/clang/test/CIR/CodeGen/builtin-object-size.cpp
deleted file mode 100644
index e077a2b57bf1d..0000000000000
--- a/clang/test/CIR/CodeGen/builtin-object-size.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
-// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
-// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
-
-typedef unsigned long size_t;
-
-// CIR-LABEL: @_Z4testPc
-// LLVM-LABEL: define {{.*}} i64 @_Z4testPc
-// OGCG-LABEL: define {{.*}} i64 @_Z4testPc
-size_t test(char *ptr) {
-  // CIR: cir.objsize max {{.*}} : !cir.ptr<!void> -> !u64i
-  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
-  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
-  return __builtin_object_size(ptr, 0);
-}
-
-// CIR-LABEL: @_Z8test_minPc
-// LLVM-LABEL: define {{.*}} i64 @_Z8test_minPc
-// OGCG-LABEL: define {{.*}} i64 @_Z8test_minPc
-size_t test_min(char *ptr) {
-  // CIR: cir.objsize min {{.*}} : !cir.ptr<!void> -> !u64i
-  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 
false)
-  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 
false)
-  return __builtin_object_size(ptr, 2);
-}
-
-// CIR-LABEL: @_Z17test_dynamic_sizePc
-// LLVM-LABEL: define {{.*}} i64 @_Z17test_dynamic_sizePc
-// OGCG-LABEL: define {{.*}} i64 @_Z17test_dynamic_sizePc
-size_t test_dynamic_size(char *ptr) {
-  // CIR: cir.objsize max dynamic {{.*}} : !cir.ptr<!void> -> !u64i
-  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
true)
-  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
true)
-  return __builtin_dynamic_object_size(ptr, 0);
-}
diff --git a/clang/test/CIR/CodeGen/object-size-flex-array.c 
b/clang/test/CIR/CodeGen/object-size-flex-array.c
new file mode 100644
index 0000000000000..74229fd1fac6c
--- /dev/null
+++ b/clang/test/CIR/CodeGen/object-size-flex-array.c
@@ -0,0 +1,317 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-cir %s 
-o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR 
--check-prefix=CIR-NO-STRICT
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-llvm 
-disable-llvm-passes %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM 
--check-prefix=LLVM-NO-STRICT
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -emit-llvm 
-disable-llvm-passes %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG 
--check-prefix=OGCG-NO-STRICT
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir 
-fstrict-flex-arrays=0 -emit-cir %s -o %t-strict-0.cir
+// RUN: FileCheck --input-file=%t-strict-0.cir %s --check-prefix=CIR 
--check-prefix=CIR-STRICT-0
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir 
-fstrict-flex-arrays=0 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-0.ll
+// RUN: FileCheck --input-file=%t-cir-strict-0.ll %s --check-prefix=LLVM 
--check-prefix=LLVM-STRICT-0
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=0 
-emit-llvm -disable-llvm-passes %s -o %t-strict-0.ll
+// RUN: FileCheck --input-file=%t-strict-0.ll %s --check-prefix=OGCG 
--check-prefix=OGCG-STRICT-0
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir 
-fstrict-flex-arrays=1 -emit-cir %s -o %t-strict-1.cir
+// RUN: FileCheck --input-file=%t-strict-1.cir %s --check-prefix=CIR 
--check-prefix=CIR-STRICT-1
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir 
-fstrict-flex-arrays=1 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-1.ll
+// RUN: FileCheck --input-file=%t-cir-strict-1.ll %s --check-prefix=LLVM 
--check-prefix=LLVM-STRICT-1
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=1 
-emit-llvm -disable-llvm-passes %s -o %t-strict-1.ll
+// RUN: FileCheck --input-file=%t-strict-1.ll %s --check-prefix=OGCG 
--check-prefix=OGCG-STRICT-1
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir 
-fstrict-flex-arrays=2 -emit-cir %s -o %t-strict-2.cir
+// RUN: FileCheck --input-file=%t-strict-2.cir %s --check-prefix=CIR 
--check-prefix=CIR-STRICT-2
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir 
-fstrict-flex-arrays=2 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-2.ll
+// RUN: FileCheck --input-file=%t-cir-strict-2.ll %s --check-prefix=LLVM 
--check-prefix=LLVM-STRICT-2
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=2 
-emit-llvm -disable-llvm-passes %s -o %t-strict-2.ll
+// RUN: FileCheck --input-file=%t-strict-2.ll %s --check-prefix=OGCG 
--check-prefix=OGCG-STRICT-2
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir 
-fstrict-flex-arrays=3 -emit-cir %s -o %t-strict-3.cir
+// RUN: FileCheck --input-file=%t-strict-3.cir %s --check-prefix=CIR 
--check-prefix=CIR-STRICT-3
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir 
-fstrict-flex-arrays=3 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-3.ll
+// RUN: FileCheck --input-file=%t-cir-strict-3.ll %s --check-prefix=LLVM 
--check-prefix=LLVM-STRICT-3
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=3 
-emit-llvm -disable-llvm-passes %s -o %t-strict-3.ll
+// RUN: FileCheck --input-file=%t-strict-3.ll %s --check-prefix=OGCG 
--check-prefix=OGCG-STRICT-3
+
+#define OBJECT_SIZE_BUILTIN __builtin_object_size
+
+typedef struct {
+  float f;
+  double c[];
+} foo_t;
+
+typedef struct {
+  float f;
+  double c[0];
+} foo0_t;
+
+typedef struct {
+  float f;
+  double c[1];
+} foo1_t;
+
+typedef struct {
+  float f;
+  double c[2];
+} foo2_t;
+
+// CIR-LABEL: @bar
+// LLVM-LABEL: @bar(
+// OGCG-LABEL: @bar(
+unsigned bar(foo_t *f) {
+  // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-2: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-3: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  return OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// CIR-LABEL: @bar0
+// LLVM-LABEL: @bar0(
+// OGCG-LABEL: @bar0(
+unsigned bar0(foo0_t *f) {
+  // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-2: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-3: cir.const #cir.int<0>
+  // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-3: store i32 0
+  // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-3: ret i32 0
+  return OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// CIR-LABEL: @bar1
+// LLVM-LABEL: @bar1(
+// OGCG-LABEL: @bar1(
+unsigned bar1(foo1_t *f) {
+  // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-2: cir.const #cir.int<8>
+  // CIR-STRICT-3: cir.const #cir.int<8>
+  // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-2: store i32 8
+  // LLVM-STRICT-3: store i32 8
+  // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-2: ret i32 8
+  // OGCG-STRICT-3: ret i32 8
+  return OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// CIR-LABEL: @bar2
+// LLVM-LABEL: @bar2(
+// OGCG-LABEL: @bar2(
+unsigned bar2(foo2_t *f) {
+  // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> 
!u64i
+  // CIR-STRICT-1: cir.const #cir.int<16>
+  // CIR-STRICT-2: cir.const #cir.int<16>
+  // CIR-STRICT-3: cir.const #cir.int<16>
+  // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // LLVM-STRICT-1: store i32 16
+  // LLVM-STRICT-2: store i32 16
+  // LLVM-STRICT-3: store i32 16
+  // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG-STRICT-1: ret i32 16
+  // OGCG-STRICT-2: ret i32 16
+  // OGCG-STRICT-3: ret i32 16
+  return OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+#define DYNAMIC_OBJECT_SIZE_BUILTIN __builtin_dynamic_object_size
+
+// CIR-LABEL: @dyn_bar
+// LLVM-LABEL: @dyn_bar(
+// OGCG-LABEL: @dyn_bar(
+unsigned dyn_bar(foo_t *f) {
+  // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-2: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-3: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// CIR-LABEL: @dyn_bar0
+// LLVM-LABEL: @dyn_bar0(
+// OGCG-LABEL: @dyn_bar0(
+unsigned dyn_bar0(foo0_t *f) {
+  // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-2: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-3: cir.const #cir.int<0>
+  // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-3: store i32 0
+  // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-3: ret i32 0
+  return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// CIR-LABEL: @dyn_bar1
+// LLVM-LABEL: @dyn_bar1(
+// OGCG-LABEL: @dyn_bar1(
+unsigned dyn_bar1(foo1_t *f) {
+  // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-2: cir.const #cir.int<8>
+  // CIR-STRICT-3: cir.const #cir.int<8>
+  // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-2: store i32 8
+  // LLVM-STRICT-3: store i32 8
+  // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-2: ret i32 8
+  // OGCG-STRICT-3: ret i32 8
+  return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// CIR-LABEL: @dyn_bar2
+// LLVM-LABEL: @dyn_bar2(
+// OGCG-LABEL: @dyn_bar2(
+unsigned dyn_bar2(foo2_t *f) {
+  // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : 
!cir.ptr<!void> -> !u64i
+  // CIR-STRICT-1: cir.const #cir.int<16>
+  // CIR-STRICT-2: cir.const #cir.int<16>
+  // CIR-STRICT-3: cir.const #cir.int<16>
+  // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // LLVM-STRICT-1: store i32 16
+  // LLVM-STRICT-2: store i32 16
+  // LLVM-STRICT-3: store i32 16
+  // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 
true)
+  // OGCG-STRICT-1: ret i32 16
+  // OGCG-STRICT-2: ret i32 16
+  // OGCG-STRICT-3: ret i32 16
+  return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// Also checks for non-trailing flex-array like members
+
+typedef struct {
+  double c[0];
+  float f;
+} foofoo0_t;
+
+typedef struct {
+  double c[1];
+  float f;
+} foofoo1_t;
+
+typedef struct {
+  double c[2];
+  float f;
+} foofoo2_t;
+
+// CIR-LABEL: @babar0
+// LLVM-LABEL: @babar0(
+// OGCG-LABEL: @babar0(
+unsigned babar0(foofoo0_t *f) {
+  // CIR-NO-STRICT: cir.const #cir.int<0>
+  // CIR-STRICT-0: cir.const #cir.int<0>
+  // CIR-STRICT-1: cir.const #cir.int<0>
+  // CIR-STRICT-2: cir.const #cir.int<0>
+  // CIR-STRICT-3: cir.const #cir.int<0>
+  // LLVM-NO-STRICT: store i32 0
+  // LLVM-STRICT-0: store i32 0
+  // LLVM-STRICT-1: store i32 0
+  // LLVM-STRICT-2: store i32 0
+  // LLVM-STRICT-3: store i32 0
+  // OGCG-NO-STRICT: ret i32 0
+  // OGCG-STRICT-0: ret i32 0
+  // OGCG-STRICT-1: ret i32 0
+  // OGCG-STRICT-2: ret i32 0
+  // OGCG-STRICT-3: ret i32 0
+  return OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// CIR-LABEL: @babar1
+// LLVM-LABEL: @babar1(
+// OGCG-LABEL: @babar1(
+unsigned babar1(foofoo1_t *f) {
+  // CIR-NO-STRICT: cir.const #cir.int<8>
+  // CIR-STRICT-0: cir.const #cir.int<8>
+  // CIR-STRICT-1: cir.const #cir.int<8>
+  // CIR-STRICT-2: cir.const #cir.int<8>
+  // CIR-STRICT-3: cir.const #cir.int<8>
+  // LLVM-NO-STRICT: store i32 8
+  // LLVM-STRICT-0: store i32 8
+  // LLVM-STRICT-1: store i32 8
+  // LLVM-STRICT-2: store i32 8
+  // LLVM-STRICT-3: store i32 8
+  // OGCG-NO-STRICT: ret i32 8
+  // OGCG-STRICT-0: ret i32 8
+  // OGCG-STRICT-1: ret i32 8
+  // OGCG-STRICT-2: ret i32 8
+  // OGCG-STRICT-3: ret i32 8
+  return OBJECT_SIZE_BUILTIN(f->c, 1);
+}
+
+// CIR-LABEL: @babar2
+// LLVM-LABEL: @babar2(
+// OGCG-LABEL: @babar2(
+unsigned babar2(foofoo2_t *f) {
+  // CIR-NO-STRICT: cir.const #cir.int<16>
+  // CIR-STRICT-0: cir.const #cir.int<16>
+  // CIR-STRICT-1: cir.const #cir.int<16>
+  // CIR-STRICT-2: cir.const #cir.int<16>
+  // CIR-STRICT-3: cir.const #cir.int<16>
+  // LLVM-NO-STRICT: store i32 16
+  // LLVM-STRICT-0: store i32 16
+  // LLVM-STRICT-1: store i32 16
+  // LLVM-STRICT-2: store i32 16
+  // LLVM-STRICT-3: store i32 16
+  // OGCG-NO-STRICT: ret i32 16
+  // OGCG-STRICT-0: ret i32 16
+  // OGCG-STRICT-1: ret i32 16
+  // OGCG-STRICT-2: ret i32 16
+  // OGCG-STRICT-3: ret i32 16
+  return OBJECT_SIZE_BUILTIN(f->c, 1);
+}
diff --git a/clang/test/CIR/CodeGen/object-size.c 
b/clang/test/CIR/CodeGen/object-size.c
new file mode 100644
index 0000000000000..1b10fb8b352cf
--- /dev/null
+++ b/clang/test/CIR/CodeGen/object-size.c
@@ -0,0 +1,877 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+char gbuf[63];
+char *gp;
+int gi, gj;
+
+// CIR-LABEL: @test1
+// LLVM-LABEL: define {{.*}} void @test1
+// OGCG-LABEL: define {{.*}} void @test1
+void test1(void) {
+  // CIR: cir.const #cir.int<59>
+  // LLVM: store i32 59
+  // OGCG: store i32 59
+  gi = __builtin_object_size(&gbuf[4], 1);
+}
+
+// CIR-LABEL: @test2
+// LLVM-LABEL: define {{.*}} void @test2
+// OGCG-LABEL: define {{.*}} void @test2
+void test2(void) {
+  // CIR: cir.const #cir.int<63>
+  // LLVM: store i32 63
+  // OGCG: store i32 63
+  gi = __builtin_object_size(gbuf, 1);
+}
+
+// CIR-LABEL: @test3
+// LLVM-LABEL: define {{.*}} void @test3
+// OGCG-LABEL: define {{.*}} void @test3
+void test3(void) {
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&gbuf[100], 1);
+}
+
+// CIR-LABEL: @test4
+// LLVM-LABEL: define {{.*}} void @test4
+// OGCG-LABEL: define {{.*}} void @test4
+void test4(void) {
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)(void*)&gbuf[-1], 1);
+}
+
+// CIR-LABEL: @test5
+// LLVM-LABEL: define {{.*}} void @test5
+// OGCG-LABEL: define {{.*}} void @test5
+void test5(void) {
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(gp, 0);
+}
+
+// CIR-LABEL: @test6
+// LLVM-LABEL: define {{.*}} void @test6
+// OGCG-LABEL: define {{.*}} void @test6
+void test6(void) {
+  char buf[57];
+
+  // CIR: cir.const #cir.int<53>
+  // LLVM: store i32 53
+  // OGCG: store i32 53
+  gi = __builtin_object_size(&buf[4], 1);
+}
+
+// CIR-LABEL: @test18
+// LLVM-LABEL: define {{.*}} i32 @test18
+// OGCG-LABEL: define {{.*}} i32 @test18
+unsigned test18(int cond) {
+  int a[4], b[4];
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64
+  // OGCG: call i64 @llvm.objectsize.i64
+  return __builtin_object_size(cond ? a : b, 0);
+}
+
+// CIR-LABEL: @test19
+// LLVM-LABEL: define {{.*}} void @test19
+// OGCG-LABEL: define {{.*}} void @test19
+void test19(void) {
+  struct {
+    int a, b;
+  } foo;
+
+  // CIR: cir.const #cir.int<8>
+  // LLVM: store i32 8
+  // OGCG: store i32 8
+  gi = __builtin_object_size(&foo.a, 0);
+  
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&foo.a, 1);
+  
+  // CIR: cir.const #cir.int<8>
+  // LLVM: store i32 8
+  // OGCG: store i32 8
+  gi = __builtin_object_size(&foo.a, 2);
+  
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&foo.a, 3);
+
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&foo.b, 0);
+  
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&foo.b, 1);
+  
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&foo.b, 2);
+  
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&foo.b, 3);
+}
+
+// CIR-LABEL: @test20
+// LLVM-LABEL: define {{.*}} void @test20
+// OGCG-LABEL: define {{.*}} void @test20
+void test20(void) {
+  struct { int t[10]; } t[10];
+
+  // CIR: cir.const #cir.int<380>
+  // LLVM: store i32 380
+  // OGCG: store i32 380
+  gi = __builtin_object_size(&t[0].t[5], 0);
+  
+  // CIR: cir.const #cir.int<20>
+  // LLVM: store i32 20
+  // OGCG: store i32 20
+  gi = __builtin_object_size(&t[0].t[5], 1);
+  
+  // CIR: cir.const #cir.int<380>
+  // LLVM: store i32 380
+  // OGCG: store i32 380
+  gi = __builtin_object_size(&t[0].t[5], 2);
+  
+  // CIR: cir.const #cir.int<20>
+  // LLVM: store i32 20
+  // OGCG: store i32 20
+  gi = __builtin_object_size(&t[0].t[5], 3);
+}
+
+// CIR-LABEL: @test21
+// LLVM-LABEL: define {{.*}} void @test21
+// OGCG-LABEL: define {{.*}} void @test21
+void test21(void) {
+  struct { int t; } t;
+
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t + 1, 0);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t + 1, 1);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t + 1, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t + 1, 3);
+
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t.t + 1, 0);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t.t + 1, 1);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t.t + 1, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t.t + 1, 3);
+}
+
+// CIR-LABEL: @test22
+// LLVM-LABEL: define {{.*}} void @test22
+// OGCG-LABEL: define {{.*}} void @test22
+void test22(void) {
+  struct { int t[10]; } t[10];
+
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[10], 0);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[10], 1);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[10], 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[10], 3);
+
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[9].t[10], 0);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[9].t[10], 1);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[9].t[10], 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[9].t[10], 3);
+
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)&t[0] + sizeof(t), 0);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)&t[0] + sizeof(t), 1);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)&t[0] + sizeof(t), 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)&t[0] + sizeof(t), 3);
+
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 0);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 1);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 3);
+}
+
+struct Test23Ty { int a; int t[10]; };
+
+// CIR-LABEL: @test23
+// LLVM-LABEL: define {{.*}} void @test23
+// OGCG-LABEL: define {{.*}} void @test23
+void test23(struct Test23Ty *p) {
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(p, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(p, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(p, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(p, 3);
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(&p->a, 0);
+  
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&p->a, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(&p->a, 2);
+  
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&p->a, 3);
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(&p->t[5], 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(&p->t[5], 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(&p->t[5], 2);
+  
+  // CIR: cir.const #cir.int<20>
+  // LLVM: store i32 20
+  // OGCG: store i32 20
+  gi = __builtin_object_size(&p->t[5], 3);
+}
+
+// CIR-LABEL: @test24
+// LLVM-LABEL: define {{.*}} void @test24
+// OGCG-LABEL: define {{.*}} void @test24
+void test24(void) {
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size((void*)0, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size((void*)0, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size((void*)0, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((void*)0, 3);
+}
+
+// CIR-LABEL: @test25
+// LLVM-LABEL: define {{.*}} void @test25
+// OGCG-LABEL: define {{.*}} void @test25
+void test25(void) {
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size((void*)0x1000, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size((void*)0x1000, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size((void*)0x1000, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size((void*)0x1000, 3);
+
+  // Skipping (void*)0 + 0x1000 tests - void pointer arithmetic NYI in CIR
+}
+
+// CIR-LABEL: @test26
+// LLVM-LABEL: define {{.*}} void @test26
+// OGCG-LABEL: define {{.*}} void @test26
+void test26(void) {
+  struct { int v[10]; } t[10];
+
+  // CIR: cir.const #cir.int<316>
+  // LLVM: store i32 316
+  // OGCG: store i32 316
+  gi = __builtin_object_size(&t[1].v[11], 0);
+  
+  // CIR: cir.const #cir.int<312>
+  // LLVM: store i32 312
+  // OGCG: store i32 312
+  gi = __builtin_object_size(&t[1].v[12], 1);
+  
+  // CIR: cir.const #cir.int<308>
+  // LLVM: store i32 308
+  // OGCG: store i32 308
+  gi = __builtin_object_size(&t[1].v[13], 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&t[1].v[14], 3);
+}
+
+struct Test27IncompleteTy;
+
+// CIR-LABEL: @test27
+// LLVM-LABEL: define {{.*}} void @test27
+// OGCG-LABEL: define {{.*}} void @test27
+void test27(struct Test27IncompleteTy *t) {
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(t, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(t, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(t, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(t, 3);
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(&test27, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(&test27, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(&test27, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(&test27, 3);
+}
+
+// CIR-LABEL: @test28
+// LLVM-LABEL: define {{.*}} void @test28
+// OGCG-LABEL: define {{.*}} void @test28
+void test28(void) {
+  struct { int v[10]; } t[10];
+
+  // CIR: cir.const #cir.int<360>
+  // LLVM: store i32 360
+  // OGCG: store i32 360
+  gi = __builtin_object_size((char*)((short*)(&t[1])), 0);
+  
+  // CIR: cir.const #cir.int<360>
+  // LLVM: store i32 360
+  // OGCG: store i32 360
+  gi = __builtin_object_size((char*)((short*)(&t[1])), 1);
+  
+  // CIR: cir.const #cir.int<360>
+  // LLVM: store i32 360
+  // OGCG: store i32 360
+  gi = __builtin_object_size((char*)((short*)(&t[1])), 2);
+  
+  // CIR: cir.const #cir.int<360>
+  // LLVM: store i32 360
+  // OGCG: store i32 360
+  gi = __builtin_object_size((char*)((short*)(&t[1])), 3);
+
+  // CIR: cir.const #cir.int<356>
+  // LLVM: store i32 356
+  // OGCG: store i32 356
+  gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 0);
+  
+  // CIR: cir.const #cir.int<36>
+  // LLVM: store i32 36
+  // OGCG: store i32 36
+  gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 1);
+  
+  // CIR: cir.const #cir.int<356>
+  // LLVM: store i32 356
+  // OGCG: store i32 356
+  gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 2);
+  
+  // CIR: cir.const #cir.int<36>
+  // LLVM: store i32 36
+  // OGCG: store i32 36
+  gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 3);
+}
+
+struct DynStructVar {
+  char fst[16];
+  char snd[];
+};
+
+struct DynStruct0 {
+  char fst[16];
+  char snd[0];
+};
+
+struct DynStruct1 {
+  char fst[16];
+  char snd[1];
+};
+
+struct StaticStruct {
+  char fst[16];
+  char snd[2];
+};
+
+// CIR-LABEL: @test29
+// LLVM-LABEL: define {{.*}} void @test29
+// OGCG-LABEL: define {{.*}} void @test29
+void test29(struct DynStructVar *dv, struct DynStruct0 *d0,
+            struct DynStruct1 *d1, struct StaticStruct *ss) {
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(dv->snd, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(dv->snd, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(dv->snd, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(dv->snd, 3);
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(d0->snd, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(d0->snd, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(d0->snd, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(d0->snd, 3);
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(d1->snd, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(d1->snd, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(d1->snd, 2);
+  
+  // CIR: cir.const #cir.int<1>
+  // LLVM: store i32 1
+  // OGCG: store i32 1
+  gi = __builtin_object_size(d1->snd, 3);
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(ss->snd, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(ss->snd, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(ss->snd, 2);
+  
+  // CIR: cir.const #cir.int<2>
+  // LLVM: store i32 2
+  // OGCG: store i32 2
+  gi = __builtin_object_size(ss->snd, 3);
+}
+
+// CIR-LABEL: @test30
+// LLVM-LABEL: define {{.*}} void @test30
+// OGCG-LABEL: define {{.*}} void @test30
+void test30(void) {
+  struct { struct DynStruct1 fst, snd; } *nested;
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(nested->fst.snd, 0);
+  
+  // CIR: cir.const #cir.int<1>
+  // LLVM: store i32 1
+  // OGCG: store i32 1
+  gi = __builtin_object_size(nested->fst.snd, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(nested->fst.snd, 2);
+  
+  // CIR: cir.const #cir.int<1>
+  // LLVM: store i32 1
+  // OGCG: store i32 1
+  gi = __builtin_object_size(nested->fst.snd, 3);
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(nested->snd.snd, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(nested->snd.snd, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(nested->snd.snd, 2);
+  
+  // CIR: cir.const #cir.int<1>
+  // LLVM: store i32 1
+  // OGCG: store i32 1
+  gi = __builtin_object_size(nested->snd.snd, 3);
+
+  union { struct DynStruct1 d1; char c[1]; } *u;
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(u->c, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(u->c, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(u->c, 2);
+  
+  // CIR: cir.const #cir.int<1>
+  // LLVM: store i32 1
+  // OGCG: store i32 1
+  gi = __builtin_object_size(u->c, 3);
+
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(u->d1.snd, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(u->d1.snd, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(u->d1.snd, 2);
+  
+  // CIR: cir.const #cir.int<1>
+  // LLVM: store i32 1
+  // OGCG: store i32 1
+  gi = __builtin_object_size(u->d1.snd, 3);
+}
+
+// CIR-LABEL: @test32
+// LLVM-LABEL: define {{.*}} i64 @test32
+// OGCG-LABEL: define {{.*}} i64 @test32
+static struct DynStructVar D32 = {
+  .fst = {},
+  .snd = { 0, 1, 2, },
+};
+unsigned long test32(void) {
+  // CIR: cir.const #cir.int<19>
+  // LLVM: store i64 19
+  // OGCG: ret i64 19
+  return __builtin_object_size(&D32, 1);
+}
+
+// CIR-LABEL: @test33
+// LLVM-LABEL: define {{.*}} i64 @test33
+// OGCG-LABEL: define {{.*}} i64 @test33
+static struct DynStructVar D33 = {
+  .fst = {},
+  .snd = {},
+};
+unsigned long test33(void) {
+  // CIR: cir.const #cir.int<16>
+  // LLVM: store i64 16
+  // OGCG: ret i64 16
+  return __builtin_object_size(&D33, 1);
+}
+
+// CIR-LABEL: @test34
+// LLVM-LABEL: define {{.*}} i64 @test34
+// OGCG-LABEL: define {{.*}} i64 @test34
+static struct DynStructVar D34 = {
+  .fst = {},
+};
+unsigned long test34(void) {
+  // CIR: cir.const #cir.int<16>
+  // LLVM: store i64 16
+  // OGCG: ret i64 16
+  return __builtin_object_size(&D34, 1);
+}
+
+// CIR-LABEL: @test35
+// LLVM-LABEL: define {{.*}} i64 @test35
+// OGCG-LABEL: define {{.*}} i64 @test35
+unsigned long test35(void) {
+  // CIR: cir.const #cir.int<16>
+  // LLVM: store i64 16
+  // OGCG: ret i64 16
+  return __builtin_object_size(&(struct DynStructVar){}, 1);
+}
+
+// CIR-LABEL: @test37
+// LLVM-LABEL: define {{.*}} i64 @test37
+// OGCG-LABEL: define {{.*}} i64 @test37
+struct Z { struct A { int x, y[]; } z; int a; int b[]; };
+static struct Z my_z = { .b = {1,2,3} };
+unsigned long test37(void) {
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i64 4
+  // OGCG: ret i64 4
+  return __builtin_object_size(&my_z.z, 1);
+}
+
+// CIR-LABEL: @PR30346
+// LLVM-LABEL: define {{.*}} void @PR30346
+// OGCG-LABEL: define {{.*}} void @PR30346
+void PR30346(void) {
+  struct sa_family_t {};
+  struct sockaddr {
+    struct sa_family_t sa_family;
+    char sa_data[14];
+  };
+
+  struct sockaddr *sa;
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(sa->sa_data, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1
+  gi = __builtin_object_size(sa->sa_data, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1
+  gi = __builtin_object_size(sa->sa_data, 2);
+  
+  // CIR: cir.const #cir.int<14>
+  // LLVM: store i32 14
+  // OGCG: store i32 14
+  gi = __builtin_object_size(sa->sa_data, 3);
+}
+
+extern char incomplete_char_array[];
+
+// CIR-LABEL: @incomplete_and_function_types
+// LLVM-LABEL: define {{.*}} void @incomplete_and_function_types
+// OGCG-LABEL: define {{.*}} void @incomplete_and_function_types
+void incomplete_and_function_types(void) {
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0
+  // OGCG: call i64 @llvm.objectsize.i64.p0
+  gi = __builtin_object_size(incomplete_char_array, 0);
+  
+  // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0
+  // OGCG: call i64 @llvm.objectsize.i64.p0
+  gi = __builtin_object_size(incomplete_char_array, 1);
+  
+  // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0
+  // OGCG: call i64 @llvm.objectsize.i64.p0
+  gi = __builtin_object_size(incomplete_char_array, 2);
+  
+  // CIR: cir.const #cir.int<0>
+  // LLVM: store i32 0
+  // OGCG: store i32 0
+  gi = __builtin_object_size(incomplete_char_array, 3);
+}
+
+// CIR-LABEL: @deeply_nested
+// LLVM-LABEL: define {{.*}} void @deeply_nested
+// OGCG-LABEL: define {{.*}} void @deeply_nested
+void deeply_nested(void) {
+  struct {
+    struct {
+      struct {
+        struct {
+          int e[2];
+          char f;
+        } d[2];
+      } c[2];
+    } b[2];
+  } *a;
+
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&a->b[1].c[1].d[1].e[1], 1);
+  
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size(&a->b[1].c[1].d[1].e[1], 3);
+}
diff --git a/clang/test/CIR/CodeGen/object-size.cpp 
b/clang/test/CIR/CodeGen/object-size.cpp
new file mode 100644
index 0000000000000..b60e24594388d
--- /dev/null
+++ b/clang/test/CIR/CodeGen/object-size.cpp
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+// C++-specific tests for __builtin_object_size
+
+int gi;
+
+// CIR-LABEL: @_Z5test1v
+// LLVM-LABEL: define{{.*}} void @_Z5test1v()
+// OGCG-LABEL: define{{.*}} void @_Z5test1v()
+void test1() {
+  // Guaranteeing that our cast removal logic doesn't break more interesting
+  // cases.
+  struct A { int a; };
+  struct B { int b; };
+  struct C: public A, public B {};
+
+  C c;
+
+  // CIR: cir.const #cir.int<8>
+  // LLVM: store i32 8
+  // OGCG: store i32 8
+  gi = __builtin_object_size(&c, 0);
+  // CIR: cir.const #cir.int<8>
+  // LLVM: store i32 8
+  // OGCG: store i32 8
+  gi = __builtin_object_size((A*)&c, 0);
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size((B*)&c, 0);
+
+  // CIR: cir.const #cir.int<8>
+  // LLVM: store i32 8
+  // OGCG: store i32 8
+  gi = __builtin_object_size((char*)&c, 0);
+  // CIR: cir.const #cir.int<8>
+  // LLVM: store i32 8
+  // OGCG: store i32 8
+  gi = __builtin_object_size((char*)(A*)&c, 0);
+  // CIR: cir.const #cir.int<4>
+  // LLVM: store i32 4
+  // OGCG: store i32 4
+  gi = __builtin_object_size((char*)(B*)&c, 0);
+}
+
+// CIR-LABEL: @_Z5test2v()
+// LLVM-LABEL: define{{.*}} void @_Z5test2v()
+// OGCG-LABEL: define{{.*}} void @_Z5test2v()
+void test2() {
+  struct A { char buf[16]; };
+  struct B : A {};
+  struct C { int i; B bs[1]; } *c;
+
+  // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
+  gi = __builtin_object_size(&c->bs[0], 0);
+  // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
+  gi = __builtin_object_size(&c->bs[0], 1);
+  // CIR: cir.objsize min nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 
false)
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 
false)
+  gi = __builtin_object_size(&c->bs[0], 2);
+  // CIR: cir.const #cir.int<16>
+  // LLVM: store i32 16
+  // OGCG: store i32 16
+  gi = __builtin_object_size(&c->bs[0], 3);
+
+  // NYI: DerivedToBase cast
+  // gi = __builtin_object_size((A*)&c->bs[0], 0);
+
+  // CIR: cir.const #cir.int<16>
+  // LLVM: store i32 16
+  // OGCG: store i32 16
+  gi = __builtin_object_size((A*)&c->bs[0], 1);
+
+  // NYI: DerivedToBase cast 
+  // gi = __builtin_object_size((A*)&c->bs[0], 2);
+
+  // CIR: cir.const #cir.int<16>
+  // LLVM: store i32 16
+  // OGCG: store i32 16
+  gi = __builtin_object_size((A*)&c->bs[0], 3);
+
+  // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 
false)
+  gi = __builtin_object_size(&c->bs[0].buf[0], 0);
+  // CIR: cir.const #cir.int<16>
+  // LLVM: store i32 16
+  // OGCG: store i32 16
+  gi = __builtin_object_size(&c->bs[0].buf[0], 1);
+  // CIR: cir.objsize min nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i
+  // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 
false)
+  // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 
false)
+  gi = __builtin_object_size(&c->bs[0].buf[0], 2);
+  // CIR: cir.const #cir.int<16>
+  // LLVM: store i32 16
+  // OGCG: store i32 16
+  gi = __builtin_object_size(&c->bs[0].buf[0], 3);
+}
diff --git a/clang/test/CIR/IR/objsize.cir b/clang/test/CIR/IR/objsize.cir
new file mode 100644
index 0000000000000..bc24551c446e6
--- /dev/null
+++ b/clang/test/CIR/IR/objsize.cir
@@ -0,0 +1,89 @@
+// Test the cir.objsize operation can parse and print correctly (roundtrip)
+// with all possible combinations of optional attributes
+
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!u64i = !cir.int<u, 64>
+!void = !cir.void
+
+module {
+  cir.func @test_max(%arg0: !cir.ptr<!void>) -> !u64i {
+    %0 = cir.objsize max %arg0 : !cir.ptr<!void> -> !u64i
+    cir.return %0 : !u64i
+  }
+
+  cir.func @test_max_nullunknown(%arg0: !cir.ptr<!void>) -> !u64i {
+    %0 = cir.objsize max nullunknown %arg0 : !cir.ptr<!void> -> !u64i
+    cir.return %0 : !u64i
+  }
+
+  cir.func @test_max_dynamic(%arg0: !cir.ptr<!void>) -> !u64i {
+    %0 = cir.objsize max dynamic %arg0 : !cir.ptr<!void> -> !u64i
+    cir.return %0 : !u64i
+  }
+
+  cir.func @test_max_nullunknown_dynamic(%arg0: !cir.ptr<!void>) -> !u64i {
+    %0 = cir.objsize max nullunknown dynamic %arg0 : !cir.ptr<!void> -> !u64i
+    cir.return %0 : !u64i
+  }
+
+  cir.func @test_min(%arg0: !cir.ptr<!void>) -> !u64i {
+    %0 = cir.objsize min %arg0 : !cir.ptr<!void> -> !u64i
+    cir.return %0 : !u64i
+  }
+
+  cir.func @test_min_nullunknown(%arg0: !cir.ptr<!void>) -> !u64i {
+    %0 = cir.objsize min nullunknown %arg0 : !cir.ptr<!void> -> !u64i
+    cir.return %0 : !u64i
+  }
+
+  cir.func @test_min_dynamic(%arg0: !cir.ptr<!void>) -> !u64i {
+    %0 = cir.objsize min dynamic %arg0 : !cir.ptr<!void> -> !u64i
+    cir.return %0 : !u64i
+  }
+
+  cir.func @test_min_nullunknown_dynamic(%arg0: !cir.ptr<!void>) -> !u64i {
+    %0 = cir.objsize min nullunknown dynamic %arg0 : !cir.ptr<!void> -> !u64i
+    cir.return %0 : !u64i
+  }
+}
+
+// CHECK: cir.func @test_max(%arg0: !cir.ptr<!void>) -> !u64i {
+// CHECK:   %0 = cir.objsize max %arg0 : !cir.ptr<!void> -> !u64i
+// CHECK:   cir.return %0 : !u64i
+// CHECK: }
+
+// CHECK: cir.func @test_max_nullunknown(%arg0: !cir.ptr<!void>) -> !u64i {
+// CHECK:   %0 = cir.objsize max nullunknown %arg0 : !cir.ptr<!void> -> !u64i
+// CHECK:   cir.return %0 : !u64i
+// CHECK: }
+
+// CHECK: cir.func @test_max_dynamic(%arg0: !cir.ptr<!void>) -> !u64i {
+// CHECK:   %0 = cir.objsize max dynamic %arg0 : !cir.ptr<!void> -> !u64i
+// CHECK:   cir.return %0 : !u64i
+// CHECK: }
+
+// CHECK: cir.func @test_max_nullunknown_dynamic(%arg0: !cir.ptr<!void>) -> 
!u64i {
+// CHECK:   %0 = cir.objsize max nullunknown dynamic %arg0 : !cir.ptr<!void> 
-> !u64i
+// CHECK:   cir.return %0 : !u64i
+// CHECK: }
+
+// CHECK: cir.func @test_min(%arg0: !cir.ptr<!void>) -> !u64i {
+// CHECK:   %0 = cir.objsize min %arg0 : !cir.ptr<!void> -> !u64i
+// CHECK:   cir.return %0 : !u64i
+// CHECK: }
+
+// CHECK: cir.func @test_min_nullunknown(%arg0: !cir.ptr<!void>) -> !u64i {
+// CHECK:   %0 = cir.objsize min nullunknown %arg0 : !cir.ptr<!void> -> !u64i
+// CHECK:   cir.return %0 : !u64i
+// CHECK: }
+
+// CHECK: cir.func @test_min_dynamic(%arg0: !cir.ptr<!void>) -> !u64i {
+// CHECK:   %0 = cir.objsize min dynamic %arg0 : !cir.ptr<!void> -> !u64i
+// CHECK:   cir.return %0 : !u64i
+// CHECK: }
+
+// CHECK: cir.func @test_min_nullunknown_dynamic(%arg0: !cir.ptr<!void>) -> 
!u64i {
+// CHECK:   %0 = cir.objsize min nullunknown dynamic %arg0 : !cir.ptr<!void> 
-> !u64i
+// CHECK:   cir.return %0 : !u64i
+// CHECK: }

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

Reply via email to