[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