added swap() slow version

This commit is contained in:
Irmen de Jong 2019-01-18 01:33:54 +01:00
parent 740dedc7a1
commit 75b38d7b84
6 changed files with 93 additions and 23 deletions

View File

@ -5,6 +5,7 @@ import prog8.ast.RegisterOrPair.*
import prog8.compiler.intermediate.IntermediateProgram import prog8.compiler.intermediate.IntermediateProgram
import prog8.compiler.intermediate.Opcode import prog8.compiler.intermediate.Opcode
import prog8.compiler.intermediate.Value import prog8.compiler.intermediate.Value
import prog8.optimizing.same
import prog8.stackvm.Syscall import prog8.stackvm.Syscall
import java.util.* import java.util.*
import kotlin.math.abs import kotlin.math.abs
@ -760,6 +761,12 @@ private class StatementTranslator(private val prog: IntermediateProgram,
private fun translateFunctionCall(funcname: String, args: List<IExpression>) { private fun translateFunctionCall(funcname: String, args: List<IExpression>) {
// some functions are implemented as vm opcodes // some functions are implemented as vm opcodes
if(funcname == "swap") {
translateSwap(args)
return
}
args.forEach { translate(it) } // place function argument(s) on the stack args.forEach { translate(it) } // place function argument(s) on the stack
when (funcname) { when (funcname) {
"len" -> { "len" -> {
@ -923,6 +930,75 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} }
} }
private fun StatementTranslator.translateSwap(args: List<IExpression>) {
// swap(x,y) is treated differently, it's not a normal function call
if (args.size != 2)
throw AstException("swap requires 2 arguments")
val dt1 = args[0].resultingDatatype(namespace, heap)!!
val dt2 = args[1].resultingDatatype(namespace, heap)!!
if (dt1 != dt2)
throw AstException("swap requires 2 args of identical type")
if (args[0].constValue(namespace, heap) != null || args[1].constValue(namespace, heap) != null)
throw AstException("swap requires 2 variables, not constant value(s)")
if (dt1 !in NumericDatatypes)
throw AstException("swap requires args of numerical type")
if(same(args[0], args[1]))
throw AstException("swap should have 2 different args")
// @todo implement the above errors as nice AstChecker expression errors.
// @todo implement this more efficiently with using the xor trick instead of the stack!
// Swap(X,Y) :=
// X ^= Y
// Y ^= X
// X ^= Y
// for floats, this doesn't work, use a temp variable instead.
// pop first then second arg
translate(args[0])
translate(args[1])
// pop stack in reverse order
when {
args[0] is IdentifierReference -> {
val target = AssignTarget(null, args[0] as IdentifierReference, null, null, args[0].position)
popValueIntoTarget(target, dt1)
}
args[0] is RegisterExpr -> {
val target = AssignTarget((args[0] as RegisterExpr).register, null, null, null, args[0].position)
popValueIntoTarget(target, dt1)
}
args[0] is ArrayIndexedExpression -> {
val target = AssignTarget(null, null, args[0] as ArrayIndexedExpression, null, args[0].position)
popValueIntoTarget(target, dt1)
}
args[0] is DirectMemoryRead -> {
val target = AssignTarget(null, null, null, DirectMemoryWrite((args[0] as DirectMemoryRead).addressExpression, args[0].position), args[0].position)
popValueIntoTarget(target, dt1)
}
else -> TODO("unpop type ${args[0]}")
}
when {
args[1] is IdentifierReference -> {
val target = AssignTarget(null, args[1] as IdentifierReference, null, null, args[1].position)
popValueIntoTarget(target, dt2)
}
args[1] is RegisterExpr -> {
val target = AssignTarget((args[1] as RegisterExpr).register, null, null, null, args[1].position)
popValueIntoTarget(target, dt2)
}
args[1] is ArrayIndexedExpression -> {
val target = AssignTarget(null, null, args[1] as ArrayIndexedExpression, null, args[1].position)
popValueIntoTarget(target, dt2)
}
args[1] is DirectMemoryRead -> {
val target = AssignTarget(null, null, null, DirectMemoryWrite((args[1] as DirectMemoryRead).addressExpression, args[1].position), args[1].position)
popValueIntoTarget(target, dt2)
}
else -> TODO("unpop type ${args[1]}")
}
return
}
private fun translateSubroutineCall(subroutine: Subroutine, arguments: List<IExpression>, callPosition: Position) { private fun translateSubroutineCall(subroutine: Subroutine, arguments: List<IExpression>, callPosition: Position) {
// evaluate the arguments and assign them into the subroutine's argument variables. // evaluate the arguments and assign them into the subroutine's argument variables.
var restoreX = Register.X in subroutine.asmClobbers var restoreX = Register.X in subroutine.asmClobbers

View File

@ -68,6 +68,7 @@ val BuiltinFunctions = mapOf(
"clear_carry" to FunctionSignature(false, emptyList(), null), "clear_carry" to FunctionSignature(false, emptyList(), null),
"set_irqd" to FunctionSignature(false, emptyList(), null), "set_irqd" to FunctionSignature(false, emptyList(), null),
"clear_irqd" to FunctionSignature(false, emptyList(), null), "clear_irqd" to FunctionSignature(false, emptyList(), null),
"swap" to FunctionSignature(false, listOf(BuiltinFunctionParam("first", NumericDatatypes), BuiltinFunctionParam("second", NumericDatatypes)), null),
"memcopy" to FunctionSignature(false, listOf( "memcopy" to FunctionSignature(false, listOf(
BuiltinFunctionParam("from", IntegerDatatypes + IterableDatatypes), BuiltinFunctionParam("from", IntegerDatatypes + IterableDatatypes),
BuiltinFunctionParam("to", IntegerDatatypes + IterableDatatypes), BuiltinFunctionParam("to", IntegerDatatypes + IterableDatatypes),

View File

@ -485,14 +485,17 @@ fun same(left: IExpression, right: IExpression): Boolean {
return (right is RegisterExpr && right.register==left.register) return (right is RegisterExpr && right.register==left.register)
is IdentifierReference -> is IdentifierReference ->
return (right is IdentifierReference && right.nameInSource==left.nameInSource) return (right is IdentifierReference && right.nameInSource==left.nameInSource)
is ArrayIndexedExpression ->
return (right is ArrayIndexedExpression && right.identifier==left.identifier && right.arrayspec==left.arrayspec)
is PrefixExpression -> is PrefixExpression ->
return (right is PrefixExpression && right.operator==left.operator && same(right.expression, left.expression)) return (right is PrefixExpression && right.operator==left.operator && same(right.expression, left.expression))
is BinaryExpression -> is BinaryExpression ->
return (right is BinaryExpression && right.operator==left.operator return (right is BinaryExpression && right.operator==left.operator
&& same(right.left, left.left) && same(right.left, left.left)
&& same(right.right, left.right)) && same(right.right, left.right))
is ArrayIndexedExpression -> {
return (right is ArrayIndexedExpression && right.identifier.nameInSource == left.identifier.nameInSource
&& same(right.arrayspec.x, left.arrayspec.x))
}
is LiteralValue -> return (right is LiteralValue && right==left)
} }
return false return false
} }

View File

@ -664,6 +664,9 @@ memcopy(from, to, numbytes)
it is only faster if the number of bytes is larger than a certain threshold. it is only faster if the number of bytes is larger than a certain threshold.
Compare the generated code to see if it was beneficial or not. Compare the generated code to see if it was beneficial or not.
swap(x, y)
Swap the values of numerical variables (or memory locations) x and y in a fast way.
set_carry() / clear_carry() set_carry() / clear_carry()
Set (or clear) the CPU status register Carry flag. No result value. Set (or clear) the CPU status register Carry flag. No result value.
(translated into ``SEC`` or ``CLC`` cpu instruction) (translated into ``SEC`` or ``CLC`` cpu instruction)

View File

@ -128,8 +128,6 @@
} }
ubyte[8] spritecolors = [1,1,7,15,12,11,9,9]
sub position_sprites() { sub position_sprites() {
; set each of the 8 sprites to the correct vertex of the cube ; set each of the 8 sprites to the correct vertex of the cube
@ -140,20 +138,15 @@
for ubyte i1 in 0 to sorti { for ubyte i1 in 0 to sorti {
ubyte i2 = i1+1 ubyte i2 = i1+1
if(rotatedz[i1] > rotatedz[i2]) { if(rotatedz[i1] > rotatedz[i2]) {
; @todo use a swap() builtin function? swap(rotatedx[i1], rotatedx[i2])
word temp = rotatedx[i1] swap(rotatedy[i1], rotatedy[i2])
rotatedx[i1] = rotatedx[i2] swap(rotatedz[i1], rotatedz[i2])
rotatedx[i2] = temp
temp = rotatedy[i1]
rotatedy[i1] = rotatedy[i2]
rotatedy[i2] = temp
temp = rotatedz[i1]
rotatedz[i1] = rotatedz[i2]
rotatedz[i2] = temp
} }
} }
} }
ubyte[8] spritecolors = [1,1,7,15,12,11,9,9]
for ubyte i in 0 to 7 { for ubyte i in 0 to 7 {
word zc = rotatedz[i] word zc = rotatedz[i]
word persp = 300+zc/256 word persp = 300+zc/256

View File

@ -18,15 +18,9 @@
for ubyte i1 in 0 to sorti { for ubyte i1 in 0 to sorti {
ubyte i2=i1+1 ubyte i2=i1+1
if(rotatedz[i2]>rotatedz[i1]) { if(rotatedz[i2]>rotatedz[i1]) {
word t = rotatedx[i1] swap(rotatedx[i1], rotatedx[i2])
rotatedx[i1] = rotatedx[i2] swap(rotatedy[i1], rotatedy[i2])
rotatedx[i2] = t swap(rotatedz[i1], rotatedz[i2])
t = rotatedy[i1]
rotatedy[i1] = rotatedy[i2]
rotatedy[i2] = t
t = rotatedz[i1]
rotatedz[i1] = rotatedz[i2]
rotatedz[i2] = t
} }
} }
} }