1 /*
   2  * Copyright (c) 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.lir.jtt;
  24 
  25 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
  26 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
  27 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
  28 
  29 import java.lang.annotation.ElementType;
  30 import java.lang.annotation.RetentionPolicy;
  31 import java.lang.reflect.Method;
  32 import java.lang.reflect.Modifier;
  33 import java.util.stream.Stream;
  34 
  35 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  36 import org.graalvm.compiler.core.common.type.StampFactory;
  37 import org.graalvm.compiler.graph.NodeClass;
  38 import org.graalvm.compiler.graph.NodeInputList;
  39 import org.graalvm.compiler.jtt.JTTTest;
  40 import org.graalvm.compiler.nodeinfo.NodeInfo;
  41 import org.graalvm.compiler.nodes.FixedWithNextNode;
  42 import org.graalvm.compiler.nodes.ValueNode;
  43 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
  44 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  45 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  46 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
  47 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  48 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  49 
  50 import jdk.vm.ci.meta.JavaKind;
  51 import jdk.vm.ci.meta.ResolvedJavaMethod;
  52 import jdk.vm.ci.meta.Value;
  53 
  54 /**
  55  * Base class for LIR tests.
  56  * <p>
  57  * It provides facilities to replace methods with {@link LIRTestSpecification arbitrary LIR
  58  * instructions}.
  59  */
  60 public abstract class LIRTest extends JTTTest {
  61 
  62     @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
  63     private static final class LIRTestNode extends FixedWithNextNode implements LIRLowerable {
  64 
  65         public static final NodeClass<LIRTestNode> TYPE = NodeClass.create(LIRTestNode.class);
  66         @Input protected ValueNode opsNode;
  67         @Input protected NodeInputList<ValueNode> values;
  68         public final SnippetReflectionProvider snippetReflection;
  69 
  70         protected LIRTestNode(SnippetReflectionProvider snippetReflection, JavaKind kind, ValueNode opsNode, ValueNode[] values) {
  71             super(TYPE, StampFactory.forKind(kind));
  72             this.opsNode = opsNode;
  73             this.values = new NodeInputList<>(this, values);
  74             this.snippetReflection = snippetReflection;
  75         }
  76 
  77         public NodeInputList<ValueNode> values() {
  78             return values;
  79         }
  80 
  81         public ValueNode getLIROpsNode() {
  82             return opsNode;
  83         }
  84 
  85         @Override
  86         public void generate(NodeLIRBuilderTool gen) {
  87             LIRTestSpecification ops = getLIROperations();
  88             Stream<Value> v = values().stream().map(node -> gen.operand(node));
  89 
  90             ops.generate(gen.getLIRGeneratorTool(), v.toArray(size -> new Value[size]));
  91             Value result = ops.getResult();
  92             if (result != null) {
  93                 gen.setResult(this, result);
  94             }
  95         }
  96 
  97         public LIRTestSpecification getLIROperations() {
  98             assert getLIROpsNode().isConstant();
  99             LIRTestSpecification spec = snippetReflection.asObject(LIRTestSpecification.class, getLIROpsNode().asJavaConstant());
 100             return spec;
 101         }
 102     }
 103 
 104     @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
 105     private static final class LIRValueNode extends FixedWithNextNode implements LIRLowerable {
 106 
 107         public static final NodeClass<LIRValueNode> TYPE = NodeClass.create(LIRValueNode.class);
 108         @Input protected ValueNode opsNode;
 109         @Input protected ValueNode name;
 110         public final SnippetReflectionProvider snippetReflection;
 111 
 112         protected LIRValueNode(SnippetReflectionProvider snippetReflection, JavaKind kind, ValueNode opsNode, ValueNode name) {
 113             super(TYPE, StampFactory.forKind(kind));
 114             this.opsNode = opsNode;
 115             this.name = name;
 116             this.snippetReflection = snippetReflection;
 117         }
 118 
 119         public ValueNode getLIROpsNode() {
 120             return opsNode;
 121         }
 122 
 123         @Override
 124         public void generate(NodeLIRBuilderTool gen) {
 125             LIRTestSpecification spec = getLIROperations();
 126             Value output = spec.getOutput(getName());
 127             gen.setResult(this, isVariable(output) ? output : gen.getLIRGeneratorTool().emitMove(output));
 128         }
 129 
 130         private String getName() {
 131             assert name.isConstant();
 132             return snippetReflection.asObject(String.class, name.asJavaConstant());
 133         }
 134 
 135         private LIRTestSpecification getLIROperations() {
 136             assert getLIROpsNode().isConstant();
 137             return snippetReflection.asObject(LIRTestSpecification.class, getLIROpsNode().asJavaConstant());
 138         }
 139 
 140     }
 141 
 142     private InvocationPlugin lirTestPlugin = new InvocationPlugin() {
 143         @Override
 144         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec) {
 145             JavaKind returnKind = targetMethod.getSignature().getReturnKind();
 146             LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{});
 147             addNode(b, returnKind, node);
 148             return true;
 149         }
 150 
 151         @Override
 152         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0) {
 153             JavaKind returnKind = targetMethod.getSignature().getReturnKind();
 154             LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0});
 155             addNode(b, returnKind, node);
 156             return true;
 157         }
 158 
 159         @Override
 160         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1) {
 161             JavaKind returnKind = targetMethod.getSignature().getReturnKind();
 162             LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1});
 163             addNode(b, returnKind, node);
 164             return true;
 165         }
 166 
 167         @Override
 168         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2) {
 169             JavaKind returnKind = targetMethod.getSignature().getReturnKind();
 170             LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2});
 171             addNode(b, returnKind, node);
 172             return true;
 173         }
 174 
 175         @Override
 176         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
 177             JavaKind returnKind = targetMethod.getSignature().getReturnKind();
 178             LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2, arg3});
 179             addNode(b, returnKind, node);
 180             return true;
 181         }
 182 
 183         private void addNode(GraphBuilderContext b, JavaKind returnKind, LIRTestNode node) {
 184             if (returnKind.equals(JavaKind.Void)) {
 185                 b.add(node);
 186             } else {
 187                 b.addPush(returnKind, node);
 188             }
 189         }
 190 
 191     };
 192 
 193     @Override
 194     protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
 195         InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
 196 
 197         Class<? extends LIRTest> c = getClass();
 198         for (Method m : c.getMethods()) {
 199             if (m.getAnnotation(LIRIntrinsic.class) != null) {
 200                 assert Modifier.isStatic(m.getModifiers());
 201                 Class<?>[] p = m.getParameterTypes();
 202                 assert p.length > 0;
 203                 assert LIRTestSpecification.class.isAssignableFrom(p[0]);
 204 
 205                 invocationPlugins.register(lirTestPlugin, c, m.getName(), p);
 206             }
 207         }
 208         InvocationPlugin outputPlugin = new InvocationPlugin() {
 209             @Override
 210             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode name, ValueNode expected) {
 211                 JavaKind returnKind = targetMethod.getSignature().getReturnKind();
 212                 b.addPush(returnKind, new LIRValueNode(getSnippetReflection(), returnKind, spec, name));
 213                 return true;
 214             }
 215         };
 216         invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class<?>[]{LIRTestSpecification.class, String.class, Object.class});
 217         invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class<?>[]{LIRTestSpecification.class, String.class, int.class});
 218         return super.editGraphBuilderConfiguration(conf);
 219     }
 220 
 221     @SuppressWarnings("unused")
 222     public static byte getOutput(LIRTestSpecification spec, String name, byte expected) {
 223         return expected;
 224     }
 225 
 226     @SuppressWarnings("unused")
 227     public static short getOutput(LIRTestSpecification spec, String name, short expected) {
 228         return expected;
 229     }
 230 
 231     @SuppressWarnings("unused")
 232     public static int getOutput(LIRTestSpecification spec, String name, int expected) {
 233         return expected;
 234     }
 235 
 236     @SuppressWarnings("unused")
 237     public static long getOutput(LIRTestSpecification spec, String name, long expected) {
 238         return expected;
 239     }
 240 
 241     @SuppressWarnings("unused")
 242     public static float getOutput(LIRTestSpecification spec, String name, float expected) {
 243         return expected;
 244     }
 245 
 246     @SuppressWarnings("unused")
 247     public static double getOutput(LIRTestSpecification spec, String name, double expected) {
 248         return expected;
 249     }
 250 
 251     @SuppressWarnings("unused")
 252     public static Object getOutput(LIRTestSpecification spec, String name, Object expected) {
 253         return expected;
 254     }
 255 
 256     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
 257     @java.lang.annotation.Target(ElementType.METHOD)
 258     public static @interface LIRIntrinsic {
 259     }
 260 
 261 }