view graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java @ 13308:d3b3c6e17d40

HSAIL: added Math intrinsifications Contributed-by: Vasanth Venkatachalam <Vasanth.Venkatachalam@amd.com>
author Doug Simon <doug.simon@oracle.com>
date Fri, 13 Dec 2013 10:44:09 +0100
parents 1a66453f73db
children 958c99d0790c
line wrap: on
line source

/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.graal.lir.hsail;

import static com.oracle.graal.api.code.ValueUtil.*;
import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;

import com.oracle.graal.api.meta.*;
import com.oracle.graal.asm.hsail.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.lir.*;
import com.oracle.graal.lir.asm.CompilationResultBuilder;

/**
 * Defines arithmetic instruction nodes.
 */
public enum HSAILArithmetic {
    ABS,
    CALL,
    CEIL,
    FDIV,
    FLOOR,
    FREM,
    DADD,
    DDIV,
    DMUL,
    DNEG,
    DREM,
    DSUB,
    FADD,
    FMUL,
    FNEG,
    FSUB,
    IADD,
    IAND,
    ICARRY,
    IDIV,
    IMAX,
    IMIN,
    IMUL,
    INEG,
    INOT,
    IOR,
    IREM,
    ISHL,
    ISHR,
    ISUB,
    IUADD,
    IUCARRY,
    IUDIV,
    IUMAX,
    IUMIN,
    IUMUL,
    IUREM,
    IUSHR,
    IUSUB,
    IXOR,
    LADD,
    LAND,
    LCARRY,
    LDIV,
    LMAX,
    LMIN,
    LMUL,
    LNEG,
    LNOT,
    LOR,
    LREM,
    LSHL,
    LSHR,
    LSUB,
    LUADD,
    LUCARRY,
    LUDIV,
    LUMAX,
    LUMIN,
    LUMUL,
    LUREM,
    LUSHR,
    LUSUB,
    LXOR,
    OADD,
    RINT,
    SQRT,
    UNDEF;

    public static class ConvertOp extends HSAILLIRInstruction {
        private final Kind from;
        private final Kind to;
        @Def({REG}) protected AllocatableValue result;
        @Use({REG, STACK}) protected AllocatableValue x;

        public ConvertOp(AllocatableValue result, AllocatableValue x, Kind to, Kind from) {
            this.from = from;
            this.to = to;
            this.result = result;
            this.x = x;
        }

        @Override
        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
            masm.emitConvert(result, x, to, from);
        }
    }

    public static class Op1Stack extends HSAILLIRInstruction {
        @Opcode private final HSAILArithmetic opcode;
        @Def({REG, HINT}) protected Value result;
        @Use({REG, STACK, CONST}) protected Value x;

        public Op1Stack(HSAILArithmetic opcode, Value result, Value x) {
            this.opcode = opcode;
            this.result = result;
            this.x = x;
        }

        @Override
        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
            emit(crb, masm, opcode, result, x, null);
        }
    }

    public static class Op2Stack extends HSAILLIRInstruction {
        @Opcode private final HSAILArithmetic opcode;
        @Def({REG, HINT}) protected Value result;
        @Use({REG, CONST}) protected Value x;
        @Alive({REG, CONST}) protected Value y;

        public Op2Stack(HSAILArithmetic opcode, Value result, Value x, Value y) {
            this.opcode = opcode;
            this.result = result;
            this.x = x;
            this.y = y;
        }

        @Override
        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
            emit(crb, masm, opcode, result, x, y, null);
        }

        @Override
        public void verify() {
            super.verify();
            verifyKind(opcode, result, x, y);
        }
    }

    public static class Op1Reg extends HSAILLIRInstruction {
        @Opcode private final HSAILArithmetic opcode;
        @Def({REG, HINT}) protected Value result;
        @Use({REG}) protected Value x;

        public Op1Reg(HSAILArithmetic opcode, Value result, Value x) {
            this.opcode = opcode;
            this.result = result;
            this.x = x;
        }

        @Override
        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
            emit(crb, masm, opcode, result, x, null);
        }
    }

    public static class Op2Reg extends HSAILLIRInstruction {
        @Opcode private final HSAILArithmetic opcode;
        @Def({REG, HINT}) protected Value result;
        @Use({REG, STACK, CONST}) protected Value x;
        @Alive({REG, CONST}) protected Value y;

        public Op2Reg(HSAILArithmetic opcode, Value result, Value x, Value y) {
            this.opcode = opcode;
            this.result = result;
            this.x = x;
            this.y = y;
        }

        @Override
        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
            emit(crb, masm, opcode, result, x, y, null);
        }

        @Override
        public void verify() {
            super.verify();
            verifyKind(opcode, result, x, y);
        }
    }

    public static class Op2RegCommutative extends HSAILLIRInstruction {
        @Opcode private final HSAILArithmetic opcode;
        @Def({REG, HINT}) protected Value result;
        @Use({REG, STACK, CONST}) protected Value x;
        @Use({REG, CONST}) protected Value y;

        public Op2RegCommutative(HSAILArithmetic opcode, Value result, Value x, Value y) {
            this.opcode = opcode;
            this.result = result;
            this.x = x;
            this.y = y;
        }

        @Override
        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
            throw GraalInternalError.shouldNotReachHere();
        }

        @Override
        protected void verify() {
            super.verify();
            verifyKind(opcode, result, x, y);
        }
    }

    public static class ShiftOp extends HSAILLIRInstruction {
        @Opcode private final HSAILArithmetic opcode;
        @Def({REG, HINT}) protected Value result;
        @Use({REG, STACK, CONST}) protected Value x;
        @Alive({REG, CONST}) protected Value y;

        public ShiftOp(HSAILArithmetic opcode, Value result, Value x, Value y) {
            this.opcode = opcode;
            this.result = result;
            this.x = x;
            this.y = y;
        }

        @Override
        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
            emit(crb, masm, opcode, result, x, y, null);
        }

        @Override
        public void verify() {
            super.verify();
            verifyKind(opcode, result, x, x);
            assert y.getKind().getStackKind() == Kind.Int;
        }
    }

    public static class DivOp extends HSAILLIRInstruction {
        @Opcode private final HSAILArithmetic opcode;
        @Def protected Value result;
        @Use protected Value x;
        @Alive protected Value y;
        @State protected LIRFrameState state;

        public DivOp(HSAILArithmetic opcode, Value result, Value x, Value y, LIRFrameState state) {
            this.opcode = opcode;
            this.result = result;
            this.x = x;
            this.y = y;
            this.state = state;
        }

        @Override
        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
            emit(crb, masm, opcode, result, y, state);
        }

        @Override
        protected void verify() {
            super.verify();
            verifyKind(opcode, result, x, y);
        }
    }

    @SuppressWarnings("unused")
    protected static void emit(CompilationResultBuilder crb, HSAILAssembler masm, HSAILArithmetic opcode, Value result) {
        switch (opcode) {
            default:
                throw GraalInternalError.shouldNotReachHere();
        }
    }

    /**
     * Emits the HSAIL code for an arithmetic operation taking one input parameter.
     * 
     * @param crb the CompilationResultBuilder
     * @param masm the HSAIL assembler
     * @param opcode the opcode of the arithmetic operation
     * @param dst the destination
     * @param src the source parameter
     * @param info structure that stores the LIRFrameState. Used for exception handling.
     */

    public static void emit(CompilationResultBuilder crb, HSAILAssembler masm, HSAILArithmetic opcode, Value dst, Value src, LIRFrameState info) {
        int exceptionOffset = -1;
        if (isRegister(src)) {
            switch (opcode) {
                case ABS:
                    masm.emit("abs", dst, src);
                    break;
                case CEIL:
                    masm.emit("ceil", dst, src);
                    break;
                case FLOOR:
                    masm.emit("floor", dst, src);
                    break;
                case RINT:
                    masm.emit("rint", dst, src);
                    break;
                case SQRT:
                    masm.emit("sqrt", dst, src);
                    break;
                case UNDEF:
                    masm.undefined("undefined node");
                    break;
                case CALL:
                    masm.undefined("undefined node CALL");
                    break;
                case INOT:
                case LNOT:
                    masm.emitForceBitwise("not", dst, src);
                    break;
                case INEG:
                case LNEG:
                case FNEG:
                case DNEG:
                    masm.emit("neg", dst, src);
                    break;
                default:
                    throw GraalInternalError.shouldNotReachHere();
            }
        } else {
            throw GraalInternalError.shouldNotReachHere();
        }
        if (info != null) {
            assert exceptionOffset != -1;
            crb.recordImplicitException(exceptionOffset, info);
        }
    }

    public static void emit(CompilationResultBuilder crb, HSAILAssembler masm, HSAILArithmetic opcode, Value dst, Value src1, Value src2, LIRFrameState info) {
        /**
         * First check if one of src1 or src2 is an AddressValue. If it is, convert the address to a
         * register using an lda instruction. We can just reuse the eventual dst register for this.
         */
        if (src1 instanceof HSAILAddressValue) {
            assert (!(src2 instanceof HSAILAddressValue));
            masm.emitLda(dst, ((HSAILAddressValue) src1).toAddress());
            emit(crb, masm, opcode, dst, dst, src2, info);
            return;
        } else if (src2 instanceof HSAILAddressValue) {
            assert (!(src1 instanceof HSAILAddressValue));
            masm.emitLda(dst, ((HSAILAddressValue) src2).toAddress());
            emit(crb, masm, opcode, dst, src1, dst, info);
            return;
        }
        int exceptionOffset = -1;
        switch (opcode) {
            case IADD:
            case LADD:
            case DADD:
            case FADD:
            case OADD:
                masm.emit("add", dst, src1, src2);
                break;
            case ISUB:
            case LSUB:
            case DSUB:
            case FSUB:
                masm.emit("sub", dst, src1, src2);
                break;
            case IMUL:
            case LMUL:
            case FMUL:
            case DMUL:
            case LUMUL:
                masm.emit("mul", dst, src1, src2);
                break;
            case IDIV:
            case LDIV:
            case FDIV:
            case DDIV:
                masm.emit("div", dst, src1, src2);
                break;
            case IMAX:
            case LMAX:
                masm.emit("max", dst, src1, src2);
                break;
            case IMIN:
            case LMIN:
                masm.emit("min", dst, src1, src2);
                break;
            case ISHL:
            case LSHL:
                masm.emit("shl", dst, src1, src2);
                break;
            case ISHR:
            case LSHR:
                masm.emit("shr", dst, src1, src2);
                break;
            case IUSHR:
            case LUSHR:
                masm.emitForceUnsigned("shr", dst, src1, src2);
                break;
            case IAND:
            case LAND:
                masm.emitForceBitwise("and", dst, src1, src2);
                break;
            case IXOR:
            case LXOR:
                masm.emitForceBitwise("xor", dst, src1, src2);
                break;
            case IOR:
            case LOR:
                masm.emitForceBitwise("or", dst, src1, src2);
                break;
            case IREM:
            case LREM:
                masm.emit("rem", dst, src1, src2);
                break;
            default:
                throw GraalInternalError.shouldNotReachHere();
        }
        if (info != null) {
            assert exceptionOffset != -1;
            crb.recordImplicitException(exceptionOffset, info);
        }
    }

    private static void verifyKind(HSAILArithmetic opcode, Value result, Value x, Value y) {
        assert (opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) ||
                        (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long) ||
                        (opcode.name().startsWith("LU") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Int) ||
                        (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) ||
                        (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double) ||
                        (opcode.name().startsWith("O") && result.getKind() == Kind.Object && x.getKind() == Kind.Object && (y.getKind() == Kind.Int || y.getKind() == Kind.Long));
    }
}