[flang] [libc] [libcxx] [llvm] [compiler-rt] [clang] [clang-tools-extra] [Clang] Generate the GEP instead of adding AST nodes (PR #73730)

Yeoul Na via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 12 12:52:08 PST 2023


================
@@ -956,60 +951,199 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
   return nullptr;
 }
 
-const Expr *
-CodeGenFunction::BuildCountedByFieldExpr(const Expr *Base,
-                                         const ValueDecl *CountedByVD) {
+namespace {
+
+/// \p StructAccessBase returns the base \p Expr of a field access. It returns
+/// either a \p DeclRefExpr, representing the base pointer to the struct, i.e.:
+///
+///     p in p-> a.b.c
+///
+/// or a \p MemberExpr, if the \p MemberExpr has the \p RecordDecl we're
+/// looking for:
+///
+///     struct s {
+///       struct s *ptr;
+///       int count;
+///       char array[] __attribute__((counted_by(count)));
+///     };
+///
+/// If we have an expression like \p p->ptr->array[index], we want the
+/// \p MemberExpr for \p p->ptr instead of \p p.
+class StructAccessBase : public StmtVisitor<StructAccessBase, Expr *> {
+  const RecordDecl *ExpectedRD;
+
+  bool IsExpectedRecordDecl(const Expr *E) const {
+    QualType Ty = E->getType();
+    if (Ty->isPointerType())
+      Ty = Ty->getPointeeType();
+    return ExpectedRD == Ty->getAsRecordDecl();
+  }
+
+public:
+  StructAccessBase(const RecordDecl *ExpectedRD) : ExpectedRD(ExpectedRD) {}
+
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  // NOTE: If we build C++ support for counted_by, then we'll have to handle
+  // horrors like this:
+  //
+  //     struct S {
+  //       int x, y;
+  //       int blah[] __attribute__((counted_by(x)));
+  //     } s;
+  //
+  //     int foo(int index, int val) {
+  //       int (S::*IHatePMDs)[] = &S::blah;
+  //       (s.*IHatePMDs)[index] = val;
+  //     }
+
+  Expr *Visit(Expr *E) {
+    return StmtVisitor<StructAccessBase, Expr *>::Visit(E);
+  }
+
+  Expr *VisitStmt(Stmt *S) { return nullptr; }
+
+  // These are the types we expect to return (in order of most to least
+  // likely):
+  //
+  //   1. DeclRefExpr - This is the expression for the base of the structure.
+  //      It's exactly what we want to build an access to the \p counted_by
+  //      field.
+  //   2. MemberExpr - This is the expression that has the same \p RecordDecl
+  //      as the flexble array member's lexical enclosing \p RecordDecl. This
+  //      allows us to catch things like: "p->p->array"
+  //   3. CompoundLiteralExpr - This is for people who create something
+  //      heretical like (struct foo has a flexible array member):
+  //
+  //        (struct foo){ 1, 2 }.blah[idx];
+  Expr *VisitDeclRefExpr(DeclRefExpr *E) {
+    return IsExpectedRecordDecl(E) ? E : nullptr;
+  }
+  Expr *VisitMemberExpr(MemberExpr *E) {
+    if (IsExpectedRecordDecl(E) && E->isArrow())
+      return E;
+    Expr *Res = Visit(E->getBase());
+    return !Res && IsExpectedRecordDecl(E) ? E : Res;
+  }
+  Expr *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+    return IsExpectedRecordDecl(E) ? E : nullptr;
+  }
+
+  // "Pass This On" --The Knife
+  Expr *VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+    if (IsExpectedRecordDecl(E))
+      return E;
+    return Visit(E->getBase());
+  }
+  Expr *VisitCastExpr(CastExpr *E) { return Visit(E->getSubExpr()); }
+  Expr *VisitImplicitCastExpr(ImplicitCastExpr *E) {
+    return Visit(E->getSubExpr());
+  }
+  Expr *VisitParenExpr(ParenExpr *E) {
+    if (IsExpectedRecordDecl(E))
+      return E;
+    return Visit(E->getSubExpr());
+  }
+  Expr *VisitUnaryAddrOf(UnaryOperator *E) {
+    if (IsExpectedRecordDecl(E))
+      return E;
+    return Visit(E->getSubExpr());
+  }
+  Expr *VisitUnaryDeref(UnaryOperator *E) {
+    if (IsExpectedRecordDecl(E))
+      return E;
+    return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+llvm::Value *CodeGenFunction::EmitCountedByFieldExpr(const Expr *Base,
+                                                     const ValueDecl *VD) {
+  // This method is typically called in contexts where we can't generate
+  // side-effects, like in __builtin{_dynamic}_object_size. When finding
+  // expressions, only choose those that have either already been emitted or
+  // can be loaded without side-effects.
+  const DeclContext *DC = VD->getLexicalDeclContext();
+  const auto *CountedByRD = cast<RecordDecl>(DC);
+
   // Find the outer struct expr (i.e. p in p->a.b.c.d).
-  Expr *CountedByExpr = const_cast<Expr *>(Base)->IgnoreParenImpCasts();
-
-  // Work our way up the expression until we reach the DeclRefExpr.
-  while (!isa<DeclRefExpr>(CountedByExpr))
-    if (const auto *ME = dyn_cast<MemberExpr>(CountedByExpr))
-      CountedByExpr = ME->getBase()->IgnoreParenImpCasts();
-
-  // Add back an implicit cast to create the required pr-value.
-  CountedByExpr = ImplicitCastExpr::Create(
-      getContext(), CountedByExpr->getType(), CK_LValueToRValue, CountedByExpr,
-      nullptr, VK_PRValue, FPOptionsOverride());
-
-  if (const auto *IFD = dyn_cast<IndirectFieldDecl>(CountedByVD)) {
-    // The counted_by field is inside an anonymous struct / union. The
-    // IndirectFieldDecl has the correct order of FieldDecls to build this
-    // easily. (Yay!)
-    for (NamedDecl *ND : IFD->chain()) {
-      auto *VD = cast<ValueDecl>(ND);
-      CountedByExpr =
-          MemberExpr::CreateImplicit(getContext(), CountedByExpr,
-                                     CountedByExpr->getType()->isPointerType(),
-                                     VD, VD->getType(), VK_LValue, OK_Ordinary);
-    }
-  } else {
-    CountedByExpr = MemberExpr::CreateImplicit(
-        getContext(), const_cast<Expr *>(CountedByExpr),
-        CountedByExpr->getType()->isPointerType(),
-        const_cast<ValueDecl *>(CountedByVD), CountedByVD->getType(), VK_LValue,
-        OK_Ordinary);
+  Expr *CountedByExpr =
+      StructAccessBase(CountedByRD).Visit(const_cast<Expr *>(Base));
+  if (!CountedByExpr)
+    return nullptr;
+
+  llvm::Value *Res = nullptr;
+  if (auto *DRE = dyn_cast<DeclRefExpr>(CountedByExpr)) {
+    Res = EmitDeclRefLValue(DRE).getPointer(*this);
+  } else if (CountedByExpr->HasSideEffects(getContext())) {
----------------
rapidsna wrote:

Nit: I meant something like `StructBase`.

https://github.com/llvm/llvm-project/pull/73730


More information about the cfe-commits mailing list