add a cmp(x,y) function that returns no value but only sets the status bits based off the comparison (can be used with a conditional jump afterwards)

This commit is contained in:
Irmen de Jong 2021-03-12 20:12:33 +01:00
parent a00c39e9cf
commit 6922333755
6 changed files with 164 additions and 16 deletions

View File

@ -206,4 +206,26 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
} }
return noModifications return noModifications
} }
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
if(functionCallStatement.target.nameInSource==listOf("cmp")) {
// if the datatype of the arguments of cmp() are different, cast the byte one to word.
val arg1 = functionCallStatement.args[0]
val arg2 = functionCallStatement.args[1]
val dt1 = arg1.inferType(program).typeOrElse(DataType.STRUCT)
val dt2 = arg2.inferType(program).typeOrElse(DataType.STRUCT)
if(dt1 in ByteDatatypes) {
if(dt2 in ByteDatatypes)
return noModifications
val cast1 = TypecastExpression(arg1, if(dt1==DataType.UBYTE) DataType.UWORD else DataType.WORD, true, functionCallStatement.position)
return listOf(IAstModification.ReplaceNode(arg1, cast1, functionCallStatement))
} else {
if(dt2 in WordDatatypes)
return noModifications
val cast2 = TypecastExpression(arg2, if(dt2==DataType.UBYTE) DataType.UWORD else DataType.WORD, true, functionCallStatement.position)
return listOf(IAstModification.ReplaceNode(arg2, cast2, functionCallStatement))
}
}
return noModifications
}
} }

View File

@ -97,6 +97,7 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("ror2" , false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), FSignature("ror2" , false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null),
FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), null), FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), null),
FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), null), FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), null),
FSignature("cmp" , false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), null),
// these few have a return value depending on the argument(s): // these few have a return value depending on the argument(s):
FSignature("max" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args FSignature("max" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args
FSignature("min" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args FSignature("min" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args

View File

@ -69,10 +69,80 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
"peek" -> throw AssemblyError("peek() should have been replaced by @()") "peek" -> throw AssemblyError("peek() should have been replaced by @()")
"pokew" -> funcPokeW(fcall) "pokew" -> funcPokeW(fcall)
"poke" -> throw AssemblyError("poke() should have been replaced by @()") "poke" -> throw AssemblyError("poke() should have been replaced by @()")
"cmp" -> funcCmp(fcall)
else -> TODO("missing asmgen for builtin func ${func.name}") else -> TODO("missing asmgen for builtin func ${func.name}")
} }
} }
private fun funcCmp(fcall: IFunctionCall) {
val arg1 = fcall.args[0]
val arg2 = fcall.args[1]
val dt1 = arg1.inferType(program).typeOrElse(DataType.STRUCT)
val dt2 = arg2.inferType(program).typeOrElse(DataType.STRUCT)
if(dt1 in ByteDatatypes) {
if(dt2 in ByteDatatypes) {
when (arg2) {
is IdentifierReference -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
asmgen.out(" cmp ${asmgen.asmVariableName(arg2)}")
}
is NumericLiteralValue -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
asmgen.out(" cmp #${arg2.number}")
}
is DirectMemoryRead -> {
if(arg2.addressExpression is NumericLiteralValue) {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
asmgen.out(" cmp ${arg2.addressExpression.constValue(program)!!.number.toHex()}")
} else {
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine())
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
asmgen.out(" cmp P8ZP_SCRATCH_B1")
}
}
else -> {
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine())
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
asmgen.out(" cmp P8ZP_SCRATCH_B1")
}
}
} else
throw AssemblyError("args for cmp() should have same dt")
} else {
// dt1 is a word
if(dt2 in WordDatatypes) {
when (arg2) {
is IdentifierReference -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
cpy ${asmgen.asmVariableName(arg2)}+1
bne +
cmp ${asmgen.asmVariableName(arg2)}
+""")
}
is NumericLiteralValue -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
cpy #>${arg2.number}
bne +
cmp #<${arg2.number}
+""")
}
else -> {
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, (fcall as Node).definingSubroutine())
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
cpy P8ZP_SCRATCH_W1+1
bne +
cmp P8ZP_SCRATCH_W1
+""")
}
}
} else
throw AssemblyError("args for cmp() should have same dt")
}
}
private fun funcMemory(fcall: IFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) { private fun funcMemory(fcall: IFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
if(discardResult || fcall !is FunctionCall) if(discardResult || fcall !is FunctionCall)
throw AssemblyError("should not discard result of memory allocation at $fcall") throw AssemblyError("should not discard result of memory allocation at $fcall")

View File

@ -791,6 +791,12 @@ sort(array)
Miscellaneous Miscellaneous
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
cmp(x,y)
Compare the integer value x to integer value y. Doesn't return a value or boolean result, only sets the processor's status bits!
You can use a conditional jumps (``if_cc`` etcetera) to act on this.
Normally you should just use a comparison expression (``x < y``)
lsb(x) lsb(x)
Get the least significant byte of the word x. Equivalent to the cast "x as ubyte". Get the least significant byte of the word x. Equivalent to the cast "x as ubyte".

View File

@ -2,7 +2,6 @@
TODO TODO
==== ====
- add a cmp(x,y) function that returns no value but only sets the status bits based off the comparison (can be used with a conditional jump afterwards)
- optimize comparisons followed by a conditional jump ; try to not have to jsr to the comparison routines. (so if/while/do-until are faster) - optimize comparisons followed by a conditional jump ; try to not have to jsr to the comparison routines. (so if/while/do-until are faster)
- optimize several inner loops in gfx2 - optimize several inner loops in gfx2

View File

@ -1,31 +1,81 @@
%import floats %import graphics
%import gfx2 %zeropage basicsafe
%import test_stack
%zeropage floatsafe
main { main {
sub start() { sub start() {
gfx2.screen_mode(1) byte xx
;graphics.enable_bitmap_mode() word yy
uword addr = $3000
cmp(xx, @($2000))
cmp(@($2000), xx)
cmp(yy, @($2000))
cmp(@($2000), yy)
}
sub start3() {
byte xx
byte yy
; all comparisons with constant values are already optimized
byte value = 100
while xx==value {
yy++
}
while xx!=value {
yy++
}
while xx>value {
yy++
}
do {
yy++
} until xx==value
do {
yy++
} until xx!=value
do {
yy++
} until xx>value
if xx==value
yy++
if xx!=value
yy++
if xx>value
yy++
}
sub start2() {
graphics.enable_bitmap_mode()
uword xx uword xx
ubyte yy ubyte yy
gfx2.line(160,100,160,80 ,1) graphics.line(150,50,150,50)
gfx2.line(160,80,180,81 ,1)
gfx2.line(180,81,177,103 ,1)
for yy in 0 to 199-60 step 16 { for yy in 0 to 199-60 step 16 {
for xx in 0 to 319-50 step 16 { for xx in 0 to 319-50 step 16 {
gfx2.line(30+xx, 10+yy, 50+xx, 30+yy ,1) graphics.line(30+xx, 10+yy, 50+xx, 30+yy)
gfx2.line(49+xx, 30+yy, 10+xx, 30+yy ,1) graphics.line(49+xx, 30+yy, 10+xx, 30+yy)
gfx2.line(11+xx, 29+yy, 29+xx, 11+yy ,1) graphics.line(11+xx, 29+yy, 29+xx, 11+yy)
; triangle 2, counter-clockwise ; triangle 2, counter-clockwise
gfx2.line(30+xx, 40+yy, 10+xx, 60+yy ,1) graphics.line(30+xx, 40+yy, 10+xx, 60+yy)
gfx2.line(11+xx, 60+yy, 50+xx, 60+yy ,1) graphics.line(11+xx, 60+yy, 50+xx, 60+yy)
gfx2.line(49+xx, 59+yy, 31+xx,41+yy ,1) graphics.line(49+xx, 59+yy, 31+xx,41+yy)
} }
} }