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.IntegerStamp;
28 import org.graalvm.compiler.core.common.type.Stamp;
29 import org.graalvm.compiler.graph.NodeClass;
30 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
31 import org.graalvm.compiler.nodeinfo.NodeInfo;
32 import org.graalvm.compiler.nodes.ConstantNode;
33 import org.graalvm.compiler.nodes.NodeView;
34 import org.graalvm.compiler.nodes.ValueNode;
35 import org.graalvm.compiler.nodes.extended.GuardingNode;
36 import org.graalvm.compiler.nodes.spi.LIRLowerable;
37 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
38 
39 import jdk.vm.ci.code.CodeUtil;
40 
41 @NodeInfo(shortName = "|%|")
42 public class UnsignedRemNode extends IntegerDivRemNode implements LIRLowerable {
43 
44     public static final NodeClass<UnsignedRemNode> TYPE = NodeClass.create(UnsignedRemNode.class);
45 
UnsignedRemNode(ValueNode x, ValueNode y, GuardingNode zeroCheck)46     public UnsignedRemNode(ValueNode x, ValueNode y, GuardingNode zeroCheck) {
47         this(TYPE, x, y, zeroCheck);
48     }
49 
UnsignedRemNode(NodeClass<? extends UnsignedRemNode> c, ValueNode x, ValueNode y, GuardingNode zeroCheck)50     protected UnsignedRemNode(NodeClass<? extends UnsignedRemNode> c, ValueNode x, ValueNode y, GuardingNode zeroCheck) {
51         super(c, x.stamp(NodeView.DEFAULT).unrestricted(), Op.REM, Type.UNSIGNED, x, y, zeroCheck);
52     }
53 
create(ValueNode x, ValueNode y, GuardingNode zeroCheck, NodeView view)54     public static ValueNode create(ValueNode x, ValueNode y, GuardingNode zeroCheck, NodeView view) {
55         Stamp stamp = x.stamp(view).unrestricted();
56         return canonical(null, x, y, zeroCheck, stamp, view);
57     }
58 
59     @Override
canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY)60     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
61         NodeView view = NodeView.from(tool);
62         return canonical(this, forX, forY, getZeroCheck(), stamp(view), view);
63     }
64 
65     @SuppressWarnings("unused")
canonical(UnsignedRemNode self, ValueNode forX, ValueNode forY, GuardingNode zeroCheck, Stamp stamp, NodeView view)66     public static ValueNode canonical(UnsignedRemNode self, ValueNode forX, ValueNode forY, GuardingNode zeroCheck, Stamp stamp, NodeView view) {
67         int bits = ((IntegerStamp) stamp).getBits();
68         if (forX.isConstant() && forY.isConstant()) {
69             long yConst = CodeUtil.zeroExtend(forY.asJavaConstant().asLong(), bits);
70             if (yConst == 0) {
71                 /* This will trap, cannot canonicalize. */
72                 return self != null ? self : new UnsignedRemNode(forX, forY, zeroCheck);
73             }
74             return ConstantNode.forIntegerStamp(stamp, Long.remainderUnsigned(CodeUtil.zeroExtend(forX.asJavaConstant().asLong(), bits), yConst));
75         } else if (forY.isConstant()) {
76             long c = CodeUtil.zeroExtend(forY.asJavaConstant().asLong(), bits);
77             if (c == 1) {
78                 return ConstantNode.forIntegerStamp(stamp, 0);
79             } else if (CodeUtil.isPowerOf2(c)) {
80                 return new AndNode(forX, ConstantNode.forIntegerStamp(stamp, c - 1));
81             }
82         }
83         return self != null ? self : new UnsignedRemNode(forX, forY, zeroCheck);
84     }
85 
86     @Override
generate(NodeLIRBuilderTool gen)87     public void generate(NodeLIRBuilderTool gen) {
88         gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitURem(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
89     }
90 }
91