mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
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:
parent
a00c39e9cf
commit
6922333755
@ -206,4 +206,26 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,7 @@ private val functionSignatures: List<FSignature> = listOf(
|
||||
FSignature("ror2" , false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("sort" , 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):
|
||||
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
|
||||
|
@ -69,10 +69,80 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
"peek" -> throw AssemblyError("peek() should have been replaced by @()")
|
||||
"pokew" -> funcPokeW(fcall)
|
||||
"poke" -> throw AssemblyError("poke() should have been replaced by @()")
|
||||
"cmp" -> funcCmp(fcall)
|
||||
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?) {
|
||||
if(discardResult || fcall !is FunctionCall)
|
||||
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
||||
|
@ -791,6 +791,12 @@ sort(array)
|
||||
|
||||
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)
|
||||
Get the least significant byte of the word x. Equivalent to the cast "x as ubyte".
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
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 several inner loops in gfx2
|
||||
|
@ -1,31 +1,81 @@
|
||||
%import floats
|
||||
%import gfx2
|
||||
%import test_stack
|
||||
%zeropage floatsafe
|
||||
%import graphics
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
gfx2.screen_mode(1)
|
||||
;graphics.enable_bitmap_mode()
|
||||
byte xx
|
||||
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
|
||||
ubyte yy
|
||||
|
||||
gfx2.line(160,100,160,80 ,1)
|
||||
gfx2.line(160,80,180,81 ,1)
|
||||
gfx2.line(180,81,177,103 ,1)
|
||||
graphics.line(150,50,150,50)
|
||||
|
||||
for yy in 0 to 199-60 step 16 {
|
||||
|
||||
for xx in 0 to 319-50 step 16 {
|
||||
gfx2.line(30+xx, 10+yy, 50+xx, 30+yy ,1)
|
||||
gfx2.line(49+xx, 30+yy, 10+xx, 30+yy ,1)
|
||||
gfx2.line(11+xx, 29+yy, 29+xx, 11+yy ,1)
|
||||
graphics.line(30+xx, 10+yy, 50+xx, 30+yy)
|
||||
graphics.line(49+xx, 30+yy, 10+xx, 30+yy)
|
||||
graphics.line(11+xx, 29+yy, 29+xx, 11+yy)
|
||||
|
||||
; triangle 2, counter-clockwise
|
||||
gfx2.line(30+xx, 40+yy, 10+xx, 60+yy ,1)
|
||||
gfx2.line(11+xx, 60+yy, 50+xx, 60+yy ,1)
|
||||
gfx2.line(49+xx, 59+yy, 31+xx,41+yy ,1)
|
||||
graphics.line(30+xx, 40+yy, 10+xx, 60+yy)
|
||||
graphics.line(11+xx, 60+yy, 50+xx, 60+yy)
|
||||
graphics.line(49+xx, 59+yy, 31+xx,41+yy)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user