changeset 16216:388b787a5fe6

implement Canonicalizable.Unary in the UnaryNode hierarchy
author Lukas Stadler <lukas.stadler@oracle.com>
date Wed, 25 Jun 2014 16:35:17 +0200
parents b558af6ff4bc
children 561070049e73
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java
diffstat 18 files changed, 154 insertions(+), 133 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -40,7 +40,7 @@
  * Compress or uncompress an oop or metaspace pointer.
  */
 @NodeInfo(nameTemplate = "{p#op/s}")
-public final class CompressionNode extends ConvertNode implements LIRLowerable, Canonicalizable {
+public final class CompressionNode extends ConvertNode implements LIRLowerable {
 
     private enum CompressionOp {
         Compress,
@@ -151,11 +151,11 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getValue().isConstant()) {
-            return ConstantNode.forConstant(stamp(), evalConst(getValue().asConstant()), tool.getMetaAccess(), graph());
-        } else if (getValue() instanceof CompressionNode) {
-            CompressionNode other = (CompressionNode) getValue();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(stamp(), evalConst(forValue.asConstant()), tool.getMetaAccess());
+        } else if (forValue instanceof CompressionNode) {
+            CompressionNode other = (CompressionNode) forValue;
             if (op != other.op && encoding.equals(other.encoding)) {
                 return other.getValue();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -35,7 +35,7 @@
 /**
  * A node that attaches a type profile to a proxied input node.
  */
-public final class TypeProfileProxyNode extends UnaryNode implements Canonicalizable, IterableNodeType, ValueProxy {
+public final class TypeProfileProxyNode extends UnaryNode implements IterableNodeType, ValueProxy {
 
     private final JavaTypeProfile profile;
     private transient ResolvedJavaType lastCheckedType;
@@ -71,12 +71,12 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (StampTool.isExactType(getValue())) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (StampTool.isExactType(forValue)) {
             // The profile is useless - we know the type!
-            return getValue();
-        } else if (getValue() instanceof TypeProfileProxyNode) {
-            TypeProfileProxyNode other = (TypeProfileProxyNode) getValue();
+            return forValue;
+        } else if (forValue instanceof TypeProfileProxyNode) {
+            TypeProfileProxyNode other = (TypeProfileProxyNode) forValue;
             JavaTypeProfile otherProfile = other.getProfile();
             if (otherProfile == lastCheckedProfile) {
                 // We have already incorporated the knowledge about this profile => abort.
@@ -87,33 +87,33 @@
             if (newProfile.equals(otherProfile)) {
                 // We are useless - just use the other proxy node.
                 Debug.log("Canonicalize with other proxy node.");
-                return getValue();
+                return forValue;
             }
             if (newProfile != this.profile) {
                 Debug.log("Improved profile via other profile.");
-                return TypeProfileProxyNode.create(getValue(), newProfile);
+                return new TypeProfileProxyNode(forValue, newProfile);
             }
-        } else if (StampTool.typeOrNull(getValue()) != null) {
-            ResolvedJavaType type = StampTool.typeOrNull(getValue());
+        } else if (StampTool.typeOrNull(forValue) != null) {
+            ResolvedJavaType type = StampTool.typeOrNull(forValue);
             ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype();
             if (uniqueConcrete != null) {
                 // Profile is useless => remove.
                 Debug.log("Profile useless, there is enough static type information available.");
-                return getValue();
+                return forValue;
             }
             if (Objects.equals(type, lastCheckedType)) {
                 // We have already incorporate the knowledge about this type => abort.
                 return this;
             }
             lastCheckedType = type;
-            JavaTypeProfile newProfile = this.profile.restrict(type, StampTool.isObjectNonNull(getValue()));
+            JavaTypeProfile newProfile = this.profile.restrict(type, StampTool.isObjectNonNull(forValue));
             if (newProfile != this.profile) {
                 Debug.log("Improved profile via static type information.");
                 if (newProfile.getTypes().length == 0) {
                     // Only null profiling is not beneficial enough to keep the node around.
-                    return getValue();
+                    return forValue;
                 }
-                return TypeProfileProxyNode.create(getValue(), newProfile);
+                return new TypeProfileProxyNode(forValue, newProfile);
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -36,7 +35,7 @@
  * A {@code FloatConvert} converts between integers and floating point numbers according to Java
  * semantics.
  */
-public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
+public class FloatConvertNode extends ConvertNode implements Lowerable, ArithmeticLIRLowerable {
 
     private final FloatConvert op;
 
@@ -147,11 +146,11 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getValue().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(getValue().asConstant()), graph());
-        } else if (getValue() instanceof FloatConvertNode) {
-            FloatConvertNode other = (FloatConvertNode) getValue();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
+        } else if (forValue instanceof FloatConvertNode) {
+            FloatConvertNode other = (FloatConvertNode) forValue;
             if (other.isLossless() && other.op == this.op.reverse()) {
                 return other.getValue();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -22,16 +22,14 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
-public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable {
 
     private final int resultBits;
 
@@ -60,18 +58,16 @@
         }
     }
 
-    protected ValueNode canonicalConvert() {
-        if (getValue().stamp() instanceof IntegerStamp) {
-            int inputBits = ((IntegerStamp) getValue().stamp()).getBits();
+    protected ValueNode canonicalConvert(ValueNode value) {
+        if (value.stamp() instanceof IntegerStamp) {
+            int inputBits = ((IntegerStamp) value.stamp()).getBits();
             if (inputBits == resultBits) {
-                return getValue();
-            } else if (getValue().isConstant()) {
-                Constant ret = evalConst(getValue().asConstant());
-                return ConstantNode.forIntegerBits(resultBits, ret.asLong(), graph());
+                return value;
+            } else if (value.isConstant()) {
+                return ConstantNode.forIntegerBits(resultBits, evalConst(value.asConstant()).asLong());
             }
         }
-
-        return null;
+        return this;
     }
 
     public static ValueNode convert(ValueNode input, Stamp stamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -62,20 +61,20 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode ret = canonicalConvert();
-        if (ret != null) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = canonicalConvert(forValue);
+        if (ret != this) {
             return ret;
         }
 
-        if (getValue() instanceof NarrowNode) {
+        if (forValue instanceof NarrowNode) {
             // zzzzzzzz yyyyxxxx -(narrow)-> yyyyxxxx -(narrow)-> xxxx
             // ==> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
-            NarrowNode other = (NarrowNode) getValue();
-            return graph().unique(new NarrowNode(other.getValue(), getResultBits()));
-        } else if (getValue() instanceof IntegerConvertNode) {
+            NarrowNode other = (NarrowNode) forValue;
+            return new NarrowNode(other.getValue(), getResultBits());
+        } else if (forValue instanceof IntegerConvertNode) {
             // SignExtendNode or ZeroExtendNode
-            IntegerConvertNode other = (IntegerConvertNode) getValue();
+            IntegerConvertNode other = (IntegerConvertNode) forValue;
             if (getResultBits() == other.getInputBits()) {
                 // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx
                 // ==> no-op
@@ -83,20 +82,19 @@
             } else if (getResultBits() < other.getInputBits()) {
                 // yyyyxxxx -(extend)-> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
                 // ==> yyyyxxxx -(narrow)-> xxxx
-                return graph().unique(new NarrowNode(other.getValue(), getResultBits()));
+                return new NarrowNode(other.getValue(), getResultBits());
             } else {
                 if (other instanceof SignExtendNode) {
                     // sxxx -(sign-extend)-> ssssssss sssssxxx -(narrow)-> sssssxxx
                     // ==> sxxx -(sign-extend)-> sssssxxx
-                    return graph().unique(new SignExtendNode(other.getValue(), getResultBits()));
+                    return new SignExtendNode(other.getValue(), getResultBits());
                 } else if (other instanceof ZeroExtendNode) {
                     // xxxx -(zero-extend)-> 00000000 00000xxx -(narrow)-> 0000xxxx
                     // ==> xxxx -(zero-extend)-> 0000xxxx
-                    return graph().unique(new ZeroExtendNode(other.getValue(), getResultBits()));
+                    return new ZeroExtendNode(other.getValue(), getResultBits());
                 }
             }
         }
-
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, 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
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -34,7 +33,7 @@
 /**
  * The {@code NegateNode} node negates its operand.
  */
-public final class NegateNode extends UnaryNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
+public final class NegateNode extends UnaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @Override
     public boolean inferStamp() {
@@ -68,16 +67,16 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getValue().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(getValue().asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
         }
-        if (getValue() instanceof NegateNode) {
-            return ((NegateNode) getValue()).getValue();
+        if (forValue instanceof NegateNode) {
+            return ((NegateNode) forValue).getValue();
         }
-        if (getValue() instanceof IntegerSubNode) {
-            IntegerSubNode sub = (IntegerSubNode) getValue();
-            return IntegerArithmeticNode.sub(graph(), sub.getY(), sub.getX());
+        if (forValue instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) forValue;
+            return new IntegerSubNode(sub.getY(), sub.getX());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -34,7 +33,7 @@
 /**
  * Binary negation of long or integer values.
  */
-public final class NotNode extends UnaryNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
+public final class NotNode extends UnaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @Override
     public boolean inferStamp() {
@@ -57,12 +56,12 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getValue().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(getValue().asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
         }
-        if (getValue() instanceof NotNode) {
-            return ((NotNode) getValue()).getValue();
+        if (forValue instanceof NotNode) {
+            return ((NotNode) forValue).getValue();
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -36,7 +35,7 @@
  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  * the old stamp.
  */
-public class ReinterpretNode extends UnaryNode implements Canonicalizable, ArithmeticLIRLowerable {
+public class ReinterpretNode extends UnaryNode implements ArithmeticLIRLowerable {
 
     private ReinterpretNode(Kind to, ValueNode value) {
         this(StampFactory.forKind(to), value);
@@ -81,16 +80,16 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getValue().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(getValue().asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
         }
-        if (stamp().isCompatible(getValue().stamp())) {
-            return getValue();
+        if (stamp().isCompatible(forValue.stamp())) {
+            return forValue;
         }
-        if (getValue() instanceof ReinterpretNode) {
-            ReinterpretNode reinterpret = (ReinterpretNode) getValue();
-            return getValue().graph().unique(new ReinterpretNode(stamp(), reinterpret.getValue()));
+        if (forValue instanceof ReinterpretNode) {
+            ReinterpretNode reinterpret = (ReinterpretNode) forValue;
+            return new ReinterpretNode(stamp(), reinterpret.getValue());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -68,32 +67,32 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode ret = canonicalConvert();
-        if (ret != null) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = canonicalConvert(forValue);
+        if (ret != this) {
             return ret;
         }
 
-        if (getValue() instanceof SignExtendNode) {
+        if (forValue instanceof SignExtendNode) {
             // sxxx -(sign-extend)-> ssss sxxx -(sign-extend)-> ssssssss sssssxxx
             // ==> sxxx -(sign-extend)-> ssssssss sssssxxx
-            SignExtendNode other = (SignExtendNode) getValue();
-            return graph().unique(new SignExtendNode(other.getValue(), getResultBits()));
-        } else if (getValue() instanceof ZeroExtendNode) {
-            ZeroExtendNode other = (ZeroExtendNode) getValue();
+            SignExtendNode other = (SignExtendNode) forValue;
+            return new SignExtendNode(other.getValue(), getResultBits());
+        } else if (forValue instanceof ZeroExtendNode) {
+            ZeroExtendNode other = (ZeroExtendNode) forValue;
             if (other.getResultBits() > other.getInputBits()) {
                 // sxxx -(zero-extend)-> 0000 sxxx -(sign-extend)-> 00000000 0000sxxx
                 // ==> sxxx -(zero-extend)-> 00000000 0000sxxx
-                return graph().unique(new ZeroExtendNode(other.getValue(), getResultBits()));
+                return new ZeroExtendNode(other.getValue(), getResultBits());
             }
         }
 
-        if (getValue().stamp() instanceof IntegerStamp) {
-            IntegerStamp inputStamp = (IntegerStamp) getValue().stamp();
+        if (forValue.stamp() instanceof IntegerStamp) {
+            IntegerStamp inputStamp = (IntegerStamp) forValue.stamp();
             if ((inputStamp.upMask() & (1L << (getInputBits() - 1))) == 0L) {
                 // 0xxx -(sign-extend)-> 0000 0xxx
                 // ==> 0xxx -(zero-extend)-> 0000 0xxx
-                return graph().unique(new ZeroExtendNode(getValue(), getResultBits()));
+                return new ZeroExtendNode(forValue, getResultBits());
             }
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -23,13 +23,14 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * The {@code UnaryNode} class is the base of arithmetic and bit logic operations with exactly one
  * input.
  */
-public abstract class UnaryNode extends FloatingNode {
+public abstract class UnaryNode extends FloatingNode implements Canonicalizable.Unary<ValueNode> {
 
     @Input private ValueNode value;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -78,20 +77,20 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode ret = canonicalConvert();
-        if (ret != null) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = canonicalConvert(forValue);
+        if (ret != this) {
             return ret;
         }
 
-        if (getValue() instanceof ZeroExtendNode) {
+        if (forValue instanceof ZeroExtendNode) {
             // xxxx -(zero-extend)-> 0000 xxxx -(zero-extend)-> 00000000 0000xxxx
             // ==> xxxx -(zero-extend)-> 00000000 0000xxxx
-            ZeroExtendNode other = (ZeroExtendNode) getValue();
-            return graph().unique(new ZeroExtendNode(other.getValue(), getResultBits()));
+            ZeroExtendNode other = (ZeroExtendNode) forValue;
+            return new ZeroExtendNode(other.getValue(), getResultBits());
         }
-        if (getValue() instanceof NarrowNode) {
-            NarrowNode narrow = (NarrowNode) getValue();
+        if (forValue instanceof NarrowNode) {
+            NarrowNode narrow = (NarrowNode) forValue;
             Stamp inputStamp = narrow.getValue().stamp();
             if (inputStamp instanceof IntegerStamp && inputStamp.isCompatible(stamp())) {
                 IntegerStamp istamp = (IntegerStamp) inputStamp;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -39,7 +38,7 @@
  * This node represents the boxing of a primitive value. This corresponds to a call to the valueOf
  * methods in Integer, Long, etc.
  */
-public class BoxNode extends UnaryNode implements VirtualizableAllocation, Lowerable, Canonicalizable {
+public class BoxNode extends UnaryNode implements VirtualizableAllocation, Lowerable {
 
     private final Kind boxingKind;
 
@@ -58,14 +57,11 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         /*
          * Constant values are not canonicalized into their constant boxing objects because this
          * would mean that the information that they came from a valueOf is lost.
          */
-        if (usages().isEmpty()) {
-            return null;
-        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -24,13 +24,12 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class UnboxNode extends UnaryNode implements Virtualizable, Lowerable, Canonicalizable {
+public class UnboxNode extends UnaryNode implements Virtualizable, Lowerable {
 
     private final Kind boxingKind;
 
@@ -61,22 +60,19 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getValue().isConstant()) {
-            Constant constant = getValue().asConstant();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant constant = forValue.asConstant();
             Constant unboxed = tool.getConstantReflection().unboxPrimitive(constant);
             if (unboxed != null && unboxed.getKind() == boxingKind) {
-                return ConstantNode.forConstant(unboxed, tool.getMetaAccess(), graph());
+                return ConstantNode.forConstant(unboxed, tool.getMetaAccess());
             }
-        } else if (getValue() instanceof BoxNode) {
-            BoxNode box = (BoxNode) getValue();
+        } else if (forValue instanceof BoxNode) {
+            BoxNode box = (BoxNode) forValue;
             if (boxingKind == box.getBoxingKind()) {
                 return box.getValue();
             }
         }
-        if (usages().isEmpty()) {
-            return null;
-        }
         return this;
     }
 
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -50,6 +51,12 @@
         throw GraalInternalError.shouldNotReachHere();
     }
 
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        // nothing to do
+        return this;
+    }
+
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getValue())));
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -24,13 +24,12 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class BitCountNode extends UnaryNode implements LIRLowerable, Canonicalizable {
+public class BitCountNode extends UnaryNode implements LIRLowerable {
 
     public BitCountNode(ValueNode value) {
         super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
@@ -46,14 +45,10 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getValue().isConstant()) {
-            Constant c = getValue().asConstant();
-            if (c.getKind() == Kind.Int) {
-                return ConstantNode.forInt(Integer.bitCount(c.asInt()), graph());
-            } else if (c.getKind() == Kind.Long) {
-                return ConstantNode.forInt(Long.bitCount(c.asLong()), graph());
-            }
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant c = forValue.asConstant();
+            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? bitCount(c.asInt()) : bitCount(c.asLong()));
         }
         return this;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -24,10 +24,15 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
+/**
+ * Determines the index of the least significant "1" bit. Note that the result is undefined if the
+ * input is zero.
+ */
 public class BitScanForwardNode extends UnaryNode implements LIRLowerable {
 
     public BitScanForwardNode(ValueNode value) {
@@ -54,6 +59,15 @@
         return updateStamp(StampFactory.forInteger(Kind.Int, min, max));
     }
 
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant c = forValue.asConstant();
+            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? scan(c.asInt()) : scan(c.asLong()));
+        }
+        return this;
+    }
+
     @NodeIntrinsic
     public static int scan(long v) {
         if (v == 0) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -24,10 +24,15 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
+/**
+ * Determines the index of the most significant "1" bit. Note that the result is undefined if the
+ * input is zero.
+ */
 public class BitScanReverseNode extends UnaryNode implements LIRLowerable {
 
     public BitScanReverseNode(ValueNode value) {
@@ -52,6 +57,15 @@
         return updateStamp(StampFactory.forInteger(Kind.Int, min, max));
     }
 
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant c = forValue.asConstant();
+            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? scan(c.asInt()) : scan(c.asLong()));
+        }
+        return this;
+    }
+
     @NodeIntrinsic
     public static int scan(int v) {
         if (v == 0) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Wed Jun 25 16:35:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Wed Jun 25 16:35:17 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
@@ -51,6 +52,15 @@
         return updateStamp(newStamp);
     }
 
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant c = forValue.asConstant();
+            return ConstantNode.forIntegerKind(getKind(), getKind() == Kind.Int ? reverse(c.asInt()) : reverse(c.asLong()));
+        }
+        return this;
+    }
+
     @NodeIntrinsic
     public static int reverse(int v) {
         return Integer.reverseBytes(v);