1 /*
   2  * Copyright (c) 2012, 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 com.oracle.graal.replacements.nodes;
  24 
  25 import com.oracle.graal.api.meta.*;
  26 import com.oracle.graal.compiler.gen.*;
  27 import com.oracle.graal.compiler.target.*;
  28 import com.oracle.graal.graph.*;
  29 import com.oracle.graal.lir.*;
  30 import com.oracle.graal.nodes.*;
  31 import com.oracle.graal.nodes.calc.*;
  32 import com.oracle.graal.nodes.spi.*;
  33 import com.oracle.graal.nodes.type.*;
  34 
  35 public class MathIntrinsicNode extends FloatingNode implements Canonicalizable, LIRGenLowerable {
  36 
  37     @Input private ValueNode x;
  38     private final Operation operation;
  39 
  40     public enum Operation {
  41         ABS, SQRT, LOG, LOG10, SIN, COS, TAN
  42     }
  43 
  44     public ValueNode x() {
  45         return x;
  46     }
  47 
  48     public Operation operation() {
  49         return operation;
  50     }
  51 
  52     public MathIntrinsicNode(ValueNode x, Operation op) {
  53         super(StampFactory.forKind(x.kind()));
  54         assert x.kind() == Kind.Double;
  55         this.x = x;
  56         this.operation = op;
  57     }
  58 
  59     @Override
  60     public void generate(LIRGenerator gen) {
  61         Variable input = gen.load(gen.operand(x()));
  62         Variable result = gen.newVariable(kind());
  63         switch (operation()) {
  64             case ABS:
  65                 gen.emitMathAbs(result, input);
  66                 break;
  67             case SQRT:
  68                 gen.emitMathSqrt(result, input);
  69                 break;
  70             case LOG:
  71                 gen.emitMathLog(result, input, false);
  72                 break;
  73             case LOG10:
  74                 gen.emitMathLog(result, input, true);
  75                 break;
  76             case SIN:
  77                 gen.emitMathSin(result, input);
  78                 break;
  79             case COS:
  80                 gen.emitMathCos(result, input);
  81                 break;
  82             case TAN:
  83                 gen.emitMathTan(result, input);
  84                 break;
  85             default:
  86                 throw GraalInternalError.shouldNotReachHere();
  87         }
  88         gen.setResult(this, result);
  89     }
  90 
  91     @Override
  92     public ValueNode canonical(CanonicalizerTool tool) {
  93         if (x().isConstant()) {
  94             double value = x().asConstant().asDouble();
  95             switch (operation()) {
  96                 case ABS:
  97                     return ConstantNode.forDouble(Math.abs(value), graph());
  98                 case SQRT:
  99                     return ConstantNode.forDouble(Math.sqrt(value), graph());
 100                 case LOG:
 101                     return ConstantNode.forDouble(Math.log(value), graph());
 102                 case LOG10:
 103                     return ConstantNode.forDouble(Math.log10(value), graph());
 104                 case SIN:
 105                     return ConstantNode.forDouble(Math.sin(value), graph());
 106                 case COS:
 107                     return ConstantNode.forDouble(Math.cos(value), graph());
 108                 case TAN:
 109                     return ConstantNode.forDouble(Math.tan(value), graph());
 110                 default:
 111                     throw GraalInternalError.shouldNotReachHere();
 112             }
 113         }
 114         return this;
 115     }
 116 
 117     @NodeIntrinsic
 118     public static double compute(double value, @ConstantNodeParameter Operation op) {
 119         switch (op) {
 120             case ABS:
 121                 return Math.abs(value);
 122             case SQRT:
 123                 return Math.sqrt(value);
 124             case LOG:
 125                 return Math.log(value);
 126             case LOG10:
 127                 return Math.log10(value);
 128             case SIN:
 129                 return Math.sin(value);
 130             case COS:
 131                 return Math.cos(value);
 132             case TAN:
 133                 return Math.tan(value);
 134         }
 135         throw new GraalInternalError("unknown op %s", op);
 136     }
 137 }