fix codegen bug for pipe expressions to actually return correct value and not corrupt X register

This commit is contained in:
Irmen de Jong 2022-01-08 17:41:46 +01:00
parent d99d977d2b
commit 7135205299
5 changed files with 63 additions and 42 deletions

View File

@ -850,7 +850,7 @@ class AsmGen(private val program: Program,
is RepeatLoop -> translate(stmt)
is When -> translate(stmt)
is AnonymousScope -> translate(stmt)
is Pipe -> expressionsAsmGen.translatePipeExpression(stmt.expressions, stmt,true)
is Pipe -> translatePipeExpression(stmt.expressions, stmt, true, false)
is BuiltinFunctionPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore")
is UntilLoop -> throw AssemblyError("do..until should have been converted to jumps")
is WhileLoop -> throw AssemblyError("while should have been converted to jumps")
@ -3411,4 +3411,54 @@ $label nop""")
else -> return false
}
}
internal fun translatePipeExpression(expressions: Iterable<Expression>, scope: Node, isStatement: Boolean, pushResultOnEstack: Boolean) {
// NOTE:
// TODO more efficient code generation to avoid needless assignments to the temp var
val subroutine = scope.definingSubroutine
var valueDt = expressions.first().inferType(program).getOrElse { throw FatalAstException("invalid dt") }
var valueVar = getTempVarName(valueDt)
assignExpressionToVariable(expressions.first(), asmVariableName(valueVar), valueDt, subroutine)
expressions.drop(1).dropLast(1).forEach {
valueDt = functioncallAsmGen.translateFunctionCall(it as IdentifierReference, listOf(IdentifierReference(valueVar, it.position)), scope)
// assign result value from the functioncall back to the temp var:
valueVar = getTempVarName(valueDt)
val valueVarTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, valueDt, subroutine, variableAsmName = valueVar.joinToString("."))
val returnRegister = returnRegisterOfFunction(it)!!
assignRegister(returnRegister, valueVarTarget)
}
if(isStatement) {
// the last term in the pipe, don't care about return var:
functioncallAsmGen.translateFunctionCallStatement(
expressions.last() as IdentifierReference,
listOf(IdentifierReference(valueVar, expressions.last().position)),
scope
)
} else {
// the last term in the pipe, regular function call with returnvalue:
valueDt = functioncallAsmGen.translateFunctionCall(
expressions.last() as IdentifierReference,
listOf(IdentifierReference(valueVar, expressions.last().position)),
scope
)
if(pushResultOnEstack) {
when (valueDt) {
in ByteDatatypes -> {
out(" sta P8ESTACK_LO,x | dex")
}
in WordDatatypes -> {
out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
}
DataType.FLOAT -> {
out(" jsr floats.push_fac1")
}
else -> throw AssemblyError("invalid dt")
}
}
}
}
}

View File

@ -1,6 +1,5 @@
package prog8.codegen.target.cpu6502.codegen
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
@ -8,8 +7,6 @@ import prog8.ast.statements.BuiltinFunctionPlaceholder
import prog8.ast.statements.Subroutine
import prog8.ast.toHex
import prog8.codegen.target.AssemblyError
import prog8.codegen.target.cpu6502.codegen.assignment.AsmAssignTarget
import prog8.codegen.target.cpu6502.codegen.assignment.TargetStorageKind
import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.CpuType
import kotlin.math.absoluteValue
@ -40,7 +37,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
is NumericLiteralValue -> translateExpression(expression)
is IdentifierReference -> translateExpression(expression)
is FunctionCallExpression -> translateFunctionCallResultOntoStack(expression)
is PipeExpression -> translatePipeExpression(expression.expressions, expression,false)
is PipeExpression -> asmgen.translatePipeExpression(expression.expressions, expression,false, true)
is ContainmentCheck -> throw AssemblyError("containment check as complex expression value is not supported")
is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable")
is RangeExpression -> throw AssemblyError("range expression should have been changed into array values")
@ -793,38 +790,4 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
asmgen.out(" dex")
}
internal fun translatePipeExpression(expressions: Iterable<Expression>, scope: Node, isStatement: Boolean) {
// TODO more efficient code generation to avoid needless assignments to the temp var
val subroutine = scope.definingSubroutine
var valueDt = expressions.first().inferType(program).getOrElse { throw FatalAstException("invalid dt") }
var valueVar = asmgen.getTempVarName(valueDt)
asmgen.assignExpressionToVariable(expressions.first(), valueVar.joinToString("."), valueDt, subroutine)
expressions.drop(1).dropLast(1).forEach {
valueDt = functioncallAsmGen.translateFunctionCall(it as IdentifierReference, listOf(IdentifierReference(valueVar, it.position)), scope)
// assign result value from the functioncall back to the temp var:
valueVar = asmgen.getTempVarName(valueDt)
val valueVarTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, valueDt, subroutine, variableAsmName = valueVar.joinToString("."))
val returnRegister = asmgen.returnRegisterOfFunction(it)!!
asmgen.assignRegister(returnRegister, valueVarTarget)
}
if(isStatement) {
// the last term in the pipe, don't care about return var:
functioncallAsmGen.translateFunctionCallStatement(
expressions.last() as IdentifierReference,
listOf(IdentifierReference(valueVar, expressions.last().position)),
scope
)
} else {
// the last term in the pipe, regular function call with returnvalue:
functioncallAsmGen.translateFunctionCall(
expressions.last() as IdentifierReference,
listOf(IdentifierReference(valueVar, expressions.last().position)),
scope
)
}
}
}

View File

@ -275,6 +275,14 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
containmentCheckIntoA(value)
assignRegisterByte(assign.target, CpuRegister.A)
}
is PipeExpression -> {
// TODO NOT VIA STACK!!
asmgen.translateExpression(value)
if (assign.target.datatype in WordDatatypes && assign.source.datatype in ByteDatatypes)
asmgen.signExtendStackLsb(assign.source.datatype)
if(assign.target.kind!=TargetStorageKind.STACK || assign.target.datatype != assign.source.datatype)
assignStackValue(assign.target)
}
else -> {
// Everything else just evaluate via the stack.
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,

View File

@ -3,7 +3,6 @@ TODO
For next compiler release (7.7)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- fix codegen bug for pipe expressions to actually return correct value and not corrupt X register
- why is wormfood 40 bytes larger now since 7.6???
- 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 .

View File

@ -23,7 +23,7 @@ main {
test_stack.test()
; TODO fix that the value is actually returned (398) and that X register is preserved:
uword @shared uw = 9+3 |> assemblything
uword @shared uw= 9+3 |> assemblything
|> sin8u
|> add_one
|> times_two
@ -52,8 +52,9 @@ main {
return input*$0002
}
asmsub assemblything(ubyte input @A) -> ubyte @A {
asmsub assemblything(ubyte input @A) clobbers(X,Y) -> ubyte @A {
%asm {{
ldx #0
asl a
rts
}}