001/*
002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.lir.jtt;
024
025import static com.oracle.graal.lir.LIRValueUtil.*;
026
027import java.lang.annotation.*;
028import java.lang.reflect.*;
029import java.util.stream.*;
030
031import jdk.internal.jvmci.meta.*;
032
033import com.oracle.graal.api.replacements.*;
034import com.oracle.graal.compiler.common.type.*;
035import com.oracle.graal.graph.*;
036import com.oracle.graal.graphbuilderconf.*;
037import com.oracle.graal.jtt.*;
038import com.oracle.graal.nodeinfo.*;
039import com.oracle.graal.nodes.*;
040import com.oracle.graal.nodes.spi.*;
041
042/**
043 * Base class for LIR tests.
044 * <p>
045 * It provides facilities to replace methods with {@link LIRTestSpecification arbitrary LIR
046 * instructions}.
047 */
048public abstract class LIRTest extends JTTTest {
049
050    @NodeInfo
051    private static final class LIRTestNode extends FixedWithNextNode implements LIRLowerable {
052
053        public static final NodeClass<LIRTestNode> TYPE = NodeClass.create(LIRTestNode.class);
054        @Input protected ValueNode opsNode;
055        @Input protected NodeInputList<ValueNode> values;
056        public final SnippetReflectionProvider snippetReflection;
057
058        public LIRTestNode(SnippetReflectionProvider snippetReflection, Kind kind, ValueNode opsNode, ValueNode[] values) {
059            super(TYPE, StampFactory.forKind(kind));
060            this.opsNode = opsNode;
061            this.values = new NodeInputList<>(this, values);
062            this.snippetReflection = snippetReflection;
063        }
064
065        public NodeInputList<ValueNode> values() {
066            return values;
067        }
068
069        public ValueNode getLIROpsNode() {
070            return opsNode;
071        }
072
073        @Override
074        public void generate(NodeLIRBuilderTool gen) {
075            LIRTestSpecification ops = getLIROperations();
076            Stream<Value> v = values().stream().map(node -> gen.operand(node));
077
078            ops.generate(gen.getLIRGeneratorTool(), v.toArray(size -> new Value[size]));
079            gen.setResult(this, ops.getResult());
080        }
081
082        public LIRTestSpecification getLIROperations() {
083            assert getLIROpsNode().isConstant();
084            LIRTestSpecification spec = snippetReflection.asObject(LIRTestSpecification.class, getLIROpsNode().asJavaConstant());
085            return spec;
086        }
087    }
088
089    @NodeInfo
090    private static final class LIRValueNode extends FixedWithNextNode implements LIRLowerable {
091
092        public static final NodeClass<LIRValueNode> TYPE = NodeClass.create(LIRValueNode.class);
093        @Input protected ValueNode opsNode;
094        @Input protected ValueNode name;
095        public final SnippetReflectionProvider snippetReflection;
096
097        public LIRValueNode(SnippetReflectionProvider snippetReflection, Kind kind, ValueNode opsNode, ValueNode name) {
098            super(TYPE, StampFactory.forKind(kind));
099            this.opsNode = opsNode;
100            this.name = name;
101            this.snippetReflection = snippetReflection;
102        }
103
104        public ValueNode getLIROpsNode() {
105            return opsNode;
106        }
107
108        @Override
109        public void generate(NodeLIRBuilderTool gen) {
110            LIRTestSpecification spec = getLIROperations();
111            Value output = spec.getOutput(getName());
112            gen.setResult(this, isVariable(output) ? output : gen.getLIRGeneratorTool().emitMove(output));
113        }
114
115        private String getName() {
116            assert name.isConstant();
117            return snippetReflection.asObject(String.class, name.asJavaConstant());
118        }
119
120        private LIRTestSpecification getLIROperations() {
121            assert getLIROpsNode().isConstant();
122            return snippetReflection.asObject(LIRTestSpecification.class, getLIROpsNode().asJavaConstant());
123        }
124
125    }
126
127    private InvocationPlugin lirTestPlugin = new InvocationPlugin() {
128        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec) {
129            Kind returnKind = targetMethod.getSignature().getReturnKind();
130            b.addPush(returnKind, new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{}));
131            return true;
132        }
133
134        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0) {
135            Kind returnKind = targetMethod.getSignature().getReturnKind();
136            b.addPush(returnKind, new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0}));
137            return true;
138        }
139
140        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1) {
141            Kind returnKind = targetMethod.getSignature().getReturnKind();
142            b.addPush(returnKind, new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1}));
143            return true;
144        }
145
146        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2) {
147            Kind returnKind = targetMethod.getSignature().getReturnKind();
148            b.addPush(returnKind, new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2}));
149            return true;
150        }
151
152        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
153            Kind returnKind = targetMethod.getSignature().getReturnKind();
154            b.addPush(returnKind, new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2, arg3}));
155            return true;
156        }
157
158    };
159
160    @Override
161    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
162        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
163
164        Class<? extends LIRTest> c = getClass();
165        for (Method m : c.getMethods()) {
166            if (m.getAnnotation(LIRIntrinsic.class) != null) {
167                assert Modifier.isStatic(m.getModifiers());
168                Class<?>[] p = m.getParameterTypes();
169                assert p.length > 0;
170                assert LIRTestSpecification.class.isAssignableFrom(p[0]);
171
172                invocationPlugins.register(lirTestPlugin, c, m.getName(), p);
173            }
174        }
175        InvocationPlugin outputPlugin = new InvocationPlugin() {
176            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode name, ValueNode expected) {
177                Kind returnKind = targetMethod.getSignature().getReturnKind();
178                b.addPush(returnKind, new LIRValueNode(getSnippetReflection(), returnKind, spec, name));
179                return true;
180            }
181        };
182        invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class<?>[]{LIRTestSpecification.class, String.class, Object.class});
183        invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class<?>[]{LIRTestSpecification.class, String.class, int.class});
184        return super.editGraphBuilderConfiguration(conf);
185    }
186
187    @SuppressWarnings("unused")
188    public static byte getOutput(LIRTestSpecification spec, String name, byte expected) {
189        return expected;
190    }
191
192    @SuppressWarnings("unused")
193    public static short getOutput(LIRTestSpecification spec, String name, short expected) {
194        return expected;
195    }
196
197    @SuppressWarnings("unused")
198    public static int getOutput(LIRTestSpecification spec, String name, int expected) {
199        return expected;
200    }
201
202    @SuppressWarnings("unused")
203    public static long getOutput(LIRTestSpecification spec, String name, long expected) {
204        return expected;
205    }
206
207    @SuppressWarnings("unused")
208    public static float getOutput(LIRTestSpecification spec, String name, float expected) {
209        return expected;
210    }
211
212    @SuppressWarnings("unused")
213    public static double getOutput(LIRTestSpecification spec, String name, double expected) {
214        return expected;
215    }
216
217    @SuppressWarnings("unused")
218    public static Object getOutput(LIRTestSpecification spec, String name, Object expected) {
219        return expected;
220    }
221
222    @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
223    @java.lang.annotation.Target(ElementType.METHOD)
224    public static @interface LIRIntrinsic {
225    }
226
227}