mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-17 10:30:43 +00:00
Added constant for return value offset on stack. Added padding when return value is larger than parameters. Improved calculations of stack frame sizes. #316
This commit is contained in:
parent
2b36c5c18b
commit
665b9adbfb
@ -0,0 +1,5 @@
|
|||||||
|
tsx
|
||||||
|
lda {z1}
|
||||||
|
sta STACK_BASE+{c1},x
|
||||||
|
lda {z1}+1
|
||||||
|
sta STACK_BASE+{c1}+1,x
|
1
src/main/fragment/mos6502-common/_stackpushbyte_1.asm
Normal file
1
src/main/fragment/mos6502-common/_stackpushbyte_1.asm
Normal file
@ -0,0 +1 @@
|
|||||||
|
pha
|
2
src/main/fragment/mos6502-common/_stackpushbyte_2.asm
Normal file
2
src/main/fragment/mos6502-common/_stackpushbyte_2.asm
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pha
|
||||||
|
pha
|
@ -0,0 +1,4 @@
|
|||||||
|
pla
|
||||||
|
sta {z1}
|
||||||
|
pla
|
||||||
|
sta {z1}+1
|
@ -163,7 +163,7 @@ public class AsmFragmentInstanceSpecFactory {
|
|||||||
signature.append(((ConstantInteger) rValue2).getValue());
|
signature.append(((ConstantInteger) rValue2).getValue());
|
||||||
} else if(
|
} else if(
|
||||||
rValue2 instanceof ConstantInteger &&
|
rValue2 instanceof ConstantInteger &&
|
||||||
((((ConstantInteger) rValue2).getValue()) % 8 == 0) &&
|
((((ConstantInteger) rValue2).getValue()) % 8 == 0) &&
|
||||||
operator != null &&
|
operator != null &&
|
||||||
(operator.getOperator().equals(">>") || operator.getOperator().equals("<<"))) {
|
(operator.getOperator().equals(">>") || operator.getOperator().equals("<<"))) {
|
||||||
signature.append(((ConstantInteger) rValue2).getValue());
|
signature.append(((ConstantInteger) rValue2).getValue());
|
||||||
@ -313,7 +313,7 @@ public class AsmFragmentInstanceSpecFactory {
|
|||||||
if(bindPointer.contains("deref")) {
|
if(bindPointer.contains("deref")) {
|
||||||
// Special handling of nested derefs - add parenthesis!
|
// Special handling of nested derefs - add parenthesis!
|
||||||
return "_deref_" + "(" + bindPointer + ")";
|
return "_deref_" + "(" + bindPointer + ")";
|
||||||
} else {
|
} else {
|
||||||
return "_deref_" + bindPointer;
|
return "_deref_" + bindPointer;
|
||||||
}
|
}
|
||||||
} else if(value instanceof PointerDereferenceIndexed) {
|
} else if(value instanceof PointerDereferenceIndexed) {
|
||||||
@ -323,7 +323,7 @@ public class AsmFragmentInstanceSpecFactory {
|
|||||||
if(bindPointer.contains("deref")) {
|
if(bindPointer.contains("deref")) {
|
||||||
// Special handling of nested derefs - add parenthesis!
|
// Special handling of nested derefs - add parenthesis!
|
||||||
bindValue.append("(").append(bindPointer).append(")");
|
bindValue.append("(").append(bindPointer).append(")");
|
||||||
} else {
|
} else {
|
||||||
bindValue.append(bindPointer);
|
bindValue.append(bindPointer);
|
||||||
}
|
}
|
||||||
bindValue.append("_derefidx_");
|
bindValue.append("_derefidx_");
|
||||||
@ -358,11 +358,17 @@ public class AsmFragmentInstanceSpecFactory {
|
|||||||
return name;
|
return name;
|
||||||
} else if(value instanceof StackIdxValue) {
|
} else if(value instanceof StackIdxValue) {
|
||||||
StackIdxValue stackIdxValue = (StackIdxValue) value;
|
StackIdxValue stackIdxValue = (StackIdxValue) value;
|
||||||
return "_stackidx"+ stackIdxValue.getValueType().getTypeName()+"_"+bind(stackIdxValue.getStackOffset());
|
SymbolType type = stackIdxValue.getValueType();
|
||||||
|
String typeShortName = Operators.getCastUnary(type).getAsmOperator().replace("_", "");
|
||||||
|
return "_stackidx" + typeShortName + "_" + bind(stackIdxValue.getStackOffset());
|
||||||
} else if(value instanceof StackPushValue) {
|
} else if(value instanceof StackPushValue) {
|
||||||
return "_stackpush"+((StackPushValue) value).getType().getTypeName()+"_";
|
SymbolType type = ((StackPushValue) value).getType();
|
||||||
|
String typeShortName = Operators.getCastUnary(type).getAsmOperator().replace("_", "");
|
||||||
|
return "_stackpush" + typeShortName + "_";
|
||||||
} else if(value instanceof StackPullValue) {
|
} else if(value instanceof StackPullValue) {
|
||||||
return "_stackpull"+((StackPullValue) value).getType().getTypeName()+"_";
|
SymbolType type = ((StackPullValue) value).getType();
|
||||||
|
String typeShortName = Operators.getCastUnary(type).getAsmOperator().replace("_", "");
|
||||||
|
return "_stackpull" + typeShortName + "_";
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Binding of value type not supported " + value.toString(program));
|
throw new RuntimeException("Binding of value type not supported " + value.toString(program));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,131 @@
|
|||||||
|
package dk.camelot64.kickc.model;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.symbols.*;
|
||||||
|
import dk.camelot64.kickc.model.types.SymbolType;
|
||||||
|
import dk.camelot64.kickc.model.values.ConstantInteger;
|
||||||
|
import dk.camelot64.kickc.model.values.ConstantRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods for {@link dk.camelot64.kickc.model.symbols.Procedure.CallingConvension#STACK_CALL}
|
||||||
|
*/
|
||||||
|
public class CallingConventionStack {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the constant variable containing the (byte) index of the return value on the stack
|
||||||
|
*
|
||||||
|
* @param procedure The procedure
|
||||||
|
* @return The return value stack offset constant
|
||||||
|
*/
|
||||||
|
public static ConstantRef getReturnOffsetConstant(Procedure procedure) {
|
||||||
|
String returnOffsetConstantName = "OFFSET_STACK_RETURN";
|
||||||
|
ConstantVar returnOffsetConstant = procedure.getConstant(returnOffsetConstantName);
|
||||||
|
if(returnOffsetConstant == null) {
|
||||||
|
// Constant not found - create it
|
||||||
|
long returnByteOffset = getReturnByteOffset(procedure);
|
||||||
|
returnOffsetConstant = new ConstantVar(returnOffsetConstantName, procedure, SymbolType.BYTE, new ConstantInteger(returnByteOffset & 0xff, SymbolType.BYTE), Scope.SEGMENT_DATA_DEFAULT);
|
||||||
|
procedure.add(returnOffsetConstant);
|
||||||
|
}
|
||||||
|
return returnOffsetConstant.getRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the constant variable containing the (byte) index of a parameter on the stack
|
||||||
|
*
|
||||||
|
* @param procedure The procedure
|
||||||
|
* @param parameter The parameter
|
||||||
|
* @return The constant variable
|
||||||
|
*/
|
||||||
|
public static ConstantRef getParameterOffsetConstant(Procedure procedure, Variable parameter) {
|
||||||
|
String paramOffsetConstantName = getParameterOffsetConstantName(parameter.getName());
|
||||||
|
ConstantVar paramOffsetConstant = procedure.getConstant(paramOffsetConstantName);
|
||||||
|
if(paramOffsetConstant == null) {
|
||||||
|
// Constant not found - create it
|
||||||
|
long paramByteOffset = getParameterByteOffset(procedure, parameter);
|
||||||
|
paramOffsetConstant = new ConstantVar(paramOffsetConstantName, procedure, SymbolType.BYTE, new ConstantInteger(paramByteOffset & 0xff, SymbolType.BYTE), Scope.SEGMENT_DATA_DEFAULT);
|
||||||
|
procedure.add(paramOffsetConstant);
|
||||||
|
}
|
||||||
|
return paramOffsetConstant.getRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the constant variable containing the (byte) offset of a specific parameter on the stack
|
||||||
|
*
|
||||||
|
* @param parameterName The name of the struct member
|
||||||
|
* @return The name of the constant
|
||||||
|
*/
|
||||||
|
private static String getParameterOffsetConstantName(String parameterName) {
|
||||||
|
return "OFFSET_STACK_" + parameterName.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of bytes that needed on the stack to pass parameters/return value to/from a procedure
|
||||||
|
*
|
||||||
|
* @param procedure The procedure to find the stack frame size for
|
||||||
|
* @return The byte size of the stack frame
|
||||||
|
*/
|
||||||
|
public static long getStackFrameByteSize(Procedure procedure) {
|
||||||
|
long byteSize = getParametersByteSize(procedure);
|
||||||
|
if(procedure.getReturnType() != null) {
|
||||||
|
int returnBytes = procedure.getReturnType().getSizeBytes();
|
||||||
|
if(returnBytes > byteSize) byteSize = returnBytes;
|
||||||
|
}
|
||||||
|
return byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of bytes needed on the stack to store the parameters from a procedure
|
||||||
|
* @param procedure The procedure
|
||||||
|
* @return The byte size of parameters
|
||||||
|
*/
|
||||||
|
public static long getParametersByteSize(Procedure procedure) {
|
||||||
|
long byteSize = 0;
|
||||||
|
for(Variable procedureParameter : procedure.getParameters()) {
|
||||||
|
byteSize += procedureParameter.getType().getSizeBytes();
|
||||||
|
}
|
||||||
|
return byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of bytes that a parameter is offset on the stack
|
||||||
|
*
|
||||||
|
* @param parameter The parameter to find offset for
|
||||||
|
* @return The byte offset of the start of the member data
|
||||||
|
*/
|
||||||
|
public static long getParameterByteOffset(Procedure procedure, Variable parameter) {
|
||||||
|
long byteOffset = 0;
|
||||||
|
for(Variable procedureParameter : procedure.getParameters()) {
|
||||||
|
if(parameter.equals(procedureParameter)) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// TODO: Consider how passing a struct should handle inline arrays byteOffset += SymbolTypeStruct.getMemberSizeBytes(parameter.getType(), programScope);
|
||||||
|
byteOffset += procedureParameter.getType().getSizeBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return byteOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of bytes that the return value is offset on the stack
|
||||||
|
*
|
||||||
|
* @param procedure The procedure
|
||||||
|
* @return The byte offset of the return value
|
||||||
|
*/
|
||||||
|
private static long getReturnByteOffset(Procedure procedure) {
|
||||||
|
return getStackFrameByteSize(procedure) - procedure.getReturnType().getSizeBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get he global STACK_BASE constant. Create it if it does not exist.
|
||||||
|
*
|
||||||
|
* @param programScope The program scope
|
||||||
|
* @return The reference to the global constant
|
||||||
|
*/
|
||||||
|
public static ConstantRef getStackBaseConstant(ProgramScope programScope) {
|
||||||
|
long STACK_BASE_ADDRESS = 0x103L;
|
||||||
|
ConstantVar stackBase = new ConstantVar("STACK_BASE", programScope, SymbolType.WORD, new ConstantInteger(STACK_BASE_ADDRESS, SymbolType.WORD), Scope.SEGMENT_DATA_DEFAULT);
|
||||||
|
programScope.add(stackBase);
|
||||||
|
return stackBase.getRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -765,6 +765,17 @@ public class Pass4CodeGeneration {
|
|||||||
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||||
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
||||||
}
|
}
|
||||||
|
// Push additional bytes if needed
|
||||||
|
long stackFrameByteSize = CallingConventionStack.getStackFrameByteSize(procedure);
|
||||||
|
long parametersByteSize = CallingConventionStack.getParametersByteSize(procedure);
|
||||||
|
if(stackFrameByteSize > parametersByteSize) {
|
||||||
|
// Add padding to the stack to make room for the return value
|
||||||
|
String pushSignature = "_stackpushbyte_" + (stackFrameByteSize - parametersByteSize);
|
||||||
|
AsmFragmentInstanceSpec pushFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, pushSignature, new LinkedHashMap<>(), block.getScope());
|
||||||
|
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
||||||
|
generateAsm(asm, pushFragmentInstanceSpec);
|
||||||
|
|
||||||
|
}
|
||||||
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
||||||
}
|
}
|
||||||
} else if(statement instanceof StatementCallExecute) {
|
} else if(statement instanceof StatementCallExecute) {
|
||||||
@ -778,21 +789,16 @@ public class Pass4CodeGeneration {
|
|||||||
StatementCallFinalize call = (StatementCallFinalize) statement;
|
StatementCallFinalize call = (StatementCallFinalize) statement;
|
||||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||||
if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
||||||
// Find parameter/return stack size
|
|
||||||
int parameterBytes = 0;
|
long stackFrameByteSize = CallingConventionStack.getStackFrameByteSize(procedure);
|
||||||
for(Variable parameter : procedure.getParameters()) {
|
long returnByteSize = procedure.getReturnType()==null?0:procedure.getReturnType().getSizeBytes();
|
||||||
parameterBytes += parameter.getType().getSizeBytes();
|
if(stackFrameByteSize > returnByteSize) {
|
||||||
|
// Clean up the stack
|
||||||
|
String pullSignature = "_stackpullbyte_" + (stackFrameByteSize-returnByteSize);
|
||||||
|
AsmFragmentInstanceSpec pullFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, pullSignature, new LinkedHashMap<>(), block.getScope());
|
||||||
|
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
||||||
|
generateAsm(asm, pullFragmentInstanceSpec);
|
||||||
}
|
}
|
||||||
int stackSizeBytes = parameterBytes;
|
|
||||||
if(call.getlValue() != null) {
|
|
||||||
SymbolType returnType = procedure.getReturnType();
|
|
||||||
stackSizeBytes -= returnType.getSizeBytes();
|
|
||||||
}
|
|
||||||
// Clean up the stack
|
|
||||||
String pullSignature = "_stackpullbyte_" + Integer.toString(stackSizeBytes);
|
|
||||||
AsmFragmentInstanceSpec pullFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, pullSignature, new LinkedHashMap<>(), block.getScope());
|
|
||||||
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
|
||||||
generateAsm(asm, pullFragmentInstanceSpec);
|
|
||||||
|
|
||||||
// Pull result from the stack
|
// Pull result from the stack
|
||||||
if(call.getlValue() != null) {
|
if(call.getlValue() != null) {
|
||||||
@ -811,28 +817,21 @@ public class Pass4CodeGeneration {
|
|||||||
procedure = getScope().getProcedure(scope.getFullName());
|
procedure = getScope().getProcedure(scope.getFullName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(procedure!=null && Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
if(procedure != null && Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
||||||
StatementReturn returnStatement = (StatementReturn) statement;
|
StatementReturn returnStatement = (StatementReturn) statement;
|
||||||
if(returnStatement.getValue()!=null) {
|
if(returnStatement.getValue() != null) {
|
||||||
// Store return value on stack
|
// Store return value on stack
|
||||||
SymbolType returnType = procedure.getReturnType();
|
SymbolType returnType = procedure.getReturnType();
|
||||||
|
|
||||||
// Find parameter/return stack size
|
// Find parameter/return stack size
|
||||||
int parameterBytes = 0;
|
ConstantRef returnOffsetConstant = CallingConventionStack.getReturnOffsetConstant(procedure);
|
||||||
for(Variable parameter : procedure.getParameters()) {
|
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(new StackIdxValue(returnOffsetConstant, returnType), returnStatement.getValue(), program, block.getScope());
|
||||||
parameterBytes += parameter.getType().getSizeBytes();
|
|
||||||
}
|
|
||||||
int returnOffset = parameterBytes - returnType.getSizeBytes();
|
|
||||||
// TODO: Put the return stack offset into a named constant (look at PassNCallingConventionStack)
|
|
||||||
ConstantValue returnValueStackOffset = new ConstantInteger((long)returnOffset, SymbolType.BYTE);
|
|
||||||
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(new StackIdxValue(returnValueStackOffset, returnType), returnStatement.getValue(), program, block.getScope());
|
|
||||||
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
|
||||||
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||||
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(procedure==null || procedure.getInterruptType() == null) {
|
if(procedure == null || procedure.getInterruptType() == null) {
|
||||||
asm.addInstruction("rts", AsmAddressingMode.NON, null, false);
|
asm.addInstruction("rts", AsmAddressingMode.NON, null, false);
|
||||||
} else {
|
} else {
|
||||||
generateInterruptExit(asm, statement, procedure.getInterruptType());
|
generateInterruptExit(asm, statement, procedure.getInterruptType());
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package dk.camelot64.kickc.passes;
|
package dk.camelot64.kickc.passes;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.CallingConventionStack;
|
||||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||||
import dk.camelot64.kickc.model.Program;
|
import dk.camelot64.kickc.model.Program;
|
||||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||||
@ -26,15 +27,27 @@ public class PassNCallingConventionStack extends Pass2SsaOptimization {
|
|||||||
Map<VariableRef, ConstantRef> offsetConstants = new HashMap<>();
|
Map<VariableRef, ConstantRef> offsetConstants = new HashMap<>();
|
||||||
|
|
||||||
// Introduce STACK_OFFSET constants
|
// Introduce STACK_OFFSET constants
|
||||||
|
boolean createStackBase = false;
|
||||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||||
if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
||||||
|
// Introduce the parameter offsets
|
||||||
for(Variable parameter : procedure.getParameters()) {
|
for(Variable parameter : procedure.getParameters()) {
|
||||||
ConstantRef parameterOffsetConstant = getParameterOffsetConstant(procedure, parameter, getScope());
|
ConstantRef parameterOffsetConstant = CallingConventionStack.getParameterOffsetConstant(procedure, parameter);
|
||||||
offsetConstants.put(parameter.getRef(), parameterOffsetConstant);
|
offsetConstants.put(parameter.getRef(), parameterOffsetConstant);
|
||||||
|
createStackBase = true;
|
||||||
|
}
|
||||||
|
// Introduce the return value offset
|
||||||
|
if(procedure.getReturnType() != null) {
|
||||||
|
CallingConventionStack.getReturnOffsetConstant(procedure);
|
||||||
|
createStackBase = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add global STACK_BASE constant
|
||||||
|
if(createStackBase)
|
||||||
|
CallingConventionStack.getStackBaseConstant(getScope());
|
||||||
|
|
||||||
// Transform STACK_CALL calls to call-prepare, call-execute, call-finalize
|
// Transform STACK_CALL calls to call-prepare, call-execute, call-finalize
|
||||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||||
@ -49,17 +62,13 @@ public class PassNCallingConventionStack extends Pass2SsaOptimization {
|
|||||||
stmtIt.add(new StatementCallPrepare(procedureRef, call.getParameters(), call.getSource(), call.getComments()));
|
stmtIt.add(new StatementCallPrepare(procedureRef, call.getParameters(), call.getSource(), call.getComments()));
|
||||||
stmtIt.add(new StatementCallExecute(procedureRef, call.getSource(), call.getComments()));
|
stmtIt.add(new StatementCallExecute(procedureRef, call.getSource(), call.getComments()));
|
||||||
stmtIt.add(new StatementCallFinalize(call.getlValue(), procedureRef, call.getSource(), call.getComments()));
|
stmtIt.add(new StatementCallFinalize(call.getlValue(), procedureRef, call.getSource(), call.getComments()));
|
||||||
getLog().append("Calling convention " + Procedure.CallingConvension.STACK_CALL + " adding prepare/execute/finalize for "+call.toString(getProgram(), false) );
|
getLog().append("Calling convention " + Procedure.CallingConvension.STACK_CALL + " adding prepare/execute/finalize for " + call.toString(getProgram(), false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(offsetConstants.size() > 0) {
|
if(offsetConstants.size() > 0) {
|
||||||
// Add global STACK_BASE constant
|
|
||||||
long STACK_BASE = 0x103L;
|
|
||||||
getScope().add(new ConstantVar("STACK_BASE", getScope(), SymbolType.WORD, new ConstantInteger(STACK_BASE, SymbolType.WORD), Scope.SEGMENT_DATA_DEFAULT));
|
|
||||||
|
|
||||||
// Convert ParamValue to StackIdxValue
|
// Convert ParamValue to StackIdxValue
|
||||||
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||||
if(programValue.get() instanceof ParamValue) {
|
if(programValue.get() instanceof ParamValue) {
|
||||||
@ -78,53 +87,4 @@ public class PassNCallingConventionStack extends Pass2SsaOptimization {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the constant variable containing the (byte) index of a parameter on the stack
|
|
||||||
*
|
|
||||||
* @param procedure The procedure
|
|
||||||
* @param procedure The parameter
|
|
||||||
* @param programScope The program scope (used for finding/adding the constant).
|
|
||||||
* @return The constant variable
|
|
||||||
*/
|
|
||||||
public static ConstantRef getParameterOffsetConstant(Procedure procedure, Variable parameter, ProgramScope programScope) {
|
|
||||||
String paramOffsetConstantName = getParameterOffsetConstantName(parameter.getName());
|
|
||||||
ConstantVar paramOffsetConstant = procedure.getConstant(paramOffsetConstantName);
|
|
||||||
if(paramOffsetConstant == null) {
|
|
||||||
// Constant not found - create it
|
|
||||||
long paramByteOffset = getParameterByteOffset(procedure, parameter, programScope);
|
|
||||||
paramOffsetConstant = new ConstantVar(paramOffsetConstantName, procedure, SymbolType.BYTE, new ConstantInteger(paramByteOffset & 0xff, SymbolType.BYTE), Scope.SEGMENT_DATA_DEFAULT);
|
|
||||||
procedure.add(paramOffsetConstant);
|
|
||||||
}
|
|
||||||
return paramOffsetConstant.getRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the name of the constant variable containing the (byte) offset of a specific parameter on the stack
|
|
||||||
*
|
|
||||||
* @param parameterName The name of the struct member
|
|
||||||
* @return The name of the constant
|
|
||||||
*/
|
|
||||||
private static String getParameterOffsetConstantName(String parameterName) {
|
|
||||||
return "OFFSET_STACK_" + parameterName.toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the number of bytes that a parameter is offset on the stack
|
|
||||||
*
|
|
||||||
* @param parameter The parameter to find offset for
|
|
||||||
* @return The byte offset of the start of the member data
|
|
||||||
*/
|
|
||||||
public static long getParameterByteOffset(Procedure procedure, Variable parameter, ProgramScope programScope) {
|
|
||||||
long byteOffset = 0;
|
|
||||||
for(Variable procedureParameter : procedure.getParameters()) {
|
|
||||||
if(parameter.equals(procedureParameter)) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// TODO: Consider hos passing a struct should handle inline arrays byteOffset += SymbolTypeStruct.getMemberSizeBytes(parameter.getType(), programScope);
|
|
||||||
byteOffset += parameter.getType().getSizeBytes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return byteOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,11 @@ public class TestPrograms {
|
|||||||
public TestPrograms() {
|
public TestPrograms() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProcedureCallingConventionStack5() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("procedure-callingconvention-stack-5"); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcedureCallingConventionStack4() throws IOException, URISyntaxException {
|
public void testProcedureCallingConventionStack4() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("procedure-callingconvention-stack-4"); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence());
|
compileAndCompare("procedure-callingconvention-stack-4"); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence());
|
||||||
|
15
src/test/kc/procedure-callingconvention-stack-5.kc
Normal file
15
src/test/kc/procedure-callingconvention-stack-5.kc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Test a procedure with calling convention stack
|
||||||
|
// Return value larger than parameter
|
||||||
|
|
||||||
|
const int* SCREEN = 0x0400;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
SCREEN[0] = next();
|
||||||
|
SCREEN[1] = next();
|
||||||
|
}
|
||||||
|
|
||||||
|
int current = 48;
|
||||||
|
|
||||||
|
int __stackcall next() {
|
||||||
|
return current++;
|
||||||
|
}
|
@ -19,6 +19,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
tsx
|
tsx
|
||||||
lda STACK_BASE+OFFSET_STACK_A,x
|
lda STACK_BASE+OFFSET_STACK_A,x
|
||||||
@ -28,6 +29,6 @@ plus: {
|
|||||||
clc
|
clc
|
||||||
adc.z a
|
adc.z a
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 3
|
.label a = 3
|
||||||
.label b = 4
|
.label b = 4
|
||||||
.label return = 5
|
.label return = 5
|
||||||
@ -237,7 +238,7 @@ plus: {
|
|||||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
||||||
lda.z return
|
lda.z return
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -330,6 +331,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||||
tsx
|
tsx
|
||||||
@ -347,7 +349,7 @@ plus: {
|
|||||||
// [13] return (byte) plus::return#0
|
// [13] return (byte) plus::return#0
|
||||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -387,6 +389,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||||
(byte) plus::a
|
(byte) plus::a
|
||||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||||
(byte) plus::b
|
(byte) plus::b
|
||||||
@ -450,6 +453,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||||
tsx
|
tsx
|
||||||
@ -467,7 +471,7 @@ plus: {
|
|||||||
// [13] return (byte) plus::return#0
|
// [13] return (byte) plus::return#0
|
||||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
|
@ -11,6 +11,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||||
(byte) plus::a
|
(byte) plus::a
|
||||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||||
(byte) plus::b
|
(byte) plus::b
|
||||||
|
@ -19,6 +19,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
tsx
|
tsx
|
||||||
lda STACK_BASE+OFFSET_STACK_A,x
|
lda STACK_BASE+OFFSET_STACK_A,x
|
||||||
@ -28,6 +29,6 @@ plus: {
|
|||||||
clc
|
clc
|
||||||
adc.z a
|
adc.z a
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 3
|
.label a = 3
|
||||||
.label b = 4
|
.label b = 4
|
||||||
.label return = 5
|
.label return = 5
|
||||||
@ -237,7 +238,7 @@ plus: {
|
|||||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
||||||
lda.z return
|
lda.z return
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -330,6 +331,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||||
tsx
|
tsx
|
||||||
@ -347,7 +349,7 @@ plus: {
|
|||||||
// [13] return (byte) plus::return#0
|
// [13] return (byte) plus::return#0
|
||||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -387,6 +389,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||||
(byte) plus::a
|
(byte) plus::a
|
||||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||||
(byte) plus::b
|
(byte) plus::b
|
||||||
@ -450,6 +453,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||||
tsx
|
tsx
|
||||||
@ -467,7 +471,7 @@ plus: {
|
|||||||
// [13] return (byte) plus::return#0
|
// [13] return (byte) plus::return#0
|
||||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
|
@ -11,6 +11,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||||
(byte) plus::a
|
(byte) plus::a
|
||||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||||
(byte) plus::b
|
(byte) plus::b
|
||||||
|
@ -31,6 +31,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 2
|
.const OFFSET_STACK_B = 2
|
||||||
|
.const OFFSET_STACK_RETURN = 2
|
||||||
.label a = 2
|
.label a = 2
|
||||||
.label b = 4
|
.label b = 4
|
||||||
.label return = 2
|
.label return = 2
|
||||||
@ -53,8 +54,8 @@ plus: {
|
|||||||
sta.z return+1
|
sta.z return+1
|
||||||
tsx
|
tsx
|
||||||
lda.z return
|
lda.z return
|
||||||
sta STACK_BASE+2,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
lda.z return+1
|
lda.z return+1
|
||||||
sta STACK_BASE+2+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
@ -240,6 +240,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 2
|
.const OFFSET_STACK_B = 2
|
||||||
|
.const OFFSET_STACK_RETURN = 2
|
||||||
.label a = 4
|
.label a = 4
|
||||||
.label b = 6
|
.label b = 6
|
||||||
.label return = 8
|
.label return = 8
|
||||||
@ -270,9 +271,9 @@ plus: {
|
|||||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||||
tsx
|
tsx
|
||||||
lda.z return
|
lda.z return
|
||||||
sta STACK_BASE+2,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
lda.z return+1
|
lda.z return+1
|
||||||
sta STACK_BASE+2+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -371,6 +372,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 2
|
.const OFFSET_STACK_B = 2
|
||||||
|
.const OFFSET_STACK_RETURN = 2
|
||||||
.label a = 2
|
.label a = 2
|
||||||
.label b = 4
|
.label b = 4
|
||||||
.label return = 2
|
.label return = 2
|
||||||
@ -401,9 +403,9 @@ plus: {
|
|||||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||||
tsx
|
tsx
|
||||||
lda.z return
|
lda.z return
|
||||||
sta STACK_BASE+2,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
lda.z return+1
|
lda.z return+1
|
||||||
sta STACK_BASE+2+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -443,6 +445,7 @@ __stackcall (word()) plus((word) plus::a , (word) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 2
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 2
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 2
|
||||||
(word) plus::a
|
(word) plus::a
|
||||||
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
||||||
(word) plus::b
|
(word) plus::b
|
||||||
@ -516,6 +519,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 2
|
.const OFFSET_STACK_B = 2
|
||||||
|
.const OFFSET_STACK_RETURN = 2
|
||||||
.label a = 2
|
.label a = 2
|
||||||
.label b = 4
|
.label b = 4
|
||||||
.label return = 2
|
.label return = 2
|
||||||
@ -546,9 +550,9 @@ plus: {
|
|||||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||||
tsx
|
tsx
|
||||||
lda.z return
|
lda.z return
|
||||||
sta STACK_BASE+2,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
lda.z return+1
|
lda.z return+1
|
||||||
sta STACK_BASE+2+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
|
@ -11,6 +11,7 @@ __stackcall (word()) plus((word) plus::a , (word) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 2
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 2
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 2
|
||||||
(word) plus::a
|
(word) plus::a
|
||||||
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
||||||
(word) plus::b
|
(word) plus::b
|
||||||
|
@ -34,6 +34,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 2
|
.const OFFSET_STACK_B = 2
|
||||||
|
.const OFFSET_STACK_RETURN = 2
|
||||||
.label a = 2
|
.label a = 2
|
||||||
.label b = 4
|
.label b = 4
|
||||||
.label return = 2
|
.label return = 2
|
||||||
@ -56,8 +57,8 @@ plus: {
|
|||||||
sta.z return+1
|
sta.z return+1
|
||||||
tsx
|
tsx
|
||||||
lda.z return
|
lda.z return
|
||||||
sta STACK_BASE+2,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
lda.z return+1
|
lda.z return+1
|
||||||
sta STACK_BASE+2+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
@ -240,6 +240,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 2
|
.const OFFSET_STACK_B = 2
|
||||||
|
.const OFFSET_STACK_RETURN = 2
|
||||||
.label a = 4
|
.label a = 4
|
||||||
.label b = 6
|
.label b = 6
|
||||||
.label return = 8
|
.label return = 8
|
||||||
@ -270,9 +271,9 @@ plus: {
|
|||||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||||
tsx
|
tsx
|
||||||
lda.z return
|
lda.z return
|
||||||
sta STACK_BASE+2,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
lda.z return+1
|
lda.z return+1
|
||||||
sta STACK_BASE+2+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -374,6 +375,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 2
|
.const OFFSET_STACK_B = 2
|
||||||
|
.const OFFSET_STACK_RETURN = 2
|
||||||
.label a = 2
|
.label a = 2
|
||||||
.label b = 4
|
.label b = 4
|
||||||
.label return = 2
|
.label return = 2
|
||||||
@ -404,9 +406,9 @@ plus: {
|
|||||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||||
tsx
|
tsx
|
||||||
lda.z return
|
lda.z return
|
||||||
sta STACK_BASE+2,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
lda.z return+1
|
lda.z return+1
|
||||||
sta STACK_BASE+2+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -446,6 +448,7 @@ __stackcall (word()) plus((word) plus::a , (word) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 2
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 2
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 2
|
||||||
(word) plus::a
|
(word) plus::a
|
||||||
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
||||||
(word) plus::b
|
(word) plus::b
|
||||||
@ -522,6 +525,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 2
|
.const OFFSET_STACK_B = 2
|
||||||
|
.const OFFSET_STACK_RETURN = 2
|
||||||
.label a = 2
|
.label a = 2
|
||||||
.label b = 4
|
.label b = 4
|
||||||
.label return = 2
|
.label return = 2
|
||||||
@ -552,9 +556,9 @@ plus: {
|
|||||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||||
tsx
|
tsx
|
||||||
lda.z return
|
lda.z return
|
||||||
sta STACK_BASE+2,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
lda.z return+1
|
lda.z return+1
|
||||||
sta STACK_BASE+2+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
|
@ -11,6 +11,7 @@ __stackcall (word()) plus((word) plus::a , (word) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 2
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 2
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 2
|
||||||
(word) plus::a
|
(word) plus::a
|
||||||
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
||||||
(word) plus::b
|
(word) plus::b
|
||||||
|
@ -31,6 +31,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
tsx
|
tsx
|
||||||
lda STACK_BASE+OFFSET_STACK_A,x
|
lda STACK_BASE+OFFSET_STACK_A,x
|
||||||
@ -40,6 +41,6 @@ plus: {
|
|||||||
clc
|
clc
|
||||||
adc.z a
|
adc.z a
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
@ -349,6 +349,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 6
|
.label a = 6
|
||||||
.label b = 7
|
.label b = 7
|
||||||
.label return = 8
|
.label return = 8
|
||||||
@ -372,7 +373,7 @@ plus: {
|
|||||||
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
||||||
lda.z return
|
lda.z return
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -498,6 +499,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
// [15] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
// [15] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||||
tsx
|
tsx
|
||||||
@ -515,7 +517,7 @@ plus: {
|
|||||||
// [18] return (byte) plus::return#0
|
// [18] return (byte) plus::return#0
|
||||||
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
@ -570,6 +572,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||||
(byte) plus::a
|
(byte) plus::a
|
||||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||||
(byte) plus::b
|
(byte) plus::b
|
||||||
@ -660,6 +663,7 @@ main: {
|
|||||||
plus: {
|
plus: {
|
||||||
.const OFFSET_STACK_A = 0
|
.const OFFSET_STACK_A = 0
|
||||||
.const OFFSET_STACK_B = 1
|
.const OFFSET_STACK_B = 1
|
||||||
|
.const OFFSET_STACK_RETURN = 1
|
||||||
.label a = 2
|
.label a = 2
|
||||||
// [15] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
// [15] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||||
tsx
|
tsx
|
||||||
@ -677,7 +681,7 @@ plus: {
|
|||||||
// [18] return (byte) plus::return#0
|
// [18] return (byte) plus::return#0
|
||||||
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||||
tsx
|
tsx
|
||||||
sta STACK_BASE+1,x
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
|
@ -20,6 +20,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
|||||||
(label) plus::@return
|
(label) plus::@return
|
||||||
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
(const byte) plus::OFFSET_STACK_A OFFSET_STACK_A = (byte) 0
|
||||||
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
(const byte) plus::OFFSET_STACK_B OFFSET_STACK_B = (byte) 1
|
||||||
|
(const byte) plus::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||||
(byte) plus::a
|
(byte) plus::a
|
||||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||||
(byte) plus::b
|
(byte) plus::b
|
||||||
|
46
src/test/ref/procedure-callingconvention-stack-5.asm
Normal file
46
src/test/ref/procedure-callingconvention-stack-5.asm
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Test a procedure with calling convention stack
|
||||||
|
// Return value larger than parameter
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
.const SIZEOF_SIGNED_WORD = 2
|
||||||
|
.label SCREEN = $400
|
||||||
|
.const STACK_BASE = $103
|
||||||
|
.label current = 2
|
||||||
|
main: {
|
||||||
|
.label _0 = 2
|
||||||
|
.label _1 = 4
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
jsr next
|
||||||
|
pla
|
||||||
|
sta.z _0
|
||||||
|
pla
|
||||||
|
sta.z _0+1
|
||||||
|
lda.z _0
|
||||||
|
sta SCREEN
|
||||||
|
lda.z _0+1
|
||||||
|
sta SCREEN+1
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
jsr next
|
||||||
|
pla
|
||||||
|
sta.z _1
|
||||||
|
pla
|
||||||
|
sta.z _1+1
|
||||||
|
lda.z _1
|
||||||
|
sta SCREEN+1*SIZEOF_SIGNED_WORD
|
||||||
|
lda.z _1+1
|
||||||
|
sta SCREEN+1*SIZEOF_SIGNED_WORD+1
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
next: {
|
||||||
|
.const OFFSET_STACK_RETURN = 0
|
||||||
|
.label return = 2
|
||||||
|
tsx
|
||||||
|
lda.z return
|
||||||
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
|
lda.z return+1
|
||||||
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
|
rts
|
||||||
|
}
|
34
src/test/ref/procedure-callingconvention-stack-5.cfg
Normal file
34
src/test/ref/procedure-callingconvention-stack-5.cfg
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
@begin: scope:[] from
|
||||||
|
[0] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] phi()
|
||||||
|
[5] callprepare next
|
||||||
|
[6] callexecute next
|
||||||
|
[7] (signed word~) main::$0 ← callfinalize next
|
||||||
|
[8] *((const signed word*) SCREEN#0) ← (signed word~) main::$0
|
||||||
|
[9] callprepare next
|
||||||
|
[10] callexecute next
|
||||||
|
[11] (signed word~) main::$1 ← callfinalize next
|
||||||
|
[12] *((const signed word*) SCREEN#0+(byte) 1*(const byte) SIZEOF_SIGNED_WORD) ← (signed word~) main::$1
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
[13] return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
__stackcall (signed word()) next()
|
||||||
|
next: scope:[next] from
|
||||||
|
[14] (signed word) current#5 ← phi( )
|
||||||
|
[15] (signed word) next::return#0 ← (signed word) current#5
|
||||||
|
to:next::@return
|
||||||
|
next::@return: scope:[next] from next
|
||||||
|
[16] return (signed word) next::return#0
|
||||||
|
to:@return
|
565
src/test/ref/procedure-callingconvention-stack-5.log
Normal file
565
src/test/ref/procedure-callingconvention-stack-5.log
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
Fixing pointer array-indexing *((signed word*) SCREEN + (number) 0)
|
||||||
|
Fixing pointer array-indexing *((signed word*) SCREEN + (number) 1)
|
||||||
|
Culled Empty Block (label) next::@1
|
||||||
|
|
||||||
|
CONTROL FLOW GRAPH SSA
|
||||||
|
@begin: scope:[] from
|
||||||
|
(signed word*) SCREEN#0 ← ((signed word*)) (number) $400
|
||||||
|
to:@1
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @2
|
||||||
|
(signed word) current#7 ← phi( @2/(signed word) current#8 )
|
||||||
|
(signed word~) main::$0 ← call next
|
||||||
|
(number~) main::$2 ← (number) 0 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
*((signed word*) SCREEN#0 + (number~) main::$2) ← (signed word~) main::$0
|
||||||
|
(signed word~) main::$1 ← call next
|
||||||
|
(number~) main::$3 ← (number) 1 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
*((signed word*) SCREEN#0 + (number~) main::$3) ← (signed word~) main::$1
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
(signed word) current#4 ← phi( main/(signed word) current#7 )
|
||||||
|
(signed word) current#0 ← (signed word) current#4
|
||||||
|
return
|
||||||
|
to:@return
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
(signed word) current#1 ← (number) $30
|
||||||
|
to:@2
|
||||||
|
|
||||||
|
__stackcall (signed word()) next()
|
||||||
|
next: scope:[next] from
|
||||||
|
(signed word) current#5 ← phi( )
|
||||||
|
(signed word) next::return#0 ← (signed word) current#5
|
||||||
|
(signed word) current#2 ← ++ (signed word) current#5
|
||||||
|
to:next::@return
|
||||||
|
next::@return: scope:[next] from next
|
||||||
|
(signed word) next::return#1 ← phi( next/(signed word) next::return#0 )
|
||||||
|
return (signed word) next::return#1
|
||||||
|
to:@return
|
||||||
|
@2: scope:[] from @1
|
||||||
|
(signed word) current#8 ← phi( @1/(signed word) current#1 )
|
||||||
|
call main
|
||||||
|
to:@3
|
||||||
|
@3: scope:[] from @2
|
||||||
|
(signed word) current#6 ← phi( @2/(signed word) current#0 )
|
||||||
|
(signed word) current#3 ← (signed word) current#6
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @3
|
||||||
|
|
||||||
|
SYMBOL TABLE SSA
|
||||||
|
(label) @1
|
||||||
|
(label) @2
|
||||||
|
(label) @3
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(signed word*) SCREEN
|
||||||
|
(signed word*) SCREEN#0
|
||||||
|
(const byte) SIZEOF_SIGNED_WORD = (byte) 2
|
||||||
|
(signed word) current
|
||||||
|
(signed word) current#0
|
||||||
|
(signed word) current#1
|
||||||
|
(signed word) current#2
|
||||||
|
(signed word) current#3
|
||||||
|
(signed word) current#4
|
||||||
|
(signed word) current#5
|
||||||
|
(signed word) current#6
|
||||||
|
(signed word) current#7
|
||||||
|
(signed word) current#8
|
||||||
|
(void()) main()
|
||||||
|
(signed word~) main::$0
|
||||||
|
(signed word~) main::$1
|
||||||
|
(number~) main::$2
|
||||||
|
(number~) main::$3
|
||||||
|
(label) main::@return
|
||||||
|
__stackcall (signed word()) next()
|
||||||
|
(label) next::@return
|
||||||
|
(signed word) next::return
|
||||||
|
(signed word) next::return#0
|
||||||
|
(signed word) next::return#1
|
||||||
|
|
||||||
|
Adding number conversion cast (unumber) 0 in (number~) main::$2 ← (number) 0 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (unumber)(number) 0 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Adding number conversion cast (unumber) 1 in (number~) main::$3 ← (number) 1 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Adding number conversion cast (unumber) main::$3 in (number~) main::$3 ← (unumber)(number) 1 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Adding number conversion cast (snumber) $30 in (signed word) current#1 ← (number) $30
|
||||||
|
Successful SSA optimization PassNAddNumberTypeConversions
|
||||||
|
Inlining cast (signed word*) SCREEN#0 ← (signed word*)(number) $400
|
||||||
|
Inlining cast (signed word) current#1 ← (snumber)(number) $30
|
||||||
|
Successful SSA optimization Pass2InlineCast
|
||||||
|
Simplifying constant pointer cast (signed word*) 1024
|
||||||
|
Simplifying constant integer cast 0
|
||||||
|
Simplifying constant integer cast 1
|
||||||
|
Simplifying constant integer cast $30
|
||||||
|
Successful SSA optimization PassNCastSimplification
|
||||||
|
Finalized unsigned number type (byte) 0
|
||||||
|
Finalized unsigned number type (byte) 1
|
||||||
|
Finalized signed number type (signed byte) $30
|
||||||
|
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||||
|
Inferred type updated to byte in (unumber~) main::$2 ← (byte) 0 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Inferred type updated to byte in (unumber~) main::$3 ← (byte) 1 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Alias (signed word) current#0 = (signed word) current#4 (signed word) current#7
|
||||||
|
Alias (signed word) next::return#0 = (signed word) next::return#1
|
||||||
|
Alias (signed word) current#1 = (signed word) current#8
|
||||||
|
Alias (signed word) current#3 = (signed word) current#6
|
||||||
|
Successful SSA optimization Pass2AliasElimination
|
||||||
|
Identical Phi Values (signed word) current#0 (signed word) current#1
|
||||||
|
Identical Phi Values (signed word) current#3 (signed word) current#0
|
||||||
|
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||||
|
Constant right-side identified [3] (byte~) main::$2 ← (byte) 0 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Constant right-side identified [6] (byte~) main::$3 ← (byte) 1 * (const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||||
|
Constant (const signed word*) SCREEN#0 = (signed word*) 1024
|
||||||
|
Constant (const byte) main::$2 = 0*SIZEOF_SIGNED_WORD
|
||||||
|
Constant (const byte) main::$3 = 1*SIZEOF_SIGNED_WORD
|
||||||
|
Constant (const signed word) current#1 = $30
|
||||||
|
Successful SSA optimization Pass2ConstantIdentification
|
||||||
|
Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_SIGNED_WORD in
|
||||||
|
Successful SSA optimization PassNSimplifyConstantZero
|
||||||
|
Simplifying expression containing zero SCREEN#0 in [4] *((const signed word*) SCREEN#0 + (const byte) main::$2) ← (signed word~) main::$0
|
||||||
|
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||||
|
Eliminating unused variable (signed word) current#2 and assignment [7] (signed word) current#2 ← ++ (signed word) current#5
|
||||||
|
Eliminating unused constant (const byte) main::$2
|
||||||
|
Eliminating unused constant (const signed word) current#1
|
||||||
|
Successful SSA optimization PassNEliminateUnusedVars
|
||||||
|
Constant inlined main::$3 = (byte) 1*(const byte) SIZEOF_SIGNED_WORD
|
||||||
|
Successful SSA optimization Pass2ConstantInlining
|
||||||
|
Consolidated array index constant in *(SCREEN#0+1*SIZEOF_SIGNED_WORD)
|
||||||
|
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||||
|
Adding NOP phi() at start of @begin
|
||||||
|
Adding NOP phi() at start of @1
|
||||||
|
Adding NOP phi() at start of @2
|
||||||
|
Adding NOP phi() at start of @3
|
||||||
|
Adding NOP phi() at start of @end
|
||||||
|
Adding NOP phi() at start of main
|
||||||
|
CALL GRAPH
|
||||||
|
Calls in [] to main:3
|
||||||
|
Calls in [main] to next:7 next:9
|
||||||
|
|
||||||
|
Created 1 initial phi equivalence classes
|
||||||
|
Coalesced down to 1 phi equivalence classes
|
||||||
|
Culled Empty Block (label) @1
|
||||||
|
Culled Empty Block (label) @3
|
||||||
|
Renumbering block @2 to @1
|
||||||
|
Adding NOP phi() at start of @begin
|
||||||
|
Adding NOP phi() at start of @1
|
||||||
|
Adding NOP phi() at start of @end
|
||||||
|
Adding NOP phi() at start of main
|
||||||
|
Calling convention STACK_CALL adding prepare/execute/finalize for [5] (signed word~) main::$0 ← call next
|
||||||
|
Calling convention STACK_CALL adding prepare/execute/finalize for [7] (signed word~) main::$1 ← call next
|
||||||
|
|
||||||
|
FINAL CONTROL FLOW GRAPH
|
||||||
|
@begin: scope:[] from
|
||||||
|
[0] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] phi()
|
||||||
|
[5] callprepare next
|
||||||
|
[6] callexecute next
|
||||||
|
[7] (signed word~) main::$0 ← callfinalize next
|
||||||
|
[8] *((const signed word*) SCREEN#0) ← (signed word~) main::$0
|
||||||
|
[9] callprepare next
|
||||||
|
[10] callexecute next
|
||||||
|
[11] (signed word~) main::$1 ← callfinalize next
|
||||||
|
[12] *((const signed word*) SCREEN#0+(byte) 1*(const byte) SIZEOF_SIGNED_WORD) ← (signed word~) main::$1
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
[13] return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
__stackcall (signed word()) next()
|
||||||
|
next: scope:[next] from
|
||||||
|
[14] (signed word) current#5 ← phi( )
|
||||||
|
[15] (signed word) next::return#0 ← (signed word) current#5
|
||||||
|
to:next::@return
|
||||||
|
next::@return: scope:[next] from next
|
||||||
|
[16] return (signed word) next::return#0
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
|
||||||
|
VARIABLE REGISTER WEIGHTS
|
||||||
|
(signed word*) SCREEN
|
||||||
|
(signed word) current
|
||||||
|
(signed word) current#5 2.0
|
||||||
|
(void()) main()
|
||||||
|
(signed word~) main::$0 2.0
|
||||||
|
(signed word~) main::$1 2.0
|
||||||
|
__stackcall (signed word()) next()
|
||||||
|
(signed word) next::return
|
||||||
|
(signed word) next::return#0 2.0
|
||||||
|
|
||||||
|
Initial phi equivalence classes
|
||||||
|
[ current#5 ]
|
||||||
|
Added variable main::$0 to zero page equivalence class [ main::$0 ]
|
||||||
|
Added variable main::$1 to zero page equivalence class [ main::$1 ]
|
||||||
|
Added variable next::return#0 to zero page equivalence class [ next::return#0 ]
|
||||||
|
Complete equivalence classes
|
||||||
|
[ current#5 ]
|
||||||
|
[ main::$0 ]
|
||||||
|
[ main::$1 ]
|
||||||
|
[ next::return#0 ]
|
||||||
|
Allocated zp ZP_WORD:2 [ current#5 ]
|
||||||
|
Allocated zp ZP_WORD:4 [ main::$0 ]
|
||||||
|
Allocated zp ZP_WORD:6 [ main::$1 ]
|
||||||
|
Allocated zp ZP_WORD:8 [ next::return#0 ]
|
||||||
|
|
||||||
|
INITIAL ASM
|
||||||
|
Target platform is c64basic / MOS6502X
|
||||||
|
// File Comments
|
||||||
|
// Test a procedure with calling convention stack
|
||||||
|
// Return value larger than parameter
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(bbegin)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.const SIZEOF_SIGNED_WORD = 2
|
||||||
|
.label SCREEN = $400
|
||||||
|
.const STACK_BASE = $103
|
||||||
|
.label current = 2
|
||||||
|
// @begin
|
||||||
|
bbegin:
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
b1_from_bbegin:
|
||||||
|
jmp b1
|
||||||
|
// @1
|
||||||
|
b1:
|
||||||
|
// [2] call main
|
||||||
|
// [4] phi from @1 to main [phi:@1->main]
|
||||||
|
main_from_b1:
|
||||||
|
jsr main
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
bend_from_b1:
|
||||||
|
jmp bend
|
||||||
|
// @end
|
||||||
|
bend:
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
.label _0 = 4
|
||||||
|
.label _1 = 6
|
||||||
|
// [5] callprepare next
|
||||||
|
// [5] callprepare next -- _stackpushbyte_2
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
// [5] callprepare next
|
||||||
|
// [6] callexecute next -- jsr
|
||||||
|
jsr next
|
||||||
|
// [7] (signed word~) main::$0 ← callfinalize next
|
||||||
|
// [7] (signed word~) main::$0 ← callfinalize next -- vwsz1=_stackpullsword_
|
||||||
|
pla
|
||||||
|
sta.z _0
|
||||||
|
pla
|
||||||
|
sta.z _0+1
|
||||||
|
// [8] *((const signed word*) SCREEN#0) ← (signed word~) main::$0 -- _deref_pwsc1=vwsz1
|
||||||
|
lda.z _0
|
||||||
|
sta SCREEN
|
||||||
|
lda.z _0+1
|
||||||
|
sta SCREEN+1
|
||||||
|
// [9] callprepare next
|
||||||
|
// [9] callprepare next -- _stackpushbyte_2
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
// [9] callprepare next
|
||||||
|
// [10] callexecute next -- jsr
|
||||||
|
jsr next
|
||||||
|
// [11] (signed word~) main::$1 ← callfinalize next
|
||||||
|
// [11] (signed word~) main::$1 ← callfinalize next -- vwsz1=_stackpullsword_
|
||||||
|
pla
|
||||||
|
sta.z _1
|
||||||
|
pla
|
||||||
|
sta.z _1+1
|
||||||
|
// [12] *((const signed word*) SCREEN#0+(byte) 1*(const byte) SIZEOF_SIGNED_WORD) ← (signed word~) main::$1 -- _deref_pwsc1=vwsz1
|
||||||
|
lda.z _1
|
||||||
|
sta SCREEN+1*SIZEOF_SIGNED_WORD
|
||||||
|
lda.z _1+1
|
||||||
|
sta SCREEN+1*SIZEOF_SIGNED_WORD+1
|
||||||
|
jmp breturn
|
||||||
|
// main::@return
|
||||||
|
breturn:
|
||||||
|
// [13] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// next
|
||||||
|
next: {
|
||||||
|
.const OFFSET_STACK_RETURN = 0
|
||||||
|
.label return = 8
|
||||||
|
// [15] (signed word) next::return#0 ← (signed word) current#5 -- vwsz1=vwsz2
|
||||||
|
lda.z current
|
||||||
|
sta.z return
|
||||||
|
lda.z current+1
|
||||||
|
sta.z return+1
|
||||||
|
jmp breturn
|
||||||
|
// next::@return
|
||||||
|
breturn:
|
||||||
|
// [16] return (signed word) next::return#0
|
||||||
|
// [16] return (signed word) next::return#0 -- _stackidxsword_vbuc1=vwsz1
|
||||||
|
tsx
|
||||||
|
lda.z return
|
||||||
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
|
lda.z return+1
|
||||||
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||||
|
Statement [7] (signed word~) main::$0 ← callfinalize next [ main::$0 ] ( main:2 [ main::$0 ] ) always clobbers reg byte a
|
||||||
|
Statement [8] *((const signed word*) SCREEN#0) ← (signed word~) main::$0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||||
|
Statement [11] (signed word~) main::$1 ← callfinalize next [ main::$1 ] ( main:2 [ main::$1 ] ) always clobbers reg byte a
|
||||||
|
Statement [12] *((const signed word*) SCREEN#0+(byte) 1*(const byte) SIZEOF_SIGNED_WORD) ← (signed word~) main::$1 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||||
|
Statement [15] (signed word) next::return#0 ← (signed word) current#5 [ next::return#0 ] ( main:2::next:6 [ next::return#0 ] main:2::next:10 [ next::return#0 ] ) always clobbers reg byte a
|
||||||
|
Statement [16] return (signed word) next::return#0 [ ] ( main:2::next:6 [ ] main:2::next:10 [ ] ) always clobbers reg byte a reg byte x
|
||||||
|
Potential registers zp ZP_WORD:2 [ current#5 ] : zp ZP_WORD:2 ,
|
||||||
|
Potential registers zp ZP_WORD:4 [ main::$0 ] : zp ZP_WORD:4 ,
|
||||||
|
Potential registers zp ZP_WORD:6 [ main::$1 ] : zp ZP_WORD:6 ,
|
||||||
|
Potential registers zp ZP_WORD:8 [ next::return#0 ] : zp ZP_WORD:8 ,
|
||||||
|
|
||||||
|
REGISTER UPLIFT SCOPES
|
||||||
|
Uplift Scope [main] 2: zp ZP_WORD:4 [ main::$0 ] 2: zp ZP_WORD:6 [ main::$1 ]
|
||||||
|
Uplift Scope [next] 2: zp ZP_WORD:8 [ next::return#0 ]
|
||||||
|
Uplift Scope [] 2: zp ZP_WORD:2 [ current#5 ]
|
||||||
|
|
||||||
|
Uplifting [main] best 140 combination zp ZP_WORD:4 [ main::$0 ] zp ZP_WORD:6 [ main::$1 ]
|
||||||
|
Uplifting [next] best 140 combination zp ZP_WORD:8 [ next::return#0 ]
|
||||||
|
Uplifting [] best 140 combination zp ZP_WORD:2 [ current#5 ]
|
||||||
|
Coalescing zero page register [ zp ZP_WORD:2 [ current#5 ] ] with [ zp ZP_WORD:8 [ next::return#0 ] ] - score: 1
|
||||||
|
Coalescing zero page register [ zp ZP_WORD:4 [ main::$0 ] ] with [ zp ZP_WORD:2 [ current#5 next::return#0 ] ]
|
||||||
|
Allocated (was zp ZP_WORD:4) zp ZP_WORD:2 [ main::$0 current#5 next::return#0 ]
|
||||||
|
Allocated (was zp ZP_WORD:6) zp ZP_WORD:4 [ main::$1 ]
|
||||||
|
|
||||||
|
ASSEMBLER BEFORE OPTIMIZATION
|
||||||
|
// File Comments
|
||||||
|
// Test a procedure with calling convention stack
|
||||||
|
// Return value larger than parameter
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(bbegin)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.const SIZEOF_SIGNED_WORD = 2
|
||||||
|
.label SCREEN = $400
|
||||||
|
.const STACK_BASE = $103
|
||||||
|
.label current = 2
|
||||||
|
// @begin
|
||||||
|
bbegin:
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
b1_from_bbegin:
|
||||||
|
jmp b1
|
||||||
|
// @1
|
||||||
|
b1:
|
||||||
|
// [2] call main
|
||||||
|
// [4] phi from @1 to main [phi:@1->main]
|
||||||
|
main_from_b1:
|
||||||
|
jsr main
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
bend_from_b1:
|
||||||
|
jmp bend
|
||||||
|
// @end
|
||||||
|
bend:
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
.label _0 = 2
|
||||||
|
.label _1 = 4
|
||||||
|
// [5] callprepare next
|
||||||
|
// [5] callprepare next -- _stackpushbyte_2
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
// [5] callprepare next
|
||||||
|
// [6] callexecute next -- jsr
|
||||||
|
jsr next
|
||||||
|
// [7] (signed word~) main::$0 ← callfinalize next
|
||||||
|
// [7] (signed word~) main::$0 ← callfinalize next -- vwsz1=_stackpullsword_
|
||||||
|
pla
|
||||||
|
sta.z _0
|
||||||
|
pla
|
||||||
|
sta.z _0+1
|
||||||
|
// [8] *((const signed word*) SCREEN#0) ← (signed word~) main::$0 -- _deref_pwsc1=vwsz1
|
||||||
|
lda.z _0
|
||||||
|
sta SCREEN
|
||||||
|
lda.z _0+1
|
||||||
|
sta SCREEN+1
|
||||||
|
// [9] callprepare next
|
||||||
|
// [9] callprepare next -- _stackpushbyte_2
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
// [9] callprepare next
|
||||||
|
// [10] callexecute next -- jsr
|
||||||
|
jsr next
|
||||||
|
// [11] (signed word~) main::$1 ← callfinalize next
|
||||||
|
// [11] (signed word~) main::$1 ← callfinalize next -- vwsz1=_stackpullsword_
|
||||||
|
pla
|
||||||
|
sta.z _1
|
||||||
|
pla
|
||||||
|
sta.z _1+1
|
||||||
|
// [12] *((const signed word*) SCREEN#0+(byte) 1*(const byte) SIZEOF_SIGNED_WORD) ← (signed word~) main::$1 -- _deref_pwsc1=vwsz1
|
||||||
|
lda.z _1
|
||||||
|
sta SCREEN+1*SIZEOF_SIGNED_WORD
|
||||||
|
lda.z _1+1
|
||||||
|
sta SCREEN+1*SIZEOF_SIGNED_WORD+1
|
||||||
|
jmp breturn
|
||||||
|
// main::@return
|
||||||
|
breturn:
|
||||||
|
// [13] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// next
|
||||||
|
next: {
|
||||||
|
.const OFFSET_STACK_RETURN = 0
|
||||||
|
.label return = 2
|
||||||
|
// [15] (signed word) next::return#0 ← (signed word) current#5
|
||||||
|
jmp breturn
|
||||||
|
// next::@return
|
||||||
|
breturn:
|
||||||
|
// [16] return (signed word) next::return#0
|
||||||
|
// [16] return (signed word) next::return#0 -- _stackidxsword_vbuc1=vwsz1
|
||||||
|
tsx
|
||||||
|
lda.z return
|
||||||
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
|
lda.z return+1
|
||||||
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
ASSEMBLER OPTIMIZATIONS
|
||||||
|
Removing instruction jmp b1
|
||||||
|
Removing instruction jmp bend
|
||||||
|
Removing instruction jmp breturn
|
||||||
|
Removing instruction jmp breturn
|
||||||
|
Succesful ASM optimization Pass5NextJumpElimination
|
||||||
|
Removing instruction b1_from_bbegin:
|
||||||
|
Removing instruction b1:
|
||||||
|
Removing instruction main_from_b1:
|
||||||
|
Removing instruction bend_from_b1:
|
||||||
|
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||||
|
Removing instruction bend:
|
||||||
|
Removing instruction breturn:
|
||||||
|
Removing instruction breturn:
|
||||||
|
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||||
|
Updating BasicUpstart to call main directly
|
||||||
|
Removing instruction jsr main
|
||||||
|
Succesful ASM optimization Pass5SkipBegin
|
||||||
|
Removing instruction bbegin:
|
||||||
|
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||||
|
|
||||||
|
FINAL SYMBOL TABLE
|
||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(signed word*) SCREEN
|
||||||
|
(const signed word*) SCREEN#0 SCREEN = (signed word*) 1024
|
||||||
|
(const byte) SIZEOF_SIGNED_WORD SIZEOF_SIGNED_WORD = (byte) 2
|
||||||
|
(const word) STACK_BASE STACK_BASE = (word) $103
|
||||||
|
(signed word) current
|
||||||
|
(signed word) current#5 current zp ZP_WORD:2 2.0
|
||||||
|
(void()) main()
|
||||||
|
(signed word~) main::$0 $0 zp ZP_WORD:2 2.0
|
||||||
|
(signed word~) main::$1 $1 zp ZP_WORD:4 2.0
|
||||||
|
(label) main::@return
|
||||||
|
__stackcall (signed word()) next()
|
||||||
|
(label) next::@return
|
||||||
|
(const byte) next::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 0
|
||||||
|
(signed word) next::return
|
||||||
|
(signed word) next::return#0 return zp ZP_WORD:2 2.0
|
||||||
|
|
||||||
|
zp ZP_WORD:2 [ main::$0 current#5 next::return#0 ]
|
||||||
|
zp ZP_WORD:4 [ main::$1 ]
|
||||||
|
|
||||||
|
|
||||||
|
FINAL ASSEMBLER
|
||||||
|
Score: 110
|
||||||
|
|
||||||
|
// File Comments
|
||||||
|
// Test a procedure with calling convention stack
|
||||||
|
// Return value larger than parameter
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.const SIZEOF_SIGNED_WORD = 2
|
||||||
|
.label SCREEN = $400
|
||||||
|
.const STACK_BASE = $103
|
||||||
|
.label current = 2
|
||||||
|
// @begin
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
// @1
|
||||||
|
// [2] call main
|
||||||
|
// [4] phi from @1 to main [phi:@1->main]
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
// @end
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
.label _0 = 2
|
||||||
|
.label _1 = 4
|
||||||
|
// next()
|
||||||
|
// [5] callprepare next
|
||||||
|
// [5] callprepare next -- _stackpushbyte_2
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
// [5] callprepare next
|
||||||
|
// [6] callexecute next -- jsr
|
||||||
|
jsr next
|
||||||
|
// [7] (signed word~) main::$0 ← callfinalize next
|
||||||
|
// [7] (signed word~) main::$0 ← callfinalize next -- vwsz1=_stackpullsword_
|
||||||
|
pla
|
||||||
|
sta.z _0
|
||||||
|
pla
|
||||||
|
sta.z _0+1
|
||||||
|
// SCREEN[0] = next()
|
||||||
|
// [8] *((const signed word*) SCREEN#0) ← (signed word~) main::$0 -- _deref_pwsc1=vwsz1
|
||||||
|
lda.z _0
|
||||||
|
sta SCREEN
|
||||||
|
lda.z _0+1
|
||||||
|
sta SCREEN+1
|
||||||
|
// next()
|
||||||
|
// [9] callprepare next
|
||||||
|
// [9] callprepare next -- _stackpushbyte_2
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
// [9] callprepare next
|
||||||
|
// [10] callexecute next -- jsr
|
||||||
|
jsr next
|
||||||
|
// [11] (signed word~) main::$1 ← callfinalize next
|
||||||
|
// [11] (signed word~) main::$1 ← callfinalize next -- vwsz1=_stackpullsword_
|
||||||
|
pla
|
||||||
|
sta.z _1
|
||||||
|
pla
|
||||||
|
sta.z _1+1
|
||||||
|
// SCREEN[1] = next()
|
||||||
|
// [12] *((const signed word*) SCREEN#0+(byte) 1*(const byte) SIZEOF_SIGNED_WORD) ← (signed word~) main::$1 -- _deref_pwsc1=vwsz1
|
||||||
|
lda.z _1
|
||||||
|
sta SCREEN+1*SIZEOF_SIGNED_WORD
|
||||||
|
lda.z _1+1
|
||||||
|
sta SCREEN+1*SIZEOF_SIGNED_WORD+1
|
||||||
|
// main::@return
|
||||||
|
// }
|
||||||
|
// [13] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// next
|
||||||
|
next: {
|
||||||
|
.const OFFSET_STACK_RETURN = 0
|
||||||
|
.label return = 2
|
||||||
|
// return current++;
|
||||||
|
// [15] (signed word) next::return#0 ← (signed word) current#5
|
||||||
|
// next::@return
|
||||||
|
// }
|
||||||
|
// [16] return (signed word) next::return#0
|
||||||
|
// [16] return (signed word) next::return#0 -- _stackidxsword_vbuc1=vwsz1
|
||||||
|
tsx
|
||||||
|
lda.z return
|
||||||
|
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||||
|
lda.z return+1
|
||||||
|
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
21
src/test/ref/procedure-callingconvention-stack-5.sym
Normal file
21
src/test/ref/procedure-callingconvention-stack-5.sym
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(signed word*) SCREEN
|
||||||
|
(const signed word*) SCREEN#0 SCREEN = (signed word*) 1024
|
||||||
|
(const byte) SIZEOF_SIGNED_WORD SIZEOF_SIGNED_WORD = (byte) 2
|
||||||
|
(const word) STACK_BASE STACK_BASE = (word) $103
|
||||||
|
(signed word) current
|
||||||
|
(signed word) current#5 current zp ZP_WORD:2 2.0
|
||||||
|
(void()) main()
|
||||||
|
(signed word~) main::$0 $0 zp ZP_WORD:2 2.0
|
||||||
|
(signed word~) main::$1 $1 zp ZP_WORD:4 2.0
|
||||||
|
(label) main::@return
|
||||||
|
__stackcall (signed word()) next()
|
||||||
|
(label) next::@return
|
||||||
|
(const byte) next::OFFSET_STACK_RETURN OFFSET_STACK_RETURN = (byte) 0
|
||||||
|
(signed word) next::return
|
||||||
|
(signed word) next::return#0 return zp ZP_WORD:2 2.0
|
||||||
|
|
||||||
|
zp ZP_WORD:2 [ main::$0 current#5 next::return#0 ]
|
||||||
|
zp ZP_WORD:4 [ main::$1 ]
|
Loading…
x
Reference in New Issue
Block a user