[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)
Bill Wendling via cfe-commits
cfe-commits at lists.llvm.org
Wed May 29 14:01:44 PDT 2024
================
@@ -1052,6 +1053,165 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, IsSigned));
}
+namespace {
+
+class ObjectSizeVisitor
+ : public ConstStmtVisitor<ObjectSizeVisitor, const Expr *> {
+ bool SkipASE;
+
+public:
+ ObjectSizeVisitor(bool SkipASE = false) : SkipASE(SkipASE) {}
+
+ const Expr *Visit(const Expr *E) {
+ return ConstStmtVisitor<ObjectSizeVisitor, const Expr *>::Visit(E);
+ }
+
+ const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+ const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+ const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+ const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ return SkipASE ? Visit(E->getBase()) : E;
+ }
+
+ const Expr *VisitCastExpr(const CastExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitParenExpr(const ParenExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+};
+
+} // end anonymous namespace
+
+/// getLastDecl - Return the last FieldDecl in the struct.
+static const FieldDecl *getLastDecl(const RecordDecl *RD) {
+ const Decl *LastDecl = nullptr;
+ for (const Decl *D : RD->decls())
+ if (isa<FieldDecl>(D) || isa<RecordDecl>(D))
+ LastDecl = D;
+
+ if (const auto *LastRD = dyn_cast<RecordDecl>(LastDecl)) {
+ LastDecl = getLastDecl(LastRD);
+ } else if (const auto *LastFD = dyn_cast<FieldDecl>(LastDecl)) {
+ QualType Ty = LastFD->getType();
+ if (Ty->isPointerType())
+ Ty = Ty->getPointeeType();
+
+ if (const RecordDecl *Rec = Ty->getAsRecordDecl())
+ // The last FieldDecl is a structure. Look into that struct to find its
+ // last FieldDecl.
+ LastDecl = getLastDecl(Rec);
+ }
+
+ return dyn_cast_if_present<FieldDecl>(LastDecl);
+}
+
+/// tryToCalculateSubObjectSize - It may be possible to calculate the
+/// sub-object size of an array and skip the generation of the llvm.objectsize
+/// intrinsic. This avoids the complication in conveying the sub-object's
+/// information to the backend. This calculation works for an N-dimentional
+/// array.
+llvm::Value *
+CodeGenFunction::tryToCalculateSubObjectSize(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType) {
+ if ((Type & 0x01) != 1)
+ // Only support sub-object calculation.
+ return nullptr;
+
+ const Expr *ObjectRef = ObjectSizeVisitor().Visit(E);
+ if (!ObjectRef)
+ return nullptr;
+
+ QualType ObjectRefType = ObjectRef->getType();
+ if (ObjectRefType->isPointerType())
+ ObjectRefType = ObjectRefType->getPointeeType();
+
+ // Collect the base and index from the array.
+ QualType ObjectBaseRefTy;
+ const Expr *ArrayIdx = nullptr;
+
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(ObjectRef)) {
+ ArrayIdx = ASE->getIdx()->IgnoreParenImpCasts();
+
+ const Expr *ArrayRefBase = ASE->getBase()->IgnoreParenImpCasts();
+ if (isa<ArraySubscriptExpr>(ArrayRefBase)) {
+ ObjectBaseRefTy = ArrayRefBase->getType();
+ if (ObjectBaseRefTy->isPointerType())
+ ObjectBaseRefTy = ObjectBaseRefTy->getPointeeType();
+ }
+ }
+
+ ASTContext &Ctx = getContext();
+ if (!ArrayIdx || ArrayIdx->HasSideEffects(Ctx))
+ return nullptr;
+
+ // Check to see if the Decl is a flexible array member. Processing of the
+ // 'counted_by' attribute is done by now. So we don't have any information on
+ // its size, so return MAX_INT.
+ //
+ // Rerun the visitor to find the base expr: MemberExpr or DeclRefExpr.
+ ObjectRef = ObjectSizeVisitor(true).Visit(ObjectRef);
+ if (!ObjectRef)
+ return nullptr;
+
+ if (const auto *ME = dyn_cast<MemberExpr>(ObjectRef)) {
+ if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+ const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
+ getLangOpts().getStrictFlexArraysLevel();
+ const RecordDecl *OuterRD =
+ FD->getParent()->getOuterLexicalRecordContext();
+ const FieldDecl *LastFD = getLastDecl(OuterRD);
+
+ if (LastFD == FD && Decl::isFlexibleArrayMemberLike(
+ Ctx, FD, FD->getType(), StrictFlexArraysLevel,
+ /*IgnoreTemplateOrMacroSubstitution=*/true))
+ return ConstantInt::get(ResType, -1, /*isSigned=*/true);
+ }
+ }
+
+ if (ObjectBaseRefTy.isNull()) {
+ ObjectBaseRefTy = ObjectRef->getType();
+ if (ObjectBaseRefTy->isPointerType())
+ ObjectBaseRefTy = ObjectBaseRefTy->getPointeeType();
+ }
+
+ // Generate the calculation:
+ //
+ // S Object[n_1][n_2]...[n_m]; /* M-dimentional array */
+ //
+ // ObjectRef = Object[n_1]...[n_x]; /* 0 < x < m */
+ // ObjectBaseRef = Object[n_1]...[n_{x-1}];
+ //
+ // ArrayRefSize = sizeof( typeof( ObjectRef ) );
+ // ArrayRefBaseSize = sizeof( typeof( ObjectBaseRef ) );
+ //
+ // Size = ArrayRefSize - (ArrayRefBaseSize * ArrayIdx);
+ // return Size > 0 ? Size : 0;
+ //
+ Value *ArrayRefSize = ConstantInt::get(
+ ResType, Ctx.getTypeSizeInChars(ObjectRefType).getQuantity(),
+ /*isSigned=*/true);
+ Value *ArrayRefBaseSize = ConstantInt::get(
+ ResType, Ctx.getTypeSizeInChars(ObjectBaseRefTy).getQuantity(),
+ /*isSigned=*/true);
+
+ Value *Res = EmitScalarExpr(ArrayIdx);
+
+ Res = Builder.CreateIntCast(Res, ResType, /*isSigned=*/true);
----------------
bwendling wrote:
Ah! Gotcha. Changed.
https://github.com/llvm/llvm-project/pull/86858
More information about the cfe-commits
mailing list