/*
* 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.c1x;
import static com.sun.max.vm.intrinsics.MaxineIntrinsicIDs.*;
import com.oracle.max.cri.intrinsics.*;
import com.sun.c1x.graph.*;
import com.sun.c1x.intrinsics.*;
import com.sun.c1x.ir.*;
import com.sun.c1x.ir.Infopoint.Op;
import com.sun.c1x.ir.Value.Flag;
import com.sun.c1x.lir.*;
import com.sun.c1x.value.*;
import com.sun.cri.bytecode.*;
import com.sun.cri.ci.*;
import com.sun.cri.ri.*;
import com.sun.max.vm.runtime.*;
public class MaxineIntrinsicImplementations {
public static class BitIntrinsic implements C1XIntrinsicImpl {
public final LIROpcode opcode;
public BitIntrinsic(LIROpcode opcode) {
this.opcode = opcode;
}
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
assert args.length == 1;
return b.append(new SignificantBitOp(args[0], opcode));
}
}
public static class UnsafeCastIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
b.compilation.setNotTypesafe();
RiSignature signature = target.signature();
int argCount = signature.argumentCount(false);
RiType accessingClass = b.scope().method.holder();
RiType fromType;
RiType toType = signature.returnType(accessingClass);
assert args.length == 1 || (args.length == 2 && MutableFrameState.isTwoSlot(args[0].kind)) : "method with @UNSAFE_CAST must have exactly 1 argument";
if (argCount == 1) {
fromType = signature.argumentTypeAt(0, accessingClass);
} else {
assert argCount == 0 : "method with @UNSAFE_CAST must have exactly 1 argument";
fromType = target.holder();
}
CiKind from = fromType.kind(true).stackKind();
CiKind to = toType.kind(true).stackKind();
if (b.compilation.target.sizeInBytes(from) != b.compilation.target.sizeInBytes(from) || from == CiKind.Float || from == CiKind.Double || to == CiKind.Float || to == CiKind.Double) {
throw new CiBailout("Unsupported unsafe cast from " + fromType + " to " + toType);
}
return b.append(new UnsafeCast(toType, args[0], from == to));
}
}
public static class PointerReadIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
assert args.length == 2 || args.length == 3;
Value pointer = args[0];
Value displacement = args.length == 3 ? args[1] : null;
Value offsetOrIndex = offsetOrIndex(b, args.length == 3 ? args[2] : args[1]);
return b.append(new LoadPointer(target.signature().returnType(null), pointer, displacement, offsetOrIndex, stateBefore, false));
}
}
public static class PointerWriteIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
// Last parameter can be a double word, in which case args ends with a null slot that must be ignored.
int numArgs = args[args.length - 1] == null ? args.length - 1 : args.length;
assert numArgs == 3 || numArgs == 4;
Value pointer = args[0];
Value displacement = numArgs == 4 ? args[1] : null;
Value offsetOrIndex = offsetOrIndex(b, numArgs == 4 ? args[2] : args[1]);
Value value = args[numArgs - 1];
RiType dataType = target.signature().argumentTypeAt(target.signature().argumentCount(false) - 1, null);
b.append(new StorePointer(dataType, pointer, displacement, offsetOrIndex, value, stateBefore, false));
return null;
}
}
public static class PointerCompareAndSwapIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
assert args.length == 4 || args.length == 6;
Value pointer = args[0];
Value offset = offsetOrIndex(b, args[1]);
Value expectedValue = args[2];
Value newValue = args[args.length == 6 ? 4 : 3];
return b.append(new CompareAndSwap(target.signature().returnType(null), pointer, offset, expectedValue, newValue, stateBefore, false));
}
}
/**
* 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.
*/
private static Value offsetOrIndex(GraphBuilder b, Value offsetOrIndex) {
if (offsetOrIndex.kind == CiKind.Int && b.compilation.target.arch.is64bit()) {
return b.append(new Convert(Convert.Op.I2L, offsetOrIndex, CiKind.Long));
}
return offsetOrIndex;
}
public static class ReadRegisterIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
assert args.length == 1;
int registerId = intConstant(args[0]);
CiRegister register = b.compilation.registerConfig.getRegisterForRole(registerId);
if (register == null) {
throw new CiBailout("Unsupported READREG operand " + registerId);
}
RiType type = target.signature().returnType(null);
LoadRegister load = new LoadRegister(target.signature().returnKind(false), register, (type instanceof RiResolvedType) ? (RiResolvedType) type : null);
RiRegisterAttributes regAttr = b.compilation.registerConfig.getAttributesMap()[register.number];
if (regAttr.isNonZero) {
load.setFlag(Flag.NonNull);
}
return b.append(load);
}
}
public static class WriteRegisterIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
assert args.length == 2;
int registerId = intConstant(args[0]);
Value value = args[1];
CiRegister register = b.compilation.registerConfig.getRegisterForRole(registerId);
if (register == null) {
throw new CiBailout("Unsupported READREG operand " + registerId);
}
b.append(new StoreRegister(register, value));
return null;
}
}
private static int intConstant(Value value) {
if (!value.isConstant() || value.kind != CiKind.Int) {
throw new CiBailout("instrinc parameter must be compile time integer constant but is " + value);
}
return value.asConstant().asInt();
}
public static class InfopointIntrinsic implements C1XIntrinsicImpl {
private Op op;
public InfopointIntrinsic(Infopoint.Op op) {
this.op = op;
}
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
assert args.length == 0;
assert op != Infopoint.Op.SAFEPOINT_POLL || !b.scopeData.noSafepointPolls() : "cannot place safepoint poll in uninterruptible code scope";
return b.append(new Infopoint(op, stateBefore));
}
}
public static class PauseIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
b.append(new Pause());
return null;
}
}
public static class BreakpointTrapIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
b.append(new BreakpointTrap());
return null;
}
}
public static class AllocaIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
return b.append(new Alloca(args[0], args[1], target.signature().returnType(null)));
}
}
public static class IfLatchBitReadIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
assert args.length == 2;
int offset = intConstant(args[0]);
int bit = intConstant(args[1]);
CiRegister register = b.compilation.registerConfig.getRegisterForRole(VMRegister.LATCH);
if (register == null) {
throw new CiBailout("Unsupported IFLATCHBITREAD operand " + VMRegister.LATCH);
}
// The intrinsic implicitly consumes also the following IFEQ or IFNE bytecode. This is very badly designed,
// but for now keep it and make a call into GraphBuilder which has access to the bytecode stream.
b.genIfLatchReadBit(register, offset, bit);
return null;
}
}
public static class CompareBytecodeIntrinsic implements C1XIntrinsicImpl {
@Override
public Value createHIR(GraphBuilder b, RiMethod target, Value[] args, boolean isStatic, FrameState stateBefore) {
int opcode = intConstant(args[0]);
assert opcode == Bytecodes.LCMP || opcode == Bytecodes.FCMPL || opcode == Bytecodes.FCMPG || opcode == Bytecodes.DCMPL || opcode == Bytecodes.DCMPG;
assert args.length == 3 || args.length == 5;
Value x = args[1];
Value y = args.length == 5 ? args[3] : args[2];
return b.append(new CompareOp(opcode, CiKind.Int, x, y));
}
}
public static void initialize(IntrinsicImpl.Registry registry) {
registry.add(LSB, new BitIntrinsic(LIROpcode.Lsb));
registry.add(MSB, new BitIntrinsic(LIROpcode.Msb));
registry.add(UNSAFE_CAST, new UnsafeCastIntrinsic());
registry.add(READREG, new ReadRegisterIntrinsic());
registry.add(WRITEREG, new WriteRegisterIntrinsic());
registry.add(IFLATCHBITREAD, new IfLatchBitReadIntrinsic());
registry.add(PREAD_OFF, new PointerReadIntrinsic());
registry.add(PREAD_IDX, new PointerReadIntrinsic());
registry.add(PWRITE_OFF, new PointerWriteIntrinsic());
registry.add(PWRITE_IDX, new PointerWriteIntrinsic());
registry.add(PCMPSWP, new PointerCompareAndSwapIntrinsic());
registry.add(SAFEPOINT_POLL, new InfopointIntrinsic(Infopoint.Op.SAFEPOINT_POLL));
registry.add(INFO, new InfopointIntrinsic(Infopoint.Op.INFO));
registry.add(HERE, new InfopointIntrinsic(Infopoint.Op.HERE));
registry.add(UNCOMMON_TRAP, new InfopointIntrinsic(Infopoint.Op.UNCOMMON_TRAP));
registry.add(PAUSE, new PauseIntrinsic());
registry.add(BREAKPOINT_TRAP, new BreakpointTrapIntrinsic());
registry.add(ALLOCA, new AllocaIntrinsic());
registry.add(CMP_BYTECODE, new CompareBytecodeIntrinsic());
}
}