1 /*
   2  * Copyright (c) 2009, 2015, 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 package org.graalvm.compiler.nodes;
  24 
  25 import java.util.Map;
  26 
  27 import org.graalvm.compiler.core.common.type.Stamp;
  28 import org.graalvm.compiler.core.common.type.StampFactory;
  29 import org.graalvm.compiler.graph.NodeClass;
  30 import org.graalvm.compiler.graph.NodeInputList;
  31 import org.graalvm.compiler.nodeinfo.NodeInfo;
  32 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
  33 import org.graalvm.compiler.nodes.type.StampTool;
  34 import org.graalvm.compiler.nodes.util.GraphUtil;
  35 import org.graalvm.util.CollectionsUtil;
  36 
  37 /**
  38  * Value {@link PhiNode}s merge data flow values at control flow merges.
  39  */
  40 @NodeInfo(nameTemplate = "Phi({i#values}, {p#valueDescription})")
  41 public class ValuePhiNode extends PhiNode implements ArrayLengthProvider {
  42 
  43     public static final NodeClass<ValuePhiNode> TYPE = NodeClass.create(ValuePhiNode.class);
  44     @Input protected NodeInputList<ValueNode> values;
  45 
  46     public ValuePhiNode(Stamp stamp, AbstractMergeNode merge) {
  47         this(TYPE, stamp, merge);
  48     }
  49 
  50     protected ValuePhiNode(NodeClass<? extends ValuePhiNode> c, Stamp stamp, AbstractMergeNode merge) {
  51         super(c, stamp, merge);
  52         assert stamp != StampFactory.forVoid();
  53         values = new NodeInputList<>(this);
  54     }
  55 
  56     public ValuePhiNode(Stamp stamp, AbstractMergeNode merge, ValueNode[] values) {
  57         super(TYPE, stamp, merge);
  58         assert stamp != StampFactory.forVoid();
  59         this.values = new NodeInputList<>(this, values);
  60     }
  61 
  62     @Override
  63     public NodeInputList<ValueNode> values() {
  64         return values;
  65     }
  66 
  67     @Override
  68     public boolean inferStamp() {
  69         /*
  70          * Meet all the values feeding this Phi but don't use the stamp of this Phi since that's
  71          * what's being computed.
  72          */
  73         Stamp valuesStamp = StampTool.meetOrNull(values(), this);
  74         if (valuesStamp == null) {
  75             valuesStamp = stamp;
  76         } else if (stamp.isCompatible(valuesStamp)) {
  77             valuesStamp = stamp.join(valuesStamp);
  78         }
  79         return updateStamp(valuesStamp);
  80     }
  81 
  82     @Override
  83     public ValueNode length() {
  84         if (merge() instanceof LoopBeginNode) {
  85             return null;
  86         }
  87         ValueNode length = null;
  88         for (ValueNode input : values()) {
  89             ValueNode l = GraphUtil.arrayLength(input);
  90             if (l == null) {
  91                 return null;
  92             }
  93             if (length == null) {
  94                 length = l;
  95             } else if (length != l) {
  96                 return null;
  97             }
  98         }
  99         return length;
 100     }
 101 
 102     @Override
 103     public boolean verify() {
 104         Stamp s = null;
 105         for (ValueNode input : values()) {
 106             assert input != null;
 107             if (s == null) {
 108                 s = input.stamp();
 109             } else {
 110                 if (!s.isCompatible(input.stamp())) {
 111                     fail("Phi Input Stamps are not compatible. Phi:%s inputs:%s", this,
 112                                     CollectionsUtil.mapAndJoin(values(), x -> x.toString() + ":" + x.stamp(), ", "));
 113                 }
 114             }
 115         }
 116         return super.verify();
 117     }
 118 
 119     @Override
 120     protected String valueDescription() {
 121         return stamp().unrestricted().toString();
 122     }
 123 
 124     @Override
 125     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
 126         Map<Object, Object> properties = super.getDebugProperties(map);
 127         properties.put("valueDescription", valueDescription());
 128         return properties;
 129     }
 130 }