Add IR parser of cast instructions

This commit is contained in:
Alexey Andreev 2016-12-03 20:39:03 +03:00
parent 825acfc85a
commit 2b94a8b05c
9 changed files with 160 additions and 20 deletions

View File

@ -232,7 +232,7 @@ class StatementGenerator implements InstructionVisitor {
case SHORT:
value = Expr.unary(UnaryOperation.INT_TO_SHORT, null, value);
break;
case CHARACTER:
case CHAR:
value = Expr.unary(UnaryOperation.INT_TO_CHAR, null, value);
break;
}

View File

@ -448,7 +448,7 @@ public class Interpreter {
case SHORT:
result = (short) a;
break;
case CHARACTER:
case CHAR:
result = (char) a;
break;
default:
@ -467,7 +467,7 @@ public class Interpreter {
case SHORT:
result = (Short) a;
break;
case CHARACTER:
case CHAR:
result = (Character) a;
break;
default:

View File

@ -231,7 +231,7 @@ public class ValueEmitter {
case SHORT:
return IntegerSubtype.SHORT;
case CHARACTER:
return IntegerSubtype.CHARACTER;
return IntegerSubtype.CHAR;
default:
break;
}
@ -776,7 +776,7 @@ public class ValueEmitter {
return ValueType.BYTE;
case SHORT:
return ValueType.SHORT;
case CHARACTER:
case CHAR:
return ValueType.CHARACTER;
}
throw new IllegalArgumentException("Unknown subtype: " + subtype);
@ -794,7 +794,7 @@ public class ValueEmitter {
throw new EmitException("Can't cast non-short value: " + type);
}
break;
case CHARACTER:
case CHAR:
if (type != ValueType.CHARACTER) {
throw new EmitException("Can't cast non-char value: " + type);
}

View File

@ -15,12 +15,8 @@
*/
package org.teavm.model.instructions;
/**
*
* @author Alexey Andreev
*/
public enum IntegerSubtype {
BYTE,
SHORT,
CHARACTER
CHAR
}

View File

@ -560,7 +560,7 @@ public class GlobalValueNumbering implements MethodOptimization {
case SHORT:
evaluatedConstant = value.intValue() << 16 >> 16;
break;
case CHARACTER:
case CHAR:
evaluatedConstant = value.intValue() & 0xFFFF;
break;
}

View File

@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.teavm.model.BasicBlock;
@ -40,12 +41,17 @@ 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.CastInstruction;
import org.teavm.model.instructions.CastIntegerDirection;
import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction;
import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.IntegerSubtype;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.JumpInstruction;
@ -290,6 +296,9 @@ public class ListingParser {
case "invokeStatic":
parseInvoke(block, receiver);
break;
case "cast":
parseCast(block, receiver);
break;
default:
unexpected();
break;
@ -549,6 +558,125 @@ public class ListingParser {
insn.getArguments().addAll(arguments);
}
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
}
private void parseCast(BasicBlock block, Variable receiver) throws IOException, ListingParseException {
lexer.nextToken();
Variable value = expectVariable();
expect(ListingToken.IDENTIFIER);
switch ((String) lexer.getTokenValue()) {
case "from":
parseNumericCast(block, receiver, value);
break;
case "to":
parseObjectCast(block, receiver, value);
break;
default:
unexpected();
}
}
private void parseNumericCast(BasicBlock block, Variable receiver, Variable value)
throws IOException, ListingParseException {
lexer.nextToken();
NumericTypeOrIntegerSubtype source = expectTypeOrIntegerSubtype();
if (source.subtype != null) {
CastIntegerInstruction insn = new CastIntegerInstruction(source.subtype,
CastIntegerDirection.TO_INTEGER);
expectKeyword("to");
expectKeyword("int");
insn.setReceiver(receiver);
insn.setValue(value);
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
} else {
expectKeyword("to");
expect(ListingToken.IDENTIFIER);
NumericTypeOrIntegerSubtype target = expectTypeOrIntegerSubtype();
if (target.subtype != null) {
if (source.type != NumericOperandType.INT) {
throw new ListingParseException("Only int can be cast to "
+ target.subtype.name().toLowerCase(Locale.ROOT), lexer.getIndex());
}
CastIntegerInstruction insn = new CastIntegerInstruction(source.subtype,
CastIntegerDirection.FROM_INTEGER);
insn.setReceiver(receiver);
insn.setValue(value);
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
} else {
CastNumberInstruction insn = new CastNumberInstruction(source.type, target.type);
insn.setReceiver(receiver);
insn.setValue(value);
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
}
}
}
private NumericTypeOrIntegerSubtype expectTypeOrIntegerSubtype() throws IOException, ListingParseException {
IntegerSubtype subtype = null;
NumericOperandType type = null;
expect(ListingToken.IDENTIFIER);
switch ((String) lexer.getTokenValue()) {
case "byte":
subtype = IntegerSubtype.BYTE;
break;
case "short":
subtype = IntegerSubtype.SHORT;
break;
case "char":
subtype = IntegerSubtype.CHAR;
break;
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:
unexpected();
return null;
}
lexer.nextToken();
return new NumericTypeOrIntegerSubtype(type, subtype);
}
private static class NumericTypeOrIntegerSubtype {
NumericOperandType type;
IntegerSubtype subtype;
public NumericTypeOrIntegerSubtype(NumericOperandType type, IntegerSubtype subtype) {
this.type = type;
this.subtype = subtype;
}
}
private void parseObjectCast(BasicBlock block, Variable receiver, Variable value)
throws IOException, ListingParseException {
lexer.nextToken();
expect(ListingToken.IDENTIFIER);
ValueType type = ValueType.parseIfPossible((String) lexer.getTokenValue());
if (type == null) {
throw new ListingParseException("Unparseable type", lexer.getTokenStart());
}
lexer.nextToken();
CastInstruction insn = new CastInstruction();
insn.setReceiver(receiver);
insn.setValue(value);
insn.setTargetType(type);
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
}

View File

@ -185,12 +185,7 @@ public class ProgramParser {
}
for (LocalVariableNode localVar : method.localVariables) {
int location = labelIndexes.get(localVar.start.getLabel());
List<LocalVariableNode> vars = localVariableMap.get(location);
if (vars == null) {
vars = new ArrayList<>();
localVariableMap.put(location, vars);
}
vars.add(localVar);
localVariableMap.computeIfAbsent(location, k -> new ArrayList<>()).add(localVar);
}
targetInstructions = new ArrayList<>(instructions.size());
targetInstructions.addAll(Collections.nCopies(instructions.size(), null));
@ -1004,7 +999,7 @@ public class ProgramParser {
}
case Opcodes.CALOAD: {
loadArrayElement(1, ArrayElementType.CHAR);
CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.CHARACTER,
CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.CHAR,
CastIntegerDirection.TO_INTEGER);
insn.setValue(getVariable(popSingle()));
insn.setReceiver(getVariable(pushSingle()));
@ -1492,7 +1487,7 @@ public class ProgramParser {
break;
}
case Opcodes.I2C: {
CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.CHARACTER,
CastIntegerInstruction insn = new CastIntegerInstruction(IntegerSubtype.CHAR,
CastIntegerDirection.FROM_INTEGER);
insn.setValue(getVariable(popSingle()));
insn.setReceiver(getVariable(pushSingle()));

View File

@ -26,6 +26,9 @@ import org.junit.Assert;
import org.junit.Test;
import org.teavm.model.BasicBlock;
import org.teavm.model.Program;
import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction;
import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
@ -102,6 +105,18 @@ public class ParserTest {
assertNotNull(invoke.getInstance());
}
@Test
public void casting() throws Exception {
Program program = runTest("casting");
assertEquals(1, program.basicBlockCount());
BasicBlock block = program.basicBlockAt(0);
assertTrue(block.getInstructions().get(0) instanceof CastInstruction);
assertTrue(block.getInstructions().get(1) instanceof CastIntegerInstruction);
assertTrue(block.getInstructions().get(2) instanceof CastIntegerInstruction);
assertTrue(block.getInstructions().get(3) instanceof CastNumberInstruction);
}
private Program runTest(String name) throws IOException {
ClassLoader classLoader = ParserTest.class.getClassLoader();
String path = "model/text/" + name + ".txt";

View File

@ -0,0 +1,6 @@
$block
@r1 := cast @a to `Ljava/lang/String;`
@r2 := cast @b from int to char
@r3 := cast @c from byte to int
@r4 := cast @d from double to long
return @r1