mirror of
https://github.com/irmen/prog8.git
synced 2026-04-21 17:16:33 +00:00
Merge branch 'refs/heads/12.1-SNAPSHOT'
# Conflicts: # docs/source/todo.rst # examples/test.p8
This commit is contained in:
@@ -440,6 +440,52 @@ jump p8_label_gen_2
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
fun optimizeImmediateLoadAssociative(replacementOpcode: Opcode) {
|
||||
|
||||
fun getImmediateLoad(reg: Int): Pair<Int, Int>? {
|
||||
// look if the given register gets an immediate value 1 or 2 istructions back
|
||||
// returns (index of load instruction, immediate value) or null.
|
||||
if(idx>=1) {
|
||||
val previous = indexedInstructions[idx-1].value
|
||||
if(previous.opcode==Opcode.LOAD && previous.reg1==reg)
|
||||
return idx-1 to previous.immediate!!
|
||||
}
|
||||
if(idx>=2) {
|
||||
val previous = indexedInstructions[idx-2].value
|
||||
if(previous.opcode==Opcode.LOAD && previous.reg1==reg)
|
||||
return idx-2 to previous.immediate!!
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
val immediate1 = getImmediateLoad(ins.reg1!!)
|
||||
if(immediate1!=null) {
|
||||
chunk.instructions[idx] = IRInstruction(replacementOpcode, ins.type, reg1 = ins.reg2, immediate = immediate1.second)
|
||||
chunk.instructions.removeAt(immediate1.first)
|
||||
changed=true
|
||||
} else {
|
||||
val immediate2 = getImmediateLoad(ins.reg2!!)
|
||||
if (immediate2 != null) {
|
||||
chunk.instructions[idx] = IRInstruction(replacementOpcode, ins.type, reg1 = ins.reg1, immediate = immediate2.second)
|
||||
chunk.instructions.removeAt(immediate2.first)
|
||||
changed=true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try to use immediate arithmetic instruction if possible
|
||||
when(ins.opcode) {
|
||||
Opcode.ADDR -> optimizeImmediateLoadAssociative(Opcode.ADD)
|
||||
Opcode.MULR -> optimizeImmediateLoadAssociative(Opcode.MUL)
|
||||
Opcode.MULSR -> optimizeImmediateLoadAssociative(Opcode.MULS)
|
||||
// Opcode.SUBR -> TODO("ir peephole Subr")
|
||||
// Opcode.DIVR -> TODO("ir peephole Divr")
|
||||
// Opcode.DIVSR -> TODO("ir peephole Divsr")
|
||||
// Opcode.MODR -> TODO("ir peephole Modr")
|
||||
// Opcode.DIVMODR -> TODO("ir peephole DivModr")
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
@@ -2093,7 +2093,9 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(memread: DirectMemoryRead) {
|
||||
if(!allowedMemoryAccessAddressExpression(memread.addressExpression, program))
|
||||
if(memread.addressExpression.inferType(program).isLong)
|
||||
errors.err("long address not yet supported", memread.addressExpression.position)
|
||||
else if(!allowedMemoryAccessAddressExpression(memread.addressExpression, program))
|
||||
errors.err("invalid address type for memory access, expected ^^ubyte or just uword", memread.position)
|
||||
|
||||
val pointervar = memread.addressExpression as? IdentifierReference
|
||||
@@ -2126,7 +2128,9 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(memwrite: DirectMemoryWrite) {
|
||||
if(!allowedMemoryAccessAddressExpression(memwrite.addressExpression, program))
|
||||
if(memwrite.addressExpression.inferType(program).isLong)
|
||||
errors.err("long address not yet supported", memwrite.addressExpression.position)
|
||||
else if(!allowedMemoryAccessAddressExpression(memwrite.addressExpression, program))
|
||||
errors.err("invalid address type for memory access, expected ^^ubyte or just uword", memwrite.position)
|
||||
|
||||
val pointervar = memwrite.addressExpression as? IdentifierReference
|
||||
|
||||
@@ -339,8 +339,13 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
}
|
||||
|
||||
override fun after(memread: DirectMemoryRead, parent: Node): Iterable<IAstModification> {
|
||||
// make sure the memory address is an uword or a pointer (to whatever type), otherwise cast
|
||||
// make sure the memory address is an uword or long or a pointer (to whatever type), otherwise cast
|
||||
val dt = memread.addressExpression.inferType(program).getOr(DataType.UWORD)
|
||||
if(dt.isLong) {
|
||||
val constAddr = memread.addressExpression.constValue(program)?.number
|
||||
if(constAddr==null || constAddr>=65536)
|
||||
return noModifications
|
||||
}
|
||||
if(dt.isUndefined || dt.isUnsignedWord || dt.isPointer)
|
||||
return noModifications
|
||||
|
||||
@@ -354,8 +359,13 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
}
|
||||
|
||||
override fun after(memwrite: DirectMemoryWrite, parent: Node): Iterable<IAstModification> {
|
||||
// make sure the memory address is an uword or a pointer (to whatever type), otherwise cast
|
||||
// make sure the memory address is an uword or long or a pointer (to whatever type), otherwise cast
|
||||
val dt = memwrite.addressExpression.inferType(program).getOr(DataType.UWORD)
|
||||
if(dt.isLong) {
|
||||
val constAddr = memwrite.addressExpression.constValue(program)?.number
|
||||
if(constAddr==null || constAddr>=65536)
|
||||
return noModifications
|
||||
}
|
||||
if(dt.isUndefined || dt.isUnsignedWord || dt.isPointer)
|
||||
return noModifications
|
||||
|
||||
|
||||
@@ -480,18 +480,31 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
|
||||
override fun after(addressOf: AddressOf, parent: Node): Iterable<IAstModification> {
|
||||
if(addressOf.arrayIndex!=null) {
|
||||
val tgt = addressOf.identifier?.constValue(program)
|
||||
if (tgt != null && tgt.type.isInteger) {
|
||||
// &constant[idx] --> constant + idx
|
||||
val indexExpr = addressOf.arrayIndex!!.indexExpr
|
||||
val right = if(indexExpr.inferType(program) issimpletype tgt.type)
|
||||
indexExpr
|
||||
else
|
||||
TypecastExpression(indexExpr, DataType.forDt(tgt.type), true, indexExpr.position)
|
||||
val add = BinaryExpression(tgt, "+", right, addressOf.position)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(addressOf, add, parent)
|
||||
)
|
||||
val tgt = addressOf.identifier
|
||||
if(tgt!=null) {
|
||||
val constAddress = tgt.constValue(program)
|
||||
if (constAddress != null && constAddress.type.isInteger) {
|
||||
// &constant[idx] --> constant + idx
|
||||
val indexExpr = addressOf.arrayIndex!!.indexExpr
|
||||
val right = if (indexExpr.inferType(program) issimpletype constAddress.type)
|
||||
indexExpr
|
||||
else
|
||||
TypecastExpression(indexExpr, DataType.forDt(constAddress.type), true, indexExpr.position)
|
||||
val add = BinaryExpression(constAddress, "+", right, addressOf.position)
|
||||
return listOf(IAstModification.ReplaceNode(addressOf, add, parent))
|
||||
} else {
|
||||
val decl = tgt.targetVarDecl()
|
||||
if(decl!=null && decl.datatype.isInteger) {
|
||||
// &addressvar[idx] --> addressvar + idx
|
||||
val indexExpr = addressOf.arrayIndex!!.indexExpr
|
||||
val right = if (indexExpr.inferType(program) istype decl.datatype)
|
||||
indexExpr
|
||||
else
|
||||
TypecastExpression(indexExpr, decl.datatype, true, indexExpr.position)
|
||||
val add = BinaryExpression(tgt, "+", right, addressOf.position)
|
||||
return listOf(IAstModification.ReplaceNode(addressOf, add, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
|
||||
@@ -16,10 +16,7 @@ import prog8.ast.expressions.PrefixExpression
|
||||
import prog8.ast.statements.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.source.SourceCode
|
||||
import prog8.code.target.C128Target
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.PETTarget
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8.code.target.*
|
||||
import prog8tests.helpers.*
|
||||
|
||||
|
||||
@@ -438,4 +435,24 @@ main {
|
||||
errors.errors[0] shouldContain "8:9: cannot assign to an array or string that is located in ROM"
|
||||
errors.errors[1] shouldContain "9:9: cannot assign to an array or string that is located in ROM"
|
||||
}
|
||||
|
||||
test("long addresses not yet supported in memread and memwrite") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
const long bufferll = 888888
|
||||
long @shared addrlv = 777777
|
||||
|
||||
cx16.r0L = bufferll[2]
|
||||
cx16.r1L = @(999999)
|
||||
cx16.r2L = @(addrlv)
|
||||
}
|
||||
}"""
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(Cx16Target(), true, src, outputDir, errors = errors, writeAssembly = false) shouldBe null
|
||||
errors.errors.size shouldBe 3
|
||||
errors.errors[0] shouldContain "long address not yet supported"
|
||||
errors.errors[1] shouldContain "long address not yet supported"
|
||||
errors.errors[2] shouldContain "long address not yet supported"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -306,26 +306,34 @@ main {
|
||||
(waDeclV as NumericLiteral).number shouldBe 40960.0
|
||||
}
|
||||
|
||||
test("address of a const uword pointer array expression") {
|
||||
test("address of a const integer pointer array expression") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
const uword buffer = 2000
|
||||
const long bufferl = 999999
|
||||
uword @shared addr = &buffer[2]
|
||||
|
||||
const ubyte width = 100
|
||||
ubyte @shared i
|
||||
ubyte @shared j
|
||||
uword @shared addr2 = &buffer[i * width + j]
|
||||
long @shared addr2 = &bufferl[2]
|
||||
const uword width = 100
|
||||
uword @shared addr3 = &buffer[width]
|
||||
long @shared addr4 = &bufferl[width]
|
||||
}
|
||||
}"""
|
||||
val result = compileText(Cx16Target(), true, src, outputDir, writeAssembly = true)!!
|
||||
val st = result.compilerAst.entrypoint.statements
|
||||
st.size shouldBe 11
|
||||
val assignAddr = (st[2] as Assignment).value
|
||||
(assignAddr as NumericLiteral).number shouldBe 2002.0
|
||||
val assignAddr2 = (st[9] as Assignment).value as BinaryExpression
|
||||
assignAddr2.operator shouldBe "+"
|
||||
st.size shouldBe 12
|
||||
val assignAddr = (st[3] as Assignment).value as NumericLiteral
|
||||
assignAddr.number shouldBe 2002.0
|
||||
assignAddr.type shouldBe BaseDataType.UWORD
|
||||
val assignAddr2 = (st[5] as Assignment).value as NumericLiteral
|
||||
assignAddr2.number shouldBe 1000001.0
|
||||
assignAddr2.type shouldBe BaseDataType.LONG
|
||||
val assignAddr3 = (st[8] as Assignment).value as NumericLiteral
|
||||
assignAddr3.number shouldBe 2100
|
||||
assignAddr3.type shouldBe BaseDataType.UWORD
|
||||
val assignAddr4 = (st[10] as Assignment).value as NumericLiteral
|
||||
assignAddr4.number shouldBe 1000099.0
|
||||
assignAddr4.type shouldBe BaseDataType.LONG
|
||||
}
|
||||
|
||||
test("out of range const byte and word give correct error") {
|
||||
|
||||
@@ -572,14 +572,15 @@ data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: Array
|
||||
val index = arrayIndex?.constIndex()
|
||||
if (index != null) {
|
||||
address += when {
|
||||
target.datatype.isUnsignedWord -> index
|
||||
target.datatype.isInteger -> index
|
||||
target.datatype.isArray -> program.memsizer.memorySize(targetVar.datatype, index)
|
||||
else -> throw FatalAstException("need array or uword ptr")
|
||||
else -> throw FatalAstException("need array or ptr")
|
||||
}
|
||||
} else
|
||||
return null
|
||||
}
|
||||
return NumericLiteral(BaseDataType.UWORD, address, position)
|
||||
val addressType = if(targetVar.datatype.isLong) BaseDataType.LONG else BaseDataType.UWORD
|
||||
return NumericLiteral(addressType, address, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1416,14 +1417,14 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
}
|
||||
|
||||
// the value of a variable can (temporarily) be a different type as the vardecl itself.
|
||||
// don't return the value if the types don't match yet!
|
||||
val value = vardecl.value?.constValue(program)
|
||||
if(value==null || value.type==vardecl.datatype.base)
|
||||
return value
|
||||
val optimal = NumericLiteral.optimalNumeric(value.number, value.position)
|
||||
if(optimal.type==vardecl.datatype.base)
|
||||
return optimal
|
||||
return null
|
||||
val casted = value.cast(vardecl.datatype.base, true)
|
||||
return if(casted.isValid)
|
||||
casted.valueOrZero()
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
||||
@@ -91,7 +91,7 @@ IR/VM
|
||||
- implement fast code paths for TODO("inplace split....
|
||||
- implement more TODOs in AssignmentGen
|
||||
- do something with the 'split' tag on split word arrays
|
||||
- add more optimizations in IRPeepholeOptimizer
|
||||
- add more optimizations in IRPeepholeOptimizer, implement the TODOs in there at least
|
||||
- extend the index range from 0-255 to 0-32767 in the LOADX, STOREX, LOADFIELD, STOREFIELD etc instructions (not compatible with 8 bit 6502, but the 68000 can use that)
|
||||
- idea: replace all scalar variables that are not @shared by an allocated register. Keep a table of the variable to register mapping (including the datatype)
|
||||
global initialization values are simply a list of LOAD instructions.
|
||||
|
||||
+7
-12
@@ -1,16 +1,11 @@
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
printf([1111,2,3,4444])
|
||||
printf([1111,2,3,"bar"])
|
||||
printf([1,2,3])
|
||||
printf([1111,2,3,-4444])
|
||||
|
||||
}
|
||||
|
||||
sub printf(uword argspointer) {
|
||||
cx16.r0++
|
||||
const long buffer = 2000
|
||||
const long bufferl = 999999
|
||||
uword @shared addr = &buffer[2]
|
||||
long @shared addr2 = &bufferl[2]
|
||||
const long width = 100
|
||||
uword @shared addr3 = &buffer[width]
|
||||
long @shared addr4 = &bufferl[width]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user