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
