package org.graalvm.compiler.replacements.aarch64;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.graph.Node.NodeIntrinsic;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.RemNode;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.replacements.SnippetTemplate;
import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.Snippets;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.meta.JavaKind;
public class AArch64FloatArithmeticSnippets extends SnippetTemplate.AbstractTemplates implements Snippets {
private final SnippetTemplate.SnippetInfo drem;
private final SnippetTemplate.SnippetInfo frem;
public AArch64FloatArithmeticSnippets(OptionValues options, Iterable<DebugHandlersFactory> factories, Providers providers, SnippetReflectionProvider snippetReflection,
TargetDescription target) {
super(options, factories, providers, snippetReflection, target);
drem = snippet(AArch64FloatArithmeticSnippets.class, "dremSnippet");
frem = snippet(AArch64FloatArithmeticSnippets.class, "fremSnippet");
}
public void lower(RemNode node, LoweringTool tool) {
JavaKind kind = node.stamp(NodeView.DEFAULT).getStackKind();
assert kind == JavaKind.Float || kind == JavaKind.Double;
if (node instanceof SafeNode) {
return;
}
SnippetTemplate.SnippetInfo snippet = kind == JavaKind.Float ? frem : drem;
StructuredGraph graph = node.graph();
Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
args.add("x", node.getX());
args.add("y", node.getY());
template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, tool, args);
}
@Snippet
public static float fremSnippet(float x, float y) {
if (Float.isInfinite(x) || y == 0.0f || Float.isNaN(y)) {
return Float.NaN;
}
if (x == 0.0f || Float.isInfinite(y)) {
return x;
}
float result = safeRem(x, y);
if (result == 0.0f && x < 0.0f) {
return -result;
}
return result;
}
@Snippet
public static double dremSnippet(double x, double y) {
if (Double.isInfinite(x) || y == 0.0 || Double.isNaN(y)) {
return Double.NaN;
}
if (x == 0.0 || Double.isInfinite(y)) {
return x;
}
double result = safeRem(x, y);
if (result == 0.0 && x < 0.0) {
return -result;
}
return result;
}
@NodeIntrinsic(SafeFloatRemNode.class)
private static native float safeRem(float x, float y);
@NodeIntrinsic(SafeFloatRemNode.class)
private static native double safeRem(double x, double y);
private interface SafeNode {
}
@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
static class SafeFloatRemNode extends RemNode implements SafeNode {
public static final NodeClass<SafeFloatRemNode> TYPE = NodeClass.create(SafeFloatRemNode.class);
protected SafeFloatRemNode(ValueNode x, ValueNode y) {
super(TYPE, x, y);
}
}
}