001/*
002 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.virtual.phases.ea;
024
025import java.util.*;
026
027import jdk.internal.jvmci.common.*;
028import com.oracle.graal.debug.*;
029
030import com.oracle.graal.compiler.common.*;
031import com.oracle.graal.compiler.common.cfg.*;
032import com.oracle.graal.compiler.common.type.*;
033import com.oracle.graal.graph.*;
034import com.oracle.graal.graph.iterators.*;
035import com.oracle.graal.nodes.*;
036import com.oracle.graal.nodes.cfg.*;
037import com.oracle.graal.nodes.extended.*;
038import com.oracle.graal.nodes.util.*;
039import com.oracle.graal.nodes.virtual.*;
040import com.oracle.graal.phases.graph.*;
041import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
042import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo;
043import com.oracle.graal.phases.schedule.*;
044
045public abstract class EffectsClosure<BlockT extends EffectsBlockState<BlockT>> extends EffectsPhase.Closure<BlockT> {
046
047    protected final ControlFlowGraph cfg;
048    protected final SchedulePhase schedule;
049
050    protected final NodeMap<ValueNode> aliases;
051    protected final BlockMap<GraphEffectList> blockEffects;
052    private final Map<Loop<Block>, GraphEffectList> loopMergeEffects = CollectionsFactory.newIdentityMap();
053    private final Map<LoopBeginNode, BlockT> loopEntryStates = Node.newIdentityMap();
054    private final NodeBitMap hasScalarReplacedInputs;
055
056    protected boolean changed;
057
058    public EffectsClosure(SchedulePhase schedule, ControlFlowGraph cfg) {
059        this.schedule = schedule;
060        this.cfg = cfg;
061        this.aliases = cfg.graph.createNodeMap();
062        this.hasScalarReplacedInputs = cfg.graph.createNodeBitMap();
063        this.blockEffects = new BlockMap<>(cfg);
064        for (Block block : cfg.getBlocks()) {
065            blockEffects.put(block, new GraphEffectList());
066        }
067    }
068
069    @Override
070    public boolean hasChanged() {
071        return changed;
072    }
073
074    @Override
075    public final void applyEffects() {
076        final StructuredGraph graph = cfg.graph;
077        final ArrayList<Node> obsoleteNodes = new ArrayList<>(0);
078        final ArrayList<GraphEffectList> effectList = new ArrayList<>();
079        BlockIteratorClosure<Void> closure = new BlockIteratorClosure<Void>() {
080
081            @Override
082            protected Void getInitialState() {
083                return null;
084            }
085
086            private void apply(GraphEffectList effects) {
087                if (effects != null && !effects.isEmpty()) {
088                    effectList.add(effects);
089                }
090            }
091
092            @Override
093            protected Void processBlock(Block block, Void currentState) {
094                apply(blockEffects.get(block));
095                return currentState;
096            }
097
098            @Override
099            protected Void merge(Block merge, List<Void> states) {
100                return null;
101            }
102
103            @Override
104            protected Void cloneState(Void oldState) {
105                return oldState;
106            }
107
108            @Override
109            protected List<Void> processLoop(Loop<Block> loop, Void initialState) {
110                LoopInfo<Void> info = ReentrantBlockIterator.processLoop(this, loop, initialState);
111                apply(loopMergeEffects.get(loop));
112                return info.exitStates;
113            }
114        };
115        ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
116        for (GraphEffectList effects : effectList) {
117            Debug.log(" ==== effects");
118            effects.apply(graph, obsoleteNodes, false);
119        }
120        for (GraphEffectList effects : effectList) {
121            Debug.log(" ==== cfg kill effects");
122            effects.apply(graph, obsoleteNodes, true);
123        }
124        Debug.dump(4, graph, "After applying effects");
125        assert VirtualUtil.assertNonReachable(graph, obsoleteNodes);
126        for (Node node : obsoleteNodes) {
127            if (node.isAlive()) {
128                node.replaceAtUsages(null);
129                GraphUtil.killWithUnusedFloatingInputs(node);
130            }
131        }
132    }
133
134    @Override
135    protected BlockT processBlock(Block block, BlockT state) {
136        if (!state.isDead()) {
137            GraphEffectList effects = blockEffects.get(block);
138
139            if (block.getBeginNode().predecessor() instanceof IfNode) {
140                IfNode ifNode = (IfNode) block.getBeginNode().predecessor();
141                LogicNode condition = ifNode.condition();
142                Node alias = getScalarAlias(condition);
143                if (alias instanceof LogicConstantNode) {
144                    LogicConstantNode constant = (LogicConstantNode) alias;
145                    boolean deadBranch = constant.getValue() != (block.getBeginNode() == ifNode.trueSuccessor());
146
147                    if (deadBranch) {
148                        state.markAsDead();
149                        effects.killIfBranch(ifNode, constant.getValue());
150                        return state;
151                    }
152                }
153            }
154
155            VirtualUtil.trace("\nBlock: %s, preds: %s, succ: %s (", block, block.getPredecessors(), block.getSuccessors());
156
157            FixedWithNextNode lastFixedNode = block.getBeginNode().predecessor() instanceof FixedWithNextNode ? (FixedWithNextNode) block.getBeginNode().predecessor() : null;
158            Iterable<? extends Node> nodes = schedule != null ? schedule.getBlockToNodesMap().get(block) : block.getNodes();
159            for (Node node : nodes) {
160                aliases.set(node, null);
161                if (node instanceof LoopExitNode) {
162                    LoopExitNode loopExit = (LoopExitNode) node;
163                    for (ProxyNode proxy : loopExit.proxies()) {
164                        changed |= processNode(proxy, state, effects, lastFixedNode) && isSignificantNode(node);
165                    }
166                    processLoopExit(loopExit, loopEntryStates.get(loopExit.loopBegin()), state, blockEffects.get(block));
167                }
168                changed |= processNode(node, state, effects, lastFixedNode) && isSignificantNode(node);
169                if (node instanceof FixedWithNextNode) {
170                    lastFixedNode = (FixedWithNextNode) node;
171                }
172                if (state.isDead()) {
173                    break;
174                }
175            }
176            VirtualUtil.trace(")\n    end state: %s\n", state);
177        }
178        return state;
179    }
180
181    private static boolean isSignificantNode(Node node) {
182        return !(node instanceof CommitAllocationNode || node instanceof AllocatedObjectNode || node instanceof BoxNode);
183    }
184
185    /**
186     * Collects the effects of virtualizing the given node.
187     *
188     * @return {@code true} if the effects include removing the node, {@code false} otherwise.
189     */
190    protected abstract boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode);
191
192    @Override
193    protected BlockT merge(Block merge, List<BlockT> states) {
194        assert blockEffects.get(merge).isEmpty();
195        MergeProcessor processor = createMergeProcessor(merge);
196        doMergeWithoutDead(processor, states);
197        processor.commitEnds(states);
198        blockEffects.get(merge).addAll(processor.mergeEffects);
199        blockEffects.get(merge).addAll(processor.afterMergeEffects);
200        return processor.newState;
201    }
202
203    @Override
204    protected final List<BlockT> processLoop(Loop<Block> loop, BlockT initialState) {
205        if (initialState.isDead()) {
206            ArrayList<BlockT> states = new ArrayList<>();
207            for (int i = 0; i < loop.getExits().size(); i++) {
208                states.add(initialState);
209            }
210            return states;
211        }
212
213        BlockT loopEntryState = initialState;
214        BlockT lastMergedState = cloneState(initialState);
215        processInitialLoopState(loop, lastMergedState);
216        MergeProcessor mergeProcessor = createMergeProcessor(loop.getHeader());
217        for (int iteration = 0; iteration < 10; iteration++) {
218            LoopInfo<BlockT> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(lastMergedState));
219
220            List<BlockT> states = new ArrayList<>();
221            states.add(initialState);
222            states.addAll(info.endStates);
223            doMergeWithoutDead(mergeProcessor, states);
224
225            Debug.log("================== %s", loop.getHeader());
226            Debug.log("%s", mergeProcessor.newState);
227            Debug.log("===== vs.");
228            Debug.log("%s", lastMergedState);
229
230            if (mergeProcessor.newState.equivalentTo(lastMergedState)) {
231                mergeProcessor.commitEnds(states);
232
233                blockEffects.get(loop.getHeader()).insertAll(mergeProcessor.mergeEffects, 0);
234                loopMergeEffects.put(loop, mergeProcessor.afterMergeEffects);
235
236                assert info.exitStates.size() == loop.getExits().size();
237                loopEntryStates.put((LoopBeginNode) loop.getHeader().getBeginNode(), loopEntryState);
238                assert assertExitStatesNonEmpty(loop, info);
239
240                return info.exitStates;
241            } else {
242                lastMergedState = mergeProcessor.newState;
243                for (Block block : loop.getBlocks()) {
244                    blockEffects.get(block).clear();
245                }
246            }
247        }
248        throw new JVMCIError("too many iterations at %s", loop);
249    }
250
251    @SuppressWarnings("unused")
252    protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) {
253        // nothing to do
254    }
255
256    private void doMergeWithoutDead(MergeProcessor mergeProcessor, List<BlockT> states) {
257        int alive = 0;
258        for (BlockT state : states) {
259            if (!state.isDead()) {
260                alive++;
261            }
262        }
263        if (alive == 0) {
264            mergeProcessor.setNewState(states.get(0));
265        } else if (alive == states.size()) {
266            int[] stateIndexes = new int[states.size()];
267            for (int i = 0; i < stateIndexes.length; i++) {
268                stateIndexes[i] = i;
269            }
270            mergeProcessor.setStateIndexes(stateIndexes);
271            mergeProcessor.merge(states);
272        } else {
273            ArrayList<BlockT> aliveStates = new ArrayList<>(alive);
274            int[] stateIndexes = new int[alive];
275            for (int i = 0; i < states.size(); i++) {
276                if (!states.get(i).isDead()) {
277                    stateIndexes[aliveStates.size()] = i;
278                    aliveStates.add(states.get(i));
279                }
280            }
281            mergeProcessor.setStateIndexes(stateIndexes);
282            mergeProcessor.merge(aliveStates);
283        }
284    }
285
286    private boolean assertExitStatesNonEmpty(Loop<Block> loop, LoopInfo<BlockT> info) {
287        for (int i = 0; i < loop.getExits().size(); i++) {
288            assert info.exitStates.get(i) != null : "no loop exit state at " + loop.getExits().get(i) + " / " + loop.getHeader();
289        }
290        return true;
291    }
292
293    protected abstract void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects);
294
295    protected abstract MergeProcessor createMergeProcessor(Block merge);
296
297    protected class MergeProcessor {
298
299        private final Block mergeBlock;
300        private final AbstractMergeNode merge;
301
302        protected final GraphEffectList mergeEffects;
303        protected final GraphEffectList afterMergeEffects;
304
305        private int[] stateIndexes;
306        protected BlockT newState;
307
308        public MergeProcessor(Block mergeBlock) {
309            this.mergeBlock = mergeBlock;
310            this.merge = (AbstractMergeNode) mergeBlock.getBeginNode();
311            this.mergeEffects = new GraphEffectList();
312            this.afterMergeEffects = new GraphEffectList();
313        }
314
315        /**
316         * @param states the states that should be merged.
317         */
318        protected void merge(List<BlockT> states) {
319            setNewState(getInitialState());
320        }
321
322        private void setNewState(BlockT state) {
323            newState = state;
324            mergeEffects.clear();
325            afterMergeEffects.clear();
326        }
327
328        private void setStateIndexes(int[] stateIndexes) {
329            this.stateIndexes = stateIndexes;
330        }
331
332        @SuppressWarnings("unused")
333        protected void commitEnds(List<BlockT> states) {
334        }
335
336        protected final Block getPredecessor(int index) {
337            return mergeBlock.getPredecessors().get(stateIndexes[index]);
338        }
339
340        protected final NodeIterable<PhiNode> getPhis() {
341            return merge.phis();
342        }
343
344        protected final ValueNode getPhiValueAt(PhiNode phi, int index) {
345            return phi.valueAt(stateIndexes[index]);
346        }
347
348        protected final ValuePhiNode createValuePhi(Stamp stamp) {
349            return new ValuePhiNode(stamp, merge, new ValueNode[mergeBlock.getPredecessorCount()]);
350        }
351
352        protected final void setPhiInput(PhiNode phi, int index, ValueNode value) {
353            afterMergeEffects.initializePhiInput(phi, stateIndexes[index], value);
354        }
355
356        protected final int getStateIndex(int i) {
357            return stateIndexes[i];
358        }
359
360        protected final StructuredGraph graph() {
361            return merge.graph();
362        }
363
364        @Override
365        public String toString() {
366            return "MergeProcessor@" + merge;
367        }
368    }
369
370    public void addScalarAlias(ValueNode node, ValueNode alias) {
371        assert !(alias instanceof VirtualObjectNode);
372        aliases.set(node, alias);
373        for (Node usage : node.usages()) {
374            if (!hasScalarReplacedInputs.isNew(usage)) {
375                hasScalarReplacedInputs.mark(usage);
376            }
377        }
378    }
379
380    protected final boolean hasScalarReplacedInputs(Node node) {
381        return hasScalarReplacedInputs.isMarked(node);
382    }
383
384    public ValueNode getScalarAlias(ValueNode node) {
385        assert !(node instanceof VirtualObjectNode);
386        if (node == null || !node.isAlive() || aliases.isNew(node)) {
387            return node;
388        }
389        ValueNode result = aliases.get(node);
390        return (result == null || result instanceof VirtualObjectNode) ? node : result;
391    }
392}