Recognize valid paths

This is a discussion on Recognize valid paths within the Compilers forums in Theory and Concepts category; Hi, for some static program analyses it is crucial to recognize valid paths of the control flow graph taken while executing the code. if (x < 1) x = 1; if (x > 10) x = 10; For this example code, it's obvious that a path through both then-parts of the conditions is not feasible. Such invalid combination often come up from dependencies between variable assignments (x=1) and values of branch conditions (if(x>10)). Please also note that this is not "dead code" since each of the then-parts can be executed depending on the value of x before the first condition. ...

Go Back   Application Development Forum > Theory and Concepts > Compilers

Object Mix

Register FAQ Calendar Search Today's Posts Mark Forums Read
  #1  
Old 08-20-2008, 03:10 PM
Tim Frink
Guest
 
Default Recognize valid paths

Hi,

for some static program analyses it is crucial to recognize valid
paths of the control flow graph taken while executing the code.

if (x < 1)
x = 1;
if (x > 10)
x = 10;

For this example code, it's obvious that a path through both
then-parts of the conditions is not feasible. Such invalid combination
often come up from dependencies between variable assignments (x=1) and
values of branch conditions (if(x>10)). Please also note that this is
not "dead code" since each of the then-parts can be executed depending
on the value of x before the first condition.

I was wondering which compiler analyses might recognized such invalid
combinations of paths. Any ideas?

Cheers,
Tim
Reply With Quote
  #2  
Old 08-23-2008, 12:24 PM
m.helvensteijn@gmail.com
Guest
 
Default Re: Recognize valid paths

> if (x < 1)
> x = 1;
> if (x > 10)
> x = 10;
>
> I was wondering which compiler analyses might recognized such invalid
> combinations of paths. Any ideas?


That is more complicated than you might think. Analyzing anything more
than the most trivial cases will require a sophisticated logic solver
(which can not guarantee an answer in all cases). But here's the gist
of it (I'm assuming a C syntax):

assert( true );
bool firstScope = false;
assert( !firstScope );
if (x < 1) {
assert( !firstScope && x < 1 );
firstScope = true;
assert( firstScope && x < 1 );
x = 1;
assert( firstScope && x== 1 );
}
assert( (firstScope && x == 1) || (x >= 1 && !firstScope) );
if (x > 10)
assert( x > 10 && ((firstScope && x == 1) || (x >= 1 && !
firstScope)) );
// |
// V
assert( x > 10 && !firstScope);
x = 10;
}

I've changed several things in your example. For convenience, I've
introduced a boolean called firstScope that indicates if you've
visited the (x<1) scope. The goal here is to prove that (!firstScope)
within the (x>10) scope. I've used assert statements to show the proof
outline. Since you haven't given any precondition, we'll start with
the precondition (true) (the weakest possible condition). Then you
work your way down as you calculate the strongest postcondition of
each statement, given its precondition.

Note that calculating the strongest postcondition of a statement
usually requires you to keep track of many temporary logical
variables, but I've left them out for clarity, since we won't need
them in this simple example. I hope the simplified rules for finding
the strongest preconditions are clear from the code. I'm not sure how
I would explain them formally. But if they're unclear, I can try to
give an informal explanation.

As you can see in the proof outline, (!firstScope) is true upon
entering the (x>10) scope.

If there's a simpler way, I don't know it.
Reply With Quote
  #3  
Old 08-23-2008, 06:41 PM
Hans-Peter Diettrich
Guest
 
Default Re: Recognize valid paths

Tim Frink schrieb:

> for some static program analyses it is crucial to recognize valid
> paths of the control flow graph taken while executing the code.
>
> if (x < 1)
> x = 1;
> if (x > 10)
> x = 10;

[...]
> I was wondering which compiler analyses might recognized such invalid
> combinations of paths. Any ideas?


Intuitively I'd partition the values of x into <1, 1..10 and >10, based
on the tested conditions. Then subdivide these ranges, when required by
modifications of the value in some branch (this will not happen in your
example). Finally I'd check whether for every partition a single path is
taken, what again is true in your example. If not, the analysis may
deserve more table space for the possible pathes. Another inspection of
the ever visited BB's, in all pathes, will reveal dead code - if this is
what you want to know. Otherwise I don't understand what an "invalid"
path (never taken) should be useful to know. Branch and bound (wikipedia)?

A more formal approach has already been posted.

DoDi
Reply With Quote
  #4  
Old 08-26-2008, 11:27 AM
Tim Frink
Guest
 
Default Re: Recognize valid paths

Hi,

> if (x > 10)
> assert( x > 10 && ((firstScope && x == 1) || (x >= 1 && !
> firstScope)) );
> // |
> // V
> assert( x > 10 && !firstScope);
> x = 10;
> }


A question on this simplification after "->". What type of rules to
do apply to infer that "
((firstScope && x == 1) || (x >= 1 && !> firstScope)) )"
becomes
"!firstScope" ?

> But if they're unclear, I can try to give an informal explanation.


That would be fine.

In general, how do you call this type of equations and their
solving? Are there any known approaches for that?
Reply With Quote
  #5  
Old 08-26-2008, 11:30 AM
Tim Frink
Guest
 
Default Re: Recognize valid paths

> Intuitively I'd partition the values of x into <1, 1..10 and >10, based
> on the tested conditions. Then subdivide these ranges, when required by
> modifications of the value in some branch (this will not happen in your
> example). Finally I'd check whether for every partition a single path is
> taken, what again is true in your example. If not, the analysis may
> deserve more table space for the possible pathes.


Will this be not complex for real-world applications that might have
a huge number of paths?


> Another inspection of
> the ever visited BB's, in all pathes, will reveal dead code - if this is
> what you want to know.


This is an information about the code that is independent of the calling
context since these BB's are never reached during program execution.

> Otherwise I don't understand what an "invalid"
> path (never taken) should be useful to know. Branch and bound
> (wikipedia)?


The problem to know which paths are taking in which context are
for example crucial for time estimations based on a static program
execution.

Regards,
Tim
Reply With Quote
  #6  
Old 08-27-2008, 07:20 AM
Michiel Helvensteijn
Guest
 
Default Re: Recognize valid paths

Tim Frink wrote:

> > if (x > 10)
> > assert( x > 10 && ((firstScope && x == 1) || (x >= 1 && !
> > firstScope)) );
> > // |
> > // V
> > assert( x > 10 && !firstScope);
> > x = 10;
> > }

>
> A question on this simplification after "->". What type of rules to
> do apply to infer that
> "((firstScope && x == 1) || (x >= 1 && ! firstScope)) )"
> becomes "!firstScope" ?


Ah, but you forget that we also know that "x > 10". I will give the
intermediate steps of the simplification:

x > 10 && ((firstScope && x == 1) || (x >= 1 && !firstScope))
[&& distributivity]
(x > 10 && firstScope && x == 1) || (x > 10 && x >= 1 && !firstScope)
["x > 10 && x == 1" = "false"]
(false && firstScope) || (x > 10 && x >= 1 && !firstScope)
["x > 10" implies "x >= 1"]
(false && firstScope) || (x > 10 && !firstScope)
["false && B" = "false"]
false || (x > 10 && !firstScope)
["false || B" = "B"]
x > 10 && !firstScope

It's simplifications like this, and conclusions you can draw from it, that
require a sophisticated logic solver if you want to do this analysis
automatically. And such solvers cannot guarantee an answer and might run
indefinitely.

> > But if they're unclear, I can try to give an informal explanation.

>
> That would be fine.


I'm not an expert (yet), but I'll try to explain. You can only use the
simple version of the rules if no variable has any relation to any other
variable. Like in this example, x only has a relation with literal integers
and firstScope also stands on its own in the logical conjunctions. This is
a rule of thumb I came up with and I wouldn't count on it in the general
case. But the simple rules I used work like this:

spc(statement, pre) returns the strongest postcondition of statement, given
precondition pre.

wo(cond, a) returns "cond", but with all constraints on "a" removed.

For assignment:
spc("a = b;", pre) = ( wo(pre, a) && a == b )

For if-statements:
spc("if (c) S1; else S2;", pre) =
( spc(S1, pre && c) || spc(S2, pre && !c) )

For no-op (the empty operation):
spc(";", pre) = pre

For if-statements without else (using "else no-op;"):
spc("if (c) S1;", pre) = ( spc(S1, pre && c) || (pre && !c) )

There are similar rules for while-loops and such, but they're more
complicated.

> In general, how do you call this type of equations and their
> solving?


Not sure. Possibly "Strongest Postcondition Logic".

> Are there any known approaches for that?


Yes. But in general, you can't use the simple rules I just showed you. See
this example:

assert(1 <= a && a <= 10);
b = a + 1;
assert(1 <= a && a <= 10 && b == a + 1);
a = 20;
assert( ??? );

What's the strongest postcondition here? Following the simple rules, it
would either be (a == 20) or maybe (a == 20 && b == a + 1). Both are wrong.
The first gives no guarantees about b at all and the second gives the wrong
guarantee, since it uses the new value of a where it should use the old
one. The correct postcondition would be:

assert(a = 20 && 1 <= a_old && a_old <= 10 && b == a_old + 1);

You see? a_old is a logical variable I introduced to complete the assertion
correctly. A logical variable does not appear in the implementation and
only exists for the proof.

Have fun!

--
Michiel
Reply With Quote
  #7  
Old 09-01-2008, 09:43 AM
Jeff Kenton
Guest
 
Default Re: Recognize valid paths

In an otherwise wretched compiler, I saw the use of edge dominators to
solve this type of problem. In the sample code below, after you have
handled the first assignment statement ("x = 1;"), you know that the
edge that got you there had "x < 1" true. Therefore, "x > 10" is false
and you can branch around that path.

Note that you can calculate edge dominators in the same way you do block
dominators, and you can do both calculations at the same time. Note
that, in general, edge dominators form a forest and not a tree as the
block dominators do.

jeff


Tim Frink wrote:
> Hi,
>
> for some static program analyses it is crucial to recognize valid
> paths of the control flow graph taken while executing the code.
>
> if (x < 1)
> x = 1;
> if (x > 10)
> x = 10;
>
> For this example code, it's obvious that a path through both
> then-parts of the conditions is not feasible.




--

---------------------------------------------------------------------
= Jeff Kenton http://home.comcast.net/~jeffrey.kenton =
---------------------------------------------------------------------
Reply With Quote
Reply


Thread Tools
Display Modes


All times are GMT -5. The time now is 06:05 AM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vB Ad Management by =RedTyger=

In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.