private void replaceJoinPhis(final FlowGraph cfg) {
		// Go in trace order since liveness was computed under this
		// assumption.

		final Iterator iter = cfg.trace().iterator();

		while (iter.hasNext()) {
			final Block block = (Block) iter.next();

			if (block == cfg.sink()) {
				continue;
			}

			block.visit(new TreeVisitor() {
				public void visitPhiJoinStmt(final PhiJoinStmt stmt) {
					// If an operand of the Phi statement is undefined, insert
					// code to assign 0 to the operand. The value should never
					// be used, but the verifier will squawk about using an
					// undefined local variable.

					final Iterator preds = cfg.preds(stmt.block()).iterator();

					while (preds.hasNext()) {
						final Block pred = (Block) preds.next();

						final Expr operand = stmt.operandAt(pred);

						if ((stmt.target() instanceof LocalExpr)
								&& (operand instanceof LocalExpr)) {

							final LocalExpr t = (LocalExpr) stmt.target();
							final LocalExpr s = (LocalExpr) operand;

							if (t.index() == s.index()) {
								// The target and the operand are already
								// allocated to
								// the same variable. Don't bother making a
								// copy.
								continue;
							}
						}

						final Tree tree = pred.tree();

						// Insert stores before the last stmt to ensure
						// we don't redefine locals used the the branch stmt.
						final Stmt last = tree.lastStmt();

						last.visitChildren(new TreeVisitor() {
							// The last statement in the block should be a jump.
							// If
							// the jump statement contains an expression,
							// replace
							// that expression with a stack variable. Before the
							// jump, insert a store of the expression into the
							// stack
							// variable. This is done so that the store to the
							// PhiJoinStmt's operand does not interfere with any
							// local variables that might appear in the
							// expression.
							//
							// operand = ...
							// JUMP (exp)
							// |
							// v
							// target = PhiJoin(operand)
							// ...
							// Becomes
							//
							// operand = ...
							// var = exp
							// target = operand
							// JUMP (var)
							// |
							// v
							// target = PhiJoin(operand) // Removed later
							// ...

							public void visitExpr(final Expr expr) {
								StackExpr var = tree.newStack(expr.type());
								var.setValueNumber(expr.valueNumber());

								final Node p = expr.parent();
								expr.setParent(null);
								p.visit(new ReplaceVisitor(expr, var));

								var = (StackExpr) var.clone();
								final StoreExpr store = new StoreExpr(var,
										expr, expr.type());
								store.setValueNumber(expr.valueNumber());

								final Stmt storeStmt = new ExprStmt(store);
								storeStmt.setValueNumber(expr.valueNumber());

								tree.addStmtBeforeJump(storeStmt);
							}

							public void visitStackExpr(final StackExpr expr) {
							}
						});

						final Stmt store = createStore(stmt.target(), operand);

						if (CodeGenerator.DEBUG) {
							System.out.println("insert for " + stmt + " "
									+ store + " in " + pred);
						}

						tree.addStmtBeforeJump(store);
					}
				}

				public void visitStmt(final Stmt stmt) {
				}
			});
		}
	}