"root" of ChunkPerFunc chunk
Matthew Fluet
Matthew Fluet <fluet@CS.Cornell.EDU>
Thu, 2 Nov 2000 09:38:17 -0500 (EST)
> > I spent
> > some time trying to determine what optimizations could occur "through" an
> > overflow checking primitive, and I decided that there really aren't any,
> > at least that correspond to the optimizations already in the simplifier.)
>
> I'm not quite sure what you mean here. The semantics of a checking primitive
> are to do the arithmetic op and to jump to the label immediately if there was an
> overflow. So, in the case of overflow, any side effects before the primitive
> must happen and any after must not happen.
Basically, I was trying to decide if any of the existing peephole
optimizations could be used with a checking prim. Briefly, I considered
translating without spliting the basic blocks; instead, just have a jo
instruction in the middle of the block. The advantage was larger basic
blocks. Also, something like copy propagation (I'm only propagating moves
of the form movl X, PseudoReg , so there isn't any problem with a
side-effect not occuring) could proceed "through" the check. However,
copy propagation doesn't occur between blocks, so the current translation
of checks prevent it. (But, see my notes on the running times below.)
> > So, it would seem I need a better ordering for the processing of blocks.
> > Topological sort would seem to do the trick, but I need one (or more)
> > roots. And, after writing all this, I realized I do in fact have those
> > roots: they are the labels in the exports field of a Chunk.
Using the exports list did the trick. Processing the blocks is now done
with a queue. Initally, all the export labels are in the queue. After
processing a block, the targets of any conditional jumps are added to the
queue. An inability to fall-through to another block might also enqueue
a target. Now the output is exactly as I expected: you never see a label
corresponding to noOverflow and you never see spilling to the temporary.
> Note, you talked about simplifying multiplies by -1, but these can
> still overflow.
Yes, they would be processed like Int_sub(0, X): turned into an Int_neg,
but leave the overflow check
> Did you do any runs to see how much the checking is costing?
Here are the results from the benchmarks I ran last night:
default detectOverflow default/detectOverflow
barnes-hut 15.27 X X
checksum 10.36 13.62 0.76
count-graphs 14.41 15.07 0.95
fft 73.79 72.48 1.02
fib 12.37 12.90 0.96
knuth-bendix 22.83 22.86 1.00
lexgen 40.61 40.11 1.01
life 75.49 80.20 0.94
logic 79.52 79.23 1.00
mandelbrot 20.31 24.76 0.82
matrix-multiply 14.44 13.00 1.11
merge 233.28 233.13 1.00
mpuz 50.79 48.26 1.05
nucleic 26.92 26.87 1.00
ratio-regions 27.04 27.65 0.98
simple 15.06 14.91 1.01
smith-normal-form 3.34 3.34 1.00
tak 30.84 31.94 0.97
tensor 14.91 X X
tsp 36.25 X X
vliw 23.04 X X
wc 6.34 8.34 0.76
zern 13.49 X X
Benchmarks with X in detectOverflow had a compile error. The problem was
that I was always assuming a destination for a checking prim; but, in
these cases I guess the destination was useless-ed away, but the overflow
check couldn't be eliminated. It was a really simple fix. But a good
reminder that some slowdown will arise not just from the actual
conditional jump, but also from CPS simplifications that couldn't happen
in the presence of the overflow check.
But, overall, the penalty doesn't seem to be that high. checksum and
wc are a little disappointing, but everything else seems fine. mandelbrot
is a little strange -- I really would have thought that the floating-point
computation would totally dominate that benchmark, but apparently counting
those iterations is costing a little.
The explaination for the cases where detectOverflow does better than the
default would appear to be related to the copyPropagation and moveHoist
optimizations. All of the control flow with overflow checking breaks up
the blocks, so these optimizations don't have as much to work with. mpuz
is a good example, because I know that it does better with copyPropagation
off than with it on. The moral of the story being that I need to think
more about those optimizations, and if I can figure out what's really
going on, maybe get it to the point where the default is always better
than detectOverflow.