Mercurial > hg > graal-compiler
comparison graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java @ 13317:755645fa92d6
the load of a constant is commoned to the nearest block dominating all usages (GRAAL-508)
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Fri, 13 Dec 2013 13:32:11 +0100 |
parents | d2165b699e0f |
children | ac5243877cc7 0393767ae0fc |
comparison
equal
deleted
inserted
replaced
13316:26472d911fcd | 13317:755645fa92d6 |
---|---|
40 import com.oracle.graal.graph.*; | 40 import com.oracle.graal.graph.*; |
41 import com.oracle.graal.lir.*; | 41 import com.oracle.graal.lir.*; |
42 import com.oracle.graal.lir.StandardOp.BlockEndOp; | 42 import com.oracle.graal.lir.StandardOp.BlockEndOp; |
43 import com.oracle.graal.lir.StandardOp.JumpOp; | 43 import com.oracle.graal.lir.StandardOp.JumpOp; |
44 import com.oracle.graal.lir.StandardOp.LabelOp; | 44 import com.oracle.graal.lir.StandardOp.LabelOp; |
45 import com.oracle.graal.lir.StandardOp.NoOp; | |
45 import com.oracle.graal.nodes.*; | 46 import com.oracle.graal.nodes.*; |
46 import com.oracle.graal.nodes.PhiNode.PhiType; | 47 import com.oracle.graal.nodes.PhiNode.PhiType; |
47 import com.oracle.graal.nodes.calc.*; | 48 import com.oracle.graal.nodes.calc.*; |
48 import com.oracle.graal.nodes.cfg.*; | 49 import com.oracle.graal.nodes.cfg.*; |
49 import com.oracle.graal.nodes.extended.*; | 50 import com.oracle.graal.nodes.extended.*; |
80 protected Block currentBlock; | 81 protected Block currentBlock; |
81 private final int traceLevel; | 82 private final int traceLevel; |
82 private final boolean printIRWithLIR; | 83 private final boolean printIRWithLIR; |
83 | 84 |
84 /** | 85 /** |
85 * Maps constants the variables within the scope of a single block to avoid loading a constant | 86 * Maps constants to variables within the scope of a single block to avoid loading a constant |
86 * more than once per block. | 87 * more than once per block. |
87 */ | 88 */ |
88 private Map<Constant, Variable> constantsLoadedInCurrentBlock; | 89 private Map<Constant, Variable> constantsLoadedInCurrentBlock; |
90 | |
91 /** | |
92 * Handle for an operation that loads a constant into a variable. The operation starts in the | |
93 * first block where the constant is used but will eventually be | |
94 * {@linkplain LIRGenerator#insertConstantLoads() moved} to a block dominating all usages of the | |
95 * constant. | |
96 */ | |
97 public static class LoadConstant implements Comparable<LoadConstant> { | |
98 /** | |
99 * The index of {@link #op} within {@link #block}'s instruction list or -1 if {@code op} is | |
100 * to be moved to a dominator block. | |
101 */ | |
102 int index; | |
103 | |
104 /** | |
105 * The operation that loads the constant. | |
106 */ | |
107 private final LIRInstruction op; | |
108 | |
109 /** | |
110 * The block that does or will contain {@link #op}. This is initially the block where the | |
111 * first usage of the constant is seen during LIR generation. | |
112 */ | |
113 private Block block; | |
114 | |
115 /** | |
116 * The variable into which the constant is loaded. | |
117 */ | |
118 private final Variable variable; | |
119 | |
120 public LoadConstant(Variable variable, Block block, int index, LIRInstruction op) { | |
121 this.variable = variable; | |
122 this.block = block; | |
123 this.index = index; | |
124 this.op = op; | |
125 } | |
126 | |
127 /** | |
128 * Sorts {@link LoadConstant} objects according to their enclosing blocks. This is used to | |
129 * group loads per block in {@link LIRGenerator#insertConstantLoads()}. | |
130 */ | |
131 public int compareTo(LoadConstant o) { | |
132 if (block.getId() < o.block.getId()) { | |
133 return -1; | |
134 } | |
135 if (block.getId() > o.block.getId()) { | |
136 return 1; | |
137 } | |
138 return 0; | |
139 } | |
140 | |
141 @Override | |
142 public String toString() { | |
143 return block + "#" + op; | |
144 } | |
145 } | |
146 | |
147 private Map<Constant, LoadConstant> constantLoads; | |
89 | 148 |
90 private ValueNode currentInstruction; | 149 private ValueNode currentInstruction; |
91 private ValueNode lastInstructionPrinted; // Debugging only | 150 private ValueNode lastInstructionPrinted; // Debugging only |
92 | 151 |
93 /** | 152 /** |
178 if (operand == null) { | 237 if (operand == null) { |
179 return getConstantOperand(node); | 238 return getConstantOperand(node); |
180 } | 239 } |
181 return operand; | 240 return operand; |
182 } | 241 } |
242 | |
243 /** | |
244 * Controls whether commoning is performed on {@linkplain #canInlineConstant(Constant) | |
245 * non-inlinable} constants. | |
246 */ | |
247 private static final boolean CommonConstantLoads = Boolean.parseBoolean(System.getProperty("graal.commonConstantLoads", "true")); | |
183 | 248 |
184 private Value getConstantOperand(ValueNode node) { | 249 private Value getConstantOperand(ValueNode node) { |
185 if (!ConstantNodeRecordsUsages) { | 250 if (!ConstantNodeRecordsUsages) { |
186 Constant value = node.asConstant(); | 251 Constant value = node.asConstant(); |
187 if (value != null) { | 252 if (value != null) { |
188 if (canInlineConstant(value)) { | 253 if (canInlineConstant(value)) { |
189 return !node.isExternal() ? setResult(node, value) : value; | 254 return !node.isExternal() ? setResult(node, value) : value; |
190 } else { | 255 } else { |
191 Variable loadedValue; | 256 Variable loadedValue; |
192 if (constantsLoadedInCurrentBlock == null) { | 257 if (CommonConstantLoads) { |
193 constantsLoadedInCurrentBlock = new HashMap<>(); | 258 if (constantLoads == null) { |
194 loadedValue = null; | 259 constantLoads = new HashMap<>(); |
260 } | |
261 LoadConstant load = constantLoads.get(value); | |
262 if (load == null) { | |
263 int index = lir.lir(currentBlock).size(); | |
264 // loadedValue = newVariable(value.getPlatformKind()); | |
265 loadedValue = emitMove(value); | |
266 LIRInstruction op = lir.lir(currentBlock).get(index); | |
267 constantLoads.put(value, new LoadConstant(loadedValue, currentBlock, index, op)); | |
268 } else { | |
269 Block dominator = ControlFlowGraph.commonDominator(load.block, currentBlock); | |
270 loadedValue = load.variable; | |
271 if (dominator != load.block) { | |
272 if (load.index >= 0) { | |
273 List<LIRInstruction> instructions = lir.lir(load.block); | |
274 instructions.set(load.index, new NoOp(null, -1)); | |
275 load.index = -1; | |
276 } | |
277 } else { | |
278 assert load.block != currentBlock || load.index < lir.lir(currentBlock).size(); | |
279 } | |
280 load.block = dominator; | |
281 } | |
195 } else { | 282 } else { |
196 loadedValue = constantsLoadedInCurrentBlock.get(value); | 283 if (constantsLoadedInCurrentBlock == null) { |
197 } | 284 constantsLoadedInCurrentBlock = new HashMap<>(); |
198 if (loadedValue == null) { | 285 loadedValue = null; |
199 loadedValue = emitMove(value); | 286 } else { |
200 constantsLoadedInCurrentBlock.put(value, loadedValue); | 287 loadedValue = constantsLoadedInCurrentBlock.get(value); |
288 } | |
289 if (loadedValue == null) { | |
290 loadedValue = emitMove(value); | |
291 constantsLoadedInCurrentBlock.put(value, loadedValue); | |
292 } | |
201 } | 293 } |
202 return loadedValue; | 294 return loadedValue; |
203 } | 295 } |
204 } | 296 } |
205 } else { | 297 } else { |
793 return frameMap; | 885 return frameMap; |
794 } | 886 } |
795 | 887 |
796 @Override | 888 @Override |
797 public void beforeRegisterAllocation() { | 889 public void beforeRegisterAllocation() { |
798 } | 890 insertConstantLoads(); |
799 | 891 } |
800 /** | 892 |
801 * Gets an garbage vale for a given kind. | 893 /** |
894 * Moves deferred {@linkplain LoadConstant loads} of constants into blocks dominating all usages | |
895 * of the constant. Any operations inserted into a block are guaranteed to be immediately prior | |
896 * to the first control flow instruction near the end of the block. | |
897 */ | |
898 private void insertConstantLoads() { | |
899 if (constantLoads != null) { | |
900 // Remove loads where all usages are in the same block. | |
901 for (Iterator<Map.Entry<Constant, LoadConstant>> iter = constantLoads.entrySet().iterator(); iter.hasNext();) { | |
902 LoadConstant lc = iter.next().getValue(); | |
903 if (lc.index != -1) { | |
904 assert lir.lir(lc.block).get(lc.index) == lc.op; | |
905 iter.remove(); | |
906 } | |
907 } | |
908 if (constantLoads.isEmpty()) { | |
909 return; | |
910 } | |
911 | |
912 // Sorting groups the loads per block. | |
913 LoadConstant[] groupedByBlock = constantLoads.values().toArray(new LoadConstant[constantLoads.size()]); | |
914 Arrays.sort(groupedByBlock); | |
915 | |
916 int groupBegin = 0; | |
917 while (true) { | |
918 int groupEnd = groupBegin + 1; | |
919 Block block = groupedByBlock[groupBegin].block; | |
920 while (groupEnd < groupedByBlock.length && groupedByBlock[groupEnd].block == block) { | |
921 groupEnd++; | |
922 } | |
923 int groupSize = groupEnd - groupBegin; | |
924 | |
925 List<LIRInstruction> ops = lir.lir(block); | |
926 int lastIndex = ops.size() - 1; | |
927 assert ops.get(lastIndex) instanceof BlockEndOp; | |
928 int insertionIndex = lastIndex; | |
929 for (int i = Math.max(0, lastIndex - MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END); i < lastIndex; i++) { | |
930 if (getExceptionEdge(ops.get(i)) != null) { | |
931 insertionIndex = i; | |
932 break; | |
933 } | |
934 } | |
935 | |
936 if (groupSize == 1) { | |
937 ops.add(insertionIndex, groupedByBlock[groupBegin].op); | |
938 } else { | |
939 assert groupSize > 1; | |
940 List<LIRInstruction> moves = new ArrayList<>(groupSize); | |
941 for (int i = groupBegin; i < groupEnd; i++) { | |
942 moves.add(groupedByBlock[i].op); | |
943 } | |
944 ops.addAll(insertionIndex, moves); | |
945 } | |
946 | |
947 if (groupEnd == groupedByBlock.length) { | |
948 break; | |
949 } | |
950 groupBegin = groupEnd; | |
951 } | |
952 constantLoads = null; | |
953 } | |
954 } | |
955 | |
956 /** | |
957 * Gets a garbage value for a given kind. | |
802 */ | 958 */ |
803 protected Constant zapValueForKind(PlatformKind kind) { | 959 protected Constant zapValueForKind(PlatformKind kind) { |
804 long dead = 0xDEADDEADDEADDEADL; | 960 long dead = 0xDEADDEADDEADDEADL; |
805 switch ((Kind) kind) { | 961 switch ((Kind) kind) { |
806 case Boolean: | 962 case Boolean: |