public void simplifyControlFlow(final FlowGraph cfg) {
		// Remove any blocks from the CFG that consist of solely jumps
		removeEmptyBlocks(cfg);

		cfg.visit(new TreeVisitor() {
			public void visitJsrStmt(final JsrStmt stmt) {
				final Subroutine sub = stmt.sub();

				// If there is only 1 path through the sub, replace both
				// the jsr and the ret with gotos.
				if (sub.numPaths() == 1) {
					final Block exit = sub.exit();

					// Remember that it is not required for a subroutine to have
					// a ret. So, no exit block may be identified and we'll
					// have to make sure one exists.
					if (exit != null) {
						final JumpStmt oldJump = (JumpStmt) exit.tree()
								.lastStmt();
						final JumpStmt jump = new GotoStmt(stmt.follow());
						jump.catchTargets().addAll(oldJump.catchTargets());
						oldJump.replaceWith(jump);
					}

					final JumpStmt jump = new GotoStmt(sub.entry());
					jump.catchTargets().addAll(stmt.catchTargets());
					stmt.replaceWith(jump);

					// The subroutine is no longer really a subroutine
					cfg.removeSub(sub);

					// Clean up the CFG by removing all AddressStoreStmts that
					// store the address of the "removed" subroutine.
					cfg.visit(new TreeVisitor() {
						Iterator iter;

						public void visitTree(final Tree tree) {
							iter = tree.stmts().iterator();

							while (iter.hasNext()) {
								final Stmt s = (Stmt) iter.next();

								if (s instanceof AddressStoreStmt) {
									final AddressStoreStmt store = (AddressStoreStmt) s;

									if (store.sub() == sub) {
										iter.remove();
									}
								}
							}
						}
					});
				}
			}

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