mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 19:29:50 +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
|
package prog8.compiler.target.cpu6502.codegen
|
||||||
|
|
||||||
import prog8.ast.base.Cx16VirtualRegisters
|
import prog8.ast.base.Cx16VirtualRegisters
|
||||||
|
import prog8.ast.base.RegisterOrPair
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.statements.Subroutine
|
import prog8.ast.statements.Subroutine
|
||||||
|
|
||||||
|
|
||||||
internal fun asmsub6502ArgsEvalOrder(sub: Subroutine): List<Int> {
|
internal fun asmsub6502ArgsEvalOrder(sub: Subroutine): List<Int> {
|
||||||
val order = mutableListOf<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 args = sub.parameters.zip(sub.asmParameterRegisters).withIndex()
|
||||||
val (cx16regs, args2) = args.partition { it.value.second.registerOrPair in Cx16VirtualRegisters }
|
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 }
|
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 }
|
rest.forEach { order += it.index }
|
||||||
require(order.size==sub.parameters.size)
|
require(order.size==sub.parameters.size)
|
||||||
return order
|
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 {
|
inline asmsub read_flags() -> ubyte @A {
|
||||||
%asm {{
|
%asm {{
|
||||||
php
|
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) {
|
inline asmsub pushw(uword value @AY) {
|
||||||
%asm {{
|
%asm {{
|
||||||
pha
|
pha
|
||||||
|
@ -880,6 +880,18 @@ sys {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline asmsub rsavex() {
|
||||||
|
%asm {{
|
||||||
|
phx
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub rrestorex() {
|
||||||
|
%asm {{
|
||||||
|
plx
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
inline asmsub read_flags() -> ubyte @A {
|
inline asmsub read_flags() -> ubyte @A {
|
||||||
%asm {{
|
%asm {{
|
||||||
php
|
php
|
||||||
@ -899,6 +911,12 @@ sys {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline asmsub popx() -> ubyte @X {
|
||||||
|
%asm {{
|
||||||
|
plx
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
inline asmsub pushw(uword value @AY) {
|
inline asmsub pushw(uword value @AY) {
|
||||||
%asm {{
|
%asm {{
|
||||||
pha
|
pha
|
||||||
|
@ -265,7 +265,7 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions
|
|||||||
program.charLiteralsToUByteLiterals(compilerOptions.compTarget)
|
program.charLiteralsToUByteLiterals(compilerOptions.compTarget)
|
||||||
program.constantFold(errors, compilerOptions.compTarget)
|
program.constantFold(errors, compilerOptions.compTarget)
|
||||||
errors.report()
|
errors.report()
|
||||||
program.reorderStatements(errors, compilerOptions.compTarget)
|
program.reorderStatements(errors, compilerOptions)
|
||||||
errors.report()
|
errors.report()
|
||||||
program.addTypecasts(errors)
|
program.addTypecasts(errors)
|
||||||
errors.report()
|
errors.report()
|
||||||
@ -327,8 +327,8 @@ private fun writeAssembly(program: Program,
|
|||||||
program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
||||||
errors.report()
|
errors.report()
|
||||||
|
|
||||||
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||||
// printProgram(program)
|
printProgram(program)
|
||||||
|
|
||||||
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
||||||
val assembly = asmGeneratorFor(compilerOptions.compTarget,
|
val assembly = asmGeneratorFor(compilerOptions.compTarget,
|
||||||
|
@ -29,8 +29,8 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Program.reorderStatements(errors: IErrorReporter, target: ICompilationTarget) {
|
internal fun Program.reorderStatements(errors: IErrorReporter, options: CompilationOptions) {
|
||||||
val reorder = StatementReorderer(this, errors, target)
|
val reorder = StatementReorderer(this, errors, options)
|
||||||
reorder.visit(this)
|
reorder.visit(this)
|
||||||
if(errors.noErrors()) {
|
if(errors.noErrors()) {
|
||||||
reorder.applyModifications()
|
reorder.applyModifications()
|
||||||
|
@ -7,11 +7,14 @@ import prog8.ast.statements.*
|
|||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.compilerinterface.BuiltinFunctions
|
import prog8.compilerinterface.BuiltinFunctions
|
||||||
|
import prog8.compilerinterface.CompilationOptions
|
||||||
import prog8.compilerinterface.ICompilationTarget
|
import prog8.compilerinterface.ICompilationTarget
|
||||||
import prog8.compilerinterface.IErrorReporter
|
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.
|
// Reorders the statements in a way the compiler needs.
|
||||||
// - 'main' block must be the very first statement UNLESS it has an address set.
|
// - 'main' block must be the very first statement UNLESS it has an address set.
|
||||||
// - library blocks are put last.
|
// - library blocks are put last.
|
||||||
@ -397,30 +400,91 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
|||||||
if(function.parameters.isEmpty()) {
|
if(function.parameters.isEmpty()) {
|
||||||
// 0 params -> just GoSub
|
// 0 params -> just GoSub
|
||||||
return listOf(IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent))
|
return listOf(IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent))
|
||||||
} else if(!compTarget.asmsubArgsHaveRegisterClobberRisk(call.args)) {
|
} else if(!options.compTarget.asmsubArgsHaveRegisterClobberRisk(call.args)) {
|
||||||
// no register clobber risk, let the asmgen assign values to registers directly.
|
// no register clobber risk, let the asmgen assign values to the registers directly.
|
||||||
return noModifications
|
return noModifications
|
||||||
} else {
|
} else {
|
||||||
// TODO new logic for passing arguments to asmsub with clobber risk...
|
// clobber risk; evaluate the arguments on the CPU stack first (in reverse order)...
|
||||||
val argEvalOrder = compTarget.asmsubArgsEvalOrder(function)
|
if (options.slowCodegenWarnings)
|
||||||
println("ARGS ORDER OF $call: ${argEvalOrder.toList()}")
|
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 {
|
return modifications + IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent)
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
%import test_stack
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -6,28 +7,9 @@ main {
|
|||||||
test_stack.test()
|
test_stack.test()
|
||||||
|
|
||||||
uword @shared uw
|
uword @shared uw
|
||||||
|
uw= 0
|
||||||
; sys.push(-22 as ubyte)
|
routine(uw+11, 22,33, true, 44)
|
||||||
; sys.push(44)
|
routine2(uw+11, 22,33, true, 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)
|
|
||||||
|
|
||||||
test_stack.test()
|
test_stack.test()
|
||||||
|
|
||||||
@ -36,14 +18,32 @@ main {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub blerp(uword z) {
|
sub routine(uword num, ubyte a1, ubyte a2, ubyte switch, byte a3) {
|
||||||
z++
|
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 {{
|
%asm {{
|
||||||
adc #20
|
sta routine.num
|
||||||
rts
|
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…
x
Reference in New Issue
Block a user