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: