package com.oracle.truffle.llvm.runtime.nodes.op;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.llvm.runtime.library.internal.LLVMNativeLibrary;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMNode;
import com.oracle.truffle.llvm.runtime.nodes.op.LLVMPointerCompareNodeGen.LLVMNegateNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.op.ToComparableValue.ManagedToComparableValue;
import com.oracle.truffle.llvm.runtime.nodes.util.LLVMSameObjectNode;
import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer;
import com.oracle.truffle.llvm.runtime.pointer.LLVMNativePointer;
@NodeChild(type = LLVMExpressionNode.class)
@NodeChild(type = LLVMExpressionNode.class)
public abstract class LLVMPointerCompareNode extends LLVMAbstractCompareNode {
private final NativePointerCompare op;
public LLVMPointerCompareNode(NativePointerCompare op) {
this.op = op;
}
@Specialization
boolean doCompare(long a, long b) {
return op.compare(a, b);
}
@Specialization
boolean doCompare(LLVMNativePointer a, LLVMNativePointer b) {
return op.compare(a.asNative(), b.asNative());
}
@Specialization(guards = {"libA.isPointer(a)", "libB.isPointer(b)"}, limit = "3", rewriteOn = UnsupportedMessageException.class)
protected boolean doPointerPointer(Object a, Object b,
@CachedLibrary("a") LLVMNativeLibrary libA,
@CachedLibrary("b") LLVMNativeLibrary libB) throws UnsupportedMessageException {
return op.compare(libA.asPointer(a), libB.asPointer(b));
}
@Specialization(guards = {"libA.isPointer(a)", "libB.isPointer(b)"}, limit = "3")
protected boolean doPointerPointerException(Object a, Object b,
@CachedLibrary("a") LLVMNativeLibrary libA,
@CachedLibrary("b") LLVMNativeLibrary libB,
@Cached LLVMManagedCompareNode managedCompare) {
try {
return doPointerPointer(a, b, libA, libB);
} catch (UnsupportedMessageException ex) {
return doOther(a, b, libA, libB, managedCompare);
}
}
@Specialization(guards = "!libA.isPointer(a) || !libB.isPointer(b)", limit = "3")
protected boolean doOther(Object a, Object b,
@CachedLibrary("a") LLVMNativeLibrary libA,
@CachedLibrary("b") LLVMNativeLibrary libB,
@Cached LLVMManagedCompareNode managedCompare) {
return managedCompare.execute(a, libA, b, libB, op);
}
public static LLVMAbstractCompareNode create(Kind kind, LLVMExpressionNode l, LLVMExpressionNode r) {
switch (kind) {
case SLT:
return LLVMPointerCompareNodeGen.create(new NativePointerCompare() {
@Override
public boolean compare(long a, long b) {
return a < b;
}
}, l, r);
case SLE:
return LLVMPointerCompareNodeGen.create(new NativePointerCompare() {
@Override
public boolean compare(long a, long b) {
return a <= b;
}
}, l, r);
case ULE:
return LLVMPointerCompareNodeGen.create(new NativePointerCompare() {
@Override
public boolean compare(long a, long b) {
return Long.compareUnsigned(a, b) <= 0;
}
}, l, r);
case ULT:
return LLVMPointerCompareNodeGen.create(new NativePointerCompare() {
@Override
public boolean compare(long a, long b) {
return Long.compareUnsigned(a, b) < 0;
}
}, l, r);
case EQ:
return LLVMAddressEqualsNodeGen.create(l, r);
case NEQ:
return LLVMNegateNode.create(LLVMAddressEqualsNodeGen.create(l, r));
default:
throw new AssertionError();
}
}
public enum Kind {
ULT,
ULE,
SLT,
SLE,
EQ,
NEQ,
}
protected abstract static class NativePointerCompare {
abstract boolean compare(long a, long b);
}
abstract static class LLVMManagedCompareNode extends LLVMNode {
private static final long TYPICAL_POINTER = 0x00007f0000000000L;
abstract boolean execute(Object a, LLVMNativeLibrary libA, Object b, LLVMNativeLibrary libB, NativePointerCompare op);
@Specialization(guards = {"pointToSameObject.execute(a.getObject(), b.getObject())"})
protected boolean doForeign(LLVMManagedPointer a, @SuppressWarnings("unused") LLVMNativeLibrary libA,
LLVMManagedPointer b, @SuppressWarnings("unused") LLVMNativeLibrary libB, NativePointerCompare op,
@SuppressWarnings("unused") @Cached LLVMSameObjectNode pointToSameObject) {
return op.compare(TYPICAL_POINTER + a.getOffset(), TYPICAL_POINTER + b.getOffset());
}
@Specialization(guards = "!pointToSameObject.execute(a.getObject(), b.getObject())")
protected boolean doForeign(LLVMManagedPointer a, @SuppressWarnings("unused") LLVMNativeLibrary libA,
LLVMManagedPointer b, @SuppressWarnings("unused") LLVMNativeLibrary libB, NativePointerCompare op,
@SuppressWarnings("unused") @Cached LLVMSameObjectNode pointToSameObject,
@Cached("createIgnoreOffset()") ManagedToComparableValue convertA,
@Cached("createIgnoreOffset()") ManagedToComparableValue convertB) {
return op.compare(convertA.executeWithTarget(a), convertB.executeWithTarget(b));
}
@Specialization(guards = "libA.isPointer(a)", rewriteOn = UnsupportedMessageException.class)
protected boolean doNativeManaged(Object a, LLVMNativeLibrary libA, Object b, LLVMNativeLibrary libB, NativePointerCompare op,
@Cached("createIgnoreOffset()") ManagedToComparableValue convert) throws UnsupportedMessageException {
return op.compare(libA.asPointer(a), convert.executeWithTarget(b));
}
@Specialization(guards = "libB.isPointer(b)", rewriteOn = UnsupportedMessageException.class)
protected boolean doManagedNative(Object a, LLVMNativeLibrary libA, Object b, LLVMNativeLibrary libB, NativePointerCompare op,
@Cached("createIgnoreOffset()") ManagedToComparableValue convert) throws UnsupportedMessageException {
return op.compare(convert.executeWithTarget(a), libB.asPointer(b));
}
@Specialization(guards = "libA.isPointer(a) || libB.isPointer(b)")
protected boolean doManagedNativeException(Object a, LLVMNativeLibrary libA, Object b, LLVMNativeLibrary libB, NativePointerCompare op,
@Cached("createIgnoreOffset()") ManagedToComparableValue convert) {
try {
return op.compare(libA.asPointer(a), convert.executeWithTarget(b));
} catch (UnsupportedMessageException e) {
try {
return op.compare(convert.executeWithTarget(a), libB.asPointer(b));
} catch (UnsupportedMessageException ex) {
return op.compare(convert.executeWithTarget(a), convert.executeWithTarget(b));
}
}
}
}
public abstract static class LLVMNegateNode extends LLVMAbstractCompareNode {
@Child private LLVMAbstractCompareNode booleanExpression;
LLVMNegateNode(LLVMAbstractCompareNode booleanExpression) {
this.booleanExpression = booleanExpression;
}
public static LLVMAbstractCompareNode create(LLVMAbstractCompareNode booleanExpression) {
return LLVMNegateNodeGen.create(booleanExpression);
}
@Override
public final boolean executeWithTarget(Object a, Object b) {
return !booleanExpression.executeWithTarget(a, b);
}
@Specialization
public boolean doNegate(VirtualFrame frame) {
return !booleanExpression.executeGenericBoolean(frame);
}
}
}