asmsub stack arg

This commit is contained in:
Irmen de Jong 2019-08-11 12:29:18 +02:00
parent d499e40a4b
commit fe5b225732
7 changed files with 39 additions and 47 deletions

View File

@ -317,14 +317,11 @@ internal class AstChecker(private val program: Program,
err("carry parameter has to come last") err("carry parameter has to come last")
} else { } else {
// TODO: non-asm subroutines can only take numeric arguments for now. (not strings and arrays) Maybe this can be improved now that we have '&' ? // Pass-by-reference datatypes can not occur as parameters to a subroutine directly
// the way string params are treated is almost okay (their address is passed) but the receiving subroutine treats it as an integer rather than referring back to the original string. // Instead, their reference (address) should be passed (as an UWORD).
// the way array params are treated is buggy; it thinks the subroutine needs a byte parameter in place of a byte[] ... // The language has no typed pointers at this time.
// This is not easy to fix because strings and arrays are treated a bit simplistic (a "virtual" pointer to the value on the heap) if(subroutine.parameters.any{it.type in PassByReferenceDatatypes }) {
// while passing them as subroutine parameters would require a "real" pointer OR copying the VALUE to the subroutine's parameter variable (which is very inefficient). err("Pass-by-reference types (str, array) cannot occur as a parameter type directly. Instead, use an uword for their address, or access the variable from the outer scope directly.")
// For now, don't pass strings and arrays as parameters and instead create the workaround as suggested in the error message below.
if(!subroutine.parameters.all{it.type in NumericDatatypes }) {
err("Non-asm subroutine can only take numerical parameters (no str/array types) for now. Workaround (for nested subroutine): access the variable from the outer scope directly.")
} }
} }
} }

View File

@ -319,7 +319,7 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
} }
} }
null -> {} null -> {}
else -> TODO("call to something weird $sub ${call.target}") else -> throw FatalAstException("call to something weird $sub ${call.target}")
} }
} }

View File

@ -662,35 +662,35 @@ internal class AsmGen2(val program: Program,
out(" ldx c64.SCRATCH_ZPREGX") // restore X again out(" ldx c64.SCRATCH_ZPREGX") // restore X again
} }
fun translateSubroutineArgument(arg: IndexedValue<SubroutineParameter>, value: Expression, sub: Subroutine) { fun translateSubroutineArgument(parameter: IndexedValue<SubroutineParameter>, value: Expression, sub: Subroutine) {
val sourceDt = value.inferType(program)!! val sourceDt = value.inferType(program)!!
if(!argumentTypeCompatible(sourceDt, arg.value.type)) if(!argumentTypeCompatible(sourceDt, parameter.value.type))
throw AssemblyError("argument type incompatible") throw AssemblyError("argument type incompatible")
if(sub.asmParameterRegisters.isEmpty()) { if(sub.asmParameterRegisters.isEmpty()) {
// pass arg via a variable // pass parameter via a variable
val paramVar = arg.value val paramVar = parameter.value
val scopedParamVar = (sub.scopedname+"."+paramVar.name).split(".") val scopedParamVar = (sub.scopedname+"."+paramVar.name).split(".")
val target = AssignTarget(null, IdentifierReference(scopedParamVar, sub.position), null, null, sub.position) val target = AssignTarget(null, IdentifierReference(scopedParamVar, sub.position), null, null, sub.position)
target.linkParents(value.parent) target.linkParents(value.parent)
when (value) { when (value) {
is NumericLiteralValue -> { is NumericLiteralValue -> {
// optimize when the argument is a constant literal // optimize when the argument is a constant literal
when(arg.value.type) { when(parameter.value.type) {
in ByteDatatypes -> assignFromByteConstant(target, value.number.toShort()) in ByteDatatypes -> assignFromByteConstant(target, value.number.toShort())
in WordDatatypes -> assignFromWordConstant(target, value.number.toInt()) in WordDatatypes -> assignFromWordConstant(target, value.number.toInt())
DataType.FLOAT -> assignFromFloatConstant(target, value.number.toDouble()) DataType.FLOAT -> assignFromFloatConstant(target, value.number.toDouble())
in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?") in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?")
else -> throw AssemblyError("weird arg datatype") else -> throw AssemblyError("weird parameter datatype")
} }
} }
is IdentifierReference -> { is IdentifierReference -> {
// optimize when the argument is a variable // optimize when the argument is a variable
when (arg.value.type) { when (parameter.value.type) {
in ByteDatatypes -> assignFromByteVariable(target, value) in ByteDatatypes -> assignFromByteVariable(target, value)
in WordDatatypes -> assignFromWordVariable(target, value) in WordDatatypes -> assignFromWordVariable(target, value)
DataType.FLOAT -> assignFromFloatVariable(target, value) DataType.FLOAT -> assignFromFloatVariable(target, value)
in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?") in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?")
else -> throw AssemblyError("weird arg datatype") else -> throw AssemblyError("weird parameter datatype")
} }
} }
is RegisterExpr -> { is RegisterExpr -> {
@ -718,13 +718,17 @@ internal class AsmGen2(val program: Program,
} }
} }
} else { } else {
// pass arg via a register parameter // pass parameter via a register parameter
val paramRegister = sub.asmParameterRegisters[arg.index] val paramRegister = sub.asmParameterRegisters[parameter.index]
val statusflag = paramRegister.statusflag val statusflag = paramRegister.statusflag
val register = paramRegister.registerOrPair val register = paramRegister.registerOrPair
val stack = paramRegister.stack val stack = paramRegister.stack
when { when {
stack==true -> TODO("param on stack") stack -> {
// push arg onto the stack
// note: argument order is reversed (first argument will be deepest on the stack)
translateExpression(value)
}
statusflag!=null -> { statusflag!=null -> {
if (statusflag == Statusflag.Pc) { if (statusflag == Statusflag.Pc) {
// this param needs to be set last, right before the jsr // this param needs to be set last, right before the jsr

View File

@ -54,7 +54,7 @@ fun optimizeAssembly(lines: MutableList<String>): Int {
numberOfOptimizations++ numberOfOptimizations++
} }
// TODO more assembly optimizations? // TODO more assembly optimizations
return numberOfOptimizations return numberOfOptimizations
} }
@ -101,7 +101,7 @@ fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<String>>>):
// optimize sequential assignments of the isSameAs value to various targets (bytes, words, floats) // optimize sequential assignments of the isSameAs value to various targets (bytes, words, floats)
// the float one is the one that requires 2*7=14 lines of code to check... // the float one is the one that requires 2*7=14 lines of code to check...
// @todo a better place to do this is in the Compiler instead and work on opcodes, and never even create the inefficient asm... // @todo a better place to do this is in the Compiler instead and transform the Ast, and never even create the inefficient asm in the first place...
val removeLines = mutableListOf<Int>() val removeLines = mutableListOf<Int>()
for (pair in linesByFourteen) { for (pair in linesByFourteen) {

View File

@ -107,13 +107,6 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
if(subroutine.canBeAsmSubroutine) { if(subroutine.canBeAsmSubroutine) {
optimizationsDone++ optimizationsDone++
return subroutine.intoAsmSubroutine() // TODO this doesn't work yet due to parameter vardecl issue return subroutine.intoAsmSubroutine() // TODO this doesn't work yet due to parameter vardecl issue
// TODO fix parameter passing so this also works:
// asmsub aa(byte arg @ Y) -> clobbers() -> () {
// byte local = arg ; @todo fix 'undefined symbol arg' by some sort of alias name for the parameter
// A=44
// }
} }
if(subroutine !in callgraph.usedSymbols && !forceOutput) { if(subroutine !in callgraph.usedSymbols && !forceOutput) {

View File

@ -19,6 +19,15 @@ these should call optimized pieces of assembly code, so they run as fast as poss
For now, we have the ``memcopy``, ``memset`` and ``strlen`` builtin functions. For now, we have the ``memcopy``, ``memset`` and ``strlen`` builtin functions.
Fixes
^^^^^
fix asmsub parameters so this works::
asmsub aa(byte arg @ Y) -> clobbers() -> () {
byte local = arg ; @todo fix 'undefined symbol arg' that occurs here
A=44
}
More optimizations More optimizations

View File

@ -4,25 +4,14 @@
main { main {
sub start() { sub start() {
derp.dop() A = testsub(33)
A=derp.dop.zzz
derp.dop.zzz=3
uword addr = &derp.dop.name ; @todo strange error "pointer-of operand must be the name of a heap variable"
c64scr.print(&derp.dop.name)
} }
}
asmsub testsub(ubyte foo @stack) -> ubyte @stack {
derp { %asm {{
Y=44
sub dop() { rts
ubyte zzz=33 }}
str name="irmen"
A=54
} }
} }