[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