From fb5175dbe85f95bd26bdcbc7165193624fecd25e Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 1 Apr 2011 13:58:10 +0200 Subject: [PATCH] generate comparisons and conditional jumps --- .../jet/codegen/ExpressionCodegen.java | 58 +++++++++++++------ .../org/jetbrains/jet/codegen/StackValue.java | 56 ++++++++++++++++++ idea/testData/codegen/gt.jet | 4 ++ .../jet/codegen/NamespaceGenTest.java | 9 +++ 4 files changed, 109 insertions(+), 18 deletions(-) create mode 100644 idea/testData/codegen/gt.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index dc54bafc9cf..b8144652ee8 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.*; @@ -72,7 +73,9 @@ public class ExpressionCodegen extends JetVisitor { public void visitIfExpression(JetIfExpression expression) { JetType expressionType = bindingContext.getExpressionType(expression); Type asmType = typeMapper.mapType(expressionType); - gen(expression.getCondition(), Type.BOOLEAN_TYPE); + int oldStackDepth = myStack.size(); + gen(expression.getCondition()); + assert myStack.size() == oldStackDepth+1; JetExpression thenExpression = expression.getThen(); JetExpression elseExpression = expression.getElse(); @@ -93,7 +96,7 @@ public class ExpressionCodegen extends JetVisitor { Label elseLabel = new Label(); - v.ifeq(elseLabel); // == 0, i.e. false + myStack.pop().condJump(elseLabel, true, v); // == 0, i.e. false gen(thenExpression, asmType); @@ -173,12 +176,7 @@ public class ExpressionCodegen extends JetVisitor { private void generateSingleBranchIf(JetExpression expression, boolean inverse) { Label endLabel = new Label(); - if (inverse) { - v.ifeq(endLabel); - } - else { - v.ifne(endLabel); - } + myStack.pop().condJump(endLabel, inverse, v); genToUnit(expression); @@ -449,7 +447,8 @@ public class ExpressionCodegen extends JetVisitor { @Override public void visitBinaryExpression(JetBinaryExpression expression) { - if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EQ) { + final IElementType opToken = expression.getOperationReference().getReferencedNameElementType(); + if (opToken == JetTokens.EQ) { generateAssignmentExpression(expression); return; } @@ -457,21 +456,44 @@ public class ExpressionCodegen extends JetVisitor { if (op instanceof FunctionDescriptor) { DeclarationDescriptor cls = op.getContainingDeclaration(); if (cls instanceof ClassDescriptor && cls.getName().equals("Int")) { - if (op.getName().equals("plus")) { - JetType returnType = ((FunctionDescriptor) op).getUnsubstitutedReturnType(); - if (returnType.equals(stdlib.getIntType())) { - gen(expression.getLeft(), Type.INT_TYPE); - gen(expression.getRight(), Type.INT_TYPE); - v.add(Type.INT_TYPE); - myStack.push(StackValue.onStack(Type.INT_TYPE)); - return; - } + if (op.getName().equals("compareTo")) { + generateCompareOp(expression, opToken); } + else { + int opcode; + if (op.getName().equals("plus")) { + opcode = Opcodes.IADD; + } + else { + throw new UnsupportedOperationException("Don't know how to generate binary op method " + op.getName()); + } + generateBinaryOp(expression, (FunctionDescriptor) op, opcode); + } + return; } } throw new UnsupportedOperationException("Don't know how to generate binary op " + expression); } + private void generateBinaryOp(JetBinaryExpression expression, FunctionDescriptor op, int opcode) { + JetType returnType = op.getUnsubstitutedReturnType(); + if (returnType.equals(stdlib.getIntType())) { + gen(expression.getLeft(), Type.INT_TYPE); + gen(expression.getRight(), Type.INT_TYPE); + v.visitInsn(Type.INT_TYPE.getOpcode(opcode)); + myStack.push(StackValue.onStack(Type.INT_TYPE)); + } + else { + throw new UnsupportedOperationException("Don't know how to generate binary op with return type " + returnType); + } + } + + private void generateCompareOp(JetBinaryExpression expression, IElementType opToken) { + gen(expression.getLeft(), Type.INT_TYPE); + gen(expression.getRight(), Type.INT_TYPE); + myStack.push(StackValue.icmp(opToken)); + } + private void generateAssignmentExpression(JetBinaryExpression expression) { if (expression.getLeft() instanceof JetReferenceExpression) { final JetReferenceExpression lhs = (JetReferenceExpression) expression.getLeft(); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index df855a340d7..ed881593f5c 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -1,6 +1,10 @@ package org.jetbrains.jet.codegen; +import com.intellij.psi.tree.IElementType; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lexer.JetTokens; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; @@ -22,6 +26,12 @@ public abstract class StackValue { return new Constant(value); } + public static StackValue icmp(IElementType opToken) { + return new IntCompare(opToken); + } + + public abstract void condJump(Label label, boolean inverse, InstructionAdapter v); + public static class Local extends StackValue { private final int index; private final JetType type; @@ -36,6 +46,17 @@ public abstract class StackValue { v.load(index, type); // TODO box/unbox } + + @Override + public void condJump(Label label, boolean inverse, InstructionAdapter v) { + put(Type.INT_TYPE, v); + if (inverse) { + v.ifeq(label); + } + else { + v.ifne(label); + } + } } public static class OnStack extends StackValue { @@ -48,6 +69,11 @@ public abstract class StackValue { @Override public void put(Type type, InstructionAdapter v) { } + + @Override + public void condJump(Label label, boolean inverse, InstructionAdapter v) { + throw new UnsupportedOperationException("don't know how to generate this condjump"); + } } public static class Constant extends StackValue { @@ -72,5 +98,35 @@ public abstract class StackValue { v.aconst(value); } } + + @Override + public void condJump(Label label, boolean inverse, InstructionAdapter v) { + throw new UnsupportedOperationException("don't know how to generate this condjump"); + } + } + + private static class IntCompare extends StackValue { + private final IElementType opToken; + + public IntCompare(IElementType opToken) { + this.opToken = opToken; + } + + @Override + public void put(Type type, InstructionAdapter v) { + throw new UnsupportedOperationException("don't know how to put an IntCompare on stack"); + } + + @Override + public void condJump(Label label, boolean inverse, InstructionAdapter v) { + int opcode; + if (opToken == JetTokens.GT) { + opcode = inverse ? Opcodes.IF_ICMPLE : Opcodes.IF_ICMPGT; + } + else { + throw new UnsupportedOperationException("don't know how to generate this condjump"); + } + v.visitJumpInsn(opcode, label); + } } } diff --git a/idea/testData/codegen/gt.jet b/idea/testData/codegen/gt.jet new file mode 100644 index 00000000000..c859ae89a38 --- /dev/null +++ b/idea/testData/codegen/gt.jet @@ -0,0 +1,4 @@ +fun foo(f: Int): Boolean { + if (f > 0) return true; + return false; +} diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 5c7cae20435..f7d9e8bb924 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -132,6 +132,15 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { assertEquals(2, main.invoke(null)); } + public void testGt() throws Exception { + loadFile("gt.jet"); + + System.out.println(generateToText()); + final Method main = generateFunction(); + assertEquals(true, main.invoke(null, 1)); + assertEquals(false, main.invoke(null, 0)); + } + private void loadFile(final String name) { myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/" + name); }