more efficient code for inc/dec on arrays

This commit is contained in:
Irmen de Jong 2018-12-26 15:47:23 +01:00
parent 8adbcb7a26
commit c58b862b34
5 changed files with 105 additions and 32 deletions

View File

@ -22,27 +22,20 @@
sub start() { sub start() {
c64scr.print(" X=") ; c64scr.print(" X=")
c64scr.print_ub(X) ; c64scr.print_ub(X)
c64.CHROUT('\n') ; c64.CHROUT('\n')
c64scr.print(" X=") ubyte[256] screenarray
c64scr.print_ub(X) ubyte index = 2
c64.CHROUT('\n') screenarray[1]--
screenarray[index]--
; c64scr.print(" X=")
; c64scr.print_ub(X)
; c64.CHROUT('\n')
} }
} }
~ irq {
sub irq() {
memory ubyte[256] screenarray = $0400
memory ubyte firstscreenchar = $0400
screenarray[0]++ ; @todo incorrect code generated?
firstscreenchar++ ; ... this is okay
c64.EXTCOL++
}
}

View File

@ -342,6 +342,28 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} }
} }
private fun opcodeIncArrayindexedVar(dt: DataType): Opcode {
return when(dt) {
DataType.ARRAY_UB -> Opcode.INC_INDEXED_VAR_UB
DataType.ARRAY_B -> Opcode.INC_INDEXED_VAR_B
DataType.ARRAY_UW -> Opcode.INC_INDEXED_VAR_UW
DataType.ARRAY_W -> Opcode.INC_INDEXED_VAR_W
DataType.ARRAY_F -> Opcode.INC_INDEXED_VAR_FLOAT
else -> throw CompilerException("can't inc type $dt")
}
}
private fun opcodeDecArrayindexedVar(dt: DataType): Opcode {
return when(dt) {
DataType.ARRAY_UB -> Opcode.DEC_INDEXED_VAR_UB
DataType.ARRAY_B -> Opcode.DEC_INDEXED_VAR_B
DataType.ARRAY_UW -> Opcode.DEC_INDEXED_VAR_UW
DataType.ARRAY_W -> Opcode.DEC_INDEXED_VAR_W
DataType.ARRAY_F -> Opcode.DEC_INDEXED_VAR_FLOAT
else -> throw CompilerException("can't dec type $dt")
}
}
private fun translate(stmt: InlineAssembly) { private fun translate(stmt: InlineAssembly) {
prog.instr(Opcode.INLINE_ASSEMBLY, callLabel = stmt.assembly) prog.instr(Opcode.INLINE_ASSEMBLY, callLabel = stmt.assembly)
} }
@ -573,7 +595,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.ARRAY_B, DataType.ARRAY_W -> { DataType.ARRAY_B, DataType.ARRAY_W -> {
if(lv.heapId==null) if(lv.heapId==null)
throw CompilerException("array should have been moved into heap ${lv.position}") throw CompilerException("array should have been moved into heap ${lv.position}")
prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.heapId)) prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.heapId)) // XXX push address of array
} }
} }
} }
@ -634,7 +656,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.UWORD -> prog.instr(Opcode.PUSH_MEM_UW, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!)) DataType.UWORD -> prog.instr(Opcode.PUSH_MEM_UW, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
DataType.WORD -> prog.instr(Opcode.PUSH_MEM_W, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!)) DataType.WORD -> prog.instr(Opcode.PUSH_MEM_W, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
DataType.FLOAT -> prog.instr(Opcode.PUSH_MEM_FLOAT, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!)) DataType.FLOAT -> prog.instr(Opcode.PUSH_MEM_FLOAT, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
else -> TODO("invalid datatype for memory variable expression: $target") else -> throw CompilerException("invalid datatype for memory variable expression: $target")
} }
} }
} }
@ -1213,16 +1235,12 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} }
} }
stmt.target.arrayindexed!=null -> { stmt.target.arrayindexed!=null -> {
// todo: generate more efficient bytecode for this? val variable = stmt.target.arrayindexed!!.identifier?.targetStatement(namespace) as VarDecl
translate(stmt.target.arrayindexed!!, false) translate(stmt.target.arrayindexed!!.arrayspec.x)
val one = Value(stmt.target.arrayindexed!!.resultingDatatype(namespace, heap)!!, 1)
val opcode = opcodePush(one.type)
prog.instr(opcode, one)
when(stmt.operator) { when(stmt.operator) {
"++" -> prog.instr(opcodeAdd(one.type)) "++" -> prog.instr(opcodeIncArrayindexedVar(variable.datatype), callLabel = variable.scopedname)
"--" -> prog.instr(opcodeSub(one.type)) "--" -> prog.instr(opcodeDecArrayindexedVar(variable.datatype), callLabel = variable.scopedname)
} }
translate(stmt.target.arrayindexed!!, true)
} }
else -> throw CompilerException("very strange postincrdecr") else -> throw CompilerException("very strange postincrdecr")
} }

View File

@ -192,13 +192,23 @@ enum class Opcode {
NOTEQUAL_WORD, NOTEQUAL_WORD,
NOTEQUAL_F, NOTEQUAL_F,
// arrayspec access // array access and simple manipulations
READ_INDEXED_VAR_BYTE, READ_INDEXED_VAR_BYTE,
READ_INDEXED_VAR_WORD, READ_INDEXED_VAR_WORD,
READ_INDEXED_VAR_FLOAT, READ_INDEXED_VAR_FLOAT,
WRITE_INDEXED_VAR_BYTE, WRITE_INDEXED_VAR_BYTE,
WRITE_INDEXED_VAR_WORD, WRITE_INDEXED_VAR_WORD,
WRITE_INDEXED_VAR_FLOAT, WRITE_INDEXED_VAR_FLOAT,
INC_INDEXED_VAR_B,
INC_INDEXED_VAR_UB,
INC_INDEXED_VAR_W,
INC_INDEXED_VAR_UW,
INC_INDEXED_VAR_FLOAT,
DEC_INDEXED_VAR_B,
DEC_INDEXED_VAR_UB,
DEC_INDEXED_VAR_W,
DEC_INDEXED_VAR_UW,
DEC_INDEXED_VAR_FLOAT,
// branching, without consuming a value from the stack // branching, without consuming a value from the stack
JUMP, JUMP,
@ -248,5 +258,9 @@ val opcodesWithVarArgument = setOf(
Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT, Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT,
Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_ADDR_HEAPVAR, Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_ADDR_HEAPVAR,
Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT,
Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT,
Opcode.INC_INDEXED_VAR_UB, Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UW,
Opcode.INC_INDEXED_VAR_W, Opcode.INC_INDEXED_VAR_FLOAT,
Opcode.DEC_INDEXED_VAR_UB, Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UW,
Opcode.DEC_INDEXED_VAR_W, Opcode.DEC_INDEXED_VAR_FLOAT
) )

View File

@ -808,6 +808,26 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
} }
} }
} }
else if((opcodes[0]==Opcode.PUSH_BYTE && opcodes[1] in setOf(Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB,
Opcode.INC_INDEXED_VAR_UW, Opcode.INC_INDEXED_VAR_W, Opcode.INC_INDEXED_VAR_FLOAT,
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB, Opcode.DEC_INDEXED_VAR_W,
Opcode.DEC_INDEXED_VAR_UW, Opcode.DEC_INDEXED_VAR_FLOAT))) {
val fragment = sameConstantIndexedVarOperation(segment[1].callLabel!!, segment[0].arg!!.integerValue(), segment[1])
if(fragment!=null) {
fragment.segmentSize=2
result.add(fragment)
}
}
else if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[1] in setOf(Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB,
Opcode.INC_INDEXED_VAR_UW, Opcode.INC_INDEXED_VAR_W, Opcode.INC_INDEXED_VAR_FLOAT,
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB, Opcode.DEC_INDEXED_VAR_W,
Opcode.DEC_INDEXED_VAR_UW, Opcode.DEC_INDEXED_VAR_FLOAT))) {
val fragment = sameIndexedVarOperation(segment[1].callLabel!!, segment[0].callLabel!!, segment[1])
if(fragment!=null) {
fragment.segmentSize=2
result.add(fragment)
}
}
else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_BYTE) || else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_BYTE) ||
(opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_BYTE) || (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_BYTE) ||
(opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_WORD) || (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_WORD) ||
@ -877,6 +897,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.ROR2_BYTE -> AsmFragment(" lda $variable+$index | lsr a | bcc + | ora #\$80 |+ | sta $variable+$index", 10) Opcode.ROR2_BYTE -> AsmFragment(" lda $variable+$index | lsr a | bcc + | ora #\$80 |+ | sta $variable+$index", 10)
Opcode.ROL2_WORD -> AsmFragment(" asl $variable+$index | rol $variable+${index+1} | bcc + | inc $variable+$index |+",20) Opcode.ROL2_WORD -> AsmFragment(" asl $variable+$index | rol $variable+${index+1} | bcc + | inc $variable+$index |+",20)
Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index+1} | ror $variable+$index | bcc + | lda $variable+${index+1} | ora #\$80 | sta $variable+${index+1} |+", 30) Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index+1} | ror $variable+$index | bcc + | lda $variable+${index+1} | ora #\$80 | sta $variable+${index+1} |+", 30)
Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> AsmFragment(" inc $variable+$index", 2)
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> AsmFragment(" dec $variable+$index", 5)
Opcode.INC_INDEXED_VAR_W -> TODO("inc array_w")
Opcode.INC_INDEXED_VAR_UW -> TODO("inc array_uw")
Opcode.INC_INDEXED_VAR_FLOAT -> TODO("inc array_f")
Opcode.DEC_INDEXED_VAR_W -> TODO("dec array_w")
Opcode.DEC_INDEXED_VAR_UW -> TODO("dec array_uw")
Opcode.DEC_INDEXED_VAR_FLOAT -> TODO("dec array_f")
else -> null else -> null
} }
} }
@ -921,6 +949,15 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.ROR2_BYTE -> AsmFragment("$saveX $loadX lda $variable,x | lsr a | bcc + | ora #\$80 |+ | sta $variable,x $restoreX", 10) Opcode.ROR2_BYTE -> AsmFragment("$saveX $loadX lda $variable,x | lsr a | bcc + | ora #\$80 |+ | sta $variable,x $restoreX", 10)
Opcode.ROL2_WORD -> AsmFragment(" txa | $loadXWord asl $variable,x | rol $variable+1,x | bcc + | inc $variable,x |+ | tax", 30) Opcode.ROL2_WORD -> AsmFragment(" txa | $loadXWord asl $variable,x | rol $variable+1,x | bcc + | inc $variable,x |+ | tax", 30)
Opcode.ROR2_WORD -> AsmFragment("$saveX $loadXWord lsr $variable+1,x | ror $variable,x | bcc + | lda $variable+1,x | ora #\$80 | sta $variable+1,x |+ $restoreX", 30) Opcode.ROR2_WORD -> AsmFragment("$saveX $loadXWord lsr $variable+1,x | ror $variable,x | bcc + | lda $variable+1,x | ora #\$80 | sta $variable+1,x |+ $restoreX", 30)
Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> AsmFragment(" txa | $loadX inc $variable,x | tax", 10)
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> AsmFragment(" txa | $loadX dec $variable,x | tax", 10)
Opcode.INC_INDEXED_VAR_W -> TODO("inc array_w")
Opcode.INC_INDEXED_VAR_UW -> TODO("inc array_uw")
Opcode.INC_INDEXED_VAR_FLOAT -> TODO("inc array_f")
Opcode.DEC_INDEXED_VAR_W -> TODO("dec array_w")
Opcode.DEC_INDEXED_VAR_UW -> TODO("dec array_uw")
Opcode.DEC_INDEXED_VAR_FLOAT -> TODO("dec array_f")
else -> null else -> null
} }
} }
@ -2807,7 +2844,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE)) { segment -> listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE)) { segment ->
" lda ${hexVal(segment[0])} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " " lda ${hexVal(segment[0])} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
} }
) )
} }

View File

@ -944,6 +944,18 @@ class StackVm(private var traceOutputFile: String?) {
checkDt(variable, DataType.FLOAT) checkDt(variable, DataType.FLOAT)
variables[ins.callLabel] =variable.dec() variables[ins.callLabel] =variable.dec()
} }
Opcode.INC_INDEXED_VAR_B,Opcode.INC_INDEXED_VAR_UB,Opcode.INC_INDEXED_VAR_W,Opcode.INC_INDEXED_VAR_UW,Opcode.INC_INDEXED_VAR_FLOAT -> {
val index = evalstack.pop().integerValue()
val variable = getVar(ins.callLabel!!)
val array = heap.get(variable.heapId)
array.array!![index].inc()
}
Opcode.DEC_INDEXED_VAR_B,Opcode.DEC_INDEXED_VAR_UB,Opcode.DEC_INDEXED_VAR_W,Opcode.DEC_INDEXED_VAR_UW,Opcode.DEC_INDEXED_VAR_FLOAT -> {
val index = evalstack.pop().integerValue()
val variable = getVar(ins.callLabel!!)
val array = heap.get(variable.heapId)
array.array!![index].dec()
}
Opcode.MSB -> { Opcode.MSB -> {
val v = evalstack.pop() val v = evalstack.pop()
checkDt(v, DataType.UWORD, DataType.WORD) checkDt(v, DataType.UWORD, DataType.WORD)