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.trace;
024
025import static jdk.internal.jvmci.code.ValueUtil.*;
026
027import java.util.*;
028
029import jdk.internal.jvmci.code.*;
030import jdk.internal.jvmci.meta.*;
031
032import com.oracle.graal.compiler.common.alloc.*;
033import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
034import com.oracle.graal.compiler.common.cfg.*;
035import com.oracle.graal.debug.*;
036import com.oracle.graal.lir.*;
037import com.oracle.graal.lir.alloc.lsra.*;
038import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
039import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
040import com.oracle.graal.lir.gen.*;
041import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
042
043public class TraceSimpleLifetimeAnalysisPhase extends TraceLinearScanLifetimeAnalysisPhase {
044
045    public TraceSimpleLifetimeAnalysisPhase(LinearScan allocator, TraceBuilderResult<?> traceBuilderResult) {
046        super(allocator, traceBuilderResult);
047    }
048
049    @Override
050    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
051                    RegisterAllocationConfig registerAllocationConfig) {
052        numberInstructions();
053        allocator.printLir("Before register allocation", true);
054        buildIntervals();
055    }
056
057    @Override
058    protected void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
059        if (!allocator.isProcessed(operand)) {
060            return;
061        }
062        if (isRegister(operand)) {
063            super.addUse(operand, from, to, registerPriority, kind);
064            return;
065        }
066
067        Interval interval = allocator.getOrCreateInterval(operand);
068        if (!kind.equals(LIRKind.Illegal)) {
069            interval.setKind(kind);
070        }
071
072        Range r = interval.first();
073        if (r == Range.EndMarker) {
074            interval.addRange(from, to);
075        } else if (r.from > from) {
076            r.from = from;
077        }
078
079        // Register use position at even instruction id.
080        interval.addUsePos(to & ~1, registerPriority);
081
082        if (Debug.isLogEnabled()) {
083            Debug.log("add use: %s, at %d (%s)", interval, to, registerPriority.name());
084        }
085    }
086
087    @Override
088    protected void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
089        if (!allocator.isProcessed(operand)) {
090            return;
091        }
092        if (isRegister(operand)) {
093            super.addTemp(operand, tempPos, registerPriority, kind);
094            return;
095        }
096
097        Interval interval = allocator.getOrCreateInterval(operand);
098        if (!kind.equals(LIRKind.Illegal)) {
099            interval.setKind(kind);
100        }
101
102        Range r = interval.first();
103        if (r == Range.EndMarker) {
104            interval.addRange(tempPos, tempPos + 1);
105        } else if (r.from > tempPos) {
106            r.from = tempPos;
107        }
108        interval.addUsePos(tempPos, registerPriority);
109        interval.addMaterializationValue(null);
110
111        if (Debug.isLogEnabled()) {
112            Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
113        }
114    }
115
116    @Override
117    protected void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
118        if (!allocator.isProcessed(operand)) {
119            return;
120        }
121        if (isRegister(operand)) {
122            super.addDef(operand, op, registerPriority, kind);
123            return;
124        }
125        int defPos = op.id();
126
127        Interval interval = allocator.getOrCreateInterval(operand);
128        if (!kind.equals(LIRKind.Illegal)) {
129            interval.setKind(kind);
130        }
131
132        Range r = interval.first();
133        if (r == Range.EndMarker) {
134            /*
135             * Dead value - make vacuous interval also add register priority for dead intervals
136             */
137            interval.addRange(defPos, defPos + 1);
138            interval.addUsePos(defPos, registerPriority);
139            if (Debug.isLogEnabled()) {
140                Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
141            }
142        } else {
143            /*
144             * Update the starting point (when a range is first created for a use, its start is the
145             * beginning of the current block until a def is encountered).
146             */
147            r.from = defPos;
148            interval.addUsePos(defPos, registerPriority);
149
150        }
151
152        changeSpillDefinitionPos(op, operand, interval, defPos);
153        if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
154            // detection of method-parameters and roundfp-results
155            interval.setSpillState(SpillState.StartInMemory);
156        }
157        interval.addMaterializationValue(getMaterializedValue(op, operand, interval));
158
159        if (Debug.isLogEnabled()) {
160            Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
161        }
162    }
163
164    @Override
165    protected void buildIntervals() {
166
167        try (Indent indent = Debug.logAndIndent("build intervals")) {
168            InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
169                if (LinearScan.isVariableOrRegister(operand)) {
170                    addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
171                    addRegisterHint(op, operand, mode, flags, true);
172                }
173            };
174
175            InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
176                if (LinearScan.isVariableOrRegister(operand)) {
177                    addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
178                    addRegisterHint(op, operand, mode, flags, false);
179                }
180            };
181
182            InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
183                if (LinearScan.isVariableOrRegister(operand)) {
184                    RegisterPriority p = registerPriorityOfInputOperand(flags);
185                    int opId = op.id();
186                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
187                    addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
188                    addRegisterHint(op, operand, mode, flags, false);
189                }
190            };
191
192            InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
193                if (LinearScan.isVariableOrRegister(operand)) {
194                    int opId = op.id();
195                    RegisterPriority p = registerPriorityOfInputOperand(flags);
196                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
197                    addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
198                    addRegisterHint(op, operand, mode, flags, false);
199                }
200            };
201
202            InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
203                if (LinearScan.isVariableOrRegister(operand)) {
204                    int opId = op.id();
205                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
206                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
207                }
208            };
209
210            // create a list with all caller-save registers (cpu, fpu, xmm)
211            Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
212
213            // iterate all blocks in reverse order
214            for (int i = allocator.blockCount() - 1; i >= 0; i--) {
215
216                AbstractBlockBase<?> block = allocator.blockAt(i);
217                // TODO (je) make empty bitset - remove
218                allocator.getBlockData(block).liveIn = new BitSet();
219                allocator.getBlockData(block).liveOut = new BitSet();
220                try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
221
222                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
223
224                    /*
225                     * Iterate all instructions of the block in reverse order. definitions of
226                     * intervals are processed before uses.
227                     */
228                    for (int j = instructions.size() - 1; j >= 0; j--) {
229                        final LIRInstruction op = instructions.get(j);
230                        final int opId = op.id();
231
232                        try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
233
234                            // add a temp range for each register if operation destroys
235                            // caller-save registers
236                            if (op.destroysCallerSavedRegisters()) {
237                                for (Register r : callerSaveRegs) {
238                                    if (allocator.attributes(r).isAllocatable()) {
239                                        addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
240                                    }
241                                }
242                                if (Debug.isLogEnabled()) {
243                                    Debug.log("operation destroys all caller-save registers");
244                                }
245                            }
246
247                            op.visitEachOutput(outputConsumer);
248                            op.visitEachTemp(tempConsumer);
249                            op.visitEachAlive(aliveConsumer);
250                            op.visitEachInput(inputConsumer);
251
252                            /*
253                             * Add uses of live locals from interpreter's point of view for proper
254                             * debug information generation. Treat these operands as temp values (if
255                             * the live range is extended to a call site, the value would be in a
256                             * register at the call otherwise).
257                             */
258                            op.visitEachState(stateProc);
259
260                            // special steps for some instructions (especially moves)
261                            handleMethodArguments(op);
262
263                        }
264
265                    } // end of instruction iteration
266                }
267                allocator.printIntervals("After Block " + block);
268            } // end of block iteration
269
270            /*
271             * Add the range [0, 1] to all fixed intervals. the register allocator need not handle
272             * unhandled fixed intervals.
273             */
274            for (Interval interval : allocator.intervals()) {
275                if (interval != null && isRegister(interval.operand)) {
276                    interval.addRange(0, 1);
277                }
278            }
279        }
280        postBuildIntervals();
281    }
282}