mirror of
https://github.com/irmen/prog8.git
synced 2025-01-13 10:29:52 +00:00
tweaks
This commit is contained in:
parent
86d4a4309f
commit
96bed8f57f
@ -334,7 +334,7 @@ val Cx16VirtualRegisters = arrayOf(
|
||||
RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, RegisterOrPair.R15
|
||||
)
|
||||
|
||||
val CpuRegisters = setOf(
|
||||
val CpuRegisters = arrayOf(
|
||||
RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y,
|
||||
RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY
|
||||
)
|
||||
|
@ -38,7 +38,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
|
||||
for (reserved in options.zpReserved)
|
||||
reserve(reserved)
|
||||
|
||||
free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
|
||||
free.removeAll(arrayOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
package prog8.code.core
|
||||
|
||||
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "xor") // note: and,or are not associative because of Shortcircuit/McCarthy evaluation
|
||||
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
||||
val LogicalOperators = setOf("and", "or", "xor", "not", "in")
|
||||
val BitwiseOperators = setOf("&", "|", "^", "~")
|
||||
val PrefixOperators = setOf("+", "-", "~", "not")
|
||||
val AssociativeOperators = arrayOf("+", "*", "&", "|", "^", "==", "!=", "xor") // note: and,or are not associative because of Shortcircuit/McCarthy evaluation
|
||||
val ComparisonOperators = arrayOf("==", "!=", "<", ">", "<=", ">=")
|
||||
val LogicalOperators = arrayOf("and", "or", "xor", "not", "in")
|
||||
val BitwiseOperators = arrayOf("&", "|", "^", "~")
|
||||
val PrefixOperators = arrayOf("+", "-", "~", "not")
|
||||
|
||||
fun invertedComparisonOperator(operator: String) =
|
||||
when (operator) {
|
||||
|
@ -28,7 +28,7 @@ class AtariZeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
ZeropageType.FULL -> {
|
||||
// TODO all atari usable zero page locations, except the ones used by the system's IRQ routine
|
||||
free.addAll(0x00u..0xffu)
|
||||
// TODO atari free.removeAll(setOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
||||
// TODO atari free.removeAll(arrayOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
||||
}
|
||||
ZeropageType.KERNALSAFE -> {
|
||||
free.addAll(0x80u..0xffu) // TODO
|
||||
|
@ -33,18 +33,18 @@ class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
ZeropageType.FULL -> {
|
||||
// $00/$01 are data port IO registers, // $02-$09 are storage locations for JSRFAR and such
|
||||
free.addAll(0x0au..0xffu)
|
||||
free.removeAll(listOf(0x90u, 0x91u, 0xa0u, 0xa1u, 0xa2u, 0xc0u, 0xccu, 0xcdu, 0xd0u, 0xd1u, 0xd2u, 0xd3u, 0xd4u, 0xd5u, 0xf7u)) // these are updated/used by IRQ
|
||||
free.removeAll(arrayOf(0x90u, 0x91u, 0xa0u, 0xa1u, 0xa2u, 0xc0u, 0xccu, 0xcdu, 0xd0u, 0xd1u, 0xd2u, 0xd3u, 0xd4u, 0xd5u, 0xf7u)) // these are updated/used by IRQ
|
||||
}
|
||||
ZeropageType.KERNALSAFE -> {
|
||||
free.addAll(0x0au..0x8fu) // BASIC variables
|
||||
free.addAll(listOf(0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
|
||||
free.addAll(arrayOf(0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
|
||||
0xb0u, 0xb1u, 0xb4u, 0xb5u, 0xb6u))
|
||||
}
|
||||
ZeropageType.FLOATSAFE,
|
||||
ZeropageType.BASICSAFE -> {
|
||||
free.addAll(listOf(0x0bu, 0x0cu, 0x0du, 0x0eu, 0x0fu, 0x10u, 0x11u, 0x12u, 0x16u, 0x17u, 0x18u, 0x19u, 0x1au))
|
||||
free.addAll(arrayOf(0x0bu, 0x0cu, 0x0du, 0x0eu, 0x0fu, 0x10u, 0x11u, 0x12u, 0x16u, 0x17u, 0x18u, 0x19u, 0x1au))
|
||||
free.addAll(0x1bu..0x23u)
|
||||
free.addAll(listOf(0x3fu, 0x40u, 0x41u, 0x42u, 0x43u, 0x44u, 0x47u, 0x48u, 0x49u, 0x4au, 0x4bu, 0x4cu, 0x4fu,
|
||||
free.addAll(arrayOf(0x3fu, 0x40u, 0x41u, 0x42u, 0x43u, 0x44u, 0x47u, 0x48u, 0x49u, 0x4au, 0x4bu, 0x4cu, 0x4fu,
|
||||
0x55u, 0x56u, 0x57u, 0x58u,
|
||||
0x74u, 0x75u, 0x78u, 0x80u, 0x83u, 0x87u, 0x88u, 0x89u, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu,
|
||||
0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
|
||||
@ -53,7 +53,7 @@ class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
|
||||
// if(options.zeropage==ZeropageType.BASICSAFE) {
|
||||
// can also clobber the FP locations (unconditionally, because the C128 target doesn't support floating point calculations in prog8 at this time0
|
||||
free.addAll(listOf(0x14u, 0x28u, 0x29u, 0x2au, 0x2bu, 0x2cu,
|
||||
free.addAll(arrayOf(0x14u, 0x28u, 0x29u, 0x2au, 0x2bu, 0x2cu,
|
||||
0x50u, 0x51u, 0x52u, 0x53u, 0x54u, 0x59u, 0x5au, 0x5bu, 0x5cu, 0x5du, 0x5eu, 0x5fu, 0x60u, 0x61u, 0x62u,
|
||||
0x63u, 0x64u, 0x65u, 0x66u, 0x67u, 0x68u,
|
||||
0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu, 0x6fu, 0x71u))
|
||||
|
@ -21,11 +21,11 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
|
||||
if (options.zeropage == ZeropageType.FULL) {
|
||||
free.addAll(0x02u..0xffu)
|
||||
free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1+1u, SCRATCH_W2, SCRATCH_W2+1u))
|
||||
free.removeAll(setOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
||||
free.removeAll(arrayOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1+1u, SCRATCH_W2, SCRATCH_W2+1u))
|
||||
free.removeAll(arrayOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
||||
} else {
|
||||
if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
|
||||
free.addAll(listOf(
|
||||
free.addAll(arrayOf(
|
||||
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||
@ -43,7 +43,7 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
|
||||
if (options.zeropage == ZeropageType.FLOATSAFE) {
|
||||
// remove the zeropage locations used for floating point operations from the free list
|
||||
free.removeAll(listOf(
|
||||
free.removeAll(arrayOf(
|
||||
0x03, 0x04, 0x05, 0x06, 0x10, 0x11, 0x12,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
|
||||
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
||||
@ -56,7 +56,7 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
if(options.zeropage != ZeropageType.DONTUSE) {
|
||||
// add the free Zp addresses
|
||||
// these are valid for the C-64 but allow BASIC to keep running fully *as long as you don't use tape I/O*
|
||||
free.addAll(listOf(0x02, 0x03, 0x04, 0x05, 0x06, 0x0a, 0x0e,
|
||||
free.addAll(arrayOf(0x02, 0x03, 0x04, 0x05, 0x06, 0x0a, 0x0e,
|
||||
0x92, 0x96, 0x9b, 0x9c, 0x9e, 0x9f, 0xa6,
|
||||
0xb0, 0xb1, 0xbe, 0xbf, 0xf9).map{it.toUInt()})
|
||||
} else {
|
||||
|
@ -228,8 +228,8 @@ class AsmGen6502Internal (
|
||||
private var generatedLabelSequenceNumber: Int
|
||||
) {
|
||||
|
||||
internal val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100)
|
||||
internal val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640)
|
||||
internal val optimizedByteMultiplications = arrayOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100)
|
||||
internal val optimizedWordMultiplications = arrayOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640)
|
||||
internal val loopEndLabels = ArrayDeque<String>()
|
||||
private val zeropage = options.compTarget.machine.zeropage
|
||||
private val allocator = VariableAllocator(symbolTable, options, errors)
|
||||
@ -241,7 +241,8 @@ 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, errors)
|
||||
private val ifElseAsmgen = IfElseAsmGen(program, symbolTable, this, assignmentAsmGen, errors)
|
||||
private val ifExpressionAsmgen = IfExpressionAsmGen(this, assignmentAsmGen, errors)
|
||||
|
||||
fun compileToAssembly(): IAssemblyProgram? {
|
||||
|
||||
@ -1370,7 +1371,7 @@ $repeatLabel""")
|
||||
return "${PtLabel.GeneratedLabelPrefix}${generatedLabelSequenceNumber}_$postfix"
|
||||
}
|
||||
|
||||
fun assignConstFloatToPointerAY(number: PtNumber) {
|
||||
internal fun assignConstFloatToPointerAY(number: PtNumber) {
|
||||
val floatConst = allocator.getFloatAsmConst(number.number)
|
||||
out("""
|
||||
pha
|
||||
@ -1383,7 +1384,158 @@ $repeatLabel""")
|
||||
}
|
||||
|
||||
internal fun assignIfExpression(target: AsmAssignTarget, value: PtIfExpression) {
|
||||
ifElseAsmgen.assignIfExpression(target, value)
|
||||
ifExpressionAsmgen.assignIfExpression(target, value)
|
||||
}
|
||||
|
||||
internal fun cmpAwithByteValue(value: PtExpression, useSbc: Boolean) {
|
||||
val compare = if(useSbc) "sec | sbc" else "cmp"
|
||||
fun cmpViaScratch() {
|
||||
if(assignmentAsmGen.directIntoY(value)) {
|
||||
assignExpressionToRegister(value, RegisterOrPair.Y, false)
|
||||
out(" sty P8ZP_SCRATCH_REG")
|
||||
} else {
|
||||
out(" pha")
|
||||
assignExpressionToVariable(value, "P8ZP_SCRATCH_REG", value.type)
|
||||
out(" pla")
|
||||
}
|
||||
out(" $compare P8ZP_SCRATCH_REG")
|
||||
}
|
||||
|
||||
when(value) {
|
||||
is PtArrayIndexer -> {
|
||||
val constIndex = value.index.asConstInteger()
|
||||
if(constIndex!=null) {
|
||||
val offset = program.memsizer.memorySize(value.type, constIndex)
|
||||
if(offset<256) {
|
||||
return out(" ldy #$offset | $compare ${asmVariableName(value.variable)},y")
|
||||
}
|
||||
}
|
||||
cmpViaScratch()
|
||||
}
|
||||
is PtMemoryByte -> {
|
||||
val constAddr = value.address.asConstInteger()
|
||||
if(constAddr!=null) {
|
||||
out(" $compare ${constAddr.toHex()}")
|
||||
} else {
|
||||
cmpViaScratch()
|
||||
}
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
out(" $compare ${asmVariableName(value)}")
|
||||
}
|
||||
is PtNumber -> {
|
||||
if(value.number!=0.0)
|
||||
out(" $compare #${value.number.toInt()}")
|
||||
}
|
||||
else -> {
|
||||
cmpViaScratch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun assignConditionValueToRegisterAndTest(condition: PtExpression) {
|
||||
assignExpressionToRegister(condition, RegisterOrPair.A, false)
|
||||
when(condition) {
|
||||
is PtNumber,
|
||||
is PtBool,
|
||||
is PtIdentifier,
|
||||
is PtIrRegister,
|
||||
is PtArrayIndexer,
|
||||
is PtPrefix,
|
||||
is PtIfExpression,
|
||||
is PtBinaryExpression -> { /* no cmp necessary the lda has been done just prior */ }
|
||||
is PtTypeCast -> {
|
||||
if(!condition.value.type.isByte && !condition.value.type.isWord)
|
||||
out(" cmp #0")
|
||||
}
|
||||
else -> out(" cmp #0")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun translateFloatsEqualsConditionIntoA(left: PtExpression, right: PtExpression) {
|
||||
fun equalf(leftName: String, rightName: String) {
|
||||
out("""
|
||||
lda #<$leftName
|
||||
ldy #>$leftName
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
lda #<$rightName
|
||||
ldy #>$rightName
|
||||
jsr floats.vars_equal_f""")
|
||||
}
|
||||
fun equalf(expr: PtExpression, rightName: String) {
|
||||
assignExpressionToRegister(expr, RegisterOrPair.FAC1, true)
|
||||
out("""
|
||||
lda #<$rightName
|
||||
ldy #>$rightName
|
||||
jsr floats.var_fac1_equal_f""")
|
||||
}
|
||||
if(left is PtIdentifier) {
|
||||
when (right) {
|
||||
is PtIdentifier -> equalf(asmVariableName(left), asmVariableName(right))
|
||||
is PtNumber -> equalf(asmVariableName(left), allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
equalf(asmVariableName(left), subroutineFloatEvalResultVar1)
|
||||
subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (right) {
|
||||
is PtIdentifier -> equalf(left, asmVariableName(right))
|
||||
is PtNumber -> equalf(left, allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
equalf(left, subroutineFloatEvalResultVar1)
|
||||
subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun translateFloatsLessConditionIntoA(left: PtExpression, right: PtExpression, lessOrEquals: Boolean) {
|
||||
fun lessf(leftName: String, rightName: String) {
|
||||
out("""
|
||||
lda #<$rightName
|
||||
ldy #>$rightName
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
lda #<$leftName
|
||||
ldy #>$leftName""")
|
||||
if(lessOrEquals)
|
||||
out("jsr floats.vars_lesseq_f")
|
||||
else
|
||||
out("jsr floats.vars_less_f")
|
||||
}
|
||||
fun lessf(expr: PtExpression, rightName: String) {
|
||||
assignExpressionToRegister(expr, RegisterOrPair.FAC1, true)
|
||||
out(" lda #<$rightName | ldy #>$rightName")
|
||||
if(lessOrEquals)
|
||||
out(" jsr floats.var_fac1_lesseq_f")
|
||||
else
|
||||
out(" jsr floats.var_fac1_less_f")
|
||||
}
|
||||
if(left is PtIdentifier) {
|
||||
when (right) {
|
||||
is PtIdentifier -> lessf(asmVariableName(left), asmVariableName(right))
|
||||
is PtNumber -> lessf(asmVariableName(left), allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
lessf(asmVariableName(left), subroutineFloatEvalResultVar1)
|
||||
subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (right) {
|
||||
is PtIdentifier -> lessf(left, asmVariableName(right))
|
||||
is PtNumber -> lessf(left, allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
lessf(left, subroutineFloatEvalResultVar1)
|
||||
subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,14 +19,14 @@ internal class AssemblyProgram(
|
||||
private val binFile = outputDir.resolve("$name.bin")
|
||||
private val viceMonListFile = outputDir.resolve(C64Target.viceMonListName(name))
|
||||
private val listFile = outputDir.resolve("$name.list")
|
||||
private val targetWithoutBreakpointsForEmulator = setOf(AtariTarget.NAME, Neo6502Target.NAME)
|
||||
private val targetWithoutBreakpointsForEmulator = arrayOf(AtariTarget.NAME, Neo6502Target.NAME)
|
||||
|
||||
override fun assemble(options: CompilationOptions, errors: IErrorReporter): Boolean {
|
||||
|
||||
val assemblerCommand: List<String>
|
||||
|
||||
when (compTarget.name) {
|
||||
in setOf("c64", "c128", "cx16", "pet32") -> {
|
||||
in arrayOf("c64", "c128", "cx16", "pet32") -> {
|
||||
// CBM machines .prg generation.
|
||||
|
||||
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps (default = do this silently)
|
||||
|
@ -1125,7 +1125,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
else -> throw AssemblyError("invalid reg")
|
||||
}
|
||||
} else {
|
||||
if(arg is PtArrayIndexer && resultRegister in setOf(null, RegisterOrPair.A, RegisterOrPair.Y, RegisterOrPair.X)) {
|
||||
if(arg is PtArrayIndexer && resultRegister in arrayOf(null, RegisterOrPair.A, RegisterOrPair.Y, RegisterOrPair.X)) {
|
||||
// just read the msb byte out of the word array
|
||||
if(arg.splitWords) {
|
||||
val arrayVar = asmgen.asmVariableName(arg.variable)+"_msb"
|
||||
@ -1225,7 +1225,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
else -> throw AssemblyError("invalid reg")
|
||||
}
|
||||
} else {
|
||||
if(arg is PtArrayIndexer && resultRegister in setOf(null, RegisterOrPair.A, RegisterOrPair.Y, RegisterOrPair.X)) {
|
||||
if(arg is PtArrayIndexer && resultRegister in arrayOf(null, RegisterOrPair.A, RegisterOrPair.Y, RegisterOrPair.X)) {
|
||||
// just read the lsb byte out of the word array
|
||||
val arrayVar = if(arg.splitWords) asmgen.asmVariableName(arg.variable)+"_lsb" else asmgen.asmVariableName(arg.variable)
|
||||
when(resultRegister) {
|
||||
|
@ -11,7 +11,6 @@ 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 errors: IErrorReporter) {
|
||||
|
||||
@ -48,7 +47,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
throw AssemblyError("not prefix in ifelse should have been replaced by swapped if-else blocks")
|
||||
else {
|
||||
checkNotExtsubReturnsStatusReg(prefixCond.value)
|
||||
assignConditionValueToRegisterAndTest(prefixCond.value)
|
||||
asmgen.assignConditionValueToRegisterAndTest(prefixCond.value)
|
||||
return if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
@ -59,84 +58,6 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
throw AssemblyError("weird non-boolean condition node type ${stmt.condition} at ${stmt.condition.position}")
|
||||
}
|
||||
|
||||
internal fun assignIfExpression(target: AsmAssignTarget, expr: PtIfExpression) {
|
||||
// this is NOT for the if-else STATEMENT, but this is code for the IF-EXPRESSION.
|
||||
require(target.datatype==expr.type)
|
||||
val falseLabel = asmgen.makeLabel("ifexpr_false")
|
||||
val endLabel = asmgen.makeLabel("ifexpr_end")
|
||||
evalIfExpressionConditonAndBranchWhenFalse(expr.condition, falseLabel)
|
||||
when {
|
||||
expr.type.isByteOrBool -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.A, false)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A, false)
|
||||
asmgen.out(endLabel)
|
||||
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, false, false)
|
||||
}
|
||||
expr.type.isWord -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY, false)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.AY, false)
|
||||
asmgen.out(endLabel)
|
||||
assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
}
|
||||
expr.type.isFloat -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.FAC1, true)
|
||||
asmgen.out(endLabel)
|
||||
asmgen.assignRegister(RegisterOrPair.FAC1, target)
|
||||
}
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun evalIfExpressionConditonAndBranchWhenFalse(condition: PtExpression, falseLabel: String) {
|
||||
if (condition is PtBinaryExpression) {
|
||||
val rightDt = condition.right.type
|
||||
return when {
|
||||
rightDt.isByteOrBool -> translateIfExpressionByteConditionBranch(condition, falseLabel)
|
||||
rightDt.isWord -> translateIfExpressionWordConditionBranch(condition, falseLabel)
|
||||
rightDt.isFloat -> translateIfExpressionFloatConditionBranch(condition, falseLabel)
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
}
|
||||
else if(condition is PtPrefix && condition.operator=="not") {
|
||||
throw AssemblyError("not prefix in ifexpression should have been replaced by swapped values")
|
||||
} else {
|
||||
// 'simple' condition, check if it is a byte bittest
|
||||
val bittest = condition as? PtBuiltinFunctionCall
|
||||
if(bittest!=null && bittest.name.startsWith("prog8_ifelse_bittest_")) {
|
||||
val variable = bittest.args[0] as PtIdentifier
|
||||
val bitnumber = (bittest.args[1] as PtNumber).number.toInt()
|
||||
val testForBitSet = bittest.name.endsWith("_set")
|
||||
when (bitnumber) {
|
||||
7 -> {
|
||||
// test via bit + N flag
|
||||
asmgen.out(" bit ${variable.name}")
|
||||
if(testForBitSet) asmgen.out(" bpl $falseLabel")
|
||||
else asmgen.out(" bmi $falseLabel")
|
||||
return
|
||||
}
|
||||
6 -> {
|
||||
// test via bit + V flag
|
||||
asmgen.out(" bit ${variable.name}")
|
||||
if(testForBitSet) asmgen.out(" bvc $falseLabel")
|
||||
else asmgen.out(" bvs $falseLabel")
|
||||
return
|
||||
}
|
||||
else -> throw AssemblyError("prog8_ifelse_bittest can only work on bits 7 and 6")
|
||||
}
|
||||
}
|
||||
|
||||
// the condition is "simple" enough to just assign its 0/1 value to a register and branch on that
|
||||
assignConditionValueToRegisterAndTest(condition)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNotExtsubReturnsStatusReg(condition: PtExpression) {
|
||||
val fcall = condition as? PtFunctionCall
|
||||
@ -148,25 +69,6 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignConditionValueToRegisterAndTest(condition: PtExpression) {
|
||||
asmgen.assignExpressionToRegister(condition, RegisterOrPair.A, false)
|
||||
when(condition) {
|
||||
is PtNumber,
|
||||
is PtBool,
|
||||
is PtIdentifier,
|
||||
is PtIrRegister,
|
||||
is PtArrayIndexer,
|
||||
is PtPrefix,
|
||||
is PtIfExpression,
|
||||
is PtBinaryExpression -> { /* no cmp necessary the lda has been done just prior */ }
|
||||
is PtTypeCast -> {
|
||||
if(!condition.value.type.isByte && !condition.value.type.isWord)
|
||||
asmgen.out(" cmp #0")
|
||||
}
|
||||
else -> asmgen.out(" cmp #0")
|
||||
}
|
||||
}
|
||||
|
||||
private fun fallbackTranslateForSimpleCondition(ifElse: PtIfElse) {
|
||||
val bittest = ifElse.condition as? PtBuiltinFunctionCall
|
||||
val jumpAfterIf = ifElse.ifScope.children.singleOrNull() as? PtJump
|
||||
@ -241,7 +143,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
// the condition is "simple" enough to just assign its 0/1 value to a register and branch on that
|
||||
assignConditionValueToRegisterAndTest(ifElse.condition)
|
||||
asmgen.assignConditionValueToRegisterAndTest(ifElse.condition)
|
||||
if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, ifElse.elseScope)
|
||||
else
|
||||
@ -293,7 +195,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
"==" -> {
|
||||
// if X==value
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
|
||||
cmpAwithByteValue(condition.right, false)
|
||||
asmgen.cmpAwithByteValue(condition.right, false)
|
||||
return if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
@ -302,7 +204,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
"!=" -> {
|
||||
// if X!=value
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
|
||||
cmpAwithByteValue(condition.right, false)
|
||||
asmgen.cmpAwithByteValue(condition.right, false)
|
||||
return if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
@ -312,7 +214,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
"<=" -> {
|
||||
// X<=Y -> Y>=X (reverse of >=)
|
||||
asmgen.assignExpressionToRegister(condition.right, RegisterOrPair.A, signed)
|
||||
cmpAwithByteValue(condition.left, false)
|
||||
asmgen.cmpAwithByteValue(condition.left, false)
|
||||
return if(signed) {
|
||||
if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bpl", "bmi", jumpAfterIf, stmt.elseScope)
|
||||
@ -328,7 +230,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
">" -> translateByteGreater(stmt, signed, jumpAfterIf)
|
||||
">=" -> {
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
|
||||
cmpAwithByteValue(condition.right, false)
|
||||
asmgen.cmpAwithByteValue(condition.right, false)
|
||||
return if(signed) {
|
||||
if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bpl", "bmi", jumpAfterIf, stmt.elseScope)
|
||||
@ -350,7 +252,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
translateIfElseBodies("beq", stmt)
|
||||
} else {
|
||||
errors.info("SLOW FALLBACK FOR 'IF' CODEGEN - ask for support", stmt.position) // should not occur ;-)
|
||||
assignConditionValueToRegisterAndTest(stmt.condition)
|
||||
asmgen.assignConditionValueToRegisterAndTest(stmt.condition)
|
||||
if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
@ -361,234 +263,10 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateIfExpressionByteConditionBranch(condition: PtBinaryExpression, falseLabel: String) {
|
||||
val signed = condition.left.type.isSigned
|
||||
val constValue = condition.right.asConstInteger()
|
||||
if(constValue==0) {
|
||||
return translateIfCompareWithZeroByteBranch(condition, signed, falseLabel)
|
||||
}
|
||||
|
||||
when(condition.operator) {
|
||||
"==" -> {
|
||||
// if X==value
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
|
||||
cmpAwithByteValue(condition.right, false)
|
||||
asmgen.out(" bne $falseLabel")
|
||||
}
|
||||
"!=" -> {
|
||||
// if X!=value
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
|
||||
cmpAwithByteValue(condition.right, false)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
in LogicalOperators -> {
|
||||
val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.BOOL), condition.definingISub(), condition.position, register=RegisterOrPair.A)
|
||||
if (assignmentAsmGen.optimizedLogicalExpr(condition, regAtarget)) {
|
||||
asmgen.out(" beq $falseLabel")
|
||||
} else {
|
||||
errors.warn("SLOW FALLBACK FOR 'IFEXPR' CODEGEN - ask for support", condition.position) // should not occur ;-)
|
||||
assignConditionValueToRegisterAndTest(condition)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does
|
||||
// TODO: special cases for <, <=, >, >= above.
|
||||
assignConditionValueToRegisterAndTest(condition)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateIfExpressionWordConditionBranch(condition: PtBinaryExpression, falseLabel: String) {
|
||||
// TODO can we reuse this whole thing from IfElse ?
|
||||
val constValue = condition.right.asConstInteger()
|
||||
if(constValue!=null) {
|
||||
if (constValue == 0) {
|
||||
when (condition.operator) {
|
||||
"==" -> return translateWordExprIsZero(condition.left, falseLabel)
|
||||
"!=" -> return translateWordExprIsNotZero(condition.left, falseLabel)
|
||||
}
|
||||
}
|
||||
if (constValue != 0) {
|
||||
when (condition.operator) {
|
||||
"==" -> return translateWordExprEqualsNumber(condition.left, constValue, falseLabel)
|
||||
"!=" -> return translateWordExprNotEqualsNumber(condition.left, constValue, falseLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
val variable = condition.right as? PtIdentifier
|
||||
if(variable!=null) {
|
||||
when (condition.operator) {
|
||||
"==" -> return translateWordExprEqualsVariable(condition.left, variable, falseLabel)
|
||||
"!=" -> return translateWordExprNotEqualsVariable(condition.left, variable, falseLabel)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does
|
||||
assignConditionValueToRegisterAndTest(condition)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
|
||||
private fun translateWordExprNotEqualsVariable(expr: PtExpression, variable: PtIdentifier, falseLabel: String) {
|
||||
// if w!=variable
|
||||
// TODO reuse code from ifElse?
|
||||
val varRight = asmgen.asmVariableName(variable)
|
||||
if(expr is PtIdentifier) {
|
||||
val varLeft = asmgen.asmVariableName(expr)
|
||||
asmgen.out("""
|
||||
lda $varLeft
|
||||
cmp $varRight
|
||||
bne +
|
||||
lda $varLeft+1
|
||||
cmp $varRight+1
|
||||
beq $falseLabel
|
||||
+""")
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
|
||||
asmgen.out("""
|
||||
cmp $varRight
|
||||
bne +
|
||||
cpy $varRight+1
|
||||
beq $falseLabel
|
||||
+""")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateWordExprEqualsVariable(expr: PtExpression, variable: PtIdentifier, falseLabel: String) {
|
||||
// if w==variable
|
||||
// TODO reuse code from ifElse?
|
||||
val varRight = asmgen.asmVariableName(variable)
|
||||
if(expr is PtIdentifier) {
|
||||
val varLeft = asmgen.asmVariableName(expr)
|
||||
asmgen.out("""
|
||||
lda $varLeft
|
||||
cmp $varRight
|
||||
bne $falseLabel
|
||||
lda $varLeft+1
|
||||
cmp $varRight+1
|
||||
bne $falseLabel""")
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
|
||||
asmgen.out("""
|
||||
cmp $varRight
|
||||
bne $falseLabel
|
||||
cpy $varRight+1
|
||||
bne $falseLabel""")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateWordExprNotEqualsNumber(expr: PtExpression, number: Int, falseLabel: String) {
|
||||
// if w!=number
|
||||
// TODO reuse code from ifElse?
|
||||
if(expr is PtIdentifier) {
|
||||
val varname = asmgen.asmVariableName(expr)
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
cmp #<$number
|
||||
bne +
|
||||
lda $varname+1
|
||||
cmp #>$number
|
||||
beq $falseLabel
|
||||
+""")
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
|
||||
asmgen.out("""
|
||||
cmp #<$number
|
||||
bne +
|
||||
cpy #>$number
|
||||
beq $falseLabel
|
||||
+""")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateWordExprEqualsNumber(expr: PtExpression, number: Int, falseLabel: String) {
|
||||
// if w==number
|
||||
// TODO reuse code from ifElse?
|
||||
if(expr is PtIdentifier) {
|
||||
val varname = asmgen.asmVariableName(expr)
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
cmp #<$number
|
||||
bne $falseLabel
|
||||
lda $varname+1
|
||||
cmp #>$number
|
||||
bne $falseLabel""")
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
|
||||
asmgen.out( """
|
||||
cmp #<$number
|
||||
bne $falseLabel
|
||||
cpy #>$number
|
||||
bne $falseLabel""")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateWordExprIsNotZero(expr: PtExpression, falseLabel: String) {
|
||||
// if w!=0
|
||||
// TODO reuse code from ifElse?
|
||||
if(expr is PtIdentifier) {
|
||||
val varname = asmgen.asmVariableName(expr)
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
ora $varname+1
|
||||
beq $falseLabel""")
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
|
||||
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | beq $falseLabel")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateWordExprIsZero(expr: PtExpression, falseLabel: String) {
|
||||
// if w==0
|
||||
// TODO reuse code from ifElse?
|
||||
if(expr is PtIdentifier) {
|
||||
val varname = asmgen.asmVariableName(expr)
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
ora $varname+1
|
||||
bne $falseLabel""")
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
|
||||
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | bne $falseLabel")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateIfCompareWithZeroByteBranch(condition: PtBinaryExpression, signed: Boolean, falseLabel: String) {
|
||||
// optimized code for byte comparisons with 0
|
||||
assignConditionValueToRegisterAndTest(condition.left)
|
||||
when (condition.operator) {
|
||||
"==" -> asmgen.out(" bne $falseLabel")
|
||||
"!=" -> asmgen.out(" beq $falseLabel")
|
||||
">" -> {
|
||||
if(signed) asmgen.out(" bmi $falseLabel | beq $falseLabel")
|
||||
else asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
">=" -> {
|
||||
if(signed) asmgen.out(" bmi $falseLabel")
|
||||
else { /* always true for unsigned */ }
|
||||
}
|
||||
"<" -> {
|
||||
if(signed) asmgen.out(" bpl $falseLabel")
|
||||
else asmgen.jmp(falseLabel)
|
||||
}
|
||||
"<=" -> {
|
||||
if(signed) {
|
||||
// inverted '>'
|
||||
asmgen.out("""
|
||||
beq +
|
||||
bpl $falseLabel
|
||||
+""")
|
||||
} else asmgen.out(" bne $falseLabel")
|
||||
}
|
||||
else -> throw AssemblyError("expected comparison operator")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateIfCompareWithZeroByte(stmt: PtIfElse, signed: Boolean, jumpAfterIf: PtJump?) {
|
||||
// optimized code for byte comparisons with 0
|
||||
val condition = stmt.condition as PtBinaryExpression
|
||||
assignConditionValueToRegisterAndTest(condition.left)
|
||||
asmgen.assignConditionValueToRegisterAndTest(condition.left)
|
||||
when (condition.operator) {
|
||||
"==" -> {
|
||||
return if(jumpAfterIf!=null)
|
||||
@ -718,56 +396,10 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun cmpAwithByteValue(value: PtExpression, useSbc: Boolean) {
|
||||
val compare = if(useSbc) "sec | sbc" else "cmp"
|
||||
fun cmpViaScratch() {
|
||||
if(assignmentAsmGen.directIntoY(value)) {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y, false)
|
||||
asmgen.out(" sty P8ZP_SCRATCH_REG")
|
||||
} else {
|
||||
asmgen.out(" pha")
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_REG", value.type)
|
||||
asmgen.out(" pla")
|
||||
}
|
||||
asmgen.out(" $compare P8ZP_SCRATCH_REG")
|
||||
}
|
||||
|
||||
when(value) {
|
||||
is PtArrayIndexer -> {
|
||||
val constIndex = value.index.asConstInteger()
|
||||
if(constIndex!=null) {
|
||||
val offset = program.memsizer.memorySize(value.type, constIndex)
|
||||
if(offset<256) {
|
||||
return asmgen.out(" ldy #$offset | $compare ${asmgen.asmVariableName(value.variable)},y")
|
||||
}
|
||||
}
|
||||
cmpViaScratch()
|
||||
}
|
||||
is PtMemoryByte -> {
|
||||
val constAddr = value.address.asConstInteger()
|
||||
if(constAddr!=null) {
|
||||
asmgen.out(" $compare ${constAddr.toHex()}")
|
||||
} else {
|
||||
cmpViaScratch()
|
||||
}
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
asmgen.out(" $compare ${asmgen.asmVariableName(value)}")
|
||||
}
|
||||
is PtNumber -> {
|
||||
if(value.number!=0.0)
|
||||
asmgen.out(" $compare #${value.number.toInt()}")
|
||||
}
|
||||
else -> {
|
||||
cmpViaScratch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateByteLess(stmt: PtIfElse, signed: Boolean, jumpAfterIf: PtJump?) {
|
||||
val condition = stmt.condition as PtBinaryExpression
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
|
||||
cmpAwithByteValue(condition.right, false)
|
||||
asmgen.cmpAwithByteValue(condition.right, false)
|
||||
if(signed) {
|
||||
if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bmi", "bpl", jumpAfterIf, stmt.elseScope)
|
||||
@ -786,14 +418,14 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
if(signed) {
|
||||
// X>Y --> Y<X
|
||||
asmgen.assignExpressionToRegister(condition.right, RegisterOrPair.A, true)
|
||||
cmpAwithByteValue(condition.left, true)
|
||||
asmgen.cmpAwithByteValue(condition.left, true)
|
||||
if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("bmi", "bpl", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies("bpl", stmt)
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, false)
|
||||
cmpAwithByteValue(condition.right, false)
|
||||
asmgen.cmpAwithByteValue(condition.right, false)
|
||||
if(jumpAfterIf!=null) {
|
||||
val (asmLabel, indirect) = asmgen.getJumpTarget(jumpAfterIf)
|
||||
if(indirect) {
|
||||
@ -2005,42 +1637,42 @@ _jump jmp ($asmLabel)
|
||||
|
||||
when(condition.operator) {
|
||||
"==" -> {
|
||||
translateFloatsEqualsConditionIntoA(condition.left, condition.right)
|
||||
asmgen.translateFloatsEqualsConditionIntoA(condition.left, condition.right)
|
||||
return if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies("beq", stmt)
|
||||
}
|
||||
"!=" -> {
|
||||
translateFloatsEqualsConditionIntoA(condition.left, condition.right)
|
||||
asmgen.translateFloatsEqualsConditionIntoA(condition.left, condition.right)
|
||||
return if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies("bne", stmt)
|
||||
}
|
||||
"<" -> {
|
||||
translateFloatsLessConditionIntoA(condition.left, condition.right, false)
|
||||
asmgen.translateFloatsLessConditionIntoA(condition.left, condition.right, false)
|
||||
return if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies("beq", stmt)
|
||||
}
|
||||
"<=" -> {
|
||||
translateFloatsLessConditionIntoA(condition.left, condition.right, true)
|
||||
asmgen.translateFloatsLessConditionIntoA(condition.left, condition.right, true)
|
||||
return if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies("beq", stmt)
|
||||
}
|
||||
">" -> {
|
||||
translateFloatsLessConditionIntoA(condition.left, condition.right, true)
|
||||
asmgen.translateFloatsLessConditionIntoA(condition.left, condition.right, true)
|
||||
return if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
translateIfElseBodies("bne", stmt)
|
||||
}
|
||||
">=" -> {
|
||||
translateFloatsLessConditionIntoA(condition.left, condition.right, false)
|
||||
asmgen.translateFloatsLessConditionIntoA(condition.left, condition.right, false)
|
||||
return if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope)
|
||||
else
|
||||
@ -2049,136 +1681,4 @@ _jump jmp ($asmLabel)
|
||||
else -> throw AssemblyError("expected comparison operator")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateIfExpressionFloatConditionBranch(condition: PtBinaryExpression, elseLabel: String) {
|
||||
val constValue = (condition.right as? PtNumber)?.number
|
||||
if(constValue==0.0) {
|
||||
if (condition.operator == "==") {
|
||||
// if FL==0.0
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.FAC1, true)
|
||||
asmgen.out(" jsr floats.SIGN | cmp #0 | bne $elseLabel")
|
||||
return
|
||||
} else if(condition.operator=="!=") {
|
||||
// if FL!=0.0
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.FAC1, true)
|
||||
asmgen.out(" jsr floats.SIGN | cmp #0 | beq $elseLabel")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
when(condition.operator) {
|
||||
"==" -> {
|
||||
translateFloatsEqualsConditionIntoA(condition.left, condition.right)
|
||||
asmgen.out(" beq $elseLabel")
|
||||
}
|
||||
"!=" -> {
|
||||
translateFloatsEqualsConditionIntoA(condition.left, condition.right)
|
||||
asmgen.out(" bne $elseLabel")
|
||||
}
|
||||
"<" -> {
|
||||
translateFloatsLessConditionIntoA(condition.left, condition.right, false)
|
||||
asmgen.out(" beq $elseLabel")
|
||||
}
|
||||
"<=" -> {
|
||||
translateFloatsLessConditionIntoA(condition.left, condition.right, true)
|
||||
asmgen.out(" beq $elseLabel")
|
||||
}
|
||||
">" -> {
|
||||
translateFloatsLessConditionIntoA(condition.left, condition.right, true)
|
||||
asmgen.out(" bne $elseLabel")
|
||||
}
|
||||
">=" -> {
|
||||
translateFloatsLessConditionIntoA(condition.left, condition.right, false)
|
||||
asmgen.out(" bne $elseLabel")
|
||||
}
|
||||
else -> throw AssemblyError("expected comparison operator")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateFloatsEqualsConditionIntoA(left: PtExpression, right: PtExpression) {
|
||||
fun equalf(leftName: String, rightName: String) {
|
||||
asmgen.out("""
|
||||
lda #<$leftName
|
||||
ldy #>$leftName
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
lda #<$rightName
|
||||
ldy #>$rightName
|
||||
jsr floats.vars_equal_f""")
|
||||
}
|
||||
fun equalf(expr: PtExpression, rightName: String) {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.FAC1, true)
|
||||
asmgen.out("""
|
||||
lda #<$rightName
|
||||
ldy #>$rightName
|
||||
jsr floats.var_fac1_equal_f""")
|
||||
}
|
||||
if(left is PtIdentifier) {
|
||||
when (right) {
|
||||
is PtIdentifier -> equalf(asmgen.asmVariableName(left), asmgen.asmVariableName(right))
|
||||
is PtNumber -> equalf(asmgen.asmVariableName(left), allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
equalf(asmgen.asmVariableName(left), subroutineFloatEvalResultVar1)
|
||||
asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (right) {
|
||||
is PtIdentifier -> equalf(left, asmgen.asmVariableName(right))
|
||||
is PtNumber -> equalf(left, allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
equalf(left, subroutineFloatEvalResultVar1)
|
||||
asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateFloatsLessConditionIntoA(left: PtExpression, right: PtExpression, lessOrEquals: Boolean) {
|
||||
fun lessf(leftName: String, rightName: String) {
|
||||
asmgen.out("""
|
||||
lda #<$rightName
|
||||
ldy #>$rightName
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
lda #<$leftName
|
||||
ldy #>$leftName""")
|
||||
if(lessOrEquals)
|
||||
asmgen.out("jsr floats.vars_lesseq_f")
|
||||
else
|
||||
asmgen.out("jsr floats.vars_less_f")
|
||||
}
|
||||
fun lessf(expr: PtExpression, rightName: String) {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.FAC1, true)
|
||||
asmgen.out(" lda #<$rightName | ldy #>$rightName")
|
||||
if(lessOrEquals)
|
||||
asmgen.out(" jsr floats.var_fac1_lesseq_f")
|
||||
else
|
||||
asmgen.out(" jsr floats.var_fac1_less_f")
|
||||
}
|
||||
if(left is PtIdentifier) {
|
||||
when (right) {
|
||||
is PtIdentifier -> lessf(asmgen.asmVariableName(left), asmgen.asmVariableName(right))
|
||||
is PtNumber -> lessf(asmgen.asmVariableName(left), allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
lessf(asmgen.asmVariableName(left), subroutineFloatEvalResultVar1)
|
||||
asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (right) {
|
||||
is PtIdentifier -> lessf(left, asmgen.asmVariableName(right))
|
||||
is PtNumber -> lessf(left, allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
lessf(left, subroutineFloatEvalResultVar1)
|
||||
asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
370
codeGenCpu6502/src/prog8/codegen/cpu6502/IfExpressionAsmGen.kt
Normal file
370
codeGenCpu6502/src/prog8/codegen/cpu6502/IfExpressionAsmGen.kt
Normal file
@ -0,0 +1,370 @@
|
||||
package prog8.codegen.cpu6502
|
||||
|
||||
import prog8.code.ast.PtBinaryExpression
|
||||
import prog8.code.ast.PtBuiltinFunctionCall
|
||||
import prog8.code.ast.PtExpression
|
||||
import prog8.code.ast.PtIdentifier
|
||||
import prog8.code.ast.PtIfExpression
|
||||
import prog8.code.ast.PtNumber
|
||||
import prog8.code.ast.PtPrefix
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.CpuRegister
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.code.core.LogicalOperators
|
||||
import prog8.code.core.RegisterOrPair
|
||||
import prog8.codegen.cpu6502.assignment.AsmAssignTarget
|
||||
import prog8.codegen.cpu6502.assignment.AssignmentAsmGen
|
||||
import prog8.codegen.cpu6502.assignment.TargetStorageKind
|
||||
|
||||
internal class IfExpressionAsmGen(private val asmgen: AsmGen6502Internal, private val assignmentAsmGen: AssignmentAsmGen, private val errors: IErrorReporter) {
|
||||
|
||||
internal fun assignIfExpression(target: AsmAssignTarget, expr: PtIfExpression) {
|
||||
require(target.datatype==expr.type)
|
||||
val falseLabel = asmgen.makeLabel("ifexpr_false")
|
||||
val endLabel = asmgen.makeLabel("ifexpr_end")
|
||||
evalIfExpressionConditonAndBranchWhenFalse(expr.condition, falseLabel)
|
||||
when {
|
||||
expr.type.isByteOrBool -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.A, false)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A, false)
|
||||
asmgen.out(endLabel)
|
||||
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, false, false)
|
||||
}
|
||||
expr.type.isWord -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY, false)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.AY, false)
|
||||
asmgen.out(endLabel)
|
||||
assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
}
|
||||
expr.type.isFloat -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.FAC1, true)
|
||||
asmgen.out(endLabel)
|
||||
asmgen.assignRegister(RegisterOrPair.FAC1, target)
|
||||
}
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun evalIfExpressionConditonAndBranchWhenFalse(condition: PtExpression, falseLabel: String) {
|
||||
if (condition is PtBinaryExpression) {
|
||||
val rightDt = condition.right.type
|
||||
return when {
|
||||
rightDt.isByteOrBool -> translateIfExpressionByteConditionBranch(condition, falseLabel)
|
||||
rightDt.isWord -> translateIfExpressionWordConditionBranch(condition, falseLabel)
|
||||
rightDt.isFloat -> translateIfExpressionFloatConditionBranch(condition, falseLabel)
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
}
|
||||
else if(condition is PtPrefix && condition.operator=="not") {
|
||||
throw AssemblyError("not prefix in ifexpression should have been replaced by swapped values")
|
||||
} else {
|
||||
// 'simple' condition, check if it is a byte bittest
|
||||
val bittest = condition as? PtBuiltinFunctionCall
|
||||
if(bittest!=null && bittest.name.startsWith("prog8_ifelse_bittest_")) {
|
||||
val variable = bittest.args[0] as PtIdentifier
|
||||
val bitnumber = (bittest.args[1] as PtNumber).number.toInt()
|
||||
val testForBitSet = bittest.name.endsWith("_set")
|
||||
when (bitnumber) {
|
||||
7 -> {
|
||||
// test via bit + N flag
|
||||
asmgen.out(" bit ${variable.name}")
|
||||
if(testForBitSet) asmgen.out(" bpl $falseLabel")
|
||||
else asmgen.out(" bmi $falseLabel")
|
||||
return
|
||||
}
|
||||
6 -> {
|
||||
// test via bit + V flag
|
||||
asmgen.out(" bit ${variable.name}")
|
||||
if(testForBitSet) asmgen.out(" bvc $falseLabel")
|
||||
else asmgen.out(" bvs $falseLabel")
|
||||
return
|
||||
}
|
||||
else -> throw AssemblyError("prog8_ifelse_bittest can only work on bits 7 and 6")
|
||||
}
|
||||
}
|
||||
|
||||
// the condition is "simple" enough to just assign its 0/1 value to a register and branch on that
|
||||
asmgen.assignConditionValueToRegisterAndTest(condition)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateIfExpressionByteConditionBranch(condition: PtBinaryExpression, falseLabel: String) {
|
||||
val signed = condition.left.type.isSigned
|
||||
val constValue = condition.right.asConstInteger()
|
||||
if(constValue==0) {
|
||||
return translateIfCompareWithZeroByteBranch(condition, signed, falseLabel)
|
||||
}
|
||||
|
||||
when(condition.operator) {
|
||||
"==" -> {
|
||||
// if X==value
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
|
||||
asmgen.cmpAwithByteValue(condition.right, false)
|
||||
asmgen.out(" bne $falseLabel")
|
||||
}
|
||||
"!=" -> {
|
||||
// if X!=value
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
|
||||
asmgen.cmpAwithByteValue(condition.right, false)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
in LogicalOperators -> {
|
||||
val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.BOOL), condition.definingISub(), condition.position, register=RegisterOrPair.A)
|
||||
if (assignmentAsmGen.optimizedLogicalExpr(condition, regAtarget)) {
|
||||
asmgen.out(" beq $falseLabel")
|
||||
} else {
|
||||
errors.warn("SLOW FALLBACK FOR 'IFEXPR' CODEGEN - ask for support", condition.position) // should not occur ;-)
|
||||
asmgen.assignConditionValueToRegisterAndTest(condition)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does
|
||||
// TODO: special cases for <, <=, >, >= above.
|
||||
asmgen.assignConditionValueToRegisterAndTest(condition)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateIfExpressionWordConditionBranch(condition: PtBinaryExpression, falseLabel: String) {
|
||||
// TODO can we reuse this whole thing from IfElse ?
|
||||
val constValue = condition.right.asConstInteger()
|
||||
if(constValue!=null) {
|
||||
if (constValue == 0) {
|
||||
when (condition.operator) {
|
||||
"==" -> return translateWordExprIsZero(condition.left, falseLabel)
|
||||
"!=" -> return translateWordExprIsNotZero(condition.left, falseLabel)
|
||||
}
|
||||
}
|
||||
if (constValue != 0) {
|
||||
when (condition.operator) {
|
||||
"==" -> return translateWordExprEqualsNumber(condition.left, constValue, falseLabel)
|
||||
"!=" -> return translateWordExprNotEqualsNumber(condition.left, constValue, falseLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
val variable = condition.right as? PtIdentifier
|
||||
if(variable!=null) {
|
||||
when (condition.operator) {
|
||||
"==" -> return translateWordExprEqualsVariable(condition.left, variable, falseLabel)
|
||||
"!=" -> return translateWordExprNotEqualsVariable(condition.left, variable, falseLabel)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does
|
||||
asmgen.assignConditionValueToRegisterAndTest(condition)
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
|
||||
private fun translateIfExpressionFloatConditionBranch(condition: PtBinaryExpression, elseLabel: String) {
|
||||
val constValue = (condition.right as? PtNumber)?.number
|
||||
if(constValue==0.0) {
|
||||
if (condition.operator == "==") {
|
||||
// if FL==0.0
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.FAC1, true)
|
||||
asmgen.out(" jsr floats.SIGN | cmp #0 | bne $elseLabel")
|
||||
return
|
||||
} else if(condition.operator=="!=") {
|
||||
// if FL!=0.0
|
||||
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.FAC1, true)
|
||||
asmgen.out(" jsr floats.SIGN | cmp #0 | beq $elseLabel")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
when(condition.operator) {
|
||||
"==" -> {
|
||||
asmgen.translateFloatsEqualsConditionIntoA(condition.left, condition.right)
|
||||
asmgen.out(" beq $elseLabel")
|
||||
}
|
||||
"!=" -> {
|
||||
asmgen.translateFloatsEqualsConditionIntoA(condition.left, condition.right)
|
||||
asmgen.out(" bne $elseLabel")
|
||||
}
|
||||
"<" -> {
|
||||
asmgen.translateFloatsLessConditionIntoA(condition.left, condition.right, false)
|
||||
asmgen.out(" beq $elseLabel")
|
||||
}
|
||||
"<=" -> {
|
||||
asmgen.translateFloatsLessConditionIntoA(condition.left, condition.right, true)
|
||||
asmgen.out(" beq $elseLabel")
|
||||
}
|
||||
">" -> {
|
||||
asmgen.translateFloatsLessConditionIntoA(condition.left, condition.right, true)
|
||||
asmgen.out(" bne $elseLabel")
|
||||
}
|
||||
">=" -> {
|
||||
asmgen.translateFloatsLessConditionIntoA(condition.left, condition.right, false)
|
||||
asmgen.out(" bne $elseLabel")
|
||||
}
|
||||
else -> throw AssemblyError("expected comparison operator")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateWordExprNotEqualsVariable(expr: PtExpression, variable: PtIdentifier, falseLabel: String) {
|
||||
// if w!=variable
|
||||
// TODO reuse code from ifElse?
|
||||
val varRight = asmgen.asmVariableName(variable)
|
||||
if(expr is PtIdentifier) {
|
||||
val varLeft = asmgen.asmVariableName(expr)
|
||||
asmgen.out("""
|
||||
lda $varLeft
|
||||
cmp $varRight
|
||||
bne +
|
||||
lda $varLeft+1
|
||||
cmp $varRight+1
|
||||
beq $falseLabel
|
||||
+""")
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
|
||||
asmgen.out("""
|
||||
cmp $varRight
|
||||
bne +
|
||||
cpy $varRight+1
|
||||
beq $falseLabel
|
||||
+""")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateWordExprEqualsVariable(expr: PtExpression, variable: PtIdentifier, falseLabel: String) {
|
||||
// if w==variable
|
||||
// TODO reuse code from ifElse?
|
||||
val varRight = asmgen.asmVariableName(variable)
|
||||
if(expr is PtIdentifier) {
|
||||
val varLeft = asmgen.asmVariableName(expr)
|
||||
asmgen.out("""
|
||||
lda $varLeft
|
||||
cmp $varRight
|
||||
bne $falseLabel
|
||||
lda $varLeft+1
|
||||
cmp $varRight+1
|
||||
bne $falseLabel""")
|
||||
} else {
|
||||