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.profiling;
024
025import static jdk.internal.jvmci.code.ValueUtil.*;
026
027import java.util.*;
028
029import jdk.internal.jvmci.code.*;
030import jdk.internal.jvmci.common.*;
031import jdk.internal.jvmci.meta.*;
032
033import com.oracle.graal.compiler.common.cfg.*;
034import com.oracle.graal.lir.*;
035import com.oracle.graal.lir.StandardOp.BlockEndOp;
036import com.oracle.graal.lir.StandardOp.LabelOp;
037import com.oracle.graal.lir.StandardOp.MoveOp;
038import com.oracle.graal.lir.gen.*;
039import com.oracle.graal.lir.phases.*;
040
041public class MoveProfiling extends PostAllocationOptimizationPhase {
042
043    @Override
044    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
045                    BenchmarkCounterFactory counterFactory) {
046        new Analyzer(lirGenRes.getLIR(), counterFactory).run();
047    }
048
049    private static enum MoveType {
050        REG2REG("Reg", "Reg"),
051        STACK2REG("Reg", "Stack"),
052        CONST2REG("Reg", "Const"),
053        REG2STACK("Stack", "Reg"),
054        CONST2STACK("Stack", "Const"),
055        STACK2STACK("Stack", "Stack");
056
057        private final String name;
058
059        MoveType(String dst, String src) {
060            this.name = String.format("%5s <- %s", dst, src);
061        }
062
063        @Override
064        public String toString() {
065            return name;
066        }
067
068        public static MoveType get(MoveOp move) {
069            AllocatableValue dst = move.getResult();
070            Value src = move.getInput();
071            if (isRegister(dst)) {
072                if (isRegister(src)) {
073                    return REG2REG;
074                }
075                if (isStackSlot(src)) {
076                    return STACK2REG;
077                }
078                if (isConstant(src)) {
079                    return CONST2REG;
080                }
081            } else if (isStackSlot(dst)) {
082                if (isRegister(src)) {
083                    return REG2STACK;
084                }
085                if (isConstant(src)) {
086                    return CONST2STACK;
087                }
088                if (isStackSlot(src)) {
089                    return STACK2STACK;
090                }
091            }
092            throw JVMCIError.shouldNotReachHere(String.format("Unrecognized Move: %s dst=%s, src=%s", move, dst, src));
093        }
094    }
095
096    private static class Analyzer {
097        private final LIR lir;
098        private final BenchmarkCounterFactory counterFactory;
099        private final LIRInsertionBuffer buffer;
100        private final int[] cnt;
101
102        public Analyzer(LIR lir, BenchmarkCounterFactory counterFactory) {
103            this.lir = lir;
104            this.counterFactory = counterFactory;
105            this.buffer = new LIRInsertionBuffer();
106            cnt = new int[MoveType.values().length];
107        }
108
109        public void run() {
110            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
111                doBlock(block);
112            }
113        }
114
115        public void doBlock(AbstractBlockBase<?> block) {
116            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
117            assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
118            assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
119            assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
120            assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
121            assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
122
123            // reset counters
124            Arrays.fill(cnt, 0);
125            // analysis phase
126            for (LIRInstruction inst : instructions) {
127                if (inst instanceof MoveOp) {
128                    cnt[MoveType.get((MoveOp) inst).ordinal()]++;
129                }
130            }
131
132            // counter insertion phase
133            List<String> names = new ArrayList<>();
134            List<Value> increments = new ArrayList<>();
135            for (MoveType type : MoveType.values()) {
136                int i = cnt[type.ordinal()];
137                if (i > 0) {
138                    names.add(type.toString());
139                    increments.add(JavaConstant.forInt(i));
140                }
141            }
142            String[] groups = new String[names.size()];
143            Arrays.fill(groups, "Move Operations");
144            if (names.size() > 0) { // Don't pollute LIR when nothing has to be done
145                LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0]));
146                assert inst != null;
147                buffer.init(instructions);
148                buffer.append(1, inst);
149                buffer.finish();
150            }
151        }
152    }
153
154}