1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Added unnamed constant inlining

This commit is contained in:
jespergravgaard 2017-10-13 08:06:55 +02:00
parent ccfa6bdbf3
commit 1a9ae72668
12 changed files with 148 additions and 42 deletions

View File

@ -136,6 +136,7 @@ public class Compiler {
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
optimizations.add(new Pass2CullEmptyBlocks(program));
optimizations.add(new Pass2ConstantIdentification(program));
optimizations.add(new Pass2ConstantInlining(program));
//optimizations.add(new Pass2ConstantPropagation(program));
//optimizations.add(new Pass2ConstantAdditionElimination(program));

View File

@ -4,6 +4,7 @@ import dk.camelot64.kickc.NumberParser;
import dk.camelot64.kickc.asm.parser.Asm6502BaseVisitor;
import dk.camelot64.kickc.asm.parser.Asm6502Parser;
import dk.camelot64.kickc.icl.*;
import dk.camelot64.kickc.passes.Pass1TypeInference;
import java.util.LinkedHashMap;
import java.util.Map;
@ -331,6 +332,19 @@ public class AsmFragment {
bindings.put(name, value);
return name;
}
} else if(value instanceof ConstantValue) {
SymbolType type = Pass1TypeInference.inferType(program.getScope(), (ConstantValue) value);
if (SymbolTypeBasic.BYTE.equals(type)) {
String name = "coby" + nextConstByteIdx++;
bindings.put(name, value);
return name;
} else if (SymbolTypeBasic.WORD.equals(type)) {
String name = "cowo" + nextConstByteIdx++;
bindings.put(name, value);
return name;
} else {
throw new RuntimeException("Unhandled constant type " + type);
}
} else if (value instanceof Label) {
String name = "la" + nextLabelIdx++;
bindings.put(name, value);
@ -439,6 +453,9 @@ public class AsmFragment {
} else if (constant instanceof ConstantVar) {
ConstantVar constantVar = (ConstantVar) constant;
return getAsmParameter(constantVar);
} else if (constant instanceof ConstantRef) {
ConstantVar constantVar = program.getScope().getConstant((ConstantRef) constant);
return getAsmParameter(constantVar);
} else if (constant instanceof ConstantUnary) {
ConstantUnary unary = (ConstantUnary) constant;
return unary.getOperator().toString() + toAsm(unary.getOperand());

View File

@ -42,13 +42,13 @@ public class Pass1TypeInference {
if (operator == null || assignment.getrValue1() == null) {
// Copy operation or Unary operation
RValue rValue = assignment.getrValue2();
SymbolType subType = inferType(rValue);
SymbolType subType = inferType(programScope, rValue);
SymbolType type = inferType(operator, subType);
symbol.setTypeInferred(type);
} else {
// Binary operation
SymbolType type1 = inferType(assignment.getrValue1());
SymbolType type2 = inferType(assignment.getrValue2());
SymbolType type1 = inferType(programScope, assignment.getrValue1());
SymbolType type2 = inferType(programScope, assignment.getrValue2());
SymbolType type = inferType(type1, operator, type2);
symbol.setTypeInferred(type);
}
@ -156,11 +156,14 @@ public class Pass1TypeInference {
}
}
public SymbolType inferType(RValue rValue) {
public static SymbolType inferType(ProgramScope programScope, RValue rValue) {
SymbolType type = null;
if (rValue instanceof VariableRef) {
Variable variable = programScope.getVariable((VariableRef) rValue);
type = variable.getType();
} else if (rValue instanceof ConstantRef) {
ConstantVar constVar = programScope.getConstant((ConstantRef) rValue);
type = constVar.getType();
} else if (rValue instanceof Symbol) {
Symbol rSymbol = (Symbol) rValue;
type = rSymbol.getType();
@ -171,6 +174,15 @@ public class Pass1TypeInference {
type = SymbolTypeBasic.STRING;
} else if (rValue instanceof ConstantBool) {
type = SymbolTypeBasic.BOOLEAN;
} else if (rValue instanceof ConstantUnary) {
ConstantUnary constUnary = (ConstantUnary) rValue;
SymbolType subType = inferType(programScope, constUnary.getOperand());
return inferType(constUnary.getOperator(), subType);
} else if (rValue instanceof ConstantBinary) {
ConstantBinary constBin = (ConstantBinary) rValue;
SymbolType leftType = inferType(programScope, constBin.getLeft());
SymbolType rightType = inferType(programScope, constBin.getRight());
return inferType(leftType, constBin.getOperator(), rightType);
}
if (type == null) {
throw new RuntimeException("Cannot infer type for " + rValue);

View File

@ -1,6 +1,5 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.*;
@ -32,7 +31,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
}
getLog().append("Alias " + str);
}
deleteVariables(aliases.getSymbolsToRemove());
deleteSymbols(aliases.getSymbolsToRemove());
return (aliases.size() > 0);
}

View File

@ -1,6 +1,5 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.ArrayList;
@ -25,7 +24,7 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
final Map<RValue, List<Statement>> usages = getAllUsages();
final List<VariableRef> simpleConditionVars = getSimpleConditions(assignments, usages);
removeAssignments(simpleConditionVars);
deleteVariables(simpleConditionVars);
deleteSymbols(simpleConditionVars);
return (simpleConditionVars.size()>0);
}

View File

@ -0,0 +1,52 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.icl.ConstantRef;
import dk.camelot64.kickc.icl.ConstantValue;
import dk.camelot64.kickc.icl.ConstantVar;
import dk.camelot64.kickc.icl.Program;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/** Compiler Pass consolidating unnamed constants into the place using them (instructions or the definition of another constant value) */
public class Pass2ConstantInlining extends Pass2SsaOptimization {
public Pass2ConstantInlining(Program program) {
super(program);
}
/**
* Consolidate unnamed constants into other constants value
* @return true optimization was performed. false if no optimization was possible.
*/
@Override
public boolean optimize() {
Map<ConstantRef, ConstantValue> unnamedConstants = findUnnamedConstants();
// Replace all usages of the unnamed constants
replaceVariables(unnamedConstants);
// Remove from symbol table
deleteSymbols(unnamedConstants.keySet());
for (ConstantRef constantRef : unnamedConstants.keySet()) {
getLog().append("Constant inlined " + constantRef.toString()+" = "+unnamedConstants.get(constantRef).toString(getProgram()));
}
return unnamedConstants.size()>0;
}
private Map<ConstantRef, ConstantValue> findUnnamedConstants() {
Map<ConstantRef, ConstantValue> unnamed = new HashMap<>();
Collection<ConstantVar> allConstants = getProgram().getScope().getAllConstants(true);
for (ConstantVar constant : allConstants) {
if(constant.getRef().isIntermediate()) {
unnamed.put(constant.getRef(), constant.getValue());
}
}
return unnamed;
}
}

View File

@ -1,6 +1,5 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.LinkedHashMap;
@ -25,7 +24,7 @@ public class Pass2RedundantPhiElimination extends Pass2SsaOptimization {
RValue alias = aliases.get(var);
getLog().append("Redundant Phi " + var.toString(getProgram()) + " " + alias.toString(getProgram()));
}
deleteVariables(aliases.keySet());
deleteSymbols(aliases.keySet());
return aliases.size()>0;
}

View File

@ -61,7 +61,7 @@ public abstract class Pass2SsaOptimization {
*
* @param aliases Variables that have alias values.
*/
public void replaceVariables(final Map<VariableRef, ? extends RValue> aliases) {
public void replaceVariables(final Map<? extends SymbolRef, ? extends RValue> aliases) {
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitAssignment(StatementAssignment assignment) {
@ -177,7 +177,7 @@ public abstract class Pass2SsaOptimization {
* @param rValue The RValue to find an alias for
* @return The alias to use. Null if no alias exists.
*/
private static RValue getAlias(Map<VariableRef, ? extends RValue> aliases, RValue rValue) {
private static RValue getAlias(Map<? extends SymbolRef, ? extends RValue> aliases, RValue rValue) {
RValue alias = aliases.get(rValue);
while (aliases.get(alias) != null) {
alias = aliases.get(alias);
@ -276,20 +276,9 @@ public abstract class Pass2SsaOptimization {
}
}
/**
* Remove symbols from the symbol table
*
* @param symbols The symbols to remove
*/
public void deleteSymbols(Collection<? extends Symbol> symbols) {
for (Symbol symbol : symbols) {
symbol.getScope().remove(symbol);
}
}
public void deleteVariables(Collection<? extends VariableRef> symbols) {
for (VariableRef variableRef : symbols) {
Symbol symbol = getSymbols().getSymbol(variableRef.getFullName());
public void deleteSymbols(Collection<? extends SymbolRef> symbols) {
for (SymbolRef symbolRef : symbols) {
Symbol symbol = getSymbols().getSymbol(symbolRef.getFullName());
symbol.getScope().remove(symbol);
}
}

View File

@ -24,7 +24,7 @@ public class Pass2UnaryNotSimplification extends Pass2SsaOptimization {
final Map<LValue, StatementAssignment> assignments = getAllAssignments();
final List<VariableRef> unusedComparisons = optimizeUnaryNots(assignments, usages);
removeAssignments(unusedComparisons);
deleteVariables(unusedComparisons);
deleteSymbols(unusedComparisons);
return (unusedComparisons.size() > 0);
}

View File

@ -1,6 +1,5 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.ArrayList;
@ -37,7 +36,7 @@ public class Pass3PhiMemCoalesce extends Pass2SsaOptimization {
phiMemCoalescer.visitGraph(getGraph());
removeAssignments(phiMemCoalescer.getRemove());
replaceVariables(phiMemCoalescer.getReplace());
deleteVariables(phiMemCoalescer.getRemove());
deleteSymbols(phiMemCoalescer.getRemove());
getLog().append("Coalesced down to " + phiEquivalenceClasses.size() + " phi equivalence classes");
return false;
}

View File

@ -81,21 +81,60 @@ public class Pass4CodeGeneration {
/**
* Add constant declarations for all scope constants
*
* @param asm The ASM program
* @param scope The scope
* @param asm The ASM program
* @param scopeRef The scope
*/
private void addConstants(AsmProgram asm, ScopeRef currentScope) {
Collection<ConstantVar> scopeConstants = program.getScope().getScope(currentScope).getAllConstants(false);
private void addConstants(AsmProgram asm, ScopeRef scopeRef) {
Scope scope = program.getScope().getScope(scopeRef);
Collection<ConstantVar> scopeConstants = scope.getAllConstants(false);
Set<String> added = new LinkedHashSet<>();
for (ConstantVar scopeConstant : scopeConstants) {
String asmName = scopeConstant.getLocalName(); // scopeConstant.getAsmName()
if (asmName != null && !added.contains(asmName)) {
asm.addConstant(asmName.replace("#","_").replace("$","_"), scopeConstant.getValue().toString(program));
added.add(asmName);
}
String asmName = scopeConstant.getLocalName(); // scopeConstant.getAsmName()
if (asmName != null && !added.contains(asmName)) {
asm.addConstant(asmName.replace("#", "_").replace("$", "_"), getConstantValueAsm(scopeConstant.getValue(), false));
added.add(asmName);
}
}
}
/**
* Get ASM code for a constant value
*
* @param value The constant value
* @param subOperator is this generated inside another operator (needing a parenthesis)
*
* @return The ASM string representing the constant value
*/
private String getConstantValueAsm(Constant value, boolean subOperator) {
if (value instanceof ConstantRef) {
value = program.getScope().getConstant((ConstantRef) value);
}
if (value instanceof ConstantVar) {
String asmName = ((ConstantVar) value).getLocalName(); // xxx.getAsmName()
return asmName.replace("#", "_").replace("$", "_");
} else if (value instanceof ConstantInteger) {
return String.format("$%x", ((ConstantInteger) value).getNumber());
} else if (value instanceof ConstantUnary) {
ConstantUnary unary = (ConstantUnary) value;
return
(subOperator ? "(" : "") +
unary.getOperator().getOperator() +
getConstantValueAsm(unary.getOperand(), true) +
(subOperator ? ")" : "");
} else if (value instanceof ConstantBinary) {
ConstantBinary binary = (ConstantBinary) value;
return
(subOperator ? "(" : "") +
getConstantValueAsm(binary.getLeft(), true) +
binary.getOperator().getOperator() +
getConstantValueAsm(binary.getRight(), true) +
(subOperator ? ")" : "");
} else {
throw new RuntimeException("Constant type not supported " + value);
}
}
/**
* Add label declarations for all scope variables assigned to ZP registers
*
@ -111,7 +150,7 @@ public class Pass4CodeGeneration {
Registers.RegisterZp registerZp = (Registers.RegisterZp) register;
String asmName = scopeVar.getAsmName();
if (asmName != null && !added.contains(asmName)) {
asm.addLabelDecl(asmName.replace("#","_").replace("$","_"), registerZp.getZp());
asm.addLabelDecl(asmName.replace("#", "_").replace("$", "_"), registerZp.getZp());
added.add(asmName);
}
}
@ -280,7 +319,7 @@ public class Pass4CodeGeneration {
}
transition.setGenerated(true);
} else {
program.getLog().append("Already generated transition from "+fromBlock.getLabel()+" to "+toBlock.getLabel()+ " - not generating it again!");
program.getLog().append("Already generated transition from " + fromBlock.getLabel() + " to " + toBlock.getLabel() + " - not generating it again!");
}
}
@ -357,7 +396,7 @@ public class Pass4CodeGeneration {
private PhiTransition findTransition(ControlFlowBlock fromBlock) {
PhiTransition transition = new PhiTransition(fromBlock);
boolean isCallTransition = toBlock.getLabel().equals(fromBlock.getCallSuccessor());
if(!isCallTransition) {
if (!isCallTransition) {
// If the transition is not a call - then attempt to join with other equal transition(s)
for (PhiTransition candidate : transitions.values()) {
if (candidate.equalAssignments(transition)) {

View File

@ -2,7 +2,7 @@ const byte* SCREEN = $0400;
const byte STAR = 81;
byte* VIC = $d000;
byte* BGCOL = VIC+$21;
byte* BGCOL = VIC+$10*2+1;
byte RED = 2;
main();