mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-23 23:32:55 +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());
|
||||
} else if(
|
||||
rValue2 instanceof ConstantInteger &&
|
||||
((((ConstantInteger) rValue2).getValue()) % 8 == 0) &&
|
||||
((((ConstantInteger) rValue2).getValue()) % 8 == 0) &&
|
||||
operator != null &&
|
||||
(operator.getOperator().equals(">>") || operator.getOperator().equals("<<"))) {
|
||||
signature.append(((ConstantInteger) rValue2).getValue());
|
||||
@ -313,7 +313,7 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
if(bindPointer.contains("deref")) {
|
||||
// Special handling of nested derefs - add parenthesis!
|
||||
return "_deref_" + "(" + bindPointer + ")";
|
||||
} else {
|
||||
} else {
|
||||
return "_deref_" + bindPointer;
|
||||
}
|
||||
} else if(value instanceof PointerDereferenceIndexed) {
|
||||
@ -323,7 +323,7 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
if(bindPointer.contains("deref")) {
|
||||
// Special handling of nested derefs - add parenthesis!
|
||||
bindValue.append("(").append(bindPointer).append(")");
|
||||
} else {
|
||||
} else {
|
||||
bindValue.append(bindPointer);
|
||||
}
|
||||
bindValue.append("_derefidx_");
|
||||
@ -358,11 +358,17 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
return name;
|
||||
} else if(value instanceof StackIdxValue) {
|
||||
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) {
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
|
@ -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);
|
||||
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));
|
||||
}
|
||||
} else if(statement instanceof StatementCallExecute) {
|
||||
@ -778,21 +789,16 @@ public class Pass4CodeGeneration {
|
||||
StatementCallFinalize call = (StatementCallFinalize) statement;
|
||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
||||
// Find parameter/return stack size
|
||||
int parameterBytes = 0;
|
||||
for(Variable parameter : procedure.getParameters()) {
|
||||
parameterBytes += parameter.getType().getSizeBytes();
|
||||
|
||||
long stackFrameByteSize = CallingConventionStack.getStackFrameByteSize(procedure);
|
||||
long returnByteSize = procedure.getReturnType()==null?0:procedure.getReturnType().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
|
||||
if(call.getlValue() != null) {
|
||||
@ -811,28 +817,21 @@ public class Pass4CodeGeneration {
|
||||
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;
|
||||
if(returnStatement.getValue()!=null) {
|
||||
if(returnStatement.getValue() != null) {
|
||||
// Store return value on stack
|
||||
SymbolType returnType = procedure.getReturnType();
|
||||
|
||||
// Find parameter/return stack size
|
||||
int parameterBytes = 0;
|
||||
for(Variable parameter : procedure.getParameters()) {
|
||||
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());
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
if(procedure==null || procedure.getInterruptType() == null) {
|
||||
if(procedure == null || procedure.getInterruptType() == null) {
|
||||
asm.addInstruction("rts", AsmAddressingMode.NON, null, false);
|
||||
} else {
|
||||
generateInterruptExit(asm, statement, procedure.getInterruptType());
|
||||
|
@ -1,5 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CallingConventionStack;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
@ -26,15 +27,27 @@ public class PassNCallingConventionStack extends Pass2SsaOptimization {
|
||||
Map<VariableRef, ConstantRef> offsetConstants = new HashMap<>();
|
||||
|
||||
// Introduce STACK_OFFSET constants
|
||||
boolean createStackBase = false;
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
||||
// Introduce the parameter offsets
|
||||
for(Variable parameter : procedure.getParameters()) {
|
||||
ConstantRef parameterOffsetConstant = getParameterOffsetConstant(procedure, parameter, getScope());
|
||||
ConstantRef parameterOffsetConstant = CallingConventionStack.getParameterOffsetConstant(procedure, parameter);
|
||||
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
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
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 StatementCallExecute(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) {
|
||||
// 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
|
||||
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
if(programValue.get() instanceof ParamValue) {
|
||||
@ -78,53 +87,4 @@ public class PassNCallingConventionStack extends Pass2SsaOptimization {
|
||||
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() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStack5() throws IOException, URISyntaxException {
|
||||
compileAndCompare("procedure-callingconvention-stack-5"); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStack4() throws IOException, URISyntaxException {
|
||||
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: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
@ -28,6 +29,6 @@ plus: {
|
||||
clc
|
||||
adc.z a
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
|
@ -214,6 +214,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 3
|
||||
.label b = 4
|
||||
.label return = 5
|
||||
@ -237,7 +238,7 @@ plus: {
|
||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
||||
lda.z return
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -330,6 +331,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
@ -347,7 +349,7 @@ plus: {
|
||||
// [13] return (byte) plus::return#0
|
||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -387,6 +389,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||
(byte) plus::a
|
||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||
(byte) plus::b
|
||||
@ -450,6 +453,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
@ -467,7 +471,7 @@ plus: {
|
||||
// [13] return (byte) plus::return#0
|
||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
@ -11,6 +11,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||
(byte) plus::a
|
||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||
(byte) plus::b
|
||||
|
@ -19,6 +19,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
@ -28,6 +29,6 @@ plus: {
|
||||
clc
|
||||
adc.z a
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
|
@ -214,6 +214,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 3
|
||||
.label b = 4
|
||||
.label return = 5
|
||||
@ -237,7 +238,7 @@ plus: {
|
||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
||||
lda.z return
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -330,6 +331,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
@ -347,7 +349,7 @@ plus: {
|
||||
// [13] return (byte) plus::return#0
|
||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -387,6 +389,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||
(byte) plus::a
|
||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||
(byte) plus::b
|
||||
@ -450,6 +453,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
// [10] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
@ -467,7 +471,7 @@ plus: {
|
||||
// [13] return (byte) plus::return#0
|
||||
// [13] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
@ -11,6 +11,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||
(byte) plus::a
|
||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||
(byte) plus::b
|
||||
|
@ -31,6 +31,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 2
|
||||
.const OFFSET_STACK_RETURN = 2
|
||||
.label a = 2
|
||||
.label b = 4
|
||||
.label return = 2
|
||||
@ -53,8 +54,8 @@ plus: {
|
||||
sta.z return+1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+2,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+2+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||
rts
|
||||
}
|
||||
|
@ -240,6 +240,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 2
|
||||
.const OFFSET_STACK_RETURN = 2
|
||||
.label a = 4
|
||||
.label b = 6
|
||||
.label return = 8
|
||||
@ -270,9 +271,9 @@ plus: {
|
||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+2,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+2+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -371,6 +372,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 2
|
||||
.const OFFSET_STACK_RETURN = 2
|
||||
.label a = 2
|
||||
.label b = 4
|
||||
.label return = 2
|
||||
@ -401,9 +403,9 @@ plus: {
|
||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+2,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+2+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -443,6 +445,7 @@ __stackcall (word()) plus((word) plus::a , (word) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 2
|
||||
(word) plus::a
|
||||
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
||||
(word) plus::b
|
||||
@ -516,6 +519,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 2
|
||||
.const OFFSET_STACK_RETURN = 2
|
||||
.label a = 2
|
||||
.label b = 4
|
||||
.label return = 2
|
||||
@ -546,9 +550,9 @@ plus: {
|
||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+2,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+2+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
@ -11,6 +11,7 @@ __stackcall (word()) plus((word) plus::a , (word) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 2
|
||||
(word) plus::a
|
||||
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
||||
(word) plus::b
|
||||
|
@ -34,6 +34,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 2
|
||||
.const OFFSET_STACK_RETURN = 2
|
||||
.label a = 2
|
||||
.label b = 4
|
||||
.label return = 2
|
||||
@ -56,8 +57,8 @@ plus: {
|
||||
sta.z return+1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+2,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+2+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||
rts
|
||||
}
|
||||
|
@ -240,6 +240,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 2
|
||||
.const OFFSET_STACK_RETURN = 2
|
||||
.label a = 4
|
||||
.label b = 6
|
||||
.label return = 8
|
||||
@ -270,9 +271,9 @@ plus: {
|
||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+2,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+2+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -374,6 +375,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 2
|
||||
.const OFFSET_STACK_RETURN = 2
|
||||
.label a = 2
|
||||
.label b = 4
|
||||
.label return = 2
|
||||
@ -404,9 +406,9 @@ plus: {
|
||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+2,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+2+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -446,6 +448,7 @@ __stackcall (word()) plus((word) plus::a , (word) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 2
|
||||
(word) plus::a
|
||||
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
||||
(word) plus::b
|
||||
@ -522,6 +525,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 2
|
||||
.const OFFSET_STACK_RETURN = 2
|
||||
.label a = 2
|
||||
.label b = 4
|
||||
.label return = 2
|
||||
@ -552,9 +556,9 @@ plus: {
|
||||
// [13] return (word) plus::return#0 -- _stackidxword_vbuc1=vwuz1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+2,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+2+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN+1,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
@ -11,6 +11,7 @@ __stackcall (word()) plus((word) plus::a , (word) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 2
|
||||
(word) plus::a
|
||||
(word) plus::a#0 a zp ZP_WORD:2 2.0
|
||||
(word) plus::b
|
||||
|
@ -31,6 +31,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
@ -40,6 +41,6 @@ plus: {
|
||||
clc
|
||||
adc.z a
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
|
@ -349,6 +349,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 6
|
||||
.label b = 7
|
||||
.label return = 8
|
||||
@ -372,7 +373,7 @@ plus: {
|
||||
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuz1
|
||||
lda.z return
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -498,6 +499,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
// [15] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
@ -515,7 +517,7 @@ plus: {
|
||||
// [18] return (byte) plus::return#0
|
||||
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
@ -570,6 +572,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||
(byte) plus::a
|
||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||
(byte) plus::b
|
||||
@ -660,6 +663,7 @@ main: {
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 0
|
||||
.const OFFSET_STACK_B = 1
|
||||
.const OFFSET_STACK_RETURN = 1
|
||||
.label a = 2
|
||||
// [15] (byte) plus::a#0 ← stackidx(byte,(const byte) plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
@ -677,7 +681,7 @@ plus: {
|
||||
// [18] return (byte) plus::return#0
|
||||
// [18] return (byte) plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+1,x
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN,x
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
@ -20,6 +20,7 @@ __stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
|
||||
(label) plus::@return
|
||||
(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_RETURN OFFSET_STACK_RETURN = (byte) 1
|
||||
(byte) plus::a
|
||||
(byte) plus::a#0 a zp ZP_BYTE:2 2.0
|
||||
(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…
Reference in New Issue
Block a user