diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index c2bfe5102..9c857950f 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -1624,28 +1624,62 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val right = binExpr.right as? PtIdentifier require(binExpr.operator=="." && left!=null && right!=null) {"invalid dereference expression ${binExpr.position}"} val result = mutableListOf() - val indexedTr = translateExpression(left) - result += indexedTr.chunks - val pointerReg = indexedTr.resultReg - val struct = left.type.dereference().subType as? StStruct - require(indexedTr.dt== IRDataType.WORD && struct!=null) - val field = struct.getField(right.name, this.codeGen.program.memsizer) - val vmDt = irType(field.first) + val field: Pair + val pointerReg: Int + var extraFieldOffset = 0 + + if(left.type.isStructInstance) { + + // indexing on a pointer directly + // fetch pointer address, determine struct and field, add index * structsize + if(left.variable!=null) { + val pointerTr = translateExpression(left.variable!!) + result += pointerTr.chunks + pointerReg = pointerTr.resultReg + } else if(left.pointerderef!=null) { + TODO("get pointer from deref $left") + } else { + throw AssemblyError("weird arrayindexer $left") + } + val struct = left.type.subType!! as StStruct + val constindex = left.index as? PtNumber + if(constindex!=null) { + extraFieldOffset = struct.size.toInt() * constindex.number.toInt() + } else { + val (chunks, indexReg) = codeGen.loadIndexReg(left.index, struct.size.toInt(), true, false) + result += chunks + addInstr(result, IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1 = pointerReg, reg2 = indexReg), null) + } + field = struct.getField(right.name, codeGen.program.memsizer) + + } else { + + // indexing on an array with pointers + // fetch the pointer from the array, determine the struct & field + val indexedTr = translateExpression(left) + result += indexedTr.chunks + pointerReg = indexedTr.resultReg + val struct = left.type.dereference().subType as? StStruct + require(indexedTr.dt == IRDataType.WORD && struct != null) + field = struct.getField(right.name, codeGen.program.memsizer) + } + + // add field offset to pointer and load the value into the result register + val fieldVmDt = irType(field.first) var resultFpReg = -1 var resultReg = -1 - if(vmDt==IRDataType.FLOAT) + if (fieldVmDt == IRDataType.FLOAT) resultFpReg = codeGen.registers.next(IRDataType.FLOAT) else - resultReg = codeGen.registers.next(vmDt) - + resultReg = codeGen.registers.next(fieldVmDt) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.ADD, IRDataType.WORD, reg1 = pointerReg, immediate = field.second.toInt()) - it += if(vmDt==IRDataType.FLOAT) + it += IRInstruction(Opcode.ADD, IRDataType.WORD, reg1 = pointerReg, immediate = field.second.toInt() + extraFieldOffset) + it += if (fieldVmDt == IRDataType.FLOAT) IRInstruction(Opcode.LOADI, IRDataType.FLOAT, fpReg1 = resultFpReg, reg1 = pointerReg) else - IRInstruction(Opcode.LOADI, vmDt, reg1 = resultReg, reg2 = pointerReg) + IRInstruction(Opcode.LOADI, fieldVmDt, reg1 = resultReg, reg2 = pointerReg) } - return ExpressionCodeResult(result, vmDt, resultReg, resultFpReg) + return ExpressionCodeResult(result, fieldVmDt, resultReg, resultFpReg) } internal fun traverseRestOfDerefChainToCalculateFinalAddress(targetPointerDeref: PtPointerDeref, pointerReg: Int): Pair { diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index b1bcc2c1a..2b30f89bd 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -389,22 +389,6 @@ _after: // this will be further modified elsewhere val ident = IdentifierReference(right.chain, right.position) return listOf(IAstModification.ReplaceNode(expr.right, ident, expr)) - - // TODO hmmm , replace cx16.r1 = listarray[2]^^.value with a temp pointer var to contain the indexed value -// val assign = expr.parent as? Assignment -// if(assign!=null) { -// val ptrDt = expr.left.inferType(program).getOrUndef() -// val pointerVar = VarDecl.createAuto(ptrDt) -// val pointerIdent = IdentifierReference(pointerVar.name.split("."), expr.position) -// val tgt = AssignTarget(pointerIdent, null, null, null, false, null, position = expr.position) -// val assignPtr = Assignment(tgt, expr.left, AssignmentOrigin.USERCODE, expr.position) -// val derefValue = PtrDereference(pointerIdent.nameInSource + right.chain, false, expr.position) -// return listOf( -// IAstModification.InsertBefore(assign, assignPtr, assign.parent as IStatementContainer), -// IAstModification.ReplaceNode(assign.value, derefValue, assign), -// IAstModification.InsertFirst(pointerVar, expr.definingSubroutine!!) -// ) -// } } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index f17e366f2..aa65db9c5 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,7 +1,6 @@ TODO ==== -fix ^^Node nodes / cx16.r0L = nodes[2].weight compiler crash disallow ^^str diff --git a/examples/test.p8 b/examples/test.p8 index e78779afb..be33a181f 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,12 +1,55 @@ +%import textio + main { struct Node { + ^^Node next ubyte weight } - ^^Node nodes + ^^Node nodes = 2000 sub start() { - cx16.r0L = nodes[2].weight ;TODO fix this compiler crash + init() + cx16.r0L = nodes[2].weight + cx16.r1L = thing.things[2].weight + + txt.print_ub(cx16.r0L) + txt.spc() + txt.print_ub(cx16.r1L) + txt.nl() + + cx16.r9L = 3 + cx16.r0L = nodes[cx16.r9L].weight + cx16.r1L = thing.things[cx16.r9L].weight + + txt.print_ub(cx16.r0L) + txt.spc() + txt.print_ub(cx16.r1L) + txt.nl() } + + sub init() { + sys.memset(2000, 100, 99) + sys.memset(3000, 100, 99) + + ; NNW NNW NNW NNW + @(2000+2) = 11 + @(2000+5) = 22 + @(2000+8) = 33 + @(2000+11) = 44 + + @(3000+2) = 101 + @(3000+5) = 102 + @(3000+8) = 103 + @(3000+11) = 104 + } +} + +thing { + struct Thing { + ^^Thing next + ubyte weight + } + ^^Thing things = 3000 }