mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 01:49:22 +00:00
IR: better code for array element assignments (w.i.p.)
This commit is contained in:
parent
8f56a7fe69
commit
f2010bf7a5
@ -14,5 +14,6 @@
|
|||||||
<orderEntry type="module" module-name="intermediate" />
|
<orderEntry type="module" module-name="intermediate" />
|
||||||
<orderEntry type="library" name="io.kotest.assertions.core.jvm" level="project" />
|
<orderEntry type="library" name="io.kotest.assertions.core.jvm" level="project" />
|
||||||
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
||||||
|
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
@ -1,5 +1,8 @@
|
|||||||
package prog8.codegen.intermediate
|
package prog8.codegen.intermediate
|
||||||
|
|
||||||
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
|
import com.github.michaelbull.result.getOrElse
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.AssemblyError
|
import prog8.code.core.AssemblyError
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.DataType
|
||||||
@ -7,6 +10,7 @@ import prog8.code.core.PrefixOperators
|
|||||||
import prog8.code.core.SignedDatatypes
|
import prog8.code.core.SignedDatatypes
|
||||||
import prog8.intermediate.*
|
import prog8.intermediate.*
|
||||||
|
|
||||||
|
|
||||||
internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) {
|
internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) {
|
||||||
|
|
||||||
internal fun translate(assignment: PtAssignment): IRCodeChunks {
|
internal fun translate(assignment: PtAssignment): IRCodeChunks {
|
||||||
@ -34,10 +38,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
else
|
else
|
||||||
fallbackAssign(augAssign)
|
fallbackAssign(augAssign)
|
||||||
} else if(array!=null) {
|
} else if(array!=null) {
|
||||||
// NOTE: naive fallback assignment here will sometimes generate code that loads the index value multiple times
|
assignArrayAugmented(array, augAssign)
|
||||||
// in a register. It's way too much work to optimize that here - instead, we trust that the generated IL assembly
|
|
||||||
// will be optimized later and have the double assignments removed.
|
|
||||||
fallbackAssign(augAssign)
|
|
||||||
} else {
|
} else {
|
||||||
fallbackAssign(augAssign)
|
fallbackAssign(augAssign)
|
||||||
}
|
}
|
||||||
@ -45,10 +46,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
return chunks
|
return chunks
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assignMemoryAugmented(
|
private fun assignMemoryAugmented(address: Int, assignment: PtAugmentedAssign): IRCodeChunks {
|
||||||
address: Int,
|
|
||||||
assignment: PtAugmentedAssign
|
|
||||||
): IRCodeChunks {
|
|
||||||
val value = assignment.value
|
val value = assignment.value
|
||||||
val targetDt = irType(assignment.target.type)
|
val targetDt = irType(assignment.target.type)
|
||||||
val signed = assignment.target.type in SignedDatatypes
|
val signed = assignment.target.type in SignedDatatypes
|
||||||
@ -63,7 +61,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
"<<=" -> expressionEval.operatorShiftLeftInplace(address, null, targetDt, value)
|
"<<=" -> expressionEval.operatorShiftLeftInplace(address, null, targetDt, value)
|
||||||
">>=" -> expressionEval.operatorShiftRightInplace(address, null, targetDt, signed, value)
|
">>=" -> expressionEval.operatorShiftRightInplace(address, null, targetDt, signed, value)
|
||||||
"%=" -> expressionEval.operatorModuloInplace(address, null, targetDt, value)
|
"%=" -> expressionEval.operatorModuloInplace(address, null, targetDt, value)
|
||||||
"==" -> expressionEval.operatorEqualsInplace(address, null, targetDt, value)
|
"==" -> expressionEval.operatorEqualsNotEqualsInplace(address, null, targetDt, value)
|
||||||
"!=" -> expressionEval.operatorNotEqualsInplace(address, null, targetDt, value)
|
"!=" -> expressionEval.operatorNotEqualsInplace(address, null, targetDt, value)
|
||||||
"<" -> expressionEval.operatorLessInplace(address, null, targetDt, signed, value)
|
"<" -> expressionEval.operatorLessInplace(address, null, targetDt, signed, value)
|
||||||
">" -> expressionEval.operatorGreaterInplace(address, null, targetDt, signed, value)
|
">" -> expressionEval.operatorGreaterInplace(address, null, targetDt, signed, value)
|
||||||
@ -92,17 +90,49 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
"<<=" -> expressionEval.operatorShiftLeftInplace(null, symbol, targetDt, value)
|
"<<=" -> expressionEval.operatorShiftLeftInplace(null, symbol, targetDt, value)
|
||||||
">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, targetDt, signed, value)
|
">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, targetDt, signed, value)
|
||||||
"%=" -> expressionEval.operatorModuloInplace(null, symbol, targetDt, value)
|
"%=" -> expressionEval.operatorModuloInplace(null, symbol, targetDt, value)
|
||||||
"==" -> expressionEval.operatorEqualsInplace(null, symbol, targetDt, value)
|
"==" -> expressionEval.operatorEqualsNotEqualsInplace(null, symbol, targetDt, value)
|
||||||
"!=" -> expressionEval.operatorNotEqualsInplace(null, symbol, targetDt, value)
|
"!=" -> expressionEval.operatorNotEqualsInplace(null, symbol, targetDt, value)
|
||||||
"<" -> expressionEval.operatorLessInplace(null, symbol, targetDt, signed, value)
|
"<" -> expressionEval.operatorLessInplace(null, symbol, targetDt, signed, value)
|
||||||
">" -> expressionEval.operatorGreaterInplace(null, symbol, targetDt, signed, value)
|
">" -> expressionEval.operatorGreaterInplace(null, symbol, targetDt, signed, value)
|
||||||
"<=" -> expressionEval.operatorLessEqualInplace(null, symbol, targetDt, signed, value)
|
"<=" -> expressionEval.operatorLessEqualInplace(null, symbol, targetDt, signed, value)
|
||||||
">=" -> expressionEval.operatorGreaterEqualInplace(null, symbol, targetDt, signed, value)
|
">=" -> expressionEval.operatorGreaterEqualInplace(null, symbol, targetDt, signed, value)
|
||||||
in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, null, symbol)
|
in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, null, symbol)
|
||||||
|
|
||||||
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
|
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assignArrayAugmented(array: PtArrayIndexer, assignment: PtAugmentedAssign): IRCodeChunks {
|
||||||
|
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||||
|
val value = assignment.value
|
||||||
|
val signed = assignment.target.type in SignedDatatypes
|
||||||
|
val result = when(assignment.operator) {
|
||||||
|
// TODO implement all of these:
|
||||||
|
// "+=" -> expressionEval.operatorPlusInplace(array, eltSize, value)
|
||||||
|
// "-=" -> expressionEval.operatorMinusInplace(array, eltSize, value)
|
||||||
|
// "*=" -> expressionEval.operatorMultiplyInplace(array, eltSize, value)
|
||||||
|
// "/=" -> expressionEval.operatorDivideInplace(array, eltSize, signed, value)
|
||||||
|
// "|=" -> expressionEval.operatorOrInplace(array, eltSize, value)
|
||||||
|
// "&=" -> expressionEval.operatorAndInplace(array, eltSize, value)
|
||||||
|
// "^=" -> expressionEval.operatorXorInplace(array, eltSize, value)
|
||||||
|
// "<<=" -> expressionEval.operatorShiftLeftInplace(array, eltSize, value)
|
||||||
|
// ">>=" -> expressionEval.operatorShiftRightInplace(array, eltSize, signed, value)
|
||||||
|
// "%=" -> expressionEval.operatorModuloInplace(array, eltSize, value)
|
||||||
|
"==" -> expressionEval.operatorEqualsNotEqualsInplace(array, eltSize, value, true)
|
||||||
|
"!=" -> expressionEval.operatorEqualsNotEqualsInplace(array, eltSize, value, false)
|
||||||
|
// "<" -> expressionEval.operatorLessInplace(array, eltSize, signed, value) // TODO reuse code from ==
|
||||||
|
// ">" -> expressionEval.operatorGreaterInplace(array, eltSize, signed, value) // TODO reuse code from ==
|
||||||
|
// "<=" -> expressionEval.operatorLessEqualInplace(array, eltSize, signed, value) // TODO reuse code from ==
|
||||||
|
// ">=" -> expressionEval.operatorGreaterEqualInplace(array, eltSize, signed, value) // TODO reuse code from ==
|
||||||
|
in PrefixOperators -> inplacePrefix(assignment.operator, array, eltSize)
|
||||||
|
|
||||||
|
// else -> Err(NotImplementedError("invalid augmented assign operator ${assignment.operator}"))
|
||||||
|
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.getOrElse { fallbackAssign(assignment) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
|
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
|
||||||
val value: PtExpression
|
val value: PtExpression
|
||||||
if(origAssign.operator in PrefixOperators) {
|
if(origAssign.operator in PrefixOperators) {
|
||||||
@ -122,12 +152,79 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
return translateRegularAssign(normalAssign)
|
return translateRegularAssign(normalAssign)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun inplacePrefix(operator: String, array: PtArrayIndexer, eltSize: Int): Result<IRCodeChunks, NotImplementedError> {
|
||||||
|
if(array.splitWords)
|
||||||
|
TODO("inplace prefix for split word array")
|
||||||
|
|
||||||
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
val vmDt = irType(array.type)
|
||||||
|
val constIndex = array.index.asConstInteger()
|
||||||
|
when(operator) {
|
||||||
|
"+" -> { }
|
||||||
|
"-" -> {
|
||||||
|
if(constIndex!=null) {
|
||||||
|
addInstr(result, IRInstruction(Opcode.NEGM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
||||||
|
} else {
|
||||||
|
val register = codeGen.registers.nextFree()
|
||||||
|
val tr = expressionEval.translateExpression(array.index)
|
||||||
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
|
if(eltSize>1)
|
||||||
|
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
||||||
|
it += IRInstruction(Opcode.NEG, vmDt, reg1 = register)
|
||||||
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"~" -> {
|
||||||
|
if(constIndex!=null) {
|
||||||
|
addInstr(result, IRInstruction(Opcode.INVM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
||||||
|
} else {
|
||||||
|
val register = codeGen.registers.nextFree()
|
||||||
|
val tr = expressionEval.translateExpression(array.index)
|
||||||
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
|
if(eltSize>1)
|
||||||
|
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
||||||
|
it += IRInstruction(Opcode.INV, vmDt, reg1 = register)
|
||||||
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"not" -> {
|
||||||
|
val register = codeGen.registers.nextFree()
|
||||||
|
if(constIndex!=null) {
|
||||||
|
// TODO: in boolean branch, is 'not' handled ok like this?
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.LOAD, vmDt, reg1=register, immediate = 1)
|
||||||
|
it += IRInstruction(Opcode.XORM, vmDt, reg1=register, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val tr = expressionEval.translateExpression(array.index)
|
||||||
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
|
if(eltSize>1)
|
||||||
|
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
||||||
|
it += IRInstruction(Opcode.XOR, vmDt, reg1 = register, immediate = 1)
|
||||||
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("weird prefix operator")
|
||||||
|
}
|
||||||
|
return Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
private fun inplacePrefix(operator: String, vmDt: IRDataType, address: Int?, symbol: String?): IRCodeChunks {
|
private fun inplacePrefix(operator: String, vmDt: IRDataType, address: Int?, symbol: String?): IRCodeChunks {
|
||||||
val code= IRCodeChunk(null, null)
|
val code= IRCodeChunk(null, null)
|
||||||
when(operator) {
|
when(operator) {
|
||||||
"+" -> { }
|
"+" -> { }
|
||||||
"-" -> code += IRInstruction(Opcode.NEGM, vmDt, address = address, labelSymbol = symbol)
|
"-" -> code += IRInstruction(Opcode.NEGM, vmDt, address = address, labelSymbol = symbol)
|
||||||
"~" -> code += IRInstruction(Opcode.INVM, vmDt, address = address, labelSymbol = symbol)
|
"~" -> code += IRInstruction(Opcode.INVM, vmDt, address = address, labelSymbol = symbol)
|
||||||
|
// TODO: in boolean branch, how is 'not' handled here?
|
||||||
else -> throw AssemblyError("weird prefix operator")
|
else -> throw AssemblyError("weird prefix operator")
|
||||||
}
|
}
|
||||||
return listOf(code)
|
return listOf(code)
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package prog8.codegen.intermediate
|
package prog8.codegen.intermediate
|
||||||
|
|
||||||
|
import com.github.michaelbull.result.Err
|
||||||
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
import prog8.code.StRomSub
|
import prog8.code.StRomSub
|
||||||
import prog8.code.StSub
|
import prog8.code.StSub
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.intermediate.*
|
import prog8.intermediate.*
|
||||||
|
|
||||||
|
|
||||||
internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int) {
|
internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int) {
|
||||||
constructor(chunks: IRCodeChunk, dt: IRDataType, resultReg: Int, resultFpReg: Int) : this(listOf(chunks), dt, resultReg, resultFpReg)
|
constructor(chunks: IRCodeChunk, dt: IRDataType, resultReg: Int, resultFpReg: Int) : this(listOf(chunks), dt, resultReg, resultFpReg)
|
||||||
|
|
||||||
@ -193,15 +197,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
|
|
||||||
if(arrayIx.splitWords) {
|
if(arrayIx.splitWords) {
|
||||||
require(vmDt==IRDataType.WORD)
|
require(vmDt==IRDataType.WORD)
|
||||||
val arrayLength = codeGen.symbolTable.getLength(arrayIx.variable.name)
|
|
||||||
resultRegister = codeGen.registers.nextFree()
|
resultRegister = codeGen.registers.nextFree()
|
||||||
val finalResultReg = codeGen.registers.nextFree()
|
val finalResultReg = codeGen.registers.nextFree()
|
||||||
if(arrayIx.index is PtNumber) {
|
if(arrayIx.index is PtNumber) {
|
||||||
val memOffset = (arrayIx.index as PtNumber).number.toInt()
|
val memOffset = (arrayIx.index as PtNumber).number.toInt()
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
val tmpRegMsb = codeGen.registers.nextFree()
|
val tmpRegMsb = codeGen.registers.nextFree()
|
||||||
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=tmpRegMsb, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_msb", symbolOffset = memOffset)
|
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=tmpRegMsb, labelSymbol= "${arrayVarSymbol}_msb", symbolOffset = memOffset)
|
||||||
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_lsb", symbolOffset = memOffset)
|
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, labelSymbol= "${arrayVarSymbol}_lsb", symbolOffset = memOffset)
|
||||||
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=finalResultReg, reg2=tmpRegMsb, reg3=resultRegister)
|
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=finalResultReg, reg2=tmpRegMsb, reg3=resultRegister)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -209,8 +212,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
val tmpRegMsb = codeGen.registers.nextFree()
|
val tmpRegMsb = codeGen.registers.nextFree()
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2 = tr.resultReg, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_msb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2 = tr.resultReg, labelSymbol= "${arrayVarSymbol}_msb")
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=resultRegister, reg2 = tr.resultReg, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_lsb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=resultRegister, reg2 = tr.resultReg, labelSymbol= "${arrayVarSymbol}_lsb")
|
||||||
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=finalResultReg, reg2=tmpRegMsb, reg3=resultRegister)
|
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=finalResultReg, reg2=tmpRegMsb, reg3=resultRegister)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1338,7 +1341,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun operatorEqualsInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
|
fun operatorEqualsNotEqualsInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
|
||||||
return if(vmDt==IRDataType.FLOAT) {
|
return if(vmDt==IRDataType.FLOAT) {
|
||||||
createInplaceFloatComparison(knownAddress, symbol, operand, Opcode.SEQ)
|
createInplaceFloatComparison(knownAddress, symbol, operand, Opcode.SEQ)
|
||||||
} else {
|
} else {
|
||||||
@ -1391,7 +1394,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createInplaceComparison(
|
private fun createInplaceComparison(
|
||||||
knownAddress: Int?,
|
knownAddress: Int?,
|
||||||
symbol: String?,
|
symbol: String?,
|
||||||
vmDt: IRDataType,
|
vmDt: IRDataType,
|
||||||
@ -1402,6 +1405,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val valueReg = codeGen.registers.nextFree()
|
val valueReg = codeGen.registers.nextFree()
|
||||||
val cmpResultReg = codeGen.registers.nextFree()
|
val cmpResultReg = codeGen.registers.nextFree()
|
||||||
if(operand is PtNumber) {
|
if(operand is PtNumber) {
|
||||||
|
// TODO optimize if operand is 0
|
||||||
val numberReg = codeGen.registers.nextFree()
|
val numberReg = codeGen.registers.nextFree()
|
||||||
if (knownAddress != null) {
|
if (knownAddress != null) {
|
||||||
// in-place modify a memory location
|
// in-place modify a memory location
|
||||||
@ -1453,6 +1457,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val cmpReg = codeGen.registers.nextFree()
|
val cmpReg = codeGen.registers.nextFree()
|
||||||
val zeroReg = codeGen.registers.nextFree()
|
val zeroReg = codeGen.registers.nextFree()
|
||||||
if(operand is PtNumber) {
|
if(operand is PtNumber) {
|
||||||
|
// TODO optimize if operand is 0 ?
|
||||||
val numberReg = codeGen.registers.nextFreeFloat()
|
val numberReg = codeGen.registers.nextFreeFloat()
|
||||||
val cmpResultReg = codeGen.registers.nextFree()
|
val cmpResultReg = codeGen.registers.nextFree()
|
||||||
if (knownAddress != null) {
|
if (knownAddress != null) {
|
||||||
@ -1507,6 +1512,38 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun operatorEqualsNotEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression, equals: Boolean): Result<IRCodeChunks, NotImplementedError> {
|
||||||
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
if(array.splitWords)
|
||||||
|
TODO("inplace == for split word array")
|
||||||
|
if(array.usesPointerVariable)
|
||||||
|
TODO("inplace == for pointer variable")
|
||||||
|
val vmDt = irType(array.type)
|
||||||
|
val constIndex = array.index.asConstInteger()
|
||||||
|
val constValue = value.asConstInteger()
|
||||||
|
val cmpResultReg = codeGen.registers.nextFree()
|
||||||
|
if(constIndex!=null) {
|
||||||
|
if(constValue!=null) {
|
||||||
|
val valueReg = codeGen.registers.nextFree()
|
||||||
|
if(constValue==0) {
|
||||||
|
val compareAndSetOpcode = if(equals) Opcode.SZ else Opcode.SNZ
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
|
||||||
|
it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2=valueReg)
|
||||||
|
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(NotImplementedError("compare against non-zero value"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TODO("non const value")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TODO("non const index")
|
||||||
|
}
|
||||||
|
return Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -475,8 +475,8 @@ class IRCodeGen(
|
|||||||
val tmpRegLsb = registers.nextFree()
|
val tmpRegLsb = registers.nextFree()
|
||||||
val tmpRegMsb = registers.nextFree()
|
val tmpRegMsb = registers.nextFree()
|
||||||
val concatReg = registers.nextFree()
|
val concatReg = registers.nextFree()
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_msb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, labelSymbol=iterable.name+"_msb")
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_lsb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, labelSymbol=iterable.name+"_lsb")
|
||||||
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=concatReg, reg2=tmpRegMsb, reg3=tmpRegLsb)
|
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=concatReg, reg2=tmpRegMsb, reg3=tmpRegLsb)
|
||||||
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=concatReg, labelSymbol = loopvarSymbol)
|
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=concatReg, labelSymbol = loopvarSymbol)
|
||||||
}
|
}
|
||||||
@ -1462,7 +1462,6 @@ class IRCodeGen(
|
|||||||
else -> throw AssemblyError("weird operator")
|
else -> throw AssemblyError("weird operator")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val arrayLength = symbolTable.getLength(array.variable.name)
|
|
||||||
val indexTr = expressionEval.translateExpression(array.index)
|
val indexTr = expressionEval.translateExpression(array.index)
|
||||||
addToResult(result, indexTr, indexTr.resultReg, -1)
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
||||||
val incReg = registers.nextFree()
|
val incReg = registers.nextFree()
|
||||||
@ -1470,28 +1469,28 @@ class IRCodeGen(
|
|||||||
when(postIncrDecr.operator) {
|
when(postIncrDecr.operator) {
|
||||||
"++" -> {
|
"++" -> {
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
|
||||||
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg)
|
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg)
|
||||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
|
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
|
||||||
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
|
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_msb")
|
||||||
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg)
|
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg)
|
||||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
|
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_msb")
|
||||||
}
|
}
|
||||||
result += IRCodeChunk(skipLabel, null)
|
result += IRCodeChunk(skipLabel, null)
|
||||||
}
|
}
|
||||||
"--" -> {
|
"--" -> {
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
|
||||||
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
|
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_msb")
|
||||||
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg)
|
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg)
|
||||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
|
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_msb")
|
||||||
}
|
}
|
||||||
result += IRCodeChunk(skipLabel, null).also {
|
result += IRCodeChunk(skipLabel, null).also {
|
||||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
|
||||||
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg)
|
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg)
|
||||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
|
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird operator")
|
else -> throw AssemblyError("weird operator")
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
|
IR assignVarAugmented(): implement all operators.
|
||||||
|
IR expressionGen.kt: optimize various stuff if the operand is const value 0
|
||||||
|
|
||||||
|
|
||||||
maze: if cell & UP!=0 and @(celladdr(cx,cy-1)) & (WALKED|BACKTRACKED) ==0
|
maze: if cell & UP!=0 and @(celladdr(cx,cy-1)) & (WALKED|BACKTRACKED) ==0
|
||||||
^^ adding this !=0 caused a weird beq + / lda #1 / + to appear in front of the shortcircuit beq...
|
^^ adding this !=0 caused a weird beq + / lda #1 / + to appear in front of the shortcircuit beq...
|
||||||
|
|
||||||
@ -65,6 +69,7 @@ Optimizations:
|
|||||||
those checks should probably be removed, or be made permanent
|
those checks should probably be removed, or be made permanent
|
||||||
- optimizeCommonSubExpressions: currently only looks in expressions on a single line, could search across multiple expressions
|
- optimizeCommonSubExpressions: currently only looks in expressions on a single line, could search across multiple expressions
|
||||||
|
|
||||||
|
|
||||||
STRUCTS again?
|
STRUCTS again?
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -1,15 +1,32 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%zeropage dontuse
|
%zeropage basicsafe
|
||||||
|
%option no_sysinit
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte @shared ubb = 99
|
uword[3] ubarr
|
||||||
uword @shared uww = 12345
|
bool[3] barr
|
||||||
ubyte[200] @shared barr
|
bool @shared bb
|
||||||
uword @shared ptr = memory("data", $2000, 0)
|
|
||||||
|
|
||||||
%breakpoint
|
; ubarr[1] = ubarr[1] + 2
|
||||||
|
; ubarr[1] = ubarr[1] * 3
|
||||||
|
|
||||||
txt.print_uwhex(sys.progend(), true)
|
; barr[1] = barr[0] and barr[2]
|
||||||
|
; barr[1] = barr[0] or barr[2]
|
||||||
|
; barr[1] = barr[0] xor barr[2]
|
||||||
|
; barr[1] = not barr[0]
|
||||||
|
|
||||||
|
ubarr[1] = 999
|
||||||
|
ubarr[1] = ubarr[1]==999
|
||||||
|
txt.print_uw(ubarr[1])
|
||||||
|
|
||||||
|
; barr[1] = barr[1] and bb
|
||||||
|
; barr[1] = barr[1] or bb
|
||||||
|
; barr[1] = barr[1] xor bb
|
||||||
|
|
||||||
|
; bb = bb and barr[1]
|
||||||
|
; bb = bb or barr[1]
|
||||||
|
; bb = bb xor barr[1]
|
||||||
|
; bb = not bb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user