private void renameBlock(NodeBlock block) { for (NodeList.iterator iter = block.nodes.begin(); iter.more();) { DNode node = iter.node; switch (node.type) { case NodeType.TempName: case NodeType.Jump: case NodeType.JumpCondition: case NodeType.Store: case NodeType.Return: case NodeType.IncDec: case NodeType.DeclareStatic: case NodeType.Switch: { iter.next(); continue; } case NodeType.DeclareLocal: { DDeclareLocal decl = (DDeclareLocal)node; if (decl.var == null) { if (decl.uses.Count <= 1) { // This was probably just a stack temporary. if (decl.uses.Count == 1) { DUse use = decl.uses.First.Value; use.node.replaceOperand(use.index, decl.value); } block.nodes.remove(iter); continue; } DTempName name = new DTempName(graph_.tempName()); node.replaceAllUsesWith(name); name.init(decl.value); block.nodes.replace(iter, name); } iter.next(); continue; } case NodeType.SysReq: case NodeType.Call: { // Calls are statements or expressions, so we can't // remove them if they have no uses. if (node.uses.Count <= 1) { if (node.uses.Count == 1) { block.nodes.remove(iter); } else { iter.next(); } continue; } break; } case NodeType.Constant: { // Constants can be deeply copied. block.nodes.remove(iter); continue; } default: { if (node.uses.Count <= 1) { // This node has one or zero uses, so instead of // renaming it, we remove it from the instruction // stream. This way the source printer will deep- // print it instead of using its 'SSA' name. block.nodes.remove(iter); continue; } break; } } // If we've reached here, the expression has more than one use // and we have to wrap it in some kind of name, lest we // duplicate it in the expression tree which may be illegal. DTempName replacement = new DTempName(graph_.tempName()); node.replaceAllUsesWith(replacement); replacement.init(node); block.nodes.replace(iter, replacement); iter.next(); } }
private static bool CollapseArrayReferences(NodeBlock block) { bool changed = false; for (NodeList.reverse_iterator iter = block.nodes.rbegin(); iter.more(); iter.next()) { DNode node = iter.node; if (node.type == NodeType.Store || node.type == NodeType.Load) { if (node.getOperand(0).type != NodeType.ArrayRef && IsArray(node.getOperand(0).typeSet)) { DConstant index0 = new DConstant(0); DArrayRef aref0 = new DArrayRef(node.getOperand(0), index0, 0); block.nodes.insertBefore(node, index0); block.nodes.insertBefore(node, aref0); node.replaceOperand(0, aref0); continue; } } if (node.type != NodeType.Binary) { continue; } DBinary binary = (DBinary)node; if (binary.spop != SPOpcode.add) { continue; } if (binary.lhs.type == NodeType.LocalRef) { //Debug.Assert(true); } // Check for an array index. DNode abase = GuessArrayBase(binary.lhs, binary.rhs); if (abase == null) { continue; } DNode index = (abase == binary.lhs) ? binary.rhs : binary.lhs; if (!IsReallyLikelyArrayCompute(binary, abase)) { continue; } // Multi-dimensional arrays are indexed like: // x[y] => x + x[y] // // We recognize this and just remove the add, ignoring the // underlying representation of the array. if (index.type == NodeType.Load && index.getOperand(0) == abase) { node.replaceAllUsesWith(index); node.removeFromUseChains(); block.nodes.remove(iter); changed = true; continue; } // Otherwise, create a new array reference. DArrayRef aref = new DArrayRef(abase, index); iter.node.replaceAllUsesWith(aref); iter.node.removeFromUseChains(); block.nodes.remove(iter); block.nodes.insertBefore(iter.node, aref); changed = true; } return(changed); }