1 /*
   2  * Copyright (c) 2011, 2015, 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.ArithmeticOpTable;
  26 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
  27 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul;
  28 import org.graalvm.compiler.core.common.type.Stamp;
  29 import org.graalvm.compiler.graph.NodeClass;
  30 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
  31 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  32 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
  33 import org.graalvm.compiler.nodeinfo.NodeCycles;
  34 import org.graalvm.compiler.nodeinfo.NodeInfo;
  35 import org.graalvm.compiler.nodes.ConstantNode;
  36 import org.graalvm.compiler.nodes.ValueNode;
  37 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  38 
  39 import jdk.vm.ci.code.CodeUtil;
  40 import jdk.vm.ci.meta.Constant;
  41 import jdk.vm.ci.meta.PrimitiveConstant;
  42 import jdk.vm.ci.meta.Value;
  43 
  44 @NodeInfo(shortName = "*", cycles = NodeCycles.CYCLES_3)
  45 public class MulNode extends BinaryArithmeticNode<Mul> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
  46 
  47     public static final NodeClass<MulNode> TYPE = NodeClass.create(MulNode.class);
  48 
  49     public MulNode(ValueNode x, ValueNode y) {
  50         this(TYPE, x, y);
  51     }
  52 
  53     protected MulNode(NodeClass<? extends MulNode> c, ValueNode x, ValueNode y) {
  54         super(c, ArithmeticOpTable::getMul, x, y);
  55     }
  56 
  57     public static ValueNode create(ValueNode x, ValueNode y) {
  58         BinaryOp<Mul> op = ArithmeticOpTable.forStamp(x.stamp()).getMul();
  59         Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
  60         ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
  61         if (tryConstantFold != null) {
  62             return tryConstantFold;
  63         } else {
  64             return new MulNode(x, y).maybeCommuteInputs();
  65         }
  66     }
  67 
  68     @Override
  69     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
  70         ValueNode ret = super.canonical(tool, forX, forY);
  71         if (ret != this) {
  72             return ret;
  73         }
  74 
  75         if (forX.isConstant() && !forY.isConstant()) {
  76             // we try to swap and canonicalize
  77             ValueNode improvement = canonical(tool, forY, forX);
  78             if (improvement != this) {
  79                 return improvement;
  80             }
  81             // if this fails we only swap
  82             return new MulNode(forY, forX);
  83         }
  84         if (forY.isConstant()) {
  85             BinaryOp<Mul> op = getOp(forX, forY);
  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 i = ((PrimitiveConstant) c).asLong();
  93                 if (i > 0 && CodeUtil.isPowerOf2(i)) {
  94                     return new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i)));
  95                 }
  96                 if (i == 0) {
  97                     return ConstantNode.forIntegerStamp(stamp, 0);
  98                 }
  99             }
 100 
 101             if (op.isAssociative()) {
 102                 // canonicalize expressions like "(a * 1) * 2"
 103                 return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
 104             }
 105         }
 106         return this;
 107     }
 108 
 109     @Override
 110     public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
 111         Value op1 = nodeValueMap.operand(getX());
 112         Value op2 = nodeValueMap.operand(getY());
 113         if (shouldSwapInputs(nodeValueMap)) {
 114             Value tmp = op1;
 115             op1 = op2;
 116             op2 = tmp;
 117         }
 118         nodeValueMap.setResult(this, gen.emitMul(op1, op2, false));
 119     }
 120 }