[clang] [Clang] Convert __builtin_dynamic_object_size into a calculation (PR #80256)
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 1 14:41:25 PST 2024
================
@@ -1051,6 +1052,145 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, IsSigned));
}
+namespace {
+
+/// \p StructBaseExpr returns the base \p Expr with a structure or union type.
+struct StructBaseExpr : public ConstStmtVisitor<StructBaseExpr, const Expr *> {
+ StructBaseExpr() = default;
+
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+ const Expr *Visit(const Expr *E) {
+ QualType Ty = E->getType();
+ if (Ty->isStructureType() || Ty->isUnionType())
+ return E;
+
+ return ConstStmtVisitor<StructBaseExpr, const Expr *>::Visit(E);
+ }
+
+ const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+
+ const Expr *VisitMemberExpr(const MemberExpr *E) {
+ return Visit(E->getBase());
+ }
+ const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ return Visit(E->getBase());
+ }
+ 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
+
+/// The offset of a field from the beginning of the record.
+llvm::Value *
+CodeGenFunction::tryEmitObjectSizeCalculation(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType) {
+ if ((Type & 0x01) != 0)
+ // We handle only the whole object size.
+ return nullptr;
+
+ E = E->IgnoreParenImpCasts();
+
+ const Expr *Base = StructBaseExpr().Visit(E);
+ if (!Base)
+ return nullptr;
+
+ const RecordDecl *RD = Base->getType()->getAsRecordDecl();
+ if (!RD)
+ return nullptr;
+
+ // Get the full size of the struct.
+ ASTContext &Ctx = getContext();
+ const RecordDecl *OuterRD = RD->getOuterLexicalRecordContext();
+ const clang::Type *RT = OuterRD->getTypeForDecl();
+ CharUnits RecordSize = Ctx.getTypeSizeInChars(RT);
+
+ Value *Res = nullptr;
+
+ if (const auto *U = dyn_cast<UnaryOperator>(E);
+ U && (U->getOpcode() == UO_AddrOf || U->getOpcode() == UO_Deref))
+ E = U->getSubExpr()->IgnoreParenImpCasts();
+
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
+ const Expr *Idx = ASE->getIdx();
+ Base = ASE->getBase()->IgnoreParenImpCasts();
+
+ if (const auto *ME = dyn_cast<MemberExpr>(Base);
+ ME && ME->getType()->isConstantArrayType()) {
+ // The simple case:
+ //
+ // struct s {
+ // int arr[42];
+ // char c;
+ // /* others */
+ // };
+ //
+ // __builtin_dynamic_object_size(&p->arr[idx], 0);
+ //
+ // We can translate the __builtin_dynamic_object_call into:
+ //
+ // sizeof(struct s) - offsetof(arr) - (idx * sizeof(int))
+ //
----------------
zygoloid wrote:
I assume we only need to do this for `Type == 1` (for `0` and `2`, we can just use the LLVM intrinsic, and you're bailing out for `3`). In that case, I don't think we need to care about `sizeof s` here -- for a pointer to an array subscript expression where we know the array bound, we can use `max(sizeof(arr) - sizeof(arr[0]) * idx, 0)`. Type 1 shouldn't permit overwriting the unrelated `c` field in the example above.
https://github.com/llvm/llvm-project/pull/80256
More information about the cfe-commits
mailing list