Debugging of optimized code

cliffc@hpl.hp.com (Cliff Click)
Thu, 2 Feb 1995 06:44:52 GMT

          From comp.compilers

Related articles
[17 earlier articles]
Re: Debugging of optimized code monnier@di.epfl.ch (Stefan Monnier) (1995-01-27)
Re: Debugging of optimized code jqb@netcom.com (1995-02-02)
Debugging of optimized code ssimmons@convex.convex.com (1995-02-02)
Re: Debugging of optimized code copperma@grenoble.rxrc.xerox.com (1995-01-30)
Re: Debugging of optimized code wicklund@Intellistor.COM (1995-01-30)
Re: Debugging of optimized code copperma@grenoble.rxrc.xerox.com (1995-01-30)
Debugging of optimized code cliffc@hpl.hp.com (1995-02-02)
Re: Debugging of optimized code bill@amber.ssd.csd.harris.com (1995-02-01)
Re: Debugging of optimized code monnier@di.epfl.ch (Stefan Monnier) (1995-02-03)
Re: Debugging of optimized code ali@N2.SP.CS.CMU.EDU (Ali-Reza Adl-Tabatabai) (1995-02-03)
Re: Debugging of optimized code bill@amber.ssd.csd.harris.com (1995-02-05)
| List of all articles for this month |

Newsgroups: comp.compilers
From: cliffc@hpl.hp.com (Cliff Click)
Keywords: debug, optimize
Organization: Compilers Central
References: 95-01-036 95-01-101
Date: Thu, 2 Feb 1995 06:44:52 GMT

Ok, how about this for debugging optimized code:


The compiler-user selects the granularity of debugging, statement, line,
block, function, etc.


The compiler inserts a conditional call to the debugger at every
specified point. The debugger call reads & sets every variable.
The compiler knows the condition is VERY unlikely to be taken (but
not zero chance). The conditional's predicate is treated as magic
unknown value (if you like, it depends on a global volatile variable,
but don't implement it that way! see below).


The compiler optimizes as usual, except that hooks to read & set
every variable are maintained to the conditional debugger calls (just
like ordinary calls). The compiler does some amount of "trace
scheduling" or cloning or inter-block motion or what-have-you, to
move code into conditional part of the debugger call-stubs. The
common path is given preference over the stubs, so that the common
path runs fast BUT if you want to call the debugger, you have to run
some clean-up code to move values to debugger-known locations (and
back again after the debugger is done).


The actual conditional test is converted to an assembler psuedo-op,
and the assembler emits no code for it (but may emit debugging info).
Instead debugging information about that location is kept, so that if
the debugger wants to stop at any particular test, it stuffs a
branch-to-debugger-stub that has been customized (by the normal
behavior of compiler optimizations) for that location.




Example:


Source code, with debug locations shown
    x := 1; // debugger called at end of line 1?
    y := x+2; // debugger called at end of line 2?
        := ...y...


Compiler view, with debug locations made explicit
    x := 1;
    if( break ) x := debug(x);
    y := x+2;
    if( break ) x,y := debug(x,y);
        := ...y...


Compiler view in SSA form, just prior to optimization
    x0 := 1;
    if( break ) x1 := debug(x0);
    x2 := phi(x0,x1);
    y0 := x2+2;
    if( break ) x3,y1 := debug(x2,y0);
    x4 := phi(x2,x3);
    y2 := phi(y0,y1);
          := ...y2...


Compile does a little code motion, a little constant folding.
Moving things into the conditional is OK, because it's very rarely executed.
    x0 := 1
    y3 := 3;
    if( break ) { x1 := debug(1); y4 := x1+2; }
    x2 := phi(x0,x1);
    y0 := phi(y3,y4);
    if( break ) { x3,y1 := debug(x2,y0); }
    x4 := phi(x2,x3);
    y2 := phi(y0,y1);
          := ...y2...


Compiler removes dead code, comes out of SSA form:
    x := 1
    y := 3;
    if( break ) { x := debug(1); y := x+2; }
    if( break ) { y := debug(x,y); }
          := ...y...


Compiler emits assembler; the break test is treated as a conditional
test by the compiler, but the assembler emits no code for it:
    ldi rx <= 1 # Variable X is in register rx
    ldi ry <= 3 # Variable Y is in register ry
    debug line1 # Conditional breakpoint for line1; no code emitted
    debug line2 # Conditional breakpoint for line2; no code emitted
    ... ry ...
    return;
label1:
    breakpoint # Real breakpoint here for debugger
    add ry <= rx,2 # Correct value in register ry, variable y
    rtx # Return from break at end of line 1
                                  # the debugger has to fool around if a break at line 2 occurs
label2:
    breakpoint # Real breakpoint here for debugger
    rtx # Return from break at end of line 2




Comments anyone?
Cliff


Cliff Click HP Laboratories Scientist
Cambridge Research Office, Hewlett-Packard Laboratories
1 Main Street, 10th Floor Cambridge, MA 02142
(617) 225-4915 Work (617) 225-4930 Fax
cliffc@hpl.hp.com WWW http://bellona.cs.rice.edu/MSCP/cliff.html


--


Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.