1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-07 07:29:49 +00:00

Added stack clean-up. Added parameter stack fetch type. #316

This commit is contained in:
Jesper Gravgaard 2019-09-20 14:19:43 +02:00
parent c6a5c54909
commit 5e1c05dc2e
7 changed files with 61 additions and 27 deletions

View File

@ -357,8 +357,8 @@ public class AsmFragmentInstanceSpecFactory {
bind(name, value);
return name;
} else if(value instanceof ParamStackValue) {
// TODO: Handle different parameter types!
return "_stackbyte_"+bind(((ParamStackValue) value).getStackOffset());
ParamStackValue paramStackValue = (ParamStackValue) value;
return "_stack"+paramStackValue.getValueType().getTypeName()+"_"+bind(paramStackValue.getStackOffset());
} else if(value instanceof ParamStackPush) {
return "_push"+((ParamStackPush) value).getType().getTypeName()+"_";
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.model.values;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.types.SymbolType;
/** The value passed into a function for a specific parameter using the stack. */
public class ParamStackValue implements RValue {
@ -8,8 +9,12 @@ public class ParamStackValue implements RValue {
/** The constant holding the stack offset of the parameter. */
private ConstantRef stackOffset;
public ParamStackValue(ConstantRef stackOffset) {
/** The type of the value to fetch from the stack. */
private SymbolType valueType;
public ParamStackValue(ConstantRef stackOffset, SymbolType valueType) {
this.stackOffset = stackOffset;
this.valueType = valueType;
}
public ConstantRef getStackOffset() {
@ -20,9 +25,17 @@ public class ParamStackValue implements RValue {
this.stackOffset = stackOffset;
}
public SymbolType getValueType() {
return valueType;
}
public void setValueType(SymbolType valueType) {
this.valueType = valueType;
}
@Override
public String toString(Program program) {
return "paramstack("+stackOffset+")";
return "paramstack("+valueType.getTypeName()+","+stackOffset+")";
}
}

View File

@ -757,8 +757,19 @@ public class Pass4CodeGeneration {
generateAsm(asm, asmFragmentInstanceSpecFactory);
}
}
asm.addInstruction("jsr", AsmAddressingMode.ABS, call.getProcedure().getFullName(), false);
// Clean up the stack
if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
int parameterBytes = 0;
for(RValue parameter : call.getParameters()) {
SymbolType parameterType = SymbolTypeInference.inferType(program.getScope(), parameter);
parameterBytes += parameterType.getSizeBytes();
}
// TODO: Replace with fragment - to allow hand-coded handling of the stack pointer modifications - eg. using TSX, TXA, AXS #{}, TXS
for(int i = 0; i < parameterBytes; i++) {
asm.addInstruction("pla", AsmAddressingMode.NON, null, false);
}
}
} else if(statement instanceof StatementReturn) {
Procedure.InterruptType interruptType = null;
ScopeRef scope = block.getScope();

View File

@ -4,6 +4,7 @@ import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeInference;
import dk.camelot64.kickc.model.values.*;
import java.util.HashMap;
@ -42,8 +43,9 @@ public class PassNCallingConventionStack extends Pass2SsaOptimization {
// Convert ParamValues to calling-convention specific param-value
ParamValue paramValue = (ParamValue) programValue.get();
VariableRef parameterRef = paramValue.getParameter();
SymbolType parameterType = SymbolTypeInference.inferType(getScope(), paramValue.getParameter());
if(offsetConstants.containsKey(parameterRef)) {
ParamStackValue paramStackValue = new ParamStackValue(offsetConstants.get(parameterRef));
ParamStackValue paramStackValue = new ParamStackValue(offsetConstants.get(parameterRef), parameterType);
programValue.set(paramStackValue);
getLog().append("Calling convention " + Procedure.CallingConvension.STACK_CALL + " replacing " + paramValue.toString(getProgram()) + " with " + paramStackValue.toString(getProgram()));
}

View File

@ -10,6 +10,8 @@ main: {
lda #7
pha
jsr plus
pla
pla
sty SCREEN
rts
}

View File

@ -20,8 +20,8 @@ main::@return: scope:[main] from main
__stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
plus: scope:[plus] from
[8] (byte) plus::a#0 ← paramstack(plus::OFFSET_STACK_A)
[9] (byte) plus::b#0 ← paramstack(plus::OFFSET_STACK_B)
[8] (byte) plus::a#0 ← paramstack(byte,plus::OFFSET_STACK_A)
[9] (byte) plus::b#0 ← paramstack(byte,plus::OFFSET_STACK_B)
[10] (byte) plus::return#0 ← (byte) plus::a#0 + (byte) plus::b#0
to:plus::@return
plus::@return: scope:[plus] from plus

View File

@ -89,8 +89,8 @@ 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 replacing param((byte) plus::a) with paramstack(plus::OFFSET_STACK_A)
Calling convention STACK_CALL replacing param((byte) plus::b) with paramstack(plus::OFFSET_STACK_B)
Calling convention STACK_CALL replacing param((byte) plus::a) with paramstack(byte,plus::OFFSET_STACK_A)
Calling convention STACK_CALL replacing param((byte) plus::b) with paramstack(byte,plus::OFFSET_STACK_B)
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
@ -115,8 +115,8 @@ main::@return: scope:[main] from main
__stackcall (byte()) plus((byte) plus::a , (byte) plus::b)
plus: scope:[plus] from
[8] (byte) plus::a#0 ← paramstack(plus::OFFSET_STACK_A)
[9] (byte) plus::b#0 ← paramstack(plus::OFFSET_STACK_B)
[8] (byte) plus::a#0 ← paramstack(byte,plus::OFFSET_STACK_A)
[9] (byte) plus::b#0 ← paramstack(byte,plus::OFFSET_STACK_B)
[10] (byte) plus::return#0 ← (byte) plus::a#0 + (byte) plus::b#0
to:plus::@return
plus::@return: scope:[plus] from plus
@ -187,6 +187,8 @@ main: {
lda #7
pha
jsr plus
pla
pla
// [6] *((const byte*) SCREEN#0) ← (byte~) main::$0 -- _deref_pbuc1=vbuz1
lda.z _0
sta SCREEN
@ -204,11 +206,11 @@ plus: {
.label a = 3
.label b = 4
.label return = 5
// [8] (byte) plus::a#0 ← paramstack(plus::OFFSET_STACK_A) -- vbuz1=_stackbyte_vbuc1
// [8] (byte) plus::a#0 ← paramstack(byte,plus::OFFSET_STACK_A) -- vbuz1=_stackbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_A,x
sta.z a
// [9] (byte) plus::b#0 ← paramstack(plus::OFFSET_STACK_B) -- vbuz1=_stackbyte_vbuc1
// [9] (byte) plus::b#0 ← paramstack(byte,plus::OFFSET_STACK_B) -- vbuz1=_stackbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_B,x
sta.z b
@ -227,16 +229,16 @@ plus: {
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [5] (byte~) main::$0 ← call plus (byte) '0' (byte) 7 [ main::$0 ] ( main:2 [ main::$0 ] ) always clobbers reg byte a
Statement [8] (byte) plus::a#0 ← paramstack(plus::OFFSET_STACK_A) [ plus::a#0 ] ( main:2::plus:5 [ main::$0 plus::a#0 ] ) always clobbers reg byte a reg byte x
Statement [8] (byte) plus::a#0 ← paramstack(byte,plus::OFFSET_STACK_A) [ plus::a#0 ] ( main:2::plus:5 [ main::$0 plus::a#0 ] ) always clobbers reg byte a reg byte x
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::$0 ]
Removing always clobbered register reg byte x as potential for zp ZP_BYTE:2 [ main::$0 ]
Statement [9] (byte) plus::b#0 ← paramstack(plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( main:2::plus:5 [ main::$0 plus::a#0 plus::b#0 ] ) always clobbers reg byte a reg byte x
Statement [9] (byte) plus::b#0 ← paramstack(byte,plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( main:2::plus:5 [ main::$0 plus::a#0 plus::b#0 ] ) always clobbers reg byte a reg byte x
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ plus::a#0 ]
Removing always clobbered register reg byte x as potential for zp ZP_BYTE:3 [ plus::a#0 ]
Statement [10] (byte) plus::return#0 ← (byte) plus::a#0 + (byte) plus::b#0 [ plus::return#0 ] ( main:2::plus:5 [ main::$0 plus::return#0 ] ) always clobbers reg byte a
Statement [5] (byte~) main::$0 ← call plus (byte) '0' (byte) 7 [ main::$0 ] ( main:2 [ main::$0 ] ) always clobbers reg byte a
Statement [8] (byte) plus::a#0 ← paramstack(plus::OFFSET_STACK_A) [ plus::a#0 ] ( main:2::plus:5 [ main::$0 plus::a#0 ] ) always clobbers reg byte a reg byte x
Statement [9] (byte) plus::b#0 ← paramstack(plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( main:2::plus:5 [ main::$0 plus::a#0 plus::b#0 ] ) always clobbers reg byte a reg byte x
Statement [8] (byte) plus::a#0 ← paramstack(byte,plus::OFFSET_STACK_A) [ plus::a#0 ] ( main:2::plus:5 [ main::$0 plus::a#0 ] ) always clobbers reg byte a reg byte x
Statement [9] (byte) plus::b#0 ← paramstack(byte,plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( main:2::plus:5 [ main::$0 plus::a#0 plus::b#0 ] ) always clobbers reg byte a reg byte x
Statement [10] (byte) plus::return#0 ← (byte) plus::a#0 + (byte) plus::b#0 [ plus::return#0 ] ( main:2::plus:5 [ main::$0 plus::return#0 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::$0 ] : zp ZP_BYTE:2 , reg byte y ,
Potential registers zp ZP_BYTE:3 [ plus::a#0 ] : zp ZP_BYTE:3 , reg byte y ,
@ -248,11 +250,11 @@ Uplift Scope [plus] 4: zp ZP_BYTE:4 [ plus::b#0 ] 2: zp ZP_BYTE:3 [ plus::a#0 ]
Uplift Scope [main] 0.5: zp ZP_BYTE:2 [ main::$0 ]
Uplift Scope []
Uplifting [plus] best 73 combination reg byte a [ plus::b#0 ] zp ZP_BYTE:3 [ plus::a#0 ] reg byte a [ plus::return#0 ]
Uplifting [main] best 70 combination reg byte y [ main::$0 ]
Uplifting [] best 70 combination
Uplifting [plus] best 81 combination reg byte a [ plus::b#0 ] zp ZP_BYTE:3 [ plus::a#0 ] reg byte a [ plus::return#0 ]
Uplifting [main] best 78 combination reg byte y [ main::$0 ]
Uplifting [] best 78 combination
Attempting to uplift remaining variables inzp ZP_BYTE:3 [ plus::a#0 ]
Uplifting [plus] best 70 combination zp ZP_BYTE:3 [ plus::a#0 ]
Uplifting [plus] best 78 combination zp ZP_BYTE:3 [ plus::a#0 ]
Allocated (was zp ZP_BYTE:3) zp ZP_BYTE:2 [ plus::a#0 ]
ASSEMBLER BEFORE OPTIMIZATION
@ -289,6 +291,8 @@ main: {
lda #7
pha
jsr plus
pla
pla
// [6] *((const byte*) SCREEN#0) ← (byte~) main::$0 -- _deref_pbuc1=vbuyy
sty SCREEN
jmp breturn
@ -303,11 +307,11 @@ plus: {
.const OFFSET_STACK_A = 0
.const OFFSET_STACK_B = 1
.label a = 2
// [8] (byte) plus::a#0 ← paramstack(plus::OFFSET_STACK_A) -- vbuz1=_stackbyte_vbuc1
// [8] (byte) plus::a#0 ← paramstack(byte,plus::OFFSET_STACK_A) -- vbuz1=_stackbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_A,x
sta.z a
// [9] (byte) plus::b#0 ← paramstack(plus::OFFSET_STACK_B) -- vbuaa=_stackbyte_vbuc1
// [9] (byte) plus::b#0 ← paramstack(byte,plus::OFFSET_STACK_B) -- vbuaa=_stackbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_B,x
// [10] (byte) plus::return#0 ← (byte) plus::a#0 + (byte) plus::b#0 -- vbuaa=vbuz1_plus_vbuaa
@ -370,7 +374,7 @@ reg byte a [ plus::return#0 ]
FINAL ASSEMBLER
Score: 52
Score: 60
// File Comments
// Test a procedure with calling convention stack
@ -397,6 +401,8 @@ main: {
lda #7
pha
jsr plus
pla
pla
// SCREEN[0] = plus('0', 7)
// [6] *((const byte*) SCREEN#0) ← (byte~) main::$0 -- _deref_pbuc1=vbuyy
sty SCREEN
@ -411,11 +417,11 @@ plus: {
.const OFFSET_STACK_A = 0
.const OFFSET_STACK_B = 1
.label a = 2
// [8] (byte) plus::a#0 ← paramstack(plus::OFFSET_STACK_A) -- vbuz1=_stackbyte_vbuc1
// [8] (byte) plus::a#0 ← paramstack(byte,plus::OFFSET_STACK_A) -- vbuz1=_stackbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_A,x
sta.z a
// [9] (byte) plus::b#0 ← paramstack(plus::OFFSET_STACK_B) -- vbuaa=_stackbyte_vbuc1
// [9] (byte) plus::b#0 ← paramstack(byte,plus::OFFSET_STACK_B) -- vbuaa=_stackbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_B,x
// return a+b;