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.And;
30 import org.graalvm.compiler.core.common.type.IntegerStamp;
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.meta.Constant;
44 import jdk.vm.ci.meta.PrimitiveConstant;
45 
46 @NodeInfo(shortName = "&")
47 public final class AndNode extends BinaryArithmeticNode<And> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
48 
49     public static final NodeClass<AndNode> TYPE = NodeClass.create(AndNode.class);
50 
AndNode(ValueNode x, ValueNode y)51     public AndNode(ValueNode x, ValueNode y) {
52         super(TYPE, getArithmeticOpTable(x).getAnd(), x, y);
53     }
54 
create(ValueNode x, ValueNode y, NodeView view)55     public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
56         BinaryOp<And> op = ArithmeticOpTable.forStamp(x.stamp(view)).getAnd();
57         Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view));
58         ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp, view);
59         if (tryConstantFold != null) {
60             return tryConstantFold;
61         }
62         return canonical(null, op, x, y, view);
63     }
64 
65     @Override
getOp(ArithmeticOpTable table)66     protected BinaryOp<And> getOp(ArithmeticOpTable table) {
67         return table.getAnd();
68     }
69 
70     @Override
canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY)71     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
72         ValueNode ret = super.canonical(tool, forX, forY);
73         if (ret != this) {
74             return ret;
75         }
76 
77         NodeView view = NodeView.from(tool);
78         return canonical(this, getOp(forX, forY), forX, forY, view);
79     }
80 
canonical(AndNode self, BinaryOp<And> op, ValueNode forX, ValueNode forY, NodeView view)81     private static ValueNode canonical(AndNode self, BinaryOp<And> op, ValueNode forX, ValueNode forY, NodeView view) {
82         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
83             return forX;
84         }
85         if (forX.isConstant() && !forY.isConstant()) {
86             return new AndNode(forY, forX);
87         }
88 
89         Stamp rawXStamp = forX.stamp(view);
90         Stamp rawYStamp = forY.stamp(view);
91         if (rawXStamp instanceof IntegerStamp && rawYStamp instanceof IntegerStamp) {
92             IntegerStamp xStamp = (IntegerStamp) rawXStamp;
93             IntegerStamp yStamp = (IntegerStamp) rawYStamp;
94             if (((~xStamp.downMask()) & yStamp.upMask()) == 0) {
95                 return forY;
96             } else if (((~yStamp.downMask()) & xStamp.upMask()) == 0) {
97                 return forX;
98             }
99         }
100 
101         if (forY.isConstant()) {
102             Constant c = forY.asConstant();
103             if (op.isNeutral(c)) {
104                 return forX;
105             }
106 
107             if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
108                 long rawY = ((PrimitiveConstant) c).asLong();
109                 if (forX instanceof SignExtendNode) {
110                     SignExtendNode ext = (SignExtendNode) forX;
111                     if (rawY == ((1L << ext.getInputBits()) - 1)) {
112                         return new ZeroExtendNode(ext.getValue(), ext.getResultBits());
113                     }
114                 }
115             }
116 
117             return reassociate(self != null ? self : (AndNode) new AndNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY, view);
118         }
119         if (forX instanceof NotNode && forY instanceof NotNode) {
120             return new NotNode(OrNode.create(((NotNode) forX).getValue(), ((NotNode) forY).getValue(), view));
121         }
122         return self != null ? self : new AndNode(forX, forY).maybeCommuteInputs();
123     }
124 
125     @Override
generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen)126     public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
127         nodeValueMap.setResult(this, gen.emitAnd(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
128     }
129 }
130