Skip to content

Commit 8fbe6e4

Browse files
Merge pull request #30 from CompilerProgramming/develop
Initial null support in optimizing compiler - missing null checks
2 parents 6147af1 + ebfbdde commit 8fbe6e4

File tree

16 files changed

+634
-159
lines changed

16 files changed

+634
-159
lines changed

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -460,13 +460,10 @@ private boolean codeBoolean(AST.BinaryExpr binaryExpr) {
460460
jumpTo(l3);
461461
startBlock(l2);
462462
// Below we must write to the same temp
463-
//code(new Instruction.Move(new Operand.ConstantOperand(isAnd ? 0 : 1, typeDictionary.INT), new Operand.TempRegisterOperand(temp.reg)));
464463
code(new Instruction.Move(new Operand.ConstantOperand(isAnd ? 0 : 1, typeDictionary.INT), temp));
465464
jumpTo(l3);
466465
startBlock(l3);
467466
// leave temp on virtual stack
468-
// var temp2 = (Operand.TempRegisterOperand) pop();
469-
// pushOperand(new Operand.TempRegisterOperand(temp2.reg));
470467
return false;
471468
}
472469

@@ -483,10 +480,19 @@ private boolean compileBinaryExpr(AST.BinaryExpr binaryExpr) {
483480
indexed = compileExpr(binaryExpr.expr2);
484481
if (indexed)
485482
codeIndexedLoad();
486-
opCode = binaryExpr.op.str;
487483
Operand right = pop();
488484
Operand left = pop();
489-
if (left instanceof Operand.ConstantOperand leftconstant &&
485+
if (left instanceof Operand.NullConstantOperand &&
486+
right instanceof Operand.NullConstantOperand) {
487+
long value = 0;
488+
switch (opCode) {
489+
case "==": value = 1; break;
490+
case "!=": value = 0; break;
491+
default: throw new CompilerException("Invalid binary op");
492+
}
493+
pushConstant(value, typeDictionary.INT);
494+
}
495+
else if (left instanceof Operand.ConstantOperand leftconstant &&
490496
right instanceof Operand.ConstantOperand rightconstant) {
491497
long value = 0;
492498
switch (opCode) {
@@ -535,14 +541,22 @@ private boolean compileUnaryExpr(AST.UnaryExpr unaryExpr) {
535541
}
536542

537543
private boolean compileConstantExpr(AST.LiteralExpr constantExpr) {
538-
pushConstant(constantExpr.value.num.intValue(), constantExpr.type);
544+
if (constantExpr.type instanceof Type.TypeInteger)
545+
pushConstant(constantExpr.value.num.intValue(), constantExpr.type);
546+
else if (constantExpr.type instanceof Type.TypeNull)
547+
pushNullConstant(constantExpr.type);
548+
else throw new CompilerException("Invalid constant type");
539549
return false;
540550
}
541551

542552
private void pushConstant(long value, Type type) {
543553
pushOperand(new Operand.ConstantOperand(value, type));
544554
}
545555

556+
private void pushNullConstant(Type type) {
557+
pushOperand(new Operand.NullConstantOperand(type));
558+
}
559+
546560
private Operand.TempRegisterOperand createTemp(Type type) {
547561
var tempRegister = new Operand.TempRegisterOperand(registerPool.newTempReg(type));
548562
pushOperand(tempRegister);
@@ -552,8 +566,8 @@ private Operand.TempRegisterOperand createTemp(Type type) {
552566
Type typeOfOperand(Operand operand) {
553567
if (operand instanceof Operand.ConstantOperand constant)
554568
return constant.type;
555-
// else if (operand instanceof Operand.NullConstantOperand nullConstantOperand)
556-
// return nullConstantOperand.type;
569+
else if (operand instanceof Operand.NullConstantOperand nullConstantOperand)
570+
return nullConstantOperand.type;
557571
else if (operand instanceof Operand.RegisterOperand registerOperand)
558572
return registerOperand.type;
559573
else throw new CompilerException("Invalid operand");
@@ -569,7 +583,7 @@ private Operand.TempRegisterOperand createTempAndMove(Operand src) {
569583
private Operand.RegisterOperand ensureTemp() {
570584
Operand top = top();
571585
if (top instanceof Operand.ConstantOperand
572-
//|| top instanceof Operand.NullConstantOperand
586+
|| top instanceof Operand.NullConstantOperand
573587
|| top instanceof Operand.LocalRegisterOperand) {
574588
return createTempAndMove(pop());
575589
} else if (top instanceof Operand.IndexedOperand) {

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/InterferenceGraph.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void rename(Integer source, Integer target) {
6565
var toSet = edges.get(target);
6666
if (toSet == null) {
6767
//throw new RuntimeException("Cannot find edge " + target + " from " + source);
68-
return; // FIXME this is workaround to handle sceanrio where target is arg register but we need a better way
68+
return; // FIXME this is workaround to handle scenario where target is arg register but we need a better way
6969
}
7070
toSet.addAll(fromSet);
7171
// If any node interfered with from

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ public String toString() {
1818
}
1919
}
2020

21+
public static class NullConstantOperand extends Operand {
22+
public NullConstantOperand(Type type) {
23+
this.type = type;
24+
}
25+
@Override
26+
public String toString() {
27+
return "null";
28+
}
29+
}
30+
2131
public static class RegisterOperand extends Operand {
2232
final Register reg;
2333
protected RegisterOperand(Register reg) {

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -377,35 +377,40 @@ private boolean evalInstruction(Instruction instruction) {
377377
}
378378
case Instruction.Binary binaryInst -> {
379379
var cell = valueLattice.get(binaryInst.result().reg);
380-
LatticeElement left, right;
380+
LatticeElement left = null;
381+
LatticeElement right = null;
382+
// TODO we cannot yet evaluate null in comparisons
381383
if (binaryInst.left() instanceof Operand.ConstantOperand constant)
382384
left = new LatticeElement(V_CONSTANT, constant.value);
383385
else if (binaryInst.left() instanceof Operand.RegisterOperand registerOperand)
384386
left = valueLattice.get(registerOperand.reg);
385-
else throw new IllegalStateException();
386387
if (binaryInst.right() instanceof Operand.ConstantOperand constant)
387388
right = new LatticeElement(V_CONSTANT, constant.value);
388389
else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand)
389390
right = valueLattice.get(registerOperand.reg);
390-
else throw new IllegalStateException();
391-
switch (binaryInst.binOp) {
392-
case "+":
393-
case "-":
394-
case "*":
395-
case "/":
396-
case "%":
397-
changed = evalArith(cell, left, right, binaryInst.binOp);
398-
break;
399-
case "==":
400-
case "!=":
401-
case "<":
402-
case ">":
403-
case "<=":
404-
case ">=":
405-
changed = evalLogical(cell, left, right, binaryInst.binOp);
406-
break;
407-
default:
408-
throw new IllegalStateException();
391+
if (left != null && right != null) {
392+
switch (binaryInst.binOp) {
393+
case "+":
394+
case "-":
395+
case "*":
396+
case "/":
397+
case "%":
398+
changed = evalArith(cell, left, right, binaryInst.binOp);
399+
break;
400+
case "==":
401+
case "!=":
402+
case "<":
403+
case ">":
404+
case "<=":
405+
case ">=":
406+
changed = evalLogical(cell, left, right, binaryInst.binOp);
407+
break;
408+
default:
409+
throw new IllegalStateException();
410+
}
411+
}
412+
else {
413+
cell.setKind(V_VARYING);
409414
}
410415
}
411416
case Instruction.NewArray newArrayInst -> {

optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public Value interpret(ExecutionStack execStack, Frame frame) {
4848
if (retInst.value() instanceof Operand.ConstantOperand constantOperand) {
4949
execStack.stack[base] = new Value.IntegerValue(constantOperand.value);
5050
}
51+
else if (retInst.value() instanceof Operand.NullConstantOperand) {
52+
execStack.stack[base] = new Value.NullValue();
53+
}
5154
else if (retInst.value() instanceof Operand.RegisterOperand registerOperand) {
5255
execStack.stack[base] = execStack.stack[base+registerOperand.frameSlot()];
5356
}
@@ -63,6 +66,9 @@ else if (retInst.value() instanceof Operand.RegisterOperand registerOperand) {
6366
else if (moveInst.from() instanceof Operand.ConstantOperand constantOperand) {
6467
execStack.stack[base + toReg.frameSlot()] = new Value.IntegerValue(constantOperand.value);
6568
}
69+
else if (moveInst.from() instanceof Operand.NullConstantOperand) {
70+
execStack.stack[base + toReg.frameSlot()] = new Value.NullValue();
71+
}
6672
else throw new IllegalStateException();
6773
}
6874
else throw new IllegalStateException();
@@ -107,6 +113,9 @@ else if (cbrInst.condition() instanceof Operand.ConstantOperand constantOperand)
107113
else if (arg instanceof Operand.ConstantOperand constantOperand) {
108114
execStack.stack[base + reg] = new Value.IntegerValue(constantOperand.value);
109115
}
116+
else if (arg instanceof Operand.NullConstantOperand) {
117+
execStack.stack[base + reg] = new Value.NullValue();
118+
}
110119
reg += 1;
111120
}
112121
// Call function
@@ -135,31 +144,60 @@ else if (arg instanceof Operand.ConstantOperand constantOperand) {
135144
case Instruction.Binary binaryInst -> {
136145
long x, y;
137146
long value = 0;
138-
if (binaryInst.left() instanceof Operand.ConstantOperand constant)
139-
x = constant.value;
140-
else if (binaryInst.left() instanceof Operand.RegisterOperand registerOperand)
141-
x = ((Value.IntegerValue) execStack.stack[base + registerOperand.frameSlot()]).value;
142-
else throw new IllegalStateException();
143-
if (binaryInst.right() instanceof Operand.ConstantOperand constant)
144-
y = constant.value;
145-
else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand)
146-
y = ((Value.IntegerValue) execStack.stack[base + registerOperand.frameSlot()]).value;
147-
else throw new IllegalStateException();
148-
switch (binaryInst.binOp) {
149-
case "+": value = x + y; break;
150-
case "-": value = x - y; break;
151-
case "*": value = x * y; break;
152-
case "/": value = x / y; break;
153-
case "%": value = x % y; break;
154-
case "==": value = x == y ? 1 : 0; break;
155-
case "!=": value = x != y ? 1 : 0; break;
156-
case "<": value = x < y ? 1: 0; break;
157-
case ">": value = x > y ? 1 : 0; break;
158-
case "<=": value = x <= y ? 1 : 0; break;
159-
case ">=": value = x <= y ? 1 : 0; break;
160-
default: throw new IllegalStateException();
147+
boolean intOp = true;
148+
if (binaryInst.binOp.equals("==") || binaryInst.binOp.equals("!=")) {
149+
Operand.RegisterOperand nonNullLitOperand = null;
150+
if (binaryInst.left() instanceof Operand.NullConstantOperand) {
151+
nonNullLitOperand = (Operand.RegisterOperand)binaryInst.right();
152+
}
153+
else if (binaryInst.right() instanceof Operand.NullConstantOperand) {
154+
nonNullLitOperand = (Operand.RegisterOperand)binaryInst.left();
155+
}
156+
if (nonNullLitOperand != null) {
157+
intOp = false;
158+
Value otherValue = execStack.stack[base + nonNullLitOperand.frameSlot()];
159+
switch (binaryInst.binOp) {
160+
case "==": {
161+
value = otherValue instanceof Value.NullValue ? 1 : 0;
162+
break;
163+
}
164+
case "!=": {
165+
value = otherValue instanceof Value.NullValue ? 0 : 1;
166+
break;
167+
}
168+
default:
169+
throw new IllegalStateException();
170+
}
171+
execStack.stack[base + binaryInst.result().frameSlot()] = new Value.IntegerValue(value);
172+
}
173+
}
174+
if (intOp) {
175+
if (binaryInst.left() instanceof Operand.ConstantOperand constant)
176+
x = constant.value;
177+
else if (binaryInst.left() instanceof Operand.RegisterOperand registerOperand)
178+
x = ((Value.IntegerValue) execStack.stack[base + registerOperand.frameSlot()]).value;
179+
else throw new IllegalStateException();
180+
if (binaryInst.right() instanceof Operand.ConstantOperand constant)
181+
y = constant.value;
182+
else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand)
183+
y = ((Value.IntegerValue) execStack.stack[base + registerOperand.frameSlot()]).value;
184+
else throw new IllegalStateException();
185+
switch (binaryInst.binOp) {
186+
case "+": value = x + y; break;
187+
case "-": value = x - y; break;
188+
case "*": value = x * y; break;
189+
case "/": value = x / y; break;
190+
case "%": value = x % y; break;
191+
case "==": value = x == y ? 1 : 0; break;
192+
case "!=": value = x != y ? 1 : 0; break;
193+
case "<": value = x < y ? 1: 0; break;
194+
case ">": value = x > y ? 1 : 0; break;
195+
case "<=": value = x <= y ? 1 : 0; break;
196+
case ">=": value = x <= y ? 1 : 0; break;
197+
default: throw new IllegalStateException();
198+
}
199+
execStack.stack[base + binaryInst.result().frameSlot()] = new Value.IntegerValue(value);
161200
}
162-
execStack.stack[base + binaryInst.result().frameSlot()] = new Value.IntegerValue(value);
163201
}
164202
case Instruction.NewArray newArrayInst -> {
165203
execStack.stack[base + newArrayInst.destOperand().frameSlot()] = new Value.ArrayValue(newArrayInst.type);
@@ -172,6 +210,9 @@ else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand)
172210
if (arrayAppendInst.value() instanceof Operand.ConstantOperand constant) {
173211
arrayValue.values.add(new Value.IntegerValue(constant.value));
174212
}
213+
else if (arrayAppendInst.value() instanceof Operand.NullConstantOperand) {
214+
arrayValue.values.add(new Value.NullValue());
215+
}
175216
else if (arrayAppendInst.value() instanceof Operand.RegisterOperand registerOperand) {
176217
arrayValue.values.add(execStack.stack[base + registerOperand.frameSlot()]);
177218
}
@@ -193,6 +234,9 @@ else if (arrayStoreInst.indexOperand() instanceof Operand.RegisterOperand regist
193234
if (arrayStoreInst.sourceOperand() instanceof Operand.ConstantOperand constantOperand) {
194235
value = new Value.IntegerValue(constantOperand.value);
195236
}
237+
else if (arrayStoreInst.sourceOperand() instanceof Operand.NullConstantOperand) {
238+
value = new Value.NullValue();
239+
}
196240
else if (arrayStoreInst.sourceOperand() instanceof Operand.RegisterOperand registerOperand) {
197241
value = execStack.stack[base + registerOperand.frameSlot()];
198242
}
@@ -221,6 +265,9 @@ else if (arrayLoadInst.indexOperand() instanceof Operand.RegisterOperand registe
221265
if (setFieldInst.sourceOperand() instanceof Operand.ConstantOperand constant) {
222266
value = new Value.IntegerValue(constant.value);
223267
}
268+
else if (setFieldInst.sourceOperand() instanceof Operand.NullConstantOperand) {
269+
value = new Value.NullValue();
270+
}
224271
else if (setFieldInst.sourceOperand() instanceof Operand.RegisterOperand registerOperand) {
225272
value = execStack.stack[base + registerOperand.frameSlot()];
226273
}

optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ public IntegerValue(long value) {
1111
}
1212
public final long value;
1313
}
14+
static public class NullValue extends Value {
15+
public NullValue() {}
16+
}
1417
static public class ArrayValue extends Value {
1518
public final Type.TypeArray arrayType;
1619
public final ArrayList<Value> values;

0 commit comments

Comments
 (0)