[cfe-dev] Visiting statements of a CFG one time

Stefan Schulze Frielinghaus via cfe-dev cfe-dev at lists.llvm.org
Tue Sep 8 06:44:11 PDT 2020


Hi all,

I'm trying to iterate over all top-level functions of a C file and perform
control-flow analysis of each function body.  My current approach looks as
follows:

class MyASTVisitor : public DeclVisitor<MyASTVisitor> {
  ASTContext &Context;
public:
  explicit MyASTVisitor(ASTContext &Context) : Context(Context) { }

  void VisitFunctionDecl(FunctionDecl *FD) {
    if (!FD->hasBody())
      return;

    FD->getNameInfo().getName().dump();

    const CFG::BuildOptions opts;
    auto CFG = CFG::buildCFG(FD, FD->getBody(), &Context, opts);
    CFG->dump(Context.getLangOpts(), true);
    // perform the actual analysis over the CFG
  }
};

class MyConsumer : public ASTConsumer {
  MyASTVisitor Visitor;
public:
  explicit MyConsumer(ASTContext &Context) : Visitor(Context) { }

  bool HandleTopLevelDecl(DeclGroupRef DR) override {
    for (auto *I : DR)
      Visitor.Visit(I);
    return true;
  }
};

What confuses me right now is how the CFG is structured.  Consider the
following C code:

extern int *pi;
extern unsigned char *pc;
void foo(void) {
    *(pi=(int *)pc, pi) = 42;
}

The dump of the corresponding CFG looks as follows:

 [B2 (ENTRY)]
   Succs (1): B1

 [B1]
   1: pi = (int *)pc
   2: pi (ImplicitCastExpr, LValueToRValue, int *)
   3: ... , [B1.2]
   4: *([B1.3]) = 42
   Preds (1): B2
   Succs (1): B0

 [B0 (EXIT)]
   Preds (1): B1

The single statement
  *(pi=(int *)pc, pi) = 42;
is broken up into 4 statements in the CFG.  That means, if I iterate over each
statement of a block like

for (const CFGBlock *block : *CFG) {
  for (const auto &I : *block) {
    if (Optional<CFGStmt> cs = I.getAs<CFGStmt>())
      TF.Visit(cs->getStmt());
  }
}

and the transfer functions TF recursively visit each subexpression, I will
visit some of them twice.  My plan was actually to construct transfer functions
of type ConstStmtVisitor in order to examine each statement recursively.  In
the past I ran into a similar problem which was related to wrongly set
CFG::BuildOptions.  However, this does not seem to be the case this time.

Is it possible to construct a CFG where statements are not split?  Or is there
another approach to walk over all statements of a basic block exactly one time?

Cheers,
Stefan


More information about the cfe-dev mailing list