001/*
002 * Copyright (c) 2011, 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.amd64;
024
025import jdk.internal.jvmci.amd64.*;
026import jdk.internal.jvmci.meta.*;
027import static jdk.internal.jvmci.code.ValueUtil.*;
028
029import com.oracle.graal.asm.*;
030import com.oracle.graal.asm.amd64.*;
031import com.oracle.graal.asm.amd64.AMD64Assembler.*;
032import com.oracle.graal.lir.*;
033import com.oracle.graal.lir.asm.*;
034
035public enum AMD64Arithmetic {
036    FREM,
037    DREM;
038
039    public static class FPDivRemOp extends AMD64LIRInstruction {
040        public static final LIRInstructionClass<FPDivRemOp> TYPE = LIRInstructionClass.create(FPDivRemOp.class);
041
042        @Opcode private final AMD64Arithmetic opcode;
043        @Def protected AllocatableValue result;
044        @Use protected AllocatableValue x;
045        @Use protected AllocatableValue y;
046        @Temp protected AllocatableValue raxTemp;
047
048        public FPDivRemOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
049            super(TYPE);
050            this.opcode = opcode;
051            this.result = result;
052            this.raxTemp = AMD64.rax.asValue(LIRKind.value(Kind.Int));
053            this.x = x;
054            this.y = y;
055        }
056
057        @Override
058        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
059            AMD64Address tmp = new AMD64Address(AMD64.rsp);
060            masm.subq(AMD64.rsp, 8);
061            if (opcode == FREM) {
062                masm.movflt(tmp, asRegister(y));
063                masm.flds(tmp);
064                masm.movflt(tmp, asRegister(x));
065                masm.flds(tmp);
066            } else {
067                assert opcode == DREM;
068                masm.movdbl(tmp, asRegister(y));
069                masm.fldd(tmp);
070                masm.movdbl(tmp, asRegister(x));
071                masm.fldd(tmp);
072            }
073
074            Label label = new Label();
075            masm.bind(label);
076            masm.fprem();
077            masm.fwait();
078            masm.fnstswAX();
079            masm.testl(AMD64.rax, 0x400);
080            masm.jcc(ConditionFlag.NotZero, label);
081            masm.fxch(1);
082            masm.fpop();
083
084            if (opcode == FREM) {
085                masm.fstps(tmp);
086                masm.movflt(asRegister(result), tmp);
087            } else {
088                masm.fstpd(tmp);
089                masm.movdbl(asRegister(result), tmp);
090            }
091            masm.addq(AMD64.rsp, 8);
092        }
093
094        @Override
095        public void verify() {
096            super.verify();
097            assert (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) ||
098                            (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double);
099        }
100    }
101}