mirror of
https://github.com/irmen/prog8.git
synced 2024-09-08 10:55:08 +00:00
use memcopy to assign arrays
This commit is contained in:
parent
d787795759
commit
4f8d4a9585
@ -268,32 +268,31 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
||||
override fun before(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
val valueType = assignment.value.inferType(program)
|
||||
val targetType = assignment.target.inferType(program)
|
||||
var assignments = emptyList<Assignment>()
|
||||
|
||||
if(targetType.istype(DataType.STRUCT) && (valueType.istype(DataType.STRUCT) || valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes )) {
|
||||
assignments = if (assignment.value is ArrayLiteralValue) {
|
||||
flattenStructAssignmentFromStructLiteral(assignment) // 'structvar = [ ..... ] '
|
||||
val assignments = if (assignment.value is ArrayLiteralValue) {
|
||||
throw FatalAstException("array literal should have been translated to a variable at "+assignment.position.toString())
|
||||
} else {
|
||||
flattenStructAssignmentFromIdentifier(assignment) // 'structvar1 = structvar2'
|
||||
flattenStructAssignmentFromIdentifier(assignment)
|
||||
}
|
||||
|
||||
if(assignments.isNotEmpty()) {
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
val scope = assignment.definingScope()
|
||||
assignments.reversed().mapTo(modifications) { IAstModification.InsertAfter(assignment, it, scope) }
|
||||
modifications.add(IAstModification.Remove(assignment, scope))
|
||||
return modifications
|
||||
}
|
||||
}
|
||||
|
||||
if(targetType.typeOrElse(DataType.STRUCT) in ArrayDatatypes && valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes ) {
|
||||
assignments = if (assignment.value is ArrayLiteralValue) {
|
||||
flattenArrayAssignmentFromArrayLiteral(assignment) // 'arrayvar = [ ..... ] '
|
||||
if (assignment.value is ArrayLiteralValue) {
|
||||
throw FatalAstException("array literal should have been translated to a variable at "+assignment.position.toString())
|
||||
} else {
|
||||
flattenArrayAssignmentFromIdentifier(assignment) // 'arrayvar1 = arrayvar2'
|
||||
return copyArrayValue(assignment)
|
||||
}
|
||||
}
|
||||
|
||||
if(assignments.isNotEmpty()) {
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
val scope = assignment.definingScope()
|
||||
assignments.reversed().mapTo(modifications) { IAstModification.InsertAfter(assignment, it, scope) }
|
||||
modifications.add(IAstModification.Remove(assignment, scope))
|
||||
return modifications
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
@ -346,66 +345,37 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun flattenArrayAssignmentFromArrayLiteral(assign: Assignment): List<Assignment> {
|
||||
private fun copyArrayValue(assign: Assignment): List<IAstModification> {
|
||||
val identifier = assign.target.identifier!!
|
||||
val targetVar = identifier.targetVarDecl(program)!!
|
||||
val alv = assign.value as? ArrayLiteralValue
|
||||
return flattenArrayAssign(targetVar, alv, identifier, assign.position)
|
||||
}
|
||||
|
||||
private fun flattenArrayAssignmentFromIdentifier(assign: Assignment): List<Assignment> {
|
||||
val identifier = assign.target.identifier!!
|
||||
val targetVar = identifier.targetVarDecl(program)!!
|
||||
if(targetVar.arraysize==null)
|
||||
errors.err("array has no defined size", assign.position)
|
||||
|
||||
val sourceIdent = assign.value as IdentifierReference
|
||||
val sourceVar = sourceIdent.targetVarDecl(program)!!
|
||||
if(!sourceVar.isArray) {
|
||||
errors.err("value must be an array", sourceIdent.position)
|
||||
errors.err("value must be an array", sourceIdent.position)
|
||||
} else {
|
||||
if (sourceVar.arraysize!!.constIndex() != targetVar.arraysize!!.constIndex())
|
||||
errors.err("element count mismatch", assign.position)
|
||||
if (sourceVar.datatype != targetVar.datatype)
|
||||
errors.err("element type mismatch", assign.position)
|
||||
}
|
||||
|
||||
if(!errors.isEmpty())
|
||||
return emptyList()
|
||||
}
|
||||
val alv = sourceVar.value as? ArrayLiteralValue
|
||||
return flattenArrayAssign(targetVar, alv, identifier, assign.position)
|
||||
}
|
||||
|
||||
private fun flattenArrayAssign(targetVar: VarDecl, alv: ArrayLiteralValue?, identifier: IdentifierReference, position: Position): List<Assignment> {
|
||||
if(targetVar.arraysize==null) {
|
||||
errors.err("array has no defined size", identifier.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
if(alv==null || alv.value.size != targetVar.arraysize!!.constIndex()) {
|
||||
errors.err("element count mismatch", position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// TODO use memcopy instead of individual assignments after certain amount of elements
|
||||
// TODO what does assigning a struct var use?
|
||||
return alv.value.mapIndexed { index, value ->
|
||||
val idx = ArrayIndexedExpression(identifier, ArrayIndex(NumericLiteralValue(DataType.UBYTE, index, position), position), position)
|
||||
Assignment(AssignTarget(null, idx, null, position), value, value.position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun flattenStructAssignmentFromStructLiteral(structAssignment: Assignment): List<Assignment> {
|
||||
val identifier = structAssignment.target.identifier!!
|
||||
val identifierName = identifier.nameInSource.single()
|
||||
val targetVar = identifier.targetVarDecl(program)!!
|
||||
val struct = targetVar.struct!!
|
||||
|
||||
val slv = structAssignment.value as? ArrayLiteralValue
|
||||
if(slv==null || slv.value.size != struct.numberOfElements) {
|
||||
errors.err("element count mismatch", structAssignment.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return struct.statements.zip(slv.value).map { (targetDecl, sourceValue) ->
|
||||
targetDecl as VarDecl
|
||||
val mangled = mangledStructMemberName(identifierName, targetDecl.name)
|
||||
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
||||
val assign = Assignment(AssignTarget(idref, null, null, structAssignment.position),
|
||||
sourceValue, sourceValue.position)
|
||||
assign.linkParents(structAssignment)
|
||||
assign
|
||||
}
|
||||
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assign.position),
|
||||
mutableListOf(
|
||||
AddressOf(sourceIdent, assign.position),
|
||||
AddressOf(identifier, assign.position),
|
||||
NumericLiteralValue.optimalInteger(targetVar.arraysize!!.constIndex()!!, assign.position)
|
||||
),
|
||||
true,
|
||||
assign.position
|
||||
)
|
||||
return listOf(IAstModification.ReplaceNode(assign, memcopy, assign.parent))
|
||||
}
|
||||
|
||||
private fun flattenStructAssignmentFromIdentifier(structAssignment: Assignment): List<Assignment> {
|
||||
|
@ -757,11 +757,12 @@ all(x)
|
||||
1 ('true') if all of the values in the array value x are 'true' (not zero), else 0 ('false')
|
||||
|
||||
len(x)
|
||||
Number of values in the array value x, or the number of characters in a string (excluding the size or 0-byte).
|
||||
Number of values in the array value x, or the number of characters in a string (excluding the 0-byte).
|
||||
Note: this can be different from the number of *bytes* in memory if the datatype isn't a byte. See sizeof().
|
||||
Note: lengths of strings and arrays are determined at compile-time! If your program modifies the actual
|
||||
length of the string during execution, the value of len(string) may no longer be correct!
|
||||
(use strlen function if you want to dynamically determine the length)
|
||||
length of the string during execution, the value of len(s) may no longer be correct!
|
||||
(use the ``string.length`` routine if you want to dynamically determine the length by counting to the
|
||||
first 0-byte)
|
||||
|
||||
max(x)
|
||||
Maximum of the values in the array value x
|
||||
|
@ -2,7 +2,8 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- optimize assigning array and struct variables (multi-element assings -> memcopy)
|
||||
- optimize assigning array and struct variables (multi-element assigns -> memcopy)
|
||||
|
||||
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
|
||||
- optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+1), @(ptr+2))
|
||||
- optimize several inner loops in gfx2
|
||||
|
131
examples/test.p8
131
examples/test.p8
@ -4,103 +4,62 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte ubb = $f4
|
||||
byte bb = -123
|
||||
uword uww = $f4a1
|
||||
word ww = -12345
|
||||
ubyte[] arr1 = [1,2,3]
|
||||
ubyte[] arr2 = [9,9,9]
|
||||
|
||||
conv.str_ub0($0f)
|
||||
txt.print(conv.string_out)
|
||||
arr1[2]=42
|
||||
txt.print_ub(arr2[0])
|
||||
txt.chrout(',')
|
||||
txt.print_ub(arr2[1])
|
||||
txt.chrout(',')
|
||||
txt.print_ub(arr2[2])
|
||||
txt.nl()
|
||||
txt.print_ub0($0f)
|
||||
arr2=[99,88,77]
|
||||
txt.print_ub(arr2[0])
|
||||
txt.chrout(',')
|
||||
txt.print_ub(arr2[1])
|
||||
txt.chrout(',')
|
||||
txt.print_ub(arr2[2])
|
||||
txt.nl()
|
||||
arr2=arr1
|
||||
txt.print_ub(arr2[0])
|
||||
txt.chrout(',')
|
||||
txt.print_ub(arr2[1])
|
||||
txt.chrout(',')
|
||||
txt.print_ub(arr2[2])
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
conv.str_ub(ubb)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_ub(ubb)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
conv.str_ub(8)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_ub(8)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
conv.str_b(bb)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_b(bb)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
conv.str_b(-8)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_b(-8)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
conv.str_ubhex(ubb)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_ubhex(ubb,false)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
struct MyType {
|
||||
uword v1
|
||||
uword w1
|
||||
uword w2
|
||||
}
|
||||
|
||||
conv.str_ubbin(ubb)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_ubbin(ubb,false)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
MyType m1 = [1, 888, 999]
|
||||
MyType m2 = [22, 222, 222]
|
||||
|
||||
conv.str_uwbin(uww)
|
||||
txt.print(conv.string_out)
|
||||
txt.print_uw(m2.v1)
|
||||
txt.chrout(',')
|
||||
txt.print_uw(m2.w1)
|
||||
txt.chrout(',')
|
||||
txt.print_uw(m2.w2)
|
||||
txt.nl()
|
||||
txt.print_uwbin(uww, false)
|
||||
m2 = [111,222,333]
|
||||
txt.print_uw(m2.v1)
|
||||
txt.chrout(',')
|
||||
txt.print_uw(m2.w1)
|
||||
txt.chrout(',')
|
||||
txt.print_uw(m2.w2)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
conv.str_uwhex(uww)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_uwhex(uww, false)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
conv.str_uw0(987)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_uw0(987)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
conv.str_uw(uww)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_uw(uww)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
conv.str_uw(7)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_uw(7)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
conv.str_w(ww)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_w(ww)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
conv.str_w(99)
|
||||
txt.print(conv.string_out)
|
||||
txt.nl()
|
||||
txt.print_w(99)
|
||||
m2 = m1
|
||||
txt.print_uw(m2.v1)
|
||||
txt.chrout(',')
|
||||
txt.print_uw(m2.w1)
|
||||
txt.chrout(',')
|
||||
txt.print_uw(m2.w2)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user