/* * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.max.vm.ext.graal; import static com.oracle.max.cri.intrinsics.IntrinsicIDs.*; import static com.oracle.max.vm.ext.maxri.MaxRuntime.*; import static com.sun.max.vm.intrinsics.MaxineIntrinsicIDs.*; import com.oracle.max.cri.intrinsics.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.max.graal.nodes.calc.*; import com.oracle.max.graal.nodes.extended.*; import com.oracle.max.graal.nodes.java.*; import com.oracle.max.vm.ext.graal.nodes.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; import com.sun.max.annotate.*; import com.sun.max.platform.*; public class GraalMaxineIntrinsicImplementations { static class NotImplementedIntrinsic extends GraalIntrinsicImpl { @Override public ValueNode createGraph(StructuredGraph graph, RiResolvedMethod method, NodeList<ValueNode> args) { throw new UnsupportedOperationException("intrinsic not implemented"); } } static class MembarIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, int barriers) { return graph.add(new MembarNode(barriers)); } } static class NormalizeCompareIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, int opcode, ValueNode x, ValueNode y) { switch (opcode) { // Checkstyle: off case Bytecodes.LCMP: assert x.kind() == CiKind.Long; break; case Bytecodes.DCMPG: case Bytecodes.DCMPL: assert x.kind() == CiKind.Double; break; case Bytecodes.FCMPG: case Bytecodes.FCMPL: assert x.kind() == CiKind.Float; break; default: throw new CiBailout("Unsupported compare bytecode: " + opcode); // Checkstyle: on } return graph.unique(new NormalizeCompareNode(x, y, opcode == Bytecodes.FCMPL || opcode == Bytecodes.DCMPL)); } } static class IntegerUDivIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, ValueNode x, ValueNode y) { return graph.unique(new IntegerUDivNode(x.kind(), x, y)); } } static class IntegerURemIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, ValueNode x, ValueNode y) { return graph.unique(new IntegerURemNode(x.kind(), x, y)); } } static class CompareIntrinsic extends GraalIntrinsicImpl { private final Condition condition; public CompareIntrinsic(Condition condition) { this.condition = condition; } public ValueNode create(StructuredGraph graph, ValueNode x, ValueNode y) { return MaterializeNode.create(graph.unique(new CompareNode(x, condition, y)), graph); } } static class BitIntrinsic extends GraalIntrinsicImpl { private final MaxineMathIntrinsicsNode.Op op; public BitIntrinsic(MaxineMathIntrinsicsNode.Op op) { this.op = op; } public ValueNode create(StructuredGraph graph, ValueNode value) { return graph.unique(new MaxineMathIntrinsicsNode(value, op)); } } static class UnsafeCastIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, RiResolvedMethod method, ValueNode value) { RiType toType = method.signature().returnType(method.holder()); if (!(toType instanceof RiResolvedType)) { throw new CiBailout("Cannot unsafe cast to an unresolved type: %s", toType); } CiKind from = value.kind(); CiKind to = toType.kind(true).stackKind(); if (Platform.target().sizeInBytes(from) != Platform.target().sizeInBytes(from) || from == CiKind.Float || from == CiKind.Double || to == CiKind.Float || to == CiKind.Double) { throw new CiBailout("Unsupported unsafe cast from " + from + " to " + to); } return graph.unique(new MaxineUnsafeCastNode(value, (RiResolvedType) toType)); } } static class PointerReadOffsetIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, RiResolvedMethod method, ValueNode pointer, ValueNode offset) { return graph.add(new ExtendedUnsafeLoadNode(pointer, null, ensureLong(graph, offset), method.signature().returnKind(true))); } } static class PointerReadIndexIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, RiResolvedMethod method, ValueNode pointer, ValueNode displacement, ValueNode index) { return graph.add(new ExtendedUnsafeLoadNode(pointer, displacement, ensureLong(graph, index), method.signature().returnKind(true))); } } static class PointerWriteOffsetIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, RiResolvedMethod method, ValueNode pointer, ValueNode offset, ValueNode value) { RiType dataType = method.signature().argumentTypeAt(method.signature().argumentCount(false) - 1, null); CiKind kind = dataType.kind(true); return graph.add(new ExtendedUnsafeStoreNode(pointer, null, ensureLong(graph, offset), value, kind)); } } static class PointerWriteIndexIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, RiResolvedMethod method, ValueNode pointer, ValueNode displacement, ValueNode index, ValueNode value) { RiType dataType = method.signature().argumentTypeAt(method.signature().argumentCount(false) - 1, null); CiKind kind = dataType.kind(true); return graph.add(new ExtendedUnsafeStoreNode(pointer, displacement, ensureLong(graph, index), value, kind)); } } static class PointerCompareAndSwapIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, ValueNode pointer, ValueNode offset, ValueNode expectedValue, ValueNode newValue) { return graph.add(new CompareAndSwapNode(pointer, ensureLong(graph, offset), expectedValue, newValue, true)); } } /** * Processes the value producing the scaled-index or the byte offset for a pointer operation. * If compiling for a 64-bit platform and the value is an {@link CiKind#Int} parameter, * then a conversion is inserted to sign extend the int to a word. * * This is required as the value is used as a 64-bit value and so the high 32 bits * need to be correct. */ static ValueNode ensureLong(Graph graph, ValueNode value) { if (value.kind() == CiKind.Int && Platform.target().arch.is64bit()) { return graph.unique(new ConvertNode(ConvertNode.Op.I2L, value)); } return value; } static class ReadRegisterIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, RiResolvedMethod method, int registerId) { RiRegisterConfig registerConfig = runtime().getRegisterConfig(method); CiRegister register = registerConfig.getRegisterForRole(registerId); if (register == null) { throw new CiBailout("Unsupported READREG operand " + registerId); } ReadRegisterNode readRegister = graph.add(new ReadRegisterNode(register, method.signature().returnKind(true))); RiRegisterAttributes regAttr = registerConfig.getAttributesMap()[register.number]; if (regAttr.isNonZero) { // TODO: (ds) propagate the info that this register is always non-zero in compiled code. } return readRegister; } } static class WriteRegisterIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, RiResolvedMethod method, int registerId, ValueNode value) { CiRegister register = runtime().getRegisterConfig(method).getRegisterForRole(registerId); if (register == null) { throw new CiBailout("Unsupported WRITEREG operand " + registerId); } return graph.add(new WriteRegisterNode(register, value)); } } static class SafepointIntrinsic extends GraalIntrinsicImpl { private SafepointNode.Op op; public SafepointIntrinsic(SafepointNode.Op op) { this.op = op; } public ValueNode create(StructuredGraph graph) { return graph.add(new SafepointNode(op)); } } static class UncommonTrapIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph) { return graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile)); } } static class AllocaIntrinsic extends GraalIntrinsicImpl { public ValueNode create(StructuredGraph graph, RiResolvedMethod method, int size, boolean refs) { return graph.add(new AllocaNode(size, refs, (RiResolvedType) method.signature().returnType(null))); } } @HOSTED_ONLY public static void initialize(IntrinsicImpl.Registry registry) { registry.add(MEMBAR, new MembarIntrinsic()); registry.add(UCMP_AE, new CompareIntrinsic(Condition.AE)); registry.add(UCMP_AT, new CompareIntrinsic(Condition.AT)); registry.add(UCMP_BE, new CompareIntrinsic(Condition.BE)); registry.add(UCMP_BT, new CompareIntrinsic(Condition.BT)); registry.add(UDIV, new IntegerUDivIntrinsic()); registry.add(UREM, new IntegerURemIntrinsic()); registry.add(LSB, new BitIntrinsic(MaxineMathIntrinsicsNode.Op.LSB)); registry.add(MSB, new BitIntrinsic(MaxineMathIntrinsicsNode.Op.MSB)); registry.add(UNSAFE_CAST, new UnsafeCastIntrinsic()); registry.add(READREG, new ReadRegisterIntrinsic()); registry.add(WRITEREG, new WriteRegisterIntrinsic()); registry.add(IFLATCHBITREAD, new NotImplementedIntrinsic()); registry.add(PREAD_OFF, new PointerReadOffsetIntrinsic()); registry.add(PREAD_IDX, new PointerReadIndexIntrinsic()); registry.add(PWRITE_OFF, new PointerWriteOffsetIntrinsic()); registry.add(PWRITE_IDX, new PointerWriteIndexIntrinsic()); registry.add(PCMPSWP, new PointerCompareAndSwapIntrinsic()); registry.add(SAFEPOINT_POLL, new SafepointIntrinsic(SafepointNode.Op.SAFEPOINT_POLL)); registry.add(INFO, new SafepointIntrinsic(SafepointNode.Op.INFO)); registry.add(HERE, new SafepointIntrinsic(SafepointNode.Op.HERE)); registry.add(UNCOMMON_TRAP, new UncommonTrapIntrinsic()); registry.add(PAUSE, new SafepointIntrinsic(SafepointNode.Op.PAUSE)); registry.add(BREAKPOINT_TRAP, new SafepointIntrinsic(SafepointNode.Op.BREAKPOINT)); registry.add(ALLOCA, new AllocaIntrinsic()); registry.add(CMP_BYTECODE, new NormalizeCompareIntrinsic()); } }