mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Add IR parser of cast instructions
This commit is contained in:
parent
825acfc85a
commit
2b94a8b05c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -15,12 +15,8 @@
|
|||
*/
|
||||
package org.teavm.model.instructions;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public enum IntegerSubtype {
|
||||
BYTE,
|
||||
SHORT,
|
||||
CHARACTER
|
||||
CHAR
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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";
|
||||
|
|
6
core/src/test/resources/model/text/casting.txt
Normal file
6
core/src/test/resources/model/text/casting.txt
Normal 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
|
Loading…
Reference in New Issue
Block a user