mirror of
https://github.com/irmen/prog8.git
synced 2025-01-26 19:30:59 +00:00
fixup split words array comparisons
This commit is contained in:
parent
620ffe54ec
commit
f29d24e96a
@ -235,7 +235,7 @@ class AsmGen6502Internal (
|
||||
private val anyExprGen = AnyExprAsmGen(this)
|
||||
private val assignmentAsmGen = AssignmentAsmGen(program, this, anyExprGen, allocator)
|
||||
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
|
||||
private val ifElseAsmgen = IfElseAsmGen(program, symbolTable, this, allocator, assignmentAsmGen)
|
||||
private val ifElseAsmgen = IfElseAsmGen(program, symbolTable, this, allocator, assignmentAsmGen, errors)
|
||||
|
||||
fun compileToAssembly(): IAssemblyProgram? {
|
||||
|
||||
|
@ -4,13 +4,16 @@ import prog8.code.StRomSub
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.codegen.cpu6502.assignment.AsmAssignTarget
|
||||
import prog8.codegen.cpu6502.assignment.AssignmentAsmGen
|
||||
import prog8.codegen.cpu6502.assignment.TargetStorageKind
|
||||
|
||||
internal class IfElseAsmGen(private val program: PtProgram,
|
||||
private val st: SymbolTable,
|
||||
private val asmgen: AsmGen6502Internal,
|
||||
private val allocator: VariableAllocator,
|
||||
private val assignmentAsmGen: AssignmentAsmGen) {
|
||||
private val assignmentAsmGen: AssignmentAsmGen,
|
||||
private val errors: IErrorReporter) {
|
||||
|
||||
fun translate(stmt: PtIfElse) {
|
||||
require(stmt.condition.type== DataType.BOOL)
|
||||
@ -19,13 +22,14 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
val jumpAfterIf = stmt.ifScope.children.singleOrNull() as? PtJump
|
||||
|
||||
if(stmt.condition is PtIdentifier ||
|
||||
stmt.condition is PtBool ||
|
||||
stmt.condition is PtArrayIndexer ||
|
||||
stmt.condition is PtTypeCast ||
|
||||
stmt.condition is PtBuiltinFunctionCall ||
|
||||
stmt.condition is PtFunctionCall ||
|
||||
stmt.condition is PtMemoryByte ||
|
||||
stmt.condition is PtContainmentCheck)
|
||||
return fallbackTranslate(stmt, false) // the fallback code for these is optimal, so no warning.
|
||||
return fallbackTranslateForSimpleCondition(stmt)
|
||||
|
||||
val compareCond = stmt.condition as? PtBinaryExpression
|
||||
if(compareCond!=null) {
|
||||
@ -47,7 +51,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
translateIfElseBodies("bne", stmt)
|
||||
}
|
||||
|
||||
fallbackTranslate(stmt, true)
|
||||
throw AssemblyError("weird non-boolean condition node type ${stmt.condition} at ${stmt.condition.position}")
|
||||
}
|
||||
|
||||
private fun checkNotRomsubReturnsStatusReg(condition: PtExpression) {
|
||||
@ -78,16 +82,27 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun fallbackTranslate(stmt: PtIfElse, warning: Boolean) {
|
||||
if(warning) println("WARN: SLOW FALLBACK IF: ${stmt.position}. Ask for support.") // TODO should have no more of these
|
||||
val jumpAfterIf = stmt.ifScope.children.singleOrNull() as? PtJump
|
||||
private fun fallbackTranslate(stmt: PtIfElse) {
|
||||
errors.warn("SLOW FALLBACK FOR 'IF' CODEGEN - ask for support", stmt.position) // TODO should have no more of these
|
||||
assignConditionValueToRegisterAndTest(stmt.condition)
|
||||
val jumpAfterIf = stmt.ifScope.children.singleOrNull() as? PtJump
|
||||
if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies("beq", stmt)
|
||||
}
|
||||
|
||||
private fun fallbackTranslateForSimpleCondition(ifElse: PtIfElse) {
|
||||
// the condition is "simple" enough to just assign its 0/1 value to a register and branch on that
|
||||
assignConditionValueToRegisterAndTest(ifElse.condition)
|
||||
val jumpAfterIf = ifElse.ifScope.children.singleOrNull() as? PtJump
|
||||
if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, ifElse.elseScope)
|
||||
else
|
||||
translateIfElseBodies("beq", ifElse)
|
||||
}
|
||||
|
||||
|
||||
private fun translateIfElseBodies(elseBranchInstr: String, stmt: PtIfElse) {
|
||||
// comparison value is already in A
|
||||
val afterIfLabel = asmgen.makeLabel("afterif")
|
||||
@ -181,7 +196,18 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
translateIfElseBodies("bcc", stmt)
|
||||
}
|
||||
}
|
||||
else -> fallbackTranslate(stmt, false)
|
||||
in LogicalOperators -> {
|
||||
val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.BOOL, stmt.definingISub(), condition.position, register=RegisterOrPair.A)
|
||||
// TODO optimize this better for if statements to not require the A register to hold the intermediate boolean result
|
||||
if (assignmentAsmGen.optimizedLogicalExpr(condition, regAtarget)) {
|
||||
if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies("beq", stmt)
|
||||
} else
|
||||
fallbackTranslate(stmt)
|
||||
}
|
||||
else -> throw AssemblyError("expected comparison or logical operator")
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,7 +340,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
translateIfElseBodies("bne", stmt)
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("weird operator")
|
||||
else -> throw AssemblyError("expected comparison operator")
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,13 +461,14 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
val constValue = condition.right.asConstInteger()
|
||||
if(constValue==0) {
|
||||
// optimized comparisons with zero
|
||||
when (condition.operator) {
|
||||
"==" -> return wordEqualsZero(condition.left, false, signed, jumpAfterIf, stmt)
|
||||
"!=" -> return wordEqualsZero(condition.left, true, signed, jumpAfterIf, stmt)
|
||||
"<" -> return wordLessZero(condition.left, signed, jumpAfterIf, stmt)
|
||||
"<=" -> return wordLessEqualsZero(condition.left, signed, jumpAfterIf, stmt)
|
||||
">" -> return wordGreaterZero(condition.left, signed, jumpAfterIf, stmt)
|
||||
">=" -> return wordGreaterEqualsZero(condition.left, signed, jumpAfterIf, stmt)
|
||||
return when (condition.operator) {
|
||||
"==" -> wordEqualsZero(condition.left, false, signed, jumpAfterIf, stmt)
|
||||
"!=" -> wordEqualsZero(condition.left, true, signed, jumpAfterIf, stmt)
|
||||
"<" -> wordLessZero(condition.left, signed, jumpAfterIf, stmt)
|
||||
"<=" -> wordLessEqualsZero(condition.left, signed, jumpAfterIf, stmt)
|
||||
">" -> wordGreaterZero(condition.left, signed, jumpAfterIf, stmt)
|
||||
">=" -> wordGreaterEqualsZero(condition.left, signed, jumpAfterIf, stmt)
|
||||
else -> throw AssemblyError("expected comparison operator")
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,7 +480,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
"<=" -> throw AssemblyError("X<=Y should have been replaced by Y>=X")
|
||||
">" -> throw AssemblyError("X>Y should have been replaced by Y<X")
|
||||
">=" -> wordGreaterEqualsValue(condition.left, condition.right, signed, jumpAfterIf, stmt)
|
||||
else -> fallbackTranslate(stmt, false)
|
||||
else -> throw AssemblyError("expected comparison operator")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1010,20 +1037,26 @@ _jump jmp ($asmLabel)
|
||||
else
|
||||
translateIfElseBodies(falseBranch, stmt)
|
||||
}
|
||||
fun translateLoadFromVarSplitw(variable: String, constIndex: Int, branch: String, falseBranch: String) {
|
||||
asmgen.out(" lda ${variable}_lsb+$constIndex | ora ${variable}_msb+$constIndex")
|
||||
return if(jump!=null)
|
||||
translateJumpElseBodies(branch, falseBranch, jump, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies(falseBranch, stmt)
|
||||
}
|
||||
|
||||
if(notEquals) {
|
||||
when(value) {
|
||||
is PtArrayIndexer -> {
|
||||
val constIndex = value.index.asConstInteger()
|
||||
if(constIndex!=null) {
|
||||
val varName = asmgen.asmVariableName(value.variable)
|
||||
if(value.splitWords) {
|
||||
TODO("split word array != 0")
|
||||
} else {
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
if (offset < 256) {
|
||||
val varName = asmgen.asmVariableName(value.variable)
|
||||
return translateLoadFromVar("$varName+$offset", "bne", "beq")
|
||||
}
|
||||
return translateLoadFromVarSplitw(varName, constIndex, "bne", "beq")
|
||||
}
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
if (offset < 256) {
|
||||
return translateLoadFromVar("$varName+$offset", "bne", "beq")
|
||||
}
|
||||
}
|
||||
viaScratchReg("bne", "beq")
|
||||
@ -1036,19 +1069,18 @@ _jump jmp ($asmLabel)
|
||||
} else {
|
||||
when (value) {
|
||||
is PtArrayIndexer -> {
|
||||
if(value.splitWords) {
|
||||
TODO("split word array ==0")
|
||||
} else {
|
||||
val constIndex = value.index.asConstInteger()
|
||||
if (constIndex != null) {
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
if (offset < 256) {
|
||||
val varName = asmgen.asmVariableName(value.variable)
|
||||
return translateLoadFromVar("$varName+$offset", "beq", "bne")
|
||||
}
|
||||
val constIndex = value.index.asConstInteger()
|
||||
if (constIndex != null) {
|
||||
val varName = asmgen.asmVariableName(value.variable)
|
||||
if(value.splitWords) {
|
||||
return translateLoadFromVarSplitw(varName, constIndex, "beq", "bne")
|
||||
}
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
if (offset < 256) {
|
||||
return translateLoadFromVar("$varName+$offset", "beq", "bne")
|
||||
}
|
||||
viaScratchReg("beq", "bne")
|
||||
}
|
||||
viaScratchReg("beq", "bne")
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
return translateLoadFromVar(asmgen.asmVariableName(value), "beq", "bne")
|
||||
@ -1170,16 +1202,16 @@ _jump jmp ($asmLabel)
|
||||
val constIndex = left.index.asConstInteger()
|
||||
if(constIndex!=null) {
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
val varName = asmgen.asmVariableName(left.variable)
|
||||
if(left.splitWords) {
|
||||
TODO("split word array !=")
|
||||
return translateNotEquals("${varName}_lsb+$constIndex", "${varName}_msb+$constIndex")
|
||||
}
|
||||
val offset = constIndex * program.memsizer.memorySize(left.type)
|
||||
if(offset<256) {
|
||||
val varName = asmgen.asmVariableName(left.variable)
|
||||
return translateNotEquals("$varName+$offset", "$varName+$offset+1")
|
||||
}
|
||||
}
|
||||
fallbackTranslate(stmt, true)
|
||||
fallbackTranslate(stmt)
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
@ -1188,14 +1220,14 @@ _jump jmp ($asmLabel)
|
||||
}
|
||||
is PtAddressOf -> {
|
||||
if(left.isFromArrayElement)
|
||||
fallbackTranslate(stmt, false)
|
||||
fallbackTranslateForSimpleCondition(stmt)
|
||||
else {
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
val varname = asmgen.asmVariableName(left.identifier)
|
||||
return translateNotEquals("#<$varname", "#>$varname")
|
||||
}
|
||||
}
|
||||
else -> fallbackTranslate(stmt, false)
|
||||
else -> fallbackTranslate(stmt)
|
||||
}
|
||||
} else {
|
||||
when(left) {
|
||||
@ -1203,16 +1235,16 @@ _jump jmp ($asmLabel)
|
||||
val constIndex = left.index.asConstInteger()
|
||||
if(constIndex!=null) {
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
val varName = asmgen.asmVariableName(left.variable)
|
||||
if(left.splitWords) {
|
||||
TODO("split word array ==")
|
||||
return translateEquals("${varName}_lsb+$constIndex", "${varName}_msb+$constIndex")
|
||||
}
|
||||
val offset = constIndex * program.memsizer.memorySize(left.type)
|
||||
if(offset<256) {
|
||||
val varName = asmgen.asmVariableName(left.variable)
|
||||
return translateEquals("$varName+$offset", "$varName+$offset+1")
|
||||
}
|
||||
}
|
||||
fallbackTranslate(stmt, true)
|
||||
fallbackTranslate(stmt)
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
@ -1221,14 +1253,14 @@ _jump jmp ($asmLabel)
|
||||
}
|
||||
is PtAddressOf -> {
|
||||
if(left.isFromArrayElement)
|
||||
fallbackTranslate(stmt, false)
|
||||
fallbackTranslateForSimpleCondition(stmt)
|
||||
else {
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
val varname = asmgen.asmVariableName(left.identifier)
|
||||
return translateEquals("#<$varname", "#>$varname")
|
||||
}
|
||||
}
|
||||
else -> fallbackTranslate(stmt, false)
|
||||
else -> fallbackTranslate(stmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1298,7 +1330,7 @@ _jump jmp ($asmLabel)
|
||||
else
|
||||
translateIfElseBodies("bne", stmt)
|
||||
}
|
||||
else -> fallbackTranslate(stmt, false)
|
||||
else -> throw AssemblyError("expected comparison operator")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1207,7 +1207,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
return false
|
||||
}
|
||||
|
||||
private fun optimizedLogicalExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean {
|
||||
internal fun optimizedLogicalExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean {
|
||||
|
||||
fun swapOperands(): Boolean =
|
||||
if(expr.right is PtIdentifier || expr.right is PtMemoryByte)
|
||||
|
@ -9,7 +9,9 @@ test: clean generate test_prgs
|
||||
|
||||
generate:
|
||||
python make_eq_tests.py
|
||||
python make_eq_tests_splitw.py
|
||||
python make_cmp_tests.py
|
||||
python make_cmp_tests_splitw.py
|
||||
p8compile -target cx16 -sourcelines *.p8 >/dev/null
|
||||
|
||||
test_prgs:
|
||||
|
196
compiler/test/comparisons/make_cmp_tests_splitw.py
Normal file
196
compiler/test/comparisons/make_cmp_tests_splitw.py
Normal file
@ -0,0 +1,196 @@
|
||||
# generates various Prog8 files with a large amount of number comparison tests,
|
||||
# using various forms of the if statement (because these forms have their own code gen paths)
|
||||
|
||||
import sys
|
||||
|
||||
fail_index = 0
|
||||
|
||||
|
||||
class C:
|
||||
def __init__(self, short, long, operator, compare):
|
||||
self.short=short
|
||||
self.long=long
|
||||
self.operator=operator
|
||||
self.compare=compare
|
||||
|
||||
|
||||
def header(dt, comparison: C):
|
||||
print(f"""
|
||||
%import textio
|
||||
%import floats
|
||||
%import test_stack
|
||||
%zeropage dontuse
|
||||
%option no_sysinit
|
||||
|
||||
main {{
|
||||
uword success = 0
|
||||
str datatype = "{dt}"
|
||||
uword @shared comparison
|
||||
|
||||
sub start() {{
|
||||
txt.print("\\n{comparison.long} split words array tests for: ")
|
||||
txt.print(datatype)
|
||||
txt.nl()
|
||||
test_stack.test()
|
||||
txt.print("\\n{comparison.operator}array[]: ")
|
||||
test_cmp_array()
|
||||
test_stack.test()
|
||||
}}
|
||||
|
||||
sub verify_success(uword expected) {{
|
||||
if success==expected {{
|
||||
txt.print("ok")
|
||||
}} else {{
|
||||
txt.print(" **failed** ")
|
||||
txt.print_uw(success)
|
||||
txt.print(" success, expected ")
|
||||
txt.print_uw(expected)
|
||||
}}
|
||||
}}
|
||||
|
||||
sub fail_word(uword idx) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
sub fail_uword(uword idx) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
""")
|
||||
|
||||
|
||||
def tc(value):
|
||||
if value < 0x8000:
|
||||
return value
|
||||
else:
|
||||
return -(65536 - value)
|
||||
|
||||
|
||||
testnumbers = {
|
||||
"word": [tc(0xaabb), -1, 0, 1, 0x00aa, 0x7700, 0x7fff],
|
||||
"uword": [0, 1, 0x7700, 0xffff],
|
||||
}
|
||||
|
||||
|
||||
def make_test_array(datatype, comparison: C):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_cmp_array() {")
|
||||
print(f""" {datatype} @shared x
|
||||
{datatype}[] @split values = [0, 0]
|
||||
{datatype}[] @split sources = [0, 0]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
global fail_index
|
||||
for x in numbers:
|
||||
print(f" x={x}")
|
||||
print(f" sources[1]={x}")
|
||||
for value in numbers:
|
||||
print(f" values[1]={value}")
|
||||
result = comparison.compare(x, value)
|
||||
comp = comparison.operator
|
||||
test_index += 1
|
||||
if result:
|
||||
expected += 8 # there are 4 test types for every successful combo
|
||||
true_action1 = "success++"
|
||||
true_action2 = "success++"
|
||||
true_action3 = "success++"
|
||||
true_action4 = "success++"
|
||||
fail_action4 = "cx16.r0L++"
|
||||
true_action5 = "success++"
|
||||
true_action6 = "success++"
|
||||
true_action7 = "success++"
|
||||
true_action8 = "success++"
|
||||
fail_action8 = "cx16.r0L++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index})"
|
||||
fail_action4 = "success++"
|
||||
fail_index += 1
|
||||
true_action5 = f"fail_{datatype}({fail_index})"
|
||||
fail_index += 1
|
||||
true_action6 = f"fail_{datatype}({fail_index})"
|
||||
fail_index += 1
|
||||
true_action7 = f"fail_{datatype}({fail_index})"
|
||||
fail_index += 1
|
||||
true_action8 = f"fail_{datatype}({fail_index})"
|
||||
fail_action8 = "success++"
|
||||
expected += 2
|
||||
print(f""" ; direct jump
|
||||
if x{comp}values[1]
|
||||
goto lbl{test_index}a
|
||||
goto skip{test_index}a
|
||||
lbl{test_index}a: {true_action1}
|
||||
skip{test_index}a:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl{test_index}b
|
||||
if x{comp}values[1]
|
||||
goto cx16.r3
|
||||
goto skip{test_index}b
|
||||
lbl{test_index}b: {true_action2}
|
||||
skip{test_index}b:
|
||||
; no else
|
||||
if x{comp}values[1]
|
||||
{true_action3}
|
||||
|
||||
; with else
|
||||
if x{comp}values[1]
|
||||
{true_action4}
|
||||
else
|
||||
{fail_action4}
|
||||
""")
|
||||
print(f""" ; direct jump
|
||||
if sources[1]{comp}values[1]
|
||||
goto lbl{test_index}c
|
||||
goto skip{test_index}c
|
||||
lbl{test_index}c: {true_action5}
|
||||
skip{test_index}c:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl{test_index}d
|
||||
if sources[1]{comp}values[1]
|
||||
goto cx16.r3
|
||||
goto skip{test_index}d
|
||||
lbl{test_index}d: {true_action6}
|
||||
skip{test_index}d:
|
||||
; no else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action7}
|
||||
|
||||
; with else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action8}
|
||||
else
|
||||
{fail_action8}
|
||||
""")
|
||||
print(f" verify_success({expected})\n}}")
|
||||
|
||||
|
||||
def generate(datatype, comparison: C):
|
||||
global fail_index
|
||||
fail_index = 0
|
||||
header(datatype, comparison)
|
||||
make_test_array(datatype, comparison)
|
||||
print("\n}\n")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
comparisons = [
|
||||
C("lt", "less-than", "<", lambda x,y: x < y),
|
||||
C("lte", "less-equal", "<=", lambda x,y: x <= y),
|
||||
C("gt", "greater-than", ">", lambda x,y: x > y),
|
||||
C("gte", "greater-equal", ">=", lambda x,y: x >= y),
|
||||
]
|
||||
for comparison in comparisons:
|
||||
for dt in ["uword", "word"]:
|
||||
sys.stdout = open(f"test_{dt}_splitw_{comparison.short}.p8", "wt")
|
||||
generate(dt, comparison)
|
@ -58,53 +58,43 @@ main {{
|
||||
}}
|
||||
}}
|
||||
|
||||
sub fail_byte(uword idx, byte v1, byte v2) {{
|
||||
sub fail_byte(uword idx, byte v1) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.chrout(':')
|
||||
txt.print_b(v1)
|
||||
txt.chrout(',')
|
||||
txt.print_b(v2)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
sub fail_ubyte(uword idx, ubyte v1, ubyte v2) {{
|
||||
sub fail_ubyte(uword idx, ubyte v1) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.chrout(':')
|
||||
txt.print_ub(v1)
|
||||
txt.chrout(',')
|
||||
txt.print_ub(v2)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
sub fail_word(uword idx, word v1, word v2) {{
|
||||
sub fail_word(uword idx, word v1) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.chrout(':')
|
||||
txt.print_w(v1)
|
||||
txt.chrout(',')
|
||||
txt.print_w(v2)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
sub fail_uword(uword idx, uword v1, uword v2) {{
|
||||
sub fail_uword(uword idx, uword v1) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.chrout(':')
|
||||
txt.print_uw(v1)
|
||||
txt.chrout(',')
|
||||
txt.print_uw(v2)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
sub fail_float(uword idx, float v1, float v2) {{
|
||||
sub fail_float(uword idx, float v1) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.chrout(':')
|
||||
floats.print(v1)
|
||||
txt.chrout(',')
|
||||
floats.print(v2)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
@ -284,13 +274,13 @@ def make_test_is_number(datatype, equals):
|
||||
true_action4 = "success++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action1 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action2 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action3 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action4 = f"fail_{datatype}({fail_index},{x})"
|
||||
print(f""" ; direct jump
|
||||
if x{comp}{value}
|
||||
goto lbl{test_index}a
|
||||
@ -342,13 +332,13 @@ def make_test_is_var(datatype, equals):
|
||||
true_action4 = "success++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index},x,value)"
|
||||
true_action1 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index},x,value)"
|
||||
true_action2 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index},x,value)"
|
||||
true_action3 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index},x,value)"
|
||||
true_action4 = f"fail_{datatype}({fail_index},{x})"
|
||||
print(f""" ; direct jump
|
||||
if x{comp}value
|
||||
goto lbl{test_index}a
|
||||
@ -380,12 +370,14 @@ def make_test_is_array(datatype, equals):
|
||||
print(" sub test_is_array() {" if equals else " sub test_not_array() {")
|
||||
print(f""" {datatype} @shared x
|
||||
{datatype}[] values = [0, 0]
|
||||
{datatype}[] sources = [0, 0]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
global fail_index
|
||||
for x in numbers:
|
||||
print(f" x={x}")
|
||||
print(f" sources[1]={x}")
|
||||
for value in numbers:
|
||||
if value == 0:
|
||||
continue # 0 already tested separately
|
||||
@ -394,20 +386,32 @@ def make_test_is_array(datatype, equals):
|
||||
comp = "==" if equals else "!="
|
||||
test_index += 1
|
||||
if result:
|
||||
expected += 4 # there are 4 test types for every successful combo
|
||||
expected += 8 # there are 8 test types for every successful combo
|
||||
true_action1 = "success++"
|
||||
true_action2 = "success++"
|
||||
true_action3 = "success++"
|
||||
true_action4 = "success++"
|
||||
true_action5 = "success++"
|
||||
true_action6 = "success++"
|
||||
true_action7 = "success++"
|
||||
true_action8 = "success++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action1 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action2 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action3 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action4 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action5 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action6 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action7 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action8 = f"fail_{datatype}({fail_index},{x})"
|
||||
print(f""" ; direct jump
|
||||
if x{comp}values[1]
|
||||
goto lbl{test_index}a
|
||||
@ -430,6 +434,29 @@ skip{test_index}b:
|
||||
{true_action4}
|
||||
else
|
||||
cx16.r0L++
|
||||
""")
|
||||
print(f""" ; direct jump
|
||||
if sources[1]{comp}values[1]
|
||||
goto lbl{test_index}c
|
||||
goto skip{test_index}c
|
||||
lbl{test_index}c: {true_action5}
|
||||
skip{test_index}c:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl{test_index}d
|
||||
if sources[1]{comp}values[1]
|
||||
goto cx16.r3
|
||||
goto skip{test_index}d
|
||||
lbl{test_index}d: {true_action6}
|
||||
skip{test_index}d:
|
||||
; no else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action7}
|
||||
|
||||
; with else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action8}
|
||||
else
|
||||
cx16.r0L++
|
||||
""")
|
||||
print(f" verify_success({expected})\n}}")
|
||||
|
||||
@ -472,13 +499,13 @@ def make_test_is_expr(datatype, equals):
|
||||
true_action4 = "success++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action1 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action2 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action3 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index},x,{value})"
|
||||
true_action4 = f"fail_{datatype}({fail_index},{x})"
|
||||
print(f""" ; direct jump
|
||||
if x{comp}{expr}
|
||||
goto lbl{test_index}a
|
||||
@ -515,10 +542,10 @@ def generate(datatype):
|
||||
make_test_is_number(datatype, False)
|
||||
make_test_is_var(datatype, True)
|
||||
make_test_is_var(datatype, False)
|
||||
make_test_is_array(datatype, True)
|
||||
make_test_is_array(datatype, False)
|
||||
make_test_is_expr(datatype, True)
|
||||
make_test_is_expr(datatype, False)
|
||||
make_test_is_array(datatype, True)
|
||||
make_test_is_array(datatype, False)
|
||||
print("\n}\n")
|
||||
|
||||
|
||||
|
530
compiler/test/comparisons/make_eq_tests_splitw.py
Normal file
530
compiler/test/comparisons/make_eq_tests_splitw.py
Normal file
@ -0,0 +1,530 @@
|
||||
# generates various Prog8 files with a large amount of number equality tests,
|
||||
# using various forms of the if statement (because these forms have their own code gen paths)
|
||||
|
||||
import sys
|
||||
|
||||
fail_index = 0
|
||||
|
||||
|
||||
def header(dt):
|
||||
print(f"""
|
||||
%import textio
|
||||
%import floats
|
||||
%import test_stack
|
||||
%zeropage dontuse
|
||||
%option no_sysinit
|
||||
|
||||
main {{
|
||||
ubyte success = 0
|
||||
str datatype = "{dt}"
|
||||
uword @shared comparison
|
||||
|
||||
sub start() {{
|
||||
txt.print("\\n(in)equality tests for split words datatype: ")
|
||||
txt.print(datatype)
|
||||
txt.nl()
|
||||
test_stack.test()
|
||||
txt.print("==0: ")
|
||||
test_is_zero()
|
||||
txt.print("\\n!=0: ")
|
||||
test_not_zero()
|
||||
txt.print("\\n==number: ")
|
||||
test_is_number()
|
||||
txt.print("\\n!=number: ")
|
||||
test_not_number()
|
||||
txt.print("\\n==var: ")
|
||||
test_is_var()
|
||||
txt.print("\\n!=var: ")
|
||||
test_not_var()
|
||||
txt.print("\\n==array[] @split: ")
|
||||
test_is_array_splitw()
|
||||
txt.print("\\n!=array[] @split: ")
|
||||
test_not_array_splitw()
|
||||
txt.print("\\n==expr: ")
|
||||
test_is_expr()
|
||||
txt.print("\\n!=expr: ")
|
||||
test_not_expr()
|
||||
test_stack.test()
|
||||
}}
|
||||
|
||||
sub verify_success(ubyte expected) {{
|
||||
if success==expected {{
|
||||
txt.print("ok")
|
||||
}} else {{
|
||||
txt.print(" **failed** ")
|
||||
txt.print_ub(success)
|
||||
txt.print(" success, expected ")
|
||||
txt.print_ub(expected)
|
||||
}}
|
||||
}}
|
||||
|
||||
sub fail_word(uword idx, word v1) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.chrout(':')
|
||||
txt.print_w(v1)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
sub fail_uword(uword idx, uword v1) {{
|
||||
txt.print(" **fail#")
|
||||
txt.print_uw(idx)
|
||||
txt.chrout(':')
|
||||
txt.print_uw(v1)
|
||||
txt.print(" **")
|
||||
}}
|
||||
|
||||
""")
|
||||
|
||||
|
||||
zero_values = {
|
||||
"byte": 0,
|
||||
"ubyte": 0,
|
||||
"word": 0,
|
||||
"uword": 0,
|
||||
"float": 0.0
|
||||
}
|
||||
|
||||
nonzero_values = {
|
||||
"byte": -100,
|
||||
"ubyte": 100,
|
||||
"word": -9999,
|
||||
"uword": 9999,
|
||||
"float": 1234.56
|
||||
}
|
||||
|
||||
|
||||
def make_test_is_zero(datatype):
|
||||
print(f"""
|
||||
sub test_is_zero() {{
|
||||
{datatype}[] @split sources = [9999, 9999]
|
||||
success = 0
|
||||
|
||||
sources[1]={zero_values[datatype]}
|
||||
; direct jump
|
||||
if sources[1]==0
|
||||
goto lbl1
|
||||
goto skip1
|
||||
lbl1: success++
|
||||
skip1:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl2
|
||||
if sources[1]==0
|
||||
goto cx16.r3
|
||||
goto skip2
|
||||
lbl2: success++
|
||||
skip2:
|
||||
; no else
|
||||
if sources[1]==0
|
||||
success++
|
||||
|
||||
; with else
|
||||
if sources[1]==0
|
||||
success++
|
||||
else
|
||||
cx16.r0L++
|
||||
|
||||
sources[1] = {nonzero_values[datatype]}
|
||||
; direct jump
|
||||
if sources[1]==0
|
||||
goto skip3
|
||||
success++
|
||||
skip3:
|
||||
; indirect jump
|
||||
cx16.r3 = &skip4
|
||||
if sources[1]==0
|
||||
goto cx16.r3
|
||||
success++
|
||||
skip4:
|
||||
; no else
|
||||
success++
|
||||
if sources[1]==0
|
||||
success--
|
||||
|
||||
; with else
|
||||
if sources[1]==0
|
||||
cx16.r0L++
|
||||
else
|
||||
success++
|
||||
|
||||
verify_success(8)
|
||||
}}
|
||||
""")
|
||||
|
||||
|
||||
def make_test_not_zero(datatype):
|
||||
print(f"""
|
||||
sub test_not_zero() {{
|
||||
{datatype}[] @split sources = [9999, 9999]
|
||||
success = 0
|
||||
|
||||
sources[1]={nonzero_values[datatype]}
|
||||
; direct jump
|
||||
if sources[1]!=0
|
||||
goto lbl1
|
||||
goto skip1
|
||||
lbl1: success++
|
||||
skip1:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl2
|
||||
if sources[1]!=0
|
||||
goto cx16.r3
|
||||
goto skip2
|
||||
lbl2: success++
|
||||
skip2:
|
||||
; no else
|
||||
if sources[1]!=0
|
||||
success++
|
||||
|
||||
; with else
|
||||
if sources[1]!=0
|
||||
success++
|
||||
else
|
||||
cx16.r0L++
|
||||
|
||||
sources[1] = {zero_values[datatype]}
|
||||
; direct jump
|
||||
if sources[1]!=0
|
||||
goto skip3
|
||||
success++
|
||||
skip3:
|
||||
; indirect jump
|
||||
cx16.r3 = &skip4
|
||||
if sources[1]!=0
|
||||
goto cx16.r3
|
||||
success++
|
||||
skip4:
|
||||
; no else
|
||||
success++
|
||||
if sources[1]!=0
|
||||
success--
|
||||
|
||||
; with else
|
||||
if sources[1]!=0
|
||||
cx16.r0L++
|
||||
else
|
||||
success++
|
||||
|
||||
verify_success(8)
|
||||
}}
|
||||
""")
|
||||
|
||||
|
||||
def tc(value):
|
||||
if value < 0x8000:
|
||||
return value
|
||||
else:
|
||||
return -(65536 - value)
|
||||
|
||||
|
||||
testnumbers = {
|
||||
"byte": [-100, 0, 100],
|
||||
"ubyte": [0, 1, 255],
|
||||
"word": [tc(0xaabb), 0, 0x00aa, 0x7700, 0x7fff],
|
||||
"uword": [0, 1, 0x7700, 0xffff],
|
||||
"float": [0.0, 1234.56]
|
||||
}
|
||||
|
||||
|
||||
def make_test_is_number(datatype, equals):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_is_number() {" if equals else " sub test_not_number() {")
|
||||
print(f""" {datatype}[] @split sources = [9999, 9999]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
global fail_index
|
||||
for x in numbers:
|
||||
print(f" sources[1]={x}")
|
||||
for value in numbers:
|
||||
if value == 0:
|
||||
continue # 0 already tested separately
|
||||
result = (x == value) if equals else (x != value)
|
||||
comp = "==" if equals else "!="
|
||||
test_index += 1
|
||||
if result:
|
||||
expected += 4 # there are 4 test types for every successful combo
|
||||
true_action1 = "success++"
|
||||
true_action2 = "success++"
|
||||
true_action3 = "success++"
|
||||
true_action4 = "success++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index},{x})"
|
||||
print(f""" ; direct jump
|
||||
if sources[1]{comp}{value}
|
||||
goto lbl{test_index}a
|
||||
goto skip{test_index}a
|
||||
lbl{test_index}a: {true_action1}
|
||||
skip{test_index}a:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl{test_index}b
|
||||
if sources[1]{comp}{value}
|
||||
goto cx16.r3
|
||||
goto skip{test_index}b
|
||||
lbl{test_index}b: {true_action2}
|
||||
skip{test_index}b:
|
||||
; no else
|
||||
if sources[1]{comp}{value}
|
||||
{true_action3}
|
||||
|
||||
; with else
|
||||
if sources[1]{comp}{value}
|
||||
{true_action4}
|
||||
else
|
||||
cx16.r0L++
|
||||
""")
|
||||
print(f" verify_success({expected})\n}}")
|
||||
|
||||
|
||||
def make_test_is_var(datatype, equals):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_is_var() {" if equals else " sub test_not_var() {")
|
||||
print(f""" {datatype}[] @split sources = [9999, 9999]
|
||||
{datatype}[] @split values = [8888,8888]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
global fail_index
|
||||
for x in numbers:
|
||||
print(f" sources[1]={x}")
|
||||
for value in numbers:
|
||||
if value == 0:
|
||||
continue # 0 already tested separately
|
||||
print(f" values[1]={value}")
|
||||
result = (x == value) if equals else (x != value)
|
||||
comp = "==" if equals else "!="
|
||||
test_index += 1
|
||||
if result:
|
||||
expected += 4 # there are 4 test types for every successful combo
|
||||
true_action1 = "success++"
|
||||
true_action2 = "success++"
|
||||
true_action3 = "success++"
|
||||
true_action4 = "success++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index},{x})"
|
||||
print(f""" ; direct jump
|
||||
if sources[1]{comp}values[1]
|
||||
goto lbl{test_index}a
|
||||
goto skip{test_index}a
|
||||
lbl{test_index}a: {true_action1}
|
||||
skip{test_index}a:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl{test_index}b
|
||||
if sources[1]{comp}values[1]
|
||||
goto cx16.r3
|
||||
goto skip{test_index}b
|
||||
lbl{test_index}b: {true_action2}
|
||||
skip{test_index}b:
|
||||
; no else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action3}
|
||||
|
||||
; with else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action4}
|
||||
else
|
||||
cx16.r0L++
|
||||
""")
|
||||
print(f" verify_success({expected})\n}}")
|
||||
|
||||
|
||||
def make_test_is_array(datatype, equals):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_is_array_splitw() {" if equals else " sub test_not_array_splitw() {")
|
||||
print(f"""
|
||||
{datatype}[] @split values = [9999, 8888]
|
||||
{datatype}[] @split sources = [9999, 8888]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
global fail_index
|
||||
for x in numbers:
|
||||
print(f" values[1]={x}")
|
||||
print(f" sources[1]={x}")
|
||||
for value in numbers:
|
||||
if value == 0:
|
||||
continue # 0 already tested separately
|
||||
print(f" values[1]={value}")
|
||||
result = (x == value) if equals else (x != value)
|
||||
comp = "==" if equals else "!="
|
||||
test_index += 1
|
||||
if result:
|
||||
expected += 8 # there are 8 test types for every successful combo
|
||||
true_action1 = "success++"
|
||||
true_action2 = "success++"
|
||||
true_action3 = "success++"
|
||||
true_action4 = "success++"
|
||||
true_action5 = "success++"
|
||||
true_action6 = "success++"
|
||||
true_action7 = "success++"
|
||||
true_action8 = "success++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action5 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action6 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action7 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action8 = f"fail_{datatype}({fail_index},{x})"
|
||||
print(f""" ; direct jump
|
||||
if sources[1]{comp}values[1]
|
||||
goto lbl{test_index}a
|
||||
goto skip{test_index}a
|
||||
lbl{test_index}a: {true_action1}
|
||||
skip{test_index}a:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl{test_index}b
|
||||
if sources[1]{comp}values[1]
|
||||
goto cx16.r3
|
||||
goto skip{test_index}b
|
||||
lbl{test_index}b: {true_action2}
|
||||
skip{test_index}b:
|
||||
; no else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action3}
|
||||
|
||||
; with else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action4}
|
||||
else
|
||||
cx16.r0L++
|
||||
""")
|
||||
print(f""" ; direct jump
|
||||
if sources[1]{comp}values[1]
|
||||
goto lbl{test_index}c
|
||||
goto skip{test_index}c
|
||||
lbl{test_index}c: {true_action5}
|
||||
skip{test_index}c:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl{test_index}d
|
||||
if sources[1]{comp}values[1]
|
||||
goto cx16.r3
|
||||
goto skip{test_index}d
|
||||
lbl{test_index}d: {true_action6}
|
||||
skip{test_index}d:
|
||||
; no else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action7}
|
||||
|
||||
; with else
|
||||
if sources[1]{comp}values[1]
|
||||
{true_action8}
|
||||
else
|
||||
cx16.r0L++
|
||||
""")
|
||||
print(f" verify_success({expected})\n}}")
|
||||
|
||||
|
||||
def make_test_is_expr(datatype, equals):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_is_expr() {" if equals else " sub test_not_expr() {")
|
||||
print(f""" {datatype}[] @split sources = [9999, 9999]
|
||||
cx16.r4 = 1
|
||||
cx16.r5 = 1
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
global fail_index
|
||||
for x in numbers:
|
||||
print(f" sources[1]={x}")
|
||||
for value in numbers:
|
||||
if value == 0:
|
||||
continue # 0 already tested separately
|
||||
if datatype=="byte":
|
||||
expr = f"cx16.r4sL+{value}-cx16.r5sL"
|
||||
elif datatype=="ubyte":
|
||||
expr = f"cx16.r4L+{value}-cx16.r5L"
|
||||
elif datatype=="word":
|
||||
expr = f"cx16.r4s+{value}-cx16.r5s"
|
||||
elif datatype=="uword":
|
||||
expr = f"cx16.r4+{value}-cx16.r5"
|
||||
elif datatype=="float":
|
||||
expr = f"f4+{value}-f5"
|
||||
result = (x == value) if equals else (x != value)
|
||||
comp = "==" if equals else "!="
|
||||
test_index += 1
|
||||
if result:
|
||||
expected += 4 # there are 4 test types for every successful combo
|
||||
true_action1 = "success++"
|
||||
true_action2 = "success++"
|
||||
true_action3 = "success++"
|
||||
true_action4 = "success++"
|
||||
else:
|
||||
fail_index += 1
|
||||
true_action1 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action2 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action3 = f"fail_{datatype}({fail_index},{x})"
|
||||
fail_index += 1
|
||||
true_action4 = f"fail_{datatype}({fail_index},{x})"
|
||||
print(f""" ; direct jump
|
||||
if sources[1]{comp}{expr}
|
||||
goto lbl{test_index}a
|
||||
goto skip{test_index}a
|
||||
lbl{test_index}a: {true_action1}
|
||||
skip{test_index}a:
|
||||
; indirect jump
|
||||
cx16.r3 = &lbl{test_index}b
|
||||
if sources[1]{comp}{expr}
|
||||
goto cx16.r3
|
||||
goto skip{test_index}b
|
||||
lbl{test_index}b: {true_action2}
|
||||
skip{test_index}b:
|
||||
; no else
|
||||
if sources[1]{comp}{expr}
|
||||
{true_action3}
|
||||
|
||||
; with else
|
||||
if sources[1]{comp}{expr}
|
||||
{true_action4}
|
||||
else
|
||||
cx16.r0L++
|
||||
""")
|
||||
print(f" verify_success({expected})\n}}")
|
||||
|
||||
|
||||
def generate(datatype):
|
||||
global fail_index
|
||||
fail_index = 0
|
||||
header(datatype)
|
||||
make_test_is_zero(datatype)
|
||||
make_test_not_zero(datatype)
|
||||
make_test_is_number(datatype, True)
|
||||
make_test_is_number(datatype, False)
|
||||
make_test_is_var(datatype, True)
|
||||
make_test_is_var(datatype, False)
|
||||
make_test_is_expr(datatype, True)
|
||||
make_test_is_expr(datatype, False)
|
||||
make_test_is_array(datatype, True)
|
||||
make_test_is_array(datatype, False)
|
||||
print("\n}\n")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for dt in ["uword", "word"]:
|
||||
sys.stdout = open(f"test_{dt}_splitw_equalities.p8", "wt")
|
||||
generate(dt)
|
@ -1,21 +1,17 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
check all comparisons for split word arrays (signed+unsigned, all 4 variants)
|
||||
|
||||
snow example is a lot larger!
|
||||
|
||||
explore possible optimizations for words when comparing to a constant number (BeforeAsmAstChanger)
|
||||
|
||||
|
||||
add tests for comparison that do an assignment rather than an if
|
||||
assign to variable, and barray[indexvar], test if they're both correct
|
||||
(bb = value > -100 --> contains a beq +++ that shouldn't be there??)
|
||||
|
||||
optimize assignOptimizedComparisonWords for when comparing to simple things like number and identifier.
|
||||
optimize optimizedPlusMinExpr for when comparing to simple things like number and identifier.
|
||||
optimize the IfElseAsmgen's fallbackTranslate even more (for arrays without const index for example?)
|
||||
|
||||
optimize byte < and byte >= assignment to use the rol trick instead of branching:
|
||||
bool @shared bb = cx16.r0L >= 128
|
||||
bool @shared bb2 = cx16.r0L < 99
|
||||
|
||||
|
||||
snow example is a lot larger!
|
||||
|
||||
|
||||
|
||||
===== ====== =======
|
||||
@ -45,7 +41,7 @@ ok ok efficient code for if byte comparisons against 0 (== and !=)
|
||||
ok ok efficient code for if word comparisons against 0 (== and !=)
|
||||
ok ok efficient code for if float comparisons against 0 (== and !=)
|
||||
ok ok efficient code for if byte comparisons against a value
|
||||
ok FAIL efficient code for if word comparisons against a value
|
||||
ok ok efficient code for if word comparisons against a value
|
||||
ok ok efficient code for if float comparisons against a value
|
||||
ok ok efficient code for assignment byte comparisons against 0 (== and !=)
|
||||
ok ok efficient code for assignment word comparisons against 0 (== and !=)
|
||||
@ -61,11 +57,8 @@ ok . check program sizes vs. master branch
|
||||
===== ====== =======
|
||||
|
||||
|
||||
check that the flood fill routine in gfx2 and paint still works.
|
||||
re-allow typecast of const true/false back to ubytes 1 and 0?
|
||||
re-allow typecast of const ubyte 0/1 to false/true boolean?
|
||||
|
||||
|
||||
IR: add TEST instruction to test memory content and set N/Z flags, without affecting any register.
|
||||
replace all LOADM+CMPI #0 / LOAD #0+LOADM+CMP+BRANCH by this instruction
|
||||
|
||||
optimize translateIfByte() handling of shortcircuiting logical operators.
|
||||
|
@ -6,32 +6,40 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte[] barray = [11,22,33]
|
||||
uword[] warray = [1111,2222,3333]
|
||||
|
||||
if any(barray)
|
||||
cx16.r0++
|
||||
ubyte[] envelope_attacks = [1,2,3,4]
|
||||
|
||||
if msb(cx16.r0) > cx16.r2L or envelope_attacks[cx16.r1L]==0 {
|
||||
txt.print("yep")
|
||||
}
|
||||
|
||||
if barray[2] == 33
|
||||
cx16.r0++
|
||||
else
|
||||
cx16.r1++
|
||||
|
||||
if warray[2] == 3333
|
||||
cx16.r0++
|
||||
else
|
||||
cx16.r1++
|
||||
|
||||
if barray[cx16.r0L] == 33
|
||||
cx16.r0++
|
||||
else
|
||||
cx16.r1++
|
||||
|
||||
if warray[cx16.r0L] == 3333
|
||||
cx16.r0++
|
||||
else
|
||||
cx16.r1++
|
||||
;
|
||||
; ubyte[] barray = [11,22,33]
|
||||
; uword[] warray = [1111,2222,3333]
|
||||
;
|
||||
; if any(barray)
|
||||
; cx16.r0++
|
||||
;
|
||||
;
|
||||
; if barray[2] == 33
|
||||
; cx16.r0++
|
||||
; else
|
||||
; cx16.r1++
|
||||
;
|
||||
; if warray[2] == 3333
|
||||
; cx16.r0++
|
||||
; else
|
||||
; cx16.r1++
|
||||
;
|
||||
; if barray[cx16.r0L] == 33
|
||||
; cx16.r0++
|
||||
; else
|
||||
; cx16.r1++
|
||||
;
|
||||
; if warray[cx16.r0L] == 3333
|
||||
; cx16.r0++
|
||||
; else
|
||||
; cx16.r1++
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user