llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) <details> <summary>Changes</summary> This fixes a few more tests from `pass-object-size.c`, but we still can't enable the entire file. --- Full diff: https://github.com/llvm/llvm-project/pull/179271.diff 4 Files Affected: - (modified) clang/lib/AST/ByteCode/Descriptor.h (+4) - (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+16-4) - (modified) clang/test/AST/ByteCode/builtin-object-size-codegen.cpp (+20) - (added) clang/test/AST/ByteCode/pass-object-size.c (+103) ``````````diff diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index 8338585a1741b..b052971733567 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -227,6 +227,10 @@ struct Descriptor final { return dyn_cast_if_present<RecordDecl>(asDecl()); } + template <typename T> const T *getAs() const { + return dyn_cast_if_present<T>(asDecl()); + } + /// Returns the size of the object without metadata. unsigned getSize() const { assert(!isUnknownSizeArray() && "Array of unknown size"); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 2921618b0c630..0edfc01fcbeba 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -2278,7 +2278,8 @@ static bool pointsToLastObject(const Pointer &Ptr) { } /// Does Ptr point to the last object AND to a flexible array member? -static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const Pointer &Ptr) { +static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const Pointer &Ptr, + bool InvalidBase) { auto isFlexibleArrayMember = [&](const Descriptor *FieldDesc) { using FAMKind = LangOptions::StrictFlexArraysLevelKind; FAMKind StrictFlexArraysLevel = @@ -2300,7 +2301,7 @@ static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const Pointer &Ptr) { if (!FieldDesc->isArray()) return false; - return Ptr.isDummy() && pointsToLastObject(Ptr) && + return InvalidBase && pointsToLastObject(Ptr) && isFlexibleArrayMember(FieldDesc); } @@ -2312,6 +2313,14 @@ UnsignedOrNone evaluateBuiltinObjectSize(const ASTContext &ASTCtx, if (Ptr.isDummy() && Ptr.getType()->isPointerType()) return std::nullopt; + bool InvalidBase = false; + + if (Ptr.isDummy()) { + if (const VarDecl *VD = Ptr.getDeclDesc()->asVarDecl(); + VD && VD->getType()->isPointerType()) + InvalidBase = true; + } + // According to the GCC documentation, we want the size of the subobject // denoted by the pointer. But that's not quite right -- what we actually // want is the size of the immediately-enclosing array, if there is one. @@ -2326,14 +2335,17 @@ UnsignedOrNone evaluateBuiltinObjectSize(const ASTContext &ASTCtx, bool ReportMinimum = (Kind & 2u); if (!UseFieldDesc || DetermineForCompleteObject) { // Lower bound, so we can't fall back to this. - if (ReportMinimum && !DetermineForCompleteObject) + if (ReportMinimum && UseFieldDesc && !DetermineForCompleteObject) return std::nullopt; // Can't read beyond the pointer decl desc. if (!UseFieldDesc && !ReportMinimum && DeclDesc->getType()->isPointerType()) return std::nullopt; + + if (InvalidBase) + return std::nullopt; } else { - if (isUserWritingOffTheEnd(ASTCtx, Ptr)) { + if (isUserWritingOffTheEnd(ASTCtx, Ptr, InvalidBase)) { // If we cannot determine the size of the initial allocation, then we // can't given an accurate upper-bound. However, we are still able to give // conservative lower-bounds for Type=3. diff --git a/clang/test/AST/ByteCode/builtin-object-size-codegen.cpp b/clang/test/AST/ByteCode/builtin-object-size-codegen.cpp index c466c815e230a..a8071764219c5 100644 --- a/clang/test/AST/ByteCode/builtin-object-size-codegen.cpp +++ b/clang/test/AST/ByteCode/builtin-object-size-codegen.cpp @@ -15,6 +15,10 @@ void foo() { gi = __builtin_object_size(&c->bs[0], 2); // CHECK: store i32 16 gi = __builtin_object_size(&c->bs[0], 3); + + C c2{}; + // CHECK: store i32 16 + gi = __builtin_object_size(&c2.bs[0], 1); } @@ -102,3 +106,19 @@ void test3() { gi = __builtin_object_size((B*)&c, 3); } + +struct A { char buf[16]; }; +struct B : A {}; +struct C { int i; B bs[1]; } *c; +void globalPointer() { + int gi; + // CHECK: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0], 2); +} + +void nonPtrParam(C c) { + int gi; + // CHECK: store i32 16 + gi = __builtin_object_size(&c.bs[0], 2); +} + diff --git a/clang/test/AST/ByteCode/pass-object-size.c b/clang/test/AST/ByteCode/pass-object-size.c new file mode 100644 index 0000000000000..d8ea5e9d3160c --- /dev/null +++ b/clang/test/AST/ByteCode/pass-object-size.c @@ -0,0 +1,103 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s + +/// This is the part of test/CodeGen/pass-object-size.c we can evaluate. + +typedef unsigned long size_t; + +struct Foo { + int t[10]; +}; + +#define PS(N) __attribute__((pass_object_size(N))) +#define PDS(N) __attribute__((pass_dynamic_object_size(N))) + +int gi = 0; + +// CHECK-LABEL: define{{.*}} i32 @ObjectSize0(ptr noundef %{{.*}}, i64 noundef %0) +int ObjectSize0(void *const p PS(0)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_object_size(p, 0); +} + +// CHECK-LABEL: define{{.*}} i32 @DynamicObjectSize0(ptr noundef %{{.*}}, i64 noundef %0) +int DynamicObjectSize0(void *const p PDS(0)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_dynamic_object_size(p, 0); +} + +// CHECK-LABEL: define{{.*}} i32 @ObjectSize1(ptr noundef %{{.*}}, i64 noundef %0) +int ObjectSize1(void *const p PS(1)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_object_size(p, 1); +} + +// CHECK-LABEL: define{{.*}} i32 @DynamicObjectSize1(ptr noundef %{{.*}}, i64 noundef %0) +int DynamicObjectSize1(void *const p PDS(1)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_dynamic_object_size(p, 1); +} + +// CHECK-LABEL: define{{.*}} i32 @ObjectSize2(ptr noundef %{{.*}}, i64 noundef %0) +int ObjectSize2(void *const p PS(2)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_object_size(p, 2); +} + +// CHECK-LABEL: define{{.*}} i32 @DynamicObjectSize2(ptr noundef %{{.*}}, i64 noundef %0) +int DynamicObjectSize2(void *const p PDS(2)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_object_size(p, 2); +} + +// CHECK-LABEL: define{{.*}} i32 @ObjectSize3(ptr noundef %{{.*}}, i64 noundef %0) +int ObjectSize3(void *const p PS(3)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_object_size(p, 3); +} + +// CHECK-LABEL: define{{.*}} i32 @DynamicObjectSize3(ptr noundef %{{.*}}, i64 noundef %0) +int DynamicObjectSize3(void *const p PDS(3)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_object_size(p, 3); +} + +void *malloc(unsigned long) __attribute__((alloc_size(1))); + +// CHECK-LABEL: define{{.*}} void @test1 +void test1(unsigned long sz) { + struct Foo t[10]; + + // CHECK: call i32 @ObjectSize0(ptr noundef %{{.*}}, i64 noundef 360) + gi = ObjectSize0(&t[1]); + // CHECK: call i32 @ObjectSize1(ptr noundef %{{.*}}, i64 noundef 360) + gi = ObjectSize1(&t[1]); + // CHECK: call i32 @ObjectSize2(ptr noundef %{{.*}}, i64 noundef 360) + gi = ObjectSize2(&t[1]); + // CHECK: call i32 @ObjectSize3(ptr noundef %{{.*}}, i64 noundef 360) + gi = ObjectSize3(&t[1]); + + // CHECK: call i32 @ObjectSize0(ptr noundef %{{.*}}, i64 noundef 356) + gi = ObjectSize0(&t[1].t[1]); + // CHECK: call i32 @ObjectSize1(ptr noundef %{{.*}}, i64 noundef 36) + gi = ObjectSize1(&t[1].t[1]); + // CHECK: call i32 @ObjectSize2(ptr noundef %{{.*}}, i64 noundef 356) + gi = ObjectSize2(&t[1].t[1]); + // CHECK: call i32 @ObjectSize3(ptr noundef %{{.*}}, i64 noundef 36) + gi = ObjectSize3(&t[1].t[1]); + + char *ptr = (char *)malloc(sz); + + // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0({{.*}}, i1 false, i1 true, i1 true) + // CHECK: call i32 @DynamicObjectSize0(ptr noundef %{{.*}}, i64 noundef [[REG]]) + gi = DynamicObjectSize0(ptr); + + // CHECK: [[WITH_OFFSET:%.*]] = getelementptr + // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[WITH_OFFSET]], i1 false, i1 true, i1 true) + // CHECK: call i32 @DynamicObjectSize0(ptr noundef {{.*}}, i64 noundef [[REG]]) + gi = DynamicObjectSize0(ptr+10); + + // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0({{.*}}, i1 true, i1 true, i1 true) + // CHECK: call i32 @DynamicObjectSize2(ptr noundef {{.*}}, i64 noundef [[REG]]) + gi = DynamicObjectSize2(ptr); +} `````````` </details> https://github.com/llvm/llvm-project/pull/179271 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
