1 /*
2  * Copyright (c) 2011, 2019, 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.nodes.calc;
26 
27 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
28 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
29 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor;
30 import org.graalvm.compiler.core.common.type.PrimitiveStamp;
31 import org.graalvm.compiler.core.common.type.Stamp;
32 import org.graalvm.compiler.graph.NodeClass;
33 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
34 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
35 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
36 import org.graalvm.compiler.nodeinfo.NodeInfo;
37 import org.graalvm.compiler.nodes.ConstantNode;
38 import org.graalvm.compiler.nodes.NodeView;
39 import org.graalvm.compiler.nodes.ValueNode;
40 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
41 import org.graalvm.compiler.nodes.util.GraphUtil;
42 
43 import jdk.vm.ci.code.CodeUtil;
44 import jdk.vm.ci.meta.Constant;
45 import jdk.vm.ci.meta.PrimitiveConstant;
46 
47 @NodeInfo(shortName = "^")
48 public final class XorNode extends BinaryArithmeticNode<Xor> implements BinaryCommutative<ValueNode>, NarrowableArithmeticNode {
49 
50     public static final NodeClass<XorNode> TYPE = NodeClass.create(XorNode.class);
51 
XorNode(ValueNode x, ValueNode y)52     public XorNode(ValueNode x, ValueNode y) {
53         super(TYPE, getArithmeticOpTable(x).getXor(), x, y);
54         assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT));
55     }
56 
XorNode(ValueNode x, ValueNode y, Stamp forcedStamp)57     private XorNode(ValueNode x, ValueNode y, Stamp forcedStamp) {
58         super(TYPE, forcedStamp, x, y);
59     }
60 
61     /**
62      * Create a new XorNode with a forced stamp, without eager folding. This should only be used in
63      * snippet code, where native-image may assign wrong stamps during graph generation.
64      */
createForSnippet(ValueNode x, ValueNode y, Stamp forcedStamp)65     public static ValueNode createForSnippet(ValueNode x, ValueNode y, Stamp forcedStamp) {
66         return new XorNode(x, y, forcedStamp);
67     }
68 
create(ValueNode x, ValueNode y, NodeView view)69     public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
70         BinaryOp<Xor> op = ArithmeticOpTable.forStamp(x.stamp(view)).getXor();
71         Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view));
72         ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp, view);
73         if (tryConstantFold != null) {
74             return tryConstantFold;
75         }
76         return canonical(null, op, stamp, x, y, view);
77     }
78 
79     @Override
getOp(ArithmeticOpTable table)80     protected BinaryOp<Xor> getOp(ArithmeticOpTable table) {
81         return table.getXor();
82     }
83 
84     @Override
canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY)85     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
86         ValueNode ret = super.canonical(tool, forX, forY);
87         if (ret != this) {
88             return ret;
89         }
90 
91         NodeView view = NodeView.from(tool);
92         return canonical(this, getOp(forX, forY), stamp(NodeView.DEFAULT), forX, forY, view);
93     }
94 
canonical(XorNode self, BinaryOp<Xor> op, Stamp stamp, ValueNode forX, ValueNode forY, NodeView view)95     private static ValueNode canonical(XorNode self, BinaryOp<Xor> op, Stamp stamp, ValueNode forX, ValueNode forY, NodeView view) {
96         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
97             return ConstantNode.forPrimitive(stamp, op.getZero(forX.stamp(view)));
98         }
99         if (forX.isConstant() && !forY.isConstant()) {
100             return new XorNode(forY, forX);
101         }
102         if (forY.isConstant()) {
103             Constant c = forY.asConstant();
104             if (op.isNeutral(c)) {
105                 return forX;
106             }
107 
108             if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
109                 long rawY = ((PrimitiveConstant) c).asLong();
110                 long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp));
111                 if ((rawY & mask) == mask) {
112                     return new NotNode(forX);
113                 }
114             }
115             return reassociate(self != null ? self : (XorNode) new XorNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY, view);
116         }
117         return self != null ? self : new XorNode(forX, forY).maybeCommuteInputs();
118     }
119 
120     @Override
generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen)121     public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
122         nodeValueMap.setResult(this, gen.emitXor(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
123     }
124 }
125