mirror of
https://github.com/irmen/prog8.git
synced 2024-10-18 16:24:26 +00:00
array and struct value assignments now via memcopy instead of assignment per element
This commit is contained in:
parent
4f8d4a9585
commit
2950d26c8e
@ -270,24 +270,16 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
|||||||
val targetType = assignment.target.inferType(program)
|
val targetType = assignment.target.inferType(program)
|
||||||
|
|
||||||
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 )) {
|
||||||
val assignments = if (assignment.value is ArrayLiteralValue) {
|
if (assignment.value is ArrayLiteralValue) {
|
||||||
throw FatalAstException("array literal should have been translated to a variable at "+assignment.position.toString())
|
errors.err("cannot assign non-const array value, use separate assignment per field", assignment.position)
|
||||||
} else {
|
} else {
|
||||||
flattenStructAssignmentFromIdentifier(assignment)
|
return copyStructValue(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 ) {
|
if(targetType.typeOrElse(DataType.STRUCT) in ArrayDatatypes && valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes ) {
|
||||||
if (assignment.value is ArrayLiteralValue) {
|
if (assignment.value is ArrayLiteralValue) {
|
||||||
throw FatalAstException("array literal should have been translated to a variable at "+assignment.position.toString())
|
errors.err("cannot assign non-const array value, use separate assignment per element", assignment.position)
|
||||||
} else {
|
} else {
|
||||||
return copyArrayValue(assignment)
|
return copyArrayValue(assignment)
|
||||||
}
|
}
|
||||||
@ -378,52 +370,61 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
|||||||
return listOf(IAstModification.ReplaceNode(assign, memcopy, assign.parent))
|
return listOf(IAstModification.ReplaceNode(assign, memcopy, assign.parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun flattenStructAssignmentFromIdentifier(structAssignment: Assignment): List<Assignment> {
|
private fun copyStructValue(structAssignment: Assignment): List<IAstModification> {
|
||||||
// TODO use memcopy beyond a certain number of elements
|
|
||||||
val identifier = structAssignment.target.identifier!!
|
val identifier = structAssignment.target.identifier!!
|
||||||
val identifierName = identifier.nameInSource.single()
|
|
||||||
val targetVar = identifier.targetVarDecl(program)!!
|
val targetVar = identifier.targetVarDecl(program)!!
|
||||||
val struct = targetVar.struct!!
|
val struct = targetVar.struct!!
|
||||||
when (structAssignment.value) {
|
when (structAssignment.value) {
|
||||||
is IdentifierReference -> {
|
is IdentifierReference -> {
|
||||||
val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program)!!
|
val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program)!!
|
||||||
|
val memsize = struct.memsize(program.memsizer)
|
||||||
when {
|
when {
|
||||||
sourceVar.struct!=null -> {
|
sourceVar.struct!=null -> {
|
||||||
// struct memberwise copy
|
// struct memberwise copy
|
||||||
val sourceStruct = sourceVar.struct!!
|
val sourceStruct = sourceVar.struct!!
|
||||||
if(sourceStruct!==targetVar.struct) {
|
if(sourceStruct!==targetVar.struct) {
|
||||||
// structs are not the same in assignment
|
errors.err("struct type mismatch", structAssignment.position)
|
||||||
return listOf() // error will be printed elsewhere
|
return listOf()
|
||||||
}
|
}
|
||||||
if(struct.statements.size!=sourceStruct.statements.size)
|
if(struct.statements.size!=sourceStruct.statements.size) {
|
||||||
return listOf() // error will be printed elsewhere
|
errors.err("struct element count mismatch", structAssignment.position)
|
||||||
return struct.statements.zip(sourceStruct.statements).map { member ->
|
return listOf()
|
||||||
val targetDecl = member.first as VarDecl
|
|
||||||
val sourceDecl = member.second as VarDecl
|
|
||||||
if(targetDecl.name != sourceDecl.name)
|
|
||||||
throw FatalAstException("struct member mismatch")
|
|
||||||
val mangled = mangledStructMemberName(identifierName, targetDecl.name)
|
|
||||||
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
|
||||||
val sourcemangled = mangledStructMemberName(sourceVar.name, sourceDecl.name)
|
|
||||||
val sourceIdref = IdentifierReference(listOf(sourcemangled), structAssignment.position)
|
|
||||||
val assign = Assignment(AssignTarget(idref, null, null, structAssignment.position), sourceIdref, member.second.position)
|
|
||||||
assign.linkParents(structAssignment)
|
|
||||||
assign
|
|
||||||
}
|
}
|
||||||
|
if(memsize!=sourceStruct.memsize(program.memsizer)) {
|
||||||
|
errors.err("memory size mismatch", structAssignment.position)
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), structAssignment.position),
|
||||||
|
mutableListOf(
|
||||||
|
AddressOf(structAssignment.value as IdentifierReference, structAssignment.position),
|
||||||
|
AddressOf(identifier, structAssignment.position),
|
||||||
|
NumericLiteralValue.optimalInteger(memsize, structAssignment.position)
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
structAssignment.position
|
||||||
|
)
|
||||||
|
return listOf(IAstModification.ReplaceNode(structAssignment, memcopy, structAssignment.parent))
|
||||||
}
|
}
|
||||||
sourceVar.isArray -> {
|
sourceVar.isArray -> {
|
||||||
val array = (sourceVar.value as ArrayLiteralValue).value
|
val array = sourceVar.value as ArrayLiteralValue
|
||||||
if(struct.statements.size!=array.size)
|
if(struct.statements.size!=array.value.size) {
|
||||||
return listOf() // error will be printed elsewhere
|
errors.err("struct element count mismatch", structAssignment.position)
|
||||||
return struct.statements.zip(array).map {
|
return listOf()
|
||||||
val decl = it.first as VarDecl
|
|
||||||
val mangled = mangledStructMemberName(identifierName, decl.name)
|
|
||||||
val targetName = IdentifierReference(listOf(mangled), structAssignment.position)
|
|
||||||
val target = AssignTarget(targetName, null, null, structAssignment.position)
|
|
||||||
val assign = Assignment(target, it.second, structAssignment.position)
|
|
||||||
assign.linkParents(structAssignment)
|
|
||||||
assign
|
|
||||||
}
|
}
|
||||||
|
if(memsize!=array.memsize(program.memsizer)) {
|
||||||
|
errors.err("memory size mismatch", structAssignment.position)
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), structAssignment.position),
|
||||||
|
mutableListOf(
|
||||||
|
AddressOf(structAssignment.value as IdentifierReference, structAssignment.position),
|
||||||
|
AddressOf(identifier, structAssignment.position),
|
||||||
|
NumericLiteralValue.optimalInteger(memsize, structAssignment.position)
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
structAssignment.position
|
||||||
|
)
|
||||||
|
return listOf(IAstModification.ReplaceNode(structAssignment, memcopy, structAssignment.parent))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
throw FatalAstException("can only assign arrays or structs to structs")
|
throw FatalAstException("can only assign arrays or structs to structs")
|
||||||
@ -431,7 +432,7 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ArrayLiteralValue -> {
|
is ArrayLiteralValue -> {
|
||||||
throw IllegalArgumentException("not going to flatten a structLv assignment here")
|
throw IllegalArgumentException("not going to do a structLv assignment here")
|
||||||
}
|
}
|
||||||
else -> throw FatalAstException("strange struct value")
|
else -> throw FatalAstException("strange struct value")
|
||||||
}
|
}
|
||||||
|
@ -321,8 +321,7 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
|
|||||||
val target = (args[0] as IdentifierReference).targetStatement(program)
|
val target = (args[0] as IdentifierReference).targetStatement(program)
|
||||||
?: throw CannotEvaluateException("sizeof", "no target")
|
?: throw CannotEvaluateException("sizeof", "no target")
|
||||||
|
|
||||||
fun structSize(target: StructDecl) =
|
fun structSize(target: StructDecl) = NumericLiteralValue(DataType.UBYTE, target.memsize(memsizer), position)
|
||||||
NumericLiteralValue(DataType.UBYTE, target.statements.map { memsizer.memorySize((it as VarDecl).datatype) }.sum(), position)
|
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
dt.typeOrElse(DataType.STRUCT) in ArrayDatatypes -> {
|
dt.typeOrElse(DataType.STRUCT) in ArrayDatatypes -> {
|
||||||
|
@ -6,7 +6,7 @@ import prog8.ast.base.*
|
|||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstVisitor
|
import prog8.ast.walk.IAstVisitor
|
||||||
import java.util.*
|
import java.util.Objects
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
@ -542,6 +542,14 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
|
|||||||
return type==other.type && value.contentEquals(other.value)
|
return type==other.type && value.contentEquals(other.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun memsize(memsizer: IMemSizer): Int {
|
||||||
|
if(type.isKnown) {
|
||||||
|
val eltType = ArrayElementTypes.getValue(type.typeOrElse(DataType.STRUCT))
|
||||||
|
return memsizer.memorySize(eltType) * value.size
|
||||||
|
}
|
||||||
|
else throw IllegalArgumentException("array datatype is not yet known")
|
||||||
|
}
|
||||||
|
|
||||||
fun guessDatatype(program: Program): InferredTypes.InferredType {
|
fun guessDatatype(program: Program): InferredTypes.InferredType {
|
||||||
// Educated guess of the desired array literal's datatype.
|
// Educated guess of the desired array literal's datatype.
|
||||||
// If it's inside a for loop, assume the data type of the loop variable is what we want.
|
// If it's inside a for loop, assume the data type of the loop variable is what we want.
|
||||||
|
@ -1000,6 +1000,9 @@ class StructDecl(override val name: String,
|
|||||||
val numberOfElements: Int
|
val numberOfElements: Int
|
||||||
get() = this.statements.size
|
get() = this.statements.size
|
||||||
|
|
||||||
|
fun memsize(memsizer: IMemSizer) =
|
||||||
|
statements.map { memsizer.memorySize((it as VarDecl).datatype) }.sum()
|
||||||
|
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
- 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
|
||||||
|
@ -31,7 +31,6 @@ main {
|
|||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct MyType {
|
struct MyType {
|
||||||
uword v1
|
uword v1
|
||||||
uword w1
|
uword w1
|
||||||
|
@ -414,14 +414,18 @@ galaxy {
|
|||||||
sub init(ubyte galaxynum) {
|
sub init(ubyte galaxynum) {
|
||||||
number = 1
|
number = 1
|
||||||
planet.number = 255
|
planet.number = 255
|
||||||
seed = [base0, base1, base2]
|
seed[0] = base0
|
||||||
|
seed[1] = base1
|
||||||
|
seed[2] = base2
|
||||||
repeat galaxynum-1 {
|
repeat galaxynum-1 {
|
||||||
nextgalaxy()
|
nextgalaxy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub nextgalaxy() {
|
sub nextgalaxy() {
|
||||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
seed[0] = twist(seed[0])
|
||||||
|
seed[1] = twist(seed[1])
|
||||||
|
seed[2] = twist(seed[2])
|
||||||
number++
|
number++
|
||||||
if number==9
|
if number==9
|
||||||
number = 1
|
number = 1
|
||||||
@ -658,7 +662,10 @@ galaxy {
|
|||||||
planet.species_kind = (planet.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
planet.species_kind = (planet.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||||
}
|
}
|
||||||
|
|
||||||
planet.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
planet.goatsoup_seed[0] = lsb(seed[1])
|
||||||
|
planet.goatsoup_seed[1] = msb(seed[1])
|
||||||
|
planet.goatsoup_seed[2] = lsb(seed[2])
|
||||||
|
planet.goatsoup_seed[3] = seed2_msb
|
||||||
}
|
}
|
||||||
|
|
||||||
sub tweakseed() {
|
sub tweakseed() {
|
||||||
|
Loading…
Reference in New Issue
Block a user