1 /* 2 * Copyright (c) 2011, 2016, 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 package org.graalvm.compiler.nodes.calc; 24 25 import org.graalvm.compiler.core.common.type.IntegerStamp; 26 import org.graalvm.compiler.core.common.type.PrimitiveStamp; 27 import org.graalvm.compiler.graph.NodeClass; 28 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 29 import org.graalvm.compiler.nodeinfo.NodeInfo; 30 import org.graalvm.compiler.nodes.ConstantNode; 31 import org.graalvm.compiler.nodes.ValueNode; 32 import org.graalvm.compiler.nodes.spi.LIRLowerable; 33 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 34 35 import jdk.vm.ci.code.CodeUtil; 36 37 @NodeInfo(shortName = "/") 38 public class SignedDivNode extends IntegerDivRemNode implements LIRLowerable { 39 40 public static final NodeClass<SignedDivNode> TYPE = NodeClass.create(SignedDivNode.class); 41 42 public SignedDivNode(ValueNode x, ValueNode y) { 43 this(TYPE, x, y); 44 } 45 46 protected SignedDivNode(NodeClass<? extends SignedDivNode> c, ValueNode x, ValueNode y) { 47 super(c, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), Op.DIV, Type.SIGNED, x, y); 48 } 49 50 @Override 51 public boolean inferStamp() { 52 return updateStamp(IntegerStamp.OPS.getDiv().foldStamp(getX().stamp(), getY().stamp())); 53 } 54 55 @Override 56 public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { 57 if (forX.isConstant() && forY.isConstant()) { 58 @SuppressWarnings("hiding") 59 long y = forY.asJavaConstant().asLong(); 60 if (y == 0) { 61 return this; // this will trap, can not canonicalize 62 } 63 return ConstantNode.forIntegerStamp(stamp(), forX.asJavaConstant().asLong() / y); 64 } else if (forY.isConstant()) { 65 long c = forY.asJavaConstant().asLong(); 66 ValueNode v = canonical(forX, c); 67 if (v != null) { 68 return v; 69 } 70 } 71 72 // Convert the expression ((a - a % b) / b) into (a / b). 73 if (forX instanceof SubNode) { 74 SubNode integerSubNode = (SubNode) forX; 75 if (integerSubNode.getY() instanceof SignedRemNode) { 76 SignedRemNode integerRemNode = (SignedRemNode) integerSubNode.getY(); 77 if (integerSubNode.stamp().isCompatible(this.stamp()) && integerRemNode.stamp().isCompatible(this.stamp()) && integerSubNode.getX() == integerRemNode.getX() && 78 forY == integerRemNode.getY()) { 79 SignedDivNode sd = new SignedDivNode(integerSubNode.getX(), forY); 80 sd.stateBefore = this.stateBefore; 81 return sd; 82 } 83 } 84 } 85 86 if (next() instanceof SignedDivNode) { 87 NodeClass<?> nodeClass = getNodeClass(); 88 if (next().getClass() == this.getClass() && nodeClass.equalInputs(this, next()) && valueEquals(next())) { 89 return next(); 90 } 91 } 92 93 return this; 94 } 95 96 public static ValueNode canonical(ValueNode forX, long c) { 97 if (c == 1) { 98 return forX; 99 } 100 if (c == -1) { 101 return NegateNode.create(forX); 102 } 103 long abs = Math.abs(c); 104 if (CodeUtil.isPowerOf2(abs) && forX.stamp() instanceof IntegerStamp) { 105 ValueNode dividend = forX; 106 IntegerStamp stampX = (IntegerStamp) forX.stamp(); 107 int log2 = CodeUtil.log2(abs); 108 // no rounding if dividend is positive or if its low bits are always 0 109 if (stampX.canBeNegative() || (stampX.upMask() & (abs - 1)) != 0) { 110 int bits = PrimitiveStamp.getBits(forX.stamp()); 111 RightShiftNode sign = new RightShiftNode(forX, ConstantNode.forInt(bits - 1)); 112 UnsignedRightShiftNode round = new UnsignedRightShiftNode(sign, ConstantNode.forInt(bits - log2)); 113 dividend = BinaryArithmeticNode.add(dividend, round); 114 } 115 RightShiftNode shift = new RightShiftNode(dividend, ConstantNode.forInt(log2)); 116 if (c < 0) { 117 return NegateNode.create(shift); 118 } 119 return shift; 120 } 121 return null; 122 } 123 124 @Override 125 public void generate(NodeLIRBuilderTool gen) { 126 gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitDiv(gen.operand(getX()), gen.operand(getY()), gen.state(this))); 127 } 128 }