diff --git a/src/trufflesom/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/src/trufflesom/compiler/ParserAst.java index 30945c57e..9e48a9c79 100644 --- a/src/trufflesom/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/src/trufflesom/compiler/ParserAst.java @@ -16,8 +16,6 @@ import static trufflesom.vm.SymbolTable.strSelf; import static trufflesom.vm.SymbolTable.strSuper; import static trufflesom.vm.SymbolTable.symNil; -import static trufflesom.vm.SymbolTable.symSelf; -import static trufflesom.vm.SymbolTable.symSuper; import static trufflesom.vm.SymbolTable.symbolFor; import java.math.BigInteger; @@ -45,11 +43,15 @@ import trufflesom.interpreter.nodes.literals.GenericLiteralNode; import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; -import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode; +import trufflesom.interpreter.supernodes.compare.GreaterThanIntNodeGen; +import trufflesom.interpreter.supernodes.compare.LessThanIntNodeGen; +import trufflesom.interpreter.supernodes.compare.LocalArgGreaterThanInt; +import trufflesom.interpreter.supernodes.compare.LocalArgLessThanInt; +import trufflesom.interpreter.supernodes.compare.LocalFieldStringEqualsNode; import trufflesom.interpreter.supernodes.LocalVariableSquareNodeGen; -import trufflesom.interpreter.supernodes.NonLocalFieldStringEqualsNode; +import trufflesom.interpreter.supernodes.compare.NonLocalFieldStringEqualsNode; import trufflesom.interpreter.supernodes.NonLocalVariableSquareNodeGen; -import trufflesom.interpreter.supernodes.StringEqualsNodeGen; +import trufflesom.interpreter.supernodes.compare.StringEqualsNodeGen; import trufflesom.interpreter.supernodes.inc.IncExpWithValueNodeGen; import trufflesom.primitives.Primitives; import trufflesom.vm.Globals; @@ -331,6 +333,20 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, } else if (msg == SymbolTable.symMinus && operand instanceof IntegerLiteralNode lit) { long litValue = lit.executeLong(null); return IncExpWithValueNodeGen.create(-litValue, true, receiver).initialize(coordWithL); + } else if (binSelector.equals(">") && operand instanceof IntegerLiteralNode lit) { + long litValue = lit.executeLong(null); + + if (receiver instanceof LocalArgumentReadNode arg) { + return new LocalArgGreaterThanInt(arg.getArg(), litValue).initialize(coordWithL); + } + return GreaterThanIntNodeGen.create(litValue, receiver).initialize(coordWithL); + } else if (binSelector.equals("<") && operand instanceof IntegerLiteralNode lit) { + long litValue = lit.executeLong(null); + + if (receiver instanceof LocalArgumentReadNode arg) { + return new LocalArgLessThanInt(arg.getArg(), litValue).initialize(coordWithL); + } + return LessThanIntNodeGen.create(litValue, receiver).initialize(coordWithL); } ExpressionNode inlined = @@ -360,21 +376,21 @@ protected ExpressionNode keywordMessage(final MethodGenerationContext mgenc, SSymbol msg = symbolFor(kw.toString()); - long coodWithL = getCoordWithLength(coord); + long coordWithL = getCoordWithLength(coord); ExpressionNode[] args = arguments.toArray(new ExpressionNode[0]); if (isSuperSend) { return MessageSendNode.createSuperSend( - mgenc.getHolder().getSuperClass(), msg, args, coodWithL); + mgenc.getHolder().getSuperClass(), msg, args, coordWithL); } - ExpressionNode inlined = inlinableNodes.inline(msg, args, mgenc, coodWithL); + ExpressionNode inlined = inlinableNodes.inline(msg, args, mgenc, coordWithL); if (inlined != null) { assert !isSuperSend; return inlined; } - return MessageSendNode.create(msg, args, coodWithL); + return MessageSendNode.create(msg, args, coordWithL); } private ExpressionNode formula(final MethodGenerationContext mgenc) diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/GreaterThanIntNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/GreaterThanIntNode.java new file mode 100644 index 000000000..365c71c16 --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/GreaterThanIntNode.java @@ -0,0 +1,62 @@ +package trufflesom.interpreter.supernodes.compare; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.interpreter.nodes.nary.UnaryExpressionNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; +import trufflesom.vmobjects.SSymbol; + + +public abstract class GreaterThanIntNode extends UnaryExpressionNode { + private final long intValue; + + public GreaterThanIntNode(final long intValue) { + this.intValue = intValue; + } + + @Override + public abstract ExpressionNode getReceiver(); + + @Specialization + public final boolean doLong(final long rcvr) { + return rcvr > intValue; + } + + @Specialization + public final boolean doDouble(final double rcvr) { + return rcvr > intValue; + } + + @Fallback + public final Object makeGenericSend(final VirtualFrame frame, + final Object receiver) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return makeGenericSend(SymbolTable.symbolFor(">")).doPreEvaluated(frame, + new Object[] {receiver, intValue}); + } + + @Override + protected GenericMessageSendNode makeGenericSend(final SSymbol selector) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + GenericMessageSendNode send = MessageSendNode.createGeneric(selector, + new ExpressionNode[] {getReceiver(), new IntegerLiteralNode(intValue)}, sourceCoord); + + if (VmSettings.UseAstInterp) { + replace(send); + send.notifyDispatchInserted(); + return send; + } + + assert getParent() instanceof BytecodeLoopNode : "This node was expected to be a direct child of a `BytecodeLoopNode`."; + throw new RespecializeException(send); + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LessThanIntNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LessThanIntNode.java new file mode 100644 index 000000000..07ce26c6a --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LessThanIntNode.java @@ -0,0 +1,62 @@ +package trufflesom.interpreter.supernodes.compare; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.interpreter.nodes.nary.UnaryExpressionNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; +import trufflesom.vmobjects.SSymbol; + + +public abstract class LessThanIntNode extends UnaryExpressionNode { + private final long intValue; + + public LessThanIntNode(final long intValue) { + this.intValue = intValue; + } + + @Override + public abstract ExpressionNode getReceiver(); + + @Specialization + public final boolean doLong(final long rcvr) { + return rcvr < intValue; + } + + @Specialization + public final boolean doDouble(final double rcvr) { + return rcvr < intValue; + } + + @Fallback + public final Object makeGenericSend(final VirtualFrame frame, + final Object receiver) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return makeGenericSend(SymbolTable.symbolFor("<")).doPreEvaluated(frame, + new Object[] {receiver, intValue}); + } + + @Override + protected GenericMessageSendNode makeGenericSend(final SSymbol selector) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + GenericMessageSendNode send = MessageSendNode.createGeneric(selector, + new ExpressionNode[] {getReceiver(), new IntegerLiteralNode(intValue)}, sourceCoord); + + if (VmSettings.UseAstInterp) { + replace(send); + send.notifyDispatchInserted(); + return send; + } + + assert getParent() instanceof BytecodeLoopNode : "This node was expected to be a direct child of a `BytecodeLoopNode`."; + throw new RespecializeException(send); + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalArgGreaterThanInt.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalArgGreaterThanInt.java new file mode 100644 index 000000000..5f814edf3 --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalArgGreaterThanInt.java @@ -0,0 +1,107 @@ +package trufflesom.interpreter.supernodes.compare; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Argument; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; + + +public final class LocalArgGreaterThanInt extends ExpressionNode { + private final Argument arg; + private final int argIdx; + private final long intValue; + + public LocalArgGreaterThanInt(final Argument arg, final long intValue) { + this.arg = arg; + this.argIdx = arg.index; + this.intValue = intValue; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object arg = frame.getArguments()[argIdx]; + if (arg instanceof Long) { + long argVal = (Long) arg; + return argVal > intValue; + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return fallbackGeneric(frame); + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] args) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new UnsupportedOperationException(); + } + + @Override + public boolean executeBoolean(final VirtualFrame frame) throws UnexpectedResultException { + Object arg = frame.getArguments()[argIdx]; + if (arg instanceof Long) { + long argVal = (Long) arg; + return argVal > intValue; + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return fallbackBool(frame); + } + + private boolean fallbackBool(final VirtualFrame frame) throws UnexpectedResultException { + Object result = makeGenericSend().doPreEvaluated(frame, + new Object[] {arg, intValue}); + if (result instanceof Boolean) { + return (Boolean) result; + } + throw new UnexpectedResultException(result); + } + + private Object fallbackGeneric(final VirtualFrame frame) { + return makeGenericSend().doPreEvaluated(frame, + new Object[] {arg, intValue}); + } + + protected GenericMessageSendNode makeGenericSend() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + GenericMessageSendNode send = + MessageSendNode.createGeneric(SymbolTable.symbolFor(">"), new ExpressionNode[] { + new LocalArgumentReadNode(arg), new IntegerLiteralNode(intValue)}, sourceCoord); + + if (VmSettings.UseAstInterp) { + replace(send); + send.notifyDispatchInserted(); + return send; + } + + assert getParent() instanceof BytecodeLoopNode : "This node was expected to be a direct child of a `BytecodeLoopNode`."; + throw new RespecializeException(send); + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(arg); + if (se.var != arg || se.contextLevel < 0) { + if (se.var instanceof Argument arg) { + replace(new LocalArgGreaterThanInt(arg, intValue).initialize(sourceCoord)); + } else { + replace(MessageSendNode.createGeneric(SymbolTable.symbolFor(">"), + new ExpressionNode[] {se.var.getReadNode(se.contextLevel, sourceCoord), + new IntegerLiteralNode(intValue)}, + sourceCoord)); + } + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalArgLessThanInt.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalArgLessThanInt.java new file mode 100644 index 000000000..f28b9f0e4 --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalArgLessThanInt.java @@ -0,0 +1,106 @@ +package trufflesom.interpreter.supernodes.compare; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Argument; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; + + +public final class LocalArgLessThanInt extends ExpressionNode { + private final Argument arg; + private final int argIdx; + private final long intValue; + + public LocalArgLessThanInt(final Argument arg, final long intValue) { + this.arg = arg; + this.argIdx = arg.index; + this.intValue = intValue; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object arg = frame.getArguments()[argIdx]; + if (arg instanceof Long) { + long argVal = (Long) arg; + return argVal < intValue; + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return fallbackGeneric(frame); + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] args) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new UnsupportedOperationException(); + } + + @Override + public boolean executeBoolean(final VirtualFrame frame) throws UnexpectedResultException { + Object arg = frame.getArguments()[argIdx]; + if (arg instanceof Long) { + long argVal = (Long) arg; + return argVal < intValue; + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return fallbackBool(frame); + } + + private boolean fallbackBool(final VirtualFrame frame) throws UnexpectedResultException { + Object result = makeGenericSend().doPreEvaluated(frame, + new Object[] {arg, intValue}); + if (result instanceof Boolean) { + return (Boolean) result; + } + throw new UnexpectedResultException(result); + } + + private Object fallbackGeneric(final VirtualFrame frame) { + return makeGenericSend().doPreEvaluated(frame, new Object[] {arg, intValue}); + } + + protected GenericMessageSendNode makeGenericSend() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + GenericMessageSendNode send = + MessageSendNode.createGeneric(SymbolTable.symbolFor("<"), new ExpressionNode[] { + new LocalArgumentReadNode(arg), new IntegerLiteralNode(intValue)}, sourceCoord); + + if (VmSettings.UseAstInterp) { + replace(send); + send.notifyDispatchInserted(); + return send; + } + + assert getParent() instanceof BytecodeLoopNode : "This node was expected to be a direct child of a `BytecodeLoopNode`."; + throw new RespecializeException(send); + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(arg); + if (se.var != arg || se.contextLevel < 0) { + if (se.var instanceof Argument a) { + replace(new LocalArgLessThanInt(a, intValue).initialize(sourceCoord)); + } else { + replace(MessageSendNode.createGeneric(SymbolTable.symbolFor("<"), + new ExpressionNode[] {se.var.getReadNode(se.contextLevel, sourceCoord), + new IntegerLiteralNode(intValue)}, + sourceCoord)); + } + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalFieldStringEqualsNode.java similarity index 99% rename from src/trufflesom/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java rename to src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalFieldStringEqualsNode.java index 079603d22..3c8340b82 100644 --- a/src/trufflesom/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/LocalFieldStringEqualsNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.supernodes; +package trufflesom.interpreter.supernodes.compare; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/NonLocalFieldStringEqualsNode.java similarity index 99% rename from src/trufflesom/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java rename to src/trufflesom/src/trufflesom/interpreter/supernodes/compare/NonLocalFieldStringEqualsNode.java index 22128db14..986ab6fb1 100644 --- a/src/trufflesom/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/NonLocalFieldStringEqualsNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.supernodes; +package trufflesom.interpreter.supernodes.compare; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/StringEqualsNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/StringEqualsNode.java similarity index 97% rename from src/trufflesom/src/trufflesom/interpreter/supernodes/StringEqualsNode.java rename to src/trufflesom/src/trufflesom/interpreter/supernodes/compare/StringEqualsNode.java index 11f8b3fcf..f7d900d6c 100644 --- a/src/trufflesom/src/trufflesom/interpreter/supernodes/StringEqualsNode.java +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/compare/StringEqualsNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.supernodes; +package trufflesom.interpreter.supernodes.compare; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Fallback; diff --git a/tests/trufflesom/supernodes/LesserGreaterThanTests.java b/tests/trufflesom/supernodes/LesserGreaterThanTests.java new file mode 100644 index 000000000..4d2e49a87 --- /dev/null +++ b/tests/trufflesom/supernodes/LesserGreaterThanTests.java @@ -0,0 +1,48 @@ +package trufflesom.supernodes; + +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.supernodes.compare.GreaterThanIntNode; +import trufflesom.interpreter.supernodes.compare.LessThanIntNode; +import trufflesom.interpreter.supernodes.compare.LocalArgGreaterThanInt; +import trufflesom.interpreter.supernodes.compare.LocalArgLessThanInt; +import trufflesom.tests.AstTestSetup; + + +public class LesserGreaterThanTests extends AstTestSetup { + @SuppressWarnings("unchecked") + private T assertThatMainNodeIs(final String test, final Class expectedNode) { + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | l1 l2 l3 l4 | \n" + test + " )"); + + ExpressionNode testExpr = read(seq, "expressions", 0); + assertThat(testExpr, instanceOf(expectedNode)); + return (T) testExpr; + } + + @Test + public void testGreaterThan() { + assertThatMainNodeIs("(1 + 3) > 0", GreaterThanIntNode.class); + + assertThatMainNodeIs("l1 > 0", GreaterThanIntNode.class); + assertThatMainNodeIs("3 > 0", GreaterThanIntNode.class); + assertThatMainNodeIs("3 > 0", GreaterThanIntNode.class); + + assertThatMainNodeIs("arg > 0", LocalArgGreaterThanInt.class); + } + + @Test + public void testLesserThan() { + assertThatMainNodeIs("(1 + 3) < 0", LessThanIntNode.class); + + assertThatMainNodeIs("l1 < 0", LessThanIntNode.class); + assertThatMainNodeIs("3 < 0", LessThanIntNode.class); + assertThatMainNodeIs("3 < 0", LessThanIntNode.class); + + assertThatMainNodeIs("arg < 0", LocalArgLessThanInt.class); + } +} diff --git a/tests/trufflesom/supernodes/StringEqualsTests.java b/tests/trufflesom/supernodes/StringEqualsTests.java index 8815df8e0..9acb7d26a 100644 --- a/tests/trufflesom/supernodes/StringEqualsTests.java +++ b/tests/trufflesom/supernodes/StringEqualsTests.java @@ -8,9 +8,9 @@ import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.SequenceNode; import trufflesom.interpreter.nodes.literals.BlockNode; -import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode; -import trufflesom.interpreter.supernodes.NonLocalFieldStringEqualsNode; -import trufflesom.interpreter.supernodes.StringEqualsNode; +import trufflesom.interpreter.supernodes.compare.LocalFieldStringEqualsNode; +import trufflesom.interpreter.supernodes.compare.NonLocalFieldStringEqualsNode; +import trufflesom.interpreter.supernodes.compare.StringEqualsNode; import trufflesom.tests.AstTestSetup;