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")
} 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 '&' ?
// 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.
// the way array params are treated is buggy; it thinks the subroutine needs a byte parameter in place of a byte[] ...
// This is not easy to fix because strings and arrays are treated a bit simplistic (a "virtual" pointer to the value on the heap)
// 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).
// 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.")
// Pass-by-reference datatypes can not occur as parameters to a subroutine directly
// Instead, their reference (address) should be passed (as an UWORD).
// The language has no typed pointers at this time.
if(subroutine.parameters.any{it.type in PassByReferenceDatatypes }) {
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.")
}
}
}

View File

@ -319,7 +319,7 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
}
}
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
}
fun translateSubroutineArgument(arg: IndexedValue<SubroutineParameter>, value: Expression, sub: Subroutine) {
fun translateSubroutineArgument(parameter: IndexedValue<SubroutineParameter>, value: Expression, sub: Subroutine) {
val sourceDt = value.inferType(program)!!
if(!argumentTypeCompatible(sourceDt, arg.value.type))
if(!argumentTypeCompatible(sourceDt, parameter.value.type))
throw AssemblyError("argument type incompatible")
if(sub.asmParameterRegisters.isEmpty()) {
// pass arg via a variable
val paramVar = arg.value
// pass parameter via a variable
val paramVar = parameter.value
val scopedParamVar = (sub.scopedname+"."+paramVar.name).split(".")
val target = AssignTarget(null, IdentifierReference(scopedParamVar, sub.position), null, null, sub.position)
target.linkParents(value.parent)
when (value) {
is NumericLiteralValue -> {
// optimize when the argument is a constant literal
when(arg.value.type) {
when(parameter.value.type) {
in ByteDatatypes -> assignFromByteConstant(target, value.number.toShort())
in WordDatatypes -> assignFromWordConstant(target, value.number.toInt())
DataType.FLOAT -> assignFromFloatConstant(target, value.number.toDouble())
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 -> {
// optimize when the argument is a variable
when (arg.value.type) {
when (parameter.value.type) {
in ByteDatatypes -> assignFromByteVariable(target, value)
in WordDatatypes -> assignFromWordVariable(target, value)
DataType.FLOAT -> assignFromFloatVariable(target, value)
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 -> {
@ -718,13 +718,17 @@ internal class AsmGen2(val program: Program,
}
}
} else {
// pass arg via a register parameter
val paramRegister = sub.asmParameterRegisters[arg.index]
// pass parameter via a register parameter
val paramRegister = sub.asmParameterRegisters[parameter.index]
val statusflag = paramRegister.statusflag
val register = paramRegister.registerOrPair
val stack = paramRegister.stack
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 -> {
if (statusflag == Statusflag.Pc) {
// this param needs to be set last, right before the jsr

View File

@ -54,7 +54,7 @@ fun optimizeAssembly(lines: MutableList<String>): Int {
numberOfOptimizations++
}
// TODO more assembly optimizations?
// TODO more assembly optimizations
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)
// 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>()
for (pair in linesByFourteen) {

View File

@ -107,13 +107,6 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
if(subroutine.canBeAsmSubroutine) {
optimizationsDone++
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) {

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.
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

View File

@ -4,25 +4,14 @@
main {
sub start() {
derp.dop()
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)
A = testsub(33)
}
}
derp {
sub dop() {
ubyte zzz=33
str name="irmen"
A=54
asmsub testsub(ubyte foo @stack) -> ubyte @stack {
%asm {{
Y=44
rts
}}
}
}