mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-26 12:49:21 +00:00
Fixed passing of value lists as return values. Fixed problems with clobbering in return/call return value fetch.
This commit is contained in:
parent
2427720581
commit
2c177dd45f
@ -1,4 +0,0 @@
|
||||
lda #<{c2}
|
||||
sta {c1}
|
||||
lda #>{c2}
|
||||
sta {c1}+1
|
@ -1,4 +0,0 @@
|
||||
lda #<{c2}
|
||||
sta {c1}
|
||||
lda #>{c2}
|
||||
sta {c1}+1
|
@ -265,6 +265,8 @@ public class Compiler {
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
|
||||
new Pass1ProcedureCallParameters(program).generate();
|
||||
//getLog().append("CONTROL FLOW GRAPH (BEFORE LIST UNWINDING)");
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
new PassNUnwindLValueLists(program).execute();
|
||||
//new Pass1PointifyMemoryVariables(program).execute();
|
||||
|
||||
@ -277,6 +279,8 @@ public class Compiler {
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
|
||||
program.setGraph(new Pass1ProcedureCallsReturnValue(program).generate());
|
||||
//getLog().append("CONTROL FLOW GRAPH (BEFORE LIST UNWINDING)");
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
new PassNUnwindLValueLists(program).execute();
|
||||
|
||||
getLog().append("\nCONTROL FLOW GRAPH SSA");
|
||||
|
@ -5,7 +5,6 @@ import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.values.RangeValue;
|
||||
import dk.camelot64.kickc.model.values.Value;
|
||||
import dk.camelot64.kickc.model.values.ValueList;
|
||||
|
||||
/**
|
||||
* Assert that all intermediate RValues in the code have been replaced in pass 2.
|
||||
@ -23,14 +22,6 @@ public class Pass3AssertRValues extends Pass2SsaAssertion {
|
||||
public void check() throws AssertionFailed {
|
||||
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
Value value = programValue.get();
|
||||
if(value instanceof ValueList) {
|
||||
throw new InternalError(
|
||||
"Error! Value list not resolved to word constructor or array initializer" +
|
||||
"\n value list: " + value.toString(getProgram()) +
|
||||
"\n statement: " + currentStmt.toString(getProgram(), false)
|
||||
, currentStmt.getSource()
|
||||
);
|
||||
}
|
||||
if(value instanceof RangeValue) {
|
||||
throw new InternalError(
|
||||
"Error! Ranged for() not resolved to constants" +
|
||||
|
@ -4,12 +4,11 @@ import dk.camelot64.kickc.asm.AsmChunk;
|
||||
import dk.camelot64.kickc.asm.AsmClobber;
|
||||
import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCallPrepare;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.ValueList;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -85,37 +84,62 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
|
||||
PhiTransitions phiTransitions = programPhiTransitions.get(statementBlock.getLabel());
|
||||
PhiTransitions.PhiTransition phiTransition = phiTransitions.getTransition(phiTransitionId);
|
||||
for(PhiTransitions.PhiTransition.PhiAssignment phiAssignment : phiTransition.getAssignments()) {
|
||||
if(phiAssignment.getAssignmentIdx() != transitionAssignmentIdx) {
|
||||
// Only the current transition var is assigned
|
||||
VariableRef assignedVar = phiAssignment.getVariable();
|
||||
assignedVars.remove(assignedVar);
|
||||
}
|
||||
if(phiAssignment.getAssignmentIdx() > transitionAssignmentIdx) {
|
||||
// IF the assignment is later than the current one
|
||||
// For all assignments later than the current one - add referenced vars to alive
|
||||
RValue rValue = phiAssignment.getrValue();
|
||||
Collection<VariableRef> alive = VariableReferenceInfos.getReferencedVars(rValue);
|
||||
aliveVars.addAll(alive);
|
||||
VariableRef assignedVar = phiAssignment.getVariable();
|
||||
assignedVars.remove(assignedVar);
|
||||
alive.remove(assignedVar);
|
||||
} else if(phiAssignment.getAssignmentIdx() < transitionAssignmentIdx) {
|
||||
// IF the assignment is before the current one
|
||||
VariableRef assignedVar = phiAssignment.getVariable();
|
||||
assignedVars.remove(assignedVar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the chunk is an call parameter prepare, examine the later call parameter prepares and update alive variables
|
||||
if(statement instanceof StatementCallPrepare && asmChunk.getSubStatementId() != null && asmChunk.getSubStatementIdx() != null) {
|
||||
int transitionAssignmentIdx = asmChunk.getSubStatementIdx();
|
||||
int parameterIdx = asmChunk.getSubStatementIdx();
|
||||
final StatementCallPrepare callPrepare = (StatementCallPrepare) statement;
|
||||
final int numParameters = callPrepare.getNumParameters();
|
||||
for(int idx = 0; idx < numParameters; idx++) {
|
||||
for(int idx = parameterIdx + 1; idx < numParameters; idx++) {
|
||||
// For parameter prepares later than the current one - add referenced to alive
|
||||
final RValue parameter = callPrepare.getParameter(idx);
|
||||
if(idx > transitionAssignmentIdx) {
|
||||
// If the parameter prepare is later than the current one
|
||||
Collection<VariableRef> alive = VariableReferenceInfos.getReferencedVars(parameter);
|
||||
aliveVars.addAll(alive);
|
||||
Collection<VariableRef> alive = VariableReferenceInfos.getReferencedVars(parameter);
|
||||
aliveVars.addAll(alive);
|
||||
}
|
||||
}
|
||||
|
||||
// If the chunk is call finalize with a value list LValue, examine the LValue assigns and update alive variables
|
||||
if(statement instanceof StatementCallFinalize && asmChunk.getSubStatementId() != null && asmChunk.getSubStatementIdx() != null) {
|
||||
int memberIdx = asmChunk.getSubStatementIdx();
|
||||
final StatementCallFinalize stmtCallFinalize = (StatementCallFinalize) statement;
|
||||
final List<RValue> lValues = ((ValueList)stmtCallFinalize.getlValue()).getList();
|
||||
final int numLValues = lValues.size();
|
||||
for(int idx = 0; idx < numLValues; idx++) {
|
||||
if(idx != memberIdx) {
|
||||
// Only the current transition var is assigned
|
||||
final VariableRef assignedVar = (VariableRef) lValues.get(idx);
|
||||
assignedVars.remove(assignedVar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the chunk is call with a value list LValue, examine the later LValue assigns and update alive variables
|
||||
if(statement instanceof StatementReturn && asmChunk.getSubStatementId() != null && asmChunk.getSubStatementIdx() != null) {
|
||||
int memberIdx = asmChunk.getSubStatementIdx();
|
||||
final StatementReturn stmtReturn = (StatementReturn) statement;
|
||||
final List<RValue> returnValues = ((ValueList) stmtReturn.getValue()).getList();
|
||||
final int numReturnValues = returnValues.size();
|
||||
for(int idx = memberIdx + 1; idx < numReturnValues; idx++) {
|
||||
// Add all referenced vars in later return values to alive
|
||||
final RValue returnValue = returnValues.get(idx);
|
||||
Collection<VariableRef> alive = VariableReferenceInfos.getReferencedVars(returnValue);
|
||||
aliveVars.addAll(alive);
|
||||
}
|
||||
}
|
||||
|
||||
// Non-assigned alive variables must not be clobbered
|
||||
for(VariableRef aliveVar : aliveVars) {
|
||||
Variable variable = getProgram().getSymbolInfos().getVariable(aliveVar);
|
||||
|
@ -896,12 +896,33 @@ public class Pass4CodeGeneration {
|
||||
}
|
||||
// Pull result from the stack
|
||||
if(call.getlValue() != null) {
|
||||
if(stackCleanBytes>0)
|
||||
if(stackCleanBytes > 0)
|
||||
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
||||
SymbolType returnType = procedure.getReturnType();
|
||||
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(call.getlValue(), new StackPullValue(returnType), program, block.getScope());
|
||||
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
||||
boolean isValueListStruct = (call.getlValue() instanceof ValueList) && (procedure.getReturnType() instanceof SymbolTypeStruct);
|
||||
if(!isValueListStruct) {
|
||||
// Simple return value - fetch from stack
|
||||
SymbolType returnType = procedure.getReturnType();
|
||||
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(call.getlValue(), new StackPullValue(returnType), program, block.getScope());
|
||||
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
||||
} else {
|
||||
// Struct value list return value - fetch each member from stack
|
||||
final List<RValue> lValues = ((ValueList) call.getlValue()).getList();
|
||||
final StructDefinition structDefinition = ((SymbolTypeStruct) procedure.getReturnType()).getStructDefinition(getScope());
|
||||
final List<Variable> memberVars = new ArrayList<>(structDefinition.getAllVars(false));
|
||||
for(int i = 0; i < memberVars.size(); i++) {
|
||||
LValue lValue = (LValue) lValues.get(i);
|
||||
Variable memberDef = memberVars.get(i);
|
||||
final SymbolType memberType = memberDef.getType();
|
||||
if(i > 0)
|
||||
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
||||
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(lValue, new StackPullValue(memberType), program, block.getScope());
|
||||
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
||||
asm.getCurrentChunk().setSubStatementIdx(i);
|
||||
asm.getCurrentChunk().setSubStatementId(memberDef.toString(program));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(statement instanceof StatementReturn) {
|
||||
@ -915,13 +936,36 @@ public class Pass4CodeGeneration {
|
||||
StatementReturn returnStatement = (StatementReturn) statement;
|
||||
if(returnStatement.getValue() != null) {
|
||||
// Store return value on stack
|
||||
SymbolType returnType = procedure.getReturnType();
|
||||
// Find parameter/return stack size
|
||||
ConstantRef returnOffsetConstant = CallingConventionStack.getReturnOffsetConstant(procedure);
|
||||
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(new StackIdxValue(returnOffsetConstant, returnType), returnStatement.getValue(), program, block.getScope());
|
||||
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
||||
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
||||
SymbolType returnType = procedure.getReturnType();
|
||||
boolean isValueListStruct = (returnStatement.getValue() instanceof ValueList) && (returnType instanceof SymbolTypeStruct);
|
||||
if(!isValueListStruct) {
|
||||
// A simple return type - put it on the stack
|
||||
ConstantRef returnOffsetConstant = CallingConventionStack.getReturnOffsetConstant(procedure);
|
||||
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(new StackIdxValue(returnOffsetConstant, returnType), returnStatement.getValue(), program, block.getScope());
|
||||
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
||||
} else {
|
||||
// A struct return value in a value list - Store each value on the stack
|
||||
final List<RValue> returnValues = ((ValueList) returnStatement.getValue()).getList();
|
||||
final StructDefinition structDefinition = ((SymbolTypeStruct) returnType).getStructDefinition(getScope());
|
||||
final List<Variable> memberVars = new ArrayList<>(structDefinition.getAllVars(false));
|
||||
for(int i = 0; i < memberVars.size(); i++) {
|
||||
RValue returnValue = returnValues.get(i);
|
||||
Variable memberDef = memberVars.get(i);
|
||||
final SymbolType memberType = memberDef.getType();
|
||||
ConstantRef returnOffsetConstant = CallingConventionStack.getReturnOffsetConstant(procedure);
|
||||
ConstantRef structMemberOffsetConstant = SizeOfConstants.getStructMemberOffsetConstant(getScope(), structDefinition, memberDef.getLocalName());
|
||||
ConstantBinary memberReturnOffsetConstant = new ConstantBinary(returnOffsetConstant, Operators.PLUS, structMemberOffsetConstant);
|
||||
if(i > 0)
|
||||
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
||||
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(new StackIdxValue(memberReturnOffsetConstant, memberType), returnValue, program, block.getScope());
|
||||
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
||||
asm.getCurrentChunk().setSubStatementIdx(i);
|
||||
asm.getCurrentChunk().setSubStatementId(memberDef.toString(program));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@ import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.statements.StatementCallFinalize;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.ValueList;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -114,32 +116,32 @@ public class Pass4LiveRangeEquivalenceClassesFinalize extends Pass2Base {
|
||||
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
if(assignment.getlValue() instanceof VariableRef) {
|
||||
VariableRef lValVar = (VariableRef) assignment.getlValue();
|
||||
List<VariableRef> preferences = new ArrayList<>();
|
||||
addToEquivalenceClassSet(lValVar, preferences, liveRangeEquivalenceClassSet);
|
||||
}
|
||||
addValueToEquivalenceClassSet(assignment.getlValue());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCall(StatementCall call) {
|
||||
if(call.getlValue() instanceof VariableRef) {
|
||||
VariableRef lValVar = (VariableRef) call.getlValue();
|
||||
List<VariableRef> preferences = new ArrayList<>();
|
||||
addToEquivalenceClassSet(lValVar, preferences, liveRangeEquivalenceClassSet);
|
||||
}
|
||||
addValueToEquivalenceClassSet(call.getlValue());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCallFinalize(StatementCallFinalize callFinalize) {
|
||||
if(callFinalize.getlValue() instanceof VariableRef) {
|
||||
VariableRef lValVar = (VariableRef) callFinalize.getlValue();
|
||||
addValueToEquivalenceClassSet(callFinalize.getlValue());
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addValueToEquivalenceClassSet(RValue lValue) {
|
||||
if(lValue instanceof VariableRef) {
|
||||
VariableRef lValVar = (VariableRef) lValue;
|
||||
List<VariableRef> preferences = new ArrayList<>();
|
||||
addToEquivalenceClassSet(lValVar, preferences, liveRangeEquivalenceClassSet);
|
||||
} else if(lValue instanceof ValueList) {
|
||||
for(RValue rValue : ((ValueList) lValue).getList()) {
|
||||
addValueToEquivalenceClassSet(rValue);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.values.LValue;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.ValueList;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.*;
|
||||
@ -39,13 +41,21 @@ public class Pass4RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
|
||||
return variableRefs;
|
||||
} else if(statement instanceof StatementLValue) {
|
||||
LValue lValue = ((StatementLValue) statement).getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
variableRefs.add((VariableRef) lValue);
|
||||
}
|
||||
addAssignedVars(lValue, variableRefs);
|
||||
}
|
||||
return variableRefs;
|
||||
}
|
||||
|
||||
private static void addAssignedVars(RValue lValue, LinkedHashSet<VariableRef> variableRefs) {
|
||||
if(lValue instanceof VariableRef) {
|
||||
variableRefs.add((VariableRef) lValue);
|
||||
} else if(lValue instanceof ValueList) {
|
||||
for(RValue rValue : ((ValueList) lValue).getList()) {
|
||||
addAssignedVars(rValue, variableRefs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* For each statement - try out all potential register combinations and examine the clobber
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user