api change: removed swap() builtin function (too complex in codegen for little used function)

This commit is contained in:
Irmen de Jong 2022-06-06 16:01:11 +02:00
parent 0a3cd652b0
commit 3054a1d32d
13 changed files with 26 additions and 539 deletions

View File

@ -6,7 +6,6 @@ import prog8.ast.Program
import prog8.ast.expressions.*
import prog8.ast.statements.ArrayIndex
import prog8.ast.statements.BuiltinFunctionCallStatement
import prog8.ast.statements.DirectMemoryWrite
import prog8.ast.statements.Subroutine
import prog8.code.core.*
import prog8.codegen.cpu6502.assignment.*
@ -82,7 +81,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
"lsb" -> funcLsb(fcall, resultToStack, resultRegister)
"mkword" -> funcMkword(fcall, resultToStack, resultRegister)
"abs" -> funcAbs(fcall, func, resultToStack, resultRegister, sscope)
"swap" -> funcSwap(fcall)
"any", "all" -> funcAnyAll(fcall, func, resultToStack, resultRegister, sscope)
"sgn" -> funcSgn(fcall, func, resultToStack, resultRegister, sscope)
"rnd", "rndw" -> funcRnd(func, resultToStack, resultRegister, sscope)
@ -709,494 +707,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
}
}
private fun funcSwap(fcall: IFunctionCall) {
val first = fcall.args[0]
val second = fcall.args[1]
// optimized simple case: swap two variables
if(first is IdentifierReference && second is IdentifierReference) {
val firstName = asmgen.asmVariableName(first)
val secondName = asmgen.asmVariableName(second)
val dt = first.inferType(program)
if(dt istype DataType.BYTE || dt istype DataType.UBYTE) {
asmgen.out(" ldy $firstName | lda $secondName | sta $firstName | sty $secondName")
return
}
if(dt istype DataType.WORD || dt istype DataType.UWORD) {
asmgen.out("""
ldy $firstName
lda $secondName
sta $firstName
sty $secondName
ldy $firstName+1
lda $secondName+1
sta $firstName+1
sty $secondName+1
""")
return
}
if(dt istype DataType.FLOAT) {
asmgen.out("""
lda #<$firstName
sta P8ZP_SCRATCH_W1
lda #>$firstName
sta P8ZP_SCRATCH_W1+1
lda #<$secondName
sta P8ZP_SCRATCH_W2
lda #>$secondName
sta P8ZP_SCRATCH_W2+1
jsr floats.func_swap_f
""")
return
}
}
// optimized simple case: swap two memory locations
if(first is DirectMemoryRead && second is DirectMemoryRead) {
val addr1 = (first.addressExpression as? NumericLiteral)?.number?.toHex()
val addr2 = (second.addressExpression as? NumericLiteral)?.number?.toHex()
val name1 = if(first.addressExpression is IdentifierReference) asmgen.asmVariableName(first.addressExpression as IdentifierReference) else null
val name2 = if(second.addressExpression is IdentifierReference) asmgen.asmVariableName(second.addressExpression as IdentifierReference) else null
when {
addr1!=null && addr2!=null -> {
asmgen.out(" ldy $addr1 | lda $addr2 | sta $addr1 | sty $addr2")
return
}
addr1!=null && name2!=null -> {
asmgen.out(" ldy $addr1 | lda $name2 | sta $addr1 | sty $name2")
return
}
name1!=null && addr2 != null -> {
asmgen.out(" ldy $name1 | lda $addr2 | sta $name1 | sty $addr2")
return
}
name1!=null && name2!=null -> {
asmgen.out(" ldy $name1 | lda $name2 | sta $name1 | sty $name2")
return
}
addr1==null && addr2==null && name1==null && name2==null -> {
val firstExpr = first.addressExpression as? BinaryExpression
val secondExpr = second.addressExpression as? BinaryExpression
if(firstExpr!=null && secondExpr!=null) {
val pointerVariable = firstExpr.left as? IdentifierReference
val firstOffset = firstExpr.right
val secondOffset = secondExpr.right
if(pointerVariable != null
&& pointerVariable isSameAs secondExpr.left
&& firstExpr.operator == "+" && secondExpr.operator == "+"
&& (firstOffset is NumericLiteral || firstOffset is IdentifierReference || firstOffset is TypecastExpression)
&& (secondOffset is NumericLiteral || secondOffset is IdentifierReference || secondOffset is TypecastExpression)
) {
if(firstOffset is NumericLiteral && secondOffset is NumericLiteral) {
if(firstOffset!=secondOffset) {
swapArrayBytesViaPointers(pointerVariable, firstOffset, pointerVariable, secondOffset)
return
}
} else if(firstOffset is TypecastExpression && secondOffset is TypecastExpression) {
if(firstOffset.type in WordDatatypes && secondOffset.type in WordDatatypes) {
val firstOffsetVar = firstOffset.expression as? IdentifierReference
val secondOffsetVar = secondOffset.expression as? IdentifierReference
if(firstOffsetVar!=null && secondOffsetVar!=null) {
if(firstOffsetVar!=secondOffsetVar) {
swapArrayBytesViaPointers(pointerVariable, firstOffsetVar, pointerVariable, secondOffsetVar)
return
}
}
}
} else if(firstOffset is IdentifierReference || secondOffset is IdentifierReference) {
throw AssemblyError("expected a typecast-to-word for index variable at ${firstOffset.position} and/or ${secondOffset.position}")
}
}
}
}
}
}
if(first is ArrayIndexedExpression && second is ArrayIndexedExpression) {
val arrayVarDecl1 = first.arrayvar.targetVarDecl(program)!!
val arrayVarDecl2 = second.arrayvar.targetVarDecl(program)!!
if(!arrayVarDecl1.isArray || !arrayVarDecl2.isArray)
throw AssemblyError("no asm gen for swapping bytes to and/or from indexed pointer var ${fcall.position}")
val arrayVarName1 = asmgen.asmVariableName(first.arrayvar)
val arrayVarName2 = asmgen.asmVariableName(second.arrayvar)
val elementIDt = first.inferType(program)
val elementDt = elementIDt.getOrElse { throw AssemblyError("unknown dt") }
val firstNum = first.indexer.indexExpr as? NumericLiteral
val firstVar = first.indexer.indexExpr as? IdentifierReference
val secondNum = second.indexer.indexExpr as? NumericLiteral
val secondVar = second.indexer.indexExpr as? IdentifierReference
if (firstNum != null && secondNum != null) {
swapArrayValues(elementDt, arrayVarName1, firstNum, arrayVarName2, secondNum)
return
} else if (firstVar != null && secondVar != null) {
swapArrayValues(elementDt, arrayVarName1, firstVar, arrayVarName2, secondVar)
return
} else if (firstNum != null && secondVar != null) {
swapArrayValues(elementDt, arrayVarName1, firstNum, arrayVarName2, secondVar)
return
} else if (firstVar != null && secondNum != null) {
swapArrayValues(elementDt, arrayVarName1, firstVar, arrayVarName2, secondNum)
return
}
}
val arrayVarDecl1 = (first as? ArrayIndexedExpression)?.arrayvar?.targetVarDecl(program)
val arrayVarDecl2 = (second as? ArrayIndexedExpression)?.arrayvar?.targetVarDecl(program)
if((arrayVarDecl1!=null && !arrayVarDecl1.isArray) || (arrayVarDecl2!=null && !arrayVarDecl2.isArray))
throw AssemblyError("no asm gen for swapping bytes to and/or from indexed pointer var ${fcall.position}")
// all other types of swap() calls are done via a temporary variable
fun targetFromExpr(expr: Expression, datatype: DataType): AsmAssignTarget {
return when (expr) {
is IdentifierReference -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, datatype, expr.definingSubroutine, variableAsmName = asmgen.asmVariableName(expr))
is ArrayIndexedExpression -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, datatype, expr.definingSubroutine, array = expr)
is DirectMemoryRead -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, datatype, expr.definingSubroutine, memory = DirectMemoryWrite(expr.addressExpression, expr.position))
else -> throw AssemblyError("invalid expression object $expr")
}
}
when(val datatype: DataType = first.inferType(program).getOr(DataType.UNDEFINED)) {
in ByteDatatypes, in WordDatatypes -> {
asmgen.assignExpressionToVariable(first, "P8ZP_SCRATCH_W1", datatype, null)
asmgen.assignExpressionToVariable(second, "P8ZP_SCRATCH_W2", datatype, null)
val assignFirst = AsmAssignment(
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, variableAsmName = "P8ZP_SCRATCH_W2"),
targetFromExpr(first, datatype),
false, program.memsizer, first.position
)
val assignSecond = AsmAssignment(
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, variableAsmName = "P8ZP_SCRATCH_W1"),
targetFromExpr(second, datatype),
false, program.memsizer, second.position
)
asmgen.translateNormalAssignment(assignFirst)
asmgen.translateNormalAssignment(assignSecond)
}
DataType.FLOAT -> {
// via temp variable and FAC1
asmgen.assignExpressionTo(first, AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.FLOAT, first.definingSubroutine, "floats.tempvar_swap_float"))
asmgen.assignExpressionTo(second, AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, DataType.FLOAT, null, register=RegisterOrPair.FAC1))
asmgen.translateNormalAssignment(
AsmAssignment(
AsmAssignSource(SourceStorageKind.REGISTER, program, asmgen, datatype, register = RegisterOrPair.FAC1),
targetFromExpr(first, datatype),
false, program.memsizer, first.position
)
)
asmgen.translateNormalAssignment(
AsmAssignment(
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, "floats.tempvar_swap_float"),
targetFromExpr(second, datatype),
false, program.memsizer, second.position
)
)
}
else -> throw AssemblyError("weird swap dt")
}
}
private fun swapArrayBytesViaPointers(
firstZpPtr: IdentifierReference,
firstOffset: NumericLiteral,
secondZpPtr: IdentifierReference,
secondOffset: NumericLiteral
) {
var firstZpPtrName = asmgen.asmSymbolName(firstZpPtr)
if(!asmgen.isZpVar(firstZpPtr)) {
asmgen.out(" lda $firstZpPtrName | sta P8ZP_SCRATCH_W1")
asmgen.out(" lda $firstZpPtrName+1 | sta P8ZP_SCRATCH_W1+1")
firstZpPtrName = "P8ZP_SCRATCH_W1"
}
var secondZpPtrName = asmgen.asmSymbolName(secondZpPtr)
if(!asmgen.isZpVar(secondZpPtr)) {
asmgen.out(" lda $secondZpPtrName | sta P8ZP_SCRATCH_W2")
asmgen.out(" lda $secondZpPtrName+1 | sta P8ZP_SCRATCH_W2+1")
secondZpPtrName = "P8ZP_SCRATCH_W2"
}
asmgen.out("""
ldy #${firstOffset.number.toInt()}
lda ($firstZpPtrName),y
pha
ldy #${secondOffset.number.toInt()}
lda ($secondZpPtrName),y
ldy #${firstOffset.number.toInt()}
sta ($firstZpPtrName),y
pla
ldy #${secondOffset.number.toInt()}
sta ($secondZpPtrName),y
""")
}
private fun swapArrayBytesViaPointers(
firstZpPtr: IdentifierReference,
index1Var: IdentifierReference,
secondZpPtr: IdentifierReference,
index2Var: IdentifierReference
) {
var firstZpPtrName = asmgen.asmSymbolName(firstZpPtr)
if(!asmgen.isZpVar(firstZpPtr)) {
asmgen.out(" lda $firstZpPtrName | sta P8ZP_SCRATCH_W1")
asmgen.out(" lda $firstZpPtrName+1 | sta P8ZP_SCRATCH_W1+1")
firstZpPtrName = "P8ZP_SCRATCH_W1"
}
var secondZpPtrName = asmgen.asmSymbolName(secondZpPtr)
if(!asmgen.isZpVar(secondZpPtr)) {
asmgen.out(" lda $secondZpPtrName | sta P8ZP_SCRATCH_W2")
asmgen.out(" lda $secondZpPtrName+1 | sta P8ZP_SCRATCH_W2+1")
secondZpPtrName = "P8ZP_SCRATCH_W2"
}
val index1Name = asmgen.asmVariableName(index1Var)
val index2Name = asmgen.asmVariableName(index2Var)
asmgen.out("""
ldy $index1Name
lda ($firstZpPtrName),y
pha
ldy $index2Name
lda ($secondZpPtrName),y
ldy $index1Name
sta ($firstZpPtrName),y
pla
ldy $index2Name
sta ($secondZpPtrName),y
""")
}
private fun swapArrayValues(elementDt: DataType, arrayVarName1: String, indexValue1: NumericLiteral, arrayVarName2: String, indexValue2: NumericLiteral) {
val index1 = indexValue1.number.toInt() * program.memsizer.memorySize(elementDt)
val index2 = indexValue2.number.toInt() * program.memsizer.memorySize(elementDt)
when(elementDt) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out("""
lda $arrayVarName1+$index1
ldy $arrayVarName2+$index2
sta $arrayVarName2+$index2
sty $arrayVarName1+$index1
""")
}
DataType.UWORD, DataType.WORD -> {
asmgen.out("""
lda $arrayVarName1+$index1
ldy $arrayVarName2+$index2
sta $arrayVarName2+$index2
sty $arrayVarName1+$index1
lda $arrayVarName1+$index1+1
ldy $arrayVarName2+$index2+1
sta $arrayVarName2+$index2+1
sty $arrayVarName1+$index1+1
""")
}
DataType.FLOAT -> {
asmgen.out("""
lda #<(${arrayVarName1}+$index1)
sta P8ZP_SCRATCH_W1
lda #>(${arrayVarName1}+$index1)
sta P8ZP_SCRATCH_W1+1
lda #<(${arrayVarName2}+$index2)
sta P8ZP_SCRATCH_W2
lda #>(${arrayVarName2}+$index2)
sta P8ZP_SCRATCH_W2+1
jsr floats.func_swap_f
""")
}
else -> throw AssemblyError("invalid aray elt type")
}
}
private fun swapArrayValues(elementDt: DataType, arrayVarName1: String, indexName1: IdentifierReference, arrayVarName2: String, indexName2: IdentifierReference) {
val idxAsmName1 = asmgen.asmVariableName(indexName1)
val idxAsmName2 = asmgen.asmVariableName(indexName2)
when(elementDt) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out("""
stx P8ZP_SCRATCH_REG
ldx $idxAsmName1
ldy $idxAsmName2
lda $arrayVarName1,x
pha
lda $arrayVarName2,y
sta $arrayVarName1,x
pla
sta $arrayVarName2,y
ldx P8ZP_SCRATCH_REG
""")
}
DataType.UWORD, DataType.WORD -> {
asmgen.out("""
stx P8ZP_SCRATCH_REG
lda $idxAsmName1
asl a
tax
lda $idxAsmName2
asl a
tay
lda $arrayVarName1,x
pha
lda $arrayVarName2,y
sta $arrayVarName1,x
pla
sta $arrayVarName2,y
lda $arrayVarName1+1,x
pha
lda $arrayVarName2+1,y
sta $arrayVarName1+1,x
pla
sta $arrayVarName2+1,y
ldx P8ZP_SCRATCH_REG
""")
}
DataType.FLOAT -> {
asmgen.out("""
lda #>$arrayVarName1
sta P8ZP_SCRATCH_W1+1
lda $idxAsmName1
asl a
asl a
clc
adc $idxAsmName1
adc #<$arrayVarName1
sta P8ZP_SCRATCH_W1
bcc +
inc P8ZP_SCRATCH_W1+1
+ lda #>$arrayVarName2
sta P8ZP_SCRATCH_W2+1
lda $idxAsmName2
asl a
asl a
clc
adc $idxAsmName2
adc #<$arrayVarName2
sta P8ZP_SCRATCH_W2
bcc +
inc P8ZP_SCRATCH_W2+1
+ jsr floats.func_swap_f
""")
}
else -> throw AssemblyError("invalid aray elt type")
}
}
private fun swapArrayValues(elementDt: DataType, arrayVarName1: String, indexValue1: NumericLiteral, arrayVarName2: String, indexName2: IdentifierReference) {
val index1 = indexValue1.number.toInt() * program.memsizer.memorySize(elementDt)
val idxAsmName2 = asmgen.asmVariableName(indexName2)
when(elementDt) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out("""
lda $arrayVarName1 + $index1
pha
ldy $idxAsmName2
lda $arrayVarName2,y
sta $arrayVarName1 + $index1
pla
sta $arrayVarName2,y
""")
}
DataType.UWORD, DataType.WORD -> {
asmgen.out("""
lda $arrayVarName1 + $index1
pha
lda $idxAsmName2
asl a
tay
lda $arrayVarName2,y
sta $arrayVarName1 + $index1
pla
sta $arrayVarName2,y
lda $arrayVarName1 + $index1+1
pha
lda $arrayVarName2+1,y
sta $arrayVarName1 + $index1+1
pla
sta $arrayVarName2+1,y
""")
}
DataType.FLOAT -> {
asmgen.out("""
lda #<(${arrayVarName1}+$index1)
sta P8ZP_SCRATCH_W1
lda #>(${arrayVarName1}+$index1)
sta P8ZP_SCRATCH_W1+1
lda #>$arrayVarName1
sta P8ZP_SCRATCH_W1+1
lda $idxAsmName2
asl a
asl a
clc
adc $idxAsmName2
adc #<$arrayVarName1
sta P8ZP_SCRATCH_W1
bcc +
inc P8ZP_SCRATCH_W1+1
+ jsr floats.func_swap_f
""")
}
else -> throw AssemblyError("invalid aray elt type")
}
}
private fun swapArrayValues(elementDt: DataType, arrayVarName1: String, indexName1: IdentifierReference, arrayVarName2: String, indexValue2: NumericLiteral) {
val idxAsmName1 = asmgen.asmVariableName(indexName1)
val index2 = indexValue2.number.toInt() * program.memsizer.memorySize(elementDt)
when(elementDt) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out("""
lda $arrayVarName2 + $index2
pha
ldy $idxAsmName1
lda $arrayVarName1,y
sta $arrayVarName2 + $index2
pla
sta $arrayVarName1,y
""")
}
DataType.UWORD, DataType.WORD -> {
asmgen.out("""
lda $arrayVarName2 + $index2
pha
lda $idxAsmName1
asl a
tay
lda $arrayVarName1,y
sta $arrayVarName2 + $index2
pla
sta $arrayVarName1,y
lda $arrayVarName2 + $index2+1
pha
lda $arrayVarName1+1,y
sta $arrayVarName2 + $index2+1
pla
sta $arrayVarName1+1,y
""")
}
DataType.FLOAT -> {
asmgen.out("""
lda #>$arrayVarName1
sta P8ZP_SCRATCH_W1+1
lda $idxAsmName1
asl a
asl a
clc
adc $idxAsmName1
adc #<$arrayVarName1
sta P8ZP_SCRATCH_W1
bcc +
inc P8ZP_SCRATCH_W1+1
+ lda #<(${arrayVarName2}+$index2)
sta P8ZP_SCRATCH_W2
lda #>(${arrayVarName2}+$index2)
sta P8ZP_SCRATCH_W2+1
jsr floats.func_swap_f
""")
}
else -> throw AssemblyError("invalid aray elt type")
}
}
private fun funcAbs(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) {
translateArguments(fcall.args, func, scope)
val dt = fcall.args.single().inferType(program).getOr(DataType.UNDEFINED)

View File

@ -41,7 +41,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
"mkword" -> funcMkword(call, resultRegister)
"sort" -> funcSort(call)
"reverse" -> funcReverse(call)
"swap" -> funcSwap(call)
"rol" -> funcRolRor(Opcode.ROXL, call, resultRegister)
"ror" -> funcRolRor(Opcode.ROXR, call, resultRegister)
"rol2" -> funcRolRor(Opcode.ROL, call, resultRegister)
@ -184,19 +183,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
return code
}
private fun funcSwap(call: PtBuiltinFunctionCall): VmCodeChunk {
val left = call.args[0]
val right = call.args[1]
val leftReg = codeGen.vmRegisters.nextFree()
val rightReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
code += exprGen.translateExpression(left, leftReg, -1)
code += exprGen.translateExpression(right, rightReg, -1)
code += assignRegisterTo(left, rightReg)
code += assignRegisterTo(right, leftReg)
return code
}
private fun funcReverse(call: PtBuiltinFunctionCall): VmCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable

View File

@ -9,7 +9,6 @@ floats {
const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586
float tempvar_swap_float ; used for some swap() operations
; ---- C64 basic and kernal ROM float constants and functions ----

View File

@ -38,8 +38,12 @@ graphics {
if y1>y2 {
; make sure dy is always positive to have only 4 instead of 8 special cases
swap(x1, x2)
swap(y1, y2)
cx16.r0 = x1
x1 = x2
x2 = cx16.r0
cx16.r0L = y1
y1 = y2
y2 = cx16.r0L
}
word @zp dx = (x2 as word)-x1
word @zp dy = (y2 as word)-y1

View File

@ -394,8 +394,12 @@ _done
; This code special-cases various quadrant loops to allow simple ++ and -- operations.
if y1>y2 {
; make sure dy is always positive to have only 4 instead of 8 special cases
swap(x1, x2)
swap(y1, y2)
cx16.r0 = x1
x1 = x2
x2 = cx16.r0
cx16.r0 = y1
y1 = y2
y2 = cx16.r0
}
word @zp dx = (x2 as word)-x1
word @zp dy = (y2 as word)-y1

View File

@ -1063,20 +1063,7 @@ internal class AstChecker(private val program: Program,
errors.err("cannot use arguments when calling a label", position)
if(target is BuiltinFunctionPlaceholder) {
if(target.name=="swap") {
// swap() is a bit weird because this one is translated into an operations directly, instead of being a function call
val dt1 = args[0].inferType(program)
val dt2 = args[1].inferType(program)
if (dt1 != dt2)
errors.err("swap requires 2 args of identical type", position)
else if (args[0].constValue(program) != null || args[1].constValue(program) != null)
errors.err("swap requires 2 variables, not constant value(s)", position)
else if(args[0] isSameAs args[1])
errors.err("swap should have 2 different args", position)
else if(!dt1.isNumeric)
errors.err("swap requires args of numerical type", position)
}
else if(target.name=="all" || target.name=="any") {
if(target.name=="all" || target.name=="any") {
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR
|| args[0].inferType(program).getOr(DataType.STR) == DataType.STR) {
errors.err("any/all on a string is useless (is always true unless the string is empty)", position)

View File

@ -444,9 +444,6 @@ main {
txt.print_b(bb)
txt.nl()
swap(fl, fzero)
swap(fzero, fl)
ub = any(flarr)
txt.print_ub(ub)
txt.nl()

View File

@ -123,13 +123,12 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("rnd" , false, emptyList(), DataType.UBYTE),
FSignature("rndw" , false, emptyList(), DataType.UWORD),
FSignature("memory" , true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null),
FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
)
val BuiltinFunctions = functionSignatures.associateBy { it.name }
val InplaceModifyingBuiltinFunctions = setOf("rol", "ror", "rol2", "ror2", "swap", "sort", "reverse")
val InplaceModifyingBuiltinFunctions = setOf("rol", "ror", "rol2", "ror2", "sort", "reverse")
private fun builtinAny(array: List<Double>): Double = if(array.any { it!=0.0 }) 1.0 else 0.0

View File

@ -72,7 +72,7 @@ Language features
- Floating point math also supported if the target system provides floating point library routines (C64 and Cx16 both do).
- Strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \\, {, } and | are also accepted and converted to the closest petscii equivalents.
- High-level code optimizations, such as const-folding, expression and statement simplifications/rewriting.
- Many built-in functions, such as ``sin``, ``cos``, ``rnd``, ``abs``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``sort`` and ``reverse``
- Many built-in functions, such as ``sin``, ``cos``, ``rnd``, ``abs``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``sort`` and ``reverse``
- Programs can be run multiple times without reloading because of automatic variable (re)initializations.
- Supports the sixteen 'virtual' 16-bit registers R0 .. R15 from the Commander X16, also on the other machines.
- If you only use standard kernal and core prog8 library routines, it is possible to compile the *exact same program* for different machines (just change the compilation target flag)!

View File

@ -869,10 +869,6 @@ sizeof(name)
For an 10 element array of floats, it is 50 (on the C-64, where a float is 5 bytes).
Note: usually you will be interested in the number of elements in an array, use len() for that.
swap(x, y)
Swap the values of numerical variables (or memory locations) x and y in a fast way.
You can swap two memory locations directly by using the direct memory access syntax, so like ``swap(@($5000), @($5001))``
memory(name, size, alignment)
Returns the address of the first location of a statically "reserved" block of memory of the given size in bytes,
with the given name. If you specify an alignment value >1, it means the block of memory will

View File

@ -3,7 +3,7 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- optimize pointervar indexing codegen: fix 6502 codegen for params to in-place modifying functions (rol, swap, ...)
- optimize pointervar indexing codegen: fix 6502 codegen for params to in-place modifying functions (rol, ror, ...)
- optimize pointervar indexing codegen: writing (all sorts of things)
- pipe operator: (targets other than 'Virtual'): allow non-unary function calls in the pipe that specify the other argument(s) in the calls. Already working for VM target.
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?

View File

@ -148,9 +148,15 @@ main {
for i1 in 0 to i {
ubyte i2 = i1+1
if(rotatedz[i1] > rotatedz[i2]) {
swap(rotatedx[i1], rotatedx[i2])
swap(rotatedy[i1], rotatedy[i2])
swap(rotatedz[i1], rotatedz[i2])
word @zp temp = rotatedx[i1]
rotatedx[i1] = rotatedx[i2]
rotatedx[i2] = temp
temp = rotatedy[i1]
rotatedy[i1] = rotatedy[i2]
rotatedy[i2] = temp
temp = rotatedz[i1]
rotatedz[i1] = rotatedz[i2]
rotatedz[i2] = temp
}
}
}

View File

@ -73,9 +73,8 @@ main {
bitmapbuf[2] += 4
bitmapbuf[2] -= 2
bitmapbuf[2] -= 2
swap(bitmapbuf[0], bitmapbuf[1])
; 2 1 3
; 1 2 3
txt.print_ub(bitmapbuf[0])
txt.spc()
txt.print_ub(bitmapbuf[1])