view graal/com.oracle.graal.replacements.aarch64/src/com/oracle/graal/replacements/aarch64/AArch64IntegerArithmeticSnippets.java @ 23217:a1bfeec72458

AArch64 Graal Port
author twisti
date Thu, 24 Dec 2015 11:43:35 -1000
parents
children 2160e7da7fb0
line wrap: on
line source

/*
 * Copyright (c) 2014, 2015, 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.replacements.aarch64;

import com.oracle.graal.api.replacements.SnippetReflectionProvider;
import com.oracle.graal.graph.Node.ConstantNodeParameter;
import com.oracle.graal.graph.Node.NodeIntrinsic;
import com.oracle.graal.graph.NodeClass;
import com.oracle.graal.nodeinfo.NodeInfo;
import com.oracle.graal.nodes.ValueNode;
import com.oracle.graal.nodes.calc.FixedBinaryNode;
import com.oracle.graal.nodes.calc.IntegerDivNode;
import com.oracle.graal.nodes.calc.IntegerRemNode;
import com.oracle.graal.nodes.calc.UnsignedDivNode;
import com.oracle.graal.nodes.calc.UnsignedRemNode;
import com.oracle.graal.nodes.spi.LoweringTool;
import com.oracle.graal.phases.util.Providers;
import com.oracle.graal.replacements.Snippet;
import com.oracle.graal.replacements.SnippetTemplate;
import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
import com.oracle.graal.replacements.Snippets;

import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.meta.JavaKind;

/**
 * Division in AArch64 ISA does not generate a trap when dividing by zero, but instead sets the
 * result to 0. These snippets throw an ArithmethicException if the denominator is 0 and otherwise
 * forward to the LIRGenerator.
 */
public class AArch64IntegerArithmeticSnippets extends AbstractTemplates implements Snippets {

    private final SnippetTemplate.SnippetInfo idiv;
    private final SnippetTemplate.SnippetInfo ldiv;
    private final SnippetTemplate.SnippetInfo irem;
    private final SnippetTemplate.SnippetInfo lrem;

    private final SnippetTemplate.SnippetInfo uidiv;
    private final SnippetTemplate.SnippetInfo uldiv;
    private final SnippetTemplate.SnippetInfo uirem;
    private final SnippetTemplate.SnippetInfo ulrem;

    public AArch64IntegerArithmeticSnippets(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
        super(providers, snippetReflection, target);
        idiv = snippet(AArch64IntegerArithmeticSnippets.class, "idivSnippet");
        ldiv = snippet(AArch64IntegerArithmeticSnippets.class, "ldivSnippet");
        irem = snippet(AArch64IntegerArithmeticSnippets.class, "iremSnippet");
        lrem = snippet(AArch64IntegerArithmeticSnippets.class, "lremSnippet");

        uidiv = snippet(AArch64IntegerArithmeticSnippets.class, "uidivSnippet");
        uldiv = snippet(AArch64IntegerArithmeticSnippets.class, "uldivSnippet");
        uirem = snippet(AArch64IntegerArithmeticSnippets.class, "uiremSnippet");
        ulrem = snippet(AArch64IntegerArithmeticSnippets.class, "ulremSnippet");
    }

    public void lower(FixedBinaryNode node, LoweringTool tool) {
        // assert node.kind() == JavaKind.Int || node.kind() == JavaKind.Long;
        // SnippetTemplate.SnippetInfo snippet;
        // if (node instanceof SafeNode) {
        // // We already introduced the 0 division check, nothing to do.
        // return;
        // } else if (node instanceof IntegerDivNode) {
        // snippet = node.kind() == JavaKind.Int ? idiv : ldiv;
        // } else if (node instanceof IntegerRemNode) {
        // snippet = node.kind() == JavaKind.Int ? irem : lrem;
        // } else if (node instanceof UnsignedDivNode) {
        // snippet = node.kind() == JavaKind.Int ? uidiv : uldiv;
        // } else if (node instanceof UnsignedRemNode) {
        // snippet = node.kind() == JavaKind.Int ? uirem : ulrem;
        // } else {
        // throw GraalInternalError.shouldNotReachHere();
        // }
        // Arguments args = new Arguments(snippet, node.graph().getGuardsStage());
        // args.add("x", node.x());
        // args.add("y", node.y());
        // template(args).instantiate(providers.getMetaAccess(), node,
        // SnippetTemplate.DEFAULT_REPLACER,
        // args);
        throw JVMCIError.unimplemented(node + ", " + tool);
    }

    @Snippet
    public static int idivSnippet(int x, int y) {
        checkForZero(y);
        return safeDiv(JavaKind.Int, x, y);
    }

    @Snippet
    public static long ldivSnippet(long x, long y) {
        checkForZero(y);
        return safeDiv(JavaKind.Long, x, y);
    }

    @Snippet
    public static int iremSnippet(int x, int y) {
        checkForZero(y);
        return safeRem(JavaKind.Int, x, y);
    }

    @Snippet
    public static long lremSnippet(long x, long y) {
        checkForZero(y);
        return safeRem(JavaKind.Long, x, y);
    }

    @Snippet
    public static int uidivSnippet(int x, int y) {
        checkForZero(y);
        return safeUDiv(JavaKind.Int, x, y);
    }

    @Snippet
    public static long uldivSnippet(long x, long y) {
        checkForZero(y);
        return safeUDiv(JavaKind.Long, x, y);
    }

    @Snippet
    public static int uiremSnippet(int x, int y) {
        checkForZero(y);
        return safeURem(JavaKind.Int, x, y);
    }

    @Snippet
    public static long ulremSnippet(long x, long y) {
        checkForZero(y);
        return safeURem(JavaKind.Long, x, y);
    }

    private static void checkForZero(int y) {
        if (y == 0) {
            throw new ArithmeticException("/ by zero.");
        }
    }

    private static void checkForZero(long y) {
        if (y == 0) {
            throw new ArithmeticException("/ by zero.");
        }
    }

    @NodeIntrinsic(SafeIntegerDivNode.class)
    private static native int safeDiv(@ConstantNodeParameter JavaKind kind, int x, int y);

    @NodeIntrinsic(SafeIntegerDivNode.class)
    private static native long safeDiv(@ConstantNodeParameter JavaKind kind, long x, long y);

    @NodeIntrinsic(SafeIntegerRemNode.class)
    private static native int safeRem(@ConstantNodeParameter JavaKind kind, int x, int y);

    @NodeIntrinsic(SafeIntegerRemNode.class)
    private static native long safeRem(@ConstantNodeParameter JavaKind kind, long x, long y);

    @NodeIntrinsic(SafeUnsignedDivNode.class)
    private static native int safeUDiv(@ConstantNodeParameter JavaKind kind, int x, int y);

    @NodeIntrinsic(SafeUnsignedDivNode.class)
    private static native long safeUDiv(@ConstantNodeParameter JavaKind kind, long x, long y);

    @NodeIntrinsic(SafeUnsignedRemNode.class)
    private static native int safeURem(@ConstantNodeParameter JavaKind kind, int x, int y);

    @NodeIntrinsic(SafeUnsignedRemNode.class)
    private static native long safeURem(@ConstantNodeParameter JavaKind kind, long x, long y);

    // Marker interface to distinguish untreated nodes from ones where we have installed the
    // additional checks
    private interface SafeNode {
    }

    @NodeInfo
    static class SafeIntegerDivNode extends IntegerDivNode implements SafeNode {
        public static final NodeClass<SafeIntegerDivNode> TYPE = NodeClass.create(SafeIntegerDivNode.class);

        @SuppressWarnings("unused")
        public SafeIntegerDivNode(JavaKind kind, ValueNode x, ValueNode y) {
            super(x, y);
        }
    }

    @NodeInfo
    static class SafeIntegerRemNode extends IntegerRemNode implements SafeNode {
        public static final NodeClass<SafeIntegerRemNode> TYPE = NodeClass.create(SafeIntegerRemNode.class);

        @SuppressWarnings("unused")
        public SafeIntegerRemNode(JavaKind kind, ValueNode x, ValueNode y) {
            super(x, y);
        }
    }

    @NodeInfo
    static class SafeUnsignedDivNode extends UnsignedDivNode implements SafeNode {
        public static final NodeClass<SafeUnsignedDivNode> TYPE = NodeClass.create(SafeUnsignedDivNode.class);

        @SuppressWarnings("unused")
        public SafeUnsignedDivNode(JavaKind kind, ValueNode x, ValueNode y) {
            super(x, y);
        }
    }

    @NodeInfo
    static class SafeUnsignedRemNode extends UnsignedRemNode implements SafeNode {
        public static final NodeClass<SafeUnsignedRemNode> TYPE = NodeClass.create(SafeUnsignedRemNode.class);

        @SuppressWarnings("unused")
        public SafeUnsignedRemNode(JavaKind kind, ValueNode x, ValueNode y) {
            super(x, y);
        }
    }
}