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.hotspot.sparc;
024
025import jdk.internal.jvmci.code.*;
026import jdk.internal.jvmci.hotspot.*;
027import jdk.internal.jvmci.meta.*;
028import static com.oracle.graal.asm.sparc.SPARCAssembler.*;
029import static jdk.internal.jvmci.code.ValueUtil.*;
030
031import com.oracle.graal.asm.*;
032import com.oracle.graal.asm.sparc.*;
033import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
034import com.oracle.graal.hotspot.*;
035import com.oracle.graal.hotspot.meta.*;
036import com.oracle.graal.lir.*;
037import com.oracle.graal.lir.asm.*;
038
039@Opcode("BenchMarkCounter")
040public class SPARCHotSpotCounterOp extends HotSpotCounterOp {
041    public static final LIRInstructionClass<SPARCHotSpotCounterOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class);
042
043    private int[] counterPatchOffsets;
044
045    public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
046        super(TYPE, name, group, increment, registers, config);
047        this.counterPatchOffsets = new int[1];
048    }
049
050    public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
051        super(TYPE, names, groups, increments, registers, config);
052        this.counterPatchOffsets = new int[names.length];
053    }
054
055    @Override
056    public void emitCode(CompilationResultBuilder crb) {
057        SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
058        TargetDescription target = crb.target;
059
060        // address for counters array
061        SPARCAddress countersArrayAddr = new SPARCAddress(thread, config.jvmciCountersThreadOffset);
062        try (ScratchRegister scratch = masm.getScratchRegister()) {
063            Register countersArrayReg = scratch.getRegister();
064
065            // load counters array
066            masm.ldx(countersArrayAddr, countersArrayReg);
067            IncrementEmitter emitter = new IncrementEmitter(countersArrayReg, masm);
068            forEachCounter(emitter, target);
069        }
070    }
071
072    private void emitIncrement(int counterIndex, SPARCMacroAssembler masm, SPARCAddress counterAddr, Value increment) {
073        try (ScratchRegister scratch = masm.getScratchRegister()) {
074            Register counterReg = scratch.getRegister();
075            // load counter value
076            masm.ldx(counterAddr, counterReg);
077            counterPatchOffsets[counterIndex] = masm.position();
078            // increment counter
079            if (isConstant(increment)) {
080                masm.add(counterReg, asInt(asConstant(increment)), counterReg);
081            } else {
082                masm.add(counterReg, asRegister(increment), counterReg);
083            }
084            // store counter value
085            masm.stx(counterReg, counterAddr);
086        }
087    }
088
089    /**
090     * Patches the increment value in the instruction emitted by the
091     * {@link #emitIncrement(int, SPARCMacroAssembler, SPARCAddress, Value)} method. This method is
092     * used if patching is needed after assembly.
093     *
094     * @param asm
095     * @param increment
096     */
097    @Override
098    public void patchCounterIncrement(Assembler asm, int[] increment) {
099        for (int i = 0; i < increment.length; i++) {
100            int inst = counterPatchOffsets[i];
101            ((SPARCAssembler) asm).patchAddImmediate(inst, increment[i]);
102        }
103    }
104
105    public int[] getCounterPatchOffsets() {
106        return counterPatchOffsets;
107    }
108
109    private class IncrementEmitter implements CounterProcedure {
110        private int lastDisplacement = 0;
111        private final Register countersArrayReg;
112        private final SPARCMacroAssembler masm;
113
114        public IncrementEmitter(Register countersArrayReg, SPARCMacroAssembler masm) {
115            super();
116            this.countersArrayReg = countersArrayReg;
117            this.masm = masm;
118        }
119
120        public void apply(int counterIndex, Value increment, int displacement) {
121            SPARCAddress counterAddr;
122            int relativeDisplacement = displacement - lastDisplacement;
123            if (isSimm13(relativeDisplacement)) { // Displacement fits into ld instruction
124                counterAddr = new SPARCAddress(countersArrayReg, relativeDisplacement);
125            } else {
126                try (ScratchRegister scratch = masm.getScratchRegister()) {
127                    Register tempOffsetRegister = scratch.getRegister();
128                    new Setx(relativeDisplacement, tempOffsetRegister, false).emit(masm);
129                    masm.add(countersArrayReg, tempOffsetRegister, countersArrayReg);
130                }
131                lastDisplacement = displacement;
132                counterAddr = new SPARCAddress(countersArrayReg, 0);
133            }
134            emitIncrement(counterIndex, masm, counterAddr, increment);
135        }
136    }
137}