1 /*
   2  * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.replacements.nodes;
  26 
  27 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
  28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1024;
  29 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1024;
  30 
  31 import org.graalvm.compiler.core.common.type.StampFactory;
  32 import org.graalvm.compiler.graph.Node;
  33 import org.graalvm.compiler.graph.NodeClass;
  34 import org.graalvm.compiler.graph.spi.Canonicalizable;
  35 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  36 import org.graalvm.compiler.nodeinfo.NodeInfo;
  37 import org.graalvm.compiler.nodes.ConstantNode;
  38 import org.graalvm.compiler.nodes.FixedWithNextNode;
  39 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  40 import org.graalvm.compiler.nodes.ValueNode;
  41 import org.graalvm.compiler.nodes.ValueNodeUtil;
  42 import org.graalvm.compiler.nodes.memory.MemoryAccess;
  43 import org.graalvm.compiler.nodes.memory.MemoryNode;
  44 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  45 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  46 import org.graalvm.compiler.nodes.spi.Virtualizable;
  47 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
  48 import org.graalvm.compiler.nodes.util.GraphUtil;
  49 import jdk.internal.vm.compiler.word.LocationIdentity;
  50 
  51 import jdk.vm.ci.meta.JavaKind;
  52 import jdk.vm.ci.meta.Value;
  53 
  54 // JaCoCo Exclude
  55 
  56 /**
  57  * Compares two arrays lexicographically.
  58  */
  59 @NodeInfo(cycles = CYCLES_1024, size = SIZE_1024)
  60 public final class ArrayCompareToNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
  61 
  62     public static final NodeClass<ArrayCompareToNode> TYPE = NodeClass.create(ArrayCompareToNode.class);
  63 
  64     /** {@link JavaKind} of one array to compare. */
  65     protected final JavaKind kind1;
  66 
  67     /** {@link JavaKind} of the other array to compare. */
  68     protected final JavaKind kind2;
  69 
  70     /** One array to be tested for equality. */
  71     @Input ValueNode array1;
  72 
  73     /** The other array to be tested for equality. */
  74     @Input ValueNode array2;
  75 
  76     /** Length of one array. */
  77     @Input ValueNode length1;
  78 
  79     /** Length of the other array. */
  80     @Input ValueNode length2;
  81 
  82     @OptionalInput(Memory) MemoryNode lastLocationAccess;
  83 
  84     public ArrayCompareToNode(ValueNode array1, ValueNode array2, ValueNode length1, ValueNode length2, @ConstantNodeParameter JavaKind kind1, @ConstantNodeParameter JavaKind kind2) {
  85         super(TYPE, StampFactory.forKind(JavaKind.Int));
  86         this.kind1 = kind1;
  87         this.kind2 = kind2;
  88         this.array1 = array1;
  89         this.array2 = array2;
  90         this.length1 = length1;
  91         this.length2 = length2;
  92     }
  93 
  94     @Override
  95     public Node canonical(CanonicalizerTool tool) {
  96         if (tool.allUsagesAvailable() && hasNoUsages()) {
  97             return null;
  98         }
  99         ValueNode a1 = GraphUtil.unproxify(array1);
 100         ValueNode a2 = GraphUtil.unproxify(array2);
 101         if (a1 == a2) {
 102             return ConstantNode.forInt(0);
 103         }
 104         return this;
 105     }
 106 
 107     @Override
 108     public void virtualize(VirtualizerTool tool) {
 109         ValueNode alias1 = tool.getAlias(array1);
 110         ValueNode alias2 = tool.getAlias(array2);
 111         if (alias1 == alias2) {
 112             // the same virtual objects will always have the same contents
 113             tool.replaceWithValue(ConstantNode.forInt(0, graph()));
 114         }
 115     }
 116 
 117     @NodeIntrinsic
 118     public static native int compareTo(Object array1, Object array2, int length1, int length2, @ConstantNodeParameter JavaKind kind1, @ConstantNodeParameter JavaKind kind2);
 119 
 120     @Override
 121     public void generate(NodeLIRBuilderTool gen) {
 122         Value result = gen.getLIRGeneratorTool().emitArrayCompareTo(kind1, kind2, gen.operand(array1), gen.operand(array2), gen.operand(length1), gen.operand(length2));
 123         gen.setResult(this, result);
 124     }
 125 
 126     @Override
 127     public LocationIdentity getLocationIdentity() {
 128         return kind1 != kind2 ? LocationIdentity.ANY_LOCATION : NamedLocationIdentity.getArrayLocation(kind1);
 129     }
 130 
 131     @Override
 132     public MemoryNode getLastLocationAccess() {
 133         return lastLocationAccess;
 134     }
 135 
 136     @Override
 137     public void setLastLocationAccess(MemoryNode lla) {
 138         updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla));
 139         lastLocationAccess = lla;
 140     }
 141 }