diff --git a/codeCore/src/prog8/code/core/BuiltinFunctions.kt b/codeCore/src/prog8/code/core/BuiltinFunctions.kt index a11f1250f..8bc39da84 100644 --- a/codeCore/src/prog8/code/core/BuiltinFunctions.kt +++ b/codeCore/src/prog8/code/core/BuiltinFunctions.kt @@ -87,7 +87,10 @@ val BuiltinFunctions: Map = mapOf( // normal functions follow: "sizeof" to FSignature(true, listOf(FParam("object", DataType.values())), DataType.UBYTE), "sgn" to FSignature(true, listOf(FParam("value", NumericDatatypesNoBool)), DataType.BYTE), - "sqrt" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE), + "sqrt" to FSignature(true, listOf(FParam("value", NumericDatatypesNoBool)), DataType.UBYTE), + "sqrt__ubyte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UBYTE))), DataType.UBYTE), + "sqrt__uword" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE), + "sqrt__float" to FSignature(true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT), "divmod" to FSignature(false, listOf(FParam("number", arrayOf(DataType.UBYTE)), FParam("divident", arrayOf(DataType.UBYTE)), FParam("division", arrayOf(DataType.UBYTE)), FParam("remainder", arrayOf(DataType.UBYTE))), null), "divmodw" to FSignature(false, listOf(FParam("number", arrayOf(DataType.UWORD)), FParam("divident", arrayOf(DataType.UWORD)), FParam("division", arrayOf(DataType.UWORD)), FParam("remainder", arrayOf(DataType.UWORD))), null), "any" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE), diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 35fb36f8c..5a11fdf42 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -36,7 +36,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, "abs__byte", "abs__word", "abs__float" -> funcAbs(fcall, resultToStack, resultRegister, sscope) "any", "all" -> funcAnyAll(fcall, resultToStack, resultRegister, sscope) "sgn" -> funcSgn(fcall, resultToStack, resultRegister, sscope) - "sqrt" -> funcSqrt(fcall, resultToStack, resultRegister, sscope) + "sqrt__ubyte", "sqrt__uword", "sqrt__float" -> funcSqrt(fcall, resultToStack, resultRegister, sscope) "divmod" -> funcDivmod(fcall) "divmodw" -> funcDivmodW(fcall) "rol" -> funcRol(fcall) @@ -301,13 +301,33 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } private fun funcSqrt(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { - require(fcall.type != DataType.FLOAT) translateArguments(fcall, scope) - if(resultToStack) - asmgen.out(" jsr prog8_lib.func_sqrt16_stack") - else { - asmgen.out(" jsr prog8_lib.func_sqrt16_into_A") - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false) + when(fcall.type) { + DataType.UBYTE -> { + if(resultToStack) + asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_stack") + else { + asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_into_A") + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false) + } + } + DataType.UWORD -> { + if(resultToStack) + asmgen.out(" jsr prog8_lib.func_sqrt16_stack") + else { + asmgen.out(" jsr prog8_lib.func_sqrt16_into_A") + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false) + } + } + DataType.FLOAT -> { + if(resultToStack) + throw AssemblyError("no support for sqrt float onto stack") + else { + asmgen.out(" jsr floats.func_sqrt_into_FAC1") + assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen)) + } + } + else -> throw AssemblyError("weird dt") } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index 547fafdbf..06f82781e 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -17,7 +17,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe "abs__byte", "abs__word", "abs__float" -> funcAbs(call) "cmp" -> funcCmp(call) "sgn" -> funcSgn(call) - "sqrt" -> funcSqrt(call) + "sqrt__ubyte", "sqrt__uword", "sqrt__float" -> funcSqrt(call) "divmod" -> funcDivmod(call, IRDataType.BYTE) "divmodw" -> funcDivmod(call, IRDataType.WORD) "pop" -> funcPop(call) @@ -236,7 +236,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe addToResult(result, tr, -1, tr.resultFpReg) val resultFpReg = codeGen.registers.nextFreeFloat() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.SQRT, IRDataType.FLOAT, fpReg1 = resultFpReg, reg2 = tr.resultFpReg) + it += IRInstruction(Opcode.SQRT, IRDataType.FLOAT, fpReg1 = resultFpReg, fpReg2 = tr.resultFpReg) } return ExpressionCodeResult(result, IRDataType.FLOAT, -1, resultFpReg) } diff --git a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt index b2e3c8edb..5caaa3125 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -92,7 +92,7 @@ class VarConstantValueTypeAdjuster(private val program: Program, private val err errors.err("min/max not supported for floats", functionCallExpr.position) return noModifications } else { - errors.err("expected numeric arguments", functionCallExpr.position) + errors.err("expected numeric arguments", functionCallExpr.args[0].position) return noModifications } return listOf(IAstModification.SetExpression({functionCallExpr.target = it as IdentifierReference}, @@ -112,7 +112,25 @@ class VarConstantValueTypeAdjuster(private val program: Program, private val err return listOf(IAstModification.ReplaceNode(functionCallExpr, functionCallExpr.args[0], parent)) } else -> { - errors.err("expected numeric argument", functionCallExpr.position) + errors.err("expected numeric argument", functionCallExpr.args[0].position) + return noModifications + } + } + return listOf(IAstModification.SetExpression({functionCallExpr.target = it as IdentifierReference}, + IdentifierReference(listOf(replaceFunc), functionCallExpr.target.position), + functionCallExpr)) + } + } + else if(func==listOf("sqrt")) { + val t1 = functionCallExpr.args[0].inferType(program) + if(t1.isKnown) { + val dt = t1.getOrElse { throw InternalCompilerException("invalid dt") } + val replaceFunc = when(dt) { + DataType.UBYTE -> "sqrt__ubyte" + DataType.UWORD -> "sqrt__uword" + DataType.FLOAT -> "sqrt__float" + else -> { + errors.err("expected unsigned or float numeric argument", functionCallExpr.args[0].position) return noModifications } } diff --git a/compiler/res/prog8lib/c64/floats_funcs.asm b/compiler/res/prog8lib/c64/floats_funcs.asm index 3ec94bf11..79e560331 100644 --- a/compiler/res/prog8lib/c64/floats_funcs.asm +++ b/compiler/res/prog8lib/c64/floats_funcs.asm @@ -152,3 +152,11 @@ func_abs_f_into_FAC1 .proc ldx P8ZP_SCRATCH_REG rts .pend + +func_sqrt_into_FAC1 .proc + stx P8ZP_SCRATCH_REG + jsr MOVFM + jsr SQR + ldx P8ZP_SCRATCH_REG + rts + .pend diff --git a/compiler/src/prog8/compiler/BuiltinFunctions.kt b/compiler/src/prog8/compiler/BuiltinFunctions.kt index bb9208918..da3fd4643 100644 --- a/compiler/src/prog8/compiler/BuiltinFunctions.kt +++ b/compiler/src/prog8/compiler/BuiltinFunctions.kt @@ -16,7 +16,9 @@ internal val constEvaluatorsForBuiltinFuncs: Map "len" to ::builtinLen, "sizeof" to ::builtinSizeof, "sgn" to ::builtinSgn, - "sqrt" to { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()) } }, + "sqrt__ubyte" to { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()) } }, + "sqrt__uword" to { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()) } }, + "sqrt__float" to { a, p, prg -> oneFloatArgOutputFloat(a, p, prg) { sqrt(it) } }, "any" to { a, p, prg -> collectionArg(a, p, prg, ::builtinAny) }, "all" to { a, p, prg -> collectionArg(a, p, prg, ::builtinAll) }, "lsb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x and 255).toDouble() } }, @@ -64,6 +66,16 @@ private fun oneIntArgOutputInt(args: List, position: Position, progr return NumericLiteral.optimalInteger(function(integer).toInt(), args[0].position) } +private fun oneFloatArgOutputFloat(args: List, position: Position, program: Program, function: (arg: Double)->Double): NumericLiteral { + if(args.size!=1) + throw SyntaxError("built-in function requires one float argument", position) + val constval = args[0].constValue(program) ?: throw NotConstArgumentException() + if(constval.type != DataType.FLOAT) + throw SyntaxError("built-in function requires one float argument", position) + + return NumericLiteral(DataType.FLOAT, function(constval.number), args[0].position) +} + private fun collectionArg(args: List, position: Position, program: Program, function: (arg: List)->Double): NumericLiteral { if(args.size!=1) throw SyntaxError("builtin function requires one non-scalar argument", position) diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 80b2ceac2..bdcb26b3c 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -242,7 +242,7 @@ point variables. This includes ``print_f``, the routine used to print floating Radians to degrees. ``fabs (x)`` - Returns the absolute value of x. Deprecated, just use the builtin ``abs(x)`` function instead. + Returns the absolute value of x. Deprecated; just use the builtin ``abs(x)`` function instead. ``floor (x)`` Rounds the floating point down to an integer towards minus infinity. @@ -274,7 +274,7 @@ point variables. This includes ``print_f``, the routine used to print floating that contains various lookup tables generated by the 64tass assembler. ``sqrtf (x)`` - Floating point Square root. + Floating point Square root. Deprecated; just use the ``sqrt (x)`` builtin fuction instead. To do the reverse, squaring a floating point number, just write ``x*x``. ``tan (x)`` diff --git a/docs/source/programming.rst b/docs/source/programming.rst index f9ef74c82..ff8ae4dbc 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -774,9 +774,9 @@ sgn (x) Get the sign of the value. Result is -1, 0 or 1 (negative, zero, positive). sqrt (w) - 16 bit unsigned integer Square root. Result is unsigned byte. - To do the reverse, squaring an integer, just write ``x*x``. - Floating point square root has its own function `floats.sqrtf()` + Returns the square root of the number. + Supports unsigned integer (result is ubyte) and floating point numbers. + To do the reverse - squaring a number - just write ``x*x``. divmod (number, divident, division, remainder) Performs division and remainder calculation in a single call. This is faster than using separate '/' and '%' calculations. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index a9ecb34d6..670ecfd62 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -5,7 +5,7 @@ For 9.0 major changes ^^^^^^^^^^^^^^^^^^^^^ - DONE: added min() max() builtin functions - DONE: added 'cbm' block in the syslib module that now contains all CBM compatible kernal routines and variables -- DONE: rename sqrt16() to just sqrt(), rename floats.sqrt() to floats.sqrtf() +- DONE: rename sqrt16() to just sqrt(), make it accept multiple numeric types. Renamed floats.sqrt() to floats.sqrtf() but you can just use sqrt() - DONE: abs() now supports multiple datatypes including float. No need to use floats.fabs() anymore. - add "polymorphism" of min() and max() to several other builtin functions as well (divmod, pop, push) Fix docs. - 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition.