mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-09-08 17:54:40 +00:00
Added unnamed constant inlining
This commit is contained in:
parent
ccfa6bdbf3
commit
1a9ae72668
@ -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));
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -82,20 +82,59 @@ public class Pass4CodeGeneration {
|
||||
* Add constant declarations for all scope constants
|
||||
*
|
||||
* @param asm The ASM program
|
||||
* @param scope The scope
|
||||
* @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));
|
||||
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)) {
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user