Package org.jnode.vm.x86.compiler.l1a

Source Code of org.jnode.vm.x86.compiler.l1a.FPCompilerFPU

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.x86.compiler.l1a;

import org.jnode.assembler.Label;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.assembler.x86.X86Register;
import org.jnode.assembler.x86.X86Register.FPU;
import org.jnode.assembler.x86.X86Register.GPR;
import org.jnode.assembler.x86.X86Register.GPR32;
import org.jnode.assembler.x86.X86Register.GPR64;
import org.jnode.bootlog.BootLogInstance;
import org.jnode.vm.JvmType;
import org.jnode.vm.facade.VmUtils;

/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
final class FPCompilerFPU extends FPCompiler {

    /**
     * @param bcv
     * @param os
     * @param ec
     * @param vstack
     * @param arrayDataOffset
     */
    public FPCompilerFPU(X86BytecodeVisitor bcv, X86Assembler os,
                         EmitterContext ec, VirtualStack vstack, int arrayDataOffset) {
        super(bcv, os, ec, vstack, arrayDataOffset);
    }

    /**
     * fadd / dadd
     *
     * @param type
     */
    final void add(int type) {
        final ItemFactory ifac = ec.getItemFactory();
        final Item v2 = vstack.pop(type);
        final Item v1 = vstack.pop(type);

        if (v1.isConstant() && v2.isConstant()) {
            final double fpv1 = getFPValue(v1);
            final double fpv2 = getFPValue(v2);
            vstack.push(createConst(ifac, type, fpv1 + fpv2));
            v1.release(ec);
            v2.release(ec);
        } else {
            // Prepare stack
            final FPUStack fpuStack = vstack.fpuStack;
            final FPU reg = prepareForOperation(os, ec, vstack, fpuStack, v2, v1, true);
            final Item result = fpuStack.getItem(reg);
            fpuStack.pop(ec);

            // Calculate
            os.writeFADDP(reg);

            // Push result
            vstack.push(result);
        }
    }

    /**
     * fcmpg, fcmpl, dcmpg, dcmpl
     *
     * @param gt
     * @param type
     * @param curInstrLabel
     */
    final void compare(boolean gt, int type, Label curInstrLabel) {
        final Item v2 = vstack.pop(type);
        final Item v1 = vstack.pop(type);

        // Prepare operands
        final FPUStack fpuStack = vstack.fpuStack;
        final FPU reg = prepareForOperation(os, ec, vstack, fpuStack, v2, v1, false);
        // We need reg to be ST1.
        fxchST1(os, fpuStack, reg);

        final X86RegisterPool pool = ec.getGPRPool();
        pool.request(X86Register.EAX);
        final IntItem result = (IntItem) L1AHelper.requestWordRegister(ec,
            JvmType.INT, false);
        final GPR resr = result.getRegister();

        // Clear resultr
        os.writeXOR(resr, resr);

        if (!gt) {
            // Reverse order
            FPUHelper.fxch(os, fpuStack, X86Register.ST1);
        }
        os.writeFUCOMPP(); // Compare, Pop twice
        os.writeFNSTSW_AX(); // Store fp status word in AX
        if (os.isCode32()) {
            os.writeSAHF(); // Store AH to Flags
        }

        // Pop fpu stack twice (FUCOMPP)
        fpuStack.pop(ec);
        fpuStack.pop(ec);

        final Label gtLabel = new Label(curInstrLabel + "gt");
        final Label ltLabel = new Label(curInstrLabel + "lt");
        final Label endLabel = new Label(curInstrLabel + "end");
        if (os.isCode32()) {
            os.writeJCC(gtLabel, X86Constants.JA);
            os.writeJCC(ltLabel, X86Constants.JB);
        } else {
            // Emulate JA
            os.writeTEST(X86Register.EAX, (X86Constants.F_CF | X86Constants.F_ZF) << 8);
            os.writeJCC(gtLabel, X86Constants.JZ);
            // Emulate JB
            os.writeTEST(X86Register.EAX, (X86Constants.F_CF) << 8);
            os.writeJCC(ltLabel, X86Constants.JNZ);
        }
        os.writeJMP(endLabel); // equal
        // Greater
        os.setObjectRef(gtLabel);
        if (gt) {
            os.writeDEC(resr);
        } else {
            os.writeINC(resr);
        }
        os.writeJMP(endLabel);
        // Less
        os.setObjectRef(ltLabel);
        if (gt) {
            os.writeINC(resr);
        } else {
            os.writeDEC(resr);
        }
        // End
        os.setObjectRef(endLabel);

        // Push result
        vstack.push(result);

        // Release
        pool.release(X86Register.EAX);
    }

    /**
     * f2x / d2x
     */
    final void convert(int fromType, int toType) {
        final ItemFactory ifac = ec.getItemFactory();
        final Item v = vstack.pop(fromType);
        if (v.isConstant()) {
            vstack.push(createConst(ifac, toType, getFPValue(v)));
            v.release(ec);
        } else {
            v.pushToFPU(ec);
            vstack.fpuStack.pop(v);
            v.release(ec);
            final Item result = ifac.createFPUStack(toType);
            vstack.push(result);
            vstack.fpuStack.push(result);

            // Now load to GPR (to force conversion)
            result.loadToGPR(ec);
        }
    }

    /**
     * fdiv / ddiv
     *
     * @param type
     */
    final void div(int type) {
        final ItemFactory ifac = ec.getItemFactory();
        final Item v2 = vstack.pop(type);
        final Item v1 = vstack.pop(type);

        if (v1.isConstant() && v2.isConstant()) {
            final double fpv1 = getFPValue(v1);
            final double fpv2 = getFPValue(v2);
            vstack.push(createConst(ifac, type, fpv1 / fpv2));
            v1.release(ec);
            v2.release(ec);
        } else {
            // Prepare stack
            final FPUStack fpuStack = vstack.fpuStack;
            final FPU reg = prepareForOperation(os, ec, vstack, fpuStack, v2, v1, false);
            final Item result = fpuStack.getItem(reg);
            fpuStack.pop(ec);

            // Calculate
            os.writeFDIVP(reg);

            // Push result
            vstack.push(result);
        }
    }

    /**
     * Ensure that there are at least items registers left on the FPU stack. If
     * the number of items is not free, the stack is flushed onto the CPU stack.
     *
     * @param os
     * @param ec
     * @param vstack
     * @param items
     */
    static void ensureStackCapacity(X86Assembler os, EmitterContext ec,
                                    VirtualStack vstack, int items) {
        final FPUStack fpuStack = vstack.fpuStack;
        if (!fpuStack.hasCapacity(items)) {
            BootLogInstance.get().debug("Flush FPU stack;\n  fpuStack=" + fpuStack
                + ",\n  vstack  =" + vstack);
            vstack.push(ec);
            if (VmUtils.verifyAssertions())
                VmUtils._assert(fpuStack.hasCapacity(items), "Out of FPU stack");
        }
    }

    /**
     * Swap the given register and ST1 unless the given register is already ST1.
     *
     * @param os
     * @param fpuStack
     * @param fpuReg
     */
    private static void fxchST1(X86Assembler os, FPUStack fpuStack,
                                FPU fpuReg) {
        // We need reg to be ST1, if not swap
        if (fpuReg != X86Register.ST1) {
            // Swap reg with ST0
            FPUHelper.fxch(os, fpuStack, fpuReg);
            FPUHelper.fxch(os, fpuStack, X86Register.ST1);
            FPUHelper.fxch(os, fpuStack, fpuReg);
        }
    }

    /**
     * fmul / dmul
     *
     * @param type
     */
    final void mul(int type) {
        final ItemFactory ifac = ec.getItemFactory();
        final Item v2 = vstack.pop(type);
        final Item v1 = vstack.pop(type);

        if (v1.isConstant() && v2.isConstant()) {
            final double fpv1 = getFPValue(v1);
            final double fpv2 = getFPValue(v2);
            vstack.push(createConst(ifac, type, fpv1 * fpv2));
            v1.release(ec);
            v2.release(ec);
        } else {
            // Prepare stack
            final FPUStack fpuStack = vstack.fpuStack;
            final FPU reg = prepareForOperation(os, ec, vstack, fpuStack, v2, v1, true);
            final Item result = fpuStack.getItem(reg);
            fpuStack.pop(ec);

            // Calculate
            os.writeFMULP(reg);

            // Push result
            vstack.push(result);
        }
    }

    /**
     * fneg / dneg
     *
     * @param type
     */
    final void neg(int type) {
        final ItemFactory ifac = ec.getItemFactory();
        final Item v = vstack.pop(type);
        if (v.isConstant()) {
            final double fpv = getFPValue(v);
            vstack.push(createConst(ifac, type, -fpv));
            v.release(ec);
        } else {
            // Prepare
            final FPUStack fpuStack = vstack.fpuStack;
            prepareForOperation(os, ec, vstack, fpuStack, v);

            // Calculate
            os.writeFCHS();

            // Push result
            vstack.push(v);
        }
    }

    /**
     * Make sure that the given operand is on the top on the FPU stack.
     *
     * @param os
     * @param ec
     * @param vstack
     * @param fpuStack
     * @param left
     */
    private static void prepareForOperation(X86Assembler os,
                                            EmitterContext ec, VirtualStack vstack, FPUStack fpuStack,
                                            Item left) {
        final boolean onFpu = left.isFPUStack();

        // If the FPU stack will be full in this operation, we flush the vstack
        // first.
        int extraItems = onFpu ? 0 : 1;
        ensureStackCapacity(os, ec, vstack, extraItems);

        if (onFpu) {
            // Operand is on the FPU stack
            if (!fpuStack.isTos(left)) {
                // operand not on top, exchange it.
                final FPU reg = fpuStack.getRegister(left);
                os.writeFXCH(reg);
                fpuStack.fxch(reg);
            }
        } else {
            // operand is not on FPU stack
            left.pushToFPU(ec); // Now left is on top
        }
    }

    /**
     * Make sure both operand are on the FPU stack, on of which is in ST0. The
     * FPU register of the other operand is returned. If commutative is true,
     * either left of right will be located in ST0, if commutative is false, the
     * left operand will be in ST0.
     * <p/>
     * The item at ST0 is popped of the given fpuStack stack.
     *
     * @param os
     * @param ec
     * @param vstack
     * @param fpuStack
     * @param left
     * @param right
     * @param commutative
     * @return
     */
    private static FPU prepareForOperation(X86Assembler os,
                                           EmitterContext ec, VirtualStack vstack, FPUStack fpuStack,
                                           Item left, Item right, boolean commutative) {
        final boolean lOnFpu = left.isFPUStack();
        final boolean rOnFpu = right.isFPUStack();
        final FPU reg;

        // If the FPU stack will be full in this operation, we flush the vstack
        // first.
        int extraItems = 0;
        extraItems += lOnFpu ? 0 : 1;
        extraItems += rOnFpu ? 0 : 1;
        ensureStackCapacity(os, ec, vstack, extraItems);

        if (lOnFpu && rOnFpu) {
            // Both operand are on the FPU stack
            if (fpuStack.isTos(left)) {
                // Left already on top
                reg = fpuStack.getRegister(right);
            } else if (fpuStack.isTos(right)) {
                // Right on top
                reg = fpuStack.getRegister(left);
                if (commutative) {
                    // Commutative so return left register
                } else {
                    // Non-commutative, so swap left-right and return left
                    // register
                    // System.out.println("stack: " + fpuStack + "\nleft: " +
                    // left + "\nright: " + right + "\nreg: " + reg);
                    FPUHelper.fxch(os, fpuStack, reg);
                }
            } else {
                // Neither left not right on top
                FPUHelper.fxch(os, fpuStack, fpuStack.getRegister(left)); // Swap left &
                // ST0, now left
                // is on top
                reg = fpuStack.getRegister(right);
            }
        } else if (!(lOnFpu || rOnFpu)) {
            // Neither operands are on the FPU stack
            left.pushToFPU(ec);
            right.pushToFPU(ec); // Now right is on top
            reg = X86Register.ST1; // Left is just below top
            if (!commutative) {
                FPUHelper.fxch(os, fpuStack, reg);
            }
        } else if (lOnFpu) {
            // Left operand is on FPU stack, right is not
            right.pushToFPU(ec); // Now right is on top
            // BootLogInstance.get().debug("left.kind=" + left.getKind());
            reg = fpuStack.getRegister(left);
            if (!commutative) {
                FPUHelper.fxch(os, fpuStack, reg);
            }
        } else {
            // Right operand is on FPU stack, left is not
            left.pushToFPU(ec); // Now left is on top
            reg = fpuStack.getRegister(right);
        }

        return reg;
    }

    /**
     * frem / drem
     *
     * @param type
     */
    final void rem(int type) {
        final ItemFactory ifac = ec.getItemFactory();
        final Item v2 = vstack.pop(type);
        final Item v1 = vstack.pop(type);

        if (v1.isConstant() && v2.isConstant()) {
            final double fpv1 = getFPValue(v1);
            final double fpv2 = getFPValue(v2);
            vstack.push(createConst(ifac, type, fpv1 % fpv2));
            v1.release(ec);
            v2.release(ec);
        } else {
            // Prepare stack
            final FPUStack fpuStack = vstack.fpuStack;
            final FPU reg = prepareForOperation(os, ec, vstack, fpuStack, v2, v1, false);
            // We need reg to be ST1, if not swap
            fxchST1(os, fpuStack, reg);

            // Pop the fpuStack.tos
            fpuStack.pop(ec);

            // Calculate
            os.writeFXCH(X86Register.ST1);
            os.writeFPREM();
            os.writeFSTP(X86Register.ST1);

            // Push result
            vstack.push(fpuStack.tos());
        }
    }

    /**
     * fsub / dsub
     *
     * @param type
     */
    final void sub(int type) {
        final ItemFactory ifac = ec.getItemFactory();
        final Item v2 = vstack.pop(type);
        final Item v1 = vstack.pop(type);

        if (v1.isConstant() && v2.isConstant()) {
            final double fpv1 = getFPValue(v1);
            final double fpv2 = getFPValue(v2);
            vstack.push(createConst(ifac, type, fpv1 - fpv2));
            v1.release(ec);
            v2.release(ec);
        } else {
            // Prepare stack
            final FPUStack fpuStack = vstack.fpuStack;
            final FPU reg = prepareForOperation(os, ec, vstack, fpuStack, v2, v1, false);
            final Item result = fpuStack.getItem(reg);
            fpuStack.pop(ec);

            // Calculate
            os.writeFSUBP(reg);

            // Push result
            vstack.push(result);
        }
    }

    /**
     * faload / daload
     *
     * @param type
     */
    final void fpaload(int type) {
        final IntItem idx = vstack.popInt();
        final RefItem ref = vstack.popRef();

        idx.loadIf(ec, ~Item.Kind.CONSTANT);
        ref.load(ec);
        final GPR refr = ref.getRegister();

        bcv.checkBounds(ref, idx);
        ensureStackCapacity(os, ec, vstack, 1);

        if (type == JvmType.FLOAT) {
            if (idx.isConstant()) {
                final int offset = idx.getValue() * 4;
                os.writeFLD32(refr, offset + arrayDataOffset);
            } else {
                GPR idxr = idx.getRegister();
                if (os.isCode64()) {
                    final GPR64 idxr64 = (GPR64) ec.getGPRPool().getRegisterInSameGroup(idxr, JvmType.LONG);
                    os.writeMOVSXD(idxr64, (GPR32) idxr);
                    idxr = idxr64;
                }
                os.writeFLD32(refr, idxr, 4, arrayDataOffset);
            }
        } else {
            if (idx.isConstant()) {
                final int offset = idx.getValue() * 8;
                os.writeFLD64(refr, offset + arrayDataOffset);
            } else {
                GPR idxr = idx.getRegister();
                if (os.isCode64()) {
                    final GPR64 idxr64 = (GPR64) ec.getGPRPool().getRegisterInSameGroup(idxr, JvmType.LONG);
                    os.writeMOVSXD(idxr64, (GPR32) idxr);
                    idxr = idxr64;
                }
                os.writeFLD64(refr, idxr, 8, arrayDataOffset);
            }
        }

        // Release
        ref.release(ec);
        idx.release(ec);

        // Push result
        final ItemFactory ifac = ec.getItemFactory();
        final Item result = ifac.createFPUStack(type);
        vstack.fpuStack.push(result);
        vstack.push(result);
    }
}
TOP

Related Classes of org.jnode.vm.x86.compiler.l1a.FPCompilerFPU

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.