1 /*
2  * Copyright (c) 2011, 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.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, ArithmeticOpTable::getXor, x, y);
54         assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT));
55     }
56 
create(ValueNode x, ValueNode y, NodeView view)57     public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
58         BinaryOp<Xor> op = ArithmeticOpTable.forStamp(x.stamp(view)).getXor();
59         Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view));
60         ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp, view);
61         if (tryConstantFold != null) {
62             return tryConstantFold;
63         }
64         return canonical(null, op, stamp, x, y, view);
65     }
66 
67     @Override
canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY)68     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
69         ValueNode ret = super.canonical(tool, forX, forY);
70         if (ret != this) {
71             return ret;
72         }
73 
74         NodeView view = NodeView.from(tool);
75         return canonical(this, getOp(forX, forY), stamp(NodeView.DEFAULT), forX, forY, view);
76     }
77 
canonical(XorNode self, BinaryOp<Xor> op, Stamp stamp, ValueNode forX, ValueNode forY, NodeView view)78     private static ValueNode canonical(XorNode self, BinaryOp<Xor> op, Stamp stamp, ValueNode forX, ValueNode forY, NodeView view) {
79         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
80             return ConstantNode.forPrimitive(stamp, op.getZero(forX.stamp(view)));
81         }
82         if (forX.isConstant() && !forY.isConstant()) {
83             return new XorNode(forY, forX);
84         }
85         if (forY.isConstant()) {
86             Constant c = forY.asConstant();
87             if (op.isNeutral(c)) {
88                 return forX;
89             }
90 
91             if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
92                 long rawY = ((PrimitiveConstant) c).asLong();
93                 long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp));
94                 if ((rawY & mask) == mask) {
95                     return new NotNode(forX);
96                 }
97             }
98             return reassociate(self != null ? self : (XorNode) new XorNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY, view);
99         }
100         return self != null ? self : new XorNode(forX, forY).maybeCommuteInputs();
101     }
102 
103     @Override
generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen)104     public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
105         nodeValueMap.setResult(this, gen.emitXor(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
106     }
107 }
108