mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
failed attempt of using sys.push/pop for stack args
This commit is contained in:
parent
69dcb4dbda
commit
02348924d0
@ -1,18 +1,31 @@
|
||||
package prog8.compiler.target.cpu6502.codegen
|
||||
|
||||
import prog8.ast.base.Cx16VirtualRegisters
|
||||
import prog8.ast.base.RegisterOrPair
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.Subroutine
|
||||
|
||||
|
||||
internal fun asmsub6502ArgsEvalOrder(sub: Subroutine): List<Int> {
|
||||
val order = mutableListOf<Int>()
|
||||
// order is: 1) cx16 virtual word registers, 2) actual CPU registers, 3) CPU Carry status flag
|
||||
// order is:
|
||||
// 1) cx16 virtual word registers,
|
||||
// 2) paired CPU registers,
|
||||
// 3) single CPU registers (X last),
|
||||
// 4) CPU Carry status flag
|
||||
val args = sub.parameters.zip(sub.asmParameterRegisters).withIndex()
|
||||
val (cx16regs, args2) = args.partition { it.value.second.registerOrPair in Cx16VirtualRegisters }
|
||||
val (regs, rest) = args2.partition { it.value.second.registerOrPair != null }
|
||||
val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)
|
||||
val (pairedRegs , args3) = args2.partition { it.value.second.registerOrPair in pairedRegisters }
|
||||
val (regs, rest) = args3.partition { it.value.second.registerOrPair != null }
|
||||
|
||||
cx16regs.forEach { order += it.index }
|
||||
regs.forEach { order += it.index }
|
||||
pairedRegs.forEach { order += it.index }
|
||||
regs.forEach {
|
||||
if(it.value.second.registerOrPair != RegisterOrPair.X)
|
||||
order += it.index
|
||||
}
|
||||
regs.firstOrNull { it.value.second.registerOrPair==RegisterOrPair.X } ?.let { order += it.index}
|
||||
rest.forEach { order += it.index }
|
||||
require(order.size==sub.parameters.size)
|
||||
return order
|
||||
|
@ -625,6 +625,22 @@ _longcopy
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub rsavex() {
|
||||
%asm {{
|
||||
txa
|
||||
pha
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub rrestorex() {
|
||||
%asm {{
|
||||
sta P8ZP_SCRATCH_REG
|
||||
pla
|
||||
tax
|
||||
lda P8ZP_SCRATCH_REG
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub read_flags() -> ubyte @A {
|
||||
%asm {{
|
||||
php
|
||||
@ -644,6 +660,15 @@ _longcopy
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub popx() -> ubyte @X {
|
||||
%asm {{
|
||||
sta P8ZP_SCRATCH_REG
|
||||
pla
|
||||
tax
|
||||
lda P8ZP_SCRATCH_REG
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub pushw(uword value @AY) {
|
||||
%asm {{
|
||||
pha
|
||||
|
@ -880,6 +880,18 @@ sys {
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub rsavex() {
|
||||
%asm {{
|
||||
phx
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub rrestorex() {
|
||||
%asm {{
|
||||
plx
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub read_flags() -> ubyte @A {
|
||||
%asm {{
|
||||
php
|
||||
@ -899,6 +911,12 @@ sys {
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub popx() -> ubyte @X {
|
||||
%asm {{
|
||||
plx
|
||||
}}
|
||||
}
|
||||
|
||||
inline asmsub pushw(uword value @AY) {
|
||||
%asm {{
|
||||
pha
|
||||
|
@ -265,7 +265,7 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions
|
||||
program.charLiteralsToUByteLiterals(compilerOptions.compTarget)
|
||||
program.constantFold(errors, compilerOptions.compTarget)
|
||||
errors.report()
|
||||
program.reorderStatements(errors, compilerOptions.compTarget)
|
||||
program.reorderStatements(errors, compilerOptions)
|
||||
errors.report()
|
||||
program.addTypecasts(errors)
|
||||
errors.report()
|
||||
@ -327,8 +327,8 @@ private fun writeAssembly(program: Program,
|
||||
program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
||||
errors.report()
|
||||
|
||||
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||
// printProgram(program)
|
||||
println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||
printProgram(program)
|
||||
|
||||
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
||||
val assembly = asmGeneratorFor(compilerOptions.compTarget,
|
||||
|
@ -29,8 +29,8 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Program.reorderStatements(errors: IErrorReporter, target: ICompilationTarget) {
|
||||
val reorder = StatementReorderer(this, errors, target)
|
||||
internal fun Program.reorderStatements(errors: IErrorReporter, options: CompilationOptions) {
|
||||
val reorder = StatementReorderer(this, errors, options)
|
||||
reorder.visit(this)
|
||||
if(errors.noErrors()) {
|
||||
reorder.applyModifications()
|
||||
|
@ -7,11 +7,14 @@ import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.compilerinterface.BuiltinFunctions
|
||||
import prog8.compilerinterface.CompilationOptions
|
||||
import prog8.compilerinterface.ICompilationTarget
|
||||
import prog8.compilerinterface.IErrorReporter
|
||||
|
||||
|
||||
internal class StatementReorderer(val program: Program, val errors: IErrorReporter, private val compTarget: ICompilationTarget) : AstWalker() {
|
||||
internal class StatementReorderer(val program: Program,
|
||||
val errors: IErrorReporter,
|
||||
private val options: CompilationOptions) : AstWalker() {
|
||||
// Reorders the statements in a way the compiler needs.
|
||||
// - 'main' block must be the very first statement UNLESS it has an address set.
|
||||
// - library blocks are put last.
|
||||
@ -397,30 +400,91 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
||||
if(function.parameters.isEmpty()) {
|
||||
// 0 params -> just GoSub
|
||||
return listOf(IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent))
|
||||
} else if(!compTarget.asmsubArgsHaveRegisterClobberRisk(call.args)) {
|
||||
// no register clobber risk, let the asmgen assign values to registers directly.
|
||||
} else if(!options.compTarget.asmsubArgsHaveRegisterClobberRisk(call.args)) {
|
||||
// no register clobber risk, let the asmgen assign values to the registers directly.
|
||||
return noModifications
|
||||
} else {
|
||||
// TODO new logic for passing arguments to asmsub with clobber risk...
|
||||
val argEvalOrder = compTarget.asmsubArgsEvalOrder(function)
|
||||
println("ARGS ORDER OF $call: ${argEvalOrder.toList()}")
|
||||
// clobber risk; evaluate the arguments on the CPU stack first (in reverse order)...
|
||||
if (options.slowCodegenWarnings)
|
||||
errors.warn("slow argument passing used to avoid register clobbering", call.position)
|
||||
val argOrder = options.compTarget.asmsubArgsEvalOrder(function)
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
if(function.shouldSaveX())
|
||||
modifications += IAstModification.InsertBefore(
|
||||
call,
|
||||
FunctionCallStatement(IdentifierReference(listOf("sys", "rsavex"), call.position), mutableListOf(), true, call.position),
|
||||
parent as IStatementContainer
|
||||
)
|
||||
argOrder.reversed().forEach {
|
||||
val arg = call.args[it]
|
||||
val param = function.parameters[it]
|
||||
val push = pushCall(arg, param.type, arg.position)
|
||||
modifications += IAstModification.InsertBefore(call, push, parent as IStatementContainer)
|
||||
}
|
||||
// ... and pop them off again into the registers.
|
||||
argOrder.forEach {
|
||||
val param = function.parameters[it]
|
||||
val targetName = function.scopedName + param.name
|
||||
val popassign =
|
||||
if(function.asmParameterRegisters[it].registerOrPair == RegisterOrPair.X)
|
||||
popCallAssignX(targetName, param.type, call.position)
|
||||
else
|
||||
popCallAssign(targetName, param.type, call.position)
|
||||
modifications += IAstModification.InsertBefore(call, popassign, parent as IStatementContainer)
|
||||
}
|
||||
if(function.shouldSaveX())
|
||||
modifications += IAstModification.InsertAfter(
|
||||
call,
|
||||
FunctionCallStatement(IdentifierReference(listOf("sys", "rrestorex"), call.position), mutableListOf(), true, call.position),
|
||||
parent as IStatementContainer
|
||||
)
|
||||
|
||||
// function.asmsubArgsEvalOrder().forEach {
|
||||
// val arg = call.args[it]
|
||||
// val param = function.parameters[it]
|
||||
// val paramReg = function.asmParameterRegisters[it]
|
||||
// when(param.type) {
|
||||
// DataType.UBYTE -> TODO()
|
||||
// DataType.BYTE -> TODO()
|
||||
// DataType.UWORD -> TODO()
|
||||
// DataType.WORD -> TODO()
|
||||
// else -> throw FatalAstException("invalidt dt for asmsub param")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
return noModifications
|
||||
return modifications + IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun popCallAssignX(targetName: List<String>, dt: DataType, position: Position): Assignment {
|
||||
val func = IdentifierReference(listOf("sys", "popx"), position)
|
||||
val popcall = when(dt) {
|
||||
DataType.UBYTE -> FunctionCall(func, mutableListOf(), position)
|
||||
DataType.BYTE -> TypecastExpression(FunctionCall(func, mutableListOf(), position), DataType.UBYTE, true, position)
|
||||
else -> throw FatalAstException("invalid dt $dt")
|
||||
}
|
||||
return Assignment(
|
||||
AssignTarget(IdentifierReference(targetName, position), null, null, position),
|
||||
popcall, position
|
||||
)
|
||||
}
|
||||
|
||||
private fun popCallAssign(targetName: List<String>, dt: DataType, position: Position): Assignment {
|
||||
val func = IdentifierReference(listOf("sys", if(dt in ByteDatatypes) "pop" else "popw"), position)
|
||||
val popcall = when(dt) {
|
||||
DataType.UBYTE, DataType.UWORD -> FunctionCall(func, mutableListOf(), position)
|
||||
in PassByReferenceDatatypes -> FunctionCall(func, mutableListOf(), position)
|
||||
DataType.BYTE -> TypecastExpression(FunctionCall(func, mutableListOf(), position), DataType.UBYTE, true, position)
|
||||
DataType.WORD -> TypecastExpression(FunctionCall(func, mutableListOf(), position), DataType.UWORD, true, position)
|
||||
else -> throw FatalAstException("invalid dt $dt")
|
||||
}
|
||||
return Assignment(
|
||||
AssignTarget(IdentifierReference(targetName, position), null, null, position),
|
||||
popcall, position
|
||||
)
|
||||
}
|
||||
|
||||
private fun pushCall(value: Expression, dt: DataType, position: Position): FunctionCallStatement {
|
||||
val pushvalue = when(dt) {
|
||||
DataType.UBYTE, DataType.UWORD -> value
|
||||
in PassByReferenceDatatypes -> value
|
||||
DataType.BYTE -> TypecastExpression(value, DataType.UBYTE, true, position)
|
||||
DataType.WORD -> TypecastExpression(value, DataType.UWORD, true, position)
|
||||
else -> throw FatalAstException("invalid dt $dt $value")
|
||||
}
|
||||
|
||||
return FunctionCallStatement(
|
||||
IdentifierReference(listOf("sys", if(dt in ByteDatatypes) "push" else "pushw"), position),
|
||||
mutableListOf(pushvalue),
|
||||
true, position
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
%import textio
|
||||
%import test_stack
|
||||
|
||||
main {
|
||||
@ -6,28 +7,9 @@ main {
|
||||
test_stack.test()
|
||||
|
||||
uword @shared uw
|
||||
|
||||
; sys.push(-22 as ubyte)
|
||||
; sys.push(44)
|
||||
; sys.pushw(-11234 as uword)
|
||||
; sys.pushw(12345)
|
||||
; sys.push(1)
|
||||
; sys.push(2)
|
||||
; ubyte @shared ub = sys.pop()
|
||||
; byte @shared bb = sys.pop() as byte
|
||||
; uw = sys.popw()
|
||||
; word @shared ww = sys.popw() as word
|
||||
; void sys.pop()
|
||||
; void sys.pop()
|
||||
|
||||
routine2(uw, 11,22, true, 33)
|
||||
routine2(uw, 11,22, true, 33)
|
||||
routine2(uw, 11,22, true, 33)
|
||||
routine2(uw, 11,22, true, 33)
|
||||
blerp(22)
|
||||
blerp(22)
|
||||
blerp(22)
|
||||
blerp(22)
|
||||
uw= 0
|
||||
routine(uw+11, 22,33, true, 44)
|
||||
routine2(uw+11, 22,33, true, 44)
|
||||
|
||||
test_stack.test()
|
||||
|
||||
@ -36,14 +18,32 @@ main {
|
||||
|
||||
}
|
||||
|
||||
sub blerp(uword z) {
|
||||
z++
|
||||
sub routine(uword num, ubyte a1, ubyte a2, ubyte switch, byte a3) {
|
||||
txt.print_uw(num)
|
||||
txt.spc()
|
||||
txt.print_ub(a1)
|
||||
txt.spc()
|
||||
txt.print_ub(a2)
|
||||
txt.spc()
|
||||
txt.print_ub(switch)
|
||||
txt.spc()
|
||||
txt.print_b(a3)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
asmsub routine2(uword num @AY, ubyte a1 @R1, ubyte a2 @R2, ubyte switch @Pc, ubyte a3 @X) {
|
||||
; TODO make switch R3 use Pc instead and make that work !
|
||||
asmsub routine2(uword num @AY, ubyte a1 @R1, ubyte a2 @R2, ubyte switch @R3, ubyte a3 @X) {
|
||||
%asm {{
|
||||
adc #20
|
||||
rts
|
||||
sta routine.num
|
||||
sty routine.num+1
|
||||
lda cx16.r1
|
||||
sta routine.a1
|
||||
lda cx16.r2
|
||||
sta routine.a2
|
||||
lda cx16.r3
|
||||
sta routine.switch
|
||||
stx routine.a3
|
||||
jmp routine
|
||||
}}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user