001/*
002 * Copyright (c) 2013, 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.replacements.nodes;
024
025import jdk.internal.jvmci.meta.*;
026
027import com.oracle.graal.compiler.common.type.*;
028import com.oracle.graal.graph.*;
029import com.oracle.graal.graph.spi.*;
030import com.oracle.graal.nodeinfo.*;
031import com.oracle.graal.nodes.*;
032import com.oracle.graal.nodes.memory.*;
033import com.oracle.graal.nodes.spi.*;
034import com.oracle.graal.nodes.util.*;
035import com.oracle.graal.nodes.virtual.*;
036
037// JaCoCo Exclude
038
039/**
040 * Compares two arrays with the same length.
041 */
042@NodeInfo
043public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
044
045    public static final NodeClass<ArrayEqualsNode> TYPE = NodeClass.create(ArrayEqualsNode.class);
046    /** {@link Kind} of the arrays to compare. */
047    protected final Kind kind;
048
049    /** One array to be tested for equality. */
050    @Input ValueNode array1;
051
052    /** The other array to be tested for equality. */
053    @Input ValueNode array2;
054
055    /** Length of both arrays. */
056    @Input ValueNode length;
057
058    @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
059
060    public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length, @ConstantNodeParameter Kind kind) {
061        super(TYPE, StampFactory.forKind(Kind.Boolean));
062        this.kind = kind;
063        this.array1 = array1;
064        this.array2 = array2;
065        this.length = length;
066    }
067
068    @Override
069    public Node canonical(CanonicalizerTool tool) {
070        if (tool.allUsagesAvailable() && hasNoUsages()) {
071            return null;
072        }
073        if (GraphUtil.unproxify(array1) == GraphUtil.unproxify(array2)) {
074            return ConstantNode.forBoolean(true);
075        }
076        return this;
077    }
078
079    public void virtualize(VirtualizerTool tool) {
080        ValueNode alias1 = tool.getAlias(array1);
081        ValueNode alias2 = tool.getAlias(array2);
082        if (alias1 == alias2) {
083            // the same virtual objects will always have the same contents
084            tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
085        } else if (alias1 instanceof VirtualObjectNode && alias2 instanceof VirtualObjectNode) {
086            VirtualObjectNode virtual1 = (VirtualObjectNode) alias1;
087            VirtualObjectNode virtual2 = (VirtualObjectNode) alias2;
088
089            if (virtual1.entryCount() == virtual2.entryCount()) {
090                int entryCount = virtual1.entryCount();
091                boolean allEqual = true;
092                for (int i = 0; i < entryCount; i++) {
093                    ValueNode entry1 = tool.getEntry(virtual1, i);
094                    ValueNode entry2 = tool.getEntry(virtual2, i);
095                    if (entry1 != entry2) {
096                        // the contents might be different
097                        allEqual = false;
098                    }
099                    if (entry1.stamp().alwaysDistinct(entry2.stamp())) {
100                        // the contents are different
101                        tool.replaceWithValue(ConstantNode.forBoolean(false, graph()));
102                        return;
103                    }
104                }
105                if (allEqual) {
106                    tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
107                }
108            }
109        }
110    }
111
112    @NodeIntrinsic
113    public static native boolean equals(Object array1, Object array2, int length, @ConstantNodeParameter Kind kind);
114
115    public static boolean equals(boolean[] array1, boolean[] array2, int length) {
116        return equals(array1, array2, length, Kind.Boolean);
117    }
118
119    public static boolean equals(byte[] array1, byte[] array2, int length) {
120        return equals(array1, array2, length, Kind.Byte);
121    }
122
123    public static boolean equals(char[] array1, char[] array2, int length) {
124        return equals(array1, array2, length, Kind.Char);
125    }
126
127    public static boolean equals(short[] array1, short[] array2, int length) {
128        return equals(array1, array2, length, Kind.Short);
129    }
130
131    public static boolean equals(int[] array1, int[] array2, int length) {
132        return equals(array1, array2, length, Kind.Int);
133    }
134
135    public static boolean equals(long[] array1, long[] array2, int length) {
136        return equals(array1, array2, length, Kind.Long);
137    }
138
139    public static boolean equals(float[] array1, float[] array2, int length) {
140        return equals(array1, array2, length, Kind.Float);
141    }
142
143    public static boolean equals(double[] array1, double[] array2, int length) {
144        return equals(array1, array2, length, Kind.Double);
145    }
146
147    @Override
148    public void generate(NodeLIRBuilderTool gen) {
149        Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length));
150        gen.setResult(this, result);
151    }
152
153    public LocationIdentity getLocationIdentity() {
154        return NamedLocationIdentity.getArrayLocation(kind);
155    }
156
157    public MemoryNode getLastLocationAccess() {
158        return lastLocationAccess;
159    }
160
161    public void setLastLocationAccess(MemoryNode lla) {
162        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla));
163        lastLocationAccess = lla;
164    }
165}