[clang] e974c65 - [CIR] Implement __builtin_object_size and __builtin_dynamic_object_size (#166191)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 6 05:10:01 PST 2025
Author: Morris Hafner
Date: 2025-11-06T14:09:56+01:00
New Revision: e974c65774414eceaf789e2464f56e39c9afc210
URL: https://github.com/llvm/llvm-project/commit/e974c65774414eceaf789e2464f56e39c9afc210
DIFF: https://github.com/llvm/llvm-project/commit/e974c65774414eceaf789e2464f56e39c9afc210.diff
LOG: [CIR] Implement __builtin_object_size and __builtin_dynamic_object_size (#166191)
* 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.
---------
Co-authored-by: Andy Kaylor <akaylor at nvidia.com>
Added:
clang/test/CIR/CodeGen/object-size-flex-array.c
clang/test/CIR/CodeGen/object-size.c
clang/test/CIR/CodeGen/object-size.cpp
clang/test/CIR/IR/objsize.cir
Modified:
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/include/clang/CIR/MissingFeatures.h
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
clang/lib/CIR/CodeGen/CIRGenFunction.h
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 6f9a69e697cc3..16258513239d9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4089,6 +4089,57 @@ 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 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
+ 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
+ );
+
+ let results = (outs CIR_AnyFundamentalIntType:$result);
+
+ let assemblyFormat = [{
+ (`min` $min^) : (`max`)?
+ (`nullunknown` $nullunknown^)?
+ (`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 6f099a7027a10..af1ffffcf54c0 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -215,6 +215,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 0803910f2e83a..4e6a5ee7ee210 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -481,6 +481,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;
@@ -663,3 +676,42 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer();
return cir::VAArgOp::create(builder, loc, type, vaList);
}
+
+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` but to a constant instead.
+ 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());
+
+ // 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);
+ // 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();
+}
+
+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 1c52a78d72e33..f879e580989f7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1307,6 +1307,28 @@ 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);
+
+ 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 ba967a43ce59a..b4afed7019417 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2832,6 +2832,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(op.getNullunknown()),
+ 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/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: }
More information about the cfe-commits
mailing list