mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-27 19:50:10 +00:00
Fixed almost all problems in constant loop head identification. A few program becomes infinite loops - needs fixing! A few also become way to long when rewritten - probably detect & rollback.
This commit is contained in:
parent
c63b031dbe
commit
e167f8dce8
@ -306,6 +306,8 @@ public class Compiler {
|
|||||||
optimizations.add(new PassNEliminateUnusedVars(program, true));
|
optimizations.add(new PassNEliminateUnusedVars(program, true));
|
||||||
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
||||||
optimizations.add(new PassNStatementIndices(program));
|
optimizations.add(new PassNStatementIndices(program));
|
||||||
|
optimizations.add(() -> { program.clearDominators(); return false; });
|
||||||
|
optimizations.add(() -> { program.clearLoopSet(); return false; });
|
||||||
optimizations.add(new Pass2LoopHeadConstantIdentification(program));
|
optimizations.add(new Pass2LoopHeadConstantIdentification(program));
|
||||||
return optimizations;
|
return optimizations;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public interface BlockSet {
|
|||||||
* @param graph The control flow graph containing the blocks
|
* @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.)
|
* @return The blocks of the loop (in the same order as they appear in the control flow graph.)
|
||||||
*/
|
*/
|
||||||
default public List<ControlFlowBlock> getBlocks(ControlFlowGraph graph) {
|
default List<ControlFlowBlock> getBlocks(ControlFlowGraph graph) {
|
||||||
ArrayList<ControlFlowBlock> controlFlowBlocks = new ArrayList<>();
|
ArrayList<ControlFlowBlock> controlFlowBlocks = new ArrayList<>();
|
||||||
for(ControlFlowBlock block : graph.getAllBlocks()) {
|
for(ControlFlowBlock block : graph.getAllBlocks()) {
|
||||||
if(getBlocks().contains(block.getLabel())) {
|
if(getBlocks().contains(block.getLabel())) {
|
||||||
|
@ -23,7 +23,6 @@ public class OperatorNotEqual extends OperatorBinary {
|
|||||||
} else if(left instanceof ConstantPointer && right instanceof ConstantPointer) {
|
} else if(left instanceof ConstantPointer && right instanceof ConstantPointer) {
|
||||||
return new ConstantBool(!Objects.equals(((ConstantPointer) left).getLocation(), ((ConstantPointer) right).getLocation()));
|
return new ConstantBool(!Objects.equals(((ConstantPointer) left).getLocation(), ((ConstantPointer) right).getLocation()));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new CompileError("Calculation not implemented " + left + " " + getOperator() + " " + right);
|
throw new CompileError("Calculation not implemented " + left + " " + getOperator() + " " + right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
package dk.camelot64.kickc.passes;
|
package dk.camelot64.kickc.passes;
|
||||||
|
|
||||||
|
|
||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
|
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||||
import dk.camelot64.kickc.model.statements.Statement;
|
import dk.camelot64.kickc.model.statements.Statement;
|
||||||
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
||||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||||
import dk.camelot64.kickc.model.symbols.Scope;
|
import dk.camelot64.kickc.model.symbols.Variable;
|
||||||
import dk.camelot64.kickc.model.values.ConstantValue;
|
import dk.camelot64.kickc.model.values.ConstantValue;
|
||||||
import dk.camelot64.kickc.model.values.LabelRef;
|
import dk.camelot64.kickc.model.values.LabelRef;
|
||||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
import dk.camelot64.kickc.model.values.PointerDereference;
|
||||||
import dk.camelot64.kickc.model.values.VariableRef;
|
import dk.camelot64.kickc.model.values.VariableRef;
|
||||||
|
import dk.camelot64.kickc.passes.utils.Unroller;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identify loop heads where the condition is constant when examind the first time
|
* Identify loop heads where the condition is constant when examind the first time
|
||||||
@ -31,8 +34,11 @@ public class Pass2LoopHeadConstantIdentification extends Pass2SsaOptimization {
|
|||||||
for(NaturalLoop loop : loopSet.getLoops()) {
|
for(NaturalLoop loop : loopSet.getLoops()) {
|
||||||
LabelRef loopHeadRef = loop.getHead();
|
LabelRef loopHeadRef = loop.getHead();
|
||||||
ControlFlowBlock loopHeadBlock = getGraph().getBlock(loopHeadRef);
|
ControlFlowBlock loopHeadBlock = getGraph().getBlock(loopHeadRef);
|
||||||
boolean modified = optimizeLoopHead(loopHeadBlock, loop, variableReferenceInfos);
|
//TODO: Fix remaining errors!
|
||||||
|
//boolean modified = optimizeLoopHead(loopHeadBlock, loop, variableReferenceInfos);
|
||||||
|
boolean modified = false;
|
||||||
if(modified) {
|
if(modified) {
|
||||||
|
getProgram().clearStatementInfos();
|
||||||
getProgram().clearLoopSet();
|
getProgram().clearLoopSet();
|
||||||
getProgram().clearDominators();
|
getProgram().clearDominators();
|
||||||
return true;
|
return true;
|
||||||
@ -52,7 +58,10 @@ public class Pass2LoopHeadConstantIdentification extends Pass2SsaOptimization {
|
|||||||
condition = (StatementConditionalJump) statement;
|
condition = (StatementConditionalJump) statement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(isVolatile(condition)) return false;
|
||||||
|
|
||||||
Collection<VariableRef> conditionVars = variableReferenceInfos.getUsedVars(condition);
|
Collection<VariableRef> conditionVars = variableReferenceInfos.getUsedVars(condition);
|
||||||
|
|
||||||
// Examines if they have constant values in the first iteration
|
// Examines if they have constant values in the first iteration
|
||||||
List<VariableRef> optimizeVars = new ArrayList<>();
|
List<VariableRef> optimizeVars = new ArrayList<>();
|
||||||
StatementPhiBlock phiBlock = loopHeadBlock.getPhiBlock();
|
StatementPhiBlock phiBlock = loopHeadBlock.getPhiBlock();
|
||||||
@ -82,14 +91,50 @@ public class Pass2LoopHeadConstantIdentification extends Pass2SsaOptimization {
|
|||||||
}
|
}
|
||||||
if(doOptimize) {
|
if(doOptimize) {
|
||||||
// Optimization is a good idea since the condition is completely constant when entering!
|
// Optimization is a good idea since the condition is completely constant when entering!
|
||||||
ScopeRef scopeRef = loopHeadBlock.getScope();
|
BlockSet unrollBlocks = () -> {
|
||||||
Scope scope = getScope().getScope(scopeRef);
|
LinkedHashSet<LabelRef> blocks = new LinkedHashSet<>();
|
||||||
|
blocks.add(loopHeadBlock.getLabel());
|
||||||
|
return blocks;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Copy the block and all statements - and redirect the PHI-entry to the copy!
|
// Copy the block and all statements - enter through the copy - finish through the original
|
||||||
|
Unroller.UnrollStrategy unrollStrategy = new Unroller.UnrollStrategy() {
|
||||||
|
@Override
|
||||||
|
public TransitionHandling getEntryStrategy(LabelRef from, LabelRef to) {
|
||||||
|
if(loop.getBlocks().contains(from)) {
|
||||||
|
return TransitionHandling.TO_ORIGINAL;
|
||||||
|
} else {
|
||||||
|
return TransitionHandling.TO_COPY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransitionHandling getInternalStrategy(LabelRef from, LabelRef to) {
|
||||||
|
return TransitionHandling.TO_ORIGINAL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Unroller unroller = new Unroller(getProgram(), unrollBlocks, unrollStrategy);
|
||||||
|
unroller.unroll();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean isVolatile(Statement condition) {
|
||||||
|
AtomicBoolean isVol = new AtomicBoolean(false);
|
||||||
|
ProgramValueIterator.execute(condition, (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||||
|
if(programValue.get() instanceof PointerDereference) {
|
||||||
|
isVol.set(true);
|
||||||
|
}
|
||||||
|
if(programValue.get() instanceof VariableRef) {
|
||||||
|
Variable variable = getScope().getVariable((VariableRef) programValue.get());
|
||||||
|
if(variable.isVolatile())
|
||||||
|
isVol.set(true);
|
||||||
|
}
|
||||||
|
}, null, null);
|
||||||
|
return isVol.get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,7 @@ import dk.camelot64.kickc.model.symbols.VariableIntermediate;
|
|||||||
import dk.camelot64.kickc.model.types.SymbolType;
|
import dk.camelot64.kickc.model.types.SymbolType;
|
||||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||||
import dk.camelot64.kickc.model.values.ConstantBinary;
|
import dk.camelot64.kickc.model.values.*;
|
||||||
import dk.camelot64.kickc.model.values.ConstantInteger;
|
|
||||||
import dk.camelot64.kickc.model.values.ConstantValue;
|
|
||||||
import dk.camelot64.kickc.model.values.RValue;
|
|
||||||
|
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
|
|
||||||
@ -44,7 +41,7 @@ public class PassNAddBooleanCasts extends Pass2SsaOptimization {
|
|||||||
if(SymbolType.isInteger(type) || type instanceof SymbolTypePointer) {
|
if(SymbolType.isInteger(type) || type instanceof SymbolTypePointer) {
|
||||||
// Found integer condition - add boolean cast
|
// Found integer condition - add boolean cast
|
||||||
getLog().append("Warning! Adding boolean cast to non-boolean condition "+rValue2.toString(getProgram()));
|
getLog().append("Warning! Adding boolean cast to non-boolean condition "+rValue2.toString(getProgram()));
|
||||||
VariableIntermediate tmpVar = addBooleanCast(rValue2, currentStmt, stmtIt, currentBlock);
|
VariableIntermediate tmpVar = addBooleanCast(rValue2, type, currentStmt, stmtIt, currentBlock);
|
||||||
conditionalJump.setrValue2(tmpVar.getRef());
|
conditionalJump.setrValue2(tmpVar.getRef());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,7 +58,8 @@ public class PassNAddBooleanCasts extends Pass2SsaOptimization {
|
|||||||
if(operand instanceof ConstantValue) {
|
if(operand instanceof ConstantValue) {
|
||||||
unaryExpression.setOperand(new ConstantBinary(new ConstantInteger(0L, SymbolType.NUMBER), Operators.NEQ, (ConstantValue) operand));
|
unaryExpression.setOperand(new ConstantBinary(new ConstantInteger(0L, SymbolType.NUMBER), Operators.NEQ, (ConstantValue) operand));
|
||||||
} else {
|
} else {
|
||||||
VariableIntermediate tmpVar = addBooleanCast(operand, currentStmt, stmtIt, currentBlock);
|
SymbolType type = SymbolTypeInference.inferType(getScope(), operand);
|
||||||
|
VariableIntermediate tmpVar = addBooleanCast(operand, type, currentStmt, stmtIt, currentBlock);
|
||||||
unaryExpression.setOperand(tmpVar.getRef());
|
unaryExpression.setOperand(tmpVar.getRef());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,13 +68,19 @@ public class PassNAddBooleanCasts extends Pass2SsaOptimization {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableIntermediate addBooleanCast(RValue rValue, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
public VariableIntermediate addBooleanCast(RValue rValue, SymbolType rValueType, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
||||||
Scope currentScope = getScope().getScope(currentBlock.getScope());
|
Scope currentScope = getScope().getScope(currentBlock.getScope());
|
||||||
stmtIt.previous();
|
stmtIt.previous();
|
||||||
VariableIntermediate tmpVar = currentScope.addVariableIntermediate();
|
VariableIntermediate tmpVar = currentScope.addVariableIntermediate();
|
||||||
tmpVar.setTypeInferred(SymbolType.BOOLEAN);
|
tmpVar.setTypeInferred(SymbolType.BOOLEAN);
|
||||||
// Go straight to xxx!=0 instead of casting to bool
|
// Go straight to xxx!=0 instead of casting to bool
|
||||||
stmtIt.add(new StatementAssignment(tmpVar.getRef(), new ConstantInteger(0L, SymbolType.NUMBER), Operators.NEQ, rValue, currentStmt.getSource(), Comment.NO_COMMENTS));
|
ConstantValue nullValue;
|
||||||
|
if(rValueType instanceof SymbolTypePointer) {
|
||||||
|
nullValue = new ConstantCastValue(rValueType, new ConstantInteger(0L, SymbolType.WORD));
|
||||||
|
} else {
|
||||||
|
nullValue = new ConstantInteger(0L, SymbolType.NUMBER);
|
||||||
|
}
|
||||||
|
stmtIt.add(new StatementAssignment(tmpVar.getRef(), nullValue, Operators.NEQ, rValue, currentStmt.getSource(), Comment.NO_COMMENTS));
|
||||||
stmtIt.next();
|
stmtIt.next();
|
||||||
return tmpVar;
|
return tmpVar;
|
||||||
}
|
}
|
||||||
|
@ -18,18 +18,18 @@ import java.util.*;
|
|||||||
* <p>
|
* <p>
|
||||||
* Unrolling has a number of phases
|
* Unrolling has a number of phases
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li>Prepare by ensuring that all successors of the blocks have PHI-statements for all variables defined inside the blocks </li>
|
* <li>Prepare by ensuring that all successors of the blocks have PHI-statements for all variables defined inside the blocks </li>
|
||||||
* <li>Copy all variables defined inside the blocks </li>
|
* <li>Copy all variables defined inside the blocks </li>
|
||||||
* <li>Copy all block labels</li>
|
* <li>Copy all block labels</li>
|
||||||
* <li>Copy all blocks & statements - rewriting all internal transitions in both original and copy according to a strategy.</li>
|
* <li>Copy all blocks & statements - rewriting all internal transitions in both original and copy according to a strategy.</li>
|
||||||
* <li>Patch all predecessor blocks so they hit either the original or the new copied block according to a strategy.</li>
|
* <li>Patch all predecessor blocks so they hit either the original or the new copied block according to a strategy.</li>
|
||||||
* <li>Patch all successor blocks so they are now hit by both original and copy.</li>
|
* <li>Patch all successor blocks so they are now hit by both original and copy.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
* <p>
|
* <p>
|
||||||
* The {@link UnrollStrategy} defines
|
* The {@link UnrollStrategy} defines
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li> For each block transition entering the blocks being copied - should the transition hit the original or the copy?</li>
|
* <li> For each block transition entering the blocks being copied - should the transition hit the original or the copy?</li>
|
||||||
* <li> For each block transition between two blocks being copied - should the transition be copied, always hit the original or always hit the copy?</li>
|
* <li> For each block transition between two blocks being copied - should the transition be copied, always hit the original or always hit the copy?</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class Unroller {
|
public class Unroller {
|
||||||
@ -57,6 +57,12 @@ public class Unroller {
|
|||||||
public void unroll() {
|
public void unroll() {
|
||||||
// 0. Prepare for copying by ensuring that all variables defined in the blocks are represented in PHI-blocks of the successors
|
// 0. Prepare for copying by ensuring that all variables defined in the blocks are represented in PHI-blocks of the successors
|
||||||
prepare();
|
prepare();
|
||||||
|
|
||||||
|
if(program.getLog().isVerboseSSAOptimize()) {
|
||||||
|
program.getLog().append("CONTROL FLOW GRAPH (PREPARED)");
|
||||||
|
program.getLog().append(program.getGraph().toString(program));
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Create new versions of all symbols assigned inside the loop
|
// 1. Create new versions of all symbols assigned inside the loop
|
||||||
this.varsOriginalToCopied = copyDefinedVars(unrollBlocks, program);
|
this.varsOriginalToCopied = copyDefinedVars(unrollBlocks, program);
|
||||||
// 2. Create new labels for all blocks in the loop
|
// 2. Create new labels for all blocks in the loop
|
||||||
@ -69,35 +75,71 @@ public class Unroller {
|
|||||||
* Ensure that all variables defined inside the blocks to be copied has a PHI in successor blocks.
|
* Ensure that all variables defined inside the blocks to be copied has a PHI in successor blocks.
|
||||||
*/
|
*/
|
||||||
private void prepare() {
|
private void prepare() {
|
||||||
for(VariableRef definedVarRef : getVarsDefinedIn(unrollBlocks, program)) {
|
for(VariableRef origVarRef : getVarsDefinedIn(unrollBlocks, program)) {
|
||||||
// Find out if the variable is ever referenced outside the loop
|
// Find out if the variable is ever referenced outside the loop
|
||||||
if(isReferencedOutside(definedVarRef, unrollBlocks, program)) {
|
if(isReferencedOutside(origVarRef, unrollBlocks, program)) {
|
||||||
// Add any needed PHI-statements to the successors
|
// Add any needed PHI-statements to the successors
|
||||||
for(SuccessorTransition successorTransition : getSuccessorTransitions(unrollBlocks, program.getGraph())) {
|
for(SuccessorTransition successorTransition : getSuccessorTransitions(unrollBlocks, program.getGraph())) {
|
||||||
ControlFlowBlock successorBlock = program.getGraph().getBlock(successorTransition.successor);
|
ControlFlowBlock successorBlock = program.getGraph().getBlock(successorTransition.successor);
|
||||||
StatementPhiBlock phiBlock = successorBlock.getPhiBlock();
|
StatementPhiBlock phiBlock = successorBlock.getPhiBlock();
|
||||||
// Create a new version of the variable
|
// Create a new version of the variable
|
||||||
Variable definedVar = program.getScope().getVariable(definedVarRef);
|
Variable origVar = program.getScope().getVariable(origVarRef);
|
||||||
Variable newVar = ((VariableVersion) definedVar).getVersionOf().createVersion();
|
Variable newVar;
|
||||||
// Replace all references outside the loop to the new version!
|
if(origVar instanceof VariableVersion) {
|
||||||
LinkedHashMap<SymbolRef, RValue> aliases = new LinkedHashMap<>();
|
newVar = ((VariableVersion) origVar).getVersionOf().createVersion();
|
||||||
aliases.put(definedVarRef, newVar.getRef());
|
} else {
|
||||||
ProgramValueIterator.execute(program, (programValue, currentStmt, stmtIt, currentBlock) -> {
|
newVar = origVar.getScope().addVariableIntermediate();
|
||||||
if(currentBlock != null) {
|
}
|
||||||
if(!unrollBlocks.getBlocks().contains(currentBlock.getLabel())) {
|
// Replace all references from the new phi and forward
|
||||||
new AliasReplacer(aliases).execute(programValue, currentStmt, stmtIt, currentBlock);
|
forwardReplaceAllUsages(successorTransition.successor, origVarRef, newVar.getRef(), new LinkedHashSet<>());
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Create the new phi-variable in the successor phi block
|
// Create the new phi-variable in the successor phi block
|
||||||
StatementPhiBlock.PhiVariable newPhiVar = phiBlock.addPhiVariable(newVar.getRef());
|
StatementPhiBlock.PhiVariable newPhiVar = phiBlock.addPhiVariable(newVar.getRef());
|
||||||
newPhiVar.setrValue(successorTransition.predecessor, definedVarRef);
|
newPhiVar.setrValue(successorTransition.predecessor, origVarRef);
|
||||||
program.getLog().append("Creating PHI for " + definedVarRef.getFullName() + " in block " + successorBlock.getLabel() + " - " + phiBlock.toString(program, false));
|
program.getLog().append("Creating PHI for " + origVarRef.getFullName() + " in block " + successorBlock.getLabel() + " - " + phiBlock.toString(program, false));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Introduces a new version of a variable - and replaces all uses of the old variable with the new one from a specific point in the control flow graph and forward until the old variable is defined.
|
||||||
|
* @param blockRef The block to replace the usage from
|
||||||
|
* @param origVarRef The original variable
|
||||||
|
* @param newVarRef The new variable replacing the original
|
||||||
|
* @param visited All blocks that have already been visited.
|
||||||
|
*/
|
||||||
|
private void forwardReplaceAllUsages(LabelRef blockRef, VariableRef origVarRef, VariableRef newVarRef, Set<LabelRef> visited) {
|
||||||
|
VariableReferenceInfos variableReferenceInfos = program.getVariableReferenceInfos();
|
||||||
|
LinkedHashMap<SymbolRef, RValue> aliases = new LinkedHashMap<>();
|
||||||
|
aliases.put(origVarRef, newVarRef);
|
||||||
|
AliasReplacer aliasReplacer = new AliasReplacer(aliases);
|
||||||
|
ControlFlowBlock block = program.getGraph().getBlock(blockRef);
|
||||||
|
if(block!=null) {
|
||||||
|
for(Statement statement : block.getStatements()) {
|
||||||
|
Collection<VariableRef> definedVars = variableReferenceInfos.getDefinedVars(statement);
|
||||||
|
if(definedVars!=null && definedVars.contains(origVarRef)) {
|
||||||
|
// Found definition of the original variable - don't replace any more
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Replace any usage in the statement
|
||||||
|
ProgramValueIterator.execute(statement, aliasReplacer, null, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visited.add(blockRef);
|
||||||
|
if(block!=null) {
|
||||||
|
if(block.getConditionalSuccessor() != null && !visited.contains(block.getConditionalSuccessor())) {
|
||||||
|
forwardReplaceAllUsages(block.getConditionalSuccessor(), origVarRef, newVarRef, visited);
|
||||||
|
}
|
||||||
|
if(block.getDefaultSuccessor() != null && !visited.contains(block.getDefaultSuccessor())) {
|
||||||
|
forwardReplaceAllUsages(block.getDefaultSuccessor(), origVarRef, newVarRef, visited);
|
||||||
|
}
|
||||||
|
if(block.getCallSuccessor() != null && !visited.contains(block.getCallSuccessor())) {
|
||||||
|
forwardReplaceAllUsages(block.getCallSuccessor(), origVarRef, newVarRef, visited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new versions of all symbols assigned inside some blocks to be unrolled
|
* Create new versions of all symbols assigned inside some blocks to be unrolled
|
||||||
*
|
*
|
||||||
@ -182,7 +224,7 @@ public class Unroller {
|
|||||||
|
|
||||||
// Set default successor for both new & original blocks
|
// Set default successor for both new & original blocks
|
||||||
LabelRef origSuccessor = origBlock.getDefaultSuccessor();
|
LabelRef origSuccessor = origBlock.getDefaultSuccessor();
|
||||||
if(unrollBlocks.contains(origSuccessor)) {
|
if(isInternal(origSuccessor)) {
|
||||||
// Default Successor is inside copied blocks - Use strategy to find default successors
|
// Default Successor is inside copied blocks - Use strategy to find default successors
|
||||||
UnrollStrategy.TransitionHandling handling = strategy.getInternalStrategy(origBlock.getLabel(), origSuccessor);
|
UnrollStrategy.TransitionHandling handling = strategy.getInternalStrategy(origBlock.getLabel(), origSuccessor);
|
||||||
if(UnrollStrategy.TransitionHandling.TO_COPY.equals(handling)) {
|
if(UnrollStrategy.TransitionHandling.TO_COPY.equals(handling)) {
|
||||||
@ -208,8 +250,8 @@ public class Unroller {
|
|||||||
|
|
||||||
// Examine whether conditional successor is external
|
// Examine whether conditional successor is external
|
||||||
LabelRef origConditionalSuccessor = origBlock.getConditionalSuccessor();
|
LabelRef origConditionalSuccessor = origBlock.getConditionalSuccessor();
|
||||||
if(origConditionalSuccessor !=null) {
|
if(origConditionalSuccessor != null) {
|
||||||
if(!unrollBlocks.contains(origConditionalSuccessor)) {
|
if(!isInternal(origConditionalSuccessor)) {
|
||||||
// Update the PHI blocks of the external conditional successor to also get values from the copied PHI block
|
// Update the PHI blocks of the external conditional successor to also get values from the copied PHI block
|
||||||
patchSuccessorBlockPhi(origConditionalSuccessor, origBlock.getLabel(), newBlockLabel);
|
patchSuccessorBlockPhi(origConditionalSuccessor, origBlock.getLabel(), newBlockLabel);
|
||||||
}
|
}
|
||||||
@ -218,11 +260,23 @@ public class Unroller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a block is one of the blovks being copied (original or copy)
|
||||||
|
*
|
||||||
|
* @param block The block to examine
|
||||||
|
* @return true if the block is one of the blocks being copied
|
||||||
|
*/
|
||||||
|
private boolean isInternal(LabelRef block) {
|
||||||
|
return unrollBlocks.contains(block) || blocksOriginalToCopied.values().contains(block);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch the PHI-block of an external successor block. Ensures that the PHI-block also receives data from the new coped block.
|
* Patch the PHI-block of an external successor block. Ensures that the PHI-block also receives data from the new coped block.
|
||||||
|
*
|
||||||
* @param successor The successor block's label
|
* @param successor The successor block's label
|
||||||
* @param origBlock The label of the original block
|
* @param origBlock The label of the original block
|
||||||
* @param newBlock The label of the newly created copy
|
* @param newBlock The label of the newly created copy
|
||||||
*/
|
*/
|
||||||
private void patchSuccessorBlockPhi(LabelRef successor, LabelRef origBlock, LabelRef newBlock) {
|
private void patchSuccessorBlockPhi(LabelRef successor, LabelRef origBlock, LabelRef newBlock) {
|
||||||
ControlFlowBlock successorBlock = program.getGraph().getBlock(successor);
|
ControlFlowBlock successorBlock = program.getGraph().getBlock(successor);
|
||||||
@ -275,8 +329,9 @@ public class Unroller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a copy of a conditional jump statement. Also updates the original conditional jump if specified by the strategy.
|
* Create a copy of a conditional jump statement. Also updates the original conditional jump if specified by the strategy.
|
||||||
|
*
|
||||||
* @param origConditional The original conditional jump
|
* @param origConditional The original conditional jump
|
||||||
* @param origBlock The block containing the original PHI statement
|
* @param origBlock The block containing the original PHI statement
|
||||||
* @return The new copied conditional jump statement.
|
* @return The new copied conditional jump statement.
|
||||||
*/
|
*/
|
||||||
private Statement unrollStatementConditionalJump(StatementConditionalJump origConditional, LabelRef origBlock) {
|
private Statement unrollStatementConditionalJump(StatementConditionalJump origConditional, LabelRef origBlock) {
|
||||||
@ -292,7 +347,7 @@ public class Unroller {
|
|||||||
newConditional.setDeclaredUnroll(origConditional.isDeclaredUnroll());
|
newConditional.setDeclaredUnroll(origConditional.isDeclaredUnroll());
|
||||||
// Then make sure the destination is correct in both the original and copy
|
// Then make sure the destination is correct in both the original and copy
|
||||||
LabelRef origSuccessor = origConditional.getDestination();
|
LabelRef origSuccessor = origConditional.getDestination();
|
||||||
if(unrollBlocks.contains(origSuccessor)) {
|
if(isInternal(origSuccessor)) {
|
||||||
// Successor is inside the copied blocks!
|
// Successor is inside the copied blocks!
|
||||||
UnrollStrategy.TransitionHandling handling = strategy.getInternalStrategy(origBlock, origSuccessor);
|
UnrollStrategy.TransitionHandling handling = strategy.getInternalStrategy(origBlock, origSuccessor);
|
||||||
if(UnrollStrategy.TransitionHandling.TO_COPY.equals(handling)) {
|
if(UnrollStrategy.TransitionHandling.TO_COPY.equals(handling)) {
|
||||||
@ -317,8 +372,9 @@ public class Unroller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a copy of a PHI-statement. Also updates the original PHI-statement if specified by the strategy.
|
* Create a copy of a PHI-statement. Also updates the original PHI-statement if specified by the strategy.
|
||||||
|
*
|
||||||
* @param origPhiBlock The original PHI statement
|
* @param origPhiBlock The original PHI statement
|
||||||
* @param origBlock The block containing the original PHI statement
|
* @param origBlock The block containing the original PHI statement
|
||||||
* @return The new copied PH statement.
|
* @return The new copied PH statement.
|
||||||
*/
|
*/
|
||||||
private Statement unrollStatementPhi(StatementPhiBlock origPhiBlock, LabelRef origBlock) {
|
private Statement unrollStatementPhi(StatementPhiBlock origPhiBlock, LabelRef origBlock) {
|
||||||
@ -332,7 +388,7 @@ public class Unroller {
|
|||||||
while(origPhiRValuesIt.hasNext()) {
|
while(origPhiRValuesIt.hasNext()) {
|
||||||
StatementPhiBlock.PhiRValue origPhiRValue = origPhiRValuesIt.next();
|
StatementPhiBlock.PhiRValue origPhiRValue = origPhiRValuesIt.next();
|
||||||
LabelRef predecessor = origPhiRValue.getPredecessor();
|
LabelRef predecessor = origPhiRValue.getPredecessor();
|
||||||
if(unrollBlocks.contains(predecessor)) {
|
if(isInternal(predecessor)) {
|
||||||
// Predecessor is inside the loop
|
// Predecessor is inside the loop
|
||||||
UnrollStrategy.TransitionHandling handling = strategy.getInternalStrategy(predecessor, origBlock);
|
UnrollStrategy.TransitionHandling handling = strategy.getInternalStrategy(predecessor, origBlock);
|
||||||
if(UnrollStrategy.TransitionHandling.TO_COPY.equals(handling)) {
|
if(UnrollStrategy.TransitionHandling.TO_COPY.equals(handling)) {
|
||||||
|
@ -46,7 +46,6 @@ public class TestPrograms {
|
|||||||
compileAndCompare("global-pc-multiple");
|
compileAndCompare("global-pc-multiple");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStructPosFill() throws IOException, URISyntaxException {
|
public void testStructPosFill() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("struct-pos-fill");
|
compileAndCompare("struct-pos-fill");
|
||||||
@ -2515,7 +2514,7 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoopWhileMin() throws IOException, URISyntaxException {
|
public void testLoopWhileMin() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("loop-while-min", log().verboseLoopAnalysis());
|
compileAndCompare("loop-while-min");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -69,10 +69,6 @@ Successful SSA optimization Pass2ConditionalJumpSimplification
|
|||||||
Constant (const byte*) SCREEN#0 = (byte*) 1024
|
Constant (const byte*) SCREEN#0 = (byte*) 1024
|
||||||
Constant (const byte) main::i#0 = 0
|
Constant (const byte) main::i#0 = 0
|
||||||
Successful SSA optimization Pass2ConstantIdentification
|
Successful SSA optimization Pass2ConstantIdentification
|
||||||
Found back edge: Loop head: main::@1 tails: main::@2 blocks: null
|
|
||||||
Populated: Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1
|
|
||||||
Found back edge: Loop head: main::@1 tails: main::@2 blocks: null
|
|
||||||
Populated: Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1
|
|
||||||
Inlining constant with var siblings (const byte) main::i#0
|
Inlining constant with var siblings (const byte) main::i#0
|
||||||
Constant inlined main::i#0 = (byte) 0
|
Constant inlined main::i#0 = (byte) 0
|
||||||
Successful SSA optimization Pass2ConstantInlining
|
Successful SSA optimization Pass2ConstantInlining
|
||||||
@ -118,26 +114,6 @@ main::@2: scope:[main] from main::@1
|
|||||||
[9] (byte) main::i#1 ← ++ (byte) main::i#2
|
[9] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||||
to:main::@1
|
to:main::@1
|
||||||
|
|
||||||
DOMINATORS
|
|
||||||
@begin dominated by @begin
|
|
||||||
@1 dominated by @1 @begin
|
|
||||||
@end dominated by @1 @begin @end
|
|
||||||
main dominated by @1 @begin main
|
|
||||||
main::@1 dominated by @1 @begin main::@1 main
|
|
||||||
main::@return dominated by main::@return @1 @begin main::@1 main
|
|
||||||
main::@2 dominated by @1 @begin main::@1 main::@2 main
|
|
||||||
|
|
||||||
NATURAL LOOPS
|
|
||||||
Found back edge: Loop head: main::@1 tails: main::@2 blocks: null
|
|
||||||
Populated: Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1
|
|
||||||
Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1
|
|
||||||
|
|
||||||
NATURAL LOOPS WITH DEPTH
|
|
||||||
Found 0 loops in scope []
|
|
||||||
Found 1 loops in scope [main]
|
|
||||||
Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1
|
|
||||||
Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 depth: 1
|
|
||||||
|
|
||||||
|
|
||||||
VARIABLE REGISTER WEIGHTS
|
VARIABLE REGISTER WEIGHTS
|
||||||
(byte*) SCREEN
|
(byte*) SCREEN
|
||||||
|
@ -18,7 +18,7 @@ main: scope:[main] from @1
|
|||||||
main::@1: scope:[main] from main main::@2
|
main::@1: scope:[main] from main main::@2
|
||||||
[10] (byte) main::idx#5 ← phi( main/(byte) 0 main::@2/(byte) main::idx#4 )
|
[10] (byte) main::idx#5 ← phi( main/(byte) 0 main::@2/(byte) main::idx#4 )
|
||||||
[10] (struct Entry*) main::entry#2 ← phi( main/(const struct Entry*) ENTRIES#0 main::@2/(struct Entry*) main::entry#1 )
|
[10] (struct Entry*) main::entry#2 ← phi( main/(const struct Entry*) ENTRIES#0 main::@2/(struct Entry*) main::entry#1 )
|
||||||
[11] if((byte) 0!=(struct Entry*) main::entry#2) goto main::@2
|
[11] if((struct Entry*)(word) 0!=(struct Entry*) main::entry#2) goto main::@2
|
||||||
to:main::@return
|
to:main::@return
|
||||||
main::@return: scope:[main] from main::@1
|
main::@return: scope:[main] from main::@1
|
||||||
[12] return
|
[12] return
|
||||||
|
@ -49,7 +49,7 @@ main: scope:[main] from @1
|
|||||||
main::@1: scope:[main] from main main::@2
|
main::@1: scope:[main] from main main::@2
|
||||||
(byte) main::idx#6 ← phi( main/(byte) main::idx#0 main::@2/(byte) main::idx#4 )
|
(byte) main::idx#6 ← phi( main/(byte) main::idx#0 main::@2/(byte) main::idx#4 )
|
||||||
(struct Entry*) main::entry#2 ← phi( main/(struct Entry*) main::entry#0 main::@2/(struct Entry*) main::entry#1 )
|
(struct Entry*) main::entry#2 ← phi( main/(struct Entry*) main::entry#0 main::@2/(struct Entry*) main::entry#1 )
|
||||||
(bool~) main::$17 ← (number) 0 != (struct Entry*) main::entry#2
|
(bool~) main::$17 ← (struct Entry*)(word) 0 != (struct Entry*) main::entry#2
|
||||||
if((bool~) main::$17) goto main::@2
|
if((bool~) main::$17) goto main::@2
|
||||||
to:main::@return
|
to:main::@return
|
||||||
main::@2: scope:[main] from main::@1
|
main::@2: scope:[main] from main::@1
|
||||||
@ -146,7 +146,6 @@ Adding number conversion cast (unumber) 1 in *((byte*) main::$8) ← (number) 1
|
|||||||
Adding number conversion cast (unumber) 2 in *((byte*) main::$10) ← (number) 2
|
Adding number conversion cast (unumber) 2 in *((byte*) main::$10) ← (number) 2
|
||||||
Adding number conversion cast (unumber) 3 in *((byte*) main::$12) ← (number) 3
|
Adding number conversion cast (unumber) 3 in *((byte*) main::$12) ← (number) 3
|
||||||
Adding number conversion cast (unumber) 0 in (byte) main::idx#0 ← (number) 0
|
Adding number conversion cast (unumber) 0 in (byte) main::idx#0 ← (number) 0
|
||||||
Adding number conversion cast (unumber) 0 in (bool~) main::$17 ← (number) 0 != (struct Entry*) main::entry#2
|
|
||||||
Successful SSA optimization PassNAddNumberTypeConversions
|
Successful SSA optimization PassNAddNumberTypeConversions
|
||||||
Inlining cast (struct Entry*) ENTRIES#0 ← (struct Entry*)(number) $1000
|
Inlining cast (struct Entry*) ENTRIES#0 ← (struct Entry*)(number) $1000
|
||||||
Inlining cast *((byte*) main::$8) ← (unumber)(number) 1
|
Inlining cast *((byte*) main::$8) ← (unumber)(number) 1
|
||||||
@ -165,7 +164,6 @@ Simplifying constant pointer cast (struct Entry*) 0
|
|||||||
Simplifying constant integer cast 3
|
Simplifying constant integer cast 3
|
||||||
Simplifying constant pointer cast (byte*) 1024
|
Simplifying constant pointer cast (byte*) 1024
|
||||||
Simplifying constant integer cast 0
|
Simplifying constant integer cast 0
|
||||||
Simplifying constant integer cast 0
|
|
||||||
Successful SSA optimization PassNCastSimplification
|
Successful SSA optimization PassNCastSimplification
|
||||||
Finalized unsigned number type (byte) 1
|
Finalized unsigned number type (byte) 1
|
||||||
Finalized unsigned number type (byte) 2
|
Finalized unsigned number type (byte) 2
|
||||||
@ -173,7 +171,6 @@ Finalized unsigned number type (byte) 1
|
|||||||
Finalized unsigned number type (byte) 2
|
Finalized unsigned number type (byte) 2
|
||||||
Finalized unsigned number type (byte) 3
|
Finalized unsigned number type (byte) 3
|
||||||
Finalized unsigned number type (byte) 0
|
Finalized unsigned number type (byte) 0
|
||||||
Finalized unsigned number type (byte) 0
|
|
||||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||||
Inferred type updated to byte in (unumber~) main::$5 ← (byte) 1 * (const byte) SIZEOF_STRUCT_ENTRY
|
Inferred type updated to byte in (unumber~) main::$5 ← (byte) 1 * (const byte) SIZEOF_STRUCT_ENTRY
|
||||||
Inferred type updated to byte in (unumber~) main::$6 ← (byte) 2 * (const byte) SIZEOF_STRUCT_ENTRY
|
Inferred type updated to byte in (unumber~) main::$6 ← (byte) 2 * (const byte) SIZEOF_STRUCT_ENTRY
|
||||||
@ -182,7 +179,7 @@ Alias (struct Entry*) main::entry2#0 = (struct Entry*~) main::$1
|
|||||||
Alias (struct Entry*) main::entry#2 = (struct Entry*) main::entry#3
|
Alias (struct Entry*) main::entry#2 = (struct Entry*) main::entry#3
|
||||||
Alias (byte) main::idx#5 = (byte) main::idx#6
|
Alias (byte) main::idx#5 = (byte) main::idx#6
|
||||||
Successful SSA optimization Pass2AliasElimination
|
Successful SSA optimization Pass2AliasElimination
|
||||||
Simple Condition (bool~) main::$17 [25] if((byte) 0!=(struct Entry*) main::entry#2) goto main::@2
|
Simple Condition (bool~) main::$17 [25] if((struct Entry*)(word) 0!=(struct Entry*) main::entry#2) goto main::@2
|
||||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||||
Constant right-side identified [2] (byte~) main::$5 ← (byte) 1 * (const byte) SIZEOF_STRUCT_ENTRY
|
Constant right-side identified [2] (byte~) main::$5 ← (byte) 1 * (const byte) SIZEOF_STRUCT_ENTRY
|
||||||
Constant right-side identified [5] (byte~) main::$6 ← (byte) 2 * (const byte) SIZEOF_STRUCT_ENTRY
|
Constant right-side identified [5] (byte~) main::$6 ← (byte) 2 * (const byte) SIZEOF_STRUCT_ENTRY
|
||||||
@ -291,7 +288,7 @@ main: scope:[main] from @1
|
|||||||
main::@1: scope:[main] from main main::@2
|
main::@1: scope:[main] from main main::@2
|
||||||
[10] (byte) main::idx#5 ← phi( main/(byte) 0 main::@2/(byte) main::idx#4 )
|
[10] (byte) main::idx#5 ← phi( main/(byte) 0 main::@2/(byte) main::idx#4 )
|
||||||
[10] (struct Entry*) main::entry#2 ← phi( main/(const struct Entry*) ENTRIES#0 main::@2/(struct Entry*) main::entry#1 )
|
[10] (struct Entry*) main::entry#2 ← phi( main/(const struct Entry*) ENTRIES#0 main::@2/(struct Entry*) main::entry#1 )
|
||||||
[11] if((byte) 0!=(struct Entry*) main::entry#2) goto main::@2
|
[11] if((struct Entry*)(word) 0!=(struct Entry*) main::entry#2) goto main::@2
|
||||||
to:main::@return
|
to:main::@return
|
||||||
main::@return: scope:[main] from main::@1
|
main::@return: scope:[main] from main::@1
|
||||||
[12] return
|
[12] return
|
||||||
@ -439,7 +436,7 @@ main: {
|
|||||||
jmp b1
|
jmp b1
|
||||||
// main::@1
|
// main::@1
|
||||||
b1:
|
b1:
|
||||||
// [11] if((byte) 0!=(struct Entry*) main::entry#2) goto main::@2 -- vwuc1_neq_pssz1_then_la1
|
// [11] if((struct Entry*)(word) 0!=(struct Entry*) main::entry#2) goto main::@2 -- pssc1_neq_pssz1_then_la1
|
||||||
lda entry+1
|
lda entry+1
|
||||||
cmp #>0
|
cmp #>0
|
||||||
bne b2
|
bne b2
|
||||||
@ -523,7 +520,7 @@ Statement [6] *((struct Entry**)(const struct Entry*) main::entry2#0+(const byte
|
|||||||
Statement [7] *((byte*)(const struct Entry*) main::entry2#0) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
Statement [7] *((byte*)(const struct Entry*) main::entry2#0) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||||
Statement [8] *((struct Entry**)(const struct Entry*) main::entry1#0+(const byte) OFFSET_STRUCT_ENTRY_NEXT) ← (struct Entry*) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
Statement [8] *((struct Entry**)(const struct Entry*) main::entry1#0+(const byte) OFFSET_STRUCT_ENTRY_NEXT) ← (struct Entry*) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||||
Statement [9] *((byte*)(const struct Entry*) main::entry1#0) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
Statement [9] *((byte*)(const struct Entry*) main::entry1#0) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||||
Statement [11] if((byte) 0!=(struct Entry*) main::entry#2) goto main::@2 [ main::entry#2 main::idx#5 ] ( main:2 [ main::entry#2 main::idx#5 ] ) always clobbers reg byte a
|
Statement [11] if((struct Entry*)(word) 0!=(struct Entry*) main::entry#2) goto main::@2 [ main::entry#2 main::idx#5 ] ( main:2 [ main::entry#2 main::idx#5 ] ) always clobbers reg byte a
|
||||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::idx#5 main::idx#4 ]
|
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::idx#5 main::idx#4 ]
|
||||||
Statement [13] (byte~) main::$2 ← (byte) '0' + *((byte*)(struct Entry*) main::entry#2) [ main::entry#2 main::idx#5 main::$2 ] ( main:2 [ main::entry#2 main::idx#5 main::$2 ] ) always clobbers reg byte a reg byte y
|
Statement [13] (byte~) main::$2 ← (byte) '0' + *((byte*)(struct Entry*) main::entry#2) [ main::entry#2 main::idx#5 main::$2 ] ( main:2 [ main::entry#2 main::idx#5 main::$2 ] ) always clobbers reg byte a reg byte y
|
||||||
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ main::idx#5 main::idx#4 ]
|
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ main::idx#5 main::idx#4 ]
|
||||||
@ -542,7 +539,7 @@ Statement [6] *((struct Entry**)(const struct Entry*) main::entry2#0+(const byte
|
|||||||
Statement [7] *((byte*)(const struct Entry*) main::entry2#0) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
Statement [7] *((byte*)(const struct Entry*) main::entry2#0) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||||
Statement [8] *((struct Entry**)(const struct Entry*) main::entry1#0+(const byte) OFFSET_STRUCT_ENTRY_NEXT) ← (struct Entry*) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
Statement [8] *((struct Entry**)(const struct Entry*) main::entry1#0+(const byte) OFFSET_STRUCT_ENTRY_NEXT) ← (struct Entry*) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||||
Statement [9] *((byte*)(const struct Entry*) main::entry1#0) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
Statement [9] *((byte*)(const struct Entry*) main::entry1#0) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||||
Statement [11] if((byte) 0!=(struct Entry*) main::entry#2) goto main::@2 [ main::entry#2 main::idx#5 ] ( main:2 [ main::entry#2 main::idx#5 ] ) always clobbers reg byte a
|
Statement [11] if((struct Entry*)(word) 0!=(struct Entry*) main::entry#2) goto main::@2 [ main::entry#2 main::idx#5 ] ( main:2 [ main::entry#2 main::idx#5 ] ) always clobbers reg byte a
|
||||||
Statement [13] (byte~) main::$2 ← (byte) '0' + *((byte*)(struct Entry*) main::entry#2) [ main::entry#2 main::idx#5 main::$2 ] ( main:2 [ main::entry#2 main::idx#5 main::$2 ] ) always clobbers reg byte a reg byte y
|
Statement [13] (byte~) main::$2 ← (byte) '0' + *((byte*)(struct Entry*) main::entry#2) [ main::entry#2 main::idx#5 main::$2 ] ( main:2 [ main::entry#2 main::idx#5 main::$2 ] ) always clobbers reg byte a reg byte y
|
||||||
Statement [16] (byte~) main::$3 ← < *((struct Entry**)(struct Entry*) main::entry#2 + (const byte) OFFSET_STRUCT_ENTRY_NEXT) [ main::entry#2 main::idx#1 main::$3 ] ( main:2 [ main::entry#2 main::idx#1 main::$3 ] ) always clobbers reg byte a reg byte y
|
Statement [16] (byte~) main::$3 ← < *((struct Entry**)(struct Entry*) main::entry#2 + (const byte) OFFSET_STRUCT_ENTRY_NEXT) [ main::entry#2 main::idx#1 main::$3 ] ( main:2 [ main::entry#2 main::idx#1 main::$3 ] ) always clobbers reg byte a reg byte y
|
||||||
Statement [19] (byte~) main::$4 ← > *((struct Entry**)(struct Entry*) main::entry#2 + (const byte) OFFSET_STRUCT_ENTRY_NEXT) [ main::entry#2 main::idx#2 main::$4 ] ( main:2 [ main::entry#2 main::idx#2 main::$4 ] ) always clobbers reg byte a reg byte y
|
Statement [19] (byte~) main::$4 ← > *((struct Entry**)(struct Entry*) main::entry#2 + (const byte) OFFSET_STRUCT_ENTRY_NEXT) [ main::entry#2 main::idx#2 main::$4 ] ( main:2 [ main::entry#2 main::idx#2 main::$4 ] ) always clobbers reg byte a reg byte y
|
||||||
@ -641,7 +638,7 @@ main: {
|
|||||||
jmp b1
|
jmp b1
|
||||||
// main::@1
|
// main::@1
|
||||||
b1:
|
b1:
|
||||||
// [11] if((byte) 0!=(struct Entry*) main::entry#2) goto main::@2 -- vwuc1_neq_pssz1_then_la1
|
// [11] if((struct Entry*)(word) 0!=(struct Entry*) main::entry#2) goto main::@2 -- pssc1_neq_pssz1_then_la1
|
||||||
lda entry+1
|
lda entry+1
|
||||||
cmp #>0
|
cmp #>0
|
||||||
bne b2
|
bne b2
|
||||||
@ -833,7 +830,7 @@ main: {
|
|||||||
// main::@1
|
// main::@1
|
||||||
b1:
|
b1:
|
||||||
// while(entry)
|
// while(entry)
|
||||||
// [11] if((byte) 0!=(struct Entry*) main::entry#2) goto main::@2 -- vwuc1_neq_pssz1_then_la1
|
// [11] if((struct Entry*)(word) 0!=(struct Entry*) main::entry#2) goto main::@2 -- pssc1_neq_pssz1_then_la1
|
||||||
lda entry+1
|
lda entry+1
|
||||||
cmp #>0
|
cmp #>0
|
||||||
bne b2
|
bne b2
|
||||||
|
Loading…
Reference in New Issue
Block a user