[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