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,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> {

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')
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

View File

@ -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

View File

@ -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()
}
}