Add IR parser of binary operations and phi functions

This commit is contained in:
Alexey Andreev 2016-12-03 18:10:31 +03:00
parent 6148d7a943
commit f6308c1782
3 changed files with 142 additions and 0 deletions

View File

@ -23,6 +23,8 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Phi;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.TextLocation; import org.teavm.model.TextLocation;
import org.teavm.model.Variable; 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.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction; 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.BranchingCondition;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.EmptyInstruction; import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.ExitInstruction; import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.JumpInstruction; import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.NumericOperandType;
import org.teavm.model.instructions.PutElementInstruction; import org.teavm.model.instructions.PutElementInstruction;
public class ListingParser { public class ListingParser {
@ -244,6 +249,19 @@ public class ListingParser {
parseAssignmentVariable(block, receiver, variable); parseAssignmentVariable(block, receiver, variable);
break; break;
} }
case IDENTIFIER: {
String keyword = (String) lexer.getTokenValue();
switch (keyword) {
case "phi":
lexer.nextToken();
parsePhi(block, receiver);
break;
default:
unexpected();
break;
}
break;
}
default: default:
unexpected(); unexpected();
} }
@ -261,11 +279,69 @@ public class ListingParser {
block.getInstructions().add(insn); block.getInstructions().add(insn);
break; 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: default:
unexpected(); 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 { private void parseArrayAssignment(BasicBlock block, Variable array) throws IOException, ListingParseException {
Variable index = expectVariable(); Variable index = expectVariable();
expect(ListingToken.RIGHT_SQUARE_BRACKET); expect(ListingToken.RIGHT_SQUARE_BRACKET);
@ -284,6 +360,30 @@ public class ListingParser {
block.getInstructions().add(insn); 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 { private void parseIf(BasicBlock block) throws IOException, ListingParseException {
Variable first = expectVariable(); Variable first = expectVariable();
@ -405,6 +505,30 @@ public class ListingParser {
return type; 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 { private Variable expectVariable() throws IOException, ListingParseException {
expect(ListingToken.VARIABLE); expect(ListingToken.VARIABLE);
String variableName = (String) lexer.getTokenValue(); String variableName = (String) lexer.getTokenValue();

View File

@ -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 { private Program runTest(String name) throws IOException {
ClassLoader classLoader = ParserTest.class.getClassLoader(); ClassLoader classLoader = ParserTest.class.getClassLoader();
String path = "model/text/" + name + ".txt"; String path = "model/text/" + name + ".txt";

View File

@ -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