[cfe-dev] Visiting statements of a CFG one time
Andrew Sutton via cfe-dev
cfe-dev at lists.llvm.org
Tue Sep 8 07:15:31 PDT 2020
I ran into exactly this problem last week. I wanted to visit top-level
statements (and expressions since expression-statements are just
expressions) and recursively work through their ASTs. I just wrote a small
pre-pass over the CFG elements that would construct a set of top-level
statements by noting which expressions occurred as subexpressions and then
extract the statements from there.
There's probably a better way to do this, but here's what my implementation
of that function looks like.
void findStatements(CFGBlock *B, llvm::SmallVectorImpl<const Stmt *>
&SS) {
llvm::SmallDenseMap<const Stmt*, bool> Map;
// Mark subexpressions of each element in the block.
for (auto I = B->begin(); I != B->end(); ++I) {
CFGElement E = *I;
if (auto SE = E.getAs<CFGStmt>()) {
const Stmt *S = SE->getStmt();
for (const Stmt *K : S->children())
Map[K] = true;
}
}
// Any expressions not in Map are statements.
for (auto I = B->begin(); I != B->end(); ++I) {
CFGElement E = *I;
if (auto SE = E.getAs<CFGStmt>()) {
const Stmt *S = SE->getStmt();
if (Map.find(S) == Map.end())
SS.push_back(S);
}
}
}
Andrew Sutton
On Tue, Sep 8, 2020 at 9:44 AM Stefan Schulze Frielinghaus via cfe-dev <
cfe-dev at lists.llvm.org> wrote:
> 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
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20200908/a8a2f9f7/attachment.html>
More information about the cfe-dev
mailing list