fix typecast removal error.

This commit is contained in:
Irmen de Jong 2020-08-20 18:07:48 +02:00
parent 7a3163f59a
commit e1812ce16c
11 changed files with 110 additions and 51 deletions

View File

@ -36,7 +36,7 @@ init_system .proc
.pend
read_byte_from_address .proc
read_byte_from_address_on_stack .proc
; -- read the byte from the memory address on the top of the stack, return in A (stack remains unchanged)
lda c64.ESTACK_LO+1,x
ldy c64.ESTACK_HI+1,x
@ -2079,7 +2079,7 @@ ror2_array_uw .proc
+ rts
.pend
strcpy .proc
; copy a string (0-terminated) from A/Y to (ZPWORD1)
; it is assumed the target string is large enough.
@ -2092,8 +2092,8 @@ strcpy .proc
bne -
rts
.pend
func_leftstr .proc
; leftstr(source, target, length) with params on stack
inx
@ -2175,12 +2175,12 @@ func_substr .proc
lda c64.ESTACK_LO,x ; start
sta c64.SCRATCH_ZPB1
inx
lda c64.ESTACK_LO,x
lda c64.ESTACK_LO,x
sta c64.SCRATCH_ZPWORD2
lda c64.ESTACK_HI,x
sta c64.SCRATCH_ZPWORD2+1
inx
lda c64.ESTACK_LO,x
lda c64.ESTACK_LO,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI,x
sta c64.SCRATCH_ZPWORD1+1

View File

@ -328,6 +328,10 @@ open class Assignment(var target: AssignTarget, var value: Expression, override
return("Assignment(target: $target, value: $value, pos=$position)")
}
/**
* Is the assigment value an expression that references the assignment target itself?
* The expression can be a BinaryExpression, PrefixExpression or TypecastExpression (possibly with one sub-cast).
*/
val isAugmentable: Boolean
get() {
val binExpr = value as? BinaryExpression
@ -354,6 +358,16 @@ open class Assignment(var target: AssignTarget, var value: Expression, override
}
}
val prefixExpr = value as? PrefixExpression
if(prefixExpr!=null)
return prefixExpr.expression isSameAs target
val castExpr = value as? TypecastExpression
if(castExpr!=null) {
val subCast = castExpr.expression as? TypecastExpression
return if(subCast!=null) subCast.expression isSameAs target else castExpr.expression isSameAs target
}
return false
}
}

View File

@ -1008,7 +1008,6 @@ $counterVar .byte 0""")
val indexName = asmIdentifierName(index)
out(" lda $indexName")
}
// TODO optimize more cases
else -> {
expressionsAsmGen.translateExpression(index)
out(" inx | lda $ESTACK_LO_HEX,x")

View File

@ -14,14 +14,13 @@ import prog8.compiler.toHex
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen) {
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen)
internal fun translate(assign: Assignment) {
when {
assign.value is NumericLiteralValue -> translateConstantValueAssignment(assign)
assign.value is IdentifierReference -> translateVariableAssignment(assign)
assign.isAugmentable -> {
println("TODO: optimize augmentable assignment ${assign.position}") // TODO
translateOtherAssignment(assign) // TODO generate better code here for augmentable assignments
}
assign.isAugmentable -> augmentableAsmGen.translate(assign)
else -> translateOtherAssignment(assign)
}
}
@ -56,7 +55,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun translateOtherAssignment(assign: Assignment) {
internal fun translateOtherAssignment(assign: Assignment) {
when (assign.value) {
is AddressOf -> {
val identifier = (assign.value as AddressOf).identifier
@ -74,23 +73,20 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
else -> {
asmgen.translateExpression(read.addressExpression)
asmgen.out(" jsr prog8_lib.read_byte_from_address | inx")
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | inx")
assignFromRegister(assign.target, CpuRegister.A)
}
}
}
is PrefixExpression -> {
// TODO optimize common cases
asmgen.translateExpression(assign.value as PrefixExpression)
assignFromEvalResult(assign.target)
}
is BinaryExpression -> {
// TODO optimize common cases
asmgen.translateExpression(assign.value as BinaryExpression)
assignFromEvalResult(assign.target)
}
is ArrayIndexedExpression -> {
// TODO optimize common cases
val arrayExpr = assign.value as ArrayIndexedExpression
val arrayDt = arrayExpr.identifier.inferType(program).typeOrElse(DataType.STRUCT)
val index = arrayExpr.arrayspec.index
@ -141,6 +137,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
private fun assignFromEvalResult(target: AssignTarget) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
val targetMemory = target.memoryAddress
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
@ -167,14 +165,14 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
else -> throw AssemblyError("weird target variable type $targetDt")
}
}
target.memoryAddress != null -> {
targetMemory != null -> {
asmgen.out(" inx")
storeByteViaRegisterAInMemoryAddress("$ESTACK_LO_HEX,x", target.memoryAddress)
storeByteViaRegisterAInMemoryAddress("$ESTACK_LO_HEX,x", targetMemory)
}
target.arrayindexed != null -> {
val arrayDt = target.arrayindexed!!.identifier.inferType(program).typeOrElse(DataType.STRUCT)
val arrayVarName = asmgen.asmIdentifierName(target.arrayindexed!!.identifier)
asmgen.translateExpression(target.arrayindexed!!.arrayspec.index)
targetArrayIdx != null -> {
val arrayDt = targetArrayIdx.identifier.inferType(program).typeOrElse(DataType.STRUCT)
val arrayVarName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
asmgen.translateExpression(targetArrayIdx.arrayspec.index)
asmgen.out(" inx | lda $ESTACK_LO_HEX,x")
popAndWriteArrayvalueWithIndexA(arrayDt, arrayVarName)
}
@ -285,6 +283,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val sourceName = asmgen.asmIdentifierName(variable)
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
val targetMemory = target.memoryAddress
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
@ -293,6 +292,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
sta $targetName
""")
}
targetMemory != null -> {
storeByteViaRegisterAInMemoryAddress(sourceName, targetMemory)
}
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
@ -302,9 +304,6 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.out(" inx | lda $ESTACK_LO_HEX,x")
popAndWriteArrayvalueWithIndexA(arrayDt, targetName)
}
target.memoryAddress != null -> {
storeByteViaRegisterAInMemoryAddress(sourceName, target.memoryAddress)
}
else -> throw AssemblyError("no asm gen for assign bytevar to $target")
}
}
@ -374,11 +373,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
when {
addressLv != null -> asmgen.out(" lda $ldaInstructionArg | sta ${addressLv.number.toHex()}")
addressExpr is IdentifierReference -> {
val targetName = asmgen.asmIdentifierName(addressExpr)
val pointerVarName = asmgen.asmIdentifierName(addressExpr)
asmgen.out("""
lda $targetName
lda $pointerVarName
sta ${C64Zeropage.SCRATCH_W1}
lda $targetName+1
lda $pointerVarName+1
sta ${C64Zeropage.SCRATCH_W1+1}
lda $ldaInstructionArg
ldy #0
@ -465,7 +464,6 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
// TODO optimize common cases
asmgen.translateExpression(index)
asmgen.out("""
inx
@ -486,7 +484,6 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
val targetMemory = target.memoryAddress
// TODO all via method?
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
@ -498,7 +495,6 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
// TODO optimize common cases
asmgen.translateExpression(index)
asmgen.out("""
inx

View File

@ -0,0 +1,34 @@
package prog8.compiler.target.c64.codegen
import prog8.ast.Program
import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.PrefixExpression
import prog8.ast.expressions.TypecastExpression
import prog8.ast.statements.Assignment
import prog8.compiler.AssemblyError
internal class AugmentableAssignmentAsmGen(private val program: Program,
private val assignmentAsmGen: AssignmentAsmGen,
private val asmgen: AsmGen) {
fun translate(assign: Assignment) {
require(assign.isAugmentable)
assignmentAsmGen.translateOtherAssignment(assign) // TODO get rid of this fallback
// when (assign.value) {
// is PrefixExpression -> {
// TODO("aug prefix")
// }
// is TypecastExpression -> {
// TODO("aug typecast")
// }
// is BinaryExpression -> {
// TODO("aug binary")
// }
// else -> {
// throw AssemblyError("invalid aug assign value type")
// }
// }
}
}

View File

@ -150,7 +150,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
else -> {
translateExpression(expr.addressExpression)
asmgen.out(" jsr prog8_lib.read_byte_from_address")
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack")
asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x")
}
}

View File

@ -412,8 +412,8 @@ private fun numericLiteral(value: Number, position: Position): NumericLiteralVal
floatNum
return when(tweakedValue) {
is Int -> NumericLiteralValue.optimalNumeric(value.toInt(), position)
is Short -> NumericLiteralValue.optimalNumeric(value.toInt(), position)
is Int -> NumericLiteralValue.optimalInteger(value.toInt(), position)
is Short -> NumericLiteralValue.optimalInteger(value.toInt(), position)
is Byte -> NumericLiteralValue(DataType.UBYTE, value.toShort(), position)
is Double -> NumericLiteralValue(DataType.FLOAT, value.toDouble(), position)
is Float -> NumericLiteralValue(DataType.FLOAT, value.toDouble(), position)

View File

@ -163,7 +163,7 @@ class ConstExprEvaluator {
val error = "cannot add $left and $right"
return when (left.type) {
in IntegerDatatypes -> when (right.type) {
in IntegerDatatypes -> NumericLiteralValue.optimalNumeric(left.number.toInt() + right.number.toInt(), left.position)
in IntegerDatatypes -> NumericLiteralValue.optimalInteger(left.number.toInt() + right.number.toInt(), left.position)
DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, left.number.toInt() + right.number.toDouble(), left.position)
else -> throw ExpressionError(error, left.position)
}
@ -180,7 +180,7 @@ class ConstExprEvaluator {
val error = "cannot subtract $left and $right"
return when (left.type) {
in IntegerDatatypes -> when (right.type) {
in IntegerDatatypes -> NumericLiteralValue.optimalNumeric(left.number.toInt() - right.number.toInt(), left.position)
in IntegerDatatypes -> NumericLiteralValue.optimalInteger(left.number.toInt() - right.number.toInt(), left.position)
DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, left.number.toInt() - right.number.toDouble(), left.position)
else -> throw ExpressionError(error, left.position)
}
@ -197,7 +197,7 @@ class ConstExprEvaluator {
val error = "cannot multiply ${left.type} and ${right.type}"
return when (left.type) {
in IntegerDatatypes -> when (right.type) {
in IntegerDatatypes -> NumericLiteralValue.optimalNumeric(left.number.toInt() * right.number.toInt(), left.position)
in IntegerDatatypes -> NumericLiteralValue.optimalInteger(left.number.toInt() * right.number.toInt(), left.position)
DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, left.number.toInt() * right.number.toDouble(), left.position)
else -> throw ExpressionError(error, left.position)
}
@ -220,7 +220,7 @@ class ConstExprEvaluator {
in IntegerDatatypes -> {
if(right.number.toInt()==0) divideByZeroError(right.position)
val result: Int = left.number.toInt() / right.number.toInt()
NumericLiteralValue.optimalNumeric(result, left.position)
NumericLiteralValue.optimalInteger(result, left.position)
}
DataType.FLOAT -> {
if(right.number.toDouble()==0.0) divideByZeroError(right.position)

View File

@ -203,7 +203,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
"-" -> when (subexpr.type) {
in IntegerDatatypes -> {
listOf(IAstModification.ReplaceNode(expr,
NumericLiteralValue.optimalNumeric(-subexpr.number.toInt(), subexpr.position),
NumericLiteralValue.optimalInteger(-subexpr.number.toInt(), subexpr.position),
parent))
}
DataType.FLOAT -> {
@ -216,7 +216,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
"~" -> when (subexpr.type) {
in IntegerDatatypes -> {
listOf(IAstModification.ReplaceNode(expr,
NumericLiteralValue.optimalNumeric(subexpr.number.toInt().inv(), subexpr.position),
NumericLiteralValue.optimalInteger(subexpr.number.toInt().inv(), subexpr.position),
parent))
}
else -> throw ExpressionError("can only take bitwise inversion of int", subexpr.position)

View File

@ -34,15 +34,25 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
mods += IAstModification.ReplaceNode(typecast.expression, newLiteral, typecast)
}
// remove redundant nested typecasts:
// if the typecast casts a value to the same type, remove the cast.
// if the typecast contains another typecast, remove the inner typecast.
// remove redundant nested typecasts
val subTypecast = typecast.expression as? TypecastExpression
if (subTypecast != null) {
mods += IAstModification.ReplaceNode(typecast.expression, subTypecast.expression, typecast)
// remove the sub-typecast if its datatype is larger than the outer typecast
if(subTypecast.type largerThan typecast.type) {
mods += IAstModification.ReplaceNode(typecast.expression, subTypecast.expression, typecast)
} else {
if(subTypecast.type == DataType.UBYTE && typecast.type == DataType.UWORD) {
// (X as ubyte) as uword -> X & 255
// TODO don't optimize this because the asm code generated by it is worse...
// val and255 = BinaryExpression(subTypecast.expression, "&", NumericLiteralValue.optimalInteger(255, subTypecast.position), subTypecast.position)
// mods += IAstModification.ReplaceNode(typecast, and255, parent)
}
}
} else {
if (typecast.expression.inferType(program).istype(typecast.type))
if (typecast.expression.inferType(program).istype(typecast.type)) {
// remove duplicate cast
mods += IAstModification.ReplaceNode(typecast, typecast.expression, parent)
}
}
return mods

View File

@ -7,12 +7,18 @@ main {
sub start() {
ubyte A=5
uword clr = $d020
A = @(clr)
A++
@(clr) = A
byte A
byte B = +A
byte C = -A
uword W = 43210
A = -A
c64scr.print_uw(W)
c64.CHROUT('\n')
W = W as ubyte ; TODO cast(W as ubyte) as uword -> W and 255
c64scr.print_uw(W)
c64.CHROUT('\n')
; uword xx = @(clr+1)
}
}