Chapter 8
|
RESOURCES
Download Chapters 7 and 8 software
Test package contains test.java that can be used to test your understanding of Chapter 7 and 8. The file contains an example of:
- generating an IR tree (Chapter 7)
- rewriting an IR tree to a canonical tree (Chapter 8)
- linearization to canonical tree to statement list (Chapter 8)
- forming basic blocks (Chapter 8)
- traces (Chapter 8)
The file can be edited to verify your understanding of the input and results of each phase.
Directions:
- Unzip to directory: Chap8
- At command prompt, change to Chap8 directory.
- Compile by: javac -classpath . Test\test.java
- Execute by: java -cp . Test.test
OVERVIEW
IR trees must eventually be translated into assembly or machine code. IR does not correspond precisely to any architecture's assembly language so translation problems are to be expected and some IR interferes with optimization.
Two types of IR nodes and some examples of translation difficulties:
Exp ESEQ(s, e) - Statement s is evaluated with possible side-effects then e is evaluated for results.
CALL(f,l) - Applies function f to argument list l.
Stm
SEQ( s1, s2 ) - Statement s1 followed by statement s2 where s1 and s2 are branches on the IR tree.
CJUMP( o, e1, e2, t, f ) - Compare evaluation of e1 and e2 using relation operator o; if result is true jump to address t else jump to address f.
SEQ
/ \
SEQ LABEL(F)
/ \
SEQ SEQ
/ \ / \
LABEL(while) CJUMP LABEL(T) SEQ
/ \
MOVE JUMP(while)
Some Mismatches
Following are useful in building trees of parent and child nodes but cause problems when translating to linear assembly code.
- CJUMP has 2 branches where most assembly has only 1
- ESEQ nodes in an expression (e.g. (a=4) < a+2) produce different results depending on the order of sub-tree code generation.
ESEQ( s, e ) = ESEQ( s, (a=4) < a + 2)
- CALL nodes in an expression have same problem with arguments:
call f( ++a - 2, a-2)
call f
/ \
++a-2 a-2- CALL nodes as arguments to other CALL nodes when putting arguments into a fixed-set of formal-parameters:
call f1(call f2(a), call f3(b) )
Remember that a nested call generates assembly code not the result of the evaluation. Functions can produce side-effects so that order code executed determines order of side-effects produced.
Transform tree to list
+
/ \
* - linearization to RPN: a b * c d -
/ \ / \
a b c d
Canon: Translation of tree to linear list package. Three stages:
- rewrite tree into a list of canonical trees without SEQ or ESEQ nodes.
- group list into set of basic blocks with no internal jumps or labels.
- order basic blocks into set of traces in which every CJUMP is followed by its false label.
package Canon;
public class Canon{
static public Tree.StmList linearize(Tree.Stm s) // removes ESEQs and move CALLs to top level
}
public class BasicBlocks { // groups statements into sequences of straightline code
public StmListList blocks;
public Temp.Label done;
public BasicBlocks(Tree.StmList stms)
}
public class StmListList {
public Tree.StmList head;
public StmListList tail;
public StmListList(Tree.StmList h, StmListList t) {head=h; tail=t;}
}
public class TraceSchedule { // orders blocks so every CJUMP followed by its false label
public Tree.StmList stms;
BasicBlocks theBlocks;
public TraceSchedule(BasicBlocks b)
}
Exercise - Why are the three operations on IR trees important to code production?
Example - The following is a simplified example of the AST to IR translation and linearized results; note that the AST node is not used so that the details of the if statment could be more simply presented.
The following is the template for translating AST to IR tree. The Ex expression and Nx statement objects of the if statement are translated by the unEx() and unNx() methods.
AST to IR AIfStatement IR tree Linearized public Stm caseAIfStatement( AIfStatement node ) {
Label T = new Label("T");
Label F = new Label("F");
Label D = new Label("D");
Ex exp = new Ex(CONST(0));
Nx stmT = new Nx(MOVE(TEMP(new Temp(1)), CONST(1)));
Nx stmF = new Nx(MOVE(TEMP(new Temp(3)), CONST(3)));
return
SEQ(
SEQ(
SEQ(
SEQ(
CJUMP(CJUMP.EQ, exp.unEx(), CONST(1),T,F),
SEQ(
LABEL(T),
stmT.unNx()
)
),
JUMP(D)
),
SEQ(
LABEL(F),
stmF.unNx()
)
),
LABEL(D)
);
}SEQ(
SEQ(
SEQ(
SEQ(
CJUMP(EQ,
CONST 0,
CONST 1,
T,F),
SEQ(
LABEL T,
MOVE(
TEMP t1,
CONST 1)
)
),
JUMP(NAME D)
),
SEQ(
LABEL F,
MOVE(
TEMP t3,
CONST 3)
)
),
LABEL D
)CJUMP(EQ,
CONST 0,
CONST 1,
T,F)
LABEL T
MOVE(
TEMP t1,
CONST 1)
JUMP(NAME D)
LABEL F
MOVE(
TEMP t3,
CONST 3)
LABEL D
8.1 CANONICAL TREES
- have no SEQ or ESEQ
- parent of each CALL is either EXP(...) or MOVE(TEMP t, ... )
TRANSFORMATIONS ON ESEQ
Remove ESEQs because make different orders of evaluating subtrees yield different result.
- Exp - result
ESEQ(s, e) - Statement s is evaluated with possible side-effects then e is evaluated for results.
- Stm - side-effects
SEQ( s1, s2 ) - Statement s1 followed by statement s2
|
![]() |
Example - Rewriting using identities moves ESEQ to top of IR tree.
Before After Linearized BINOP(
PLUS,
CONST(1),
ESEQ(
MOVE(
TEMP(t2),
CONST(2)
),
TEMP(t2)
)
)ESEQ(
MOVE(
TEMP (t1),
CONST(1)
),
ESEQ(
MOVE(
TEMP (t2),
CONST(2)
),
BINOP(
PLUS,
TEMP(t1),
TEMP(t2)
)
)
)MOVE(
TEMP t2,
CONST 1
)
MOVE(
TEMP t3,
CONST 2
)
BINOP(
PLUS,
TEMP t2,
TEMP t3
)
Example - One goal of rewriting is to eliminate ESEQ but preserve the results.
Before After MOVE(
TEMP t0,
ESEQ(
MOVE(
TEMP t0,
CONST 4
),
CONST 3
)
)MOVE(
TEMP t0,
CONST 4
)
MOVE(
TEMP t0,
CONST 3
)
GENERAL REWRITING RULES
Three possible rewrites of the expressions to remove ESEQ by moving s to left of e1 and e2:
[e1, e2, ESEQ( s, e3 )]
- e1 and e2 commute, not affected by side-effects of s: (s; [e1, e2, e3])
- e2 does not commute: SEQ( MOVE(t1, e1), SEQ(MOVE( t2, e2), s)); (s; [TEMP(t1), TEMP(t2), e3])
- e2 does but e1 does not commute: SEQ( MOVE(t1, e1), s); (s; [TEMP(t1), e2, e3])
Exercise - Do both e1 and e2 need to be in TEMPs in case 2?
reorder function takes a list of expressions and returns (statement, expression-list) as illustrated in Figure 8.1 of the text.
- statement contains things to execute before expression-list,
- includes statement parts of ESEQ and any expressions to left of ESEQ that do not commute
- statement EXP(CONST(0)) when no ESEQs
The reorder method code illustrates:
- making all CALLs child nodes by adding ESEQ with MOVE of CALL to a TEMP
- the reordering (moving to the left) by placing ESEQ at head of expression list by:
- directly moving commutable statements to left of expressions
- computing TEMP for non-commutable expressions to left of statements
static StmExpList reorder(ExpList exps) { // Remove ESEQs
if (exps==null) return nopNull;
else {
Exp a = exps.head;
if (a instanceof CALL) { // parent of each CALL is either EXP(...) or MOVE(TEMP t, ... )
Temp.Temp t = new Temp.Temp();
Exp e = ESEQ(MOVE( TEMP(t), a), TEMP(t));
return reorder(new ExpList(e, exps.tail));
} else {
ESEQ aa = do_exp(a); // translate expression a into ESEQ( s, e )
StmExpList bb = reorder(exps.tail);
if (commute(bb.stm, aa.exp)) // Stms on left, expressions on right
return new StmExpList( SEQ(aa.stm, bb.stm), new ExpList(aa.exp, bb.exps));
else {
Temp.Temp t = new Temp.Temp();
return new StmExpList(
SEQ(aa.stm,
SEQ(MOVE(TEMP(t), aa.exp), bb.stm)),
new ExpList(TEMP(t), bb.exps));
}
}
}
}
Algorithm
Each Tree kind will require:
- kids - sub-expression extraction method to pull each type of expression apart for reordering
- build - sub-expression insertion method to put the reordered expression back together
The basic idea of two above methods is to pull ESEQs out from right-to-left using and insert the reordering to the left
Each Exp or Stm subclass must implement kids and build. Some examples:
| package Tree; abstract public class Exp { abstract public ExpList kids(); abstract public Exp build(ExpList kids); } |
package Tree; abstract public class Stm { abstract public ExpList kids(); abstract public Stm build(ExpList kids); } |
| public class BINOP extends Exp { public int binop; public Exp left, right; public BINOP(int b, Exp l, Exp r) { binop=b; left=l; right=r; } public final static int PLUS=0, MINUS=1, MUL=2, DIV=3, AND=4,OR=5,LSHIFT=6,RSHIFT=7, ARSHIFT=8,XOR=9; public ExpList kids() {return new ExpList(left, new ExpList(right,null));} public Exp build(ExpList kids) { return new BINOP(binop, kids.head, kids.tail.head); } } |
public class CONST extends Exp { public int value; public CONST(int v) {value=v;} public ExpList kids() {return null;} public Exp build(ExpList kids) {return this;} |
| public class CALL extends Exp { public Exp func; public ExpList args; public CALL(Exp f, ExpList a) {func=f; args=a;} public ExpList kids() {return new ExpList(func,args);} public Exp build(ExpList kids) { return new CALL(kids.head, kids.tail); } |
public class MOVE extends Stm { public Exp dst, src; public MOVE(Exp d, Exp s) { dst=d; src=s; } public ExpList kids() { if (dst instanceof MEM) return new ExpList(((MEM)dst).exp, new ExpList(src,null)); else return new ExpList(src,null); } public Stm build(ExpList kids) { if (dst instanceof MEM) return new MOVE(new MEM(kids.head), kids.tail.head); else return new MOVE(dst, kids.head); } |
| public class ESEQ extends Exp { public Stm stm; public Exp exp; public ESEQ(Stm s, Exp e) {stm=s; exp=e;} public ExpList kids() { throw new Error("kids() not applicable to ESEQ"); } public Exp build(ExpList kids) { throw new Error("build() not applicable to ESEQ"); } |
MOVE must determine whether left-hand side (destination) is MEM, which then acts as a source. (see bottom p. 167)
Note that an ExpList is a list of expressions with an Exp head and ExpList tail.
package Tree;
public class ExpList {
public Exp head;
public ExpList tail;
public ExpList(Exp h, ExpList t) {head=h; tail=t;}
}ExpList a = new ExpList(CONST(1),null); ExpList b = new ExpList(CONST(2), a );
b = [CONST(2), [CONST(1), null] ]
Example
public class BINOP extends Exp {
public int binop;
public Exp left, right;
public BINOP(int b, Exp l, Exp r) { binop=b; left=l; right=r; }
public final static int PLUS=0, MINUS=1, MUL=2, DIV=3,
AND=4,OR=5,LSHIFT=6,RSHIFT=7,
ARSHIFT=8,XOR=9;
public ExpList kids() {
return new ExpList(left, new ExpList(right,null));
}
public Exp build(ExpList kids) {
return new BINOP(binop, kids.head, kids.tail.head);
}
}BINOP e = BINOP( PLUS, e1, e2 )
- binop = PLUS
- left = e1
- right = e2
e.kids() returns
- el = ExpList(e1, new ExpList(e2, null))
e.build( el ) returns
- BINOP( PLUS, e1, e2 )
MOVING CALLS TO TOP LEVEL
Because all calls return result in TEMP(RV) register and CALL nodes can be sub-expressions:
BINOP( PLUS, CALL(...), CALL(...) )
the first call overwrites the second. We saw that on the 386 the intermediate result could be saved by pushing, however the IR has no PUSHs and POPs, only TEMPs. Rewriting:
BINOP( PLUS, ESEQ( MOVE(TEMP(tnew), CALL(...)), TEMP(tnew)), CALL(...) )
reorder replaces each CALL(...) not preceded by a MOVE by:
ESEQ( MOVE(TEMP(tnew), CALL(...)), TEMP(tnew) )
where TEMP(tnew) holds the result of the CALL expression.
A LINEAR LIST OF STATEMENTS
The result of processing the IR is a tree with SEQs near the root, never under another type of node.
linearize method repeatedly applies the rule:
SEQ( SEQ( a, b ), c ) = SEQ( a, SEQ( b, c ) )
to convert a tree into a linearized expression of the form:
SEQ( s1, SEQ( s2, SEQ ( s3, ..., SEQ(sn-1, sn)...))
which is equivalent to a list of statements without ESEQ or SEQ:
s1, s2, s3, ..., sn-1, sn
Rewrite SEQ rule is implemented below:
static Tree.StmList linear(Tree.SEQ s, Tree.StmList l) {
return linear(s.left,linear(s.right,l));
}
static Tree.StmList linear(Tree.Stm s, Tree.StmList l) {
if (s instanceof Tree.SEQ) return linear((Tree.SEQ)s, l);
else return new Tree.StmList(s,l);
}
static public Tree.StmList linearize(Tree.Stm s) {
return linear(do_stm(s), null);
}Example - The following is a simplified example of the AST to IR translation and linearized results; note that the AST node is not used so that the details of the if statement could be more simply presented.
The following is the template for translating AST to IR tree. The Ex expression and Nx statement objects of the if statement are translated by the unEx() and unNx() methods
AST to IR AIfStatement IR tree Linearized public Stm caseAIfStatement( AIfStatement node ) {
Label T = new Label("T");
Label F = new Label("F");
Label D = new Label("D");
Ex exp = new Ex(CONST(0));
Nx stmT = new Nx(MOVE(TEMP(new Temp(1)), CONST(1)));
Nx stmF = new Nx(MOVE(TEMP(new Temp(3)), CONST(3)));
return
SEQ(
SEQ(
SEQ(
SEQ(
CJUMP(CJUMP.EQ, exp.unEx(), CONST(1),T,F),
SEQ(
LABEL(T),
stmT.unNx()
)
),
JUMP(D)
),
SEQ(
LABEL(F),
stmF.unNx()
)
),
LABEL(D)
);
}SEQ(
SEQ(
SEQ(
SEQ(
CJUMP(EQ,
CONST 0,
CONST 1,
T,F),
SEQ(
LABEL T,
MOVE(
TEMP t1,
CONST 1)
)
),
JUMP(NAME D)
),
SEQ(
LABEL F,
MOVE(
TEMP t3,
CONST 3)
)
),
LABEL D
)CJUMP(EQ,
CONST 0,
CONST 1,
T,F)
LABEL T
MOVE(
TEMP t1,
CONST 1)
JUMP(NAME D)
LABEL F
MOVE(
TEMP t3,
CONST 3)
LABEL D
8.2 TAMING CONDITIONAL BRANCHES - ANALYZING THE CONTROL FLOW
CJUMP is a two-way branch, convenient for translating into trees but most machines have only single-branch, branching on true or falling through to the next instruction.
For more direct translation to machine code, CJUMP's will be arranged so that each is followed immediately by the false branch. Recall that the CJUMP is defined as:
CJUMP( condition, e1, e2, T, F )
Consider the following while pseudo-code:
while( e1 <= e2) do
statement(s)
endwhileThere are a number of possible implementations; the following all compute the same result but the two at right have the false immediately following the CJUMP, more easily translated into machine code:
LABEL( while )
CJUMP (<=, e1, e2, do, endwhile)
LABEL( do )
statement(s)
JUMP( while )
LABEL(endwhile)
LABEL( while )
CJUMP (<=, e1, e2, do, endwhile)
LABEL( endwhile )
JUMP( end )
LABEL( do )
statement(s)
JUMP( while )LABEL( end )
LABEL( while )
CJUMP (>, e1, e2, endwhile, do)
LABEL( do )
statement(s)
JUMP( while )LABEL( endwhile )
Rewrite
The rearrangement of each CJUMP( condition, T, F ) can then be directly implemented on a machine as a conditional branch to T.
Requires:
- forming sequences of statements into groupings called basic blocks,
- ordering basic blocks into flow sequence.
BASIC BLOCKS
Basic blocks are statement sequences that are always entered at the beginning and exited at the end:
- LABEL is the first statement
- JUMP or CJUMP is the last statement
- No other LABELs, JUMPs or CJUMPs
The idea behind rewriting as basic blocks is that blocks can be rearranged without changing execution result. The purpose of the rearrangement is to rewrite a general two-branch CJUMP into a one that is always followed by the false branch (i.e. fall through).
Example
IR Linearization Basic Blocks MOVE(
TEMP t0,
ESEQ(
MOVE(
TEMP t0,
CONST 4
),
CONST 3
)
)MOVE(
TEMP t0,
CONST 4
)
MOVE(
TEMP t0,
CONST 3
)LABEL L1
MOVE(
TEMP t0,
CONST 4
)
MOVE(
TEMP t0,
CONST 3
)
JUMP(NAME L0)Exercise - Circle which part, if any of the following are basic blocks. Are execution results the same for the two?
MOVE( e1, e2 )
LABEL( L1 )
BINOP(PLUS, e1, e2)
CJUMP(<, e1, e3, L1, L2)
LABEL( L2 )
MOVE( e1, e2 )
JUMP( L1 )
MOVE( e1, e2 )LABEL( L0 )
MOVE( e1, e2 )
JUMP( L1 )
LABEL( L2 )
MOVE( e1, e2 )
JUMP( L1 )
LABEL( L1 )
BINOP(PLUS, e1, e2)
CJUMP(<, e1, e3, L1, L2)
MOVE( e1, e2 )
Algorithm for Basic Blocks
Keep in mind that:
- LABEL is the first statement
- JUMP or CJUMP is the last statement
- No other LABELs, JUMPs or CJUMPs
Scan each method-body sequence of statements, when:
- No LABEL at beginning, create one
- LABEL is found:
- end the current block
- if current block does not end with JUMP or CJUMP the add a JUMP to LABEL
- start a new block with LABEL
- JUMP or CJUMP is found:
- end the current block with the JUMP or CJUMP
- start a new block
- if new block does not start with a LABEL, create one for the start
Translation - The general approach can be seen by example, the following left-hand side is transformed to the right-hand side:
MOVE(
TEMP t0,
CONST 4
)LABEL L1
MOVE(
TEMP t0,
CONST 4)
JUMP(
NAME L0)JUMP(
NAME L0)
MOVE(
TEMP t0,
CONST 4)
LABEL L0LABEL L2
JUMP(
NAME L0)
LABEL L3
MOVE(
TEMP t0,
CONST 4)
JUMP(
NAME L0)
LABEL L0
JUMP(
NAME L1)LABEL L0
MOVE(
TEMP t0,
CONST 4)
JUMP(
NAME L0)LABEL L0
MOVE(
TEMP t0,
CONST 4)
JUMP(
NAME L0)LABEL L0
MOVE(
TEMP t1,
CONST 4)
CJUMP(LT,
TEMP t0,
CONST 4,
L1,L2)
JUMP(
NAME L0)LABEL L0
MOVE(
TEMP t1,
CONST 4)
CJUMP(LT,
TEMP t0,
CONST 4,
L1,L2)
LABEL L4
JUMP(
NAME L0)Exercise - Apply the basic blocks algorithm to the following sequences:
MOVE( e1, e2 )
LABEL( L1 )
BINOP(PLUS, e1, e2)
CJUMP(<, e1, e3, L1, L2)
LABEL( L2 )
MOVE( e1, e2 )
JUMP( L1 )
MOVE( e1, e2 )LABEL( L0 )
MOVE( e1, e2 )
JUMP( L1 )
LABEL( L2 )
MOVE( e1, e2 )
JUMP( L1 )
LABEL( L1 )
BINOP(PLUS, e1, e2)
CJUMP(<, e1, e3, L1, L2)
MOVE( e1, e2 )
Scan each method-body sequence of statements, when:
- No LABEL at beginning, create one
- LABEL is found:
- end the current block
- if current block does not end with JUMP or CJUMP the add a JUMP to LABEL
- start a new block with LABEL
- JUMP or CJUMP is found:
- end the current block with the JUMP or CJUMP
- start a new block
- if new block does not start with a LABEL, create one for the start
BasicBlocks.Java
package Canon;
public class BasicBlocks {
public StmListList blocks;
public Temp.Label done;
private StmListList lastBlock;
private Tree.StmList lastStm;
public BasicBlocks(Tree.StmList stms) {
done = new Temp.Label();
mkBlocks(stms);
}
void mkBlocks(Tree.StmList l) {
if (l==null) return;
else if (l.head instanceof LABEL) { // Already has LABEL
lastStm = new Tree.StmList(l.head,null);
if (lastBlock==null)
lastBlock= blocks= new StmListList(lastStm,null);
else
lastBlock = lastBlock.tail = new StmListList(lastStm,null);
doStms(l.tail);
} // No LABEL at start, insert LABEL
else mkBlocks(new Tree.StmList( LABEL(new Temp.Label()), l));
}
}private void doStms(Tree.StmList l) {
if (l==null) // if none at end of block add JUMP
doStms(new Tree.StmList( JUMP(done), null));
else if (l.head instanceof JUMP || l.head instanceof CJUMP) {
addStm(l.head); // head is a JUMP or CJUMP
mkBlocks(l.tail); // followed by LABEL block JUMP
}
else if (l.head instanceof LABEL)
doStms(new Tree.StmList( JUMP(((LABEL)l.head).label), l));
else {
addStm(l.head);
doStms(l.tail);
}
}private void addStm(Tree.Stm s) {
lastStm = lastStm.tail = new Tree.StmList(s,null);
}
}package Tree;
public class StmList {
public Stm head;
public StmList tail;
public StmList(Stm h, StmList t) {head=h; tail=t;}
}package Canon;
public class StmListList {
public Tree.StmList head;
public StmListList tail;
public StmListList(Tree.StmList h, StmListList t) {head=h; tail=t;}
}
TRACES
A trace is a sequence of statements that could be consecutively executed during the execution of the program.
The purpose of the trace phase is rearrange CJUMPS so that all are immediately followed by their false branch; allowing for conversion into single conditional branch machine code.
Original Basic Blocks Trace LABEL WHILE
MOVE(TEMP t0, CONST 4)
CJUMP(LT, TEMP t1, CONST 4,T,F)
LABEL T
JUMP(NAME WHILE)
LABEL FLABEL WHILE
MOVE(TEMP t0, CONST 4)
CJUMP(LT, TEMP t1, CONST 4,T,F)
LABEL T
JUMP(NAME WHILE)
LABEL F
JUMP(NAME L1)LABEL WHILE
MOVE(TEMP t0, CONST 4)
CJUMP(LT,TEMP t1,CONST 4,T,F)
LABEL F
JUMP(NAME L1)
LABEL T
JUMP(NAME WHILE)
LABEL L1LABEL b1
MOVE(TEMP t0,CONST 0)
JUMP(NAME b4)
LABEL b6
MOVE(TEMP t1,CONST 1)
LABEL b4
MOVE(TEMP t2,CONST 2)
JUMP(NAME b6)LABEL b1
MOVE(TEMP t0,CONST 0)
JUMP(NAME b4)
LABEL b6
MOVE(TEMP t1,CONST 1)
JUMP(NAME b4)
LABEL b4
MOVE(TEMP t2,CONST 2)
JUMP(NAME b6)LABEL b1
MOVE(TEMP t0,CONST 0)
LABEL b4
MOVE(TEMP t2,CONST 2)
LABEL b6
MOVE(TEMP t1,CONST 1)
JUMP(NAME b4)
LABEL L0LABEL b1
MOVE(TEMP t0,CONST 0)
JUMP(NAME b4)
LABEL b6
MOVE(TEMP t1,CONST 1)
LABEL b4
MOVE(TEMP t2,CONST 2)
CJUMP(LT,TEMP t10,CONST 10,b7,b3)
LABEL b7
MOVE(TEMP t7,CONST 7)
LABEL b3
MOVE(TEMP t3,CONST 3)LABEL b1
MOVE(TEMP t0,CONST 0)
JUMP(NAME b4)
LABEL b6
MOVE(TEMP t1,CONST 1)
JUMP(NAME b4)
LABEL b4
MOVE(TEMP t2,CONST 2)
CJUMP(LT,TEMP t10,CONST 10,b7,b3)
LABEL b7
MOVE(TEMP t7,CONST 7)
JUMP(NAME b3)
LABEL b3
MOVE(TEMP t3,CONST 3)
JUMP(NAME L0)LABEL b1
MOVE(TEMP t0,CONST 0)
LABEL b4
MOVE(TEMP t2,CONST 2)
CJUMP(LT,TEMP t10,CONST 10,b7,b3)
LABEL b3
MOVE(TEMP t3,CONST 3)
JUMP(NAME L0)
LABEL b6
MOVE(TEMP t1,CONST 1)
JUMP(NAME b4)
LABEL b7
MOVE(TEMP t7,CONST 7)
JUMP(NAME b3)
LABEL L0Exercise - Comment on the effect of the basic block and the trace applications to each row above.
Exercise - The following illustrates three traces that produce the same results; which is the more efficient? Why?
| LABEL test CJUMP(GT,TEMP t10,CONST 10,body,done) LABEL body MOVE(TEMP t7,CONST 7) JUMP(NAME test) LABEL done MOVE(TEMP t9,CONST 9) |
LABEL test CJUMP(GT,TEMP t10,CONST 10,body,done) LABEL body MOVE(TEMP t7,CONST 7) JUMP(NAME test) LABEL done MOVE(TEMP t9,CONST 9) JUMP(NAME L0) |
LABEL test CJUMP(GT,TEMP t10,CONST 10,body,done) LABEL done MOVE(TEMP t9,CONST 9) JUMP(NAME L0) LABEL body MOVE(TEMP t7,CONST 7) JUMP(NAME test) LABEL L0 |
Exercise - The following illustrates three traces that produce the same results; which is the more efficient? Why?
LABEL(test)
CJUMP (>, e1, e2, done, body)
LABEL(body)
statement(s)
JUMP( test )
LABEL(done)
statement(s)LABEL( test )
CJUMP (<=, e1, e2, body, done)
LABEL(done)
statement(s)
JUMP( join )
LABEL(body)
statement(s)
JUMP( test )LABEL( join )
JUMP( test ) LABEL(body)
statement(s)LABEL( test )
CJUMP (<=, e1, e2, body, done)LABEL(done)
statement(s)TraceSchedule.java
package Canon;
public class TraceSchedule {
public Tree.StmList stms;
BasicBlocks theBlocks;
java.util.Dictionary table = new java.util.Hashtable();
Tree.StmList getLast(Tree.StmList block) {
Tree.StmList l=block;
while (l.tail.tail!=null) l=l.tail;
return l;
}
void trace(Tree.StmList l) {
for(;;) {
Tree.LABEL lab = (Tree.LABEL)l.head;
table.remove(lab.label);
Tree.StmList last = getLast(l);
Tree.Stm s = last.tail.head;
if (s instanceof Tree.JUMP) {
Tree.JUMP j = (Tree.JUMP)s;
Tree.StmList target = (Tree.StmList)table.get(j.targets.head);
if (j.targets.tail==null && target!=null) {
last.tail=target;
l=target;
}
else {
last.tail.tail=getNext();
return;
}
}
else
if (s instanceof Tree.CJUMP) {
Tree.CJUMP j = (Tree.CJUMP)s;
Tree.StmList t = (Tree.StmList)table.get(j.iftrue);
Tree.StmList f = (Tree.StmList)table.get(j.iffalse);
if (f!=null) {
last.tail.tail=f;
l=f;
}
else
if (t!=null) {
last.tail.head=new Tree.CJUMP(Tree.CJUMP.notRel(j.relop), j.left,j.right, j.iffalse,j.iftrue);
last.tail.tail=t;
l=t;
}
else {
Temp.Label ff = new Temp.Label();
last.tail.head=new Tree.CJUMP(j.relop,j.left,j.right, j.iftrue,ff);
last.tail.tail=new Tree.StmList(new Tree.LABEL(ff),
new Tree.StmList(new Tree.JUMP(j.iffalse),
getNext()));
return;
}
}
else throw new Error("Bad basic block in TraceSchedule");
}
}
Tree.StmList getNext() {
if (theBlocks.blocks==null)
return new Tree.StmList(new Tree.LABEL(theBlocks.done), null);
else {
Tree.StmList s = theBlocks.blocks.head;
Tree.LABEL lab = (Tree.LABEL)s.head;
if (table.get(lab.label) != null) {
trace(s);
return s;
}
else {
theBlocks.blocks = theBlocks.blocks.tail;
return getNext();
}
}
}
public TraceSchedule(BasicBlocks b) {
theBlocks=b;
for(StmListList l = b.blocks; l!=null; l=l.tail)
table.put(((Tree.LABEL)l.head.head).label, l.head);
stms=getNext();
table=null;
}
}