IR: optimize load+add+load into single loadm with offset (also store)

update gradle wrapper to 9.2.0
This commit is contained in:
Irmen de Jong
2025-12-15 21:40:47 +01:00
parent 1799b5f00c
commit d157d03ea0
11 changed files with 41 additions and 11 deletions

View File

@@ -55,6 +55,8 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
|| cleanupPushPop(chunk1, indexedInstructions) || cleanupPushPop(chunk1, indexedInstructions)
|| simplifyConstantReturns(chunk1, indexedInstructions) || simplifyConstantReturns(chunk1, indexedInstructions)
|| removeNeedlessLoads(chunk1, indexedInstructions) || removeNeedlessLoads(chunk1, indexedInstructions)
|| useArrayIndexingInsteadOfAdds(chunk1, indexedInstructions)
|| removeNops(chunk1, indexedInstructions) // last time, in case one of the optimizers replaced something with a nop
} while (changed) } while (changed)
} }
} }
@@ -553,4 +555,40 @@ jump p8_label_gen_2
} }
return changed return changed
} }
private fun useArrayIndexingInsteadOfAdds(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if (ins.opcode == Opcode.ADD && ins.immediate!=null && idx>0) {
val load = indexedInstructions[idx-1].value
if((load.opcode==Opcode.LOAD) && load.labelSymbol!=null) {
val lastInstruction = indexedInstructions[idx+1].value
if(lastInstruction.opcode==Opcode.LOADI) {
val targetRegister = lastInstruction.reg1!!
if(ins.reg1==lastInstruction.reg2!! && load.reg1==lastInstruction.reg2!!) {
val loadm = IRInstruction(Opcode.LOADM, lastInstruction.type, reg1=targetRegister, labelSymbol = load.labelSymbol, symbolOffset = ins.immediate)
chunk.instructions[idx-1] = loadm
chunk.instructions.removeAt(idx+1)
chunk.instructions.removeAt(idx)
changed = true
}
} else if(lastInstruction.opcode==Opcode.STOREI) {
val targetRegister = lastInstruction.reg1!!
if(ins.reg1==lastInstruction.reg2!! && load.reg1==lastInstruction.reg2!!) {
val valueLoad = indexedInstructions[idx-2].value
if(valueLoad.opcode==Opcode.LOAD && valueLoad.reg1==targetRegister) {
val storem = IRInstruction(Opcode.STOREM, lastInstruction.type, reg1=valueLoad.reg1, labelSymbol = load.labelSymbol, symbolOffset = ins.immediate)
chunk.instructions[idx-1] = storem
chunk.instructions.removeAt(idx+1)
chunk.instructions.removeAt(idx)
changed = true
}
}
}
}
}
}
return changed
}
} }

View File

@@ -1,6 +1,5 @@
Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit cfa4355a in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c128.p8 Compiling program import-all-c128.p8

View File

@@ -1,6 +1,5 @@
Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit cfa4355a in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c64.p8 Compiling program import-all-c64.p8

View File

@@ -1,6 +1,5 @@
Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit cfa4355a in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-cx16.p8 Compiling program import-all-cx16.p8

View File

@@ -1,6 +1,5 @@
Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit cfa4355a in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-pet32.p8 Compiling program import-all-pet32.p8

View File

@@ -1,6 +1,5 @@
Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v12.0.1 by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit cfa4355a in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-virtual.p8 Compiling program import-all-virtual.p8

View File

@@ -61,9 +61,8 @@ Future Things and Ideas
IR/VM IR/VM
----- -----
- optimize away the use of ADD to offset from a label. It's possible to do that with a label-offset in the instruction itself: loadm.b r7,main.start.array2+255 (it works for 255 but after that it starts using ADD!)
- get rid of LOADX/STOREX/STOREZX, LOADINDEXED/STOREINDEXED just use add + loadi / storei?
- extend the index range from 0-255 to 0-32767 in the LOADX, STOREX, STOREZX, LOADINDEXED, STOREINDEXED etc instructions (not compatible with 8 bit 6502, but the 68000 can use that) - extend the index range from 0-255 to 0-32767 in the LOADX, STOREX, STOREZX, LOADINDEXED, STOREINDEXED etc instructions (not compatible with 8 bit 6502, but the 68000 can use that)
- get rid of LOADX/STOREX/STOREZX, LOADINDEXED/STOREINDEXED just use add + loadi / storei?
- if float<0 / if word<0 uses sgn or load, but still use a bgt etc instruction after that with a #0 operand even though the sgn and load instructions sets the status bits already, so just use bstneg etc - if float<0 / if word<0 uses sgn or load, but still use a bgt etc instruction after that with a #0 operand even though the sgn and load instructions sets the status bits already, so just use bstneg etc
- add and sub instructions should modify the status flags so an explicit compare to zero can be avoided for example: if cx16.r0sL + cx16.r1sL <= 0 now compiles into: addr.b r10,r11 / bgts.b r10,#0,label - add and sub instructions should modify the status flags so an explicit compare to zero can be avoided for example: if cx16.r0sL + cx16.r1sL <= 0 now compiles into: addr.b r10,r11 / bgts.b r10,#0,label
- getting it in shape for code generation: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!) - getting it in shape for code generation: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)

View File

@@ -26,8 +26,6 @@ main {
%ir {{ %ir {{
loadm.b r1007,main.start.array2+255 loadm.b r1007,main.start.array2+255
storem.b r1007,$ff02 storem.b r1007,$ff02
loadm.b r1007,main.start.array2+256
storem.b r1007,$ff04
load.w r1009,main.start.array2 load.w r1009,main.start.array2
add.w r1009,#$0100 add.w r1009,#$0100
loadi.b r1008,r1009 loadi.b r1008,r1009

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@@ -306,7 +306,7 @@ class IRProgram(val name: String,
fun convert(asmChunk: IRInlineAsmChunk): IRCodeChunks { fun convert(asmChunk: IRInlineAsmChunk): IRCodeChunks {
val chunks = mutableListOf<IRCodeChunkBase>() val chunks = mutableListOf<IRCodeChunkBase>()
var chunk = IRCodeChunk(asmChunk.label, null) var chunk = IRCodeChunk(asmChunk.label, null)
asmChunk.assembly.lineSequence().forEach { asmChunk.assembly.lineSequence().filter{it.isNotBlank()}.forEach {
val parsed = parseIRCodeLine(it.trim()) val parsed = parseIRCodeLine(it.trim())
parsed.fold( parsed.fold(
ifLeft = { instruction -> chunk += instruction }, ifLeft = { instruction -> chunk += instruction },