mirror of
https://github.com/irmen/prog8.git
synced 2025-01-22 09:31:36 +00:00
IR: optimize code for ==0 and !=0 augmented assigns
This commit is contained in:
parent
f2010bf7a5
commit
8cf0b6cf51
@ -4,10 +4,7 @@ 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.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.PrefixOperators
|
||||
import prog8.code.core.SignedDatatypes
|
||||
import prog8.code.core.*
|
||||
import prog8.intermediate.*
|
||||
|
||||
|
||||
@ -30,6 +27,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val memory = augAssign.target.memory
|
||||
val array = augAssign.target.array
|
||||
|
||||
// TODO don't fragment the implementation over multiple subroutines
|
||||
val chunks = if(ident!=null) {
|
||||
assignVarAugmented(ident.name, augAssign)
|
||||
} else if(memory != null) {
|
||||
@ -38,7 +36,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
else
|
||||
fallbackAssign(augAssign)
|
||||
} else if(array!=null) {
|
||||
assignArrayAugmented(array, augAssign)
|
||||
// TODO assignArrayAugmented(array, augAssign)
|
||||
fallbackAssign(augAssign)
|
||||
} else {
|
||||
fallbackAssign(augAssign)
|
||||
}
|
||||
@ -118,12 +117,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
// "<<=" -> 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 ==
|
||||
"==" -> expressionEval.operatorEqualsInplace(array, eltSize, value)
|
||||
"!=" -> expressionEval.operatorNotEqualsInplace(array, eltSize, value)
|
||||
"<" -> expressionEval.operatorLessInplace(array, eltSize, signed, value)
|
||||
">" -> expressionEval.operatorGreaterInplace(array, eltSize, signed, value)
|
||||
"<=" -> expressionEval.operatorLessEqualInplace(array, eltSize, signed, value)
|
||||
">=" -> expressionEval.operatorGreaterEqualInplace(array, eltSize, signed, value)
|
||||
in PrefixOperators -> inplacePrefix(assignment.operator, array, eltSize)
|
||||
|
||||
// else -> Err(NotImplementedError("invalid augmented assign operator ${assignment.operator}"))
|
||||
@ -136,12 +135,17 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
|
||||
val value: PtExpression
|
||||
if(origAssign.operator in PrefixOperators) {
|
||||
value = PtPrefix(origAssign.operator, origAssign.target.type, origAssign.value.position)
|
||||
value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position)
|
||||
value.add(origAssign.value)
|
||||
} else {
|
||||
require(origAssign.operator.endsWith('='))
|
||||
val operator = if(origAssign.operator=="==") "==" else origAssign.operator.dropLast(1)
|
||||
value = PtBinaryExpression(operator, origAssign.target.type, origAssign.value.position)
|
||||
val operator = when(origAssign.operator) {
|
||||
in ComparisonOperators -> origAssign.operator
|
||||
else -> {
|
||||
require(origAssign.operator.endsWith('='))
|
||||
origAssign.operator.dropLast(1)
|
||||
}
|
||||
}
|
||||
value = PtBinaryExpression(operator, origAssign.value.type, origAssign.value.position)
|
||||
val left: PtExpression = origAssign.target.children.single() as PtExpression
|
||||
value.add(left)
|
||||
value.add(origAssign.value)
|
||||
|
@ -1394,7 +1394,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createInplaceComparison(
|
||||
private fun createInplaceComparison(
|
||||
knownAddress: Int?,
|
||||
symbol: String?,
|
||||
vmDt: IRDataType,
|
||||
@ -1405,7 +1405,29 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val valueReg = codeGen.registers.nextFree()
|
||||
val cmpResultReg = codeGen.registers.nextFree()
|
||||
if(operand is PtNumber) {
|
||||
// TODO optimize if operand is 0
|
||||
|
||||
if(operand.number==0.0 && compareAndSetOpcode in arrayOf(Opcode.SEQ, Opcode.SNE)) {
|
||||
// ==0 or !=0 optimized case
|
||||
val compareAndSetOpcodeZero = if(compareAndSetOpcode==Opcode.SEQ) Opcode.SZ else Opcode.SNZ
|
||||
if (knownAddress != null) {
|
||||
// in-place modify a memory location
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = knownAddress)
|
||||
it += IRInstruction(compareAndSetOpcodeZero, vmDt, reg1 = cmpResultReg, reg2 = valueReg)
|
||||
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = knownAddress)
|
||||
}
|
||||
} else {
|
||||
// in-place modify a symbol (variable)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol)
|
||||
it += IRInstruction(compareAndSetOpcodeZero, vmDt, reg1=cmpResultReg, reg2 = valueReg)
|
||||
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// compare against number that is not 0
|
||||
val numberReg = codeGen.registers.nextFree()
|
||||
if (knownAddress != null) {
|
||||
// in-place modify a memory location
|
||||
@ -1457,7 +1479,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val cmpReg = codeGen.registers.nextFree()
|
||||
val zeroReg = codeGen.registers.nextFree()
|
||||
if(operand is PtNumber) {
|
||||
// TODO optimize if operand is 0 ?
|
||||
val numberReg = codeGen.registers.nextFreeFloat()
|
||||
val cmpResultReg = codeGen.registers.nextFree()
|
||||
if (knownAddress != null) {
|
||||
@ -1512,7 +1533,54 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return result
|
||||
}
|
||||
|
||||
fun operatorEqualsNotEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression, equals: Boolean): Result<IRCodeChunks, NotImplementedError> {
|
||||
fun operatorEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
|
||||
if(array.type==DataType.FLOAT)
|
||||
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
|
||||
else
|
||||
return createCompareArrayInplace(array, eltSize, value, Opcode.SZ)
|
||||
}
|
||||
|
||||
fun operatorNotEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
|
||||
if(array.type==DataType.FLOAT)
|
||||
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
|
||||
else
|
||||
return createCompareArrayInplace(array, eltSize, value, Opcode.SNZ)
|
||||
}
|
||||
|
||||
fun operatorLessInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
|
||||
if(array.type==DataType.FLOAT)
|
||||
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
|
||||
else
|
||||
TODO("<")
|
||||
//return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ)
|
||||
}
|
||||
|
||||
fun operatorLessEqualInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
|
||||
if(array.type==DataType.FLOAT)
|
||||
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
|
||||
else
|
||||
TODO("<=")
|
||||
//return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ)
|
||||
}
|
||||
|
||||
fun operatorGreaterInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
|
||||
if(array.type==DataType.FLOAT)
|
||||
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
|
||||
else
|
||||
TODO(">")
|
||||
//return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ)
|
||||
}
|
||||
|
||||
fun operatorGreaterEqualInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
|
||||
if(array.type==DataType.FLOAT)
|
||||
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
|
||||
else
|
||||
TODO(">=")
|
||||
//return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ)
|
||||
}
|
||||
|
||||
private fun createCompareArrayInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression, compareAndSetOpcode: Opcode): Result<IRCodeChunks, NotImplementedError> {
|
||||
require(array.type!=DataType.FLOAT)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(array.splitWords)
|
||||
TODO("inplace == for split word array")
|
||||
@ -1526,7 +1594,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
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)
|
||||
|
@ -196,7 +196,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
if(valuetype in IterableDatatypes && targettype==DataType.UWORD)
|
||||
// special case, don't typecast STR/arrays to UWORD, we support those assignments "directly"
|
||||
return noModifications
|
||||
if((assignment.value as? BinaryExpression)?.operator in ComparisonOperators) {
|
||||
if((assignment.value as? BinaryExpression)?.operator in ComparisonOperators && targettype in IntegerDatatypes) {
|
||||
// special case, treat a boolean comparison result as the same type as the target value to avoid needless casts later
|
||||
return noModifications
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
}
|
||||
|
||||
// if the expression is a comparison expression, or a logical expression, it produces the
|
||||
// correct 'boolean' byte result so the cast can be removed.
|
||||
// correct 'boolean' byte result so the cast can be removed. Only if target is Integer.
|
||||
val binExpr = typecast.expression as? BinaryExpression
|
||||
if(binExpr!=null && binExpr.operator in ComparisonOperators + LogicalOperators) {
|
||||
if(binExpr!=null && binExpr.operator in ComparisonOperators + LogicalOperators && typecast.type in IntegerDatatypesNoBool) {
|
||||
return listOf(IAstModification.ReplaceNode(typecast, binExpr, parent))
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
IR assignVarAugmented(): implement all operators.
|
||||
IR expressionGen.kt: optimize various stuff if the operand is const value 0
|
||||
IR assignArrayAugmented(): implement all operators. (BUT: actually, don't split this up anymore per assign target type ...)
|
||||
|
||||
|
||||
maze: if cell & UP!=0 and @(celladdr(cx,cy-1)) & (WALKED|BACKTRACKED) ==0
|
||||
|
@ -1,24 +1,29 @@
|
||||
%import textio
|
||||
%import floats
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte @shared xx
|
||||
uword[3] ubarr
|
||||
bool[3] barr
|
||||
float[3] flarr
|
||||
bool @shared bb
|
||||
|
||||
; ubarr[1] = ubarr[1] + 2
|
||||
; ubarr[1] = ubarr[1] * 3
|
||||
ubarr[1] = ubarr[1] < 2
|
||||
ubarr[1] = ubarr[1] <= 2
|
||||
ubarr[1] = ubarr[1] > 3
|
||||
ubarr[1] = ubarr[1] >= 3
|
||||
|
||||
; 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])
|
||||
; 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user