use memcopy to assign arrays

This commit is contained in:
Irmen de Jong 2021-03-06 19:01:16 +01:00
parent d787795759
commit 4f8d4a9585
4 changed files with 88 additions and 157 deletions

View File

@ -268,22 +268,12 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
override fun before(assignment: Assignment, parent: Node): Iterable<IAstModification> { override fun before(assignment: Assignment, parent: Node): Iterable<IAstModification> {
val valueType = assignment.value.inferType(program) val valueType = assignment.value.inferType(program)
val targetType = assignment.target.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 )) { if(targetType.istype(DataType.STRUCT) && (valueType.istype(DataType.STRUCT) || valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes )) {
assignments = if (assignment.value is ArrayLiteralValue) { val assignments = if (assignment.value is ArrayLiteralValue) {
flattenStructAssignmentFromStructLiteral(assignment) // 'structvar = [ ..... ] ' throw FatalAstException("array literal should have been translated to a variable at "+assignment.position.toString())
} else { } else {
flattenStructAssignmentFromIdentifier(assignment) // 'structvar1 = structvar2' flattenStructAssignmentFromIdentifier(assignment)
}
}
if(targetType.typeOrElse(DataType.STRUCT) in ArrayDatatypes && valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes ) {
assignments = if (assignment.value is ArrayLiteralValue) {
flattenArrayAssignmentFromArrayLiteral(assignment) // 'arrayvar = [ ..... ] '
} else {
flattenArrayAssignmentFromIdentifier(assignment) // 'arrayvar1 = arrayvar2'
}
} }
if(assignments.isNotEmpty()) { if(assignments.isNotEmpty()) {
@ -293,6 +283,15 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
modifications.add(IAstModification.Remove(assignment, scope)) modifications.add(IAstModification.Remove(assignment, scope))
return modifications return modifications
} }
}
if(targetType.typeOrElse(DataType.STRUCT) in ArrayDatatypes && valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes ) {
if (assignment.value is ArrayLiteralValue) {
throw FatalAstException("array literal should have been translated to a variable at "+assignment.position.toString())
} else {
return copyArrayValue(assignment)
}
}
return noModifications return noModifications
} }
@ -346,66 +345,37 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
return noModifications return noModifications
} }
private fun flattenArrayAssignmentFromArrayLiteral(assign: Assignment): List<Assignment> { private fun copyArrayValue(assign: Assignment): List<IAstModification> {
val identifier = assign.target.identifier!! val identifier = assign.target.identifier!!
val targetVar = identifier.targetVarDecl(program)!! 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> { if(targetVar.arraysize==null)
val identifier = assign.target.identifier!! errors.err("array has no defined size", assign.position)
val targetVar = identifier.targetVarDecl(program)!!
val sourceIdent = assign.value as IdentifierReference val sourceIdent = assign.value as IdentifierReference
val sourceVar = sourceIdent.targetVarDecl(program)!! val sourceVar = sourceIdent.targetVarDecl(program)!!
if(!sourceVar.isArray) { 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() 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> { val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assign.position),
if(targetVar.arraysize==null) { mutableListOf(
errors.err("array has no defined size", identifier.position) AddressOf(sourceIdent, assign.position),
return emptyList() AddressOf(identifier, assign.position),
} NumericLiteralValue.optimalInteger(targetVar.arraysize!!.constIndex()!!, assign.position)
),
if(alv==null || alv.value.size != targetVar.arraysize!!.constIndex()) { true,
errors.err("element count mismatch", position) assign.position
return emptyList() )
} return listOf(IAstModification.ReplaceNode(assign, memcopy, assign.parent))
// 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
}
} }
private fun flattenStructAssignmentFromIdentifier(structAssignment: Assignment): List<Assignment> { private fun flattenStructAssignmentFromIdentifier(structAssignment: Assignment): List<Assignment> {

View File

@ -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') 1 ('true') if all of the values in the array value x are 'true' (not zero), else 0 ('false')
len(x) 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: 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 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! length of the string during execution, the value of len(s) may no longer be correct!
(use strlen function if you want to dynamically determine the length) (use the ``string.length`` routine if you want to dynamically determine the length by counting to the
first 0-byte)
max(x) max(x)
Maximum of the values in the array value x Maximum of the values in the array value x

View File

@ -2,7 +2,8 @@
TODO 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) - 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 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 - optimize several inner loops in gfx2

View File

@ -4,103 +4,62 @@
main { main {
sub start() { sub start() {
ubyte ubb = $f4 ubyte[] arr1 = [1,2,3]
byte bb = -123 ubyte[] arr2 = [9,9,9]
uword uww = $f4a1
word ww = -12345
conv.str_ub0($0f) arr1[2]=42
txt.print(conv.string_out) txt.print_ub(arr2[0])
txt.chrout(',')
txt.print_ub(arr2[1])
txt.chrout(',')
txt.print_ub(arr2[2])
txt.nl() 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()
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) struct MyType {
txt.print(conv.string_out) uword v1
txt.nl() uword w1
txt.print_ubhex(ubb,false) uword w2
txt.nl() }
txt.nl()
conv.str_ubbin(ubb) MyType m1 = [1, 888, 999]
txt.print(conv.string_out) MyType m2 = [22, 222, 222]
txt.nl()
txt.print_ubbin(ubb,false)
txt.nl()
txt.nl()
conv.str_uwbin(uww) txt.print_uw(m2.v1)
txt.print(conv.string_out) txt.chrout(',')
txt.print_uw(m2.w1)
txt.chrout(',')
txt.print_uw(m2.w2)
txt.nl() 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()
txt.nl() m2 = m1
txt.print_uw(m2.v1)
conv.str_uwhex(uww) txt.chrout(',')
txt.print(conv.string_out) txt.print_uw(m2.w1)
txt.nl() txt.chrout(',')
txt.print_uwhex(uww, false) txt.print_uw(m2.w2)
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)
txt.nl() txt.nl()
} }
} }