optimize % and logical operations on words

This commit is contained in:
Irmen de Jong 2019-01-11 20:24:36 +01:00
parent 6fe0959fdc
commit c0920a43a3
4 changed files with 198 additions and 262 deletions

View File

@ -3052,6 +3052,82 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
" lda ${segment[0].callLabel} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
},
// push memory word | wordvalue
AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_WORD, Opcode.BITOR_WORD),
listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_WORD, Opcode.BITOR_WORD)) { segment ->
"""
lda ${hexVal(segment[0])}
ora #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
lda ${hexValPlusOne(segment[0])}
ora #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
dex
"""
},
// push memory word & wordvalue
AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_WORD, Opcode.BITAND_WORD),
listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_WORD, Opcode.BITAND_WORD)) { segment ->
"""
lda ${hexVal(segment[0])}
and #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
lda ${hexValPlusOne(segment[0])}
and #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
dex
"""
},
// push memory word ^ wordvalue
AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_WORD, Opcode.BITXOR_WORD),
listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_WORD, Opcode.BITXOR_WORD)) { segment ->
"""
lda ${hexVal(segment[0])}
eor #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
lda ${hexValPlusOne(segment[0])}
eor #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
dex
"""
},
// push var word | wordvalue
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_WORD, Opcode.BITOR_WORD)) { segment ->
"""
lda ${segment[0].callLabel}
ora #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
lda ${segment[0].callLabel}+1
ora #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
dex
"""
},
// push var word & wordvalue
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_WORD, Opcode.BITAND_WORD)) { segment ->
"""
lda ${segment[0].callLabel}
and #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
lda ${segment[0].callLabel}+1
and #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
dex
"""
},
// push var word ^ wordvalue
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_WORD, Opcode.BITXOR_WORD)) { segment ->
"""
lda ${segment[0].callLabel}
eor #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
lda ${segment[0].callLabel}+1
eor #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
dex
"""
},
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD)) { segment ->
"""
lda ${segment[0].callLabel}

View File

@ -13,8 +13,6 @@ import kotlin.math.log2
-X + A -> A - X
X+ (-A) -> X - A
X- (-A) -> X + A
X % 1 -> constant 0 (if X is byte/word)
X % 2 -> X and 1 (if X is byte/word)
todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call + introduce variable to hold it)
@ -120,6 +118,7 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
"+" -> return optimizeAdd(expr, leftVal, rightVal)
"-" -> return optimizeSub(expr, leftVal, rightVal)
"**" -> return optimizePower(expr, leftVal, rightVal)
"%" -> return optimizeRemainder(expr, leftVal, rightVal)
}
return expr
}
@ -349,6 +348,30 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
return expr
}
private fun optimizeRemainder(expr: BinaryExpression, leftVal: LiteralValue?, rightVal: LiteralValue?): IExpression {
if(leftVal==null && rightVal==null)
return expr
// simplify assignments A = B <operator> C
val cv = rightVal?.asIntegerValue?.toDouble()
when(expr.operator) {
"%" -> {
if (cv == 1.0) {
optimizationsDone++
return LiteralValue.fromNumber(0, expr.resultingDatatype(namespace, heap)!!, expr.position)
} else if (cv == 2.0) {
optimizationsDone++
expr.operator = "&"
expr.right = LiteralValue.optimalInteger(1, expr.position)
return expr
}
}
}
return expr
}
private fun optimizeDivision(expr: BinaryExpression, leftVal: LiteralValue?, rightVal: LiteralValue?): IExpression {
if(leftVal==null && rightVal==null)
return expr
@ -379,8 +402,7 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
if(leftDt in IntegerDatatypes) {
// divided by a power of two => shift right
optimizationsDone++
val numshifts = log2(cv)
println("DIV: SHIFT RIGHT $cv -> $numshifts") // TODO
val numshifts = log2(cv).toInt()
return BinaryExpression(expr.left, ">>", LiteralValue.optimalInteger(numshifts, expr.position), expr.position)
}
}
@ -388,8 +410,7 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
if(leftDt in IntegerDatatypes) {
// divided by a negative power of two => negate, then shift right
optimizationsDone++
val numshifts = log2(-cv)
println("DIV: SHIFT RIGHT $cv -> $numshifts") // TODO
val numshifts = log2(-cv).toInt()
return BinaryExpression(PrefixExpression("-", expr.left, expr.position), ">>", LiteralValue.optimalInteger(numshifts, expr.position), expr.position)
}
}

View File

@ -168,113 +168,112 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
if(assignment.aug_op!=null)
throw AstException("augmented assignments should have been converted to normal assignments before this optimizer")
// remove assignments that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc
if(assignment.targets.size==1) {
val target=assignment.targets[0]
if(same(target, assignment.value)) {
optimizationsDone++
return NopStatement(assignment.position)
}
val targetDt = target.determineDatatype(namespace, heap, assignment)
val targetDt = target.determineDatatype(namespace, heap, assignment)!!
val bexpr=assignment.value as? BinaryExpression
if(bexpr!=null && same(target, bexpr.left)) {
if(bexpr!=null) {
val cv = bexpr.right.constValue(namespace, heap)?.asNumericValue?.toDouble()
if(cv!=null) {
when (bexpr.operator) {
"+" -> {
if (cv==0.0) {
optimizationsDone++
return NopStatement(assignment.position)
} else if(cv in 1.0..8.0 && targetDt in IntegerDatatypes && floor(cv)==cv) {
// replace by several INCs
val decs = AnonymousScope(mutableListOf(), assignment.position)
repeat(cv.toInt()) {
decs.statements.add(PostIncrDecr(target, "++", assignment.position))
if (same(target, bexpr.left)) {
// remove assignments that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc
// A = A <operator> B
when (bexpr.operator) {
"+" -> {
if (cv == 0.0) {
optimizationsDone++
return NopStatement(assignment.position)
} else if (cv in 1.0..8.0 && targetDt in IntegerDatatypes && floor(cv) == cv) {
// replace by several INCs
val decs = AnonymousScope(mutableListOf(), assignment.position)
repeat(cv.toInt()) {
decs.statements.add(PostIncrDecr(target, "++", assignment.position))
}
return decs
}
return decs
}
}
"-" -> {
if (cv==0.0) {
optimizationsDone++
return NopStatement(assignment.position)
} else if(cv in 1.0..8.0 && targetDt in IntegerDatatypes && floor(cv)==cv) {
// replace by several DECs
val decs = AnonymousScope(mutableListOf(), assignment.position)
repeat(cv.toInt()) {
decs.statements.add(PostIncrDecr(target, "--", assignment.position))
"-" -> {
if (cv == 0.0) {
optimizationsDone++
return NopStatement(assignment.position)
} else if (cv in 1.0..8.0 && targetDt in IntegerDatatypes && floor(cv) == cv) {
// replace by several DECs
val decs = AnonymousScope(mutableListOf(), assignment.position)
repeat(cv.toInt()) {
decs.statements.add(PostIncrDecr(target, "--", assignment.position))
}
return decs
}
return decs
}
}
"*" -> if (cv==1.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
"%" -> if (cv==1.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
"/" -> if (cv==1.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
"**" -> if (cv==1.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
"|" -> if (cv==0.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
"^" -> if (cv==0.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
"<<" -> {
if(cv==0.0) {
"*" -> if (cv == 1.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
if(((targetDt==DataType.UWORD || targetDt==DataType.WORD) && cv >15.0) ||
((targetDt==DataType.UBYTE || targetDt==DataType.BYTE) && cv > 7.0)) {
assignment.value = LiteralValue.optimalInteger(0, assignment.value.position)
assignment.value.linkParents(assignment)
optimizationsDone++
}
else {
// replace by in-place lsl(...) call
val scope = AnonymousScope(mutableListOf(), assignment.position)
var numshifts = cv.toInt()
while(numshifts>0) {
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("lsl"), assignment.position), mutableListOf(bexpr.left), assignment.position))
numshifts--
}
optimizationsDone++
return scope
}
}
">>" -> {
if(cv==0.0) {
"/" -> if (cv == 1.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
if(((targetDt==DataType.UWORD || targetDt==DataType.WORD) && cv >15.0) ||
((targetDt==DataType.UBYTE || targetDt==DataType.BYTE) && cv > 7.0)) {
assignment.value = LiteralValue.optimalInteger(0, assignment.value.position)
assignment.value.linkParents(assignment)
"**" -> if (cv == 1.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
else {
// replace by in-place lsr(...) call
val scope = AnonymousScope(mutableListOf(), assignment.position)
var numshifts = cv.toInt()
while(numshifts>0) {
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("lsr"), assignment.position), mutableListOf(bexpr.left), assignment.position))
numshifts--
}
"|" -> if (cv == 0.0) {
optimizationsDone++
return scope
return NopStatement(assignment.position)
}
"^" -> if (cv == 0.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
"<<" -> {
if (cv == 0.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
if (((targetDt == DataType.UWORD || targetDt == DataType.WORD) && cv > 15.0) ||
((targetDt == DataType.UBYTE || targetDt == DataType.BYTE) && cv > 7.0)) {
assignment.value = LiteralValue.optimalInteger(0, assignment.value.position)
assignment.value.linkParents(assignment)
optimizationsDone++
} else {
// replace by in-place lsl(...) call
val scope = AnonymousScope(mutableListOf(), assignment.position)
var numshifts = cv.toInt()
while (numshifts > 0) {
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("lsl"), assignment.position), mutableListOf(bexpr.left), assignment.position))
numshifts--
}
optimizationsDone++
return scope
}
}
">>" -> {
if (cv == 0.0) {
optimizationsDone++
return NopStatement(assignment.position)
}
if (((targetDt == DataType.UWORD || targetDt == DataType.WORD) && cv > 15.0) ||
((targetDt == DataType.UBYTE || targetDt == DataType.BYTE) && cv > 7.0)) {
assignment.value = LiteralValue.optimalInteger(0, assignment.value.position)
assignment.value.linkParents(assignment)
optimizationsDone++
} else {
// replace by in-place lsr(...) call
val scope = AnonymousScope(mutableListOf(), assignment.position)
var numshifts = cv.toInt()
while (numshifts > 0) {
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("lsr"), assignment.position), mutableListOf(bexpr.left), assignment.position))
numshifts--
}
optimizationsDone++
return scope
}
}
}
}

View File

@ -1,4 +1,5 @@
%import c64utils
%import c64flt
~ main {
@ -12,178 +13,17 @@
uword uw2
word w = 1000
word w2
float f1 = 1.1
float f2 = 2.2
ub2=i*1
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*2
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*3
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*4
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*5
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*6
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*7
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*8
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*9
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*10
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*11
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*12
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*13
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*14
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*15
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*16
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*17
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*18
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*19
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*20
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*21
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*22
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*23
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*24
c64scr.print_ub(ub2)
c64.CHROUT('\n')
ub2=i*25
c64scr.print_ub(ub2)
c64.CHROUT('\n')
i=5
ub2=i*40
c64scr.print_ub(ub2)
c64.CHROUT('\n')
c64.CHROUT('\n')
b2=j*1
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*2
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*3
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*4
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*5
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*6
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*7
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*8
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*9
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*10
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*11
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*12
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*13
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*14
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*15
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*16
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*17
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*18
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*19
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*20
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*21
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*22
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*23
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*24
c64scr.print_b(b2)
c64.CHROUT('\n')
b2=j*25
c64scr.print_b(b2)
c64.CHROUT('\n')
j=3
b2=j*40
c64scr.print_b(b2)
c64.CHROUT('\n')
c64.CHROUT('\n')
;@todo multiplication by negative values
;@todo the same, for uword and word
i %= 1
i %= 2
ub2 = i % 1
ub2 = i % 2
uw %= 1
uw %= 2
uw2 = uw % 1
uw2 = uw % 2
}
}