Held Monday, April 2, 2001
Summary
Today we begin our serious consideration of the back end. In particular,
we begin our consideration of the techniques used to translate expressions.
Notes
- I hope you had a great break and that you're refreshed and ready
for the remaining weeks of the semester.
- The trip to London went well. I'll give a quick report.
- However, it appears that someone broke into my office during break and
took my Powerbook and DV camera. If you saw anything suspicious,
please report it to me or campus security.
- A candidate for the tree-year temporary CS position is on campus
for the next few days. Please come to his talk at 8pm tonight.
If you're available, please come to CS152 at 11am tomorrow.
Overview
- Notes on translation
- Translating ...
- Assignments
- Basic Operations
- Records and Arrays
- More
- We'll spend a few minutes going over our current "state" in the
translation from source code to assembly code.
- We know how to build the parse tree (and, I think, can successfully
build those parse trees).
- We know how to check the types and build the symbol table for the
parse tree.
- You're currently working on that stage of the project.
- Note that because we've separated the symbol stuff from the translation,
you can think of this as a multi-pass compiler.
- In the good old days, many people worried that doing multiple passes
over the source tree was a bad idea because it used lots of extra
time. Now, many are willing to pay the cost in exchange for more
elegant (and, ocassionally, more powerful) design.
- It is possible to do more than these two passes, but we'll stick with
these two basics passes over the tree and then a few passes over the
resultant code.
- One to deal with register allocation.
- At least one to deal with optimization.
- (Yes, they may be partially combined.)
- Another possibility would be to use some intermediate representations
before going directly to assembly code. Such intermediate representations
make it easier to compile for different architectures (since you worry
less about precise details until those details are necessary).
- We'll use an intermediate representation fairly close to our assembly,
but perhaps with some details left to later.
- Translation is typically done top-down: You translate the subtrees
and then tie them together depending on the overall structure of the
tree.
- At this stage of our translation, we're somewhat free about using
temporary "variables" for partial results. In a pass over the generated
code, we'll eliminate duplicates and unused memory.
- When we translate an expression, we don't just generate code; we also
identify a memory location (most typically, a temporary location) in which
the result of that expression resides.
- We should also know the type of the result.
- We may want to keep track of what kind of memory we're talking about
at every stage:
- register
- "temporary" (created by compiler)
- program variable (local or global)
- procedure parameter
- fixed memory location
- An offset from ...
- ...
- Typical form: var := exp.
- 1. Build the code for the expression.
- 2. Check the types of the expression and the variable.
- a. If they're the same, do nothing.
- b. If they're different, add code to coerce the result of the expression
to the appropriate type. (The result will probably be in a new
temporary.)
- 3. Copy the value from the memory location associated with the result
to the memory location associated with the variable.
- We want to leave the copy fairly generic at this stage, since
the result and the variable can be in memory or registers.
- You may want to think about what it means for the variable and the
expression to be compound types, like arrays or records. What copying
should you then do?
- We'll come back to some of these issues when we deal with procedure
calls.
- Note that you can better handle the coercion by changing the structure
of the parse tree when you do type checking (to insert a "coerce-to-xxx"
node).
- Example: exp + exp
- 1. Translate the first argument, remember the location of the result.
- 2. Translate the second argument, remember the location of the result.
- 3. Call the appropriate operation, putting the result in an appropriate
place.
- Some architectures provide three-argument arithmetic operations in
which you store the result in one of the three arguments.
- Other architectures provide two-argument arithmetic operations in
which the result is stored in one of the two arguments.
- For now, it may be better to pretend you have the three-argument version
and implement it using the two-argument version by a copy and then
assign.
Monday, 22 January 2001
- Created as a blank outline.
Monday, 2 April 2001
Wednesday, 4 April 2001
- Removed uncovered sections, which now appear in the next outline.