Merge branch '815-procedure-compilation' into 'master'

More procedure compilation

Closes #815

See merge request camelot/kickc!44
This commit is contained in:
Jesper Balman Gravgaard 2023-05-21 17:24:27 +00:00
commit f759c5c9c1
211 changed files with 6948 additions and 3979 deletions

View File

@ -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());
}

View File

@ -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());

View File

@ -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 =

View File

@ -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());
}
/**

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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));

View File

@ -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) {

View File

@ -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;

View File

@ -20,4 +20,6 @@ public interface Symbol extends Value {
int getScopeDepth();
SymbolRef getRef();
Procedure getContainingProcedure();
}

View File

@ -531,6 +531,11 @@ public class Variable implements Symbol {
return false;
}
@Override
public Procedure getContainingProcedure() {
return scope.getContainingProcedure();
}
public boolean isDeclarationOnly() {
return declarationOnly;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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());
}
}
}

View File

@ -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);
}

View File

@ -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());
}
}
}

View File

@ -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()));
}

View File

@ -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);
}
}
}

View File

@ -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())) {

View File

@ -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) {

View File

@ -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());
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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());
}

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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());

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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) {

View File

@ -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());
}
}

View File

@ -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");
}
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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()) {

View File

@ -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())

View File

@ -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;
}

View File

@ -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();

View File

@ -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));
}
}

View File

@ -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) {

View File

@ -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());
}

View File

@ -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);

View File

@ -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());

View File

@ -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()));

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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));
}
}
}

View File

@ -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()))

View File

@ -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) {

View File

@ -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) {

View File

@ -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());

View File

@ -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());

View File

@ -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());

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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())) {

View File

@ -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);
}
}
}

View File

@ -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(); }
}

View File

@ -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)));
}
}
}

View File

@ -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();

View File

@ -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()) {

View File

@ -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());
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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());

View File

@ -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
*

View File

@ -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<>();

View File

@ -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)

View File

@ -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) {

View File

@ -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++;

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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()) {

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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