1 /*
  2  * Copyright (c) 2024, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package experiments;
 27 
 28 
 29 import optkl.codebuilders.JavaCodeBuilder;
 30 import optkl.Trxfmr;
 31 import static optkl.OpHelper.Invoke;
 32 import static optkl.OpHelper.Invoke.invoke;
 33 import jdk.incubator.code.Op;
 34 import jdk.incubator.code.bytecode.BytecodeGenerator;
 35 import jdk.incubator.code.dialect.core.CoreOp;
 36 import jdk.incubator.code.dialect.core.CoreType;
 37 import jdk.incubator.code.dialect.java.JavaOp;
 38 import jdk.incubator.code.dialect.java.JavaOp.InvokeOp.InvokeKind;
 39 import jdk.incubator.code.dialect.java.JavaType;
 40 import jdk.incubator.code.dialect.java.MethodRef;
 41 import optkl.util.Regex;
 42 
 43 import java.lang.invoke.MethodHandles;
 44 
 45 public class SwapMath {
 46     public static void main(String[] args) throws Throwable {
 47         var lookup = MethodHandles.lookup();
 48         MethodRef MathSqrt = MethodRef.method(Math.class, "sqrt", double.class, double.class);
 49         MethodRef MathAbs = MethodRef.method(Math.class, "abs", double.class, double.class);
 50 
 51         CoreOp.FuncOp rsqrt= CoreOp.func("rsqrt", CoreType.functionType(JavaType.DOUBLE, JavaType.DOUBLE))
 52                 .body(builder -> {// double rsqrt(double arg){return 1 / Math.sqrt(qrg)}
 53                    // var arg = builder.parameters().getFirst();
 54                     var argOp = CoreOp.var("arg", builder.parameters().getFirst());
 55                     var arg = builder.op(argOp);
 56 
 57                     // We can pass builder.parameters().getFirst() directly as arg below.  But then we don't know the name
 58                     var sqrtInvoke = JavaOp.invoke(InvokeKind.STATIC, false, JavaType.DOUBLE, MathSqrt, arg);
 59                     var _1f = builder.op(CoreOp.constant(JavaType.DOUBLE, 1.0));
 60 
 61                     Op.Result invokeResult = builder.op(sqrtInvoke);
 62                     Op.Result divResult = builder.op(
 63                             JavaOp.div(_1f, invokeResult)
 64                     );
 65                     builder.op(CoreOp.return_(divResult));
 66                 });
 67         var javaCodeBuilder = new JavaCodeBuilder<>(lookup,rsqrt);
 68         System.out.println(rsqrt.toText());
 69         System.out.println(javaCodeBuilder.toText());
 70         System.out.println(" 1/sqrt(100) = " + BytecodeGenerator.generate(lookup, rsqrt).invoke(100));
 71 
 72 
 73 
 74         System.out.println("--------------------------");
 75         var abs = rsqrt.transform("usingAbs", (builder,op)->{
 76             if (invoke(lookup,op) instanceof Invoke.Static ih
 77                     && ih.named("sqrt") &&  ih.returns(double.class) && ih.receives(double.class)){
 78                 var absStaticMethod = MethodRef.method(Math.class, "abs", double.class, double.class);
 79                 var absInvoke =  JavaOp.invoke(InvokeKind.STATIC, false, absStaticMethod.type().returnType(), absStaticMethod,
 80                         builder.context().getValue(op.operands().get(0)));
 81                 var absResult= builder.op(absInvoke);
 82                 builder.context().mapValue(op.result(), absResult);
 83             }else{
 84                 builder.op(op);
 85             }
 86             return builder;
 87         });
 88 
 89         System.out.println(abs.toText());
 90         javaCodeBuilder = new JavaCodeBuilder<>(lookup,abs);
 91         System.out.println(" 1/abs(100) = " + BytecodeGenerator.generate(MethodHandles.lookup(), abs).invoke(100));
 92 
 93 
 94         System.out.println("Now using txfmr--------------------------");
 95         var newAbs =Trxfmr.of(lookup,rsqrt)
 96                 .transform("usingAbs", ce-> invoke(lookup,ce) instanceof Invoke.Static $
 97                                 && $.named("sqrt")
 98                                 && $.returns(double.class)
 99                                 && $.receives(double.class)
100                         , c->
101                         c.replace(JavaOp.invoke(InvokeKind.STATIC, false, JavaType.DOUBLE, MathAbs, c.mappedOperand( 0)))
102                 )
103                 .funcOp();
104 
105 
106         System.out.println(newAbs.toText());
107         javaCodeBuilder = new JavaCodeBuilder<>(lookup,newAbs);
108         System.out.println(javaCodeBuilder.toText());
109         System.out.println(" 1/abs(100) = " + BytecodeGenerator.generate(MethodHandles.lookup(), newAbs).invoke(100));
110 
111 
112     }
113 }
114