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