mirror of
https://github.com/irmen/prog8.git
synced 2025-01-14 17:31:01 +00:00
cleanup of Pipe codegen
This commit is contained in:
parent
17694c1d01
commit
75d857027e
@ -959,6 +959,9 @@ class AsmGen(private val program: Program,
|
|||||||
internal fun translateBuiltinFunctionCallExpression(functionCallExpr: FunctionCallExpression, signature: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?) =
|
internal fun translateBuiltinFunctionCallExpression(functionCallExpr: FunctionCallExpression, signature: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?) =
|
||||||
builtinFunctionsAsmGen.translateFunctioncallExpression(functionCallExpr, signature, resultToStack, resultRegister)
|
builtinFunctionsAsmGen.translateFunctioncallExpression(functionCallExpr, signature, resultToStack, resultRegister)
|
||||||
|
|
||||||
|
internal fun translateBuiltinFunctionCallStatement(functionCallStmt: FunctionCallStatement, signature: FSignature) =
|
||||||
|
builtinFunctionsAsmGen.translateFunctioncallStatement(functionCallStmt, signature)
|
||||||
|
|
||||||
internal fun translateFunctionCall(functionCallExpr: FunctionCallExpression, isExpression: Boolean) =
|
internal fun translateFunctionCall(functionCallExpr: FunctionCallExpression, isExpression: Boolean) =
|
||||||
functioncallAsmGen.translateFunctionCall(functionCallExpr, isExpression)
|
functioncallAsmGen.translateFunctionCall(functionCallExpr, isExpression)
|
||||||
|
|
||||||
@ -1634,40 +1637,31 @@ $label nop""")
|
|||||||
val subroutine = pipe.definingSubroutine
|
val subroutine = pipe.definingSubroutine
|
||||||
assignExpressionToVariable(pipe.expressions.first(), valueVar.joinToString("."), valueDt, subroutine)
|
assignExpressionToVariable(pipe.expressions.first(), valueVar.joinToString("."), valueDt, subroutine)
|
||||||
pipe.expressions.drop(1).dropLast(1).forEach {
|
pipe.expressions.drop(1).dropLast(1).forEach {
|
||||||
val callName = it as IdentifierReference
|
valueDt = functioncallAsmGen.translateFunctionCall(it as IdentifierReference, listOf(IdentifierReference(valueVar, it.position)), pipe)
|
||||||
val args = mutableListOf<Expression>(IdentifierReference(valueVar, it.position))
|
// assign result value from the functioncall back to the temp var:
|
||||||
val call = FunctionCallExpression(callName, args,it.position)
|
|
||||||
call.linkParents(pipe)
|
|
||||||
valueDt = call.inferType(program).getOrElse { throw AssemblyError("invalid dt") }
|
|
||||||
valueVar = getTempVarName(valueDt)
|
valueVar = getTempVarName(valueDt)
|
||||||
assignExpressionToVariable(call, valueVar.joinToString("."), valueDt, subroutine)
|
val valueVarTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, valueDt, subroutine, variableAsmName = valueVar.joinToString("."))
|
||||||
|
val returnRegister = returnRegisterOfFunction(it)!!
|
||||||
|
assignRegister(returnRegister, valueVarTarget)
|
||||||
}
|
}
|
||||||
// the last term in the pipe:
|
// the last term in the pipe, don't care about return var:
|
||||||
val callName = pipe.expressions.last() as IdentifierReference
|
functioncallAsmGen.translateFunctionCallStatement(
|
||||||
val callTarget = callName.targetStatement(program)!!
|
pipe.expressions.last() as IdentifierReference,
|
||||||
when (callTarget) {
|
listOf(IdentifierReference(valueVar, pipe.expressions.last().position)),
|
||||||
|
pipe
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun returnRegisterOfFunction(it: IdentifierReference): RegisterOrPair? {
|
||||||
|
return when (val targetRoutine = it.targetStatement(program)!!) {
|
||||||
is BuiltinFunctionPlaceholder -> {
|
is BuiltinFunctionPlaceholder -> {
|
||||||
val args = mutableListOf<Expression>(IdentifierReference(valueVar, callName.position))
|
when (BuiltinFunctions.getValue(targetRoutine.name).known_returntype) {
|
||||||
val call = FunctionCallStatement(callName, args, true, callName.position)
|
in ByteDatatypes -> RegisterOrPair.A
|
||||||
call.linkParents(pipe)
|
in WordDatatypes -> RegisterOrPair.AY
|
||||||
translate(call)
|
else -> return null
|
||||||
}
|
|
||||||
is Subroutine -> {
|
|
||||||
if(callTarget.isAsmSubroutine) {
|
|
||||||
val args = mutableListOf<Expression>(IdentifierReference(valueVar, callName.position))
|
|
||||||
val call = FunctionCallStatement(callName, args, true, callName.position)
|
|
||||||
call.linkParents(pipe)
|
|
||||||
translate(call)
|
|
||||||
} else {
|
|
||||||
// have to use GoSub and manual parameter assignment, because no codegen for FunctionCallStmt here
|
|
||||||
val param = callTarget.parameters.single()
|
|
||||||
val paramName = callTarget.scopedName.joinToString(".") + ".${param.name}"
|
|
||||||
val tempvar = IdentifierReference(valueVar, callName.position)
|
|
||||||
tempvar.linkParents(pipe)
|
|
||||||
assignExpressionToVariable(tempvar, paramName, param.type, subroutine)
|
|
||||||
out(" jsr ${asmSymbolName(callName)}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is Subroutine -> targetRoutine.asmReturnvaluesRegisters.single().registerOrPair!!
|
||||||
else -> throw AssemblyError("invalid call target")
|
else -> throw AssemblyError("invalid call target")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import prog8.codegen.target.cpu6502.codegen.assignment.AsmAssignSource
|
|||||||
import prog8.codegen.target.cpu6502.codegen.assignment.AsmAssignTarget
|
import prog8.codegen.target.cpu6502.codegen.assignment.AsmAssignTarget
|
||||||
import prog8.codegen.target.cpu6502.codegen.assignment.AsmAssignment
|
import prog8.codegen.target.cpu6502.codegen.assignment.AsmAssignment
|
||||||
import prog8.codegen.target.cpu6502.codegen.assignment.TargetStorageKind
|
import prog8.codegen.target.cpu6502.codegen.assignment.TargetStorageKind
|
||||||
|
import prog8.compilerinterface.BuiltinFunctions
|
||||||
import prog8.compilerinterface.CpuType
|
import prog8.compilerinterface.CpuType
|
||||||
|
|
||||||
|
|
||||||
@ -126,9 +127,53 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
// remember: dealing with the X register and/or dealing with return values is the responsibility of the caller
|
// remember: dealing with the X register and/or dealing with return values is the responsibility of the caller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun translateFunctionCall(target: IdentifierReference, args: Iterable<Expression>, scope: Node): DataType {
|
||||||
|
when(val targetStmt = target.targetStatement(program)!!) {
|
||||||
|
is BuiltinFunctionPlaceholder -> {
|
||||||
|
val call = FunctionCallExpression(target, args.toMutableList(), scope.position)
|
||||||
|
call.linkParents(scope)
|
||||||
|
val signature = BuiltinFunctions.getValue(targetStmt.name)
|
||||||
|
asmgen.translateBuiltinFunctionCallExpression(call, signature, false, null)
|
||||||
|
return signature.known_returntype!!
|
||||||
|
}
|
||||||
|
is Subroutine -> {
|
||||||
|
val call = FunctionCallExpression(target, args.toMutableList(), scope.position)
|
||||||
|
call.linkParents(scope)
|
||||||
|
translateFunctionCall(call, true)
|
||||||
|
return call.inferType(program).getOrElse { throw AssemblyError("invalid dt") }
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("invalid call target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun translateFunctionCallStatement(target: IdentifierReference, args: Iterable<Expression>, scope: Node) {
|
||||||
|
when(val targetStmt = target.targetStatement(program)!!) {
|
||||||
|
is BuiltinFunctionPlaceholder -> {
|
||||||
|
val call = FunctionCallStatement(target, args.toMutableList(), true, scope.position)
|
||||||
|
call.linkParents(scope)
|
||||||
|
val signature = BuiltinFunctions.getValue(targetStmt.name)
|
||||||
|
asmgen.translateBuiltinFunctionCallStatement(call, signature)
|
||||||
|
}
|
||||||
|
is Subroutine -> {
|
||||||
|
if(targetStmt.isAsmSubroutine) {
|
||||||
|
val call = FunctionCallStatement(target, args.toMutableList(), true, scope.position)
|
||||||
|
call.linkParents(scope)
|
||||||
|
translateFunctionCallStatement(call)
|
||||||
|
} else {
|
||||||
|
// have to use manual parameter assignment and jsr, because no codegen for FunctionCallStmt here
|
||||||
|
val tempVar = args.single()
|
||||||
|
tempVar.linkParents(scope)
|
||||||
|
argumentViaVariable(targetStmt, targetStmt.parameters.single(), tempVar)
|
||||||
|
asmgen.out(" jsr ${asmgen.asmSymbolName(target)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("invalid call target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun argumentsViaVariables(sub: Subroutine, call: IFunctionCall) {
|
private fun argumentsViaVariables(sub: Subroutine, call: IFunctionCall) {
|
||||||
for(arg in sub.parameters.withIndex().zip(call.args))
|
for(arg in sub.parameters.withIndex().zip(call.args))
|
||||||
argumentViaVariable(sub, arg.first, arg.second)
|
argumentViaVariable(sub, arg.first.value, arg.second)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun argumentsViaRegisters(sub: Subroutine, call: IFunctionCall) {
|
private fun argumentsViaRegisters(sub: Subroutine, call: IFunctionCall) {
|
||||||
@ -272,15 +317,15 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
asmgen.out(" plp") // set the carry flag back to correct value
|
asmgen.out(" plp") // set the carry flag back to correct value
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun argumentViaVariable(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression) {
|
private fun argumentViaVariable(sub: Subroutine, parameter: SubroutineParameter, value: Expression) {
|
||||||
// pass parameter via a regular variable (not via registers)
|
// pass parameter via a regular variable (not via registers)
|
||||||
val valueIDt = value.inferType(program)
|
val valueIDt = value.inferType(program)
|
||||||
val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") }
|
val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") }
|
||||||
if(!isArgumentTypeCompatible(valueDt, parameter.value.type))
|
if(!isArgumentTypeCompatible(valueDt, parameter.type))
|
||||||
throw AssemblyError("argument type incompatible")
|
throw AssemblyError("argument type incompatible")
|
||||||
|
|
||||||
val varName = asmgen.asmVariableName(sub.scopedName + parameter.value.name)
|
val varName = asmgen.asmVariableName(sub.scopedName + parameter.name)
|
||||||
asmgen.assignExpressionToVariable(value, varName, parameter.value.type, sub)
|
asmgen.assignExpressionToVariable(value, varName, parameter.type, sub)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun argumentViaRegister(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression, registerOverride: RegisterOrPair? = null) {
|
private fun argumentViaRegister(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression, registerOverride: RegisterOrPair? = null) {
|
||||||
|
@ -3,6 +3,7 @@ TODO
|
|||||||
|
|
||||||
For next compiler release (7.7)
|
For next compiler release (7.7)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
- make pipe statement an expression so that it DOES return a result value (possibly) so you can assign it ??
|
||||||
- optimize codegen of pipe operator to avoid needless assigns to temp var
|
- optimize codegen of pipe operator to avoid needless assigns to temp var
|
||||||
- copying floats around: do it with a subroutine rather than 5 lda/sta pairs .
|
- copying floats around: do it with a subroutine rather than 5 lda/sta pairs .
|
||||||
is slower but floats are very slow already anyway and this should take a lot less program size.
|
is slower but floats are very slow already anyway and this should take a lot less program size.
|
||||||
@ -24,6 +25,7 @@ Blocked by an official Commander-x16 r39 release
|
|||||||
Future Things and Ideas
|
Future Things and Ideas
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
- can we promise a left-to-right function call argument evaluation? without sacrificing performance
|
- can we promise a left-to-right function call argument evaluation? without sacrificing performance
|
||||||
|
- for the pipe operator: recognise a placeholder (? or % or _) in a non-unary function call to allow things as 4 |> mkword(?, $44) |> print_uw
|
||||||
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``v_``
|
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``v_``
|
||||||
then we can get rid of the instruction lists in the machinedefinitions as well?
|
then we can get rid of the instruction lists in the machinedefinitions as well?
|
||||||
- fix the asm-labels problem (github issue #62)
|
- fix the asm-labels problem (github issue #62)
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
%import floats
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
times_two(554 as ubyte)
|
1.234 |> addfloat |> addfloat |> floats.print_f
|
||||||
; txt.print_uw(times_two(add_one(9+3)))
|
txt.nl()
|
||||||
; txt.nl()
|
9 * 3 |> assemblything
|
||||||
; 9 + 3
|
|> sin8u
|
||||||
; |> add_one |> times_two
|
|> add_one |> times_two
|
||||||
; |> txt.print_uw
|
|> txt.print_uw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub addfloat(float fl) -> float {
|
||||||
|
return fl+1.11
|
||||||
|
}
|
||||||
sub add_one(ubyte input) -> ubyte {
|
sub add_one(ubyte input) -> ubyte {
|
||||||
return input+1
|
return input+1
|
||||||
}
|
}
|
||||||
@ -18,6 +22,13 @@ main {
|
|||||||
sub times_two(ubyte input) -> uword {
|
sub times_two(ubyte input) -> uword {
|
||||||
return input*$0002
|
return input*$0002
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asmsub assemblything(ubyte input @A) -> ubyte @A {
|
||||||
|
%asm {{
|
||||||
|
asl a
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user