001/*
002 * Copyright (c) 2015, 2015, 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.lir.alloc.lsra;
024
025import static com.oracle.graal.compiler.common.GraalOptions.*;
026import static com.oracle.graal.lir.LIRValueUtil.*;
027import static com.oracle.graal.lir.debug.LIRGenerationDebugContext.*;
028import static jdk.internal.jvmci.code.ValueUtil.*;
029
030import java.util.*;
031
032import jdk.internal.jvmci.code.*;
033import jdk.internal.jvmci.common.*;
034import com.oracle.graal.debug.*;
035import com.oracle.graal.debug.Debug.*;
036import jdk.internal.jvmci.meta.*;
037
038import com.oracle.graal.compiler.common.alloc.*;
039import com.oracle.graal.compiler.common.cfg.*;
040import com.oracle.graal.compiler.common.util.*;
041import com.oracle.graal.lir.*;
042import com.oracle.graal.lir.LIRInstruction.OperandFlag;
043import com.oracle.graal.lir.LIRInstruction.OperandMode;
044import com.oracle.graal.lir.StandardOp.MoveOp;
045import com.oracle.graal.lir.StandardOp.StackStoreOp;
046import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
047import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
048import com.oracle.graal.lir.alloc.lsra.LinearScan.BlockData;
049import com.oracle.graal.lir.gen.*;
050import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
051import com.oracle.graal.lir.phases.*;
052
053public class LinearScanLifetimeAnalysisPhase extends AllocationPhase {
054
055    protected final LinearScan allocator;
056
057    /**
058     * @param linearScan
059     */
060    protected LinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
061        allocator = linearScan;
062    }
063
064    @Override
065    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
066                    RegisterAllocationConfig registerAllocationConfig) {
067        numberInstructions();
068        allocator.printLir("Before register allocation", true);
069        computeLocalLiveSets();
070        computeGlobalLiveSets();
071        buildIntervals();
072    }
073
074    /**
075     * Bit set for each variable that is contained in each loop.
076     */
077    private BitMap2D intervalInLoop;
078
079    boolean isIntervalInLoop(int interval, int loop) {
080        return intervalInLoop.at(interval, loop);
081    }
082
083    /**
084     * Numbers all instructions in all blocks. The numbering follows the
085     * {@linkplain ComputeBlockOrder linear scan order}.
086     */
087    protected void numberInstructions() {
088
089        allocator.initIntervals();
090
091        ValueConsumer setVariableConsumer = (value, mode, flags) -> {
092            if (isVariable(value)) {
093                allocator.getOrCreateInterval(asVariable(value));
094            }
095        };
096
097        // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
098        int numInstructions = 0;
099        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
100            numInstructions += allocator.getLIR().getLIRforBlock(block).size();
101        }
102
103        // initialize with correct length
104        allocator.initOpIdMaps(numInstructions);
105
106        int opId = 0;
107        int index = 0;
108        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
109            allocator.initBlockData(block);
110
111            List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
112
113            int numInst = instructions.size();
114            for (int j = 0; j < numInst; j++) {
115                LIRInstruction op = instructions.get(j);
116                op.setId(opId);
117
118                allocator.putOpIdMaps(index, op, block);
119                assert allocator.instructionForId(opId) == op : "must match";
120
121                op.visitEachTemp(setVariableConsumer);
122                op.visitEachOutput(setVariableConsumer);
123
124                index++;
125                opId += 2; // numbering of lirOps by two
126            }
127        }
128        assert index == numInstructions : "must match";
129        assert (index << 1) == opId : "must match: " + (index << 1);
130    }
131
132    /**
133     * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill})
134     * separately for each block.
135     */
136    void computeLocalLiveSets() {
137        int liveSize = allocator.liveSetSize();
138
139        intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops());
140
141        // iterate all blocks
142        for (final AbstractBlockBase<?> block : allocator.sortedBlocks()) {
143            try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) {
144
145                final BitSet liveGen = new BitSet(liveSize);
146                final BitSet liveKill = new BitSet(liveSize);
147
148                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
149                int numInst = instructions.size();
150
151                ValueConsumer useConsumer = (operand, mode, flags) -> {
152                    if (isVariable(operand)) {
153                        int operandNum = allocator.operandNumber(operand);
154                        if (!liveKill.get(operandNum)) {
155                            liveGen.set(operandNum);
156                            if (Debug.isLogEnabled()) {
157                                Debug.log("liveGen for operand %d(%s)", operandNum, operand);
158                            }
159                        }
160                        if (block.getLoop() != null) {
161                            intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
162                        }
163                    }
164
165                    if (DetailedAsserts.getValue()) {
166                        verifyInput(block, liveKill, operand);
167                    }
168                };
169                ValueConsumer stateConsumer = (operand, mode, flags) -> {
170                    if (LinearScan.isVariableOrRegister(operand)) {
171                        int operandNum = allocator.operandNumber(operand);
172                        if (!liveKill.get(operandNum)) {
173                            liveGen.set(operandNum);
174                            if (Debug.isLogEnabled()) {
175                                Debug.log("liveGen in state for operand %d(%s)", operandNum, operand);
176                            }
177                        }
178                    }
179                };
180                ValueConsumer defConsumer = (operand, mode, flags) -> {
181                    if (isVariable(operand)) {
182                        int varNum = allocator.operandNumber(operand);
183                        liveKill.set(varNum);
184                        if (Debug.isLogEnabled()) {
185                            Debug.log("liveKill for operand %d(%s)", varNum, operand);
186                        }
187                        if (block.getLoop() != null) {
188                            intervalInLoop.setBit(varNum, block.getLoop().getIndex());
189                        }
190                    }
191
192                    if (DetailedAsserts.getValue()) {
193                        /*
194                         * Fixed intervals are never live at block boundaries, so they need not be
195                         * processed in live sets. Process them only in debug mode so that this can
196                         * be checked
197                         */
198                        verifyTemp(liveKill, operand);
199                    }
200                };
201
202                // iterate all instructions of the block
203                for (int j = 0; j < numInst; j++) {
204                    final LIRInstruction op = instructions.get(j);
205
206                    try (Indent indent2 = Debug.logAndIndent("handle op %d: %s", op.id(), op)) {
207                        op.visitEachInput(useConsumer);
208                        op.visitEachAlive(useConsumer);
209                        /*
210                         * Add uses of live locals from interpreter's point of view for proper debug
211                         * information generation.
212                         */
213                        op.visitEachState(stateConsumer);
214                        op.visitEachTemp(defConsumer);
215                        op.visitEachOutput(defConsumer);
216                    }
217                } // end of instruction iteration
218
219                BlockData blockSets = allocator.getBlockData(block);
220                blockSets.liveGen = liveGen;
221                blockSets.liveKill = liveKill;
222                blockSets.liveIn = new BitSet(liveSize);
223                blockSets.liveOut = new BitSet(liveSize);
224
225                if (Debug.isLogEnabled()) {
226                    Debug.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
227                    Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
228                }
229
230            }
231        } // end of block iteration
232    }
233
234    private void verifyTemp(BitSet liveKill, Value operand) {
235        /*
236         * Fixed intervals are never live at block boundaries, so they need not be processed in live
237         * sets. Process them only in debug mode so that this can be checked
238         */
239        if (isRegister(operand)) {
240            if (allocator.isProcessed(operand)) {
241                liveKill.set(allocator.operandNumber(operand));
242            }
243        }
244    }
245
246    private void verifyInput(AbstractBlockBase<?> block, BitSet liveKill, Value operand) {
247        /*
248         * Fixed intervals are never live at block boundaries, so they need not be processed in live
249         * sets. This is checked by these assertions to be sure about it. The entry block may have
250         * incoming values in registers, which is ok.
251         */
252        if (isRegister(operand) && block != allocator.getLIR().getControlFlowGraph().getStartBlock()) {
253            if (allocator.isProcessed(operand)) {
254                assert liveKill.get(allocator.operandNumber(operand)) : "using fixed register that is not defined in this block";
255            }
256        }
257    }
258
259    /**
260     * Performs a backward dataflow analysis to compute global live sets (i.e.
261     * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
262     */
263    protected void computeGlobalLiveSets() {
264        try (Indent indent = Debug.logAndIndent("compute global live sets")) {
265            int numBlocks = allocator.blockCount();
266            boolean changeOccurred;
267            boolean changeOccurredInBlock;
268            int iterationCount = 0;
269            BitSet liveOut = new BitSet(allocator.liveSetSize()); // scratch set for calculations
270
271            /*
272             * Perform a backward dataflow analysis to compute liveOut and liveIn for each block.
273             * The loop is executed until a fixpoint is reached (no changes in an iteration).
274             */
275            do {
276                changeOccurred = false;
277
278                try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) {
279
280                    // iterate all blocks in reverse order
281                    for (int i = numBlocks - 1; i >= 0; i--) {
282                        AbstractBlockBase<?> block = allocator.blockAt(i);
283                        BlockData blockSets = allocator.getBlockData(block);
284
285                        changeOccurredInBlock = false;
286
287                        /* liveOut(block) is the union of liveIn(sux), for successors sux of block. */
288                        int n = block.getSuccessorCount();
289                        if (n > 0) {
290                            liveOut.clear();
291                            // block has successors
292                            if (n > 0) {
293                                for (AbstractBlockBase<?> successor : block.getSuccessors()) {
294                                    liveOut.or(allocator.getBlockData(successor).liveIn);
295                                }
296                            }
297
298                            if (!blockSets.liveOut.equals(liveOut)) {
299                                /*
300                                 * A change occurred. Swap the old and new live out sets to avoid
301                                 * copying.
302                                 */
303                                BitSet temp = blockSets.liveOut;
304                                blockSets.liveOut = liveOut;
305                                liveOut = temp;
306
307                                changeOccurred = true;
308                                changeOccurredInBlock = true;
309                            }
310                        }
311
312                        if (iterationCount == 0 || changeOccurredInBlock) {
313                            /*
314                             * liveIn(block) is the union of liveGen(block) with (liveOut(block) &
315                             * !liveKill(block)).
316                             * 
317                             * Note: liveIn has to be computed only in first iteration or if liveOut
318                             * has changed!
319                             */
320                            BitSet liveIn = blockSets.liveIn;
321                            liveIn.clear();
322                            liveIn.or(blockSets.liveOut);
323                            liveIn.andNot(blockSets.liveKill);
324                            liveIn.or(blockSets.liveGen);
325
326                            if (Debug.isLogEnabled()) {
327                                Debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
328                            }
329                        }
330                    }
331                    iterationCount++;
332
333                    if (changeOccurred && iterationCount > 50) {
334                        throw new BailoutException("too many iterations in computeGlobalLiveSets");
335                    }
336                }
337            } while (changeOccurred);
338
339            if (DetailedAsserts.getValue()) {
340                verifyLiveness();
341            }
342
343            // check that the liveIn set of the first block is empty
344            AbstractBlockBase<?> startBlock = allocator.getLIR().getControlFlowGraph().getStartBlock();
345            if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) {
346                if (DetailedAsserts.getValue()) {
347                    reportFailure(numBlocks);
348                }
349                // bailout if this occurs in product mode.
350                throw new JVMCIError("liveIn set of first block must be empty: " + allocator.getBlockData(startBlock).liveIn);
351            }
352        }
353    }
354
355    protected void reportFailure(int numBlocks) {
356        try (Scope s = Debug.forceLog()) {
357            try (Indent indent = Debug.logAndIndent("report failure")) {
358
359                BitSet startBlockLiveIn = allocator.getBlockData(allocator.getLIR().getControlFlowGraph().getStartBlock()).liveIn;
360                try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) {
361                    for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
362                        Interval interval = allocator.intervalFor(operandNum);
363                        if (interval != null) {
364                            Value operand = interval.operand;
365                            Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getSourceForOperandFromDebugContext(operand));
366                        } else {
367                            Debug.log("var %d; missing operand", operandNum);
368                        }
369                    }
370                }
371
372                // print some additional information to simplify debugging
373                for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
374                    Interval interval = allocator.intervalFor(operandNum);
375                    Value operand = null;
376                    Object valueForOperandFromDebugContext = null;
377                    if (interval != null) {
378                        operand = interval.operand;
379                        valueForOperandFromDebugContext = getSourceForOperandFromDebugContext(operand);
380                    }
381                    try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) {
382
383                        Deque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>();
384                        HashSet<AbstractBlockBase<?>> usedIn = new HashSet<>();
385                        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
386                            if (allocator.getBlockData(block).liveGen.get(operandNum)) {
387                                usedIn.add(block);
388                                try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) {
389                                    for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) {
390                                        try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) {
391                                            ins.forEachState((liveStateOperand, mode, flags) -> {
392                                                Debug.log("operand=%s", liveStateOperand);
393                                                return liveStateOperand;
394                                            });
395                                        }
396                                    }
397                                }
398                            }
399                            if (allocator.getBlockData(block).liveKill.get(operandNum)) {
400                                definedIn.add(block);
401                                try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) {
402                                    for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) {
403                                        Debug.log("%d: %s", ins.id(), ins);
404                                    }
405                                }
406                            }
407                        }
408
409                        int[] hitCount = new int[numBlocks];
410
411                        while (!definedIn.isEmpty()) {
412                            AbstractBlockBase<?> block = definedIn.removeFirst();
413                            usedIn.remove(block);
414                            for (AbstractBlockBase<?> successor : block.getSuccessors()) {
415                                if (successor.isLoopHeader()) {
416                                    if (!block.isLoopEnd()) {
417                                        definedIn.add(successor);
418                                    }
419                                } else {
420                                    if (++hitCount[successor.getId()] == successor.getPredecessorCount()) {
421                                        definedIn.add(successor);
422                                    }
423                                }
424                            }
425                        }
426                        try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) {
427                            for (AbstractBlockBase<?> block : usedIn) {
428                                Debug.log("B%d", block.getId());
429                            }
430                        }
431                    }
432                }
433            }
434        } catch (Throwable e) {
435            throw Debug.handle(e);
436        }
437    }
438
439    protected void verifyLiveness() {
440        /*
441         * Check that fixed intervals are not live at block boundaries (live set must be empty at
442         * fixed intervals).
443         */
444        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
445            for (int j = 0; j <= allocator.maxRegisterNumber(); j++) {
446                assert !allocator.getBlockData(block).liveIn.get(j) : "liveIn  set of fixed register must be empty";
447                assert !allocator.getBlockData(block).liveOut.get(j) : "liveOut set of fixed register must be empty";
448                assert !allocator.getBlockData(block).liveGen.get(j) : "liveGen set of fixed register must be empty";
449            }
450        }
451    }
452
453    protected void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
454        if (!allocator.isProcessed(operand)) {
455            return;
456        }
457
458        Interval interval = allocator.getOrCreateInterval(operand);
459        if (!kind.equals(LIRKind.Illegal)) {
460            interval.setKind(kind);
461        }
462
463        interval.addRange(from, to);
464
465        // Register use position at even instruction id.
466        interval.addUsePos(to & ~1, registerPriority);
467
468        if (Debug.isLogEnabled()) {
469            Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name());
470        }
471    }
472
473    protected void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
474        if (!allocator.isProcessed(operand)) {
475            return;
476        }
477
478        Interval interval = allocator.getOrCreateInterval(operand);
479        if (!kind.equals(LIRKind.Illegal)) {
480            interval.setKind(kind);
481        }
482
483        interval.addRange(tempPos, tempPos + 1);
484        interval.addUsePos(tempPos, registerPriority);
485        interval.addMaterializationValue(null);
486
487        if (Debug.isLogEnabled()) {
488            Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
489        }
490    }
491
492    protected void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
493        if (!allocator.isProcessed(operand)) {
494            return;
495        }
496        int defPos = op.id();
497
498        Interval interval = allocator.getOrCreateInterval(operand);
499        if (!kind.equals(LIRKind.Illegal)) {
500            interval.setKind(kind);
501        }
502
503        Range r = interval.first();
504        if (r.from <= defPos) {
505            /*
506             * Update the starting point (when a range is first created for a use, its start is the
507             * beginning of the current block until a def is encountered).
508             */
509            r.from = defPos;
510            interval.addUsePos(defPos, registerPriority);
511
512        } else {
513            /*
514             * Dead value - make vacuous interval also add register priority for dead intervals
515             */
516            interval.addRange(defPos, defPos + 1);
517            interval.addUsePos(defPos, registerPriority);
518            if (Debug.isLogEnabled()) {
519                Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
520            }
521        }
522
523        changeSpillDefinitionPos(op, operand, interval, defPos);
524        if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
525            // detection of method-parameters and roundfp-results
526            interval.setSpillState(SpillState.StartInMemory);
527        }
528        interval.addMaterializationValue(getMaterializedValue(op, operand, interval));
529
530        if (Debug.isLogEnabled()) {
531            Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
532        }
533    }
534
535    /**
536     * Optimizes moves related to incoming stack based arguments. The interval for the destination
537     * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot.
538     */
539    protected void handleMethodArguments(LIRInstruction op) {
540        if (op instanceof MoveOp) {
541            MoveOp move = (MoveOp) op;
542            if (optimizeMethodArgument(move.getInput())) {
543                StackSlot slot = asStackSlot(move.getInput());
544                if (DetailedAsserts.getValue()) {
545                    assert op.id() > 0 : "invalid id";
546                    assert allocator.blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block";
547                    assert isVariable(move.getResult()) : "result of move must be a variable";
548
549                    if (Debug.isLogEnabled()) {
550                        Debug.log("found move from stack slot %s to %s", slot, move.getResult());
551                    }
552                }
553
554                Interval interval = allocator.intervalFor(move.getResult());
555                interval.setSpillSlot(slot);
556                interval.assignLocation(slot);
557            }
558        } else if (op instanceof StackStoreOp) {
559            StackStoreOp store = (StackStoreOp) op;
560            StackSlot slot = asStackSlot(store.getStackSlot());
561            Interval interval = allocator.intervalFor(store.getResult());
562            interval.setSpillSlot(slot);
563            interval.setSpillState(SpillState.StartInMemory);
564        }
565    }
566
567    protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
568        if (flags.contains(OperandFlag.HINT) && LinearScan.isVariableOrRegister(targetValue)) {
569
570            op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> {
571                if (LinearScan.isVariableOrRegister(registerHint)) {
572                    Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
573                    Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
574
575                    /* hints always point from def to use */
576                    if (hintAtDef) {
577                        to.setLocationHint(from);
578                    } else {
579                        from.setLocationHint(to);
580                    }
581                    if (Debug.isLogEnabled()) {
582                        Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
583                    }
584
585                    return registerHint;
586                }
587                return null;
588            });
589        }
590    }
591
592    /**
593     * Eliminates moves from register to stack if the stack slot is known to be correct.
594     *
595     * @param op
596     * @param operand
597     */
598    protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) {
599        assert interval.isSplitParent() : "can only be called for split parents";
600
601        switch (interval.spillState()) {
602            case NoDefinitionFound:
603                assert interval.spillDefinitionPos() == -1 : "must no be set before";
604                interval.setSpillDefinitionPos(defPos);
605                interval.setSpillState(SpillState.NoSpillStore);
606                break;
607
608            case NoSpillStore:
609                assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
610                if (defPos < interval.spillDefinitionPos() - 2) {
611                    // second definition found, so no spill optimization possible for this interval
612                    interval.setSpillState(SpillState.NoOptimization);
613                } else {
614                    // two consecutive definitions (because of two-operand LIR form)
615                    assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal";
616                }
617                break;
618
619            case NoOptimization:
620                // nothing to do
621                break;
622
623            default:
624                throw new BailoutException("other states not allowed at this time");
625        }
626    }
627
628    private static boolean optimizeMethodArgument(Value value) {
629        /*
630         * Object method arguments that are passed on the stack are currently not optimized because
631         * this requires that the runtime visits method arguments during stack walking.
632         */
633        return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getKind() != Kind.Object;
634    }
635
636    /**
637     * Determines the register priority for an instruction's output/result operand.
638     */
639    protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
640        if (op instanceof MoveOp) {
641            MoveOp move = (MoveOp) op;
642            if (optimizeMethodArgument(move.getInput())) {
643                return RegisterPriority.None;
644            }
645        } else if (op instanceof StackStoreOp) {
646            return RegisterPriority.ShouldHaveRegister;
647        }
648
649        // all other operands require a register
650        return RegisterPriority.MustHaveRegister;
651    }
652
653    /**
654     * Determines the priority which with an instruction's input operand will be allocated a
655     * register.
656     */
657    protected static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
658        if (flags.contains(OperandFlag.STACK)) {
659            return RegisterPriority.ShouldHaveRegister;
660        }
661        // all other operands require a register
662        return RegisterPriority.MustHaveRegister;
663    }
664
665    protected void buildIntervals() {
666
667        try (Indent indent = Debug.logAndIndent("build intervals")) {
668            InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
669                if (LinearScan.isVariableOrRegister(operand)) {
670                    addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
671                    addRegisterHint(op, operand, mode, flags, true);
672                }
673            };
674
675            InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
676                if (LinearScan.isVariableOrRegister(operand)) {
677                    addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
678                    addRegisterHint(op, operand, mode, flags, false);
679                }
680            };
681
682            InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
683                if (LinearScan.isVariableOrRegister(operand)) {
684                    RegisterPriority p = registerPriorityOfInputOperand(flags);
685                    int opId = op.id();
686                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
687                    addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
688                    addRegisterHint(op, operand, mode, flags, false);
689                }
690            };
691
692            InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
693                if (LinearScan.isVariableOrRegister(operand)) {
694                    int opId = op.id();
695                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
696                    RegisterPriority p = registerPriorityOfInputOperand(flags);
697                    addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
698                    addRegisterHint(op, operand, mode, flags, false);
699                }
700            };
701
702            InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
703                if (LinearScan.isVariableOrRegister(operand)) {
704                    int opId = op.id();
705                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
706                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
707                }
708            };
709
710            // create a list with all caller-save registers (cpu, fpu, xmm)
711            Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
712
713            // iterate all blocks in reverse order
714            for (int i = allocator.blockCount() - 1; i >= 0; i--) {
715
716                AbstractBlockBase<?> block = allocator.blockAt(i);
717                try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
718
719                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
720                    final int blockFrom = allocator.getFirstLirInstructionId(block);
721                    int blockTo = allocator.getLastLirInstructionId(block);
722
723                    assert blockFrom == instructions.get(0).id();
724                    assert blockTo == instructions.get(instructions.size() - 1).id();
725
726                    // Update intervals for operands live at the end of this block;
727                    BitSet live = allocator.getBlockData(block).liveOut;
728                    for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
729                        assert live.get(operandNum) : "should not stop here otherwise";
730                        AllocatableValue operand = allocator.intervalFor(operandNum).operand;
731                        if (Debug.isLogEnabled()) {
732                            Debug.log("live in %d: %s", operandNum, operand);
733                        }
734
735                        addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal);
736
737                        /*
738                         * Add special use positions for loop-end blocks when the interval is used
739                         * anywhere inside this loop. It's possible that the block was part of a
740                         * non-natural loop, so it might have an invalid loop index.
741                         */
742                        if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) {
743                            allocator.intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd);
744                        }
745                    }
746
747                    /*
748                     * Iterate all instructions of the block in reverse order. definitions of
749                     * intervals are processed before uses.
750                     */
751                    for (int j = instructions.size() - 1; j >= 0; j--) {
752                        final LIRInstruction op = instructions.get(j);
753                        final int opId = op.id();
754
755                        try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
756
757                            // add a temp range for each register if operation destroys
758                            // caller-save registers
759                            if (op.destroysCallerSavedRegisters()) {
760                                for (Register r : callerSaveRegs) {
761                                    if (allocator.attributes(r).isAllocatable()) {
762                                        addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
763                                    }
764                                }
765                                if (Debug.isLogEnabled()) {
766                                    Debug.log("operation destroys all caller-save registers");
767                                }
768                            }
769
770                            op.visitEachOutput(outputConsumer);
771                            op.visitEachTemp(tempConsumer);
772                            op.visitEachAlive(aliveConsumer);
773                            op.visitEachInput(inputConsumer);
774
775                            /*
776                             * Add uses of live locals from interpreter's point of view for proper
777                             * debug information generation. Treat these operands as temp values (if
778                             * the live range is extended to a call site, the value would be in a
779                             * register at the call otherwise).
780                             */
781                            op.visitEachState(stateProc);
782
783                            // special steps for some instructions (especially moves)
784                            handleMethodArguments(op);
785
786                        }
787
788                    } // end of instruction iteration
789                }
790            } // end of block iteration
791
792            /*
793             * Add the range [0, 1] to all fixed intervals. the register allocator need not handle
794             * unhandled fixed intervals.
795             */
796            for (Interval interval : allocator.intervals()) {
797                if (interval != null && isRegister(interval.operand)) {
798                    interval.addRange(0, 1);
799                }
800            }
801        }
802    }
803
804    /**
805     * Returns a value for a interval definition, which can be used for re-materialization.
806     *
807     * @param op An instruction which defines a value
808     * @param operand The destination operand of the instruction
809     * @param interval The interval for this defined value.
810     * @return Returns the value which is moved to the instruction and which can be reused at all
811     *         reload-locations in case the interval of this instruction is spilled. Currently this
812     *         can only be a {@link JavaConstant}.
813     */
814    protected static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) {
815        if (op instanceof MoveOp) {
816            MoveOp move = (MoveOp) op;
817            if (move.getInput() instanceof JavaConstant) {
818                /*
819                 * Check if the interval has any uses which would accept an stack location (priority
820                 * == ShouldHaveRegister). Rematerialization of such intervals can result in a
821                 * degradation, because rematerialization always inserts a constant load, even if
822                 * the value is not needed in a register.
823                 */
824                Interval.UsePosList usePosList = interval.usePosList();
825                int numUsePos = usePosList.size();
826                for (int useIdx = 0; useIdx < numUsePos; useIdx++) {
827                    Interval.RegisterPriority priority = usePosList.registerPriority(useIdx);
828                    if (priority == Interval.RegisterPriority.ShouldHaveRegister) {
829                        return null;
830                    }
831                }
832                return (JavaConstant) move.getInput();
833            }
834        }
835        return null;
836    }
837}