mirror of
https://github.com/irmen/prog8.git
synced 2024-11-28 10:51:14 +00:00
Codegen: use BIT instruction for memory location bit 7 and 6 tests (use N and V flags)
This commit is contained in:
parent
0ec719e429
commit
c67f877857
@ -82,6 +82,8 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
|
||||
"prog8_lib_arraycopy" to FSignature(false, listOf(FParam("source", ArrayDatatypes), FParam("target", ArrayDatatypes)), null),
|
||||
"prog8_lib_square_byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), DataType.UBYTE),
|
||||
"prog8_lib_square_word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD, DataType.UWORD))), DataType.UWORD),
|
||||
"prog8_ifelse_bittest_set" to FSignature(true, listOf(FParam("variable", ByteDatatypes), FParam("bitnumber", arrayOf(DataType.UBYTE))), DataType.BOOL),
|
||||
"prog8_ifelse_bittest_notset" to FSignature(true, listOf(FParam("variable", ByteDatatypes), FParam("bitnumber", arrayOf(DataType.UBYTE))), DataType.BOOL),
|
||||
"abs" to FSignature(true, listOf(FParam("value", NumericDatatypes)), null),
|
||||
"abs__byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE))), DataType.BYTE),
|
||||
"abs__word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD))), DataType.WORD),
|
||||
|
@ -11,6 +11,7 @@ fun optimizeIntermediateAst(program: PtProgram, options: CompilationOptions, st:
|
||||
return
|
||||
while (errors.noErrors() &&
|
||||
(optimizeCommonSubExpressions(program, errors)
|
||||
+ optimizeBitTest(program, options)
|
||||
+ optimizeAssignTargets(program, st, errors)) > 0
|
||||
) {
|
||||
// keep rolling
|
||||
@ -164,6 +165,51 @@ private fun optimizeAssignTargets(program: PtProgram, st: SymbolTable, errors: I
|
||||
return changes
|
||||
}
|
||||
|
||||
|
||||
private fun optimizeBitTest(program: PtProgram, options: CompilationOptions): Int {
|
||||
if(options.compTarget.machine.cpu == CpuType.VIRTUAL)
|
||||
return 0 // the special bittest optimization is not yet valid for the IR
|
||||
|
||||
var changes = 0
|
||||
var recurse = true
|
||||
walkAst(program) { node: PtNode, depth: Int ->
|
||||
if(node is PtIfElse) {
|
||||
val condition = node.condition as? PtBinaryExpression
|
||||
if(condition!=null && (condition.operator=="==" || condition.operator=="!=")) {
|
||||
if(condition.right.asConstInteger()==0) {
|
||||
val and = condition.left as? PtBinaryExpression
|
||||
if(and != null && and.operator=="&" && and.type == DataType.UBYTE) {
|
||||
val variable = and.left as? PtIdentifier
|
||||
val bitmask = and.right.asConstInteger()
|
||||
if(variable!=null && variable.type in ByteDatatypes && (bitmask==128 || bitmask==64)) {
|
||||
val setOrNot = if(condition.operator=="!=") "set" else "notset"
|
||||
val index = node.parent.children.indexOf(node)
|
||||
val bittestCall = PtBuiltinFunctionCall("prog8_ifelse_bittest_$setOrNot", false, true, DataType.BOOL, node.condition.position)
|
||||
bittestCall.add(variable)
|
||||
if(bitmask==128)
|
||||
bittestCall.add(PtNumber(DataType.UBYTE, 7.0, and.right.position))
|
||||
else
|
||||
bittestCall.add(PtNumber(DataType.UBYTE, 6.0, and.right.position))
|
||||
val ifElse = PtIfElse(node.position)
|
||||
ifElse.add(bittestCall)
|
||||
ifElse.add(node.ifScope)
|
||||
if(node.hasElse())
|
||||
ifElse.add(node.elseScope)
|
||||
node.parent.children[index] = ifElse
|
||||
ifElse.parent = node.parent
|
||||
changes++
|
||||
recurse = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
recurse
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
|
||||
internal fun isSame(identifier: PtIdentifier, type: DataType, returnedRegister: RegisterOrPair): Boolean {
|
||||
if(returnedRegister in Cx16VirtualRegisters) {
|
||||
val regname = returnedRegister.name.lowercase()
|
||||
|
@ -626,6 +626,16 @@ private fun optimizeJsrRtsAndOtherCombinations(linesByFour: Sequence<List<Indexe
|
||||
mods.add(Modification(lines[0].index, true, null))
|
||||
mods.add(Modification(lines[1].index, false, branch))
|
||||
}
|
||||
else if((" bvc " in first || "\tbvc " in first) && sameLabel(first, second, third)) {
|
||||
val branch = second.replace("jmp", "bvs")
|
||||
mods.add(Modification(lines[0].index, true, null))
|
||||
mods.add(Modification(lines[1].index, false, branch))
|
||||
}
|
||||
else if((" bvs " in first || "\tbvs " in first) && sameLabel(first, second, third)) {
|
||||
val branch = second.replace("jmp", "bvc")
|
||||
mods.add(Modification(lines[0].index, true, null))
|
||||
mods.add(Modification(lines[1].index, false, branch))
|
||||
}
|
||||
}
|
||||
}
|
||||
return mods
|
||||
|
@ -65,6 +65,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
"cmp" -> funcCmp(fcall)
|
||||
"callfar" -> funcCallFar(fcall, resultRegister)
|
||||
"call" -> funcCall(fcall)
|
||||
"prog8_ifelse_bittest_set" -> throw AssemblyError("prog8_ifelse_bittest_set() should have been translated as part of an ifElse statement")
|
||||
"prog8_ifelse_bittest_notset" -> throw AssemblyError("prog8_ifelse_bittest_notset() should have been translated as part of an ifElse statement")
|
||||
"prog8_lib_stringcompare" -> funcStringCompare(fcall, resultRegister)
|
||||
"prog8_lib_square_byte" -> funcSquare(fcall, DataType.UBYTE, resultRegister)
|
||||
"prog8_lib_square_word" -> funcSquare(fcall, DataType.UWORD, resultRegister)
|
||||
|
@ -83,9 +83,80 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun fallbackTranslateForSimpleCondition(ifElse: PtIfElse) {
|
||||
val bittest = ifElse.condition as? PtBuiltinFunctionCall
|
||||
val jumpAfterIf = ifElse.ifScope.children.singleOrNull() as? PtJump
|
||||
|
||||
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) {
|
||||
if(jumpAfterIf!=null) {
|
||||
val (asmLabel, indirect) = asmgen.getJumpTarget(jumpAfterIf)
|
||||
if(indirect)
|
||||
throw AssemblyError("cannot BIT to indirect label ${ifElse.position}")
|
||||
if(ifElse.hasElse())
|
||||
throw AssemblyError("didn't expect else part here ${ifElse.position}")
|
||||
else
|
||||
asmgen.out(" bmi $asmLabel")
|
||||
}
|
||||
else
|
||||
translateIfElseBodies("bpl", ifElse)
|
||||
} else {
|
||||
if(jumpAfterIf!=null) {
|
||||
val (asmLabel, indirect) = asmgen.getJumpTarget(jumpAfterIf)
|
||||
if(indirect)
|
||||
throw AssemblyError("cannot BIT to indirect label ${ifElse.position}")
|
||||
if(ifElse.hasElse())
|
||||
throw AssemblyError("didn't expect else part here ${ifElse.position}")
|
||||
else
|
||||
asmgen.out(" bpl $asmLabel")
|
||||
}
|
||||
else
|
||||
translateIfElseBodies("bmi", ifElse)
|
||||
}
|
||||
return
|
||||
}
|
||||
6 -> {
|
||||
// test via bit + V flag
|
||||
asmgen.out(" bit ${variable.name}")
|
||||
if(testForBitSet) {
|
||||
if(jumpAfterIf!=null) {
|
||||
val (asmLabel, indirect) = asmgen.getJumpTarget(jumpAfterIf)
|
||||
if(indirect)
|
||||
throw AssemblyError("cannot BIT to indirect label ${ifElse.position}")
|
||||
if(ifElse.hasElse())
|
||||
throw AssemblyError("didn't expect else part here ${ifElse.position}")
|
||||
else
|
||||
asmgen.out(" bvs $asmLabel")
|
||||
}
|
||||
else
|
||||
translateIfElseBodies("bvc", ifElse)
|
||||
} else {
|
||||
if(jumpAfterIf!=null) {
|
||||
val (asmLabel, indirect) = asmgen.getJumpTarget(jumpAfterIf)
|
||||
if(indirect)
|
||||
throw AssemblyError("cannot BIT to indirect label ${ifElse.position}")
|
||||
if(ifElse.hasElse())
|
||||
throw AssemblyError("didn't expect else part here ${ifElse.position}")
|
||||
else
|
||||
asmgen.out(" bvc $asmLabel")
|
||||
}
|
||||
else
|
||||
translateIfElseBodies("bvs", ifElse)
|
||||
}
|
||||
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(ifElse.condition)
|
||||
val jumpAfterIf = ifElse.ifScope.children.singleOrNull() as? PtJump
|
||||
if(jumpAfterIf!=null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, ifElse.elseScope)
|
||||
else
|
||||
|
@ -38,6 +38,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
"ror" -> funcRolRor(call)
|
||||
"rol2" -> funcRolRor(call)
|
||||
"ror2" -> funcRolRor(call)
|
||||
"prog8_ifelse_bittest_set" -> throw AssemblyError("prog8_ifelse_bittest_set() should have been translated as part of an ifElse statement")
|
||||
"prog8_ifelse_bittest_notset" -> throw AssemblyError("prog8_ifelse_bittest_notset() should have been translated as part of an ifElse statement")
|
||||
"prog8_lib_stringcompare" -> funcStringCompare(call)
|
||||
"prog8_lib_square_byte" -> funcSquare(call, IRDataType.BYTE)
|
||||
"prog8_lib_square_word" -> funcSquare(call, IRDataType.WORD)
|
||||
|
@ -1318,6 +1318,10 @@ class IRCodeGen(
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
|
||||
fun translateSimple(condition: PtExpression, jumpFalseOpcode: Opcode) {
|
||||
|
||||
if(condition is PtBuiltinFunctionCall && condition.name.startsWith("prog8_ifelse_bittest_"))
|
||||
throw AssemblyError("IR codegen doesn't have special instructions for dedicated BIT tests and should just still use normal AND")
|
||||
|
||||
val tr = expressionEval.translateExpression(condition)
|
||||
result += tr.chunks
|
||||
if(ifElse.hasElse()) {
|
||||
|
@ -3,16 +3,6 @@ TODO
|
||||
|
||||
See open issues on github.
|
||||
|
||||
Asm peephole optimizer: while cx16.VERA_AUDIO_CTRL & %01000000 == 0 { } compiles into the following. Replace the bne+bra into a beq. Similar for !=0 I guess?
|
||||
p8l_label_5_whileloop
|
||||
lda cx16.VERA_AUDIO_CTRL
|
||||
and #$40
|
||||
bne p8l_label_6_afterwhile
|
||||
bra p8l_label_5_whileloop
|
||||
p8l_label_6_afterwhile
|
||||
|
||||
Codegen: use BIT instruction for memory location bit 7 and 6 tests (use N and V flags)
|
||||
|
||||
Re-generate the skeletons doc files.
|
||||
|
||||
Improve register load order in subroutine call args assignments:
|
||||
|
172
examples/test.p8
172
examples/test.p8
@ -1,4 +1,3 @@
|
||||
%import buffers
|
||||
%import textio
|
||||
%option no_sysinit
|
||||
%zeropage basicsafe
|
||||
@ -6,75 +5,114 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
signed()
|
||||
unsigned()
|
||||
}
|
||||
ubyte @shared variable
|
||||
|
||||
sub signed() {
|
||||
txt.print("signed\n")
|
||||
byte @shared bvalue = -88
|
||||
word @shared wvalue = -8888
|
||||
variable = 0
|
||||
while variable & %10000000 == 0 {
|
||||
cx16.r0L++
|
||||
variable = 128
|
||||
}
|
||||
txt.chrout('1')
|
||||
while variable & %10000000 != 0 {
|
||||
cx16.r0L++
|
||||
variable = 0
|
||||
}
|
||||
txt.chrout('2')
|
||||
while variable & %01000000 == 0 {
|
||||
cx16.r0L++
|
||||
variable = 64
|
||||
}
|
||||
txt.chrout('3')
|
||||
while variable & %01000000 != 0 {
|
||||
cx16.r0L++
|
||||
variable=0
|
||||
}
|
||||
txt.chrout('4')
|
||||
variable = 255
|
||||
while variable & %10000000 == 0 {
|
||||
}
|
||||
while variable & %01000000 == 0 {
|
||||
}
|
||||
txt.chrout('5')
|
||||
variable = 0
|
||||
while variable & %10000000 != 0 {
|
||||
}
|
||||
while variable & %01000000 != 0 {
|
||||
}
|
||||
txt.chrout('6')
|
||||
txt.chrout('\n')
|
||||
|
||||
txt.print_b(bvalue/2)
|
||||
txt.spc()
|
||||
txt.print_b(bvalue/4)
|
||||
txt.spc()
|
||||
txt.print_b(bvalue/8)
|
||||
txt.nl()
|
||||
variable = 0
|
||||
cx16.r0L++
|
||||
if variable & %10000000 == 0 {
|
||||
txt.print("bit 7 not set\n")
|
||||
}
|
||||
if variable & %10000000 != 0 {
|
||||
txt.print("bit 7 set\n")
|
||||
}
|
||||
if variable & %10000000 == 0 {
|
||||
txt.print("bit 7 not set\n")
|
||||
} else {
|
||||
txt.print("bit 7 set\n")
|
||||
}
|
||||
if variable & %10000000 != 0 {
|
||||
txt.print("bit 7 set\n")
|
||||
} else {
|
||||
txt.print("bit 7 not set\n")
|
||||
}
|
||||
|
||||
bvalue /= 2
|
||||
txt.print_b(bvalue)
|
||||
txt.spc()
|
||||
bvalue /= 8
|
||||
txt.print_b(bvalue)
|
||||
txt.nl()
|
||||
variable = 128
|
||||
cx16.r0L++
|
||||
if variable & %10000000 == 0 {
|
||||
txt.print("bit 7 not set\n")
|
||||
}
|
||||
if variable & %10000000 != 0 {
|
||||
txt.print("bit 7 set\n")
|
||||
}
|
||||
if variable & %10000000 == 0 {
|
||||
txt.print("bit 7 not set\n")
|
||||
} else {
|
||||
txt.print("bit 7 set\n")
|
||||
}
|
||||
if variable & %10000000 != 0 {
|
||||
txt.print("bit 7 set\n")
|
||||
} else {
|
||||
txt.print("bit 7 not set\n")
|
||||
}
|
||||
|
||||
txt.print_w(wvalue/2)
|
||||
txt.spc()
|
||||
txt.print_w(wvalue/4)
|
||||
txt.spc()
|
||||
txt.print_w(wvalue/8)
|
||||
txt.nl()
|
||||
|
||||
wvalue /= 2
|
||||
txt.print_w(wvalue)
|
||||
txt.spc()
|
||||
wvalue /= 8
|
||||
txt.print_w(wvalue)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub unsigned() {
|
||||
txt.print("\nunsigned\n")
|
||||
ubyte @shared bvalue = 88
|
||||
uword @shared wvalue = 8888
|
||||
|
||||
txt.print_ub(bvalue/2)
|
||||
txt.spc()
|
||||
txt.print_ub(bvalue/4)
|
||||
txt.spc()
|
||||
txt.print_ub(bvalue/8)
|
||||
txt.nl()
|
||||
|
||||
bvalue /= 2
|
||||
txt.print_ub(bvalue)
|
||||
txt.spc()
|
||||
bvalue /= 8
|
||||
txt.print_ub(bvalue)
|
||||
txt.nl()
|
||||
|
||||
txt.print_uw(wvalue/2)
|
||||
txt.spc()
|
||||
txt.print_uw(wvalue/4)
|
||||
txt.spc()
|
||||
txt.print_uw(wvalue/8)
|
||||
txt.nl()
|
||||
|
||||
wvalue /= 2
|
||||
txt.print_uw(wvalue)
|
||||
txt.spc()
|
||||
wvalue /= 8
|
||||
txt.print_uw(wvalue)
|
||||
txt.nl()
|
||||
if variable & %01000000 == 0 {
|
||||
txt.print("bit 6 not set\n")
|
||||
}
|
||||
if variable & %01000000 != 0 {
|
||||
txt.print("bit 6 set\n")
|
||||
}
|
||||
if variable & %01000000 == 0 {
|
||||
txt.print("bit 6 not set\n")
|
||||
} else {
|
||||
txt.print("bit 6 set\n")
|
||||
}
|
||||
if variable & %01000000 != 0 {
|
||||
txt.print("bit 6 set\n")
|
||||
} else {
|
||||
txt.print("bit 6 not set\n")
|
||||
}
|
||||
variable = %01000000
|
||||
cx16.r0L++
|
||||
if variable & %01000000 == 0 {
|
||||
txt.print("bit 6 not set\n")
|
||||
}
|
||||
if variable & %01000000 != 0 {
|
||||
txt.print("bit 6 set\n")
|
||||
}
|
||||
if variable & %01000000 == 0 {
|
||||
txt.print("bit 6 not set\n")
|
||||
} else {
|
||||
txt.print("bit 6 set\n")
|
||||
}
|
||||
if variable & %01000000 != 0 {
|
||||
txt.print("bit 6 set\n")
|
||||
} else {
|
||||
txt.print("bit 6 not set\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user