Write an attribute grammar for Cool expressions and branches that
reg to each
expression/branch that indicates
which register (a number) to compute the result into:
r1, r2, r3, ...; andmaxreg
used in each expression or
branch tree as a synthesized attribute.handle_op.
For example:
loop(cond,body : Expression) cond.reg = reg body.reg = reg maxreg = max(cond.maxreg,body.maxreg) integer_constant(token : Symbol) maxreg = reg // don't need any others beyond thisAssume that let-bound and case-bound variables will be stored in temporary registers just like operands.
The code generated by Figure 9.8 is very poor. In particular it may
spill the same register over and over even when the saved value is not
changing. A better way to do spilling is to use the ``maximum register
needed'' attribute you defined in your attribute grammar, to generate
code that spills an intermediate result at the point it is defined, if
we know we're going to need the register for a subcomputation.
That way, the intermediate value will be spilled and restored only
once.
This improvement can be accomplished through a few changes in
the macro handle_op.
handle_op and explain what you are doing.