[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)
Eli Friedman via cfe-commits
cfe-commits at lists.llvm.org
Thu May 30 15:09:33 PDT 2024
================
@@ -1062,6 +1063,160 @@ 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 *> {
+ ASTContext &Ctx;
+ bool SkipASE;
+
+public:
+ ObjectSizeVisitor(ASTContext &Ctx, bool SkipASE = false)
+ : Ctx(Ctx), 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()->IgnoreParenImpCasts()) : E;
+ }
+
+ const Expr *VisitCastExpr(const CastExpr *E) {
+ const Expr *NoopE = E->IgnoreParenNoopCasts(Ctx);
+ return NoopE != E ? Visit(NoopE->IgnoreParenImpCasts()) : nullptr;
+ }
+ const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+ return Visit(E->getSubExpr()->IgnoreParenImpCasts());
+ }
+};
+
+} // end anonymous namespace
+
+/// getLastDecl - Return the last FieldDecl in the struct.
+static const FieldDecl *getLastDecl(const RecordDecl *RD) {
+ const FieldDecl *LastFieldDecl = nullptr;
+ for (const FieldDecl *FD : RD->fields())
+ LastFieldDecl = FD;
+
+ if (LastFieldDecl) {
+ QualType Ty = LastFieldDecl->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.
+ LastFieldDecl = getLastDecl(Rec);
+ }
+
+ return LastFieldDecl;
+}
+
+/// 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;
+
+ ASTContext &Ctx = getContext();
+ const Expr *ObjectRef = ObjectSizeVisitor(Ctx).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();
+ }
+ }
+
+ 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(Ctx, 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();
+
+ if (getLastDecl(OuterRD) == 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);
----------------
efriedma-quic wrote:
Do we need to check whether ArrayIdx has side-effects? (If EmittedE is non-null, we don't check for side-effects otherwise.)
https://github.com/llvm/llvm-project/pull/86858
More information about the cfe-commits
mailing list