mirror of https://gitlab.com/camelot/kickc.git
Merge branch '815-procedure-compilation' into 'master'
More procedure compilation Closes #815 See merge request camelot/kickc!44
This commit is contained in:
commit
f759c5c9c1
|
@ -59,7 +59,7 @@ public class Compiler {
|
|||
return program;
|
||||
}
|
||||
|
||||
void setDisableUplift(boolean disableUplift) {
|
||||
public void setDisableUplift(boolean disableUplift) {
|
||||
this.disableUplift = disableUplift;
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ public class Compiler {
|
|||
pass2FinalizeAllNumbers();
|
||||
|
||||
//getLog().append("\nCONTROL FLOW GRAPH PASS 2");
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
//getLog().append(program.prettyControlFlowGraph());
|
||||
|
||||
//getLog().append("SYMBOL TABLE PASS 2");
|
||||
//getLog().append(program.getScope().toString(program, null));
|
||||
|
@ -220,7 +220,7 @@ public class Compiler {
|
|||
new Pass1GenerateControlFlowGraph(program).execute();
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("FIRST CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new Pass1ResolveForwardReferences(program).execute();
|
||||
new Pass1ByteXIntrinsicRewrite(program).execute();
|
||||
|
@ -256,7 +256,7 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("CONTROL FLOW GRAPH BEFORE SIZEOF FIX");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
|
||||
new Pass1PointerSizeofFix(program).execute(); // After this point in the code all pointer math is byte-based
|
||||
|
@ -270,7 +270,7 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("CONTROL FLOW GRAPH AFTER UNWIND");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
|
||||
new PassNDeInlineCastValues(program, true).execute();
|
||||
|
@ -283,7 +283,7 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("CONTROL FLOW GRAPH BEFORE INLINING");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new Pass1ProcedureInline(program).execute();
|
||||
new PassNStatementIndices(program).step();
|
||||
|
@ -293,7 +293,7 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("INITIAL CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
|
||||
new Pass1EliminateUncalledProcedures(program).execute();
|
||||
|
@ -314,14 +314,14 @@ public class Compiler {
|
|||
new Pass1CallStackVarConvert(program).execute();
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("PROCEDURE CALLS");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new Pass1CallStack(program).execute();
|
||||
new Pass1CallVar(program).execute();
|
||||
new Pass1CallPhiParameters(program).execute();
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("PROCEDURE PARAMETERS");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new PassNUnwindLValueLists(program).execute();
|
||||
new Pass1GenerateSingleStaticAssignmentForm(program).execute();
|
||||
|
@ -334,7 +334,7 @@ public class Compiler {
|
|||
|
||||
|
||||
getLog().append("\nCONTROL FLOW GRAPH SSA");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
|
||||
getLog().append("SYMBOL TABLE SSA");
|
||||
getLog().append(program.getScope().toStringVars(program, false));
|
||||
|
@ -465,7 +465,7 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerboseLoopUnroll()) {
|
||||
getLog().append("CONTROL FLOW GRAPH BEFORE UNROLLING");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
|
||||
boolean unrolled;
|
||||
|
@ -474,7 +474,7 @@ public class Compiler {
|
|||
if(unrolled) {
|
||||
if(getLog().isVerboseLoopUnroll()) {
|
||||
getLog().append("UNROLLED CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
pass2Optimize();
|
||||
new Pass2LoopUnrollAssertComplete(program).step();
|
||||
|
@ -560,7 +560,7 @@ public class Compiler {
|
|||
getLog().append("Successful SSA optimization " + optimization.getClass().getSimpleName() + "");
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -583,7 +583,7 @@ public class Compiler {
|
|||
new Pass3PhiLifting(program).perform();
|
||||
new PassNBlockSequencePlanner(program).step();
|
||||
//getLog().append("CONTROL FLOW GRAPH - PHI LIFTED");
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
//getLog().append(program.prettyControlFlowGraph());
|
||||
pass2AssertSSA();
|
||||
new Pass3AddNopBeforeCallOns(program).generate();
|
||||
new PassNStatementIndices(program).execute();
|
||||
|
@ -604,17 +604,17 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new PassNCullEmptyBlocks(program, false).step();
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new PassNRenumberLabels(program, false).execute();
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
}
|
||||
new PassNBlockSequencePlanner(program).step();
|
||||
new Pass3AddNopBeforeCallOns(program).generate();
|
||||
|
@ -632,12 +632,12 @@ public class Compiler {
|
|||
|
||||
// program.getLiveRangeVariablesEffective();
|
||||
// getLog().append("CONTROL FLOW GRAPH - LIVE RANGES FOUND");
|
||||
// getLog().append(program.getGraph().toString(program));
|
||||
// getLog().append(program.prettyControlFlowGraph());
|
||||
|
||||
program.getLiveRangeVariablesEffective();
|
||||
|
||||
getLog().append("\nFINAL CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
getLog().append(program.prettyControlFlowGraph());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.fragment;
|
|||
|
||||
import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueHandler;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
|
@ -41,7 +42,7 @@ public class AsmEncodingHelper {
|
|||
public static Set<StringEncoding> getEncoding(Value value) {
|
||||
LinkedHashSet<StringEncoding> encodings = new LinkedHashSet<>();
|
||||
ProgramValue programValue = new ProgramValue.GenericValue(value);
|
||||
ProgramValueHandler handler = (ProgramValue pVal, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) -> {
|
||||
ProgramValueHandler handler = (ProgramValue pVal, Statement currentStmt, ListIterator<Statement> stmtIt, Graph.Block currentBlock) -> {
|
||||
Value val = pVal.get();
|
||||
if(val instanceof ConstantChar) {
|
||||
encodings.add(((ConstantChar) val).getEncoding());
|
||||
|
|
|
@ -4,10 +4,7 @@ import dk.camelot64.kickc.asm.AsmFormat;
|
|||
import dk.camelot64.kickc.fragment.signature.AsmFragmentBindings;
|
||||
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
|
||||
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignatureExpr;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.ControlFlowGraph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.operators.Operator;
|
||||
import dk.camelot64.kickc.model.operators.OperatorBinary;
|
||||
import dk.camelot64.kickc.model.operators.OperatorUnary;
|
||||
|
@ -92,7 +89,7 @@ final public class AsmFragmentInstanceSpecBuilder {
|
|||
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
|
||||
}
|
||||
|
||||
public static AsmFragmentInstanceSpec conditionalJump(StatementConditionalJump conditionalJump, ControlFlowBlock block, Program program) {
|
||||
public static AsmFragmentInstanceSpec conditionalJump(StatementConditionalJump conditionalJump, Graph.Block block, Program program) {
|
||||
AsmFragmentBindings bindings = new AsmFragmentBindings(program);
|
||||
ScopeRef codeScope = program.getStatementInfos().getBlock(conditionalJump).getScope();
|
||||
AsmFragmentSignature signature = conditionalJumpSignature(bindings, conditionalJump, block, program.getGraph());
|
||||
|
@ -185,8 +182,8 @@ final public class AsmFragmentInstanceSpecBuilder {
|
|||
private static AsmFragmentSignature conditionalJumpSignature(
|
||||
AsmFragmentBindings bindings,
|
||||
StatementConditionalJump conditionalJump,
|
||||
ControlFlowBlock block,
|
||||
ControlFlowGraph graph) {
|
||||
Graph.Block block,
|
||||
Graph graph) {
|
||||
AsmFragmentSignatureExpr rVal1SignatureExpr = null;
|
||||
if (conditionalJump.getrValue1() instanceof ConstantInteger && ((ConstantInteger) conditionalJump.getrValue1()).getValue() == 0) {
|
||||
rVal1SignatureExpr = new AsmFragmentSignatureExpr.Number(new ConstantInteger(0L));
|
||||
|
@ -212,7 +209,7 @@ final public class AsmFragmentInstanceSpecBuilder {
|
|||
}
|
||||
|
||||
LabelRef destination = conditionalJump.getDestination();
|
||||
ControlFlowBlock destinationBlock = graph.getBlock(destination);
|
||||
Graph.Block destinationBlock = graph.getBlock(destination);
|
||||
String destinationLabel;
|
||||
if (destinationBlock.hasPhiBlock()) {
|
||||
destinationLabel =
|
||||
|
|
|
@ -5,6 +5,7 @@ import dk.camelot64.kickc.model.values.LabelRef;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A set of blocks
|
||||
|
@ -22,14 +23,8 @@ public interface BlockSet {
|
|||
* @param graph The control flow graph containing the blocks
|
||||
* @return The blocks of the loop (in the same order as they appear in the control flow graph.)
|
||||
*/
|
||||
default List<ControlFlowBlock> getBlocks(ControlFlowGraph graph) {
|
||||
ArrayList<ControlFlowBlock> controlFlowBlocks = new ArrayList<>();
|
||||
for(ControlFlowBlock block : graph.getAllBlocks()) {
|
||||
if(getBlocks().contains(block.getLabel())) {
|
||||
controlFlowBlocks.add(block);
|
||||
}
|
||||
}
|
||||
return controlFlowBlocks;
|
||||
default List<Graph.Block> getBlocks(Graph graph) {
|
||||
return graph.getAllBlocks().stream().filter(block -> getBlocks().contains(block.getLabel())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,8 +2,6 @@ package dk.camelot64.kickc.model;
|
|||
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.symbols.Symbol;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
|
||||
|
@ -17,7 +15,7 @@ import java.util.ListIterator;
|
|||
* The connections defines the control flow of the program.
|
||||
* The block only knows its own successors. To find predecessor blocks access to the entire graph is needed.
|
||||
*/
|
||||
public class ControlFlowBlock {
|
||||
public class ControlFlowBlock implements Graph.Block {
|
||||
|
||||
/** The label representing the block. */
|
||||
private LabelRef label;
|
||||
|
@ -139,16 +137,6 @@ public class ControlFlowBlock {
|
|||
return statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the block the entry of a procedure, ie. the first block of the code of the procedure.
|
||||
*
|
||||
* @return true if this is the entry of a procedure
|
||||
*/
|
||||
public boolean isProcedureEntry(Program program) {
|
||||
Symbol symbol = program.getScope().getSymbol(getLabel());
|
||||
return (symbol instanceof Procedure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the block the exit of a procedure, ie. the last block of code of the the procedure
|
||||
*
|
||||
|
@ -159,27 +147,11 @@ public class ControlFlowBlock {
|
|||
return getLabel().isProcExit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the procedure, that the block is part of. Null if the block is not part of a procedure.
|
||||
*
|
||||
* @return the procedure, that the block is part of
|
||||
*/
|
||||
public Procedure getProcedure(Program program) {
|
||||
final ScopeRef scopeRef = getScope();
|
||||
final Scope scope = program.getScope().getScope(scopeRef);
|
||||
if(scope instanceof Procedure) {
|
||||
return (Procedure) scope;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString(Program program) {
|
||||
ControlFlowGraph graph = program.getGraph();
|
||||
public String toString(Program program, Graph graph) {
|
||||
StringBuffer out = new StringBuffer();
|
||||
|
||||
if(isProcedureEntry(program)) {
|
||||
if(program.isProcedureEntry(this)) {
|
||||
Procedure procedure = (Procedure) program.getScope().getScope(scope);
|
||||
out.append("\n");
|
||||
out.append(procedure.toString(program)+"\n");
|
||||
|
@ -189,9 +161,9 @@ public class ControlFlowBlock {
|
|||
out.append(" scope:[" + this.scope.getFullName() + "] ");
|
||||
out.append(" from");
|
||||
if(graph != null) {
|
||||
List<ControlFlowBlock> predecessors = graph.getPredecessors(this);
|
||||
List<Graph.Block> predecessors = program.getGraph().getPredecessors(this);
|
||||
if(predecessors.size() > 0) {
|
||||
for(ControlFlowBlock predecessor : predecessors) {
|
||||
for(Graph.Block predecessor : predecessors) {
|
||||
out.append(" " + predecessor.getLabel().getFullName());
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +179,7 @@ public class ControlFlowBlock {
|
|||
}
|
||||
if(program.getLog().isVerboseSsaSourceCode()) {
|
||||
if(statement.getSource()!=null && statement.getSource().getCode()!=null)
|
||||
out.append(" // " + statement.getSource().getCode()).append("\n");
|
||||
out.append(" // " + statement.getSource().getCode()).append("\n");
|
||||
}
|
||||
out.append(" " + statement.toString(program, program.getLog().isVerboseLiveRanges()) + "\n");
|
||||
}
|
||||
|
@ -270,23 +242,4 @@ public class ControlFlowBlock {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all successors of the block
|
||||
*
|
||||
* @return All successors
|
||||
*/
|
||||
public Collection<LabelRef> getSuccessors() {
|
||||
List<LabelRef> successors = new ArrayList<>();
|
||||
if(defaultSuccessor != null) {
|
||||
successors.add(defaultSuccessor);
|
||||
}
|
||||
if(conditionalSuccessor != null) {
|
||||
successors.add(conditionalSuccessor);
|
||||
}
|
||||
if(callSuccessor != null) {
|
||||
successors.add(callSuccessor);
|
||||
}
|
||||
return successors;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCalling;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.passes.utils.ProcedureUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -17,21 +9,21 @@ import java.util.*;
|
|||
* The control flow graph of the program.
|
||||
* The control flow graph is a set of connected basic blocks.
|
||||
*/
|
||||
public class ControlFlowGraph {
|
||||
public class ControlFlowGraph implements Graph {
|
||||
|
||||
private List<ControlFlowBlock> blocks;
|
||||
private List<Graph.Block> blocks;
|
||||
|
||||
/**
|
||||
* Sequence of blocks used when generating ASM
|
||||
*/
|
||||
private List<LabelRef> sequence;
|
||||
|
||||
public ControlFlowGraph(List<ControlFlowBlock> blocks) {
|
||||
public ControlFlowGraph(List<Graph.Block> blocks) {
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getBlock(LabelRef symbol) {
|
||||
for(ControlFlowBlock block : blocks) {
|
||||
public Graph.Block getBlock(LabelRef symbol) {
|
||||
for(var block : blocks) {
|
||||
if(block.getLabel().equals(symbol)) {
|
||||
return block;
|
||||
}
|
||||
|
@ -39,22 +31,18 @@ public class ControlFlowGraph {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void addBlock(ControlFlowBlock block) {
|
||||
public void addBlock(Graph.Block block) {
|
||||
blocks.add(block);
|
||||
}
|
||||
|
||||
public List<ControlFlowBlock> getAllBlocks() {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public void setAllBlocks(List<ControlFlowBlock> blocks) {
|
||||
this.blocks = blocks;
|
||||
public List<Block> getAllBlocks() {
|
||||
return Collections.unmodifiableList(blocks);
|
||||
}
|
||||
|
||||
public void remove(LabelRef label) {
|
||||
ListIterator<ControlFlowBlock> blocksIt = blocks.listIterator();
|
||||
ListIterator<Graph.Block> blocksIt = blocks.listIterator();
|
||||
while(blocksIt.hasNext()) {
|
||||
ControlFlowBlock block = blocksIt.next();
|
||||
var block = blocksIt.next();
|
||||
if(block.getLabel().equals(label)) {
|
||||
blocksIt.remove();
|
||||
return;
|
||||
|
@ -62,135 +50,11 @@ public class ControlFlowGraph {
|
|||
}
|
||||
}
|
||||
|
||||
public ControlFlowBlock getDefaultSuccessor(ControlFlowBlock block) {
|
||||
if(block.getDefaultSuccessor() != null) {
|
||||
return getBlock(block.getDefaultSuccessor());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ControlFlowBlock getCallSuccessor(ControlFlowBlock block) {
|
||||
if(block.getCallSuccessor() != null) {
|
||||
return getBlock(block.getCallSuccessor());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ControlFlowBlock getConditionalSuccessor(ControlFlowBlock block) {
|
||||
if(block.getConditionalSuccessor() != null) {
|
||||
return getBlock(block.getConditionalSuccessor());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<ControlFlowBlock> getPredecessors(ControlFlowBlock block) {
|
||||
ArrayList<ControlFlowBlock> predecessorBlocks = new ArrayList<>();
|
||||
for(ControlFlowBlock other : getAllBlocks()) {
|
||||
if(block.getLabel().equals(other.getDefaultSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
if(block.getLabel().equals(other.getConditionalSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
if(block.getLabel().equals(other.getCallSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
}
|
||||
Collections.sort(predecessorBlocks, Comparator.comparing(o -> o.getLabel().getFullName()));
|
||||
return predecessorBlocks;
|
||||
}
|
||||
|
||||
public List<LabelRef> getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public void setSequence(List<LabelRef> sequence) {
|
||||
if(sequence.size() != blocks.size()) {
|
||||
throw new CompileError("ERROR! Sequence does not contain all blocks from the program. Sequence: " + sequence.size() + " Blocks: " + blocks.size());
|
||||
}
|
||||
this.sequence = sequence;
|
||||
ArrayList<ControlFlowBlock> seqBlocks = new ArrayList<>();
|
||||
for(LabelRef labelRef : sequence) {
|
||||
seqBlocks.add(getBlock(labelRef));
|
||||
}
|
||||
this.blocks = seqBlocks;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getMainBlock() {
|
||||
for(ControlFlowBlock block : getAllBlocks()) {
|
||||
LabelRef label = block.getLabel();
|
||||
if(label.getFullName().equals(SymbolRef.MAIN_PROC_NAME)) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getStartBlock() {
|
||||
for(ControlFlowBlock block : getAllBlocks()) {
|
||||
LabelRef label = block.getLabel();
|
||||
if(label.getFullName().equals(SymbolRef.START_PROC_NAME)) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all blocks that are program entry points.
|
||||
* This is the start-block and any blocks referenced by the address-off operator (&)
|
||||
*
|
||||
* @param program The program
|
||||
* @return All entry-point blocks
|
||||
*/
|
||||
public List<ControlFlowBlock> getEntryPointBlocks(Program program) {
|
||||
List<ControlFlowBlock> entryPointBlocks = new ArrayList<>();
|
||||
for(Procedure procedure : program.getScope().getAllProcedures(true)) {
|
||||
if(ProcedureUtils.isEntrypoint(procedure.getRef(), program) || Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention()) || Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
|
||||
// Address-of is used on the procedure
|
||||
Label procedureLabel = procedure.getLabel();
|
||||
ControlFlowBlock procedureBlock = getBlock(procedureLabel.getRef());
|
||||
entryPointBlocks.add(procedureBlock);
|
||||
}
|
||||
}
|
||||
return entryPointBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all called procedures in the graph
|
||||
*
|
||||
* @return All called procedures
|
||||
*/
|
||||
public Set<ProcedureRef> getAllCalledProcedures() {
|
||||
Set<ProcedureRef> calledProcedures = new LinkedHashSet<>();
|
||||
for(ControlFlowBlock block : getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementCalling) {
|
||||
StatementCalling call = (StatementCalling) statement;
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
calledProcedures.add(procedureRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
return calledProcedures;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
}
|
||||
|
||||
public String toString(Program program) {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for(ControlFlowBlock block : getAllBlocks()) {
|
||||
out.append(block.toString(program));
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
@ -207,102 +71,12 @@ public class ControlFlowGraph {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a statement from its statement index
|
||||
*
|
||||
* @param statementIdx The statement index
|
||||
* @return The statement
|
||||
* Clear all statement indices,
|
||||
*/
|
||||
public Statement getStatementByIndex(int statementIdx) {
|
||||
for(ControlFlowBlock block : getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement.getIndex() != null && statementIdx == statement.getIndex()) {
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all blocks that are part of the execution of a specific scope. (mostly a procedure)
|
||||
*
|
||||
* @param scope The scope to find blocks for
|
||||
* @return All blocks that are part of the execution of the scope
|
||||
*/
|
||||
public List<ControlFlowBlock> getScopeBlocks(ScopeRef scope) {
|
||||
ArrayList<ControlFlowBlock> scopeBlocks = new ArrayList<>();
|
||||
for(ControlFlowBlock block : getAllBlocks()) {
|
||||
if(block.getScope().equals(scope)) {
|
||||
scopeBlocks.add(block);
|
||||
}
|
||||
}
|
||||
return scopeBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about the size of the program
|
||||
*
|
||||
* @return Size information
|
||||
*/
|
||||
public String getSizeInfo() {
|
||||
StringBuilder sizeInfo = new StringBuilder();
|
||||
sizeInfo.append("SIZE blocks " + getAllBlocks().size()).append("\n");
|
||||
int numStmt = getAllBlocks().stream().mapToInt(block -> block.getStatements().size()).sum();
|
||||
sizeInfo.append("SIZE statements " + numStmt).append("\n");
|
||||
int numPhiVars = getAllBlocks().stream().mapToInt(value -> value.getStatements().stream().mapToInt(value1 -> (value1 instanceof StatementPhiBlock) ? ((StatementPhiBlock) value1).getPhiVariables().size() : 0).sum()).sum();
|
||||
sizeInfo.append("SIZE phi variables " + numPhiVars).append("\n");
|
||||
return sizeInfo.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all statements executed between two statements (none of these are included in the result)
|
||||
*
|
||||
* @param from The statement to start at
|
||||
* @param to The statement to end at
|
||||
* @return All statements executed between the two passed statements
|
||||
*/
|
||||
public Collection<Statement> getStatementsBetween(Statement from, Statement to, StatementInfos statementInfos) {
|
||||
Collection<Statement> between = new LinkedHashSet<>();
|
||||
final ControlFlowBlock block = statementInfos.getBlock(from);
|
||||
populateStatementsBetween(from, to, false, between, block);
|
||||
return between;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the between collection with all statements executed between two statements (none of these are included in the result)
|
||||
*
|
||||
* @param from The statement to start at
|
||||
* @param to The statement to end at
|
||||
* @param between The between collection
|
||||
* @param block The block to start from
|
||||
*/
|
||||
private void populateStatementsBetween(Statement from, Statement to, boolean isBetween, Collection<Statement> between, ControlFlowBlock block) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(between.contains(statement))
|
||||
// Stop infinite recursion
|
||||
return;
|
||||
if(isBetween) {
|
||||
if(statement.equals(to))
|
||||
// The end was reached!
|
||||
isBetween = false;
|
||||
else
|
||||
// We are between - add the statement
|
||||
between.add(statement);
|
||||
} else {
|
||||
if(statement.equals(from))
|
||||
// We are now between!
|
||||
isBetween = true;
|
||||
}
|
||||
}
|
||||
if(isBetween) {
|
||||
// Recurse to successor blocks
|
||||
final Collection<LabelRef> successors = block.getSuccessors();
|
||||
for(LabelRef successor : successors) {
|
||||
if(successor.getFullName().equals(ProcedureRef.PROCEXIT_BLOCK_NAME))
|
||||
continue;
|
||||
final ControlFlowBlock successorBlock = getBlock(successor);
|
||||
populateStatementsBetween(from, to, true, between, successorBlock);
|
||||
}
|
||||
public void clearStatementIndices() {
|
||||
for (Statement statement : getAllStatements()) {
|
||||
statement.setIndex(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A read-only control flow graph.
|
||||
*/
|
||||
public interface Graph {
|
||||
|
||||
Block getBlock(LabelRef symbol);
|
||||
|
||||
List<Block> getAllBlocks();
|
||||
|
||||
void addBlock(Graph.Block block);
|
||||
|
||||
default List<Statement> getAllStatements() {
|
||||
return getAllBlocks().stream().map(Block::getStatements).flatMap(Collection::stream).toList();
|
||||
}
|
||||
|
||||
default List<Graph.Block> getPredecessors(Graph.Block block) {
|
||||
ArrayList<Block> predecessorBlocks = new ArrayList<>();
|
||||
for(Graph.Block other : getAllBlocks()) {
|
||||
if(block.getLabel().equals(other.getDefaultSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
if(block.getLabel().equals(other.getConditionalSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
if(block.getLabel().equals(other.getCallSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
}
|
||||
predecessorBlocks.sort(Comparator.comparing(o -> o.getLabel().getFullName()));
|
||||
return predecessorBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all blocks that are part of the execution of a specific scope. (mostly a procedure)
|
||||
*
|
||||
* @param scope The scope to find blocks for
|
||||
* @return All blocks that are part of the execution of the scope
|
||||
*/
|
||||
default List<Graph.Block> getScopeBlocks(ScopeRef scope) {
|
||||
ArrayList<Graph.Block> scopeBlocks = new ArrayList<>();
|
||||
for(Graph.Block block : getAllBlocks()) {
|
||||
if(block.getScope().equals(scope)) {
|
||||
scopeBlocks.add(block);
|
||||
}
|
||||
}
|
||||
return scopeBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a statement from its statement index
|
||||
*
|
||||
* @param statementIdx The statement index
|
||||
* @return The statement
|
||||
*/
|
||||
default Statement getStatementByIndex(int statementIdx) {
|
||||
for (Statement statement : getAllStatements()) {
|
||||
if (statement.getIndex() != null && statementIdx == statement.getIndex()) {
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
default Graph.Block getDefaultSuccessor(Graph.Block block) {
|
||||
if(block.getDefaultSuccessor() != null) {
|
||||
return getBlock(block.getDefaultSuccessor());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
default Graph.Block getCallSuccessor(Graph.Block block) {
|
||||
if(block.getCallSuccessor() != null) {
|
||||
return getBlock(block.getCallSuccessor());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
default Graph.Block getConditionalSuccessor(Graph.Block block) {
|
||||
if(block.getConditionalSuccessor() != null) {
|
||||
return getBlock(block.getConditionalSuccessor());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
default String toString(Program program) {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for(Graph.Block block : getAllBlocks()) {
|
||||
out.append(block.toString(program, this));
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
interface Block {
|
||||
|
||||
LabelRef getLabel();
|
||||
|
||||
ScopeRef getScope();
|
||||
|
||||
List<Statement> getStatements();
|
||||
|
||||
boolean hasPhiBlock();
|
||||
|
||||
StatementPhiBlock getPhiBlock();
|
||||
|
||||
LabelRef getDefaultSuccessor();
|
||||
|
||||
LabelRef getConditionalSuccessor();
|
||||
|
||||
LabelRef getCallSuccessor();
|
||||
|
||||
/**
|
||||
* Get all successors of the block
|
||||
*
|
||||
* @return All successors
|
||||
*/
|
||||
default Collection<LabelRef> getSuccessors() {
|
||||
List<LabelRef> successors = new ArrayList<>();
|
||||
if(getDefaultSuccessor() != null) {
|
||||
successors.add(getDefaultSuccessor());
|
||||
}
|
||||
if(getConditionalSuccessor() != null) {
|
||||
successors.add(getConditionalSuccessor());
|
||||
}
|
||||
if(getCallSuccessor() != null) {
|
||||
successors.add(getCallSuccessor());
|
||||
}
|
||||
return successors;
|
||||
}
|
||||
|
||||
public List<Comment> getComments();
|
||||
|
||||
void setComments(List<Comment> comments);
|
||||
|
||||
void setDefaultSuccessor(LabelRef defaultSuccessor);
|
||||
|
||||
void setConditionalSuccessor(LabelRef conditionalSuccessor);
|
||||
|
||||
void setCallSuccessor(LabelRef callSuccessor);
|
||||
|
||||
void addStatement(Statement statement);
|
||||
|
||||
void addStatementAfter(Statement newStatement, Statement predecessor);
|
||||
|
||||
void addStatementBeforeCall(Statement newStatement);
|
||||
|
||||
String toString(Program program, Graph graph);
|
||||
}
|
||||
}
|
|
@ -5,17 +5,17 @@ import dk.camelot64.kickc.model.statements.*;
|
|||
import java.util.Collection;
|
||||
|
||||
/** Base visitor for iterating through a control flow graph */
|
||||
public class ControlFlowGraphBaseVisitor<T> {
|
||||
public class GraphBaseVisitor<T> {
|
||||
|
||||
public T visitGraph(ControlFlowGraph graph) {
|
||||
Collection<ControlFlowBlock> blocks = graph.getAllBlocks();
|
||||
for(ControlFlowBlock block : blocks) {
|
||||
public T visitGraph(Graph graph) {
|
||||
Collection<Graph.Block> blocks = graph.getAllBlocks();
|
||||
for(Graph.Block block : blocks) {
|
||||
this.visitBlock(block);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public T visitBlock(ControlFlowBlock block) {
|
||||
public T visitBlock(Graph.Block block) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
this.visitStatement(statement);
|
||||
}
|
|
@ -45,10 +45,8 @@ public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesE
|
|||
this.referenceInfo = referenceInfo;
|
||||
this.blockSuccessorClosure = blockSuccessorClosure;
|
||||
this.statementLiveVariables = new LinkedHashMap<>();
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
statementLiveVariables.put(statement.getIndex(), liveRangeVariables.getAlive(statement.getIndex()));
|
||||
}
|
||||
for (Statement statement : program.getGraph().getAllStatements()) {
|
||||
statementLiveVariables.put(statement.getIndex(), liveRangeVariables.getAlive(statement.getIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +100,7 @@ public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesE
|
|||
Collection<VariableRef> aliveAtStmt = statementLiveVariables.get(statement.getIndex());
|
||||
CallPaths callPaths;
|
||||
Collection<VariableRef> referencedInProcedure;
|
||||
ControlFlowBlock block = program.getStatementInfos().getBlock(statement);
|
||||
Graph.Block block = program.getStatementInfos().getBlock(statement);
|
||||
ScopeRef scopeRef = block.getScope();
|
||||
Scope scope = program.getScope().getScope(scopeRef);
|
||||
if(scope instanceof Procedure) {
|
||||
|
|
|
@ -19,23 +19,23 @@ public class PhiTransitions {
|
|||
private Program program;
|
||||
|
||||
/** The destination block for the phi transitions */
|
||||
private ControlFlowBlock toBlock;
|
||||
private Graph.Block toBlock;
|
||||
|
||||
/** The phi-block of the to-block. */
|
||||
private StatementPhiBlock phiBlock;
|
||||
|
||||
/** Maps from-block to the transition from the from-block to the to-block. */
|
||||
private Map<ControlFlowBlock, PhiTransition> transitions;
|
||||
private Map<Graph.Block, PhiTransition> transitions;
|
||||
|
||||
public PhiTransitions(Program program, ControlFlowBlock toBlock) {
|
||||
public PhiTransitions(Program program, Graph.Block toBlock) {
|
||||
this.program = program;
|
||||
this.toBlock = toBlock;
|
||||
this.transitions = new LinkedHashMap<>();
|
||||
if(toBlock.hasPhiBlock()) {
|
||||
this.phiBlock = toBlock.getPhiBlock();
|
||||
List<ControlFlowBlock> predecessors = new ArrayList<>(program.getGraph().getPredecessors(toBlock));
|
||||
List<Graph.Block> predecessors = new ArrayList<>(program.getGraph().getPredecessors(toBlock));
|
||||
predecessors.sort(Comparator.comparing(o -> o.getLabel().getFullName()));
|
||||
for(ControlFlowBlock predecessor : predecessors) {
|
||||
for(Graph.Block predecessor : predecessors) {
|
||||
PhiTransition transition = findTransition(predecessor);
|
||||
transitions.put(predecessor, transition);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public class PhiTransitions {
|
|||
* @param fromBlock The block where the transition starts
|
||||
* @return The transition into the passed block
|
||||
*/
|
||||
private PhiTransition findTransition(ControlFlowBlock fromBlock) {
|
||||
private PhiTransition findTransition(Graph.Block fromBlock) {
|
||||
PhiTransition transition = new PhiTransition(fromBlock, toBlock, phiBlock, program);
|
||||
boolean isCallTransition = toBlock.getLabel().equals(fromBlock.getCallSuccessor());
|
||||
if(!isCallTransition) {
|
||||
|
@ -64,7 +64,7 @@ public class PhiTransitions {
|
|||
return transition;
|
||||
}
|
||||
|
||||
public Collection<ControlFlowBlock> getFromBlocks() {
|
||||
public Collection<Graph.Block> getFromBlocks() {
|
||||
return transitions.keySet();
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ public class PhiTransitions {
|
|||
* @param fromBlock The from-block
|
||||
* @return The transition from the from-block into the to-block
|
||||
*/
|
||||
public PhiTransition getTransition(ControlFlowBlock fromBlock) {
|
||||
public PhiTransition getTransition(Graph.Block fromBlock) {
|
||||
return transitions.get(fromBlock);
|
||||
}
|
||||
|
||||
|
@ -104,20 +104,20 @@ public class PhiTransitions {
|
|||
private Program program;
|
||||
|
||||
/** The block we are entering into. */
|
||||
private ControlFlowBlock toBlock;
|
||||
private Graph.Block toBlock;
|
||||
|
||||
/** The phi statement of the to-block. */
|
||||
private StatementPhiBlock phiBlock;
|
||||
|
||||
/** The block we are entering from. */
|
||||
private List<ControlFlowBlock> fromBlocks;
|
||||
private List<Graph.Block> fromBlocks;
|
||||
|
||||
/** The assignments when transitioning between the two blocks. */
|
||||
private List<PhiTransition.PhiAssignment> assignments;
|
||||
|
||||
private int nextIdx;
|
||||
|
||||
PhiTransition(ControlFlowBlock fromBlock, ControlFlowBlock toBlock, StatementPhiBlock phiBlock, Program program) {
|
||||
PhiTransition(Graph.Block fromBlock, Graph.Block toBlock, StatementPhiBlock phiBlock, Program program) {
|
||||
this.program = program;
|
||||
this.toBlock = toBlock;
|
||||
this.phiBlock = phiBlock;
|
||||
|
@ -127,7 +127,7 @@ public class PhiTransitions {
|
|||
initAssignments(fromBlock);
|
||||
}
|
||||
|
||||
private void initAssignments(ControlFlowBlock fromBlock) {
|
||||
private void initAssignments(Graph.Block fromBlock) {
|
||||
this.assignments = new ArrayList<>();
|
||||
if(phiBlock != null) {
|
||||
List<StatementPhiBlock.PhiVariable> phiVariables = new ArrayList<>(phiBlock.getPhiVariables());
|
||||
|
@ -153,7 +153,7 @@ public class PhiTransitions {
|
|||
StringBuilder id = new StringBuilder();
|
||||
id.append("phi:");
|
||||
boolean first = true;
|
||||
for(ControlFlowBlock fromBlock : fromBlocks) {
|
||||
for(Graph.Block fromBlock : fromBlocks) {
|
||||
if(!first) {
|
||||
id.append("/");
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ public class PhiTransitions {
|
|||
return assignments;
|
||||
}
|
||||
|
||||
void addFromBlock(ControlFlowBlock fromBlock) {
|
||||
void addFromBlock(Graph.Block fromBlock) {
|
||||
fromBlocks.add(fromBlock);
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ public class PhiTransitions {
|
|||
return true;
|
||||
}
|
||||
|
||||
public List<ControlFlowBlock> getFromBlocks() {
|
||||
public List<Graph.Block> getFromBlocks() {
|
||||
return fromBlocks;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ public class ProcedureCompilation {
|
|||
/** The statements of the procedure. */
|
||||
private StatementSequence statementSequence;
|
||||
|
||||
/** The control flow graph of the procedure. */
|
||||
private ControlFlowGraph graph;
|
||||
|
||||
public ProcedureCompilation(ProcedureRef procedureRef) {
|
||||
this.procedureRef = procedureRef;
|
||||
this.statementSequence = new StatementSequence();
|
||||
|
@ -27,4 +30,12 @@ public class ProcedureCompilation {
|
|||
return statementSequence;
|
||||
}
|
||||
|
||||
public ControlFlowGraph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
public void setGraph(ControlFlowGraph graph) {
|
||||
this.graph = graph;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,17 +4,16 @@ import dk.camelot64.kickc.CompileLog;
|
|||
import dk.camelot64.kickc.OutputFileManager;
|
||||
import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateMasterSynthesizer;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.passes.calcs.*;
|
||||
import dk.camelot64.kickc.passes.utils.ProcedureUtils;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/** A KickC Intermediate Compiler Language (ICL) Program */
|
||||
public class Program {
|
||||
|
@ -58,8 +57,6 @@ public class Program {
|
|||
|
||||
/** The main scope. PASS 0-5 (DYNAMIC) */
|
||||
private ProgramScope scope;
|
||||
/** The control flow graph. PASS 1-5 (DYNAMIC) */
|
||||
private ControlFlowGraph graph;
|
||||
/** The procedure that starts the execution of the program. (Default: _start() which calls _init() and main() ) */
|
||||
private ProcedureRef startProcedure;
|
||||
|
||||
|
@ -69,8 +66,8 @@ public class Program {
|
|||
/** Cached information about calls. PASS 1-4 (CACHED ON-DEMAND) */
|
||||
private CallGraph callGraph;
|
||||
|
||||
/** The procedures being compiled. */
|
||||
private final Map<ProcedureRef, ProcedureCompilation> procedureCompilations;
|
||||
/** The procedures being compiled. PASS 1-5 (DYNAMIC)*/
|
||||
private List<ProcedureCompilation> procedureCompilations;
|
||||
|
||||
/** Variables modified inside procedures. PASS 1 (STATIC) */
|
||||
private ProcedureModifiedVars procedureModifiedVars;
|
||||
|
@ -82,9 +79,6 @@ public class Program {
|
|||
/** The 6502 ASM program. PASS 4-5 (DYNAMIC) */
|
||||
private AsmProgram asm;
|
||||
|
||||
/** A saved program snapshot that can be rolled back. Used to store the (DYNAMIC) state of the program while trying out a potential optimization. PASS 2 (DYNAMIC) */
|
||||
private ProgramSnapshot snapshot;
|
||||
|
||||
/** Cached information about the variables referenced by blocks/statements. PASS 1-4 (CACHED ON-DEMAND) */
|
||||
private VariableReferenceInfos variableReferenceInfos;
|
||||
/** Cached information about the closure of all block successors. */
|
||||
|
@ -118,7 +112,7 @@ public class Program {
|
|||
this.loadedFiles = new ArrayList<>();
|
||||
this.asmResourceFiles = new ArrayList<>();
|
||||
this.reservedZps = new ArrayList<>();
|
||||
this.procedureCompilations = new LinkedHashMap<>();
|
||||
this.procedureCompilations = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,7 +131,6 @@ public class Program {
|
|||
* Clears all data that is only used in PASS 2-4
|
||||
*/
|
||||
public void endPass4() {
|
||||
this.snapshot = null;
|
||||
this.mainFileComments = null;
|
||||
this.callGraph = null;
|
||||
this.variableReferenceInfos = null;
|
||||
|
@ -150,33 +143,47 @@ public class Program {
|
|||
this.registerUpliftProgram = null;
|
||||
}
|
||||
|
||||
/** Save a snapshot of the dynamic parts of the program. */
|
||||
public void snapshotCreate() {
|
||||
if(this.snapshot != null)
|
||||
throw new InternalError("Snapshot already saved!");
|
||||
if(this.liveRangeEquivalenceClassSet != null)
|
||||
throw new InternalError("Compiler Program Snapshot does not support liveRangeEquivalenceClassSet!");
|
||||
this.snapshot = new ProgramSnapshot(scope, graph);
|
||||
/**
|
||||
* Get a read-only control flow graph for the entire program.
|
||||
* @return The control flow graph
|
||||
*/
|
||||
public Graph getGraph() {
|
||||
return new Graph() {
|
||||
@Override
|
||||
public Block getBlock(LabelRef symbol) {
|
||||
return getProcedureCompilations().stream().map(ProcedureCompilation::getGraph).filter(Objects::nonNull).map(graph -> graph.getBlock(symbol)).filter(Objects::nonNull).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Block> getAllBlocks() {
|
||||
return getProcedureCompilations().stream().map(ProcedureCompilation::getGraph).filter(Objects::nonNull).map(ControlFlowGraph::getAllBlocks).flatMap(Collection::stream).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBlock(Block block) {
|
||||
throw new CompileError("Internal Error! Cannot add blocks to the read-only total control flow graph!");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Restore the snapshot of the dynamic parts of the program. Clear all cached data and the snapshot. */
|
||||
public void snapshotRestore() {
|
||||
this.scope = snapshot.getScope();
|
||||
this.graph = snapshot.getGraph();
|
||||
this.snapshot = null;
|
||||
this.callGraph = null;
|
||||
this.variableReferenceInfos = null;
|
||||
this.dominators = null;
|
||||
this.loopSet = null;
|
||||
this.statementInfos = null;
|
||||
this.symbolInfos = null;
|
||||
this.phiTransitions = null;
|
||||
this.liveRangeVariables = null;
|
||||
this.liveRangeVariablesEffective = null;
|
||||
this.variableRegisterWeights = null;
|
||||
this.registerPotentials = null;
|
||||
this.registerUpliftProgram = null;
|
||||
this.asm = null;
|
||||
public List<ProcedureCompilation> getProcedureCompilations() {
|
||||
return procedureCompilations;
|
||||
}
|
||||
|
||||
public void setProcedureCompilations(List<ProcedureCompilation> procedureCompilations) {
|
||||
this.procedureCompilations = procedureCompilations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty-print the entire control flow graph of all procedures.
|
||||
* @return The pretty-printed control flow graph
|
||||
*/
|
||||
public String prettyControlFlowGraph() {
|
||||
StringBuilder graphPretty = new StringBuilder();
|
||||
for(ProcedureCompilation procedureCompilation : getProcedureCompilations()) {
|
||||
graphPretty.append(procedureCompilation.getGraph().toString(this));
|
||||
}
|
||||
return graphPretty.toString();
|
||||
}
|
||||
|
||||
public OutputFileManager getOutputFileManager() {
|
||||
|
@ -272,15 +279,15 @@ public class Program {
|
|||
}
|
||||
|
||||
public ProcedureCompilation createProcedureCompilation(ProcedureRef procedureRef) {
|
||||
if(procedureCompilations.get(procedureRef)!=null)
|
||||
if(getProcedureCompilation(procedureRef)!=null)
|
||||
throw new CompileError("Error! Procedure already defined "+procedureRef.getFullName());
|
||||
final ProcedureCompilation procedureCompilation = new ProcedureCompilation(procedureRef);
|
||||
procedureCompilations.put(procedureRef, procedureCompilation);
|
||||
procedureCompilations.add(procedureCompilation);
|
||||
return procedureCompilation;
|
||||
}
|
||||
|
||||
public ProcedureCompilation getProcedureCompilation(ProcedureRef procedureRef) {
|
||||
return procedureCompilations.get(procedureRef);
|
||||
return procedureCompilations.stream().filter(pc -> pc.getProcedureRef().equals(procedureRef)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public ProgramScope getScope() {
|
||||
|
@ -291,14 +298,6 @@ public class Program {
|
|||
this.scope = scope;
|
||||
}
|
||||
|
||||
public ControlFlowGraph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
public void setGraph(ControlFlowGraph graph) {
|
||||
this.graph = graph;
|
||||
}
|
||||
|
||||
public ProcedureRef getStartProcedure() {
|
||||
return startProcedure;
|
||||
}
|
||||
|
@ -413,11 +412,7 @@ public class Program {
|
|||
* Clear index numbers for all statements in the control flow graph.
|
||||
*/
|
||||
public void clearStatementIndices() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
statement.setIndex(null);
|
||||
}
|
||||
}
|
||||
getProcedureCompilations().stream().map(ProcedureCompilation::getGraph).filter(Objects::nonNull).forEach(ControlFlowGraph::clearStatementIndices);
|
||||
}
|
||||
|
||||
public SymbolInfos getSymbolInfos() {
|
||||
|
@ -487,9 +482,6 @@ public class Program {
|
|||
this.registerPotentials = registerPotentials;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adds a bunch of reserved zero-page addresses that the compiler is not allowed to use.
|
||||
*
|
||||
|
@ -527,7 +519,14 @@ public class Program {
|
|||
public String getSizeInfo() {
|
||||
StringBuilder sizeInfo = new StringBuilder();
|
||||
sizeInfo.append(getScope().getSizeInfo());
|
||||
sizeInfo.append(getGraph().getSizeInfo());
|
||||
|
||||
final List<Graph.Block> allBlocks = getProcedureCompilations().stream().map(ProcedureCompilation::getGraph).map(ControlFlowGraph::getAllBlocks).flatMap(Collection::stream).toList();
|
||||
sizeInfo.append("SIZE blocks ").append(allBlocks.size()).append("\n");
|
||||
int numStmt = allBlocks.stream().mapToInt(block -> block.getStatements().size()).sum();
|
||||
sizeInfo.append("SIZE statements ").append(numStmt).append("\n");
|
||||
int numPhiVars = allBlocks.stream().mapToInt(value -> value.getStatements().stream().mapToInt(value1 -> (value1 instanceof StatementPhiBlock) ? ((StatementPhiBlock) value1).getPhiVariables().size() : 0).sum()).sum();
|
||||
sizeInfo.append("SIZE phi variables ").append(numPhiVars).append("\n");
|
||||
|
||||
if(variableReferenceInfos != null)
|
||||
sizeInfo.append(variableReferenceInfos.getSizeInfo());
|
||||
if(getLiveRangeEquivalenceClassSet() != null)
|
||||
|
@ -539,4 +538,61 @@ public class Program {
|
|||
return sizeInfo.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the procedure, that the block is part of. Null if the block is not part of a procedure.
|
||||
*
|
||||
* @param block The control flow graph block
|
||||
* @return the procedure, that the block is part of
|
||||
*/
|
||||
public Procedure getProcedure(Graph.Block block) {
|
||||
final ScopeRef scopeRef = block.getScope();
|
||||
final Scope scope = getScope().getScope(scopeRef);
|
||||
if(scope instanceof Procedure) {
|
||||
return (Procedure) scope;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an entire procedure.
|
||||
* Removes the entire control flow graph and all symbols.
|
||||
* Does not check that the removal results in a legal program.
|
||||
* @param procedureRef The procedure to remove.
|
||||
*/
|
||||
public void removeProcedure(ProcedureRef procedureRef) {
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
procedure.getScope().remove(procedure);
|
||||
procedureCompilations.remove(getProcedureCompilation(procedureRef));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the block the entry of a procedure, ie. the first block of the code of the procedure.
|
||||
*
|
||||
* @param block
|
||||
* @return true if this is the entry of a procedure
|
||||
*/
|
||||
public boolean isProcedureEntry(Graph.Block block) {
|
||||
Symbol symbol = getScope().getSymbol(block.getLabel());
|
||||
return (symbol instanceof Procedure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all blocks that are program entry points.
|
||||
* This is the start-block and any blocks referenced by the address-off operator (&)
|
||||
*/
|
||||
public List<Graph.Block> getEntryPointBlocks() {
|
||||
final Graph graph = getGraph();
|
||||
List<Graph.Block> entryPointBlocks = new ArrayList<>();
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
if(ProcedureUtils.isEntrypoint(procedure.getRef(), this) || Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention()) || Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
|
||||
// Address-of is used on the procedure
|
||||
Label procedureLabel = procedure.getLabel();
|
||||
Graph.Block procedureBlock = graph.getBlock(procedureLabel.getRef());
|
||||
entryPointBlocks.add(procedureBlock);
|
||||
}
|
||||
}
|
||||
return entryPointBlocks;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* A snapshot of all dynamic data in a {@link Program}.
|
||||
* Used whenever the compiler need to run an experiment where it may need to roll back to a previous state.
|
||||
*/
|
||||
public class ProgramSnapshot {
|
||||
|
||||
/** The main scope. PASS 0-5 (DYNAMIC) */
|
||||
private ProgramScope scope;
|
||||
/** The control flow graph. PASS 1-5 (DYNAMIC) */
|
||||
private ControlFlowGraph graph;
|
||||
|
||||
public ProgramSnapshot(ProgramScope scope, ControlFlowGraph graph) {
|
||||
this.scope = snapshot(scope);
|
||||
this.graph = snapshot(graph);
|
||||
}
|
||||
|
||||
public ProgramScope getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public ControlFlowGraph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a deep copy of an object (by using serialization)
|
||||
* @param orig The object tot copy
|
||||
* @return the copy with zero references to the original
|
||||
*/
|
||||
private static <T extends Object> T snapshot(T orig) {
|
||||
if(orig==null) return null;
|
||||
T obj = null;
|
||||
try {
|
||||
// Write the object out to a byte array
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream out = new ObjectOutputStream(bos);
|
||||
out.writeObject(orig);
|
||||
out.flush();
|
||||
out.close();
|
||||
// Make an input stream from the byte array and read a copy of the object back in.
|
||||
ObjectInputStream in = new ObjectInputStream(
|
||||
new ByteArrayInputStream(bos.toByteArray()));
|
||||
obj = (T) in.readObject();
|
||||
}
|
||||
catch(IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
|
@ -9,15 +9,15 @@ import java.util.Map;
|
|||
public class StatementInfos {
|
||||
|
||||
/** The control flow graph. */
|
||||
private ControlFlowGraph graph;
|
||||
private Graph graph;
|
||||
|
||||
/** Maps statement index to block. */
|
||||
private Map<Integer, ControlFlowBlock> stmtBlocks;
|
||||
private Map<Integer, Graph.Block> stmtBlocks;
|
||||
|
||||
/** Maps statement index to statement. */
|
||||
private Map<Integer, Statement> stmtIdx;
|
||||
|
||||
public StatementInfos(Program program, Map<Integer, ControlFlowBlock> stmtBlocks, Map<Integer, Statement> stmtIdx) {
|
||||
public StatementInfos(Program program, Map<Integer, Graph.Block> stmtBlocks, Map<Integer, Statement> stmtIdx) {
|
||||
this.graph = program.getGraph();
|
||||
this.stmtBlocks = stmtBlocks;
|
||||
this.stmtIdx = stmtIdx;
|
||||
|
@ -49,7 +49,7 @@ public class StatementInfos {
|
|||
* @param stmt The statement
|
||||
* @return The containing block
|
||||
*/
|
||||
public ControlFlowBlock getBlock(Statement stmt) {
|
||||
public Graph.Block getBlock(Statement stmt) {
|
||||
return stmtBlocks.get(stmt.getIndex());
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ public class StatementInfos {
|
|||
* @param stmtIdx The statement index
|
||||
* @return The containing block
|
||||
*/
|
||||
public ControlFlowBlock getBlock(Integer stmtIdx) {
|
||||
public Graph.Block getBlock(Integer stmtIdx) {
|
||||
return graph.getBlock(getBlockRef(stmtIdx));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.model.iterator;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
@ -21,6 +22,6 @@ public interface ProgramExpressionHandler {
|
|||
* @param stmtIt The statement iterator - just past the current statement. Can be used for modifying the control flow block.
|
||||
* @param currentBlock The current block that the value is a part of
|
||||
*/
|
||||
void execute(ProgramExpression programExpression, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock);
|
||||
void execute(ProgramExpression programExpression, Statement currentStmt, ListIterator<Statement> stmtIt, Graph.Block currentBlock);
|
||||
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class ProgramExpressionIterator {
|
|||
ProgramValueIterator.execute(program.getScope(), programValueHandler);
|
||||
|
||||
// Iterate all blocks/statements
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(var block : program.getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement stmt = stmtIt.next();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.model.iterator;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
@ -19,6 +20,6 @@ public interface ProgramValueHandler {
|
|||
* @param stmtIt The statement iterator - just past the current statement. Can be used for modifying the control flow block.
|
||||
* @param currentBlock The current block that the value is a part of
|
||||
*/
|
||||
void execute(ProgramValue programValue, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock);
|
||||
void execute(ProgramValue programValue, Statement currentStmt, ListIterator<Statement> stmtIt, Graph.Block currentBlock);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package dk.camelot64.kickc.model.iterator;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.ControlFlowGraph;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
|
@ -80,8 +80,8 @@ public class ProgramValueIterator {
|
|||
* @param graph The program control flow graph
|
||||
* @param handler The handler to execute
|
||||
*/
|
||||
public static void execute(ControlFlowGraph graph, ProgramValueHandler handler) {
|
||||
for(ControlFlowBlock block : graph.getAllBlocks()) {
|
||||
public static void execute(Graph graph, ProgramValueHandler handler) {
|
||||
for(Graph.Block block : graph.getAllBlocks()) {
|
||||
execute(block, handler);
|
||||
}
|
||||
}
|
||||
|
@ -92,16 +92,17 @@ public class ProgramValueIterator {
|
|||
* @param block The control flow graph block
|
||||
* @param handler The handler to execute
|
||||
*/
|
||||
public static void execute(ControlFlowBlock block, ProgramValueHandler handler) {
|
||||
public static void execute(Graph.Block block, ProgramValueHandler handler) {
|
||||
ListIterator<Statement> statementsIt = block.getStatements().listIterator();
|
||||
while(statementsIt.hasNext()) {
|
||||
Statement statement = statementsIt.next();
|
||||
execute(statement, handler, statementsIt, block);
|
||||
}
|
||||
execute(new ProgramValue.BlockLabel(block), handler, null, null, block);
|
||||
execute(new ProgramValue.BlockDefaultSuccessor(block), handler, null, null, block);
|
||||
execute(new ProgramValue.BlockConditionalSuccessor(block), handler, null, null, block);
|
||||
execute(new ProgramValue.BlockCallSuccessor(block), handler, null, null, block);
|
||||
ControlFlowBlock mutableBlock = (ControlFlowBlock) block;
|
||||
execute(new ProgramValue.BlockLabel(mutableBlock), handler, null, null, block);
|
||||
execute(new ProgramValue.BlockDefaultSuccessor(mutableBlock), handler, null, null, block);
|
||||
execute(new ProgramValue.BlockConditionalSuccessor(mutableBlock), handler, null, null, block);
|
||||
execute(new ProgramValue.BlockCallSuccessor(mutableBlock), handler, null, null, block);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,14 +111,13 @@ public class ProgramValueIterator {
|
|||
* @param statement The statement
|
||||
* @param handler The handler to execute
|
||||
*/
|
||||
public static void execute(Statement statement, ProgramValueHandler handler, ListIterator<Statement> statementsIt, ControlFlowBlock block) {
|
||||
public static void execute(Statement statement, ProgramValueHandler handler, ListIterator<Statement> statementsIt, Graph.Block block) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
// The sequence RValue1, RValue2, LValue is important - as it is essential for {@link dk.camelot64.kickc.passes.Pass1GenerateSingleStaticAssignmentForm} to create the correct SSA
|
||||
execute(new ProgramValue.RValue1((StatementAssignment) statement), handler, statement, statementsIt, block);
|
||||
execute(new ProgramValue.RValue2((StatementAssignment) statement), handler, statement, statementsIt, block);
|
||||
execute(new ProgramValue.ProgramValueLValue((StatementLValue) statement), handler, statement, statementsIt, block);
|
||||
} else if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
} else if(statement instanceof StatementCall call) {
|
||||
if(call.getParameters() != null) {
|
||||
int size = call.getParameters().size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
|
@ -125,8 +125,7 @@ public class ProgramValueIterator {
|
|||
}
|
||||
}
|
||||
execute(new ProgramValue.ProgramValueLValue((StatementLValue) statement), handler, statement, statementsIt, block);
|
||||
} else if(statement instanceof StatementCallPrepare) {
|
||||
StatementCallPrepare call = (StatementCallPrepare) statement;
|
||||
} else if(statement instanceof StatementCallPrepare call) {
|
||||
if(call.getParameters() != null) {
|
||||
int size = call.getParameters().size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
|
@ -137,8 +136,7 @@ public class ProgramValueIterator {
|
|||
execute(new ProgramValue.CallExecuteProcedure((StatementCallExecute) statement), handler, statement, statementsIt, block);
|
||||
} else if(statement instanceof StatementCallFinalize) {
|
||||
execute(new ProgramValue.ProgramValueLValue((StatementLValue) statement), handler, statement, statementsIt, block);
|
||||
} else if(statement instanceof StatementCallPointer) {
|
||||
StatementCallPointer call = (StatementCallPointer) statement;
|
||||
} else if(statement instanceof StatementCallPointer call) {
|
||||
execute(new ProgramValue.CallPointerProcedure((StatementCallPointer) statement), handler, statement, statementsIt, block);
|
||||
if(call.getParameters() != null) {
|
||||
int size = call.getParameters().size();
|
||||
|
@ -162,8 +160,7 @@ public class ProgramValueIterator {
|
|||
}
|
||||
execute(new ProgramValue.PhiVariable(phiVariable), handler, statement, statementsIt, block);
|
||||
}
|
||||
} else if(statement instanceof StatementKickAsm) {
|
||||
StatementKickAsm statementKickAsm = (StatementKickAsm) statement;
|
||||
} else if(statement instanceof StatementKickAsm statementKickAsm) {
|
||||
RValue bytes = statementKickAsm.getBytes();
|
||||
if(bytes != null) {
|
||||
execute(new ProgramValue.ProgramValueKickAsmBytes(statementKickAsm), handler, statement, statementsIt, block);
|
||||
|
@ -176,14 +173,12 @@ public class ProgramValueIterator {
|
|||
for(int i = 0; i < uses.size(); i++) {
|
||||
execute(new ProgramValue.KickAsmUses(statementKickAsm, i), handler, statement, statementsIt, block);
|
||||
}
|
||||
} else if(statement instanceof StatementAsm) {
|
||||
StatementAsm statementAsm = (StatementAsm) statement;
|
||||
} else if(statement instanceof StatementAsm statementAsm) {
|
||||
Map<String, SymbolRef> referenced = statementAsm.getReferenced();
|
||||
for(String label : referenced.keySet()) {
|
||||
execute(new ProgramValue.ProgramValueAsmReferenced(statementAsm, label), handler, statement, statementsIt, block);
|
||||
}
|
||||
} else if(statement instanceof StatementExprSideEffect) {
|
||||
StatementExprSideEffect statementExprSideEffect = (StatementExprSideEffect) statement;
|
||||
} else if(statement instanceof StatementExprSideEffect statementExprSideEffect) {
|
||||
execute(new ProgramValue.ExprSideEffect(statementExprSideEffect), handler, statement, statementsIt, block);
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +189,7 @@ public class ProgramValueIterator {
|
|||
* @param programValue The programValue value
|
||||
* @param handler The value handler
|
||||
*/
|
||||
public static void execute(ProgramValue programValue, ProgramValueHandler handler, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
||||
public static void execute(ProgramValue programValue, ProgramValueHandler handler, Statement currentStmt, ListIterator<Statement> stmtIt, Graph.Block currentBlock) {
|
||||
handler.execute(programValue, currentStmt, stmtIt, currentBlock);
|
||||
for(ProgramValue subValue : getSubValues(programValue.get())) {
|
||||
execute(subValue, handler, currentStmt, stmtIt, currentBlock);
|
||||
|
@ -221,20 +216,17 @@ public class ProgramValueIterator {
|
|||
for(int i = 0; i < size; i++) {
|
||||
subValues.add(new ProgramValue.ProgramValueStructUnwoundPlaceholderMember((StructUnwoundPlaceholder) value, i));
|
||||
}
|
||||
} else if(value instanceof ValueList) {
|
||||
ValueList valueList = (ValueList) value;
|
||||
} else if(value instanceof ValueList valueList) {
|
||||
int size = valueList.getList().size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
subValues.add(new ProgramValue.ProgramValueListElement(valueList, i));
|
||||
}
|
||||
} else if(value instanceof ConstantArrayList) {
|
||||
ConstantArrayList constantArrayList = (ConstantArrayList) value;
|
||||
} else if(value instanceof ConstantArrayList constantArrayList) {
|
||||
int size = constantArrayList.getElements().size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
subValues.add(new ProgramValue.ProgramValueConstantArrayElement(constantArrayList, i));
|
||||
}
|
||||
} else if(value instanceof ConstantStructValue) {
|
||||
ConstantStructValue constantStructValue = (ConstantStructValue) value;
|
||||
} else if(value instanceof ConstantStructValue constantStructValue) {
|
||||
for(SymbolVariableRef memberRef : constantStructValue.getMembers()) {
|
||||
subValues.add(new ProgramValue.ProgramValueConstantStructMember(constantStructValue, memberRef));
|
||||
}
|
||||
|
@ -254,8 +246,7 @@ public class ProgramValueIterator {
|
|||
subValues.add(new ProgramValue.ProgramValueConstantUnaryValue((ConstantUnary) value));
|
||||
} else if(value instanceof ConstantArrayFilled) {
|
||||
subValues.add(new ProgramValue.ProgramValueConstantArrayFilledSize((ConstantArrayFilled) value));
|
||||
} else if(value instanceof ConstantArrayKickAsm) {
|
||||
ConstantArrayKickAsm constantArrayKickAsm = (ConstantArrayKickAsm) value;
|
||||
} else if(value instanceof ConstantArrayKickAsm constantArrayKickAsm) {
|
||||
List<SymbolRef> uses = constantArrayKickAsm.getUses();
|
||||
for(int i = 0; i < uses.size(); i++) {
|
||||
subValues.add(new ProgramValue.ProgramValueConstantArrayKickAsmUses(constantArrayKickAsm, i));
|
||||
|
|
|
@ -45,6 +45,11 @@ public class Label implements Symbol {
|
|||
this.scope = scope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Procedure getContainingProcedure() {
|
||||
return getScope().getContainingProcedure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeDepth() {
|
||||
if(scope == null) {
|
||||
|
|
|
@ -34,6 +34,19 @@ public abstract class Scope implements Symbol {
|
|||
setFullName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the containing procedure.
|
||||
* @return The procedure containing the scope. Null if the scope is not contained in a procedure.
|
||||
*/
|
||||
public Procedure getContainingProcedure() {
|
||||
if(this instanceof Procedure)
|
||||
return (Procedure) this;
|
||||
else if(this instanceof ProgramScope)
|
||||
return null;
|
||||
else
|
||||
return this.getScope().getContainingProcedure();
|
||||
}
|
||||
|
||||
private void setFullName() {
|
||||
String scopeName = (parentScope == null) ? "" : parentScope.getFullName();
|
||||
fullName = (scopeName.length() > 0) ? scopeName + "::" + name : name;
|
||||
|
|
|
@ -20,4 +20,6 @@ public interface Symbol extends Value {
|
|||
int getScopeDepth();
|
||||
|
||||
SymbolRef getRef();
|
||||
|
||||
Procedure getContainingProcedure();
|
||||
}
|
||||
|
|
|
@ -531,6 +531,11 @@ public class Variable implements Symbol {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Procedure getContainingProcedure() {
|
||||
return scope.getContainingProcedure();
|
||||
}
|
||||
|
||||
public boolean isDeclarationOnly() {
|
||||
return declarationOnly;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
this.scopeStack = new Stack<>();
|
||||
this.currentCallingConvention = initialCallingConvention;
|
||||
this.currentEncoding = defaultEncoding;
|
||||
this.pragmaConstructorFors = new ArrayList();
|
||||
this.pragmaConstructorFors = new ArrayList<>();
|
||||
this.currentInterruptType = defaultInterruptType;
|
||||
scopeStack.push(program.getScope());
|
||||
}
|
||||
|
@ -240,21 +240,21 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
public Object visitPragma(KickCParser.PragmaContext ctx) {
|
||||
final String pragmaName = ctx.NAME().getText();
|
||||
switch(pragmaName) {
|
||||
case CParser.PRAGMA_TARGET:
|
||||
throw new InternalError("Error! #pragma target() should be handled in preprocessor!");
|
||||
case CParser.PRAGMA_CPU:
|
||||
case CParser.PRAGMA_TARGET ->
|
||||
throw new InternalError("Error! #pragma target() should be handled in preprocessor!");
|
||||
case CParser.PRAGMA_CPU -> {
|
||||
final String cpuName = pragmaParamName(pragmaParamSingle(ctx));
|
||||
TargetCpu cpu = TargetCpu.getTargetCpu(cpuName, false);
|
||||
program.getTargetPlatform().setCpu(cpu);
|
||||
break;
|
||||
case CParser.PRAGMA_VAR_MODEL:
|
||||
}
|
||||
case CParser.PRAGMA_VAR_MODEL -> {
|
||||
final List<KickCParser.PragmaParamContext> pragmaParams = ctx.pragmaParam();
|
||||
List<String> settings = pragmaParams.stream().map(Pass0GenerateStatementSequence::pragmaParamName).collect(Collectors.toList());
|
||||
final VariableBuilderConfig config = VariableBuilderConfig.fromSettings(settings, new StatementSource(ctx));
|
||||
config.setStructModelClassic(program.getTargetPlatform().getVariableBuilderConfig().isStructModelClassic());
|
||||
program.getTargetPlatform().setVariableBuilderConfig(config);
|
||||
break;
|
||||
case CParser.PRAGMA_STRUCT_MODEL:
|
||||
}
|
||||
case CParser.PRAGMA_STRUCT_MODEL -> {
|
||||
final String modelName = pragmaParamName(pragmaParamSingle(ctx));
|
||||
if(modelName.equalsIgnoreCase("classic"))
|
||||
program.getTargetPlatform().getVariableBuilderConfig().setStructModelClassic(true);
|
||||
|
@ -262,38 +262,34 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
program.getTargetPlatform().getVariableBuilderConfig().setStructModelClassic(true);
|
||||
else
|
||||
throw new CompileError("Unknown struct model " + modelName, new StatementSource(ctx));
|
||||
break;
|
||||
case CParser.PRAGMA_LINKSCRIPT:
|
||||
}
|
||||
case CParser.PRAGMA_LINKSCRIPT -> {
|
||||
final String linkScriptName = pragmaParamString(pragmaParamSingle(ctx));
|
||||
program.getLog().append("Loading link script \"" + linkScriptName + "\"");
|
||||
Path currentPath = cParser.getSourceFolderPath(ctx);
|
||||
final File linkScriptFile = SourceLoader.loadFile(linkScriptName, currentPath, program.getTargetPlatformPaths());
|
||||
program.getTargetPlatform().setLinkScriptFile(linkScriptFile);
|
||||
break;
|
||||
case CParser.PRAGMA_EXTENSION:
|
||||
}
|
||||
case CParser.PRAGMA_EXTENSION -> {
|
||||
String extension = pragmaParamString(pragmaParamSingle(ctx));
|
||||
program.getTargetPlatform().setOutFileExtension(extension);
|
||||
program.getOutputFileManager().setBinaryExtension(extension);
|
||||
break;
|
||||
case CParser.PRAGMA_EMULATOR:
|
||||
}
|
||||
case CParser.PRAGMA_EMULATOR -> {
|
||||
String emuName = pragmaParamString(pragmaParamSingle(ctx));
|
||||
program.getTargetPlatform().setEmulatorCommand(emuName);
|
||||
break;
|
||||
case CParser.PRAGMA_ENCODING:
|
||||
}
|
||||
case CParser.PRAGMA_ENCODING -> {
|
||||
final String encodingName = pragmaParamName(pragmaParamSingle(ctx));
|
||||
try {
|
||||
this.currentEncoding = StringEncoding.fromName(encodingName.toUpperCase(Locale.ENGLISH));
|
||||
} catch(IllegalArgumentException e) {
|
||||
throw new CompileError("Unknown string encoding " + encodingName, new StatementSource(ctx));
|
||||
}
|
||||
break;
|
||||
case CParser.PRAGMA_CODE_SEG:
|
||||
this.currentSegmentCode = pragmaParamName(pragmaParamSingle(ctx));
|
||||
break;
|
||||
case CParser.PRAGMA_DATA_SEG:
|
||||
this.currentSegmentData = pragmaParamName(pragmaParamSingle(ctx));
|
||||
break;
|
||||
case CParser.PRAGMA_BANK:
|
||||
}
|
||||
case CParser.PRAGMA_CODE_SEG -> this.currentSegmentCode = pragmaParamName(pragmaParamSingle(ctx));
|
||||
case CParser.PRAGMA_DATA_SEG -> this.currentSegmentData = pragmaParamName(pragmaParamSingle(ctx));
|
||||
case CParser.PRAGMA_BANK -> {
|
||||
if(ctx.pragmaParam().size() != 2)
|
||||
throw new CompileError("#pragma expects two parameters!", new StatementSource(ctx));
|
||||
try {
|
||||
|
@ -303,34 +299,27 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
} catch(IllegalArgumentException e) {
|
||||
throw new CompileError("Illegal bank parameter " + ctx.getText(), new StatementSource(ctx));
|
||||
}
|
||||
break;
|
||||
case CParser.PRAGMA_NOBANK:
|
||||
this.currentBank = Bank.COMMON; // When the current segment is null, the procedure will not be declared as far.
|
||||
break;
|
||||
case CParser.PRAGMA_RESOURCE:
|
||||
}
|
||||
case CParser.PRAGMA_NOBANK -> this.currentBank = Bank.COMMON; // When the current segment is null, the procedure will not be declared as far.
|
||||
case CParser.PRAGMA_RESOURCE -> {
|
||||
String resourceFileName = pragmaParamString(pragmaParamSingle(ctx));
|
||||
addResourceFile(ctx, resourceFileName);
|
||||
break;
|
||||
case CParser.PRAGMA_START_ADDRESS:
|
||||
}
|
||||
case CParser.PRAGMA_START_ADDRESS -> {
|
||||
Number startAddress = pragmaParamNumber(pragmaParamSingle(ctx));
|
||||
program.getTargetPlatform().setStartAddress(startAddress);
|
||||
break;
|
||||
case CParser.PRAGMA_CALLING:
|
||||
currentCallingConvention = pragmaParamCallingConvention(pragmaParamSingle(ctx));
|
||||
break;
|
||||
case CParser.PRAGMA_INTERRUPT:
|
||||
this.currentInterruptType = pragmaParamName(pragmaParamSingle(ctx));
|
||||
break;
|
||||
case CParser.PRAGMA_ZP_RESERVE:
|
||||
}
|
||||
case CParser.PRAGMA_CALLING -> currentCallingConvention = pragmaParamCallingConvention(pragmaParamSingle(ctx));
|
||||
case CParser.PRAGMA_INTERRUPT -> this.currentInterruptType = pragmaParamName(pragmaParamSingle(ctx));
|
||||
case CParser.PRAGMA_ZP_RESERVE -> {
|
||||
List<Integer> reservedZps = pragmaParamRanges(ctx.pragmaParam());
|
||||
program.addReservedZps(reservedZps);
|
||||
break;
|
||||
case CParser.PRAGMA_CONSTRUCTOR_FOR:
|
||||
}
|
||||
case CParser.PRAGMA_CONSTRUCTOR_FOR -> {
|
||||
this.pragmaConstructorFors.add(ctx);
|
||||
return null;
|
||||
default:
|
||||
program.getLog().append("Warning! Unknown #pragma " + pragmaName);
|
||||
|
||||
}
|
||||
default -> program.getLog().append("Warning! Unknown #pragma " + pragmaName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -508,7 +497,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
private Procedure declareProcedure(boolean defineProcedure, ParserRuleContext ctx, StatementSource statementSource) {
|
||||
|
||||
Procedure procedure = new Procedure(varDecl.getVarName(), (SymbolTypeProcedure) varDecl.getEffectiveType(), program.getScope(), currentSegmentCode, currentSegmentData, currentCallingConvention, currentBank);
|
||||
addDirectives(procedure, varDecl.getDeclDirectives(), statementSource);
|
||||
addDirectives(procedure, varDecl.getDeclDirectives());
|
||||
// Check if the declaration matches any existing declaration!
|
||||
final Symbol existingSymbol = program.getScope().getSymbol(procedure.getRef());
|
||||
if(existingSymbol != null) {
|
||||
|
@ -534,7 +523,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
|
||||
if(defineProcedure) {
|
||||
// Make sure comments, directives and source are from the definition
|
||||
addDirectives(procedure, varDecl.getDeclDirectives(), statementSource);
|
||||
addDirectives(procedure, varDecl.getDeclDirectives());
|
||||
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
|
||||
procedure.setDefinitionSource(statementSource);
|
||||
// enter the procedure
|
||||
|
@ -773,7 +762,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
|
||||
/** ASM Directive specifying clobber registers. */
|
||||
private static class AsmDirectiveClobber implements AsmDirective {
|
||||
private CpuClobber clobber;
|
||||
private final CpuClobber clobber;
|
||||
|
||||
AsmDirectiveClobber(CpuClobber clobber) {
|
||||
this.clobber = clobber;
|
||||
|
@ -1072,8 +1061,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
// The previous assignment of an intermediate variable that can be modified instead of creating a new statement
|
||||
StatementLValue previousAssignment = null;
|
||||
|
||||
if(initValue instanceof VariableRef) {
|
||||
VariableRef initVarRef = (VariableRef) initValue;
|
||||
if(initValue instanceof VariableRef initVarRef) {
|
||||
if(initVarRef.isIntermediate()) {
|
||||
Statement previousStatement = getPreviousStatement();
|
||||
if(previousStatement instanceof StatementLValue && ((StatementLValue) previousStatement).getlValue().equals(initVarRef)) {
|
||||
|
@ -1126,7 +1114,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
throw new CompileError("Constant value contains a pre/post-modifier.", statementSource);
|
||||
}
|
||||
if(initValue instanceof ForwardVariableRef) {
|
||||
throw new CompileError("Variable used before being defined " + initValue.toString(), statementSource);
|
||||
throw new CompileError("Variable used before being defined " + initValue, statementSource);
|
||||
}
|
||||
if(!(initValue instanceof ConstantValue))
|
||||
throw new CompileError("Initializer is not a constant value.", statementSource);
|
||||
|
@ -1186,7 +1174,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
* @param procedure The procedure
|
||||
* @param directives The directives to add
|
||||
*/
|
||||
private void addDirectives(Procedure procedure, List<Directive> directives, StatementSource source) {
|
||||
private void addDirectives(Procedure procedure, List<Directive> directives) {
|
||||
for(Directive directive : directives) {
|
||||
if(directive instanceof Directive.Inline) {
|
||||
procedure.setDeclaredInline(true);
|
||||
|
@ -1301,7 +1289,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
RValue initValue = (initializer == null) ? null : (RValue) visit(initializer);
|
||||
StatementSource statementSource = new StatementSource(ctx);
|
||||
ConstantValue addressAsConstantValue = getConstInitValue(initValue, initializer, statementSource);
|
||||
ConstantLiteral literal = addressAsConstantValue.calculateLiteral(program.getScope());
|
||||
ConstantLiteral<?> literal = addressAsConstantValue.calculateLiteral(program.getScope());
|
||||
if(literal instanceof ConstantInteger) {
|
||||
Long address = ((ConstantInteger) literal).getValue();
|
||||
return new Directive.Address(addressAsConstantValue, address);
|
||||
|
@ -1769,9 +1757,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
|
||||
private void addLoopBody(KickCParser.StmtContext stmt) {
|
||||
if(stmt != null) {
|
||||
if(stmt instanceof KickCParser.StmtBlockContext) {
|
||||
if(stmt instanceof KickCParser.StmtBlockContext stmtBlockContext) {
|
||||
// Skip the block context and reuse the one created by the for() itself
|
||||
KickCParser.StmtBlockContext stmtBlockContext = (KickCParser.StmtBlockContext) stmt;
|
||||
if(stmtBlockContext.stmtSeq() != null) {
|
||||
this.visit(stmtBlockContext.stmtSeq());
|
||||
}
|
||||
|
@ -1866,7 +1853,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
private Map<String, SymbolRef> getAsmReferencedSymbolVariables(KickCParser.StmtAsmContext
|
||||
ctx, List<String> definedLabels) {
|
||||
Map<String, SymbolRef> referenced = new LinkedHashMap<>();
|
||||
KickCParserBaseVisitor<Void> findReferenced = new KickCParserBaseVisitor<Void>() {
|
||||
KickCParserBaseVisitor<Void> findReferenced = new KickCParserBaseVisitor<>() {
|
||||
|
||||
@Override
|
||||
public Void visitAsmExprBinary(KickCParser.AsmExprBinaryContext ctx) {
|
||||
|
@ -1911,7 +1898,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
*/
|
||||
private List<String> getAsmDefinedLabels(KickCParser.StmtAsmContext ctx) {
|
||||
List<String> definedLabels = new ArrayList<>();
|
||||
KickCParserBaseVisitor<Void> findDefinedLabels = new KickCParserBaseVisitor<Void>() {
|
||||
KickCParserBaseVisitor<Void> findDefinedLabels = new KickCParserBaseVisitor<>() {
|
||||
@Override
|
||||
public Void visitAsmLabelName(KickCParser.AsmLabelNameContext ctx) {
|
||||
String label = ctx.ASM_NAME().getText();
|
||||
|
@ -1962,13 +1949,13 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
|
||||
@Override
|
||||
public Object visitTypeSimple(KickCParser.TypeSimpleContext ctx) {
|
||||
String typeName = "";
|
||||
StringBuilder typeName = new StringBuilder();
|
||||
for(TerminalNode simpleTypeNode : ctx.SIMPLETYPE()) {
|
||||
if(typeName.length() > 0)
|
||||
typeName += " ";
|
||||
typeName += simpleTypeNode.getText();
|
||||
typeName.append(" ");
|
||||
typeName.append(simpleTypeNode.getText());
|
||||
}
|
||||
final SymbolType typeSimple = SymbolType.get(typeName);
|
||||
final SymbolType typeSimple = SymbolType.get(typeName.toString());
|
||||
if(typeSimple == null)
|
||||
throw new CompileError("Unknown type '" + typeName + "'", new StatementSource(ctx));
|
||||
varDecl.setDeclType(typeSimple);
|
||||
|
@ -2321,12 +2308,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
public Object visitExprAssignment(KickCParser.ExprAssignmentContext ctx) {
|
||||
Object val = visit(ctx.expr(0));
|
||||
if(val instanceof ConstantRef) {
|
||||
throw new CompileError("const variable may not be modified " + val.toString(), new StatementSource(ctx));
|
||||
throw new CompileError("const variable may not be modified " + val, new StatementSource(ctx));
|
||||
}
|
||||
if(!(val instanceof LValue)) {
|
||||
if(!(val instanceof LValue lValue)) {
|
||||
throw new CompileError("Illegal assignment Lvalue " + val.toString(), new StatementSource(ctx));
|
||||
}
|
||||
LValue lValue = (LValue) val;
|
||||
if(lValue instanceof VariableRef && ((VariableRef) lValue).isIntermediate()) {
|
||||
// Encountered an intermediate variable. This must be turned into a proper LValue later. Put it into a marker to signify that
|
||||
lValue = new LvalueIntermediate((VariableRef) lValue);
|
||||
|
@ -2343,10 +2329,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
public Object visitExprAssignmentCompound(KickCParser.ExprAssignmentCompoundContext ctx) {
|
||||
// Assignment (rValue/lValue)
|
||||
Object value = visit(ctx.expr(0));
|
||||
if(!(value instanceof LValue)) {
|
||||
if(!(value instanceof LValue lValue)) {
|
||||
throw new CompileError("Illegal assignment Lvalue " + value.toString(), new StatementSource(ctx));
|
||||
}
|
||||
LValue lValue = (LValue) value;
|
||||
if(lValue instanceof VariableRef && ((VariableRef) lValue).isIntermediate()) {
|
||||
// Encountered an intermediate variable. This must be turned into a proper LValue later. Put it into a marker to signify that
|
||||
lValue = new LvalueIntermediate((VariableRef) lValue);
|
||||
|
|
|
@ -52,7 +52,7 @@ public class Pass1AddressOfHandling extends Pass2SsaOptimization {
|
|||
*/
|
||||
private void updateAddressOfValue(Value value, Statement currentStmt) {
|
||||
if(value instanceof SymbolRef) {
|
||||
Symbol toSymbol = getScope().getSymbol((SymbolRef) value);
|
||||
Symbol toSymbol = getProgramScope().getSymbol((SymbolRef) value);
|
||||
final String stmtStr = currentStmt == null ? toSymbol.toString(getProgram()) : currentStmt.toString(getProgram(), false);
|
||||
if(toSymbol instanceof Variable) {
|
||||
final Variable variable = (Variable) toSymbol;
|
||||
|
|
|
@ -26,7 +26,7 @@ public class Pass1AsmUsesHandling extends Pass2SsaOptimization {
|
|||
// Symbol used in inline ASM or KickAsm
|
||||
final Value value = programValue.get();
|
||||
if(value instanceof SymbolVariableRef) {
|
||||
Variable variable = getScope().getVariable((SymbolVariableRef) value);
|
||||
Variable variable = getProgramScope().getVariable((SymbolVariableRef) value);
|
||||
if(!variable.isKindConstant() && !variable.isVolatile()) {
|
||||
final String stmtStr = currentStmt == null ? value.toString(getProgram()) : currentStmt.toString(getProgram(), false);
|
||||
updateAddressOfVariable(variable, stmtStr);
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCalling;
|
||||
|
@ -18,27 +19,25 @@ public class Pass1AssertInterrupts extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementCalling) {
|
||||
ProcedureRef procedureRef = ((StatementCalling) statement).getProcedure();
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
if(procedure.getInterruptType()!=null) {
|
||||
throw new CompileError("Interrupts cannot be called.", statement.getSource());
|
||||
}
|
||||
for(Statement statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementCalling) {
|
||||
ProcedureRef procedureRef = ((StatementCalling) statement).getProcedure();
|
||||
Procedure procedure = getProgramScope().getProcedure(procedureRef);
|
||||
if(procedure.getInterruptType() != null) {
|
||||
throw new CompileError("Interrupts cannot be called.", statement.getSource());
|
||||
}
|
||||
}
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
if(procedure.getInterruptType()!=null) {
|
||||
if(procedure.isDeclaredInline()) {
|
||||
throw new CompileError("Interrupts cannot be inlined. " + procedure.toString());
|
||||
}
|
||||
if(procedure.getParameters().size()>0) {
|
||||
throw new CompileError("Interrupts cannot have parameters. " + procedure.toString());
|
||||
}
|
||||
if(!SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
throw new CompileError("Interrupts cannot return anything. " + procedure.toString());
|
||||
}
|
||||
}
|
||||
for(Procedure procedure : getProgramScope().getAllProcedures(true)) {
|
||||
if(procedure.getInterruptType()!=null) {
|
||||
if(procedure.isDeclaredInline()) {
|
||||
throw new CompileError("Interrupts cannot be inlined. " + procedure.toString());
|
||||
}
|
||||
if(procedure.getParameters().size()>0) {
|
||||
throw new CompileError("Interrupts cannot have parameters. " + procedure.toString());
|
||||
}
|
||||
if(!SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
throw new CompileError("Interrupts cannot return anything. " + procedure.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class Pass1AssertJumpLabels extends Pass1Base {
|
|||
for(Statement statement : statementSequence.getStatements()) {
|
||||
if(statement instanceof StatementJump) {
|
||||
LabelRef jumpLabel = ((StatementJump) statement).getDestination();
|
||||
Label label = getScope().getLabel(jumpLabel);
|
||||
Label label = getProgramScope().getLabel(jumpLabel);
|
||||
if(label==null) {
|
||||
throw new CompileError("goto label undefined '"+jumpLabel.getLocalName()+"'", statement);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementLValue;
|
||||
|
@ -23,16 +24,14 @@ public class Pass1AssertNoLValueIntermediate extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementLValue) {
|
||||
LValue lValue = ((StatementLValue) statement).getlValue();
|
||||
if(lValue instanceof LvalueIntermediate) {
|
||||
VariableRef intermediateVar = ((LvalueIntermediate) lValue).getVariable();
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(intermediateVar, getGraph(), getScope());
|
||||
final VarAssignments.VarAssignment varAssignment = varAssignments.get(0);
|
||||
throw new CompileError("LValue is illegal. " + statement + " - definition of lValue " + varAssignment, varAssignment.getSource());
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementLValue) {
|
||||
LValue lValue = ((StatementLValue) statement).getlValue();
|
||||
if(lValue instanceof LvalueIntermediate) {
|
||||
VariableRef intermediateVar = ((LvalueIntermediate) lValue).getVariable();
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(intermediateVar, getGraph(), getProgramScope());
|
||||
final VarAssignments.VarAssignment varAssignment = varAssignments.get(0);
|
||||
throw new CompileError("LValue is illegal. " + statement + " - definition of lValue " + varAssignment, varAssignment.getSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ public class Pass1AssertNoLocalAddressArray extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(Variable variable : getScope().getAllVars(true)) {
|
||||
for(Variable variable : getProgramScope().getAllVars(true)) {
|
||||
if(!ScopeRef.ROOT.equals(variable.getScope().getRef()) && variable.isArray() && variable.getMemoryAddress()!=null)
|
||||
throw new CompileError("Error! Local array variables with __address() not allowed. "+variable.toString(getProgram()));
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementLValue;
|
||||
|
@ -19,14 +20,16 @@ public class Pass1AssertNoModifyVars extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementLValue) {
|
||||
StatementLValue statementLValue = (StatementLValue) statement;
|
||||
if(!statementLValue.isInitialAssignment() && statementLValue.getlValue() instanceof VariableRef) {
|
||||
Variable assignedVar = getScope().getVariable((VariableRef) statementLValue.getlValue());
|
||||
if(assignedVar.isNoModify())
|
||||
throw new CompileError("const variable may not be modified! " + assignedVar.toString(), statement);
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if (statement instanceof StatementLValue) {
|
||||
StatementLValue statementLValue = (StatementLValue) statement;
|
||||
if (!statementLValue.isInitialAssignment()
|
||||
&& statementLValue.getlValue() instanceof VariableRef) {
|
||||
Variable assignedVar = getProgramScope().getVariable(
|
||||
(VariableRef) statementLValue.getlValue());
|
||||
if (assignedVar.isNoModify()) {
|
||||
throw new CompileError(
|
||||
"const variable may not be modified! " + assignedVar.toString(), statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public class Pass1AssertNoRecursion extends Pass1Base {
|
|||
@Override
|
||||
public boolean step() {
|
||||
CallGraph callGraph = getProgram().getCallGraph();
|
||||
Collection<Procedure> procedures = getScope().getAllProcedures(true);
|
||||
Collection<Procedure> procedures = getProgramScope().getAllProcedures(true);
|
||||
for(Procedure procedure : procedures) {
|
||||
Collection<ScopeRef> recursiveCalls = callGraph.getRecursiveCalls(procedure.getRef());
|
||||
if(recursiveCalls.contains(procedure.getRef()) && !Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
|
@ -27,11 +28,11 @@ public class Pass1AssertProcedureCallParameters extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
Procedure procedure = getProgramScope().getProcedure(call.getProcedure());
|
||||
List<Variable> declParameters = procedure.getParameters();
|
||||
List<RValue> callParameters = call.getParameters();
|
||||
if(callParameters.size()!=declParameters.size()) {
|
||||
|
@ -40,7 +41,7 @@ public class Pass1AssertProcedureCallParameters extends Pass1Base {
|
|||
for(int i = 0; i < declParameters.size(); i++) {
|
||||
Variable declParameter = declParameters.get(i);
|
||||
RValue callParameter = callParameters.get(i);
|
||||
SymbolType callParameterType = SymbolTypeInference.inferType(getScope(), callParameter);
|
||||
SymbolType callParameterType = SymbolTypeInference.inferType(getProgramScope(), callParameter);
|
||||
SymbolType declParameterType = declParameter.getType();
|
||||
|
||||
if(declParameterType instanceof SymbolTypePointer) {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
||||
|
@ -17,7 +15,7 @@ public class Pass1AssertProcedureDefined extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
final Collection<Procedure> allProcedures = getScope().getAllProcedures(true);
|
||||
final Collection<Procedure> allProcedures = getProgramScope().getAllProcedures(true);
|
||||
for(Procedure procedure : allProcedures) {
|
||||
if(procedure.isDeclaredIntrinsic()) {
|
||||
if(!Procedure.INTRINSIC_PROCEDURES.contains(procedure.getLocalName()))
|
||||
|
@ -25,7 +23,13 @@ public class Pass1AssertProcedureDefined extends Pass1Base {
|
|||
continue;
|
||||
}
|
||||
final Label procedureLabel = procedure.getLabel();
|
||||
final ControlFlowBlock procedureBlock = getGraph().getBlock(procedureLabel.getRef());
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
if(procedureCompilation == null)
|
||||
throw new CompileError("Error! Function body is never defined: " + procedure.getFullName());
|
||||
final ControlFlowGraph graph = procedureCompilation.getGraph();
|
||||
if(graph == null)
|
||||
throw new CompileError("Error! Function body is never defined: " + procedure.getFullName());
|
||||
final Graph.Block procedureBlock = graph.getBlock(procedureLabel.getRef());
|
||||
if(procedureBlock == null)
|
||||
throw new CompileError("Error! Function body is never defined: " + procedure.getFullName());
|
||||
}
|
||||
|
|
|
@ -28,9 +28,11 @@ public class Pass1AssertReturn extends Pass1Base {
|
|||
for(Procedure procedure : allProcedures) {
|
||||
if(procedure.isDeclaredIntrinsic()) continue;
|
||||
if(procedure.getReturnType() != null && !SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
final ControlFlowGraph graph = procedureCompilation.getGraph();
|
||||
LabelRef entryLabel = procedure.getRef().getLabelRef();
|
||||
ControlFlowBlock entryBlock = getProgram().getGraph().getBlock(entryLabel);
|
||||
assertReturn(entryBlock, new LinkedHashSet<>());
|
||||
Graph.Block entryBlock = graph.getBlock(entryLabel);
|
||||
assertReturn(graph, entryBlock, new LinkedHashSet<>());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -43,29 +45,27 @@ public class Pass1AssertReturn extends Pass1Base {
|
|||
* @param block The block to examine
|
||||
* @param visited Blocks already visited
|
||||
*/
|
||||
public void assertReturn(ControlFlowBlock block, Collection<LabelRef> visited) {
|
||||
public void assertReturn(ControlFlowGraph graph, Graph.Block block, Collection<LabelRef> visited) {
|
||||
if(visited.contains(block.getLabel())) {
|
||||
return;
|
||||
}
|
||||
visited.add(block.getLabel());
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(statement instanceof StatementAssignment assignment) {
|
||||
if(assignment.getlValue() instanceof VariableRef && ((VariableRef) assignment.getlValue()).getLocalName().equals("return")) {
|
||||
// Happy days - return found!
|
||||
return;
|
||||
}
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump cond = (StatementConditionalJump) statement;
|
||||
ControlFlowBlock jumpTo = getProgram().getGraph().getBlock(cond.getDestination());
|
||||
assertReturn(jumpTo, visited);
|
||||
} else if(statement instanceof StatementConditionalJump cond) {
|
||||
Graph.Block jumpTo = graph.getBlock(cond.getDestination());
|
||||
assertReturn(graph, jumpTo, visited);
|
||||
}
|
||||
}
|
||||
ControlFlowBlock successor = getProgram().getGraph().getBlock(block.getDefaultSuccessor());
|
||||
Graph.Block successor = graph.getBlock(block.getDefaultSuccessor());
|
||||
if(successor == null || successor.getLabel().getLocalName().equals(SymbolRef.PROCEXIT_BLOCK_NAME)) {
|
||||
throw new CompileError("Error! Method must end with a return statement. " + block.getScope().toString(getProgram()));
|
||||
} else {
|
||||
assertReturn(successor, visited);
|
||||
assertReturn(graph, successor, visited);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
|
@ -35,10 +32,10 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
|||
getProgram().clearControlFlowBlockSuccessorClosure();
|
||||
VariableReferenceInfos referenceInfos = getProgram().getVariableReferenceInfos();
|
||||
|
||||
ControlFlowBlock startBlock = getProgram().getGraph().getBlock(new LabelRef(SymbolRef.START_PROC_NAME));
|
||||
Graph.Block startBlock = getProgram().getGraph().getBlock(new LabelRef(SymbolRef.START_PROC_NAME));
|
||||
final LinkedHashSet<SymbolVariableRef> defined = new LinkedHashSet<>();
|
||||
// Add all variables with an init-value
|
||||
for(Variable var : getScope().getAllVars(true)) {
|
||||
for(Variable var : getProgramScope().getAllVars(true)) {
|
||||
if(var.getInitValue()!=null) {
|
||||
defined.add(var.getRef());
|
||||
}
|
||||
|
@ -61,7 +58,7 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
|||
* @param defined Variables already assigned a value at the point of the first execution of the block
|
||||
* @param visited Blocks already visited
|
||||
*/
|
||||
public void assertUsedVars(ControlFlowBlock block, LabelRef predecessor, VariableReferenceInfos referenceInfos, Collection<SymbolVariableRef> defined, Collection<LabelRef> visited) {
|
||||
public void assertUsedVars(Graph.Block block, LabelRef predecessor, VariableReferenceInfos referenceInfos, Collection<SymbolVariableRef> defined, Collection<LabelRef> visited) {
|
||||
// If the block has a phi statement it is always examined (to not skip any of the predecessor checks)
|
||||
assertUsedVarsPhi(block, predecessor, referenceInfos, defined);
|
||||
// If we have already visited the block - skip it
|
||||
|
@ -91,7 +88,7 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
|||
for(String paramName : procedure.getParameterNames()) {
|
||||
defined.add(procedure.getLocalVariable(paramName).getRef());
|
||||
}
|
||||
ControlFlowBlock procedureStart = getProgram().getGraph().getBlock(call.getProcedure().getLabelRef());
|
||||
Graph.Block procedureStart = getProgram().getGraph().getBlock(call.getProcedure().getLabelRef());
|
||||
assertUsedVars(procedureStart, block.getLabel(), referenceInfos, defined, visited);
|
||||
} else if(statement instanceof StatementCallPrepare) {
|
||||
StatementCallPrepare call = (StatementCallPrepare) statement;
|
||||
|
@ -101,15 +98,15 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
|||
}
|
||||
} else if(statement instanceof StatementCallExecute) {
|
||||
StatementCallExecute call = (StatementCallExecute) statement;
|
||||
ControlFlowBlock procedureStart = getProgram().getGraph().getBlock(call.getProcedure().getLabelRef());
|
||||
Graph.Block procedureStart = getProgram().getGraph().getBlock(call.getProcedure().getLabelRef());
|
||||
assertUsedVars(procedureStart, block.getLabel(), referenceInfos, defined, visited);
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump cond = (StatementConditionalJump) statement;
|
||||
ControlFlowBlock jumpTo = getProgram().getGraph().getBlock(cond.getDestination());
|
||||
Graph.Block jumpTo = getProgram().getGraph().getBlock(cond.getDestination());
|
||||
assertUsedVars(jumpTo, block.getLabel(), referenceInfos, defined, visited);
|
||||
}
|
||||
}
|
||||
ControlFlowBlock successor = getProgram().getGraph().getBlock(block.getDefaultSuccessor());
|
||||
Graph.Block successor = getProgram().getGraph().getBlock(block.getDefaultSuccessor());
|
||||
if(successor != null) {
|
||||
assertUsedVars(successor, block.getLabel(), referenceInfos, defined, visited);
|
||||
}
|
||||
|
@ -122,10 +119,9 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
|||
* @param predecessor The block jumping into this block (used for phi analysis)
|
||||
* @param referenceInfos Information about assigned/used variables in statements
|
||||
* @param defined Variables already assigned a value at the point of the first execution of the block
|
||||
* @param visited Blocks already visited
|
||||
*/
|
||||
|
||||
private void assertUsedVarsPhi(ControlFlowBlock block, LabelRef predecessor, VariableReferenceInfos referenceInfos, Collection<SymbolVariableRef> defined) {
|
||||
private void assertUsedVarsPhi(Graph.Block block, LabelRef predecessor, VariableReferenceInfos referenceInfos, Collection<SymbolVariableRef> defined) {
|
||||
if(predecessor != null && block.hasPhiBlock()) {
|
||||
StatementPhiBlock phiBlock = block.getPhiBlock();
|
||||
ArrayList<SymbolVariableRef> used = new ArrayList<>();
|
||||
|
@ -148,7 +144,7 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
|||
throw new CompileError("Variable used before being defined " + usedRef.toString(getProgram()) + " in " + phiBlock.toString(getProgram(), false), phiBlock.getSource());
|
||||
}
|
||||
}
|
||||
// Add all variables fefined by the PHI block
|
||||
// Add all variables defined by the PHI block
|
||||
Collection<VariableRef> defd = referenceInfos.getDefinedVars(phiBlock);
|
||||
for(VariableRef definedRef : defd) {
|
||||
defined.add(definedRef);
|
||||
|
|
|
@ -13,7 +13,7 @@ public class Pass1AssertVariableDefined extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(Variable var : getScope().getAllVars(true)) {
|
||||
for(Variable var : getProgramScope().getAllVars(true)) {
|
||||
if(var.isDeclarationOnly())
|
||||
throw new CompileError("Error! Variable is declared but never defined: " + var.getFullName());
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.model.ControlFlowGraph;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
||||
|
||||
|
@ -37,7 +37,11 @@ public abstract class Pass1Base implements PassStep {
|
|||
return program;
|
||||
}
|
||||
|
||||
public ProgramScope getScope() {
|
||||
public Graph getGraph() {
|
||||
return program.getGraph();
|
||||
}
|
||||
|
||||
public ProgramScope getProgramScope() {
|
||||
return program.getScope();
|
||||
}
|
||||
|
||||
|
@ -45,9 +49,4 @@ public abstract class Pass1Base implements PassStep {
|
|||
return program.getLog();
|
||||
}
|
||||
|
||||
public ControlFlowGraph getGraph() {
|
||||
return program.getGraph();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.OperatorUnary;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
|
@ -43,7 +44,7 @@ public class Pass1ByteXIntrinsicRewrite extends Pass2SsaOptimization {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
|
|
@ -15,40 +15,49 @@ import java.util.*;
|
|||
/** Handle calling convention {@link Procedure.CallingConvention#PHI_CALL} by passing parameters through variables */
|
||||
public class Pass1CallPhiParameters {
|
||||
|
||||
private Program program;
|
||||
private final Program program;
|
||||
|
||||
public Pass1CallPhiParameters(Program program) {
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
private Map<LabelRef, LabelRef> splitBlockMap = new LinkedHashMap<>();
|
||||
|
||||
public void execute() {
|
||||
final List<ControlFlowBlock> todoBlocks = getGraph().getAllBlocks();
|
||||
List<ControlFlowBlock> doneBlocks = new ArrayList<>();
|
||||
for(ProcedureCompilation procedureCompilation : this.program.getProcedureCompilations()) {
|
||||
handleProcedure(procedureCompilation);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleProcedure(ProcedureCompilation procedureCompilation) {
|
||||
|
||||
final Graph graph = procedureCompilation.getGraph();
|
||||
|
||||
final List<Graph.Block> todoBlocks = new ArrayList<>(graph.getAllBlocks());
|
||||
List<Graph.Block> doneBlocks = new ArrayList<>();
|
||||
|
||||
Map<LabelRef, LabelRef> splitBlockMap = new LinkedHashMap<>();
|
||||
|
||||
|
||||
while(!todoBlocks.isEmpty()) {
|
||||
final ControlFlowBlock block = todoBlocks.get(0);
|
||||
final Graph.Block block = todoBlocks.get(0);
|
||||
todoBlocks.remove(0);
|
||||
doneBlocks.add(block);
|
||||
|
||||
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
if(statement instanceof StatementCall call) {
|
||||
// Generate parameter passing assignments
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
// Handle PHI-calls
|
||||
if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention())) {
|
||||
final ControlFlowBlock newBlock = handlePhiCall(call, procedure, stmtIt, block);
|
||||
final ControlFlowBlock newBlock = handlePhiCall(call, procedure, stmtIt, block, splitBlockMap);
|
||||
// The current block was split into two blocks - add the new block at the front of the todoBlocks
|
||||
todoBlocks.add(0, newBlock);
|
||||
}
|
||||
}
|
||||
if(statement instanceof StatementReturn) {
|
||||
Procedure procedure = block.getProcedure(program);
|
||||
Procedure procedure = program.getProcedure(block);
|
||||
// Handle PHI-calls
|
||||
if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention())) {
|
||||
// Add self-assignments for all variables modified in the procedure
|
||||
|
@ -57,18 +66,19 @@ public class Pass1CallPhiParameters {
|
|||
for(VariableRef modifiedVar : modifiedVars) {
|
||||
if(getScope().getVariable(modifiedVar).isKindLoadStore())
|
||||
continue;
|
||||
stmtIt.add(new StatementAssignment(modifiedVar, modifiedVar, false, ((StatementReturn) statement).getSource(), Comment.NO_COMMENTS));
|
||||
stmtIt.add(new StatementAssignment(modifiedVar, modifiedVar, false, statement.getSource(), Comment.NO_COMMENTS));
|
||||
}
|
||||
stmtIt.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update graph blocks to include the new blocks added
|
||||
program.getGraph().setAllBlocks(doneBlocks);
|
||||
procedureCompilation.setGraph(new ControlFlowGraph(doneBlocks));
|
||||
|
||||
// Fix phi predecessors for any blocks has a split block as predecessor
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : procedureCompilation.getGraph().getAllBlocks()) {
|
||||
if(block.hasPhiBlock()) {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : block.getPhiBlock().getPhiVariables()) {
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
|
@ -86,11 +96,7 @@ public class Pass1CallPhiParameters {
|
|||
return program.getScope();
|
||||
}
|
||||
|
||||
private ControlFlowGraph getGraph() {
|
||||
return program.getGraph();
|
||||
}
|
||||
|
||||
private ControlFlowBlock handlePhiCall(StatementCall call, Procedure procedure, ListIterator<Statement> stmtIt, ControlFlowBlock block) {
|
||||
private ControlFlowBlock handlePhiCall(StatementCall call, Procedure procedure, ListIterator<Statement> stmtIt, Graph.Block block, Map<LabelRef, LabelRef> splitBlockMap) {
|
||||
|
||||
List<Variable> parameterDefs = procedure.getParameters();
|
||||
List<RValue> parameterValues = call.getParameters();
|
||||
|
@ -141,7 +147,7 @@ public class Pass1CallPhiParameters {
|
|||
call.setlValue(procReturnVarRef);
|
||||
|
||||
// Create a new block in the program, splitting the current block at the call/return (call finalize)
|
||||
Scope currentBlockScope = block.getProcedure(program);
|
||||
Scope currentBlockScope = program.getProcedure(block);
|
||||
if(currentBlockScope==null) currentBlockScope = getScope().getScope(ScopeRef.ROOT);
|
||||
LabelRef splitBlockNewLabelRef = currentBlockScope.addLabelIntermediate().getRef();
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(splitBlockNewLabelRef, block.getScope());
|
||||
|
|
|
@ -23,7 +23,7 @@ public class Pass1CallPhiReturn {
|
|||
}
|
||||
|
||||
public void execute() {
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(var block : program.getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
@ -38,11 +38,11 @@ public class Pass1CallPhiReturn {
|
|||
}
|
||||
}
|
||||
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(var block : program.getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementReturn) {
|
||||
StatementReturn statementReturn = (StatementReturn) statement;
|
||||
Procedure procedure = block.getProcedure(program);
|
||||
Procedure procedure = program.getProcedure(block);
|
||||
if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention())) {
|
||||
statementReturn.setValue(null);
|
||||
}
|
||||
|
@ -60,12 +60,12 @@ public class Pass1CallPhiReturn {
|
|||
* @param callBlock The block containing the call
|
||||
* @param stmtIt Iterator used for adding statements
|
||||
*/
|
||||
void handlePhiCall(StatementCall call, Procedure procedure, ControlFlowBlock callBlock, ListIterator<Statement> stmtIt) {
|
||||
void handlePhiCall(StatementCall call, Procedure procedure, Graph.Block callBlock, ListIterator<Statement> stmtIt) {
|
||||
// Generate return value assignment (call finalize)
|
||||
if(!SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
// Find return variable final version
|
||||
Label returnBlockLabel = procedure.getLocalLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
|
||||
ControlFlowBlock returnBlock = program.getGraph().getBlock(returnBlockLabel.getRef());
|
||||
Graph.Block returnBlock = program.getGraph().getBlock(returnBlockLabel.getRef());
|
||||
RValue returnVarFinal = null;
|
||||
for(Statement statement : returnBlock.getStatements()) {
|
||||
if(statement instanceof StatementReturn) {
|
||||
|
@ -91,7 +91,7 @@ public class Pass1CallPhiReturn {
|
|||
|
||||
// Patch versions of rValues in assignments for vars modified in the call (call finalize)
|
||||
LabelRef successor = callBlock.getDefaultSuccessor();
|
||||
ControlFlowBlock successorBlock = program.getGraph().getBlock(successor);
|
||||
Graph.Block successorBlock = program.getGraph().getBlock(successor);
|
||||
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
|
||||
for(Statement statement : successorBlock.getStatements()) {
|
||||
if(statement instanceof StatementPhiBlock) {
|
||||
|
@ -115,7 +115,7 @@ public class Pass1CallPhiReturn {
|
|||
private VariableRef findReturnVersion(Procedure procedure, VariableRef assignedVar) {
|
||||
String unversionedName = assignedVar.getFullNameUnversioned();
|
||||
LabelRef returnBlock = new LabelRef(procedure.getRef().getFullName() + "::@return");
|
||||
ControlFlowBlock block = program.getGraph().getBlock(returnBlock);
|
||||
Graph.Block block = program.getGraph().getBlock(returnBlock);
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CallingConventionStack;
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
|
@ -34,7 +31,7 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
|
||||
// Introduce STACK_OFFSET constants
|
||||
boolean createStackBase = false;
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
for(Procedure procedure : getProgramScope().getAllProcedures(true)) {
|
||||
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
|
||||
// Introduce the parameter offsets
|
||||
for(Variable parameter : procedure.getParameters()) {
|
||||
|
@ -52,7 +49,7 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
|
||||
// Add global STACK_BASE constant
|
||||
if(createStackBase)
|
||||
CallingConventionStack.getStackBaseConstant(getScope());
|
||||
CallingConventionStack.getStackBaseConstant(getProgramScope());
|
||||
|
||||
// Convert param(xxx) to stackidx(PARAM_X) = xxx
|
||||
if(offsetConstants.size() > 0) {
|
||||
|
@ -61,7 +58,7 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
// Convert ParamValues to calling-convention specific param-value
|
||||
ParamValue paramValue = (ParamValue) programValue.get();
|
||||
VariableRef parameterRef = paramValue.getParameter();
|
||||
SymbolType parameterType = SymbolTypeInference.inferType(getScope(), paramValue.getParameter());
|
||||
SymbolType parameterType = SymbolTypeInference.inferType(getProgramScope(), paramValue.getParameter());
|
||||
if(offsetConstants.containsKey(parameterRef)) {
|
||||
StackIdxValue stackIdxValue = new StackIdxValue(offsetConstants.get(parameterRef), parameterType);
|
||||
programValue.set(stackIdxValue);
|
||||
|
@ -72,12 +69,12 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Convert procedure return xxx to stackidx(RETURN) = xxx;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementReturn) {
|
||||
final Scope blockScope = getScope().getScope(block.getScope());
|
||||
final Scope blockScope = getProgramScope().getScope(block.getScope());
|
||||
if(blockScope instanceof Procedure) {
|
||||
Procedure procedure = (Procedure) blockScope;
|
||||
final SymbolType returnType = procedure.getReturnType();
|
||||
|
@ -95,7 +92,7 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Convert xxx = callfinalize to xxx = stackpull(type);
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
@ -125,7 +122,7 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Convert callprepare(xxx,yyy,) to stackpush(type)=xxx, ...;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
@ -182,12 +179,12 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
} else {
|
||||
// A struct to put on the stack
|
||||
final List<RValue> memberValues = ((ValueList) value).getList();
|
||||
final StructDefinition structDefinition = ((SymbolTypeStruct) returnType).getStructDefinition(getScope());
|
||||
final StructDefinition structDefinition = ((SymbolTypeStruct) returnType).getStructDefinition(getProgramScope());
|
||||
final List<Variable> memberVars = new ArrayList<>(structDefinition.getAllVars(false));
|
||||
for(int i = 0; i < memberVars.size(); i++) {
|
||||
final Variable memberVar = memberVars.get(i);
|
||||
final RValue memberValue = memberValues.get(i);
|
||||
ConstantRef structMemberOffsetConstant = SizeOfConstants.getStructMemberOffsetConstant(getScope(), structDefinition, memberVar.getLocalName());
|
||||
ConstantRef structMemberOffsetConstant = SizeOfConstants.getStructMemberOffsetConstant(getProgramScope(), structDefinition, memberVar.getLocalName());
|
||||
ConstantBinary memberReturnOffsetConstant = new ConstantBinary(stackReturnOffset, Operators.PLUS, structMemberOffsetConstant);
|
||||
generateStackReturnValues(memberValue, memberVar.getType(), memberReturnOffsetConstant, source, comments, stmtIt);
|
||||
}
|
||||
|
@ -212,7 +209,7 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
} else {
|
||||
// A struct to put on the stack
|
||||
final List<RValue> memberValues = ((ValueList) value).getList();
|
||||
final StructDefinition structDefinition = ((SymbolTypeStruct) symbolType).getStructDefinition(getScope());
|
||||
final StructDefinition structDefinition = ((SymbolTypeStruct) symbolType).getStructDefinition(getProgramScope());
|
||||
final List<Variable> memberVars = new ArrayList<>(structDefinition.getAllVars(false));
|
||||
for(int i = 0; i < memberVars.size(); i++) {
|
||||
final Variable memberVar = memberVars.get(i);
|
||||
|
@ -240,7 +237,7 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
} else {
|
||||
// A struct to put on the stack
|
||||
final List<RValue> memberValues = ((ValueList) value).getList();
|
||||
final StructDefinition structDefinition = ((SymbolTypeStruct) symbolType).getStructDefinition(getScope());
|
||||
final StructDefinition structDefinition = ((SymbolTypeStruct) symbolType).getStructDefinition(getProgramScope());
|
||||
final List<Variable> memberVars = new ArrayList<>(structDefinition.getAllVars(false));
|
||||
for(int i = 0; i < memberVars.size(); i++) {
|
||||
final Variable memberVar = memberVars.get(i);
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
|
@ -24,14 +21,14 @@ public class Pass1CallStackVarConvert extends Pass2SsaOptimization {
|
|||
public boolean step() {
|
||||
|
||||
// Transform STACK_CALL/VAR_CALL calls to call-prepare, call-execute, call-finalize
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
Procedure procedure = getProgramScope().getProcedure(procedureRef);
|
||||
Procedure.CallingConvention callingConvention = procedure.getCallingConvention();
|
||||
if(Procedure.CallingConvention.STACK_CALL.equals(callingConvention) || Procedure.CallingConvention.VAR_CALL.equals(callingConvention)) {
|
||||
boolean hasParamOrReturn = (call.getParameters().size() > 0) || !SymbolType.VOID.equals(procedure.getReturnType());
|
||||
|
@ -45,7 +42,7 @@ public class Pass1CallStackVarConvert extends Pass2SsaOptimization {
|
|||
StatementCallPointer call = (StatementCallPointer) statement;
|
||||
boolean hasParamOrReturn = call.getNumParameters() > 0 || call.getlValue() != null;
|
||||
//if(hasParamOrReturn) {
|
||||
final SymbolType procType = SymbolTypeInference.inferType(getScope(), call.getProcedure());
|
||||
final SymbolType procType = SymbolTypeInference.inferType(getProgramScope(), call.getProcedure());
|
||||
if(!(procType instanceof SymbolTypeProcedure)) {
|
||||
throw new CompileError("Called object is not a function or function pointer "+call.getProcedure().toString(), call);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
@ -26,11 +27,11 @@ public class Pass1CallStackVarPrepare extends Pass2SsaOptimization {
|
|||
public boolean step() {
|
||||
|
||||
// Set variables modified in STACK_CALL/VAR_CALL procedures to load/store
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
for(Procedure procedure : getProgramScope().getAllProcedures(true)) {
|
||||
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention()) || Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
|
||||
Set<VariableRef> modifiedVars = getProgram().getProcedureModifiedVars().getModifiedVars(procedure.getRef());
|
||||
for(VariableRef modifiedVar : modifiedVars) {
|
||||
final Variable variable = getScope().getVariable(modifiedVar);
|
||||
final Variable variable = getProgramScope().getVariable(modifiedVar);
|
||||
if(variable.isKindPhiMaster()) {
|
||||
getLog().append("Converting variable modified inside "+procedure.getCallingConvention().getName()+" procedure "+procedure.getFullName()+"() to load/store "+variable.toString(getProgram()));
|
||||
variable.setKind(Variable.Kind.LOAD_STORE);
|
||||
|
@ -40,7 +41,7 @@ public class Pass1CallStackVarPrepare extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Set all parameter/return variables in VAR_CALL procedures to LOAD/STORE
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
for(Procedure procedure : getProgramScope().getAllProcedures(true)) {
|
||||
if(Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
|
||||
for(Variable parameter : procedure.getParameters()) {
|
||||
parameter.setKind(Variable.Kind.LOAD_STORE);
|
||||
|
@ -55,10 +56,10 @@ public class Pass1CallStackVarPrepare extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Add parameter assignments at start of procedure in STACK_CALL procedures
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
for(Procedure procedure : getProgramScope().getAllProcedures(true)) {
|
||||
if(procedure.isDeclaredIntrinsic()) continue;
|
||||
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
|
||||
final ControlFlowBlock procedureBlock = getGraph().getBlock(procedure.getLabel().getRef());
|
||||
final Graph.Block procedureBlock = getGraph().getBlock(procedure.getLabel().getRef());
|
||||
final ArrayList<Variable> params = new ArrayList<>(procedure.getParameters());
|
||||
Collections.reverse(params);
|
||||
for(Variable param : params) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
@ -30,12 +31,12 @@ public class Pass1CallVar extends Pass2SsaOptimization {
|
|||
public boolean step() {
|
||||
|
||||
// Convert procedure return xxx to proc.return = xxx;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementReturn) {
|
||||
final Scope blockScope = getScope().getScope(block.getScope());
|
||||
final Scope blockScope = getProgramScope().getScope(block.getScope());
|
||||
if(blockScope instanceof Procedure) {
|
||||
Procedure procedure = (Procedure) blockScope;
|
||||
final SymbolType returnType = procedure.getReturnType();
|
||||
|
@ -49,13 +50,13 @@ public class Pass1CallVar extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Convert xxx = callfinalize to xxx = proc.return
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementCallFinalize) {
|
||||
final StatementCallFinalize call = (StatementCallFinalize) statement;
|
||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
Procedure procedure = getProgramScope().getProcedure(call.getProcedure());
|
||||
if(Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
|
||||
final StatementSource source = call.getSource();
|
||||
final List<Comment> comments = call.getComments();
|
||||
|
@ -71,13 +72,13 @@ public class Pass1CallVar extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Convert callprepare(xxx,yyy,) to proc.param = xxx, ...;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementCallPrepare) {
|
||||
final StatementCallPrepare call = (StatementCallPrepare) statement;
|
||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
Procedure procedure = getProgramScope().getProcedure(call.getProcedure());
|
||||
if(Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
|
||||
stmtIt.previous();
|
||||
final StatementSource source = call.getSource();
|
||||
|
@ -110,8 +111,8 @@ public class Pass1CallVar extends Pass2SsaOptimization {
|
|||
} else {
|
||||
final CastValue structLValue = new CastValue(returnType, lValue);
|
||||
// A struct to unwind
|
||||
final ValueSource lValueSource = ValueSourceFactory.getValueSource(structLValue, getProgram(), getScope(), currentStmt, stmtIt, null);
|
||||
final ValueSource rValueSource = ValueSourceFactory.getValueSource(returnVar.getRef(), getProgram(), getScope(), currentStmt, stmtIt, null);
|
||||
final ValueSource lValueSource = ValueSourceFactory.getValueSource(structLValue, getProgram(), getProgramScope(), currentStmt, stmtIt, null);
|
||||
final ValueSource rValueSource = ValueSourceFactory.getValueSource(returnVar.getRef(), getProgram(), getProgramScope(), currentStmt, stmtIt, null);
|
||||
Pass1UnwindStructValues.copyValues(lValueSource, rValueSource, null, false, currentStmt, null, stmtIt, getProgram());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
@ -29,29 +26,31 @@ public class Pass1CallVoidReturns extends Pass2SsaOptimization {
|
|||
getProgram().clearControlFlowBlockSuccessorClosure();
|
||||
VariableReferenceInfos referenceInfos = getProgram().getVariableReferenceInfos();
|
||||
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementCall) {
|
||||
final ProcedureRef procedureRef = ((StatementCall) statement).getProcedure();
|
||||
final Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
if(SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
// Found a call to a VOID returning procedure
|
||||
final LValue lValue = ((StatementCall) statement).getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
VariableRef tmpVar = (VariableRef) lValue;
|
||||
final Collection<Integer> usages = referenceInfos.getVarUseStatements(tmpVar);
|
||||
if(usages.size() > 0) {
|
||||
final Integer usageIdx = usages.iterator().next();
|
||||
final Statement usage = getProgram().getStatementInfos().getStatement(usageIdx);
|
||||
throw new CompileError("Function " + procedure.getLocalName() + " does not return a value! ", usage);
|
||||
} else {
|
||||
// Delete the temporary variable
|
||||
final Variable var = getScope().getVar(tmpVar);
|
||||
var.getScope().remove(var);
|
||||
// And remove the lValue
|
||||
((StatementCall) statement).setlValue(null);
|
||||
if(getLog().isVerbosePass1CreateSsa())
|
||||
getLog().append("Removing LValue from call to function returning void");
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if (statement instanceof StatementCall) {
|
||||
final ProcedureRef procedureRef = ((StatementCall) statement).getProcedure();
|
||||
final Procedure procedure = getProgramScope().getProcedure(procedureRef);
|
||||
if (SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
// Found a call to a VOID returning procedure
|
||||
final LValue lValue = ((StatementCall) statement).getlValue();
|
||||
if (lValue instanceof VariableRef) {
|
||||
VariableRef tmpVar = (VariableRef) lValue;
|
||||
final Collection<Integer> usages = referenceInfos.getVarUseStatements(tmpVar);
|
||||
if (usages.size() > 0) {
|
||||
final Integer usageIdx = usages.iterator().next();
|
||||
final Statement usage = getProgram().getStatementInfos()
|
||||
.getStatement(usageIdx);
|
||||
throw new CompileError(
|
||||
"Function " + procedure.getLocalName() + " does not return a value! ",
|
||||
usage);
|
||||
} else {
|
||||
// Delete the temporary variable
|
||||
final Variable var = getProgramScope().getVar(tmpVar);
|
||||
var.getScope().remove(var);
|
||||
// And remove the lValue
|
||||
((StatementCall) statement).setlValue(null);
|
||||
if (getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("Removing LValue from call to function returning void");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class Pass1EarlyConstantIdentification extends Pass1Base {
|
|||
// Skip variables allocated into memory
|
||||
continue;
|
||||
if(!isParameter(variableRef)) {
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(variableRef, getGraph(), getScope());
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(variableRef, getGraph(), getProgramScope());
|
||||
if(varAssignments.size() == 1) {
|
||||
final VarAssignments.VarAssignment varAssignment = varAssignments.get(0);
|
||||
if(varAssignment.type.equals(VarAssignments.VarAssignment.Type.STATEMENT_LVALUE)) {
|
||||
|
@ -75,8 +75,8 @@ public class Pass1EarlyConstantIdentification extends Pass1Base {
|
|||
}
|
||||
}
|
||||
// Remove the statements
|
||||
for(ControlFlowBlock allBlock : getGraph().getAllBlocks()) {
|
||||
allBlock.getStatements().removeIf(removeStmt::contains);
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
block.getStatements().removeIf(removeStmt::contains);
|
||||
}
|
||||
// Replace all variable refs with constant refs
|
||||
ProgramValueIterator.execute(getProgram(), new AliasReplacer(aliases));
|
||||
|
@ -112,13 +112,13 @@ public class Pass1EarlyConstantIdentification extends Pass1Base {
|
|||
*/
|
||||
private ConstantValue prepareConstantValue(Variable variable, ConstantValue constantValue) {
|
||||
// Perform type checking
|
||||
SymbolType valueType = SymbolTypeInference.inferType(getScope(), constantValue);
|
||||
SymbolType valueType = SymbolTypeInference.inferType(getProgramScope(), constantValue);
|
||||
SymbolType variableType = variable.getType();
|
||||
|
||||
if(!SymbolTypeConversion.assignmentTypeMatch(variableType, valueType) || SymbolType.NUMBER.equals(valueType)) {
|
||||
ConstantLiteral constantLiteral = null;
|
||||
try {
|
||||
constantLiteral = constantValue.calculateLiteral(getScope());
|
||||
constantLiteral = constantValue.calculateLiteral(getProgramScope());
|
||||
} catch(ConstantNotLiteral e) {
|
||||
// ignore
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ public class Pass1EarlyConstantIdentification extends Pass1Base {
|
|||
* @return true if the variable is a procedure parameter
|
||||
*/
|
||||
public boolean isParameter(SymbolVariableRef variableRef) {
|
||||
Variable var = getScope().getVariable(variableRef);
|
||||
Variable var = getProgramScope().getVariable(variableRef);
|
||||
Scope varScope = var.getScope();
|
||||
if(varScope instanceof Procedure) {
|
||||
List<Variable> parameters = ((Procedure) varScope).getParameters();
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCalling;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.passes.utils.ProcedureUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** Eliminate uncalled methods */
|
||||
|
@ -18,10 +19,10 @@ public class Pass1EliminateUncalledProcedures extends Pass1Base {
|
|||
super(program);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
Set<ProcedureRef> calledProcedures = getGraph().getAllCalledProcedures();
|
||||
//calledProcedures.add(getProgram().getStartProcedure());
|
||||
Set<ProcedureRef> calledProcedures = getAllCalledProcedures(getGraph());
|
||||
|
||||
Set<ProcedureRef> unusedProcedures = new LinkedHashSet<>();
|
||||
Collection<Procedure> allProcedures = getProgram().getScope().getAllProcedures(true);
|
||||
|
@ -38,6 +39,22 @@ public class Pass1EliminateUncalledProcedures extends Pass1Base {
|
|||
return unusedProcedures.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all called procedures in a control flow graph
|
||||
*
|
||||
* @return All called procedures
|
||||
*/
|
||||
public static Set<ProcedureRef> getAllCalledProcedures(Graph graph) {
|
||||
Set<ProcedureRef> calledProcedures = new LinkedHashSet<>();
|
||||
for(var statement : graph.getAllStatements()) {
|
||||
if(statement instanceof StatementCalling call) {
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
calledProcedures.add(procedureRef);
|
||||
}
|
||||
}
|
||||
return calledProcedures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed a procedure from the program (the symbol in the symbol table and all blocks in the control flow graph)
|
||||
*
|
||||
|
@ -48,12 +65,7 @@ public class Pass1EliminateUncalledProcedures extends Pass1Base {
|
|||
if(program.getLog().isVerbosePass1CreateSsa()) {
|
||||
program.getLog().append("Removing unused procedure " + procedureRef);
|
||||
}
|
||||
Procedure procedure = program.getScope().getProcedure(procedureRef);
|
||||
List<ControlFlowBlock> procedureBlocks = program.getGraph().getScopeBlocks(procedureRef);
|
||||
for(ControlFlowBlock procedureBlock : procedureBlocks) {
|
||||
program.getGraph().remove(procedureBlock.getLabel());
|
||||
}
|
||||
procedure.getScope().remove(procedure);
|
||||
program.removeProcedure(procedureRef);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,12 +63,12 @@ public class Pass1ExtractInlineStrings extends Pass1Base {
|
|||
// Struct member initialization
|
||||
final ProgramValue.ProgramValueConstantStructMember constantStructMember = (ProgramValue.ProgramValueConstantStructMember) programValue;
|
||||
final SymbolVariableRef memberRef = constantStructMember.getMemberRef();
|
||||
final Variable memberDef = getScope().getVar(memberRef);
|
||||
final Variable memberDef = getProgramScope().getVar(memberRef);
|
||||
if(memberDef.getType() instanceof SymbolTypePointer) {
|
||||
if(((SymbolTypePointer) memberDef.getType()).getArraySpec()==null) {
|
||||
// Member is not an array - create a string.
|
||||
nameHint = memberDef.getFullName().replace("::","_").toLowerCase();
|
||||
Variable strConst = Pass1ExtractInlineStrings.this.createStringConstantVar(getScope(), (ConstantString) programValue.get(), nameHint);
|
||||
Variable strConst = Pass1ExtractInlineStrings.this.createStringConstantVar(getProgramScope(), (ConstantString) programValue.get(), nameHint);
|
||||
programValue.set(strConst.getRef());
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class Pass1ExtractInlineStrings extends Pass1Base {
|
|||
if(elementType instanceof SymbolTypePointer) {
|
||||
if(((SymbolTypePointer) elementType).getArraySpec()==null) {
|
||||
// Element is not an array - create a string.
|
||||
Variable strConst = Pass1ExtractInlineStrings.this.createStringConstantVar(getScope(), (ConstantString) programValue.get(), null);
|
||||
Variable strConst = Pass1ExtractInlineStrings.this.createStringConstantVar(getProgramScope(), (ConstantString) programValue.get(), null);
|
||||
programValue.set(strConst.getRef());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableBuilder;
|
||||
import dk.camelot64.kickc.model.operators.Operator;
|
||||
|
@ -36,7 +37,7 @@ public class Pass1FixLValuesLoHi extends Pass1Base {
|
|||
List<VariableRef> intermediates = new ArrayList<>();
|
||||
|
||||
ProgramScope programScope = getProgram().getScope();
|
||||
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
for(var block : getProgram().getGraph().getAllBlocks()) {
|
||||
List<Statement> statements = block.getStatements();
|
||||
ListIterator<Statement> statementsIt = statements.listIterator();
|
||||
while(statementsIt.hasNext()) {
|
||||
|
|
|
@ -21,7 +21,7 @@ public class Pass1FixProcedureParamSegment extends Pass2SsaOptimization {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
final Collection<Variable> allVariables = getScope().getAllVariables(true);
|
||||
final Collection<Variable> allVariables = getProgramScope().getAllVariables(true);
|
||||
for(Variable variable : allVariables) {
|
||||
if(variable.isKindLoadStore() || variable.isKindPhiMaster() || variable.isKindIntermediate()) {
|
||||
if(variable.getRegister() instanceof Registers.RegisterMainMem registerMainMem && registerMainMem.isAddressHardcoded())
|
||||
|
|
|
@ -4,20 +4,16 @@ import dk.camelot64.kickc.model.*;
|
|||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import org.antlr.v4.runtime.RuleContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/** Pass that generates a control flow graph for the program */
|
||||
public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
||||
|
||||
private List<ControlFlowBlock> blocks;
|
||||
|
||||
public Pass1GenerateControlFlowGraph(Program program) {
|
||||
super(program);
|
||||
|
@ -25,8 +21,7 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
this.blocks = new ArrayList<>();
|
||||
ProgramScope programScope = getScope();
|
||||
ProgramScope programScope = getProgramScope();
|
||||
final Collection<Procedure> allProcedures = getProgram().getScope().getAllProcedures(true);
|
||||
for(Procedure procedure : allProcedures) {
|
||||
if(procedure.isDeclaredIntrinsic())
|
||||
|
@ -34,10 +29,13 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
|||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
final StatementSequence sequence = procedureCompilation.getStatementSequence();
|
||||
if(sequence.getStatements().size()==0)
|
||||
// Empry procedures should not produce any blocks
|
||||
// Empty procedures should not produce any blocks
|
||||
continue;
|
||||
ControlFlowBlock currentBlock = null;
|
||||
ControlFlowBlock procBlock = getOrCreateBlock(procedure.getLabel().getRef(), procedure.getRef());
|
||||
|
||||
List<Graph.Block> blocks = new ArrayList<>();
|
||||
|
||||
Graph.Block currentBlock;
|
||||
Graph.Block procBlock = getOrCreateBlock(procedure.getLabel().getRef(), procedure.getRef(), blocks);
|
||||
currentBlock = procBlock;
|
||||
for(Statement statement : sequence.getStatements()) {
|
||||
Symbol currentBlockLabel = getProgram().getScope().getSymbol(currentBlock.getLabel());
|
||||
|
@ -52,48 +50,44 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
|||
} else if(statement instanceof StatementProcedureEnd) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
currentBlock.setDefaultSuccessor(new Label(SymbolRef.PROCEXIT_BLOCK_NAME, programScope, false).getRef());
|
||||
} else if(statement instanceof StatementLabel) {
|
||||
StatementLabel statementLabel = (StatementLabel) statement;
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(statementLabel.getLabel(), currentBlock.getScope());
|
||||
} else if(statement instanceof StatementLabel statementLabel) {
|
||||
Graph.Block nextBlock = getOrCreateBlock(statementLabel.getLabel(), currentBlock.getScope(), blocks);
|
||||
nextBlock.setComments(statementLabel.getComments());
|
||||
currentBlock.setDefaultSuccessor(nextBlock.getLabel());
|
||||
currentBlock = nextBlock;
|
||||
} else if(statement instanceof StatementJump) {
|
||||
StatementJump statementJump = (StatementJump) statement;
|
||||
ControlFlowBlock jmpBlock = getOrCreateBlock(statementJump.getDestination(), currentBlock.getScope());
|
||||
} else if(statement instanceof StatementJump statementJump) {
|
||||
Graph.Block jmpBlock = getOrCreateBlock(statementJump.getDestination(), currentBlock.getScope(), blocks);
|
||||
currentBlock.setDefaultSuccessor(jmpBlock.getLabel());
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope());
|
||||
Graph.Block nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope(), blocks);
|
||||
currentBlock = nextBlock;
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
} else if(statement instanceof StatementConditionalJump statementConditionalJump) {
|
||||
currentBlock.addStatement(statement);
|
||||
StatementConditionalJump statementConditionalJump = (StatementConditionalJump) statement;
|
||||
ControlFlowBlock jmpBlock = getOrCreateBlock(statementConditionalJump.getDestination(), currentBlock.getScope());
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope());
|
||||
Graph.Block jmpBlock = getOrCreateBlock(statementConditionalJump.getDestination(), currentBlock.getScope(), blocks);
|
||||
Graph.Block nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope(), blocks);
|
||||
currentBlock.setDefaultSuccessor(nextBlock.getLabel());
|
||||
currentBlock.setConditionalSuccessor(jmpBlock.getLabel());
|
||||
currentBlock = nextBlock;
|
||||
} else if(statement instanceof StatementReturn) {
|
||||
} else if(statement instanceof StatementReturn aReturn) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
StatementReturn aReturn = (StatementReturn) statement;
|
||||
currentBlock.addStatement(aReturn);
|
||||
// TODO: Make all returns exit through the same exit-block!
|
||||
} else {
|
||||
currentBlock.addStatement(statement);
|
||||
}
|
||||
}
|
||||
ControlFlowGraph controlFlowGraph = new ControlFlowGraph(blocks);
|
||||
procedureCompilation.setGraph(controlFlowGraph);
|
||||
|
||||
}
|
||||
ControlFlowGraph controlFlowGraph = new ControlFlowGraph(blocks);
|
||||
getProgram().setGraph(controlFlowGraph);
|
||||
return false;
|
||||
}
|
||||
|
||||
private ControlFlowBlock getOrCreateBlock(LabelRef label, ScopeRef scope) {
|
||||
for(ControlFlowBlock block : blocks) {
|
||||
private Graph.Block getOrCreateBlock(LabelRef label, ScopeRef scope, List<Graph.Block> blocks) {
|
||||
for(var block : blocks) {
|
||||
if(block.getLabel().equals(label)) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
ControlFlowBlock block = new ControlFlowBlock(label, scope);
|
||||
Graph.Block block = new ControlFlowBlock(label, scope);
|
||||
blocks.add(block);
|
||||
return block;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
@ -51,20 +49,21 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
* Version all non-versioned non-intermediary being assigned a value.
|
||||
*/
|
||||
private void versionAllAssignments() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementLValue) {
|
||||
StatementLValue statementLValue = (StatementLValue) statement;
|
||||
LValue lValue = statementLValue.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
versionAssignment((VariableRef) lValue, new ProgramValue.ProgramValueLValue(statementLValue), statementLValue.getSource());
|
||||
} else if(lValue instanceof ValueList) {
|
||||
List<RValue> lValueList = ((ValueList) lValue).getList();
|
||||
for(int i = 0; i < lValueList.size(); i++) {
|
||||
LValue lVal = (LValue) lValueList.get(i);
|
||||
if(lVal instanceof VariableRef) {
|
||||
versionAssignment((VariableRef) lVal, new ProgramValue.ProgramValueListElement((ValueList) lValue, i), statementLValue.getSource());
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if (statement instanceof StatementLValue statementLValue) {
|
||||
LValue lValue = statementLValue.getlValue();
|
||||
if (lValue instanceof VariableRef) {
|
||||
versionAssignment((VariableRef) lValue,
|
||||
new ProgramValue.ProgramValueLValue(statementLValue),
|
||||
statementLValue.getSource());
|
||||
} else if (lValue instanceof ValueList) {
|
||||
List<RValue> lValueList = ((ValueList) lValue).getList();
|
||||
for (int i = 0; i < lValueList.size(); i++) {
|
||||
LValue lVal = (LValue) lValueList.get(i);
|
||||
if (lVal instanceof VariableRef) {
|
||||
versionAssignment((VariableRef) lVal,
|
||||
new ProgramValue.ProgramValueListElement((ValueList) lValue, i),
|
||||
statementLValue.getSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +79,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
* @param source The statement source - usable for error messages
|
||||
*/
|
||||
private void versionAssignment(VariableRef lValueRef, ProgramValue programLValue, StatementSource source) {
|
||||
Variable assignedVar = getScope().getVariable(lValueRef);
|
||||
Variable assignedVar = getProgramScope().getVariable(lValueRef);
|
||||
if(assignedVar.isKindPhiMaster()) {
|
||||
if(assignedVar.isVolatile())
|
||||
throw new InternalError("Error! Volatiles can not be versioned ", source);
|
||||
|
@ -93,7 +92,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
* Version all uses of non-versioned non-intermediary variables
|
||||
*/
|
||||
private void versionAllUses() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
// Newest version of variables in the block.
|
||||
Map<Variable, Variable> blockVersions = new LinkedHashMap<>();
|
||||
// New phi functions introduced in the block to create versions of variables.
|
||||
|
@ -109,8 +108,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
programValue.set(version.getRef());
|
||||
}
|
||||
// Update map of versions encountered in the block
|
||||
if(currentStmt instanceof StatementLValue && programValue instanceof ProgramValue.ProgramValueLValue) {
|
||||
StatementLValue statementLValue = (StatementLValue) currentStmt;
|
||||
if(currentStmt instanceof StatementLValue statementLValue && programValue instanceof ProgramValue.ProgramValueLValue) {
|
||||
LValue lValue = statementLValue.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
updateBlockVersions((VariableRef) lValue, blockVersions);
|
||||
|
@ -132,7 +130,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
}
|
||||
|
||||
private void updateBlockVersions(VariableRef lValue, Map<Variable, Variable> blockVersions) {
|
||||
Variable variable = Pass1GenerateSingleStaticAssignmentForm.this.getScope().getVariable(lValue);
|
||||
Variable variable = Pass1GenerateSingleStaticAssignmentForm.this.getProgramScope().getVariable(lValue);
|
||||
if(variable.isKindPhiVersion()) {
|
||||
blockVersions.put(variable.getPhiMaster(), variable);
|
||||
}
|
||||
|
@ -153,7 +151,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
Map<Variable, Variable> blockNewPhis) {
|
||||
Variable version = null;
|
||||
if(rValue instanceof VariableRef) {
|
||||
Variable rValueVar = getScope().getVariable((VariableRef) rValue);
|
||||
Variable rValueVar = getProgramScope().getVariable((VariableRef) rValue);
|
||||
if(rValueVar.isKindPhiMaster()) {
|
||||
// rValue needs versioning - look for version in statements
|
||||
Variable rSymbol = rValueVar;
|
||||
|
@ -192,7 +190,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
private boolean completePhiFunctions() {
|
||||
Map<LabelRef, Map<Variable, Variable>> newPhis = new LinkedHashMap<>();
|
||||
Map<LabelRef, Map<Variable, Variable>> symbolMap = buildSymbolMap();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
|
||||
if(statement instanceof StatementPhiBlock) {
|
||||
|
@ -200,10 +198,10 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
|
||||
if(phiVariable.isEmpty()) {
|
||||
VariableRef phiLValVarRef = phiVariable.getVariable();
|
||||
Variable versioned = getScope().getVariable(phiLValVarRef);
|
||||
Variable versioned = getProgramScope().getVariable(phiLValVarRef);
|
||||
Variable unversioned = versioned.getPhiMaster();
|
||||
List<ControlFlowBlock> predecessors = getPhiPredecessors(block, getProgram());
|
||||
for(ControlFlowBlock predecessor : predecessors) {
|
||||
List<Graph.Block> predecessors = getPhiPredecessors(block, getProgram());
|
||||
for(var predecessor : predecessors) {
|
||||
LabelRef predecessorLabel = predecessor.getLabel();
|
||||
Map<Variable, Variable> predecessorMap = symbolMap.get(predecessorLabel);
|
||||
Variable previousSymbol = null;
|
||||
|
@ -232,7 +230,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
}
|
||||
}
|
||||
// Ads new phi functions to blocks
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
Map<Variable, Variable> blockNewPhis = newPhis.get(block.getLabel());
|
||||
if(blockNewPhis != null) {
|
||||
for(Variable symbol : blockNewPhis.keySet()) {
|
||||
|
@ -251,16 +249,16 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
* @param block The block to examine
|
||||
* @return All predecessor blocks
|
||||
*/
|
||||
public static List<ControlFlowBlock> getPhiPredecessors(ControlFlowBlock block, Program program) {
|
||||
List<ControlFlowBlock> predecessors = program.getGraph().getPredecessors(block);
|
||||
public static List<Graph.Block> getPhiPredecessors(Graph.Block block, Program program) {
|
||||
List<Graph.Block> predecessors = program.getGraph().getPredecessors(block);
|
||||
Symbol symbol = program.getScope().getSymbol(block.getLabel());
|
||||
if(symbol instanceof Procedure) {
|
||||
Procedure procedure = (Procedure) symbol;
|
||||
if(procedure.getInterruptType() != null || Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), program)) {
|
||||
// Find all root-level predecessors to the main block
|
||||
ControlFlowBlock mainBlock = program.getGraph().getBlock(new LabelRef(SymbolRef.MAIN_PROC_NAME));
|
||||
List<ControlFlowBlock> mainPredecessors = program.getGraph().getPredecessors(mainBlock);
|
||||
for(ControlFlowBlock mainPredecessor : mainPredecessors) {
|
||||
Graph.Block mainBlock = program.getGraph().getBlock(new LabelRef(SymbolRef.MAIN_PROC_NAME));
|
||||
List<Graph.Block> mainPredecessors = program.getGraph().getPredecessors(mainBlock);
|
||||
for(var mainPredecessor : mainPredecessors) {
|
||||
if(mainPredecessor.getScope().equals(ScopeRef.ROOT)) {
|
||||
predecessors.add(mainPredecessor);
|
||||
throw new RuntimeException("W");
|
||||
|
@ -277,7 +275,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
*/
|
||||
private Map<LabelRef, Map<Variable, Variable>> buildSymbolMap() {
|
||||
Map<LabelRef, Map<Variable, Variable>> symbolMap = new LinkedHashMap<>();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementLValue) {
|
||||
StatementLValue assignment = (StatementLValue) statement;
|
||||
|
@ -293,9 +291,9 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||
return symbolMap;
|
||||
}
|
||||
|
||||
private void addSymbolToMap(LValue lValue, ControlFlowBlock block, Map<LabelRef, Map<Variable, Variable>> symbolMap) {
|
||||
private void addSymbolToMap(LValue lValue, Graph.Block block, Map<LabelRef, Map<Variable, Variable>> symbolMap) {
|
||||
if(lValue instanceof VariableRef) {
|
||||
Variable lValueVar = getScope().getVariable((VariableRef) lValue);
|
||||
Variable lValueVar = getProgramScope().getVariable((VariableRef) lValue);
|
||||
if(lValueVar.isKindPhiVersion()) {
|
||||
Variable versioned = lValueVar;
|
||||
LabelRef label = block.getLabel();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.ProcedureModifiedVars;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
@ -24,7 +25,7 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
|
|||
@Override
|
||||
public boolean step() {
|
||||
Map<ProcedureRef, Set<VariableRef>> modified = new LinkedHashMap<>();
|
||||
Collection<Procedure> allProcedures = getScope().getAllProcedures(true);
|
||||
Collection<Procedure> allProcedures = getProgramScope().getAllProcedures(true);
|
||||
for(Procedure procedure : allProcedures) {
|
||||
Set<VariableRef> modifiedVars = getModifiedVars(procedure, new HashSet<>());
|
||||
modified.put(procedure.getRef(), modifiedVars);
|
||||
|
@ -47,8 +48,8 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
|
|||
|
||||
Set<VariableRef> modified = new LinkedHashSet<>();
|
||||
ScopeRef procScope = procedure.getRef();
|
||||
List<ControlFlowBlock> procBlocks = getProgram().getGraph().getScopeBlocks(procScope);
|
||||
for(ControlFlowBlock block : procBlocks) {
|
||||
List<Graph.Block> procBlocks = getProgram().getGraph().getScopeBlocks(procScope);
|
||||
for(var block : procBlocks) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementLValue) {
|
||||
LValue lValue = ((StatementLValue) statement).getlValue();
|
||||
|
@ -60,7 +61,7 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
|
|||
}
|
||||
if(statement instanceof StatementCalling) {
|
||||
ProcedureRef called = ((StatementCalling) statement).getProcedure();
|
||||
Procedure calledProc = getScope().getProcedure(called);
|
||||
Procedure calledProc = getProgramScope().getProcedure(called);
|
||||
modified.addAll(getModifiedVars(calledProc, visited));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class Pass1PointerSizeofFix extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
@ -69,8 +69,8 @@ public class Pass1PointerSizeofFix extends Pass1Base {
|
|||
getLog().append("Fixing pointer array-indexing " + deref.toString(getProgram()));
|
||||
SymbolVariableRef idx2VarRef = handled.getOrDefault(currentStmt, new LinkedHashMap<>()).get(deref.getIndex());
|
||||
if(idx2VarRef == null) {
|
||||
SymbolType type = SymbolTypeInference.inferType(getScope(), deref.getIndex());
|
||||
Scope scope = getScope().getScope(currentBlock.getScope());
|
||||
SymbolType type = SymbolTypeInference.inferType(getProgramScope(), deref.getIndex());
|
||||
Scope scope = getProgramScope().getScope(currentBlock.getScope());
|
||||
Variable idx2Var = VariableBuilder.createIntermediate(scope, type, getProgram());
|
||||
ConstantRef sizeOfTargetType = SizeOfConstants.getSizeOfConstantVar(getProgram().getScope(), pointerType.getElementType());
|
||||
StatementAssignment idx2 = new StatementAssignment((LValue) idx2Var.getRef(), deref.getIndex(), Operators.MULTIPLY, sizeOfTargetType, true, currentStmt.getSource(), Comment.NO_COMMENTS);
|
||||
|
@ -95,7 +95,7 @@ public class Pass1PointerSizeofFix extends Pass1Base {
|
|||
* @param assignment The assignment statement
|
||||
*/
|
||||
|
||||
private void fixPointerBinary(ControlFlowBlock block, ListIterator<Statement> stmtIt, StatementAssignment assignment) {
|
||||
private void fixPointerBinary(Graph.Block block, ListIterator<Statement> stmtIt, StatementAssignment assignment) {
|
||||
SymbolTypePointer pointerType = getPointerType(assignment.getrValue1());
|
||||
if(pointerType != null) {
|
||||
if(SymbolType.VOID.equals(pointerType.getElementType())) {
|
||||
|
@ -107,15 +107,15 @@ public class Pass1PointerSizeofFix extends Pass1Base {
|
|||
if(Operators.PLUS.equals(assignment.getOperator()) || Operators.MINUS.equals(assignment.getOperator())) {
|
||||
boolean isPointerPlusConst = true;
|
||||
if(assignment.getrValue2() instanceof SymbolVariableRef) {
|
||||
Symbol symbolR2 = getScope().getSymbol((SymbolVariableRef) assignment.getrValue2());
|
||||
Symbol symbolR2 = getProgramScope().getSymbol((SymbolVariableRef) assignment.getrValue2());
|
||||
if(symbolR2.getType() instanceof SymbolTypePointer) {
|
||||
// RValue 2 is a pointer
|
||||
isPointerPlusConst = false;
|
||||
if(getLog().isVerboseParse())
|
||||
getLog().append("Fixing pointer addition " + assignment.toString(getProgram(), false));
|
||||
LValue lValue = assignment.getlValue();
|
||||
Scope scope = getScope().getScope(block.getScope());
|
||||
SymbolType type = SymbolTypeInference.inferType(getScope(), assignment.getlValue());
|
||||
Scope scope = getProgramScope().getScope(block.getScope());
|
||||
SymbolType type = SymbolTypeInference.inferType(getProgramScope(), assignment.getlValue());
|
||||
Variable tmpVar = VariableBuilder.createIntermediate(scope, type, getProgram());
|
||||
assignment.setlValue((LValue) tmpVar.getRef());
|
||||
ConstantRef sizeOfTargetType = SizeOfConstants.getSizeOfConstantVar(getProgram().getScope(), pointerType.getElementType());
|
||||
|
@ -128,8 +128,8 @@ public class Pass1PointerSizeofFix extends Pass1Base {
|
|||
// Adding to a pointer - multiply by sizeof()
|
||||
if(getLog().isVerboseParse())
|
||||
getLog().append("Fixing pointer addition " + assignment.toString(getProgram(), false));
|
||||
Scope scope = getScope().getScope(block.getScope());
|
||||
SymbolType type = SymbolTypeInference.inferType(getScope(), assignment.getrValue2());
|
||||
Scope scope = getProgramScope().getScope(block.getScope());
|
||||
SymbolType type = SymbolTypeInference.inferType(getProgramScope(), assignment.getrValue2());
|
||||
Variable tmpVar = VariableBuilder.createIntermediate(scope, type, getProgram());
|
||||
stmtIt.remove();
|
||||
ConstantRef sizeOfTargetType = SizeOfConstants.getSizeOfConstantVar(getProgram().getScope(), pointerType.getElementType());
|
||||
|
@ -187,7 +187,7 @@ public class Pass1PointerSizeofFix extends Pass1Base {
|
|||
private SymbolTypePointer getPointerType(RValue pointer) {
|
||||
if(pointer instanceof SymbolVariableRef) {
|
||||
SymbolVariableRef varRef = (SymbolVariableRef) pointer;
|
||||
Variable variable = getScope().getVar(varRef);
|
||||
Variable variable = getProgramScope().getVar(varRef);
|
||||
SymbolType type = variable.getType();
|
||||
if(type instanceof SymbolTypePointer) {
|
||||
return (SymbolTypePointer) type;
|
||||
|
@ -195,9 +195,9 @@ public class Pass1PointerSizeofFix extends Pass1Base {
|
|||
} else if(pointer instanceof StructMemberRef) {
|
||||
StructMemberRef structMemberRef = (StructMemberRef) pointer;
|
||||
RValue struct = structMemberRef.getStruct();
|
||||
SymbolType structType = SymbolTypeInference.inferType(getScope(), struct);
|
||||
SymbolType structType = SymbolTypeInference.inferType(getProgramScope(), struct);
|
||||
if(structType instanceof SymbolTypeStruct) {
|
||||
StructDefinition structDefinition = ((SymbolTypeStruct) structType).getStructDefinition(getScope());
|
||||
StructDefinition structDefinition = ((SymbolTypeStruct) structType).getStructDefinition(getProgramScope());
|
||||
Variable memberVariable = structDefinition.getMember(structMemberRef.getMemberName());
|
||||
SymbolType memberType = memberVariable.getType();
|
||||
if(memberType instanceof SymbolTypePointer) {
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
@ -71,7 +68,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
|||
@Override
|
||||
public boolean step() {
|
||||
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
@ -129,7 +126,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
|||
final String formatString = ((ConstantString) formatLiteral).getString();
|
||||
final StringEncoding formatEncoding = ((ConstantString) formatLiteral).getEncoding();
|
||||
|
||||
Symbol putcSymbol = getScope().getGlobalSymbol(putcName);
|
||||
Symbol putcSymbol = getProgramScope().getGlobalSymbol(putcName);
|
||||
if(putcSymbol==null)
|
||||
throw new CompileError("Needed printf sub-procedure not found " + putcName + "().", ((Statement) printfCall).getSource());
|
||||
ConstantValue putcRef = new ConstantSymbolPointer(putcSymbol.getRef());
|
||||
|
@ -209,24 +206,24 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
|||
switch(typeField) {
|
||||
case "d":
|
||||
case "i":
|
||||
radix = getScope().getLocalConstant(DECIMAL).getRef();
|
||||
radix = getProgramScope().getLocalConstant(DECIMAL).getRef();
|
||||
signed = true;
|
||||
break;
|
||||
case "u":
|
||||
radix = getScope().getLocalConstant(DECIMAL).getRef();
|
||||
radix = getProgramScope().getLocalConstant(DECIMAL).getRef();
|
||||
signed = false;
|
||||
break;
|
||||
case "x":
|
||||
radix = getScope().getLocalConstant(HEXADECIMAL).getRef();
|
||||
radix = getProgramScope().getLocalConstant(HEXADECIMAL).getRef();
|
||||
signed = false;
|
||||
break;
|
||||
case "X":
|
||||
radix = getScope().getLocalConstant(HEXADECIMAL).getRef();
|
||||
radix = getProgramScope().getLocalConstant(HEXADECIMAL).getRef();
|
||||
signed = false;
|
||||
upperCase = 1l;
|
||||
break;
|
||||
case "o":
|
||||
radix = getScope().getLocalConstant(OCTAL).getRef();
|
||||
radix = getProgramScope().getLocalConstant(OCTAL).getRef();
|
||||
signed = false;
|
||||
break;
|
||||
default:
|
||||
|
@ -236,7 +233,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
|||
if(lengthField == null) {
|
||||
// Check if the parameter type is 8-bit or 32-bit
|
||||
RValue paramValue = getParameterValue(parameters, paramIdx, printfCall);
|
||||
SymbolType paramType = SymbolTypeInference.inferType(getScope(), paramValue);
|
||||
SymbolType paramType = SymbolTypeInference.inferType(getProgramScope(), paramValue);
|
||||
if(SymbolType.BYTE.equals(paramType) || SymbolType.SBYTE.equals(paramType)) {
|
||||
// Integer (8bit)
|
||||
printf_number_procedure = signed ? PRINTF_SCHAR : PRINTF_UCHAR;
|
||||
|
@ -290,7 +287,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
|||
new ConstantInteger(signAlways, SymbolType.BYTE),
|
||||
new ConstantInteger(zeroPadding, SymbolType.BYTE),
|
||||
new ConstantInteger(upperCase, SymbolType.BYTE),
|
||||
getScope().getLocalConstant(HEXADECIMAL).getRef()
|
||||
getProgramScope().getLocalConstant(HEXADECIMAL).getRef()
|
||||
));
|
||||
addPrintfCall(PRINTF_UINT, Arrays.asList(putcRef, new CastValue(SymbolType.WORD, getParameterValue(parameters, paramIdx, printfCall)), format_number_struct), stmtIt, printfCall);
|
||||
paramIdx++;
|
||||
|
@ -329,7 +326,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
|||
*/
|
||||
private void addPrintfCall(String printfProcedureName, List<RValue> printfProcedureParameters, ListIterator<Statement> stmtIt, StatementCall printfCall) {
|
||||
final StatementCall call_printf_str_prefix = new StatementCall(null, printfProcedureName, printfProcedureParameters, printfCall.getSource(), Comment.NO_COMMENTS);
|
||||
final Procedure printfProcedure = getScope().getLocalProcedure(call_printf_str_prefix.getProcedureName());
|
||||
final Procedure printfProcedure = getProgramScope().getLocalProcedure(call_printf_str_prefix.getProcedureName());
|
||||
if(printfProcedure == null) {
|
||||
throw new CompileError("Needed printf sub-procedure not found " + printfProcedureName + "().", printfCall.getSource());
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueHandler;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
|
@ -26,26 +23,37 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
List<ControlFlowBlock> allBlocks = getGraph().getAllBlocks();
|
||||
ListIterator<ControlFlowBlock> blocksIt = allBlocks.listIterator();
|
||||
while(blocksIt.hasNext()) {
|
||||
ControlFlowBlock block = blocksIt.next();
|
||||
List<Statement> blockStatements = block.getStatements();
|
||||
ListIterator<Statement> statementsIt = blockStatements.listIterator();
|
||||
while(statementsIt.hasNext()) {
|
||||
Statement statement = statementsIt.next();
|
||||
if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
if(procedure.isDeclaredInline()) {
|
||||
procedure.setCallingConvention(Procedure.CallingConvention.PHI_CALL);
|
||||
if(procedure.getInterruptType()!=null) {
|
||||
throw new CompileError("Error! Interrupts cannot be inlined. "+procedure.getRef().toString());
|
||||
for(var procedureCompilation : getProgram().getProcedureCompilations())
|
||||
if(inlineProcedure(procedureCompilation))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean inlineProcedure(ProcedureCompilation procedureCompilation) {
|
||||
final ControlFlowGraph procedureGraph = procedureCompilation.getGraph();
|
||||
if(procedureGraph!=null) {
|
||||
final List<Graph.Block> procedureBlocks = new ArrayList<>(procedureGraph.getAllBlocks());
|
||||
ListIterator<Graph.Block> blocksIt = procedureBlocks.listIterator();
|
||||
while(blocksIt.hasNext()) {
|
||||
Graph.Block block = blocksIt.next();
|
||||
List<Statement> blockStatements = block.getStatements();
|
||||
ListIterator<Statement> statementsIt = blockStatements.listIterator();
|
||||
while(statementsIt.hasNext()) {
|
||||
Statement statement = statementsIt.next();
|
||||
if(statement instanceof StatementCall call) {
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
Procedure procedure = getProgramScope().getProcedure(procedureRef);
|
||||
if(procedure.isDeclaredInline()) {
|
||||
procedure.setCallingConvention(Procedure.CallingConvention.PHI_CALL);
|
||||
if(procedure.getInterruptType() != null) {
|
||||
throw new CompileError("Error! Interrupts cannot be inlined. " + procedure.getRef().toString());
|
||||
}
|
||||
inlineProcedureCall(call, procedure, statementsIt, block, blocksIt);
|
||||
// Update the procedure graph
|
||||
procedureCompilation.setGraph(new ControlFlowGraph(procedureBlocks));
|
||||
// Exit and restart
|
||||
return true;
|
||||
}
|
||||
inlineProcedureCall(call, procedure, statementsIt, block, blocksIt);
|
||||
// Exit and restart
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,8 +70,8 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
* @param block The block containing the call
|
||||
* @param blocksIt The block iterator pointing to the block containing the call
|
||||
*/
|
||||
private void inlineProcedureCall(StatementCall call, Procedure procedure, ListIterator<Statement> statementsIt, ControlFlowBlock block, ListIterator<ControlFlowBlock> blocksIt) {
|
||||
Scope callScope = getScope().getScope(block.getScope());
|
||||
private void inlineProcedureCall(StatementCall call, Procedure procedure, ListIterator<Statement> statementsIt, Graph.Block block, ListIterator<Graph.Block> blocksIt) {
|
||||
Scope callScope = getProgramScope().getScope(block.getScope());
|
||||
// Remove call
|
||||
statementsIt.remove();
|
||||
// Find call serial number (handles when multiple calls to the same procedure is made in the call scope)
|
||||
|
@ -75,10 +83,10 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
// Create a new block label for the rest of the calling block
|
||||
Label restBlockLabel = callScope.addLabelIntermediate();
|
||||
// Copy all procedure blocks
|
||||
List<ControlFlowBlock> procedureBlocks = getGraph().getScopeBlocks(procedure.getRef());
|
||||
for(ControlFlowBlock procedureBlock : procedureBlocks) {
|
||||
List<Graph.Block> procedureBlocks = getGraph().getScopeBlocks(procedure.getRef());
|
||||
for(var procedureBlock : procedureBlocks) {
|
||||
LabelRef procBlockLabelRef = procedureBlock.getLabel();
|
||||
Symbol procBlockLabel = getScope().getSymbol(procBlockLabelRef);
|
||||
Symbol procBlockLabel = getProgramScope().getSymbol(procBlockLabelRef);
|
||||
Label inlinedBlockLabel;
|
||||
if(procedure.equals(procBlockLabel)) {
|
||||
inlinedBlockLabel = callScope.getLocalLabel(procedure.getLocalName() + serial);
|
||||
|
@ -119,7 +127,7 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
// Remove the tmp var receiving the result
|
||||
LValue lValue = call.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
callScope.remove(getScope().getVariable((VariableRef) lValue));
|
||||
callScope.remove(getProgramScope().getVariable((VariableRef) lValue));
|
||||
call.setlValue(null);
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +155,7 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
// Set successor of the @return block to the rest block
|
||||
inlinedSuccessor = restBlockLabel.getRef();
|
||||
} else {
|
||||
Label procBlockSuccessor = getScope().getLabel(procBlockSuccessorRef);
|
||||
Label procBlockSuccessor = getProgramScope().getLabel(procBlockSuccessorRef);
|
||||
String inlinedSuccessorName = getInlineSymbolName(procedure, procBlockSuccessor, serial);
|
||||
Label inlinedSuccessorLabel = callScope.getLocalLabel(inlinedSuccessorName);
|
||||
inlinedSuccessor = inlinedSuccessorLabel.getRef();
|
||||
|
@ -187,26 +195,19 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
*/
|
||||
private Statement inlineStatement(Statement procStatement, Procedure procedure, Scope callScope, int serial) {
|
||||
Statement inlinedStatement;
|
||||
if(procStatement instanceof StatementAssignment) {
|
||||
StatementAssignment procAssignment = (StatementAssignment) procStatement;
|
||||
if(procStatement instanceof StatementAssignment procAssignment) {
|
||||
inlinedStatement = new StatementAssignment(procAssignment.getlValue(), procAssignment.getrValue1(), procAssignment.getOperator(), procAssignment.getrValue2(), procAssignment.isInitialAssignment(), procAssignment.getSource(), Comment.NO_COMMENTS);
|
||||
} else if(procStatement instanceof StatementCall) {
|
||||
StatementCall procCall = (StatementCall) procStatement;
|
||||
} else if(procStatement instanceof StatementCall procCall) {
|
||||
StatementCall inlinedCall = new StatementCall(procCall.getlValue(), procCall.getProcedureName(), new ArrayList<>(procCall.getParameters()), procCall.getSource(), procCall.getComments());
|
||||
inlinedCall.setProcedure(procCall.getProcedure());
|
||||
inlinedStatement = inlinedCall;
|
||||
} else if(procStatement instanceof StatementAsm) {
|
||||
StatementAsm procAsm = (StatementAsm) procStatement;
|
||||
StatementAsm inlinedAsm = new StatementAsm(procAsm.getAsmLines(), new LinkedHashMap<>(procAsm.getReferenced()), procAsm.getDeclaredClobber(), procAsm.getSource(), Comment.NO_COMMENTS);
|
||||
inlinedStatement = inlinedAsm;
|
||||
} else if(procStatement instanceof StatementKickAsm) {
|
||||
StatementKickAsm procKasm = (StatementKickAsm) procStatement;
|
||||
StatementKickAsm inlinedAsm = new StatementKickAsm(procKasm.getKickAsmCode(), procKasm.getBytes(), procKasm.getCycles(), procKasm.getUses(), procKasm.getDeclaredClobber(), procKasm.getSource(), Comment.NO_COMMENTS);
|
||||
inlinedStatement = inlinedAsm;
|
||||
} else if(procStatement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump procConditional = (StatementConditionalJump) procStatement;
|
||||
} else if(procStatement instanceof StatementAsm procAsm) {
|
||||
inlinedStatement = new StatementAsm(procAsm.getAsmLines(), new LinkedHashMap<>(procAsm.getReferenced()), procAsm.getDeclaredClobber(), procAsm.getSource(), Comment.NO_COMMENTS);
|
||||
} else if(procStatement instanceof StatementKickAsm procKasm) {
|
||||
inlinedStatement = new StatementKickAsm(procKasm.getKickAsmCode(), procKasm.getBytes(), procKasm.getCycles(), procKasm.getUses(), procKasm.getDeclaredClobber(), procKasm.getSource(), Comment.NO_COMMENTS);
|
||||
} else if(procStatement instanceof StatementConditionalJump procConditional) {
|
||||
LabelRef procDestinationRef = procConditional.getDestination();
|
||||
Label procDestination = getScope().getLabel(procDestinationRef);
|
||||
Label procDestination = getProgramScope().getLabel(procDestinationRef);
|
||||
Label inlinedDest = procDestination;
|
||||
if(procDestination.getScope().equals(procedure)) {
|
||||
String inlineSymbolName = getInlineSymbolName(procedure, procDestination, serial);
|
||||
|
@ -221,9 +222,7 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
} else {
|
||||
throw new CompileError("Statement type of Inline function not handled " + procStatement, procStatement.getSource());
|
||||
}
|
||||
if(inlinedStatement!=null) {
|
||||
ProgramValueIterator.execute(inlinedStatement, new RValueInliner(procedure, serial, callScope), null, null);
|
||||
}
|
||||
ProgramValueIterator.execute(inlinedStatement, new RValueInliner(procedure, serial, callScope), null, null);
|
||||
return inlinedStatement;
|
||||
}
|
||||
|
||||
|
@ -247,11 +246,10 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void execute(ProgramValue programValue, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
||||
public void execute(ProgramValue programValue, Statement currentStmt, ListIterator<Statement> stmtIt, Graph.Block currentBlock) {
|
||||
Value rValue = programValue.get();
|
||||
if(rValue instanceof VariableRef) {
|
||||
VariableRef procVarRef = (VariableRef) rValue;
|
||||
Variable procVar = Pass1ProcedureInline.this.getScope().getVariable(procVarRef);
|
||||
if(rValue instanceof VariableRef procVarRef) {
|
||||
Variable procVar = Pass1ProcedureInline.this.getProgramScope().getVariable(procVarRef);
|
||||
if(procVar.getScope().equals(procedure)) {
|
||||
String inlineSymbolName = Pass1ProcedureInline.this.getInlineSymbolName(procedure, procVar, serial);
|
||||
Variable inlineVar = callScope.getLocalVariable(inlineSymbolName);
|
||||
|
@ -302,8 +300,7 @@ public class Pass1ProcedureInline extends Pass1Base {
|
|||
callScope.addLabel(procedure.getLocalName() + serial);
|
||||
// And copy all procedure symbols
|
||||
for(Symbol procSymbol : procedure.getAllSymbols()) {
|
||||
if(procSymbol instanceof Variable) {
|
||||
Variable procVar = (Variable) procSymbol;
|
||||
if(procSymbol instanceof Variable procVar) {
|
||||
String inlineVarName = getInlineSymbolName(procedure, procSymbol, serial);
|
||||
Variable inlineVar = Variable.createCopy(inlineVarName, callScope, procVar);
|
||||
callScope.add(inlineVar);
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
|
@ -20,12 +21,12 @@ public class Pass1Procedures extends Pass2SsaOptimization {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
String procedureName = call.getProcedureName();
|
||||
Scope localScope = (Scope) getScope().getSymbol(block.getScope());
|
||||
Scope localScope = (Scope) getProgramScope().getSymbol(block.getScope());
|
||||
final Symbol procedureSymbol = localScope.findSymbol(procedureName);
|
||||
if(procedureSymbol == null)
|
||||
throw new CompileError("Called procedure not found. " + procedureName, statement.getSource());
|
||||
|
|
|
@ -6,7 +6,6 @@ import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
|||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.symbols.Symbol;
|
||||
import dk.camelot64.kickc.model.values.ForwardVariableRef;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.Value;
|
||||
|
||||
/** Pass that resolves all forward variable references - and fails if they cannot be resolved*/
|
||||
|
@ -22,7 +21,7 @@ public class Pass1ResolveForwardReferences extends Pass1Base {
|
|||
Value rValue = programValue.get();
|
||||
if(rValue instanceof ForwardVariableRef) {
|
||||
String varName = ((ForwardVariableRef) rValue).getName();
|
||||
Scope currentScope = getScope().getScope(currentBlock.getScope());
|
||||
Scope currentScope = getProgramScope().getScope(currentBlock.getScope());
|
||||
Symbol symbol = currentScope.findSymbol(varName);
|
||||
if(symbol!=null) {
|
||||
getLog().append("Resolved forward reference " + varName+" to "+symbol.toString(getProgram()));
|
||||
|
|
|
@ -27,7 +27,7 @@ public class Pass1StructTypeSizeFix extends Pass2SsaOptimization {
|
|||
boolean modified = false;
|
||||
|
||||
// Update all types in variables
|
||||
for(Variable variable : getScope().getAllVars(true)) {
|
||||
for(Variable variable : getProgramScope().getAllVars(true)) {
|
||||
modified |= fixStructSize(variable.getType());
|
||||
}
|
||||
|
||||
|
@ -46,15 +46,15 @@ public class Pass1StructTypeSizeFix extends Pass2SsaOptimization {
|
|||
});
|
||||
|
||||
// Update all SIZEOF_XXX constants
|
||||
for(Scope subScope : getScope().getAllScopes(false)) {
|
||||
for(Scope subScope : getProgramScope().getAllScopes(false)) {
|
||||
if(subScope instanceof StructDefinition) {
|
||||
SymbolTypeStruct typeStruct = new SymbolTypeStruct((StructDefinition) subScope, false, false);
|
||||
StructDefinition structDefinition = typeStruct.getStructDefinition(getScope());
|
||||
int sizeBytes = typeStruct.calculateSizeBytes(structDefinition, getScope());
|
||||
StructDefinition structDefinition = typeStruct.getStructDefinition(getProgramScope());
|
||||
int sizeBytes = typeStruct.calculateSizeBytes(structDefinition, getProgramScope());
|
||||
if(sizeBytes != typeStruct.getSizeBytes()) {
|
||||
getLog().append("Fixing struct type SIZE_OF " + typeStruct.toCDecl() + " to " + sizeBytes);
|
||||
typeStruct.setSizeBytes(sizeBytes);
|
||||
SizeOfConstants.fixSizeOfConstantVar(getScope(), typeStruct);
|
||||
SizeOfConstants.fixSizeOfConstantVar(getProgramScope(), typeStruct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +71,8 @@ public class Pass1StructTypeSizeFix extends Pass2SsaOptimization {
|
|||
private boolean fixStructSize(SymbolType type) {
|
||||
if(type instanceof SymbolTypeStruct) {
|
||||
SymbolTypeStruct typeStruct = (SymbolTypeStruct) type;
|
||||
StructDefinition structDefinition = typeStruct.getStructDefinition(getScope());
|
||||
int sizeBytes = typeStruct.calculateSizeBytes(structDefinition, getScope());
|
||||
StructDefinition structDefinition = typeStruct.getStructDefinition(getProgramScope());
|
||||
int sizeBytes = typeStruct.calculateSizeBytes(structDefinition, getProgramScope());
|
||||
if(sizeBytes != typeStruct.getSizeBytes()) {
|
||||
getLog().append("Fixing struct type size " + type.toCDecl() + " to " + sizeBytes);
|
||||
typeStruct.setSizeBytes(sizeBytes);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
@ -26,21 +27,20 @@ public class Pass1UnrollConditionVariableSsa extends Pass2SsaOptimization {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
final StatementConditionalJump conditionalJump = (StatementConditionalJump) statement;
|
||||
if(conditionalJump.isDeclaredUnroll()) {
|
||||
Collection<VariableRef> referencedVars = new LinkedHashSet<>();
|
||||
findAllReferencedVars(referencedVars, conditionalJump.getrValue1());
|
||||
findAllReferencedVars(referencedVars, conditionalJump.getrValue2());
|
||||
for(VariableRef referencedVar : referencedVars) {
|
||||
final Variable variable = getScope().getVariable(referencedVar);
|
||||
if(variable.isKindLoadStore()) {
|
||||
// Convert the variable to versioned if it is load/store
|
||||
getLog().append("Converting unrolled condition variable to single-static-assignment "+variable);
|
||||
variable.setKind(Variable.Kind.PHI_MASTER);
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if (statement instanceof final StatementConditionalJump conditionalJump) {
|
||||
if (conditionalJump.isDeclaredUnroll()) {
|
||||
Collection<VariableRef> referencedVars = new LinkedHashSet<>();
|
||||
findAllReferencedVars(referencedVars, conditionalJump.getrValue1());
|
||||
findAllReferencedVars(referencedVars, conditionalJump.getrValue2());
|
||||
for (VariableRef referencedVar : referencedVars) {
|
||||
final Variable variable = getProgramScope().getVariable(referencedVar);
|
||||
if (variable.isKindLoadStore()) {
|
||||
// Convert the variable to versioned if it is load/store
|
||||
getLog().append(
|
||||
"Converting unrolled condition variable to single-static-assignment "
|
||||
+ variable);
|
||||
variable.setKind(Variable.Kind.PHI_MASTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ public class Pass1UnrollConditionVariableSsa extends Pass2SsaOptimization {
|
|||
for(VariableRef varRef : directReferenced) {
|
||||
if(varRef.isIntermediate()) {
|
||||
// Found an intermediate variable - recurse to the definition
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(varRef, getGraph(), getScope());
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(varRef, getGraph(), getProgramScope());
|
||||
for(VarAssignments.VarAssignment varAssignment : varAssignments) {
|
||||
if(VarAssignments.VarAssignment.Type.STATEMENT_LVALUE.equals(varAssignment.type)) {
|
||||
if(varAssignment.statementLValue instanceof StatementAssignment) {
|
||||
|
|
|
@ -24,7 +24,7 @@ public class Pass1UnwindBlockScopes extends Pass1Base {
|
|||
@Override
|
||||
public boolean step() {
|
||||
Map<SymbolRef, SymbolRef> unwoundSymbols = new LinkedHashMap<>();
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
for(Procedure procedure : getProgramScope().getAllProcedures(true)) {
|
||||
for(Scope subScope : procedure.getAllScopes(false)) {
|
||||
unwindSubScope(subScope, procedure, unwoundSymbols);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Initializers;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
@ -11,8 +9,10 @@ import dk.camelot64.kickc.model.symbols.Variable;
|
|||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import dk.camelot64.kickc.model.values.CastValue;
|
||||
import dk.camelot64.kickc.model.values.ConstantValue;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.ValueList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -28,38 +28,34 @@ public class Pass1UnwindStructPrepare extends Pass2SsaOptimization {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(assignment.getOperator()==null) {
|
||||
SymbolType lValueType = SymbolTypeInference.inferType(getProgram().getScope(), assignment.getlValue());
|
||||
RValue rValue = assignment.getrValue2();
|
||||
if(!(rValue instanceof ConstantValue) && lValueType instanceof SymbolTypeStruct) {
|
||||
// TODO: Constantify all R-Values?
|
||||
Initializers.ValueTypeSpec lValueTypeSpec = new Initializers.ValueTypeSpec(lValueType);
|
||||
RValue rValueConstantified = Initializers.constantify(rValue, lValueTypeSpec, getProgram(), assignment.getSource());
|
||||
if(!rValue.equals(rValueConstantified)) {
|
||||
assignment.setrValue2(rValueConstantified);
|
||||
getLog().append("Constantified RValue "+assignment.toString(getProgram(), false));
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementAssignment assignment) {
|
||||
if(assignment.getOperator()==null) {
|
||||
SymbolType lValueType = SymbolTypeInference.inferType(getProgram().getScope(), assignment.getlValue());
|
||||
RValue rValue = assignment.getrValue2();
|
||||
if(!(rValue instanceof ConstantValue) && lValueType instanceof SymbolTypeStruct) {
|
||||
// TODO: Constantify all R-Values?
|
||||
Initializers.ValueTypeSpec lValueTypeSpec = new Initializers.ValueTypeSpec(lValueType);
|
||||
RValue rValueConstantified = Initializers.constantify(rValue, lValueTypeSpec, getProgram(), assignment.getSource());
|
||||
if(!rValue.equals(rValueConstantified)) {
|
||||
assignment.setrValue2(rValueConstantified);
|
||||
getLog().append("Constantified RValue "+assignment.toString(getProgram(), false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if(statement instanceof StatementCall) {
|
||||
final StatementCall call = (StatementCall) statement;
|
||||
final Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
final List<Variable> paramDefs = procedure.getParameters();
|
||||
final List<RValue> paramVals = call.getParameters();
|
||||
for(int i=0;i<paramDefs.size();i++) {
|
||||
final Variable paramDef = paramDefs.get(i);
|
||||
final RValue paramVal = paramVals.get(i);
|
||||
if(paramDef.getType() instanceof SymbolTypeStruct && paramVal instanceof ValueList) {
|
||||
// Add a cast to the parameter value list
|
||||
paramVals.set(i, new CastValue(paramDef.getType(), paramVal));
|
||||
getLog().append("Added struct type cast to parameter value list "+call.toString(getProgram(), false));
|
||||
}
|
||||
}
|
||||
if(statement instanceof final StatementCall call) {
|
||||
final Procedure procedure = getProgramScope().getProcedure(call.getProcedure());
|
||||
final List<Variable> paramDefs = procedure.getParameters();
|
||||
final List<RValue> paramVals = call.getParameters();
|
||||
for(int i=0;i<paramDefs.size();i++) {
|
||||
final Variable paramDef = paramDefs.get(i);
|
||||
final RValue paramVal = paramVals.get(i);
|
||||
if(paramDef.getType() instanceof SymbolTypeStruct && paramVal instanceof ValueList) {
|
||||
// Add a cast to the parameter value list
|
||||
paramVals.set(i, new CastValue(paramDef.getType(), paramVal));
|
||||
getLog().append("Added struct type cast to parameter value list "+call.toString(getProgram(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
*/
|
||||
private boolean unwindStructReferences() {
|
||||
boolean modified = false;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
@ -72,10 +72,10 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
if(programValue.get() instanceof StructMemberRef) {
|
||||
StructMemberRef structMemberRef = (StructMemberRef) programValue.get();
|
||||
final ValueSource structValueSource = ValueSourceFactory.getValueSource(structMemberRef.getStruct(), getProgram(), getScope(), currentStmt, stmtIt, currentBlock);
|
||||
final ValueSource structValueSource = ValueSourceFactory.getValueSource(structMemberRef.getStruct(), getProgram(), getProgramScope(), currentStmt, stmtIt, currentBlock);
|
||||
if(structValueSource != null) {
|
||||
final ValueSource memberUnwinding = structValueSource.getMemberUnwinding(structMemberRef.getMemberName(), getProgram(), getScope(), currentStmt, stmtIt, currentBlock);
|
||||
RValue memberSimpleValue = memberUnwinding.getSimpleValue(getScope());
|
||||
final ValueSource memberUnwinding = structValueSource.getMemberUnwinding(structMemberRef.getMemberName(), getProgram(), getProgramScope(), currentStmt, stmtIt, currentBlock);
|
||||
RValue memberSimpleValue = memberUnwinding.getSimpleValue(getProgramScope());
|
||||
if(getLog().isVerboseStructUnwind())
|
||||
getLog().append("Replacing struct member reference " + structMemberRef.toString(getProgram()) + " with member unwinding reference " + memberSimpleValue.toString(getProgram()));
|
||||
programValue.set(memberSimpleValue);
|
||||
|
@ -91,8 +91,8 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
*
|
||||
* @param call The call to unwind
|
||||
*/
|
||||
private boolean unwindCall(StatementCall call, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
||||
final Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
private boolean unwindCall(StatementCall call, ListIterator<Statement> stmtIt, Graph.Block currentBlock) {
|
||||
final Procedure procedure = getProgramScope().getProcedure(call.getProcedure());
|
||||
|
||||
// Unwind struct value return value
|
||||
|
||||
|
@ -102,7 +102,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
if(procReturnVar != null && procReturnVar.isStructUnwind()) {
|
||||
if(call.getlValue() != null && !(call.getlValue() instanceof ValueList)) {
|
||||
// Return value already unwound - move on
|
||||
final ValueSource valueSource = ValueSourceFactory.getValueSource(call.getlValue(), getProgram(), getScope(), call, stmtIt, currentBlock);
|
||||
final ValueSource valueSource = ValueSourceFactory.getValueSource(call.getlValue(), getProgram(), getProgramScope(), call, stmtIt, currentBlock);
|
||||
RValue unwoundLValue = unwindValue(valueSource, call, stmtIt, currentBlock);
|
||||
if(call.getlValue().equals(unwoundLValue))
|
||||
throw new CompileError("Call return value already unwound", call);
|
||||
|
@ -128,12 +128,12 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
final SymbolVariableRef unwindingMaster = getProgram().getStructVariableMemberUnwinding().getUnwindingMaster(procParameter.getRef());
|
||||
if(unwindingMaster != null) {
|
||||
// The procedure parameter is unwound
|
||||
final ValueSource parameterSource = ValueSourceFactory.getValueSource(callParameter, getProgram(), getScope(), call, stmtIt, currentBlock);
|
||||
final ValueSource parameterSource = ValueSourceFactory.getValueSource(callParameter, getProgram(), getProgramScope(), call, stmtIt, currentBlock);
|
||||
if(parameterSource != null && parameterSource.isUnwindable())
|
||||
// Passing an unwinding struct value
|
||||
for(String memberName : parameterSource.getMemberNames(getScope())) {
|
||||
ValueSource memberUnwinding = parameterSource.getMemberUnwinding(memberName, getProgram(), getScope(), call, stmtIt, currentBlock);
|
||||
unwoundParameters.add(memberUnwinding.getSimpleValue(getScope()));
|
||||
for(String memberName : parameterSource.getMemberNames(getProgramScope())) {
|
||||
ValueSource memberUnwinding = parameterSource.getMemberUnwinding(memberName, getProgram(), getProgramScope(), call, stmtIt, currentBlock);
|
||||
unwoundParameters.add(memberUnwinding.getSimpleValue(getProgramScope()));
|
||||
unwound = true;
|
||||
anyParameterUnwound = true;
|
||||
idx_proc++;
|
||||
|
@ -166,15 +166,15 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
* @param currentBlock current block
|
||||
* @return The unwound ValueList. null if the value is not unwindable.
|
||||
*/
|
||||
private RValue unwindValue(ValueSource lValueSource, Statement statement, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
||||
private RValue unwindValue(ValueSource lValueSource, Statement statement, ListIterator<Statement> stmtIt, Graph.Block currentBlock) {
|
||||
if(lValueSource == null) {
|
||||
return null;
|
||||
} else if(lValueSource.isSimple()) {
|
||||
return lValueSource.getSimpleValue(getScope());
|
||||
return lValueSource.getSimpleValue(getProgramScope());
|
||||
} else if(lValueSource.isUnwindable()) {
|
||||
ArrayList<RValue> unwoundMembers = new ArrayList<>();
|
||||
for(String memberName : lValueSource.getMemberNames(getScope())) {
|
||||
ValueSource memberUnwinding = lValueSource.getMemberUnwinding(memberName, getProgram(), getScope(), statement, stmtIt, currentBlock);
|
||||
for(String memberName : lValueSource.getMemberNames(getProgramScope())) {
|
||||
ValueSource memberUnwinding = lValueSource.getMemberUnwinding(memberName, getProgram(), getProgramScope(), statement, stmtIt, currentBlock);
|
||||
unwoundMembers.add(unwindValue(memberUnwinding, statement, stmtIt, currentBlock));
|
||||
}
|
||||
return new ValueList(unwoundMembers);
|
||||
|
@ -189,15 +189,15 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
* @param statementReturn The return to unwind
|
||||
*/
|
||||
|
||||
private boolean unwindReturn(StatementReturn statementReturn, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
||||
private boolean unwindReturn(StatementReturn statementReturn, ListIterator<Statement> stmtIt, Graph.Block currentBlock) {
|
||||
final RValue returnValue = statementReturn.getValue();
|
||||
if(returnValue == null)
|
||||
return false;
|
||||
if(returnValue instanceof SymbolVariableRef)
|
||||
if(getScope().getVar((SymbolVariableRef) returnValue).isStructClassic())
|
||||
if(getProgramScope().getVar((SymbolVariableRef) returnValue).isStructClassic())
|
||||
return false;
|
||||
boolean unwound = false;
|
||||
final ValueSource valueSource = ValueSourceFactory.getValueSource(returnValue, getProgram(), getScope(), statementReturn, stmtIt, currentBlock);
|
||||
final ValueSource valueSource = ValueSourceFactory.getValueSource(returnValue, getProgram(), getProgramScope(), statementReturn, stmtIt, currentBlock);
|
||||
RValue unwoundValue = unwindValue(valueSource, statementReturn, stmtIt, currentBlock);
|
||||
if(unwoundValue != null && !returnValue.equals(unwoundValue)) {
|
||||
statementReturn.setValue(unwoundValue);
|
||||
|
@ -214,7 +214,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
private boolean unwindStructParameters() {
|
||||
boolean modified = false;
|
||||
// Iterate through all procedures changing parameter lists by unwinding each struct value parameter
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
for(Procedure procedure : getProgramScope().getAllProcedures(true)) {
|
||||
ArrayList<String> unwoundParameterNames = new ArrayList<>();
|
||||
boolean procedureUnwound = false;
|
||||
for(Variable parameter : procedure.getParameters()) {
|
||||
|
@ -247,7 +247,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
* @param stmtIt The statement iterator used for adding/removing statements
|
||||
* @param currentBlock The current code block
|
||||
*/
|
||||
public static boolean unwindAssignment(StatementAssignment assignment, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Program program) {
|
||||
public static boolean unwindAssignment(StatementAssignment assignment, ListIterator<Statement> stmtIt, Graph.Block currentBlock, Program program) {
|
||||
LValue lValue = assignment.getlValue();
|
||||
SymbolType lValueType = SymbolTypeInference.inferType(program.getScope(), lValue);
|
||||
|
||||
|
@ -279,7 +279,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static boolean copyValues(ValueSource lValueSource, ValueSource rValueSource, List<RValue> lValueUnwoundList, boolean initialAssignment, Statement currentStmt, ControlFlowBlock currentBlock, ListIterator<Statement> stmtIt, Program program) {
|
||||
public static boolean copyValues(ValueSource lValueSource, ValueSource rValueSource, List<RValue> lValueUnwoundList, boolean initialAssignment, Statement currentStmt, Graph.Block currentBlock, ListIterator<Statement> stmtIt, Program program) {
|
||||
if(lValueSource == null || rValueSource == null)
|
||||
return false;
|
||||
if(rValueSource instanceof ValueSourceParamValue && lValueSource.equals(((ValueSourceParamValue) rValueSource).getValueSource()))
|
||||
|
|
|
@ -35,7 +35,7 @@ public class Pass1UnwindStructVariables extends Pass1Base {
|
|||
private boolean unwindStructVariables() {
|
||||
boolean modified = false;
|
||||
// Iterate through all scopes generating member-variables for each struct
|
||||
for(Variable variable : getScope().getAllVariables(true)) {
|
||||
for(Variable variable : getProgramScope().getAllVariables(true)) {
|
||||
if(variable.isStructUnwind()) {
|
||||
StructVariableMemberUnwinding structVariableMemberUnwinding = getProgram().getStructVariableMemberUnwinding();
|
||||
if(structVariableMemberUnwinding.getVariableUnwinding(variable.getRef()) == null) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
|
@ -29,11 +30,11 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
|||
|
||||
fixAliasSources(aliases);
|
||||
removeAliasAssignments(aliases);
|
||||
replaceVariables(aliases.getReplacements(getScope()));
|
||||
replaceVariables(aliases.getReplacements(getProgramScope()));
|
||||
for(AliasSet aliasSet : aliases.getAliasSets()) {
|
||||
getLog().append("Alias " + aliasSet.toString(getProgram()));
|
||||
}
|
||||
deleteSymbols(getScope(), aliases.getSymbolsToRemove(getScope()));
|
||||
deleteSymbols(getProgramScope(), aliases.getSymbolsToRemove(getProgramScope()));
|
||||
return (aliases.size() > 0);
|
||||
}
|
||||
|
||||
|
@ -51,7 +52,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
|||
while(aliasSetListIterator.hasNext()) {
|
||||
AliasSet aliasSet = aliasSetListIterator.next();
|
||||
boolean removeSet = false;
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(var block : program.getGraph().getAllBlocks()) {
|
||||
if(block.hasPhiBlock()) {
|
||||
StatementPhiBlock phi = block.getPhiBlock();
|
||||
boolean lMatch = false;
|
||||
|
@ -119,7 +120,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
|||
*/
|
||||
private static Aliases findAliasesCandidates(final Program program) {
|
||||
Aliases aliases = new Aliases();
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(var block : program.getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
|
@ -247,7 +248,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
|||
StatementSource bestSource = null;
|
||||
List<Statement> assignments = new ArrayList<>();
|
||||
for(VariableRef aliasVar : aliasSet.getVars()) {
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(aliasVar, getGraph(), getScope());
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(aliasVar, getGraph(), getProgramScope());
|
||||
if(varAssignments.size()!=1)
|
||||
continue;
|
||||
final VarAssignments.VarAssignment varAssignment = varAssignments.get(0);
|
||||
|
@ -286,7 +287,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
|||
* @param aliases The aliases
|
||||
*/
|
||||
private void removeAliasAssignments(Aliases aliases) {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
for(Iterator<Statement> iterator = block.getStatements().iterator(); iterator.hasNext(); ) {
|
||||
Statement statement = iterator.next();
|
||||
if(statement instanceof StatementAssignment) {
|
||||
|
|
|
@ -24,21 +24,21 @@ public class Pass2AssertBlocks extends Pass2SsaAssertion {
|
|||
blockReferenceFinder.visitGraph(getGraph());
|
||||
|
||||
Set<LabelRef> seenBlocks = blockReferenceFinder.getSeenBlocks();
|
||||
Collection<ControlFlowBlock> allBlocks = getGraph().getAllBlocks();
|
||||
Collection<Graph.Block> allBlocks = getGraph().getAllBlocks();
|
||||
for(LabelRef seenBlock : seenBlocks) {
|
||||
ControlFlowBlock block = getGraph().getBlock(seenBlock);
|
||||
Graph.Block block = getGraph().getBlock(seenBlock);
|
||||
if(!allBlocks.contains(block)) {
|
||||
throw new AssertionFailed("Compilation Process Error! A block in the program is not contained in the allBocks list (probably a block sequence problem). " + seenBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class BlockReferenceChecker extends ControlFlowGraphBaseVisitor<Void> {
|
||||
private static class BlockReferenceChecker extends GraphBaseVisitor<Void> {
|
||||
|
||||
Set<LabelRef> seenBlocks;
|
||||
private ControlFlowGraph graph;
|
||||
private Graph graph;
|
||||
|
||||
public BlockReferenceChecker(ControlFlowGraph graph) {
|
||||
public BlockReferenceChecker(Graph graph) {
|
||||
this.graph = graph;
|
||||
this.seenBlocks = new HashSet<>();
|
||||
}
|
||||
|
@ -55,14 +55,14 @@ public class Pass2AssertBlocks extends Pass2SsaAssertion {
|
|||
return;
|
||||
}
|
||||
seenBlocks.add(blockLabel);
|
||||
ControlFlowBlock block = graph.getBlock(blockLabel);
|
||||
Graph.Block block = graph.getBlock(blockLabel);
|
||||
if(block == null) {
|
||||
throw new AssertionFailed("Compilation Process Error! Block referenced, but not found in program. " + blockLabel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitBlock(ControlFlowBlock block) {
|
||||
public Void visitBlock(Graph.Block block) {
|
||||
assertBlock(block.getDefaultSuccessor());
|
||||
assertBlock(block.getCallSuccessor());
|
||||
assertBlock(block.getConditionalSuccessor());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
@ -15,7 +15,7 @@ public class Pass2AssertNoCallLvalues extends Pass2SsaAssertion {
|
|||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
|
||||
ControlFlowGraphBaseVisitor<Void> checkCalls = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> checkCalls = new GraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitCall(StatementCall call) {
|
||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
@ -17,7 +17,7 @@ public class Pass2AssertNoCallParameters extends Pass2SsaAssertion {
|
|||
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
ControlFlowGraphBaseVisitor<Void> checkCalls = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> checkCalls = new GraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitCall(StatementCall call) {
|
||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementLabel;
|
||||
|
||||
|
@ -14,7 +14,7 @@ public class Pass2AssertNoLabels extends Pass2SsaAssertion {
|
|||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
|
||||
ControlFlowGraphBaseVisitor<Void> checkCalls = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> checkCalls = new GraphBaseVisitor<Void>() {
|
||||
|
||||
@Override
|
||||
public Void visitJumpTarget(StatementLabel jumpTarget) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementProcedureBegin;
|
||||
import dk.camelot64.kickc.model.statements.StatementProcedureEnd;
|
||||
|
@ -15,7 +15,7 @@ public class Pass2AssertNoProcs extends Pass2SsaAssertion {
|
|||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
|
||||
ControlFlowGraphBaseVisitor<Void> checkCalls = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> checkCalls = new GraphBaseVisitor<Void>() {
|
||||
|
||||
@Override
|
||||
public Void visitProcedureBegin(StatementProcedureBegin procedureBegin) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementReturn;
|
||||
|
@ -17,7 +18,7 @@ public class Pass2AssertNoReturnValues extends Pass2SsaAssertion {
|
|||
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ScopeRef blockScopeRef = block.getScope();
|
||||
Scope scope = getScope().getScope(blockScopeRef);
|
||||
if(scope instanceof Procedure) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
|
@ -18,12 +19,12 @@ public class Pass2AssertPhiPredecessors extends Pass2SsaAssertion {
|
|||
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
if(block.hasPhiBlock()) {
|
||||
StatementPhiBlock phiBlock = block.getPhiBlock();
|
||||
List<ControlFlowBlock> phiPredecessors = Pass1GenerateSingleStaticAssignmentForm.getPhiPredecessors(block, getProgram());
|
||||
List<Graph.Block> phiPredecessors = Pass1GenerateSingleStaticAssignmentForm.getPhiPredecessors(block, getProgram());
|
||||
List<LabelRef> predecessors =
|
||||
phiPredecessors.stream().map(ControlFlowBlock::getLabel).collect(Collectors.toList());
|
||||
phiPredecessors.stream().map(Graph.Block::getLabel).toList();
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if(!predecessors.contains(phiRValue.getPredecessor())) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementLValue;
|
||||
|
@ -23,17 +24,15 @@ public class Pass2AssertSingleAssignment extends Pass2SsaAssertion {
|
|||
|
||||
Map<VariableRef, Statement> assignments = new LinkedHashMap<>();
|
||||
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementLValue) {
|
||||
LValue lValue = ((StatementLValue) statement).getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
checkAssignment(assignments, (VariableRef) lValue, statement);
|
||||
}
|
||||
} else if(statement instanceof StatementPhiBlock) {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
|
||||
checkAssignment(assignments, phiVariable.getVariable(), statement);
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if (statement instanceof StatementLValue) {
|
||||
LValue lValue = ((StatementLValue) statement).getlValue();
|
||||
if (lValue instanceof VariableRef) {
|
||||
checkAssignment(assignments, (VariableRef) lValue, statement);
|
||||
}
|
||||
} else if (statement instanceof StatementPhiBlock) {
|
||||
for (StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
|
||||
checkAssignment(assignments, phiVariable.getVariable(), statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.model.ControlFlowGraph;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
||||
|
||||
|
@ -18,10 +19,6 @@ public class Pass2Base {
|
|||
return program.getLog();
|
||||
}
|
||||
|
||||
public ControlFlowGraph getGraph() {
|
||||
return program.getGraph();
|
||||
}
|
||||
|
||||
public ProgramScope getSymbols() {
|
||||
return program.getScope();
|
||||
}
|
||||
|
@ -30,4 +27,6 @@ public class Pass2Base {
|
|||
return program;
|
||||
}
|
||||
|
||||
public Graph getGraph() { return program.getGraph(); }
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.ConstantNotLiteral;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.Operator;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
|
@ -34,39 +35,37 @@ public class Pass2ComparisonOptimization extends Pass2SsaOptimization {
|
|||
*/
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump conditionalJump = (StatementConditionalJump) statement;
|
||||
Operator operator = conditionalJump.getOperator();
|
||||
if(operator!=null && conditionalJump.getrValue2() instanceof ConstantValue) {
|
||||
SymbolType valueType = SymbolTypeInference.inferType(getScope(), conditionalJump.getrValue1());
|
||||
ConstantValue constantValue = (ConstantValue) conditionalJump.getrValue2();
|
||||
ConstantLiteral constantLiteral = null;
|
||||
try {
|
||||
constantLiteral = constantValue.calculateLiteral(getScope());
|
||||
} catch(ConstantNotLiteral e) {
|
||||
// Ignore
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump conditionalJump = (StatementConditionalJump) statement;
|
||||
Operator operator = conditionalJump.getOperator();
|
||||
if(operator!=null && conditionalJump.getrValue2() instanceof ConstantValue) {
|
||||
SymbolType valueType = SymbolTypeInference.inferType(getProgramScope(), conditionalJump.getrValue1());
|
||||
ConstantValue constantValue = (ConstantValue) conditionalJump.getrValue2();
|
||||
ConstantLiteral constantLiteral = null;
|
||||
try {
|
||||
constantLiteral = constantValue.calculateLiteral(getProgramScope());
|
||||
} catch(ConstantNotLiteral e) {
|
||||
// Ignore
|
||||
}
|
||||
if(Operators.GT.equals(operator) && valueType instanceof SymbolTypeIntegerFixed && constantLiteral instanceof ConstantInteger) {
|
||||
// Found > C - rewrite to >= C+1 if possible
|
||||
Long longValue = (Long) constantLiteral.getValue();
|
||||
if(longValue > 0x00L && longValue < 0xffL) {
|
||||
// Rewrite is possible - do it
|
||||
getLog().append("Rewriting conditional comparison " + statement.toString(getProgram(), false));
|
||||
conditionalJump.setOperator(Operators.GE);
|
||||
conditionalJump.setrValue2(new ConstantBinary(constantValue, Operators.PLUS, new ConstantInteger(1L)));
|
||||
}
|
||||
if(Operators.GT.equals(operator) && valueType instanceof SymbolTypeIntegerFixed && constantLiteral instanceof ConstantInteger) {
|
||||
// Found > C - rewrite to >= C+1 if possible
|
||||
Long longValue = (Long) constantLiteral.getValue();
|
||||
if(longValue > 0x00L && longValue < 0xffL) {
|
||||
// Rewrite is possible - do it
|
||||
getLog().append("Rewriting conditional comparison " + statement.toString(getProgram(), false));
|
||||
conditionalJump.setOperator(Operators.GE);
|
||||
conditionalJump.setrValue2(new ConstantBinary(constantValue, Operators.PLUS, new ConstantInteger(1L)));
|
||||
}
|
||||
}
|
||||
if(Operators.LE.equals(operator) && valueType instanceof SymbolTypeIntegerFixed && constantLiteral instanceof ConstantInteger) {
|
||||
// Found <= C - rewrite to < C+1 if possible
|
||||
Long longValue = (Long) constantLiteral.getValue();
|
||||
if(longValue > 0x00L && longValue < 0xffL) {
|
||||
// Rewrite is possible - do it
|
||||
getLog().append("Rewriting conditional comparison " + statement.toString(getProgram(), false));
|
||||
conditionalJump.setOperator(Operators.LT);
|
||||
conditionalJump.setrValue2(new ConstantBinary(constantValue, Operators.PLUS, new ConstantInteger(1L)));
|
||||
}
|
||||
}
|
||||
if(Operators.LE.equals(operator) && valueType instanceof SymbolTypeIntegerFixed && constantLiteral instanceof ConstantInteger) {
|
||||
// Found <= C - rewrite to < C+1 if possible
|
||||
Long longValue = (Long) constantLiteral.getValue();
|
||||
if(longValue > 0x00L && longValue < 0xffL) {
|
||||
// Rewrite is possible - do it
|
||||
getLog().append("Rewriting conditional comparison " + statement.toString(getProgram(), false));
|
||||
conditionalJump.setOperator(Operators.LT);
|
||||
conditionalJump.setrValue2(new ConstantBinary(constantValue, Operators.PLUS, new ConstantInteger(1L)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
|
@ -31,15 +28,23 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
boolean modified = false;
|
||||
for(ProcedureCompilation procedureCompilation : getProgram().getProcedureCompilations()) {
|
||||
modified |= findAndRewriteBooleanConditions(procedureCompilation.getGraph());
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
private boolean findAndRewriteBooleanConditions(Graph graph) {
|
||||
boolean done = false;
|
||||
boolean modified = false;
|
||||
while(!done) {
|
||||
VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition();
|
||||
VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition(graph);
|
||||
if(obsoleteConditionVar != null) {
|
||||
Collection<VariableRef> obsoleteVars = new ArrayList<>();
|
||||
obsoleteVars.add(obsoleteConditionVar);
|
||||
removeAssignments(getGraph(), obsoleteVars);
|
||||
deleteSymbols(getScope(), obsoleteVars);
|
||||
removeAssignments(graph, obsoleteVars);
|
||||
deleteSymbols(getProgramScope(), obsoleteVars);
|
||||
modified = true;
|
||||
} else {
|
||||
done = true;
|
||||
|
@ -49,17 +54,17 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
/**
|
||||
* Look through the entire program looking for an if() condition that uses &&, || or !.
|
||||
* Look through a control flow graph looking for an if() condition that uses &&, || or !.
|
||||
* When found rewrite it (adding blocks)
|
||||
*
|
||||
* @return Null if no condition was found to rewrite. The now obsolete variable containing the && / || / ! to be removed.
|
||||
* @param graph The control flow graph to modify
|
||||
*/
|
||||
private VariableRef findAndRewriteBooleanCondition() {
|
||||
private VariableRef findAndRewriteBooleanCondition(Graph graph) {
|
||||
final VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : graph.getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump conditional = (StatementConditionalJump) statement;
|
||||
if(statement instanceof StatementConditionalJump conditional) {
|
||||
if(conditional.getrValue1() == null && conditional.getOperator() == null) {
|
||||
RValue conditionRValue = conditional.getrValue2();
|
||||
if(conditionRValue instanceof VariableRef) {
|
||||
|
@ -68,16 +73,15 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
VariableRef conditionVar = (VariableRef) conditionRValue;
|
||||
final Integer conditionDefineStatementIdx = variableReferenceInfos.getVarDefineStatement(conditionVar);
|
||||
if(conditionDefineStatementIdx != null) {
|
||||
final Statement conditionDefineStatement = getGraph().getStatementByIndex(conditionDefineStatementIdx);
|
||||
if(conditionDefineStatement instanceof StatementAssignment) {
|
||||
StatementAssignment conditionAssignment = (StatementAssignment) conditionDefineStatement;
|
||||
final Statement conditionDefineStatement = graph.getStatementByIndex(conditionDefineStatementIdx);
|
||||
if(conditionDefineStatement instanceof StatementAssignment conditionAssignment) {
|
||||
if(Operators.LOGIC_AND.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical && condition - rewrite to if(c1) if(c2) { xx }
|
||||
rewriteLogicAnd(block, conditional, conditionAssignment);
|
||||
rewriteLogicAnd(block, conditional, conditionAssignment, graph);
|
||||
return conditionVar;
|
||||
} else if(Operators.LOGIC_OR.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical || condition - rewrite to if(c1) goto x else if(c2) goto x else goto end, x:{ xx } end:
|
||||
rewriteLogicOr(block, conditional, conditionAssignment);
|
||||
rewriteLogicOr(block, conditional, conditionAssignment, graph);
|
||||
return conditionVar;
|
||||
} else if(Operators.LOGIC_NOT.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical ! condition - rewrite to if(!c1) goto x else goto end, x:{ xx } end:
|
||||
|
@ -101,16 +105,17 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
* @param block The block containing the current if()
|
||||
* @param conditional The if()-statement
|
||||
* @param conditionAssignment The assignment defining the condition variable.
|
||||
* @param graph The control flow graph to modify
|
||||
*/
|
||||
private void rewriteLogicAnd(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
private void rewriteLogicAnd(Graph.Block block, StatementConditionalJump conditional, StatementAssignment conditionAssignment, Graph graph) {
|
||||
// Found an if with a logical && condition - rewrite to if(c1) if(c2) { xx }
|
||||
getLog().append("Rewriting && if()-condition to two if()s " + conditionAssignment.toString(getProgram(), false));
|
||||
ScopeRef currentScopeRef = block.getScope();
|
||||
Scope currentScope = getScope().getScope(currentScopeRef);
|
||||
Scope currentScope = getProgramScope().getScope(currentScopeRef);
|
||||
// Add a new block containing the second part of the && condition expression
|
||||
Label newBlockLabel = currentScope.addLabelIntermediate();
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
|
||||
getGraph().addBlock(newBlock);
|
||||
graph.addBlock(newBlock);
|
||||
LabelRef destLabel = conditional.getDestination();
|
||||
StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), destLabel, conditional.getSource(), Comment.NO_COMMENTS);
|
||||
newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll());
|
||||
|
@ -123,7 +128,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
conditional.setrValue2(conditionAssignment.getrValue1());
|
||||
|
||||
// Replace the phi labels inside the destination block with the new block
|
||||
ControlFlowBlock destBlock = getGraph().getBlock(destLabel);
|
||||
Graph.Block destBlock = graph.getBlock(destLabel);
|
||||
LinkedHashMap<LabelRef, LabelRef> replacements = new LinkedHashMap<>();
|
||||
replacements.put(block.getLabel(), newBlockLabel.getRef());
|
||||
replaceLabels(destBlock.getPhiBlock(), replacements);
|
||||
|
@ -136,15 +141,16 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
* @param block The block containing the current if()
|
||||
* @param conditional The if()-statement
|
||||
* @param conditionAssignment The assignment defining the condition variable.
|
||||
* @param graph The control flow graph to modify
|
||||
*/
|
||||
private void rewriteLogicOr(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
private void rewriteLogicOr(Graph.Block block, StatementConditionalJump conditional, StatementAssignment conditionAssignment, Graph graph) {
|
||||
getLog().append("Rewriting || if()-condition to two if()s " + conditionAssignment.toString(getProgram(), false));
|
||||
ScopeRef currentScopeRef = block.getScope();
|
||||
Scope currentScope = getScope().getScope(currentScopeRef);
|
||||
Scope currentScope = getProgramScope().getScope(currentScopeRef);
|
||||
// Add a new block containing the second part of the && condition expression
|
||||
Label newBlockLabel = currentScope.addLabelIntermediate();
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
|
||||
getGraph().addBlock(newBlock);
|
||||
graph.addBlock(newBlock);
|
||||
StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), conditional.getDestination(), conditional.getSource(), Comment.NO_COMMENTS);
|
||||
// Copy unrolling to the new conditional
|
||||
newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll());
|
||||
|
@ -158,7 +164,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
conditional.setDeclaredUnroll(false);
|
||||
|
||||
// Update the default destination PHI block to reflect the last of the conditions
|
||||
ControlFlowBlock defaultDestBlock = getGraph().getBlock(newBlock.getDefaultSuccessor());
|
||||
Graph.Block defaultDestBlock = graph.getBlock(newBlock.getDefaultSuccessor());
|
||||
if(defaultDestBlock.hasPhiBlock()) {
|
||||
StatementPhiBlock defaultDestPhiBlock = defaultDestBlock.getPhiBlock();
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : defaultDestPhiBlock.getPhiVariables()) {
|
||||
|
@ -171,13 +177,13 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
}
|
||||
}
|
||||
|
||||
ControlFlowBlock conditionalDestBlock = getGraph().getBlock(conditional.getDestination());
|
||||
Graph.Block conditionalDestBlock = graph.getBlock(conditional.getDestination());
|
||||
if(conditionalDestBlock.hasPhiBlock()) {
|
||||
StatementPhiBlock conditionalDestPhiBlock = conditionalDestBlock.getPhiBlock();
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : conditionalDestPhiBlock.getPhiVariables()) {
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if(phiRValue.getPredecessor().equals(block.getLabel())) {
|
||||
// Found phi-variable with current block as predecessor - copy the phivalue for the new block
|
||||
// Found phi-variable with current block as predecessor - copy the phi-value for the new block
|
||||
phiVariable.setrValue(newBlockLabel.getRef(), phiRValue.getrValue());
|
||||
break;
|
||||
}
|
||||
|
@ -194,7 +200,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
|||
* @param conditional The if()-statement
|
||||
* @param conditionAssignment The assignment defining the condition variable.
|
||||
*/
|
||||
private void rewriteLogicNot(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
private void rewriteLogicNot(Graph.Block block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
getLog().append("Rewriting ! if()-condition to reversed if() " + conditionAssignment.toString(getProgram(), false));
|
||||
// Rewrite the conditional to use only the first part of the && condition expression
|
||||
LabelRef defaultSuccessor = block.getDefaultSuccessor();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.Operator;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
|
@ -19,9 +20,9 @@ public class Pass2ConditionalJumpSequenceImprovement extends Pass2SsaOptimizatio
|
|||
@Override
|
||||
public boolean step() {
|
||||
boolean modified = false;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
ControlFlowBlock conditionalSuccessor = getGraph().getConditionalSuccessor(block);
|
||||
ControlFlowBlock defaultSuccessor = getGraph().getDefaultSuccessor(block);
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
Graph.Block conditionalSuccessor = getGraph().getConditionalSuccessor(block);
|
||||
Graph.Block defaultSuccessor = getGraph().getDefaultSuccessor(block);
|
||||
if(conditionalSuccessor != null && defaultSuccessor != null) {
|
||||
if(conditionalSuccessor.getDefaultSuccessor().equals(defaultSuccessor.getLabel())) {
|
||||
if(conditionalSuccessor.equals(block)) continue;
|
||||
|
@ -35,7 +36,7 @@ public class Pass2ConditionalJumpSequenceImprovement extends Pass2SsaOptimizatio
|
|||
return modified;
|
||||
}
|
||||
|
||||
private boolean negateCondition(ControlFlowBlock block) {
|
||||
private boolean negateCondition(Graph.Block block) {
|
||||
LabelRef defaultSuccessor = block.getDefaultSuccessor();
|
||||
LabelRef conditionalSuccessor = block.getConditionalSuccessor();
|
||||
for(Statement statement : block.getStatements()) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import dk.camelot64.kickc.model.values.SymbolRef;
|
|||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
import dk.camelot64.kickc.passes.utils.AliasReplacer;
|
||||
|
||||
import dk.camelot64.kickc.passes.utils.StatementsBetween;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -40,7 +41,7 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
|
|||
simpleConditionVars.add(simpleCondition.conditionVar);
|
||||
}
|
||||
removeAssignments(getGraph(), simpleConditionVars);
|
||||
deleteSymbols(getScope(), simpleConditionVars);
|
||||
deleteSymbols(getProgramScope(), simpleConditionVars);
|
||||
return (simpleConditionVars.size() > 0);
|
||||
}
|
||||
|
||||
|
@ -65,33 +66,29 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
|
|||
private List<SimpleCondition> getSimpleConditionTodos() {
|
||||
final VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos();
|
||||
List<SimpleCondition> todos = new ArrayList<>();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump conditionalJump = (StatementConditionalJump) statement;
|
||||
if(conditionalJump.getrValue1() == null && conditionalJump.getOperator() == null) {
|
||||
RValue conditionRValue = conditionalJump.getrValue2();
|
||||
if(conditionRValue instanceof VariableRef) {
|
||||
VariableRef conditionVar = (VariableRef) conditionRValue;
|
||||
final Collection<Integer> conditionRvalueUsages = variableReferenceInfos.getVarUseStatements(conditionVar);
|
||||
final Integer conditionDefineStmtIdx = variableReferenceInfos.getVarDefineStatement(conditionVar);
|
||||
if(conditionRvalueUsages.size() == 1 && conditionDefineStmtIdx != null) {
|
||||
final Statement conditionDefineStmt = getGraph().getStatementByIndex(conditionDefineStmtIdx);
|
||||
if(conditionDefineStmt instanceof StatementAssignment && ((StatementAssignment) conditionDefineStmt).getOperator() != null) {
|
||||
StatementAssignment conditionAssignment = (StatementAssignment) conditionDefineStmt;
|
||||
switch(conditionAssignment.getOperator().getOperator()) {
|
||||
case "==":
|
||||
case "<>":
|
||||
case "!=":
|
||||
case "<":
|
||||
case ">":
|
||||
case "<=":
|
||||
case "=<":
|
||||
case ">=":
|
||||
case "=>":
|
||||
todos.add(new SimpleCondition(conditionalJump, conditionAssignment, conditionVar));
|
||||
default:
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementConditionalJump conditionalJump) {
|
||||
if(conditionalJump.getrValue1() == null && conditionalJump.getOperator() == null) {
|
||||
RValue conditionRValue = conditionalJump.getrValue2();
|
||||
if(conditionRValue instanceof VariableRef conditionVar) {
|
||||
final Collection<Integer> conditionRvalueUsages = variableReferenceInfos.getVarUseStatements(conditionVar);
|
||||
final Integer conditionDefineStmtIdx = variableReferenceInfos.getVarDefineStatement(conditionVar);
|
||||
if(conditionRvalueUsages.size() == 1 && conditionDefineStmtIdx != null) {
|
||||
final Statement conditionDefineStmt = getGraph().getStatementByIndex(conditionDefineStmtIdx);
|
||||
if(conditionDefineStmt instanceof StatementAssignment conditionAssignment
|
||||
&& ((StatementAssignment) conditionDefineStmt).getOperator() != null) {
|
||||
switch(conditionAssignment.getOperator().getOperator()) {
|
||||
case "==":
|
||||
case "<>":
|
||||
case "!=":
|
||||
case "<":
|
||||
case ">":
|
||||
case "<=":
|
||||
case "=<":
|
||||
case ">=":
|
||||
case "=>":
|
||||
todos.add(new SimpleCondition(conditionalJump, conditionAssignment, conditionVar));
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,16 +117,16 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
|
|||
// Found referenced load/store variables
|
||||
// Examine all statements between the conditionAssignment and conditionalJump for modifications
|
||||
final StatementInfos statementInfos = getProgram().getStatementInfos();
|
||||
Collection<Statement> statementsBetween = getGraph().getStatementsBetween(simpleCondition.conditionAssignment, simpleCondition.conditionalJump, statementInfos);
|
||||
final Graph.Block conditionDefineBlock = statementInfos.getBlock(simpleCondition.conditionAssignment);
|
||||
Collection<Statement> statementsBetween = StatementsBetween.find(simpleCondition.conditionAssignment, conditionDefineBlock, simpleCondition.conditionalJump, getGraph());
|
||||
for(Statement statementBetween : statementsBetween) {
|
||||
for(Variable referencedLoadStoreVariable : referencedLoadStoreVariables) {
|
||||
if(variableReferenceInfos.getDefinedVars(statementBetween).contains(referencedLoadStoreVariable.getVariableRef())) {
|
||||
// A referenced load/store-variable is modified in a statement between the assignment and the condition!
|
||||
getLog().append("Condition not simple " + simpleCondition.conditionVar.toString(getProgram()) + " " + simpleCondition.conditionalJump.toString(getProgram(), false));
|
||||
// Create an intermediate variable copy of the load/store-variable at the position of the condition-variable to preserve the value
|
||||
final ControlFlowBlock conditionDefineBlock = statementInfos.getBlock(simpleCondition.conditionAssignment);
|
||||
final ScopeRef conditionDefineScopeRef = conditionDefineBlock.getScope();
|
||||
final Scope conditionDefineScope = getScope().getScope(conditionDefineScopeRef);
|
||||
final Scope conditionDefineScope = getProgramScope().getScope(conditionDefineScopeRef);
|
||||
SymbolType typeQualified = referencedLoadStoreVariable.getType().getQualified(false, referencedLoadStoreVariable.getType().isNomodify());
|
||||
final Variable intermediateLoadStoreVar = VariableBuilder.createIntermediate(conditionDefineScope, typeQualified, getProgram());
|
||||
final StatementAssignment intermediateLoadStoreAssignment = new StatementAssignment(intermediateLoadStoreVar.getVariableRef(), referencedLoadStoreVariable.getRef(), true, simpleCondition.conditionAssignment.getSource(), Comment.NO_COMMENTS);
|
||||
|
@ -168,7 +165,7 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
|
|||
private Collection<Variable> getReferencedLoadStoreVariables(RValue rValue) {
|
||||
return VariableReferenceInfos.getReferencedVars(rValue)
|
||||
.stream()
|
||||
.map(variableRef -> getScope().getVariable(variableRef))
|
||||
.map(variableRef -> getProgramScope().getVariable(variableRef))
|
||||
.filter(Variable::isKindLoadStore)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
|
|
@ -55,20 +55,18 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
|||
});
|
||||
|
||||
// Examine all assignments - performing constant consolidation for +/-
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
Operator operator = assignment.getOperator();
|
||||
if(operator != null) {
|
||||
switch(operator.getOperator()) {
|
||||
case "+":
|
||||
optimized[0] |= optimizePlus(assignment);
|
||||
break;
|
||||
case "*idx":
|
||||
optimized[0] |= optimizeArrayDeref(assignment);
|
||||
break;
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
Operator operator = assignment.getOperator();
|
||||
if(operator != null) {
|
||||
switch(operator.getOperator()) {
|
||||
case "+":
|
||||
optimized[0] |= optimizePlus(assignment);
|
||||
break;
|
||||
case "*idx":
|
||||
optimized[0] |= optimizeArrayDeref(assignment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +142,7 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
|||
} else {
|
||||
// Check if the constant is zero
|
||||
try {
|
||||
ConstantLiteral constantLiteral = ((ConstantValue) assignment.getrValue1()).calculateLiteral(getScope());
|
||||
ConstantLiteral constantLiteral = ((ConstantValue) assignment.getrValue1()).calculateLiteral(getProgramScope());
|
||||
if(constantLiteral.getValue().equals(0L)) {
|
||||
getLog().append("Removed zero-constant in assignment " + assignment.getlValue());
|
||||
assignment.setrValue1(null);
|
||||
|
@ -167,7 +165,7 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
|||
} else {
|
||||
// Check if the constant is zero
|
||||
try {
|
||||
ConstantLiteral constantLiteral = ((ConstantValue) assignment.getrValue2()).calculateLiteral(getScope());
|
||||
ConstantLiteral constantLiteral = ((ConstantValue) assignment.getrValue2()).calculateLiteral(getProgramScope());
|
||||
if(constantLiteral.getValue().equals(0L)) {
|
||||
getLog().append("Removed zero-constant in assignment " + assignment.getlValue());
|
||||
assignment.setrValue2(assignment.getrValue1());
|
||||
|
@ -193,10 +191,10 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
|||
if(getUsages(variable) > 1) {
|
||||
return null;
|
||||
}
|
||||
final Variable var = getScope().getVar(variable);
|
||||
final Variable var = getProgramScope().getVar(variable);
|
||||
if(var.isKindLoadStore())
|
||||
return null;
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(variable, getGraph(), getScope());
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(variable, getGraph(), getProgramScope());
|
||||
if(varAssignments.size()!=1)
|
||||
return null;
|
||||
final VarAssignments.VarAssignment varAssignment = varAssignments.get(0);
|
||||
|
@ -208,7 +206,7 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
|||
if(assignment.getOperator() != null && "+".equals(assignment.getOperator().getOperator())) {
|
||||
if(assignment.getrValue1() instanceof ConstantValue) {
|
||||
ConstantValue constant = (ConstantValue) assignment.getrValue1();
|
||||
SymbolType constantType = constant.getType(getScope());
|
||||
SymbolType constantType = constant.getType(getProgramScope());
|
||||
if(SymbolType.isInteger(constantType)) {
|
||||
assignment.setrValue1(null);
|
||||
assignment.setOperator(null);
|
||||
|
|
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCallExecute;
|
||||
|
@ -24,7 +25,7 @@ public class Pass2ConstantCallPointerIdentification extends Pass2SsaOptimization
|
|||
@Override
|
||||
public boolean step() {
|
||||
boolean optimized = false;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> statementsIt = block.getStatements().listIterator();
|
||||
while(statementsIt.hasNext()) {
|
||||
Statement statement = statementsIt.next();
|
||||
|
@ -39,7 +40,7 @@ public class Pass2ConstantCallPointerIdentification extends Pass2SsaOptimization
|
|||
optimized = true;
|
||||
}
|
||||
} else if(procedure instanceof ConstantRef) {
|
||||
Variable procedureVariable = getScope().getConstant((ConstantRef) procedure);
|
||||
Variable procedureVariable = getProgramScope().getConstant((ConstantRef) procedure);
|
||||
SymbolType procedureVariableType = procedureVariable.getType();
|
||||
if(procedureVariableType instanceof SymbolTypePointer) {
|
||||
if(((SymbolTypePointer) procedureVariableType).getElementType() instanceof SymbolTypeProcedure) {
|
||||
|
@ -63,12 +64,12 @@ public class Pass2ConstantCallPointerIdentification extends Pass2SsaOptimization
|
|||
* @param constProcedureRef The constant procedure pointed to
|
||||
* @param block The block containing the call
|
||||
*/
|
||||
private void replacePointerCall(StatementCallExecute callPointer, ProcedureRef constProcedureRef, ControlFlowBlock block) {
|
||||
private void replacePointerCall(StatementCallExecute callPointer, ProcedureRef constProcedureRef, Graph.Block block) {
|
||||
callPointer.setProcedure(constProcedureRef);
|
||||
if(block.getCallSuccessor()!=null)
|
||||
throw new CompileError("Internal error! Block has two calls!", callPointer);
|
||||
block.setCallSuccessor(constProcedureRef.getLabelRef());
|
||||
final Procedure procedure = getScope().getProcedure(constProcedureRef);
|
||||
final Procedure procedure = getProgramScope().getProcedure(constProcedureRef);
|
||||
procedure.setCallingConvention(Procedure.CallingConvention.STACK_CALL);
|
||||
getLog().append("Replacing constant pointer function " + callPointer.toString(getProgram(), false));
|
||||
}
|
||||
|
@ -82,7 +83,7 @@ public class Pass2ConstantCallPointerIdentification extends Pass2SsaOptimization
|
|||
*/
|
||||
private ProcedureRef findConstProcedure(RValue procedurePointer) {
|
||||
if(procedurePointer instanceof ConstantRef) {
|
||||
Variable constant = getScope().getConstant((ConstantRef) procedurePointer);
|
||||
Variable constant = getProgramScope().getConstant((ConstantRef) procedurePointer);
|
||||
return findConstProcedure(constant.getInitValue());
|
||||
} else if(procedurePointer instanceof ConstantSymbolPointer) {
|
||||
ConstantSymbolPointer pointer = (ConstantSymbolPointer) procedurePointer;
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ConstantNotLiteral;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.operators.OperatorBinary;
|
||||
|
@ -49,7 +46,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
ConstantVariableValue constVarVal = constants.get(constRef);
|
||||
Scope scope = variable.getScope();
|
||||
ConstantValue constVal = constVarVal.getConstantValue();
|
||||
SymbolType valueType = SymbolTypeInference.inferType(getScope(), constVal);
|
||||
SymbolType valueType = SymbolTypeInference.inferType(getProgramScope(), constVal);
|
||||
SymbolType variableType = variable.getType();
|
||||
|
||||
if(!SymbolType.NUMBER.equals(variableType) && SymbolType.NUMBER.equals(valueType)) {
|
||||
|
@ -62,9 +59,9 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
// NULL pointer assigment is OK
|
||||
;
|
||||
else if(!SymbolTypeConversion.assignmentTypeMatch(variableType, valueType)) {
|
||||
ConstantLiteral constantLiteral = null;
|
||||
ConstantLiteral<?> constantLiteral = null;
|
||||
try {
|
||||
constantLiteral = constVal.calculateLiteral(getScope());
|
||||
constantLiteral = constVal.calculateLiteral(getProgramScope());
|
||||
} catch(ConstantNotLiteral e) {
|
||||
// ignore
|
||||
}
|
||||
|
@ -95,16 +92,16 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
private static class ConstantVariableValue {
|
||||
|
||||
/** The variable that has been determined to be constant. */
|
||||
private VariableRef variableRef;
|
||||
private final VariableRef variableRef;
|
||||
|
||||
/** The constant value of the variable. */
|
||||
private ConstantValue constantValue;
|
||||
private final ConstantValue constantValue;
|
||||
|
||||
/**
|
||||
* The statement that assigns the variable its value (the assignment will be removed at the end).
|
||||
* Either a {@link StatementAssignment} or a {@link StatementPhiBlock}.
|
||||
*/
|
||||
private Statement assignment;
|
||||
private final Statement assignment;
|
||||
|
||||
public ConstantVariableValue(VariableRef variableRef, ConstantValue constantValue, Statement assignment) {
|
||||
this.variableRef = variableRef;
|
||||
|
@ -134,39 +131,34 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
final Map<VariableRef, ConstantVariableValue> constants = new LinkedHashMap<>();
|
||||
|
||||
// Look for constants among versions, intermediates & declared constants
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
LValue lValue = assignment.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
VariableRef varRef = (VariableRef) lValue;
|
||||
Variable var = getScope().getVariable(varRef);
|
||||
if(var.isVolatile() || var.isKindLoadStore())
|
||||
// Do not examine volatiles and non-versioned variables
|
||||
continue;
|
||||
if(var.getRegister() != null && var.getRegister().isMem())
|
||||
// Skip variables allocated into memory
|
||||
continue;
|
||||
ConstantValue constant = getConstant(assignment.getrValue2());
|
||||
if(assignment.getrValue1() == null && assignment.getOperator() == null && constant != null) {
|
||||
constants.put(varRef, new ConstantVariableValue(varRef, constant, assignment));
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementAssignment assignment) {
|
||||
LValue lValue = assignment.getlValue();
|
||||
if(lValue instanceof VariableRef varRef) {
|
||||
Variable var = getProgramScope().getVariable(varRef);
|
||||
if(var.isVolatile() || var.isKindLoadStore())
|
||||
// Do not examine volatiles and non-versioned variables
|
||||
continue;
|
||||
if(var.getRegister() != null && var.getRegister().isMem())
|
||||
// Skip variables allocated into memory
|
||||
continue;
|
||||
ConstantValue constant = getConstant(assignment.getrValue2());
|
||||
if(assignment.getrValue1() == null && assignment.getOperator() == null && constant != null) {
|
||||
constants.put(varRef, new ConstantVariableValue(varRef, constant, assignment));
|
||||
}
|
||||
} else if(statement instanceof StatementPhiBlock) {
|
||||
StatementPhiBlock phi = (StatementPhiBlock) statement;
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
|
||||
if(phiVariable.getValues().size() == 1) {
|
||||
StatementPhiBlock.PhiRValue phiRValue = phiVariable.getValues().get(0);
|
||||
if(getConstant(phiRValue.getrValue()) != null) {
|
||||
VariableRef varRef = phiVariable.getVariable();
|
||||
Variable var = getScope().getVariable(varRef);
|
||||
if(var.isVolatile() || var.isKindLoadStore())
|
||||
// Do not examine volatiles and non-versioned variables
|
||||
continue;
|
||||
ConstantValue constant = getConstant(phiRValue.getrValue());
|
||||
constants.put(varRef, new ConstantVariableValue(varRef, constant, phi));
|
||||
}
|
||||
}
|
||||
} else if(statement instanceof StatementPhiBlock phi) {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
|
||||
if(phiVariable.getValues().size() == 1) {
|
||||
StatementPhiBlock.PhiRValue phiRValue = phiVariable.getValues().get(0);
|
||||
if(getConstant(phiRValue.getrValue()) != null) {
|
||||
VariableRef varRef = phiVariable.getVariable();
|
||||
Variable var = getProgramScope().getVariable(varRef);
|
||||
if(var.isVolatile() || var.isKindLoadStore())
|
||||
// Do not examine volatiles and non-versioned variables
|
||||
continue;
|
||||
ConstantValue constant = getConstant(phiRValue.getrValue());
|
||||
constants.put(varRef, new ConstantVariableValue(varRef, constant, phi));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,14 +166,14 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Look for constants among non-versioned variables
|
||||
for(Variable variable : getScope().getAllVariables(true)) {
|
||||
for(Variable variable : getProgramScope().getAllVariables(true)) {
|
||||
if(variable.isVolatile() || !variable.isKindLoadStore())
|
||||
// Do not examine volatiles, non-constants or versioned variables
|
||||
continue;
|
||||
if(variable.getRegister() != null && variable.getRegister().isMem())
|
||||
// Skip variables allocated into memory
|
||||
continue;
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(variable.getRef(), getGraph(), getScope());
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(variable.getRef(), getGraph(), getProgramScope());
|
||||
if(varAssignments.size() == 1) {
|
||||
final VarAssignments.VarAssignment varAssignment = varAssignments.get(0);
|
||||
if(!VarAssignments.VarAssignment.Type.STATEMENT_LVALUE.equals(varAssignment.type) || !(varAssignment.statementLValue instanceof StatementAssignment))
|
||||
|
@ -189,8 +181,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
continue;
|
||||
StatementAssignment assignment = (StatementAssignment) varAssignment.statementLValue;
|
||||
LValue lValue = assignment.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
VariableRef varRef = (VariableRef) lValue;
|
||||
if(lValue instanceof VariableRef varRef) {
|
||||
ConstantValue constant = getConstant(assignment.getrValue2());
|
||||
if(assignment.getrValue1() == null && assignment.getOperator() == null && constant != null) {
|
||||
constants.put(varRef, new ConstantVariableValue(varRef, constant, assignment));
|
||||
|
@ -212,11 +203,9 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
public static ConstantValue getConstant(RValue rValue) {
|
||||
if(rValue instanceof ConstantValue) {
|
||||
return (ConstantValue) rValue;
|
||||
} else if(rValue instanceof Variable && ((Variable) rValue).isKindConstant()) {
|
||||
Variable constantVar = (Variable) rValue;
|
||||
} else if(rValue instanceof Variable constantVar && ((Variable) rValue).isKindConstant()) {
|
||||
return constantVar.getConstantRef();
|
||||
} else if(rValue instanceof CastValue) {
|
||||
CastValue castValue = (CastValue) rValue;
|
||||
} else if(rValue instanceof CastValue castValue) {
|
||||
ConstantValue castConstant = getConstant(castValue.getValue());
|
||||
if(castConstant != null) {
|
||||
return new ConstantCastValue(castValue.getToType(), castConstant);
|
||||
|
@ -239,47 +228,43 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
return new ConstantBinary(c1, operator, c2);
|
||||
}
|
||||
|
||||
switch(operator.getOperator()) {
|
||||
case "-":
|
||||
case "*":
|
||||
case "/":
|
||||
case "%":
|
||||
case "&":
|
||||
case "|":
|
||||
case "&&":
|
||||
case "||":
|
||||
case "^":
|
||||
case "<<":
|
||||
case ">>":
|
||||
case "==":
|
||||
case "!=":
|
||||
case ">":
|
||||
case "<":
|
||||
case ">=":
|
||||
case "<=":
|
||||
return new ConstantBinary(c1, operator, c2);
|
||||
case "w=":
|
||||
return new ConstantBinary(new ConstantBinary(c1, Operators.MULTIPLY, new ConstantInteger(256L)), Operators.PLUS, c2);
|
||||
case "dw=":
|
||||
return new ConstantBinary(new ConstantBinary(c1, Operators.MULTIPLY, new ConstantInteger(65536L)), Operators.PLUS, c2);
|
||||
case "byte0=":
|
||||
return new ConstantBinary(new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0xffffff00L)), Operators.BOOL_OR, c2);
|
||||
case "byte1=":
|
||||
return new ConstantBinary(new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0xffff00ffL)), Operators.BOOL_OR, new ConstantBinary(c2, Operators.MULTIPLY, new ConstantInteger(0x100L)));
|
||||
case "byte2=":
|
||||
return new ConstantBinary(new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0xff00ffffL)), Operators.BOOL_OR, new ConstantBinary(c2, Operators.MULTIPLY, new ConstantInteger(0x10000L)));
|
||||
case "byte3=":
|
||||
return new ConstantBinary(new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0x00ffffffL)), Operators.BOOL_OR, new ConstantBinary(c2, Operators.MULTIPLY, new ConstantInteger(0x1000000L)));
|
||||
case "word0=":
|
||||
return new ConstantBinary(new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0xffff0000L)), Operators.BOOL_OR, c2);
|
||||
case "word1=":
|
||||
return new ConstantBinary(new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0x0000ffffL)), Operators.BOOL_OR, new ConstantBinary(c2, Operators.MULTIPLY, new ConstantInteger(0x10000L)));
|
||||
case "*idx":
|
||||
return switch (operator.getOperator()) {
|
||||
case "-", "*", "/", "%", "&", "|", "&&", "||", "^", "<<", ">>", "==", "!=", ">", "<", ">=", "<=" ->
|
||||
new ConstantBinary(c1, operator, c2);
|
||||
case "w=" -> new ConstantBinary(
|
||||
new ConstantBinary(c1, Operators.MULTIPLY, new ConstantInteger(256L)), Operators.PLUS,
|
||||
c2);
|
||||
case "dw=" -> new ConstantBinary(
|
||||
new ConstantBinary(c1, Operators.MULTIPLY, new ConstantInteger(65536L)),
|
||||
Operators.PLUS, c2);
|
||||
case "byte0=" -> new ConstantBinary(
|
||||
new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0xffffff00L)),
|
||||
Operators.BOOL_OR, c2);
|
||||
case "byte1=" -> new ConstantBinary(
|
||||
new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0xffff00ffL)),
|
||||
Operators.BOOL_OR,
|
||||
new ConstantBinary(c2, Operators.MULTIPLY, new ConstantInteger(0x100L)));
|
||||
case "byte2=" -> new ConstantBinary(
|
||||
new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0xff00ffffL)),
|
||||
Operators.BOOL_OR,
|
||||
new ConstantBinary(c2, Operators.MULTIPLY, new ConstantInteger(0x10000L)));
|
||||
case "byte3=" -> new ConstantBinary(
|
||||
new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0x00ffffffL)),
|
||||
Operators.BOOL_OR,
|
||||
new ConstantBinary(c2, Operators.MULTIPLY, new ConstantInteger(0x1000000L)));
|
||||
case "word0=" -> new ConstantBinary(
|
||||
new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0xffff0000L)),
|
||||
Operators.BOOL_OR, c2);
|
||||
case "word1=" -> new ConstantBinary(
|
||||
new ConstantBinary(c1, Operators.BOOL_AND, new ConstantInteger(0x0000ffffL)),
|
||||
Operators.BOOL_OR,
|
||||
new ConstantBinary(c2, Operators.MULTIPLY, new ConstantInteger(0x10000L)));
|
||||
case "*idx" ->
|
||||
// Pointer dereference - not constant
|
||||
return null;
|
||||
default:
|
||||
throw new RuntimeException("Unhandled Binary Operator " + operator.getOperator());
|
||||
}
|
||||
null;
|
||||
default ->
|
||||
throw new RuntimeException("Unhandled Binary Operator " + operator.getOperator());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
@ -304,13 +289,10 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||
}
|
||||
|
||||
// Examine all statements
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && procedureRef.equals(assignment.getrValue2())) {
|
||||
return true;
|
||||
}
|
||||
for(var statement : program.getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementAssignment assignment) {
|
||||
if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && procedureRef.equals(assignment.getrValue2())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||
|
||||
import dk.camelot64.kickc.model.ConstantNotLiteral;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.Operator;
|
||||
import dk.camelot64.kickc.model.operators.OperatorBinary;
|
||||
|
@ -35,7 +35,7 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization {
|
|||
public boolean step() {
|
||||
boolean modified = false;
|
||||
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
@ -85,15 +85,15 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization {
|
|||
// If all values are constant find the literal condition value
|
||||
if(conditional.getrValue1() == null && operator == null && constValue2 != null) {
|
||||
// Constant condition
|
||||
return constValue2.calculateLiteral(getScope());
|
||||
return constValue2.calculateLiteral(getProgramScope());
|
||||
} else if(conditional.getrValue1() == null && operator != null && constValue2 != null) {
|
||||
// Constant unary condition
|
||||
ConstantValue constVal = Pass2ConstantIdentification.createUnary((OperatorUnary) operator, constValue2);
|
||||
return constVal.calculateLiteral(getScope());
|
||||
return constVal.calculateLiteral(getProgramScope());
|
||||
} else if(constValue1 != null && operator != null && constValue2 != null) {
|
||||
// Constant binary condition
|
||||
ConstantValue constVal = Pass2ConstantIdentification.createBinary(constValue1, (OperatorBinary) operator, constValue2, getScope());
|
||||
return constVal.calculateLiteral(getScope());
|
||||
ConstantValue constVal = Pass2ConstantIdentification.createBinary(constValue1, (OperatorBinary) operator, constValue2, getProgramScope());
|
||||
return constVal.calculateLiteral(getProgramScope());
|
||||
}
|
||||
|
||||
} catch(ConstantNotLiteral e) {
|
||||
|
@ -183,7 +183,7 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization {
|
|||
ConstantValue constValue = Pass2ConstantIdentification.getConstant(rValue);
|
||||
if(constValue != null) {
|
||||
try {
|
||||
ConstantLiteral constantLiteral = constValue.calculateLiteral(getScope());
|
||||
ConstantLiteral constantLiteral = constValue.calculateLiteral(getProgramScope());
|
||||
if(constantLiteral instanceof ConstantInteger) {
|
||||
Long value = ((ConstantInteger) constantLiteral).getInteger();
|
||||
return new IntValueInterval(value, value);
|
||||
|
@ -193,7 +193,7 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization {
|
|||
}
|
||||
}
|
||||
// Not constant - find the interval of the type
|
||||
SymbolType symbolType = SymbolTypeInference.inferType(getScope(), rValue);
|
||||
SymbolType symbolType = SymbolTypeInference.inferType(getProgramScope(), rValue);
|
||||
if(symbolType instanceof SymbolTypeIntegerFixed) {
|
||||
SymbolTypeIntegerFixed typeIntegerFixed = (SymbolTypeIntegerFixed) symbolType;
|
||||
return new IntValueInterval(typeIntegerFixed.getMinValue(), typeIntegerFixed.getMaxValue());
|
||||
|
|
|
@ -57,7 +57,7 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
|
|||
final Set<ConstantRef> inlineRefs = inline.keySet();
|
||||
removeParameters(inlineRefs);
|
||||
// Remove from symbol table
|
||||
deleteSymbols(getScope(), inlineRefs);
|
||||
deleteSymbols(getProgramScope(), inlineRefs);
|
||||
|
||||
|
||||
for(ConstantRef constantRef : inlineRefs) {
|
||||
|
@ -70,8 +70,8 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
|
|||
|
||||
private void removeParameters(Set<ConstantRef> inlineRefs) {
|
||||
for(ConstantRef inlineRef : inlineRefs) {
|
||||
final Scope scope = getScope().getConstant(inlineRef).getScope();
|
||||
final Procedure procedure = getProcedure(scope);
|
||||
final Scope scope = getProgramScope().getConstant(inlineRef).getScope();
|
||||
final Procedure procedure = scope.getContainingProcedure();
|
||||
if(procedure!=null) {
|
||||
final List<Variable> parameters = procedure.getParameters();
|
||||
final boolean modified = parameters.removeIf(param -> param.getRef().equals(inlineRef));
|
||||
|
@ -83,15 +83,6 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
|
|||
}
|
||||
}
|
||||
|
||||
private static Procedure getProcedure(Scope scope) {
|
||||
if(scope instanceof Procedure)
|
||||
return (Procedure) scope;
|
||||
else if(scope instanceof ProgramScope)
|
||||
return null;
|
||||
else
|
||||
return getProcedure(scope.getScope());
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace any aliases within the constant values themselves
|
||||
*
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
@ -28,13 +29,13 @@ public class Pass2ConstantIntrinsics extends Pass2SsaOptimization {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementCall) {
|
||||
final StatementCall call = (StatementCall) statement;
|
||||
final Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
final Procedure procedure = getProgramScope().getProcedure(call.getProcedure());
|
||||
if(procedure.isDeclaredIntrinsic()) {
|
||||
if(procedure.getFullName().equals(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4)) {
|
||||
List<ConstantValue> constParams = new ArrayList<>();
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.OperatorBinary;
|
||||
import dk.camelot64.kickc.model.operators.OperatorUnary;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
|
@ -32,20 +30,17 @@ public class Pass2ConstantRValueConsolidation extends Pass2SsaOptimization {
|
|||
@Override
|
||||
public boolean step() {
|
||||
boolean modified = false;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(assignment.getrValue1() != null || assignment.getOperator() != null || !(assignment.getrValue2() instanceof ConstantValue)) {
|
||||
SymbolType lValueType = SymbolTypeInference.inferType(getScope(), assignment.getlValue());
|
||||
ConstantValue constant = getConstantAssignmentValue(assignment, lValueType);
|
||||
if(constant != null) {
|
||||
getLog().append("Constant right-side identified " + assignment.toString(getProgram(), false));
|
||||
assignment.setrValue2(constant);
|
||||
assignment.setOperator(null);
|
||||
assignment.setrValue1(null);
|
||||
modified = true;
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementAssignment assignment) {
|
||||
if(assignment.getrValue1() != null || assignment.getOperator() != null || !(assignment.getrValue2() instanceof ConstantValue)) {
|
||||
SymbolType lValueType = SymbolTypeInference.inferType(getProgramScope(), assignment.getlValue());
|
||||
ConstantValue constant = getConstantAssignmentValue(assignment);
|
||||
if(constant != null) {
|
||||
getLog().append("Constant right-side identified " + assignment.toString(getProgram(), false));
|
||||
assignment.setrValue2(constant);
|
||||
assignment.setOperator(null);
|
||||
assignment.setrValue1(null);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,10 +52,9 @@ public class Pass2ConstantRValueConsolidation extends Pass2SsaOptimization {
|
|||
* Examine the right side of an assignment and if it is constant then return the constant value.
|
||||
*
|
||||
* @param assignment The assignment to examine
|
||||
* @param lValueType The type of the lvalue
|
||||
* @return The constant value if the right side is constant
|
||||
*/
|
||||
private ConstantValue getConstantAssignmentValue(StatementAssignment assignment, SymbolType lValueType) {
|
||||
private ConstantValue getConstantAssignmentValue(StatementAssignment assignment) {
|
||||
|
||||
if(assignment.getrValue1() == null && Pass2ConstantIdentification.getConstant(assignment.getrValue2()) != null) {
|
||||
if(assignment.getOperator() == null) {
|
||||
|
@ -79,25 +73,25 @@ public class Pass2ConstantRValueConsolidation extends Pass2SsaOptimization {
|
|||
Pass2ConstantIdentification.getConstant(assignment.getrValue1()),
|
||||
(OperatorBinary) assignment.getOperator(),
|
||||
Pass2ConstantIdentification.getConstant(assignment.getrValue2()),
|
||||
getScope());
|
||||
getProgramScope());
|
||||
} else if(Operators.BYTE1.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
|
||||
final SymbolType rVal2Type = SymbolTypeInference.inferType(getScope(), assignment.getrValue2());
|
||||
final SymbolType rVal2Type = SymbolTypeInference.inferType(getProgramScope(), assignment.getrValue2());
|
||||
if(SymbolType.isInteger(rVal2Type) && rVal2Type.getSizeBytes() < 2)
|
||||
return new ConstantInteger(0l, SymbolType.BYTE);
|
||||
} else if(Operators.BYTE2.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
|
||||
final SymbolType rVal2Type = SymbolTypeInference.inferType(getScope(), assignment.getrValue2());
|
||||
final SymbolType rVal2Type = SymbolTypeInference.inferType(getProgramScope(), assignment.getrValue2());
|
||||
if(SymbolType.isInteger(rVal2Type) && rVal2Type.getSizeBytes() < 3)
|
||||
return new ConstantInteger(0l, SymbolType.BYTE);
|
||||
else if(rVal2Type instanceof SymbolTypePointer)
|
||||
return new ConstantInteger(0l, SymbolType.BYTE);
|
||||
} else if(Operators.BYTE3.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
|
||||
final SymbolType rVal2Type = SymbolTypeInference.inferType(getScope(), assignment.getrValue2());
|
||||
final SymbolType rVal2Type = SymbolTypeInference.inferType(getProgramScope(), assignment.getrValue2());
|
||||
if(SymbolType.isInteger(rVal2Type) && rVal2Type.getSizeBytes() < 4)
|
||||
return new ConstantInteger(0l, SymbolType.BYTE);
|
||||
else if(rVal2Type instanceof SymbolTypePointer)
|
||||
return new ConstantInteger(0l, SymbolType.BYTE);
|
||||
} else if(Operators.WORD1.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
|
||||
final SymbolType rVal2Type = SymbolTypeInference.inferType(getScope(), assignment.getrValue2());
|
||||
final SymbolType rVal2Type = SymbolTypeInference.inferType(getProgramScope(), assignment.getrValue2());
|
||||
if(SymbolType.isInteger(rVal2Type) && rVal2Type.getSizeBytes() < 3)
|
||||
return new ConstantInteger(0l, SymbolType.WORD);
|
||||
else if(rVal2Type instanceof SymbolTypePointer)
|
||||
|
|
|
@ -69,10 +69,10 @@ public class Pass2ConstantSimplification extends Pass2SsaOptimization {
|
|||
if(Operators.MULTIPLY.equals(binary.getOperator())) {
|
||||
if(binary.getLeft() instanceof ConstantInteger && ((ConstantInteger) binary.getLeft()).getValue() == 0) {
|
||||
getLog().append("Simplifying constant multiply by zero " + binary);
|
||||
programValue.set(new ConstantInteger(0L, binary.getType(getScope())));
|
||||
programValue.set(new ConstantInteger(0L, binary.getType(getProgramScope())));
|
||||
} else if(binary.getRight() instanceof ConstantInteger && ((ConstantInteger) binary.getRight()).getValue() == 0) {
|
||||
getLog().append("Simplifying constant multiply by zero " + binary);
|
||||
programValue.set(new ConstantInteger(0L, binary.getType(getScope())));
|
||||
programValue.set(new ConstantInteger(0L, binary.getType(getProgramScope())));
|
||||
}
|
||||
} else if(Operators.PLUS.equals(binary.getOperator())) {
|
||||
if(binary.getLeft() instanceof ConstantInteger && ((ConstantInteger) binary.getLeft()).getValue() == 0) {
|
||||
|
|
|
@ -33,7 +33,7 @@ public class Pass2ConstantStringConsolidation extends Pass2SsaOptimization {
|
|||
boolean modified = false;
|
||||
// Build a map with all constant strings
|
||||
Map<ConstantString, List<Variable>> constantStringMap = new LinkedHashMap<>();
|
||||
for(Variable constVar : getScope().getAllConstants(true)) {
|
||||
for(Variable constVar : getProgramScope().getAllConstants(true)) {
|
||||
ConstantValue constVal = constVar.getInitValue();
|
||||
if(constVal instanceof ConstantString) {
|
||||
ConstantString constString = (ConstantString) constVal;
|
||||
|
@ -89,7 +89,7 @@ public class Pass2ConstantStringConsolidation extends Pass2SsaOptimization {
|
|||
rootConstant = constantVars.get(0);
|
||||
} else {
|
||||
// Create a new root - and roll around again
|
||||
ProgramScope rootScope = getScope();
|
||||
ProgramScope rootScope = getProgramScope();
|
||||
String localName = getRootName(constantVars);
|
||||
final long stringLength = constString.getStringLength();
|
||||
final ConstantInteger arraySize = new ConstantInteger(stringLength, stringLength<256?SymbolType.BYTE : SymbolType.WORD);
|
||||
|
@ -117,7 +117,7 @@ public class Pass2ConstantStringConsolidation extends Pass2SsaOptimization {
|
|||
for(Variable constantVar : constantVars) {
|
||||
if(!constantVar.getRef().isIntermediate()) {
|
||||
String candidateName = constantVar.getLocalName();
|
||||
if(getScope().getLocalSymbol(candidateName) == null) {
|
||||
if(getProgramScope().getLocalSymbol(candidateName) == null) {
|
||||
if(constName == null || constName.length() > candidateName.length()) {
|
||||
constName = candidateName;
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ public class Pass2ConstantStringConsolidation extends Pass2SsaOptimization {
|
|||
int i = 0;
|
||||
do {
|
||||
String candidateName = "string_" + i;
|
||||
if(getScope().getLocalSymbol(candidateName) == null) {
|
||||
if(getProgramScope().getLocalSymbol(candidateName) == null) {
|
||||
return candidateName;
|
||||
}
|
||||
i++;
|
||||
|
|
|
@ -4,14 +4,12 @@ import dk.camelot64.kickc.model.Comment;
|
|||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableBuilder;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.operators.OperatorPlus;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
@ -30,12 +28,12 @@ public class Pass2DeInlineWordDerefIdx extends Pass2SsaOptimization {
|
|||
if(programValue.get() instanceof PointerDereferenceIndexed) {
|
||||
PointerDereferenceIndexed dereferenceIndexed = (PointerDereferenceIndexed) programValue.get();
|
||||
RValue indexValue = dereferenceIndexed.getIndex();
|
||||
SymbolType indexType = SymbolTypeInference.inferType(getScope(), indexValue);
|
||||
SymbolType indexType = SymbolTypeInference.inferType(getProgramScope(), indexValue);
|
||||
if(indexType.getSizeBytes()>1) {
|
||||
// Index is multiple bytes - de-inline it
|
||||
getLog().append("De-inlining pointer[w] to *(pointer+w) "+currentStmt.toString(getProgram(), false));
|
||||
Scope currentScope = getScope().getScope(currentBlock.getScope());
|
||||
SymbolType pointerType = Operators.PLUS.inferType(SymbolTypeInference.inferType(getScope(), dereferenceIndexed.getPointer()), SymbolTypeInference.inferType(getScope(), dereferenceIndexed.getIndex()));
|
||||
Scope currentScope = getProgramScope().getScope(currentBlock.getScope());
|
||||
SymbolType pointerType = Operators.PLUS.inferType(SymbolTypeInference.inferType(getProgramScope(), dereferenceIndexed.getPointer()), SymbolTypeInference.inferType(getProgramScope(), dereferenceIndexed.getIndex()));
|
||||
Variable tmpVar = VariableBuilder.createIntermediate(currentScope, pointerType, getProgram());
|
||||
stmtIt.previous();
|
||||
StatementAssignment tmpVarAssignment = new StatementAssignment((LValue) tmpVar.getRef(), dereferenceIndexed.getPointer(), Operators.PLUS, indexValue, true, currentStmt.getSource(), Comment.NO_COMMENTS);
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.DominatorsBlock;
|
||||
import dk.camelot64.kickc.model.DominatorsGraph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueHandler;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
|
@ -17,6 +14,7 @@ import dk.camelot64.kickc.model.types.SymbolType;
|
|||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.lang.InternalError;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
@ -39,7 +37,7 @@ public class Pass2DuplicateRValueIdentification extends Pass2SsaOptimization {
|
|||
// All RValues in the program
|
||||
Set<AssignmentWithRValue> rValues = new HashSet<>();
|
||||
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment thisAssignment = (StatementAssignment) statement;
|
||||
|
@ -115,7 +113,7 @@ public class Pass2DuplicateRValueIdentification extends Pass2SsaOptimization {
|
|||
}
|
||||
, null, null, null);
|
||||
for(SymbolVariableRef varRef : varRefs) {
|
||||
Variable var = getScope().getVariable(varRef);
|
||||
Variable var = getProgramScope().getVariable(varRef);
|
||||
if(!var.getScope().getRef().equals(scopeRef))
|
||||
return false;
|
||||
}
|
||||
|
@ -148,13 +146,13 @@ public class Pass2DuplicateRValueIdentification extends Pass2SsaOptimization {
|
|||
* Represents an RValue of an assignment.
|
||||
*/
|
||||
private class AssignmentWithRValue {
|
||||
private ControlFlowBlock block;
|
||||
private Graph.Block block;
|
||||
private StatementAssignment assignment;
|
||||
private RValue rValue1;
|
||||
private Operator operator;
|
||||
private RValue rValue2;
|
||||
|
||||
public AssignmentWithRValue(StatementAssignment assignment, ControlFlowBlock block) {
|
||||
public AssignmentWithRValue(StatementAssignment assignment, Graph.Block block) {
|
||||
this.block = block;
|
||||
this.assignment = assignment;
|
||||
this.rValue1 = assignment.getrValue1();
|
||||
|
@ -175,7 +173,7 @@ public class Pass2DuplicateRValueIdentification extends Pass2SsaOptimization {
|
|||
ProgramValueHandler loadStoreIdentificator = (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
Value value = programValue.get();
|
||||
if(value instanceof VariableRef) {
|
||||
Variable var = getScope().getVar((VariableRef) value);
|
||||
Variable var = getProgramScope().getVar((VariableRef) value);
|
||||
if(var.isKindLoadStore())
|
||||
isLoadStore.set(true);
|
||||
}
|
||||
|
@ -191,7 +189,7 @@ public class Pass2DuplicateRValueIdentification extends Pass2SsaOptimization {
|
|||
if(programValue.get() instanceof PointerDereference)
|
||||
isVol.set(true);
|
||||
if(programValue.get() instanceof VariableRef) {
|
||||
Variable variable = getScope().getVariable((VariableRef) programValue.get());
|
||||
Variable variable = getProgramScope().getVariable((VariableRef) programValue.get());
|
||||
if(variable.isVolatile())
|
||||
isVol.set(true);
|
||||
}
|
||||
|
@ -222,11 +220,11 @@ public class Pass2DuplicateRValueIdentification extends Pass2SsaOptimization {
|
|||
if(operator.equals(Operators.WORD0)) return true;
|
||||
if(operator.equals(Operators.WORD1)) return true;
|
||||
if(operator.equals(Operators.PLUS) && rValue2 instanceof ConstantValue) {
|
||||
final SymbolType type1 = SymbolTypeInference.inferType(getScope(), rValue1);
|
||||
final SymbolType type1 = SymbolTypeInference.inferType(getProgramScope(), rValue1);
|
||||
return type1.getSizeBytes() == 1;
|
||||
}
|
||||
if(operator.equals(Operators.PLUS) && rValue1 instanceof ConstantValue) {
|
||||
final SymbolType type2 = SymbolTypeInference.inferType(getScope(), rValue2);
|
||||
final SymbolType type2 = SymbolTypeInference.inferType(getProgramScope(), rValue2);
|
||||
return type2.getSizeBytes() == 1;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
@ -13,7 +11,7 @@ import dk.camelot64.kickc.model.values.*;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
/** Pass that eliminates constant if's - they are either removed (if false) or replaces the default successor (if true). */
|
||||
/** Pass that eliminates blocks that are not referenced. */
|
||||
public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
|
||||
public Pass2EliminateUnusedBlocks(Program program) {
|
||||
|
@ -24,15 +22,19 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||
public boolean step() {
|
||||
Set<LabelRef> referencedBlocks = getReferencedBlocks();
|
||||
Set<LabelRef> unusedBlocks = new LinkedHashSet<>();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
if(!referencedBlocks.contains(block.getLabel())) {
|
||||
unusedBlocks.add(block.getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
if(unusedBlocks.contains(block.getLabel())) {
|
||||
for(Statement stmt : block.getStatements()) {
|
||||
if(stmt instanceof StatementLValue) {
|
||||
StatementLValue assignment = (StatementLValue) stmt;
|
||||
if(stmt instanceof StatementLValue assignment) {
|
||||
LValue lValue = assignment.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
Variable variable = getScope().getVariable((VariableRef) lValue);
|
||||
Variable variable = getProgramScope().getVariable((VariableRef) lValue);
|
||||
if(variable.isKindPhiVersion() || variable.isKindIntermediate()) {
|
||||
getLog().append("Eliminating variable " + lValue.toString(getProgram()) + " from unused block " + block.getLabel());
|
||||
variable.getScope().remove(variable);
|
||||
|
@ -42,7 +44,7 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||
for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) stmt).getPhiVariables()) {
|
||||
VariableRef phiVar = phiVariable.getVariable();
|
||||
getLog().append("Eliminating variable " + phiVar.toString(getProgram()) + " from unused block " + block.getLabel());
|
||||
Variable variable = getScope().getVariable(phiVar);
|
||||
Variable variable = getProgramScope().getVariable(phiVar);
|
||||
variable.getScope().remove(variable);
|
||||
|
||||
}
|
||||
|
@ -51,13 +53,15 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Set<LabelRef> removedBlocks = new HashSet<>();
|
||||
for(LabelRef unusedBlock : unusedBlocks) {
|
||||
Symbol unusedSymbol = getScope().getSymbol(unusedBlock);
|
||||
Symbol unusedSymbol = getProgramScope().getSymbol(unusedBlock);
|
||||
if(unusedSymbol instanceof Label) {
|
||||
getGraph().remove(unusedBlock);
|
||||
Label label = getScope().getLabel(unusedBlock);
|
||||
final Procedure procedure = unusedSymbol.getScope().getContainingProcedure();
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
final ControlFlowGraph procedureGraph = procedureCompilation.getGraph();
|
||||
procedureGraph.remove(unusedBlock);
|
||||
Label label = getProgramScope().getLabel(unusedBlock);
|
||||
label.getScope().remove(label);
|
||||
removePhiRValues(unusedBlock, getProgram());
|
||||
removedBlocks.add(unusedBlock);
|
||||
|
@ -84,31 +88,19 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||
public static void removeProcedure(ProcedureRef procedureRef, Set<LabelRef> removedBlocks, Program program) {
|
||||
program.getLog().append("Removing unused procedure " + procedureRef);
|
||||
Procedure unusedProcedure = program.getScope().getProcedure(procedureRef);
|
||||
List<ControlFlowBlock> procedureBlocks = program.getGraph().getScopeBlocks(procedureRef);
|
||||
for(ControlFlowBlock procedureBlock : procedureBlocks) {
|
||||
final ProcedureCompilation procedureCompilation = program.getProcedureCompilation(procedureRef);
|
||||
final ControlFlowGraph procedureGraph = procedureCompilation.getGraph();
|
||||
List<Graph.Block> procedureBlocks = new ArrayList<>(procedureGraph.getAllBlocks());
|
||||
for(var procedureBlock : procedureBlocks) {
|
||||
LabelRef blockLabelRef = procedureBlock.getLabel();
|
||||
program.getLog().append("Removing unused procedure block " + blockLabelRef);
|
||||
program.getGraph().remove(blockLabelRef);
|
||||
procedureGraph.remove(blockLabelRef);
|
||||
removePhiRValues(blockLabelRef, program);
|
||||
removedBlocks.add(blockLabelRef);
|
||||
}
|
||||
unusedProcedure.getScope().remove(unusedProcedure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all referenced blocks in the entire program
|
||||
*
|
||||
* @return All blocks referenced
|
||||
*/
|
||||
private Set<LabelRef> getReferencedBlocks() {
|
||||
Set<LabelRef> referencedBlocks = new LinkedHashSet<>();
|
||||
List<ControlFlowBlock> entryPointBlocks = getGraph().getEntryPointBlocks(getProgram());
|
||||
for(ControlFlowBlock entryPointBlock : entryPointBlocks) {
|
||||
findReferencedBlocks(entryPointBlock, referencedBlocks);
|
||||
}
|
||||
|
||||
return referencedBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all PHI RValues in any phi-statements referencing the passed block
|
||||
|
@ -116,7 +108,7 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||
* @param removeBlock The block to remove from PHI RValues
|
||||
*/
|
||||
private static void removePhiRValues(LabelRef removeBlock, Program program) {
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(var block : program.getGraph().getAllBlocks()) {
|
||||
removePhiRValues(removeBlock, block, program.getLog());
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +119,7 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||
* @param removeBlock The block to remove from PHI RValues
|
||||
* @param block The block to modify
|
||||
*/
|
||||
public static void removePhiRValues(LabelRef removeBlock, ControlFlowBlock block, CompileLog log) {
|
||||
public static void removePhiRValues(LabelRef removeBlock, Graph.Block block, CompileLog log) {
|
||||
if(block.hasPhiBlock()) {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : block.getPhiBlock().getPhiVariables()) {
|
||||
ListIterator<StatementPhiBlock.PhiRValue> phiRValueIt = phiVariable.getValues().listIterator();
|
||||
|
@ -142,13 +134,28 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all referenced blocks in the entire program
|
||||
*
|
||||
* @return All blocks referenced
|
||||
*/
|
||||
private Set<LabelRef> getReferencedBlocks() {
|
||||
Set<LabelRef> referencedBlocks = new LinkedHashSet<>();
|
||||
List<Graph.Block> entryPointBlocks = getProgram().getEntryPointBlocks();
|
||||
for(var entryPointBlock : entryPointBlocks) {
|
||||
findReferencedBlocks(entryPointBlock, referencedBlocks);
|
||||
}
|
||||
|
||||
return referencedBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all referenced block labels recursively
|
||||
*
|
||||
* @param block The block to add (inc. all blocks that this block calls or jumps to)
|
||||
* @param used The blocks already discovered (not examined again)
|
||||
*/
|
||||
private void findReferencedBlocks(ControlFlowBlock block, Set<LabelRef> used) {
|
||||
private void findReferencedBlocks(Graph.Block block, Set<LabelRef> used) {
|
||||
if(block == null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.SymbolVariableRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
@ -26,42 +23,39 @@ public class Pass2IdenticalPhiElimination extends Pass2SsaOptimization {
|
|||
@Override
|
||||
public boolean step() {
|
||||
Map<VariableRef, RValue> phiIdentical = new LinkedHashMap<>();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementPhiBlock) {
|
||||
StatementPhiBlock statementPhi = (StatementPhiBlock) statement;
|
||||
ListIterator<StatementPhiBlock.PhiVariable> phiVariableIt = statementPhi.getPhiVariables().listIterator();
|
||||
while(phiVariableIt.hasNext()) {
|
||||
StatementPhiBlock.PhiVariable phiVariable = phiVariableIt.next();
|
||||
RValue rValue = null;
|
||||
boolean identical = true;
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if(phiRValue.getrValue() instanceof SymbolVariableRef) {
|
||||
Variable symbolVar = (Variable) getScope().getSymbol((SymbolVariableRef) phiRValue.getrValue());
|
||||
if(symbolVar.getRegister() != null) { //TODO: Handle register/memory/storage strategy differently!
|
||||
// Do not collapse PHI's for variables with declared registers (this prevents procedure parameters from being turned into constants)
|
||||
identical = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(phiRValue.getrValue().equals(phiVariable.getVariable())) {
|
||||
// Self PHI - skip that
|
||||
continue;
|
||||
}
|
||||
if(rValue == null) {
|
||||
rValue = phiRValue.getrValue();
|
||||
} else {
|
||||
if(!rValue.equals(phiRValue.getrValue())) {
|
||||
identical = false;
|
||||
break;
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementPhiBlock statementPhi) {
|
||||
ListIterator<StatementPhiBlock.PhiVariable> phiVariableIt = statementPhi.getPhiVariables().listIterator();
|
||||
while(phiVariableIt.hasNext()) {
|
||||
StatementPhiBlock.PhiVariable phiVariable = phiVariableIt.next();
|
||||
RValue rValue = null;
|
||||
boolean identical = true;
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if(phiRValue.getrValue() instanceof SymbolVariableRef) {
|
||||
Variable symbolVar = (Variable) getProgramScope().getSymbol((SymbolVariableRef) phiRValue.getrValue());
|
||||
if(symbolVar.getRegister() != null) { //TODO: Handle register/memory/storage strategy differently!
|
||||
// Do not collapse PHI's for variables with declared registers (this prevents procedure parameters from being turned into constants)
|
||||
identical = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(identical && rValue!=null) {
|
||||
// Found a phi-value with all rValues being identical
|
||||
phiIdentical.put(phiVariable.getVariable(), rValue);
|
||||
phiVariableIt.remove();
|
||||
if(phiRValue.getrValue().equals(phiVariable.getVariable())) {
|
||||
// Self PHI - skip that
|
||||
continue;
|
||||
}
|
||||
if(rValue == null) {
|
||||
rValue = phiRValue.getrValue();
|
||||
} else {
|
||||
if(!rValue.equals(phiRValue.getrValue())) {
|
||||
identical = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(identical && rValue!=null) {
|
||||
// Found a phi-value with all rValues being identical
|
||||
phiIdentical.put(phiVariable.getVariable(), rValue);
|
||||
phiVariableIt.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +65,7 @@ public class Pass2IdenticalPhiElimination extends Pass2SsaOptimization {
|
|||
RValue alias = phiIdentical.get(var);
|
||||
getLog().append("Identical Phi Values " + var.toString(getProgram()) + " " + alias.toString(getProgram()));
|
||||
}
|
||||
deleteSymbols(getScope(), phiIdentical.keySet());
|
||||
deleteSymbols(getProgramScope(), phiIdentical.keySet());
|
||||
return phiIdentical.size() > 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.OperatorCast;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.values.CastValue;
|
||||
|
@ -18,17 +16,14 @@ public class Pass2InlineCast extends Pass2SsaOptimization {
|
|||
@Override
|
||||
public boolean step() {
|
||||
boolean optimized = false;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(assignment.getrValue1()==null && assignment.getOperator() instanceof OperatorCast) {
|
||||
SymbolType toType = ((OperatorCast) assignment.getOperator()).getToType();
|
||||
assignment.setrValue2(new CastValue(toType, assignment.getrValue2()));
|
||||
assignment.setOperator(null);
|
||||
getLog().append("Inlining cast "+assignment.toString(getProgram(), false));
|
||||
optimized = true;
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementAssignment assignment) {
|
||||
if(assignment.getrValue1()==null && assignment.getOperator() instanceof OperatorCast) {
|
||||
SymbolType toType = ((OperatorCast) assignment.getOperator()).getToType();
|
||||
assignment.setrValue2(new CastValue(toType, assignment.getrValue2()));
|
||||
assignment.setOperator(null);
|
||||
getLog().append("Inlining cast "+assignment.toString(getProgram(), false));
|
||||
optimized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,10 +51,10 @@ public class Pass2InlineDerefIdx extends Pass2SsaOptimization {
|
|||
public RValue attemptInlineDeref(RValue pointer) {
|
||||
if(pointer instanceof VariableRef) {
|
||||
VariableRef derefVar = (VariableRef) pointer;
|
||||
final Variable var = getScope().getVar(derefVar);
|
||||
final Variable var = getProgramScope().getVar(derefVar);
|
||||
if(var.isKindLoadStore())
|
||||
return null;
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(derefVar, getGraph(), getScope());
|
||||
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(derefVar, getGraph(), getProgramScope());
|
||||
if(varAssignments.size()!=1)
|
||||
return null;
|
||||
final VarAssignments.VarAssignment varAssignment = varAssignments.get(0);
|
||||
|
@ -90,9 +90,9 @@ public class Pass2InlineDerefIdx extends Pass2SsaOptimization {
|
|||
return null;
|
||||
}
|
||||
if(Operators.PLUS.equals(derefAssignment.getOperator())) {
|
||||
SymbolType derefLeftType = SymbolTypeInference.inferType(getScope(), derefAssignment.getrValue1());
|
||||
SymbolType derefLeftType = SymbolTypeInference.inferType(getProgramScope(), derefAssignment.getrValue1());
|
||||
if(derefLeftType instanceof SymbolTypePointer) {
|
||||
SymbolType derefIndexType = SymbolTypeInference.inferType(getScope(), derefAssignment.getrValue2());
|
||||
SymbolType derefIndexType = SymbolTypeInference.inferType(getProgramScope(), derefAssignment.getrValue2());
|
||||
if(derefIndexType.getSizeBytes()==1) {
|
||||
// Only inline byte-based indices
|
||||
return new PointerDereferenceIndexed(derefAssignment.getrValue1(), derefAssignment.getrValue2());
|
||||
|
|
|
@ -33,7 +33,7 @@ public class Pass2LoopHeadConstantIdentification extends Pass2SsaOptimization {
|
|||
NaturalLoopSet loopSet = getProgram().getLoopSet();
|
||||
for(NaturalLoop loop : loopSet.getLoops()) {
|
||||
LabelRef loopHeadRef = loop.getHead();
|
||||
ControlFlowBlock loopHeadBlock = getGraph().getBlock(loopHeadRef);
|
||||
Graph.Block loopHeadBlock = getGraph().getBlock(loopHeadRef);
|
||||
boolean modified = optimizeLoopHead(loopHeadBlock, loop, variableReferenceInfos);
|
||||
if(modified) {
|
||||
getProgram().clearVariableReferenceInfos();
|
||||
|
@ -49,7 +49,7 @@ public class Pass2LoopHeadConstantIdentification extends Pass2SsaOptimization {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean optimizeLoopHead(ControlFlowBlock loopHeadBlock, NaturalLoop loop, VariableReferenceInfos variableReferenceInfos) {
|
||||
private boolean optimizeLoopHead(Graph.Block loopHeadBlock, NaturalLoop loop, VariableReferenceInfos variableReferenceInfos) {
|
||||
if(loopHeadBlock.getConditionalSuccessor() != null && loopHeadBlock.hasPhiBlock()) {
|
||||
// Find the variables used in the continue/end condition
|
||||
StatementConditionalJump condition = null;
|
||||
|
@ -142,7 +142,7 @@ public class Pass2LoopHeadConstantIdentification extends Pass2SsaOptimization {
|
|||
isVol.set(true);
|
||||
}
|
||||
if(programValue.get() instanceof VariableRef) {
|
||||
Variable variable = getScope().getVariable((VariableRef) programValue.get());
|
||||
Variable variable = getProgramScope().getVariable((VariableRef) programValue.get());
|
||||
if(variable.isVolatile())
|
||||
isVol.set(true);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization {
|
|||
* @param unroll The (original) blocks being unrolled
|
||||
*/
|
||||
private static void markOriginalUnrolled(BlockSet unroll, Program program) {
|
||||
for(ControlFlowBlock block : unroll.getBlocks(program.getGraph())) {
|
||||
for(var block : unroll.getBlocks(program.getGraph())) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
// - Remove the "unroll" directive on the condition in the old loop (as it is already unrolled).
|
||||
|
@ -106,7 +106,7 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization {
|
|||
private static List<NaturalLoop> findUnrollLoops(Program program) {
|
||||
NaturalLoopSet loops = program.getLoopSet();
|
||||
List<NaturalLoop> unrollLoopCandidates = new ArrayList<>();
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(var block : program.getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
if(((StatementConditionalJump) statement).isDeclaredUnroll()) {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
||||
|
||||
/**
|
||||
* Check that the unrolling of a loop was sucessfully completed.
|
||||
* Check that the unrolling of a loop was successfully completed.
|
||||
* This is done by checking that no conditional jumps exist marked as wasUnrolled.
|
||||
* Since unrolling requires the loop iteration count to be constant the conditionals must always be resolved to true or false and thus deleted or changed to jumps.
|
||||
*/
|
||||
|
@ -19,12 +17,10 @@ public class Pass2LoopUnrollAssertComplete extends Pass2SsaOptimization {
|
|||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
if(((StatementConditionalJump) statement).isWasUnrolled()) {
|
||||
throw new CompileError("Loop cannot be unrolled. Condition not resolvable to a constant true/false. ", statement);
|
||||
}
|
||||
for(var statement : getGraph().getAllStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
if(((StatementConditionalJump) statement).isWasUnrolled()) {
|
||||
throw new CompileError("Loop cannot be unrolled. Condition not resolvable to a constant true/false. ", statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class Pass2ModuloToAndRewriting extends Pass2SsaOptimization {
|
|||
*/
|
||||
private ConstantLiteral getConstantLiteral(ConstantValue constantValue) {
|
||||
try {
|
||||
return constantValue.calculateLiteral(getScope());
|
||||
return constantValue.calculateLiteral(getProgramScope());
|
||||
} catch(ConstantNotLiteral e) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ public class Pass2MultiplyToShiftRewriting extends Pass2SsaOptimization {
|
|||
@Override
|
||||
public boolean step() {
|
||||
boolean optimized = false;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
Scope scope = getScope().getScope(block.getScope());
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
Scope scope = getProgramScope().getScope(block.getScope());
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
|
@ -82,7 +82,7 @@ public class Pass2MultiplyToShiftRewriting extends Pass2SsaOptimization {
|
|||
// Multiplication by constant
|
||||
getLog().append("Rewriting multiplication to use shift and addition" + assignment.toString(getProgram(), false));
|
||||
stmtIt.previous();
|
||||
SymbolType resultType = SymbolTypeInference.inferType(getScope(), varValue);
|
||||
SymbolType resultType = SymbolTypeInference.inferType(getProgramScope(), varValue);
|
||||
long pow2 = (long) power2;
|
||||
long remains = constValue - (1L << pow2);
|
||||
RValue building = varValue;
|
||||
|
@ -150,7 +150,7 @@ public class Pass2MultiplyToShiftRewriting extends Pass2SsaOptimization {
|
|||
if(rValue instanceof ConstantValue) {
|
||||
ConstantValue constantValue = (ConstantValue) rValue;
|
||||
try {
|
||||
final ConstantLiteral constantLiteral = constantValue.calculateLiteral(getScope());
|
||||
final ConstantLiteral constantLiteral = constantValue.calculateLiteral(getProgramScope());
|
||||
if(constantLiteral instanceof ConstantInteger)
|
||||
return ((ConstantInteger) constantLiteral).getInteger();
|
||||
} catch(ConstantNotLiteral e) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
|
@ -12,8 +11,11 @@ import dk.camelot64.kickc.model.values.CastValue;
|
|||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Compiler Pass inlining cast assignments that has no effect (byte to/from signed byte, word to/from signed word)
|
||||
|
@ -40,28 +42,24 @@ public class Pass2NopCastInlining extends Pass2SsaOptimization {
|
|||
|
||||
Mode mode = null;
|
||||
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement stmt = stmtIt.next();
|
||||
if(stmt instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) stmt;
|
||||
if(stmt instanceof StatementAssignment assignment) {
|
||||
// TODO: Handle constant values?
|
||||
if(assignment.getOperator() == null && assignment.getrValue2() instanceof CastValue) {
|
||||
CastValue castValue = (CastValue) assignment.getrValue2();
|
||||
SymbolType subValType = SymbolTypeInference.inferType(getScope(), castValue.getValue());
|
||||
if(assignment.getOperator() == null && assignment.getrValue2() instanceof CastValue castValue) {
|
||||
SymbolType subValType = SymbolTypeInference.inferType(getProgramScope(), castValue.getValue());
|
||||
final SymbolType castToType = castValue.getToType();
|
||||
boolean isNopCast = isNopCast(castToType, subValType);
|
||||
if(isNopCast && assignment.getlValue() instanceof VariableRef) {
|
||||
|
||||
final Variable assignmentVar = getScope().getVariable((VariableRef) assignment.getlValue());
|
||||
final Variable assignmentVar = getProgramScope().getVariable((VariableRef) assignment.getlValue());
|
||||
if(assignmentVar.isKindLoadStore())
|
||||
continue;
|
||||
|
||||
boolean isIntermediateVar = false;
|
||||
if(castValue.getValue() instanceof VariableRef && ((VariableRef) castValue.getValue()).isIntermediate()) {
|
||||
isIntermediateVar = true;
|
||||
}
|
||||
boolean isIntermediateVar = castValue.getValue() instanceof VariableRef
|
||||
&& ((VariableRef) castValue.getValue()).isIntermediate();
|
||||
if(isIntermediateVar) {
|
||||
if(mode == null || mode == Mode.VARS) {
|
||||
mode = Mode.VARS;
|
||||
|
@ -76,7 +74,7 @@ public class Pass2NopCastInlining extends Pass2SsaOptimization {
|
|||
// 3. Delete the cast variable
|
||||
delete.add((SymbolRef) castValue.getValue());
|
||||
// Change the type of the assignment variable
|
||||
Variable castVar = getScope().getVariable((VariableRef) castValue.getValue());
|
||||
Variable castVar = getProgramScope().getVariable((VariableRef) castValue.getValue());
|
||||
// Copy type qualifiers from the variable being assigned
|
||||
SymbolType qualifiedType = castVar.getType().getQualified(assignmentVar.getType().isVolatile(), assignmentVar.getType().isNomodify());
|
||||
assignmentVar.setType(qualifiedType);
|
||||
|
@ -90,8 +88,7 @@ public class Pass2NopCastInlining extends Pass2SsaOptimization {
|
|||
while(castVal instanceof CastValue) {
|
||||
castVal = ((CastValue) castVal).getValue();
|
||||
}
|
||||
if(castVal instanceof VariableRef) {
|
||||
VariableRef castVarRef = (VariableRef) castVal;
|
||||
if(castVal instanceof VariableRef castVarRef) {
|
||||
VariableRef lValueRef = (VariableRef) assignment.getlValue();
|
||||
if(castVarRef.getScopeNames().equals(lValueRef.getScopeNames())) {
|
||||
// Same scope - optimize away
|
||||
|
@ -124,7 +121,7 @@ public class Pass2NopCastInlining extends Pass2SsaOptimization {
|
|||
// 2. Perform second replace
|
||||
replaceVariables(replace2);
|
||||
// 3. Delete unused symbols
|
||||
deleteSymbols(getScope(), delete);
|
||||
deleteSymbols(getProgramScope(), delete);
|
||||
}
|
||||
|
||||
return (replace1.size() > 0);
|
||||
|
|
|
@ -35,8 +35,8 @@ public class Pass2RangeResolving extends Pass2SsaOptimization {
|
|||
RangeValue rangeValue = (RangeValue) value;
|
||||
if(rangeValue.getRangeFirst() instanceof ConstantValue && rangeValue.getRangeLast() instanceof ConstantValue) {
|
||||
// Range value with constant first & last found - resolve it
|
||||
ConstantLiteral firstLiteral = ((ConstantValue) rangeValue.getRangeFirst()).calculateLiteral(getScope());
|
||||
ConstantLiteral lastLiteral = ((ConstantValue) rangeValue.getRangeLast()).calculateLiteral(getScope());
|
||||
ConstantLiteral firstLiteral = ((ConstantValue) rangeValue.getRangeFirst()).calculateLiteral(getProgramScope());
|
||||
ConstantLiteral lastLiteral = ((ConstantValue) rangeValue.getRangeLast()).calculateLiteral(getProgramScope());
|
||||
if(!(firstLiteral instanceof ConstantEnumerable)) {
|
||||
throw new CompileError("Ranged for() has non-integer first value in the range " + currentStmt.getSource().toString(), currentStmt);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue