diff --git a/core/src/main/java/org/teavm/model/text/ListingParser.java b/core/src/main/java/org/teavm/model/text/ListingParser.java index cc1820e38..f2df6e9da 100644 --- a/core/src/main/java/org/teavm/model/text/ListingParser.java +++ b/core/src/main/java/org/teavm/model/text/ListingParser.java @@ -23,6 +23,8 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import org.teavm.model.BasicBlock; +import org.teavm.model.Incoming; +import org.teavm.model.Phi; import org.teavm.model.Program; import org.teavm.model.TextLocation; import org.teavm.model.Variable; @@ -30,11 +32,14 @@ import org.teavm.model.instructions.ArrayElementType; import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryBranchingInstruction; +import org.teavm.model.instructions.BinaryInstruction; +import org.teavm.model.instructions.BinaryOperation; import org.teavm.model.instructions.BranchingCondition; import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.EmptyInstruction; import org.teavm.model.instructions.ExitInstruction; import org.teavm.model.instructions.JumpInstruction; +import org.teavm.model.instructions.NumericOperandType; import org.teavm.model.instructions.PutElementInstruction; public class ListingParser { @@ -244,6 +249,19 @@ public class ListingParser { parseAssignmentVariable(block, receiver, variable); break; } + case IDENTIFIER: { + String keyword = (String) lexer.getTokenValue(); + switch (keyword) { + case "phi": + lexer.nextToken(); + parsePhi(block, receiver); + break; + default: + unexpected(); + break; + } + break; + } default: unexpected(); } @@ -261,11 +279,69 @@ public class ListingParser { block.getInstructions().add(insn); break; } + case ADD: + parseBinary(block, receiver, variable, BinaryOperation.ADD); + break; + case SUBTRACT: + parseBinary(block, receiver, variable, BinaryOperation.SUBTRACT); + break; + case MULTIPLY: + parseBinary(block, receiver, variable, BinaryOperation.MULTIPLY); + break; + case DIVIDE: + parseBinary(block, receiver, variable, BinaryOperation.DIVIDE); + break; + case REMAINDER: + parseBinary(block, receiver, variable, BinaryOperation.MODULO); + break; + case AND: + parseBinary(block, receiver, variable, BinaryOperation.AND); + break; + case OR: + parseBinary(block, receiver, variable, BinaryOperation.OR); + break; + case XOR: + parseBinary(block, receiver, variable, BinaryOperation.XOR); + break; + case SHIFT_LEFT: + parseBinary(block, receiver, variable, BinaryOperation.SHIFT_LEFT); + break; + case SHIFT_RIGHT: + parseBinary(block, receiver, variable, BinaryOperation.SHIFT_RIGHT); + break; + case SHIFT_RIGHT_UNSIGNED: + parseBinary(block, receiver, variable, BinaryOperation.SHIFT_RIGHT_UNSIGNED); + break; + case IDENTIFIER: + switch ((String) lexer.getTokenValue()) { + case "compareTo": + parseBinary(block, receiver, variable, BinaryOperation.COMPARE); + break; + default: + unexpected(); + break; + } + break; default: unexpected(); } } + private void parseBinary(BasicBlock block, Variable receiver, Variable first, BinaryOperation operation) + throws IOException, ListingParseException { + lexer.nextToken(); + Variable second = expectVariable(); + expectKeyword("as"); + NumericOperandType type = expectNumericType(); + + BinaryInstruction instruction = new BinaryInstruction(operation, type); + instruction.setFirstOperand(first); + instruction.setSecondOperand(second); + instruction.setReceiver(receiver); + + block.getInstructions().add(instruction); + } + private void parseArrayAssignment(BasicBlock block, Variable array) throws IOException, ListingParseException { Variable index = expectVariable(); expect(ListingToken.RIGHT_SQUARE_BRACKET); @@ -284,6 +360,30 @@ public class ListingParser { block.getInstructions().add(insn); } + private void parsePhi(BasicBlock block, Variable receiver) throws IOException, ListingParseException { + int phiStart = lexer.getIndex(); + + Phi phi = new Phi(); + while (true) { + Incoming incoming = new Incoming(); + incoming.setValue(expectVariable()); + expectKeyword("from"); + incoming.setSource(expectBlock()); + phi.getIncomings().add(incoming); + + if (lexer.getToken() != ListingToken.COMMA) { + break; + } + lexer.nextToken(); + } + + if (!block.getInstructions().isEmpty() || block.getExceptionVariable() != null) { + throw new ListingParseException("Phi must be first instruction in block", phiStart); + } + + block.getPhis().add(phi); + } + private void parseIf(BasicBlock block) throws IOException, ListingParseException { Variable first = expectVariable(); @@ -405,6 +505,30 @@ public class ListingParser { return type; } + private NumericOperandType expectNumericType() throws IOException, ListingParseException { + expect(ListingToken.IDENTIFIER); + NumericOperandType type; + switch ((String) lexer.getTokenValue()) { + case "int": + type = NumericOperandType.INT; + break; + case "long": + type = NumericOperandType.LONG; + break; + case "float": + type = NumericOperandType.FLOAT; + break; + case "double": + type = NumericOperandType.DOUBLE; + break; + default: + throw new ListingParseException("Unknown numeric type: " + lexer.getTokenValue(), + lexer.getTokenStart()); + } + lexer.nextToken(); + return type; + } + private Variable expectVariable() throws IOException, ListingParseException { expect(ListingToken.VARIABLE); String variableName = (String) lexer.getTokenValue(); diff --git a/core/src/test/java/org/teavm/model/text/ParserTest.java b/core/src/test/java/org/teavm/model/text/ParserTest.java index 449db67e5..765915b47 100644 --- a/core/src/test/java/org/teavm/model/text/ParserTest.java +++ b/core/src/test/java/org/teavm/model/text/ParserTest.java @@ -41,6 +41,13 @@ public class ParserTest { } } + @Test + public void phi() throws Exception { + Program program = runTest("phi"); + Assert.assertEquals(4, program.basicBlockCount()); + Assert.assertEquals(2, program.basicBlockAt(3).getPhis().size()); + } + private Program runTest(String name) throws IOException { ClassLoader classLoader = ParserTest.class.getClassLoader(); String path = "model/text/" + name + ".txt"; diff --git a/core/src/test/resources/model/text/phi.txt b/core/src/test/resources/model/text/phi.txt new file mode 100644 index 000000000..f85b20291 --- /dev/null +++ b/core/src/test/resources/model/text/phi.txt @@ -0,0 +1,11 @@ +$test + if @param == 0 then goto $whenzero else goto $whennonzero +$whenzero + goto $joint +$whennonzero + goto $joint +$joint + @u := phi @a from $whenzero, @b from $whennonzero + @v := phi @x from $whenzero, @y from $whennonzero + @result := @u + @v as int + return @result