comparison graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java @ 2707:7ed72769d51a

exception handling related changes: * changed blockPredecessors to list of Instructions, instead of Blocks * removed explicit predecessor management in BlockBegin, now using predecessors from Graph structure * replaced generated LIR exception entries with exception dispatch chains in IR * added Unwind and ExceptionDispatch instructions * removed ExceptionEntry flag in BlockBegin and all code depending on it * removed exceptionHandler list from Instruction, replaced by exception Edge on Invoke and Throw * replaced list of ExceptionHandlers with single exception edge in debug info misc: * changed GraphvizPrinter layout (smaller ports on large nodes) * removed defunct run config
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 18 May 2011 18:09:20 +0200
parents 6ab73784566a
children 4272b7af2d17
comparison
equal deleted inserted replaced
2677:0ea5f12e873a 2707:7ed72769d51a
26 import static java.lang.reflect.Modifier.*; 26 import static java.lang.reflect.Modifier.*;
27 27
28 import java.util.*; 28 import java.util.*;
29 29
30 import com.sun.c1x.*; 30 import com.sun.c1x.*;
31 import com.sun.c1x.alloc.Interval.*; 31 import com.sun.c1x.alloc.Interval.RegisterBinding;
32 import com.sun.c1x.alloc.Interval.RegisterPriority;
33 import com.sun.c1x.alloc.Interval.SpillState;
32 import com.sun.c1x.debug.*; 34 import com.sun.c1x.debug.*;
33 import com.sun.c1x.gen.*; 35 import com.sun.c1x.gen.*;
34 import com.sun.c1x.graph.*; 36 import com.sun.c1x.graph.*;
35 import com.sun.c1x.ir.*; 37 import com.sun.c1x.ir.*;
36 import com.sun.c1x.ir.BlockBegin.BlockFlag;
37 import com.sun.c1x.lir.*; 38 import com.sun.c1x.lir.*;
38 import com.sun.c1x.lir.LIRInstruction.OperandMode; 39 import com.sun.c1x.lir.LIRInstruction.OperandMode;
39 import com.sun.c1x.observer.*; 40 import com.sun.c1x.observer.*;
40 import com.sun.c1x.util.*; 41 import com.sun.c1x.util.*;
41 import com.sun.c1x.value.*; 42 import com.sun.c1x.value.*;
42 import com.sun.c1x.value.FrameState.PhiProcedure;
43 import com.sun.c1x.value.FrameState.ValueProcedure; 43 import com.sun.c1x.value.FrameState.ValueProcedure;
44 import com.sun.cri.ci.*; 44 import com.sun.cri.ci.*;
45 import com.sun.cri.ri.*; 45 import com.sun.cri.ri.*;
46 46
47 /** 47 /**
596 // iterate all blocks 596 // iterate all blocks
597 for (int i = 0; i < numBlocks; i++) { 597 for (int i = 0; i < numBlocks; i++) {
598 BlockBegin block = blockAt(i); 598 BlockBegin block = blockAt(i);
599 final CiBitMap liveGen = new CiBitMap(liveSize); 599 final CiBitMap liveGen = new CiBitMap(liveSize);
600 final CiBitMap liveKill = new CiBitMap(liveSize); 600 final CiBitMap liveKill = new CiBitMap(liveSize);
601
602 if (block.isExceptionEntry()) {
603 // Phi functions at the begin of an exception handler are
604 // implicitly defined (= killed) at the beginning of the block.
605 block.stateBefore().forEachLivePhi(block, new PhiProcedure() {
606 public boolean doPhi(Phi phi) {
607 liveKill.set(operandNumber(phi.operand()));
608 return true;
609 }
610 });
611 }
612 601
613 List<LIRInstruction> instructions = block.lir().instructionsList(); 602 List<LIRInstruction> instructions = block.lir().instructionsList();
614 int numInst = instructions.size(); 603 int numInst = instructions.size();
615 604
616 // iterate all instructions of the block. skip the first because it is always a label 605 // iterate all instructions of the block. skip the first because it is always a label
771 760
772 changeOccurredInBlock = false; 761 changeOccurredInBlock = false;
773 762
774 // liveOut(block) is the union of liveIn(sux), for successors sux of block 763 // liveOut(block) is the union of liveIn(sux), for successors sux of block
775 int n = block.numberOfSux(); 764 int n = block.numberOfSux();
776 int e = block.numberOfExceptionHandlers(); 765 if (n > 0) {
777 if (n + e > 0) {
778 // block has successors 766 // block has successors
779 if (n > 0) { 767 if (n > 0) {
780 liveOut.setFrom(block.suxAt(0).lirBlock.liveIn); 768 liveOut.setFrom(block.suxAt(0).lirBlock.liveIn);
781 for (int j = 1; j < n; j++) { 769 for (int j = 1; j < n; j++) {
782 liveOut.setUnion(block.suxAt(j).lirBlock.liveIn); 770 liveOut.setUnion(block.suxAt(j).lirBlock.liveIn);
783 } 771 }
784 } else { 772 } else {
785 liveOut.clearAll(); 773 liveOut.clearAll();
786 }
787 for (int j = 0; j < e; j++) {
788 liveOut.setUnion(block.exceptionHandlerAt(j).lirBlock.liveIn);
789 } 774 }
790 775
791 if (!lirBlock.liveOut.isSame(liveOut)) { 776 if (!lirBlock.liveOut.isSame(liveOut)) {
792 // A change occurred. Swap the old and new live out sets to avoid copying. 777 // A change occurred. Swap the old and new live out sets to avoid copying.
793 CiBitMap temp = lirBlock.liveOut; 778 CiBitMap temp = lirBlock.liveOut;
1280 addRegisterHints(op); 1265 addRegisterHints(op);
1281 1266
1282 } // end of instruction iteration 1267 } // end of instruction iteration
1283 1268
1284 // (tw) Make sure that no spill store optimization is applied for phi instructions that flow into exception handlers. 1269 // (tw) Make sure that no spill store optimization is applied for phi instructions that flow into exception handlers.
1285 if (block.isExceptionEntry()) { 1270 // if (block.isExceptionEntry()) {
1286 FrameState stateBefore = block.stateBefore(); 1271 // FrameState stateBefore = block.stateBefore();
1287 stateBefore.forEachLivePhi(block, new PhiProcedure() { 1272 // stateBefore.forEachLivePhi(block, new PhiProcedure() {
1288 @Override 1273 // @Override
1289 public boolean doPhi(Phi phi) { 1274 // public boolean doPhi(Phi phi) {
1290 Interval interval = intervalFor(phi.operand()); 1275 // Interval interval = intervalFor(phi.operand());
1291 if (interval != null) { 1276 // if (interval != null) {
1292 interval.setSpillState(SpillState.NoOptimization); 1277 // interval.setSpillState(SpillState.NoOptimization);
1293 } 1278 // }
1294 return true; 1279 // return true;
1295 } 1280 // }
1296 }); 1281 // });
1297 } 1282 // }
1298 1283
1299 } // end of block iteration 1284 } // end of block iteration
1300 1285
1301 // add the range [0, 1] to all fixed intervals. 1286 // add the range [0, 1] to all fixed intervals.
1302 // the register allocator need not handle unhandled fixed intervals 1287 // the register allocator need not handle unhandled fixed intervals
1594 // because the number of predecessor edges matches the number of 1579 // because the number of predecessor edges matches the number of
1595 // successor edges, blocks which are reached by switch statements 1580 // successor edges, blocks which are reached by switch statements
1596 // may have be more than one predecessor but it will be guaranteed 1581 // may have be more than one predecessor but it will be guaranteed
1597 // that all predecessors will be the same. 1582 // that all predecessors will be the same.
1598 for (int i = 0; i < toBlock.numberOfPreds(); i++) { 1583 for (int i = 0; i < toBlock.numberOfPreds(); i++) {
1599 assert fromBlock == toBlock.predAt(i).begin() : "all critical edges must be broken"; 1584 assert fromBlock == toBlock.predAt(i).block() : "all critical edges must be broken";
1600 } 1585 }
1601 } 1586 }
1602 1587
1603 moveResolver.setInsertPosition(toBlock.lir(), 0); 1588 moveResolver.setInsertPosition(toBlock.lir(), 0);
1604 } 1589 }
1617 int i; 1602 int i;
1618 for (i = 0; i < numBlocks; i++) { 1603 for (i = 0; i < numBlocks; i++) {
1619 BlockBegin block = blockAt(i); 1604 BlockBegin block = blockAt(i);
1620 1605
1621 // check if block has only one predecessor and only one successor 1606 // check if block has only one predecessor and only one successor
1622 if (block.numberOfPreds() == 1 && block.numberOfSux() == 1 && block.numberOfExceptionHandlers() == 0 && !block.isExceptionEntry()) { 1607 if (block.numberOfPreds() == 1 && block.numberOfSux() == 1) {
1623 List<LIRInstruction> instructions = block.lir().instructionsList(); 1608 List<LIRInstruction> instructions = block.lir().instructionsList();
1624 assert instructions.get(0).code == LIROpcode.Label : "block must start with label"; 1609 assert instructions.get(0).code == LIROpcode.Label : "block must start with label";
1625 assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successors must end with branch"; 1610 assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successors must end with branch";
1626 assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block with successor must end with unconditional branch"; 1611 assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block with successor must end with unconditional branch";
1627 1612
1628 // check if block is empty (only label and branch) 1613 // check if block is empty (only label and branch)
1629 if (instructions.size() == 2) { 1614 if (instructions.size() == 2) {
1630 BlockBegin pred = block.predAt(0).begin(); 1615 BlockBegin pred = block.predAt(0).block();
1631 BlockBegin sux = block.suxAt(0); 1616 BlockBegin sux = block.suxAt(0);
1632 1617
1633 // prevent optimization of two consecutive blocks 1618 // prevent optimization of two consecutive blocks
1634 if (!blockCompleted.get(pred.linearScanNumber()) && !blockCompleted.get(sux.linearScanNumber())) { 1619 if (!blockCompleted.get(pred.linearScanNumber()) && !blockCompleted.get(sux.linearScanNumber())) {
1635 if (C1XOptions.TraceLinearScanLevel >= 3) { 1620 if (C1XOptions.TraceLinearScanLevel >= 3) {
1669 if (moveResolver.hasMappings()) { 1654 if (moveResolver.hasMappings()) {
1670 resolveFindInsertPos(fromBlock, toBlock, moveResolver); 1655 resolveFindInsertPos(fromBlock, toBlock, moveResolver);
1671 moveResolver.resolveAndAppendMoves(); 1656 moveResolver.resolveAndAppendMoves();
1672 } 1657 }
1673 } 1658 }
1674 }
1675 }
1676 }
1677 }
1678
1679 void resolveExceptionEntry(BlockBegin block, CiValue operand, MoveResolver moveResolver) {
1680 if (intervalFor(operand) == null) {
1681 // if a phi function is never used, no interval is created . ignore this
1682 return;
1683 }
1684
1685 Interval interval = intervalAtBlockBegin(block, operand);
1686 CiValue location = interval.location();
1687
1688 if (location.isRegister() && interval.alwaysInMemory()) {
1689 // the interval is split to get a short range that is located on the stack
1690 // in the following two cases:
1691 // * the interval started in memory (e.g. method parameter), but is currently in a register
1692 // this is an optimization for exception handling that reduces the number of moves that
1693 // are necessary for resolving the states when an exception uses this exception handler
1694 // * the interval would be on the fpu stack at the begin of the exception handler
1695 // this is not allowed because of the complicated fpu stack handling on Intel
1696
1697 // range that will be spilled to memory
1698 int fromOpId = block.firstLirInstructionId();
1699 int toOpId = fromOpId + 1; // short live range of length 1
1700 assert interval.from() <= fromOpId && interval.to() >= toOpId : "no split allowed between exception entry and first instruction";
1701
1702 if (interval.from() != fromOpId) {
1703 // the part before fromOpId is unchanged
1704 interval = interval.split(fromOpId, this);
1705 interval.assignLocation(location);
1706 }
1707 assert interval.from() == fromOpId : "must be true now";
1708
1709 Interval spilledPart = interval;
1710 if (interval.to() != toOpId) {
1711 // the part after toOpId is unchanged
1712 spilledPart = interval.splitFromStart(toOpId, this);
1713 moveResolver.addMapping(spilledPart, interval);
1714 }
1715 assignSpillSlot(spilledPart);
1716
1717 assert spilledPart.from() == fromOpId && spilledPart.to() == toOpId : "just checking";
1718 }
1719 }
1720
1721 void resolveExceptionEntry(final BlockBegin block, final MoveResolver moveResolver) {
1722 assert block.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry) : "should not call otherwise";
1723 assert moveResolver.checkEmpty();
1724
1725 // visit all registers where the liveIn bit is set
1726 for (int operandNum = block.lirBlock.liveIn.nextSetBit(0); operandNum >= 0; operandNum = block.lirBlock.liveIn.nextSetBit(operandNum + 1)) {
1727 resolveExceptionEntry(block, operands.operandFor(operandNum), moveResolver);
1728 }
1729
1730 // the liveIn bits are not set for phi functions of the xhandler entry, so iterate them separately
1731 block.stateBefore().forEachLivePhi(block, new PhiProcedure() {
1732 public boolean doPhi(Phi phi) {
1733 resolveExceptionEntry(block, phi.operand(), moveResolver);
1734 return true;
1735 }
1736 });
1737
1738 if (moveResolver.hasMappings()) {
1739 // insert moves after first instruction
1740 moveResolver.setInsertPosition(block.lir(), 0);
1741 moveResolver.resolveAndAppendMoves();
1742 }
1743 }
1744
1745 void resolveExceptionEdge(ExceptionHandler handler, int throwingOpId, CiValue operand, Phi phi, MoveResolver moveResolver) {
1746 if (intervalFor(operand) == null) {
1747 // if a phi function is never used, no interval is created . ignore this
1748 return;
1749 }
1750
1751 // the computation of toInterval is equal to resolveCollectMappings,
1752 // but fromInterval is more complicated because of phi functions
1753 BlockBegin toBlock = handler.entryBlock();
1754 Interval toInterval = intervalAtBlockBegin(toBlock, operand);
1755
1756 if (phi != null) {
1757 // phi function of the exception entry block
1758 // no moves are created for this phi function in the LIRGenerator, so the
1759 // interval at the throwing instruction must be searched using the operands
1760 // of the phi function
1761 Value fromValue = phi.inputAt(handler.phiOperand());
1762 Constant con = null;
1763 if (fromValue instanceof Constant) {
1764 con = (Constant) fromValue;
1765 }
1766 if (con != null && (con.operand().isIllegal() || con.operand().isConstant())) {
1767 // unpinned constants may have no register, so add mapping from constant to interval
1768 moveResolver.addMapping(con.asConstant(), toInterval);
1769 } else {
1770 // search split child at the throwing opId
1771 Interval fromInterval = intervalAtOpId(fromValue.operand(), throwingOpId);
1772 if (fromInterval != toInterval) {
1773 moveResolver.addMapping(fromInterval, toInterval);
1774 // with phi functions it can happen that the same fromValue is used in
1775 // multiple mappings, so notify move-resolver that this is allowed
1776 moveResolver.setMultipleReadsAllowed();
1777 }
1778 }
1779 } else {
1780 // no phi function, so use regNum also for fromInterval
1781 // search split child at the throwing opId
1782 Interval fromInterval = intervalAtOpId(operand, throwingOpId);
1783 if (fromInterval != toInterval) {
1784 // optimization to reduce number of moves: when toInterval is on stack and
1785 // the stack slot is known to be always correct, then no move is necessary
1786 if (!fromInterval.alwaysInMemory() || fromInterval.spillSlot() != toInterval.location()) {
1787 moveResolver.addMapping(fromInterval, toInterval);
1788 }
1789 }
1790 }
1791 }
1792
1793 void resolveExceptionEdge(final ExceptionHandler handler, final int throwingOpId, final MoveResolver moveResolver) {
1794 if (C1XOptions.TraceLinearScanLevel >= 4) {
1795 TTY.println("resolving exception handler B%d: throwingOpId=%d", handler.entryBlock().blockID, throwingOpId);
1796 }
1797
1798 assert moveResolver.checkEmpty();
1799 assert handler.lirOpId() == -1 : "already processed this xhandler";
1800 handler.setLirOpId(throwingOpId);
1801 assert handler.entryCode() == null : "code already present";
1802
1803 // visit all registers where the liveIn bit is set
1804 BlockBegin block = handler.entryBlock();
1805 for (int operandNum = block.lirBlock.liveIn.nextSetBit(0); operandNum >= 0; operandNum = block.lirBlock.liveIn.nextSetBit(operandNum + 1)) {
1806 resolveExceptionEdge(handler, throwingOpId, operands.operandFor(operandNum), null, moveResolver);
1807 }
1808
1809 // the liveIn bits are not set for phi functions of the xhandler entry, so iterate them separately
1810 block.stateBefore().forEachLivePhi(block, new PhiProcedure() {
1811 public boolean doPhi(Phi phi) {
1812 resolveExceptionEdge(handler, throwingOpId, phi.operand(), phi, moveResolver);
1813 return true;
1814 }
1815 });
1816
1817 if (moveResolver.hasMappings()) {
1818 LIRList entryCode = new LIRList(gen);
1819 moveResolver.setInsertPosition(entryCode, 0);
1820 moveResolver.resolveAndAppendMoves();
1821
1822 entryCode.jump(handler.entryBlock());
1823 handler.setEntryCode(entryCode);
1824 }
1825 }
1826
1827 void resolveExceptionHandlers() {
1828 MoveResolver moveResolver = new MoveResolver(this);
1829 //LIRVisitState visitor = new LIRVisitState();
1830 int numBlocks = blockCount();
1831
1832 int i;
1833 for (i = 0; i < numBlocks; i++) {
1834 BlockBegin block = blockAt(i);
1835 if (block.checkBlockFlag(BlockFlag.ExceptionEntry)) {
1836 resolveExceptionEntry(block, moveResolver);
1837 }
1838 }
1839
1840 for (i = 0; i < numBlocks; i++) {
1841 BlockBegin block = blockAt(i);
1842 LIRList ops = block.lir();
1843 int numOps = ops.length();
1844
1845 // iterate all instructions of the block. skip the first because it is always a label
1846 assert !ops.at(0).hasOperands() : "first operation must always be a label";
1847 for (int j = 1; j < numOps; j++) {
1848 LIRInstruction op = ops.at(j);
1849 int opId = op.id;
1850
1851 if (opId != -1 && op.info != null) {
1852 // visit operation to collect all operands
1853 for (ExceptionHandler handler : op.exceptionEdges()) {
1854 resolveExceptionEdge(handler, opId, moveResolver);
1855 }
1856
1857 } else if (C1XOptions.DetailedAsserts) {
1858 assert op.exceptionEdges().size() == 0 : "missed exception handler";
1859 } 1659 }
1860 } 1660 }
1861 } 1661 }
1862 } 1662 }
1863 1663
2170 } 1970 }
2171 } 1971 }
2172 1972
2173 if (op.info != null) { 1973 if (op.info != null) {
2174 // exception handling 1974 // exception handling
2175 if (compilation.hasExceptionHandlers()) { 1975 // if (compilation.hasExceptionHandlers()) {
2176 for (ExceptionHandler handler : op.exceptionEdges()) { 1976 // if (op.exceptionEdge() != null && op.exceptionEdge().lir() != null) {
2177 if (handler.entryCode() != null) { 1977 // assignLocations(op.exceptionEdge().lir().instructionsList(), iw);
2178 assignLocations(handler.entryCode().instructionsList(), null); 1978 // }
2179 } 1979 // }
2180 }
2181 }
2182 1980
2183 // compute reference map and debug information 1981 // compute reference map and debug information
2184 computeDebugInfo(iw, op); 1982 computeDebugInfo(iw, op);
2185 } 1983 }
2186 1984
2250 C1XTimers.LINEAR_SCAN.stop(); 2048 C1XTimers.LINEAR_SCAN.stop();
2251 C1XTimers.RESOLUTION.start(); 2049 C1XTimers.RESOLUTION.start();
2252 } 2050 }
2253 2051
2254 resolveDataFlow(); 2052 resolveDataFlow();
2255 if (compilation.hasExceptionHandlers()) {
2256 resolveExceptionHandlers();
2257 }
2258 2053
2259 if (C1XOptions.PrintTimers) { 2054 if (C1XOptions.PrintTimers) {
2260 C1XTimers.RESOLUTION.stop(); 2055 C1XTimers.RESOLUTION.stop();
2261 C1XTimers.DEBUG_INFO.start(); 2056 C1XTimers.DEBUG_INFO.start();
2262 } 2057 }