abs() now works on multiple data types including float.

no need to use floats.fabs() anymore
This commit is contained in:
Irmen de Jong 2023-04-29 22:11:26 +02:00
parent 319079de7a
commit 38efe25c68
11 changed files with 134 additions and 88 deletions

View File

@ -79,7 +79,10 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
// cmp returns a status in the carry flag, but not a proper return value
"cmp" to FSignature(false, listOf(FParam("value1", IntegerDatatypesNoBool), FParam("value2", NumericDatatypesNoBool)), null),
"prog8_lib_stringcompare" to FSignature(true, listOf(FParam("str1", arrayOf(DataType.STR)), FParam("str2", arrayOf(DataType.STR))), DataType.BYTE),
"abs" to FSignature(true, listOf(FParam("value", IntegerDatatypesNoBool)), DataType.UWORD),
"abs" to FSignature(true, listOf(), null),
"abs__byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE))), DataType.BYTE),
"abs__word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD))), DataType.WORD),
"abs__float" to FSignature(true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT),
"len" to FSignature(true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD),
// normal functions follow:
"sizeof" to FSignature(true, listOf(FParam("object", DataType.values())), DataType.UBYTE),

View File

@ -33,7 +33,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
"mkword" -> funcMkword(fcall, resultToStack, resultRegister)
"min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(fcall, resultToStack, resultRegister)
"max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(fcall, resultToStack, resultRegister)
"abs" -> funcAbs(fcall, resultToStack, resultRegister, sscope)
"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)
@ -301,6 +301,7 @@ 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")
@ -679,21 +680,32 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
val dt = fcall.args.single().type
if(resultToStack) {
when (dt) {
DataType.UBYTE -> asmgen.out(" ldy #0")
DataType.BYTE -> asmgen.out(" jsr prog8_lib.abs_b_stack")
DataType.UWORD -> {}
DataType.WORD -> asmgen.out(" jsr prog8_lib.abs_w_stack")
else -> throw AssemblyError("weird type")
else -> throw AssemblyError("no support for abs onto stack for this dt")
}
} else {
when (dt) {
DataType.UBYTE -> asmgen.out(" ldy #0")
DataType.BYTE -> asmgen.out(" jsr prog8_lib.abs_b_into_AY")
DataType.UWORD -> {}
DataType.WORD -> asmgen.out(" jsr prog8_lib.abs_w_into_AY")
DataType.BYTE -> {
asmgen.out(" jsr prog8_lib.abs_b_into_A")
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A,false)
}
DataType.WORD -> {
asmgen.out(" jsr prog8_lib.abs_w_into_AY")
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY)
}
DataType.FLOAT -> {
asmgen.out(" jsr floats.func_abs_f_into_FAC1")
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
}
DataType.UBYTE -> {
asmgen.assignRegister(RegisterOrPair.A, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.A, false, fcall.position, scope, asmgen))
}
DataType.UWORD -> {
asmgen.assignRegister(RegisterOrPair.AY, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.AY, false, fcall.position, scope, asmgen))
}
else -> throw AssemblyError("weird type")
}
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY)
}
}

View File

@ -14,7 +14,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
return when(call.name) {
"any" -> funcAny(call)
"all" -> funcAll(call)
"abs" -> funcAbs(call)
"abs__byte", "abs__word", "abs__float" -> funcAbs(call)
"cmp" -> funcCmp(call)
"sgn" -> funcSgn(call)
"sqrt" -> funcSqrt(call)
@ -165,12 +165,6 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, tr.resultReg, -1)
when (sourceDt) {
DataType.UBYTE -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1 = tr.resultReg)
}
return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1)
}
DataType.BYTE -> {
val notNegativeLabel = codeGen.createLabelName()
val compareReg = codeGen.registers.nextFree()
@ -196,7 +190,12 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
result += IRCodeChunk(notNegativeLabel, null)
return ExpressionCodeResult(result, IRDataType.WORD, tr.resultReg, -1)
}
else -> throw AssemblyError("weird type")
DataType.FLOAT -> {
val resultFpReg = codeGen.registers.nextFreeFloat()
addInstr(result, IRInstruction(Opcode.FABS, IRDataType.FLOAT, fpReg1 = resultFpReg, fpReg2 = tr.resultFpReg), null)
return ExpressionCodeResult(result, IRDataType.FLOAT, -1, resultFpReg)
}
else -> throw AssemblyError("weird dt")
}
}

View File

@ -100,6 +100,27 @@ class VarConstantValueTypeAdjuster(private val program: Program, private val err
functionCallExpr))
}
}
else if(func==listOf("abs")) {
val t1 = functionCallExpr.args[0].inferType(program)
if(t1.isKnown) {
val dt = t1.getOrElse { throw InternalCompilerException("invalid dt") }
val replaceFunc = when(dt) {
DataType.BYTE -> "abs__byte"
DataType.WORD -> "abs__word"
DataType.FLOAT -> "abs__float"
DataType.UBYTE, DataType.UWORD -> {
return listOf(IAstModification.ReplaceNode(functionCallExpr, functionCallExpr.args[0], parent))
}
else -> {
errors.err("expected numeric argument", functionCallExpr.position)
return noModifications
}
}
return listOf(IAstModification.SetExpression({functionCallExpr.target = it as IdentifierReference},
IdentifierReference(listOf(replaceFunc), functionCallExpr.target.position),
functionCallExpr))
}
}
return noModifications
}
}

View File

@ -144,3 +144,11 @@ func_all_f_stack .proc
jsr a_times_5
jmp prog8_lib.func_all_b_stack
.pend
func_abs_f_into_FAC1 .proc
stx P8ZP_SCRATCH_REG
jsr MOVFM
jsr ABS
ldx P8ZP_SCRATCH_REG
rts
.pend

View File

@ -86,16 +86,15 @@ func_all_w_stack .proc
abs_b_stack .proc
; -- push abs(A) on stack (as unsigned word)
jsr abs_b_into_AY
jsr abs_b_into_A
sta P8ESTACK_LO,x
stz P8ESTACK_HI,x
dex
rts
.pend
abs_b_into_AY .proc
; -- AY = abs(A) (abs always returns unsigned word)
ldy #0
abs_b_into_A .proc
; -- A = abs(A)
cmp #0
bmi +
rts

View File

@ -532,7 +532,7 @@ class TestOptimization: FunSpec({
uword @shared zz
zz += 60 ; NOT ok to remove initializer, should evaluate to 60
ubyte @shared xx
xx = 6+lsb(abs(xx)) ; is not an initializer because it references xx
xx = 6+lsb(mkword(xx,22)) ; is not an initializer because it references xx
}
}
"""

View File

@ -27,14 +27,14 @@ class TestTypecasts: FunSpec({
main {
sub start() {
float fl
floats.print_f(abs(fl))
floats.print_f(lsb(fl))
}
}"""
val errors = ErrorReporterForTests()
val result = compileText(C64Target(), false, text, writeAssembly = false, errors=errors)
result shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "type mismatch, was: FLOAT expected one of: [UBYTE, BYTE, UWORD, WORD]"
errors.errors[0] shouldContain "type mismatch, was: FLOAT expected one of: [UWORD, WORD]"
}
test("not casting bool operands to logical operators") {

View File

@ -225,61 +225,65 @@ floats
Floating point support is only available on c64, cx16 and virtual targets for now.
Provides definitions for the ROM/Kernal subroutines and utility routines dealing with floating
point variables. This includes ``print_f``, the routine used to print floating point numbers,
``fabs`` to get the absolute value of a floating point number, and a dozen or so floating point
math routines.
point variables. This includes ``print_f``, the routine used to print floating point numbers.
atan(x)
``atan (x)``
Arctangent.
ceil(x)
``ceil (x)``
Rounds the floating point up to an integer towards positive infinity.
cos(x)
``cos (x)``
Cosine.
If you want a fast integer cosine, have a look at examples/cx16/sincos.p8
that contains various lookup tables generated by the 64tass assembler.
deg(x)
``deg (x)``
Radians to degrees.
floor (x)
``fabs (x)``
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.
ln(x)
``ln (x)``
Natural logarithm (base e).
log2(x)
``log2 (x)``
Base 2 logarithm.
minf(x, y)
``minf (x, y)``
returns the smallest of x and y.
maxf(x, y)
``maxf (x, y)``
returns the largest of x and y.
rad(x)
``print_f (x)``
prints the floating point number x as a string.
``rad (x)``
Degrees to radians.
round(x)
``round (x)``
Rounds the floating point to the closest integer.
sin(x)
``sin (x)``
Sine.
If you want a fast integer sine, have a look at examples/cx16/sincos.p8
that contains various lookup tables generated by the 64tass assembler.
sqrtf(x)
``sqrtf (x)``
Floating point Square root.
To do the reverse, squaring a floating point number, just write ``x*x``.
tan(x)
``tan (x)``
Tangent.
rndf()
``rndf ()``
returns the next random float between 0.0 and 1.0 from the Pseudo RNG sequence.
rndseedf(seed)
``rndseedf (seed)``
Sets a new seed for the float pseudo-RNG sequence. Use a negative non-zero number as seed value.
@ -306,41 +310,41 @@ Usually a custom lookup table is the way to go if your application needs these,
but perhaps the provided ones can be of service too.
rnd()
``rnd ()``
Returns next random byte 0-255 from the pseudo-RNG sequence.
rndw()
``rndw ()``
Returns next random word 0-65535 from the pseudo-RNG sequence.
rndseed(uword seed1, uword seed2)
``rndseed (uword seed1, uword seed2)``
Sets a new seed for the pseudo-RNG sequence (both rnd and rndw). The seed consists of two words.
Do not use zeros for the seed!
sin8u(x)
``sin8u (x)``
Fast 8-bit ubyte sine of angle 0..255, result is in range 0..255
sin8(x)
``sin8 (x)``
Fast 8-bit byte sine of angle 0..255, result is in range -127..127
sinr8u(x)
``sinr8u (x)``
Fast 8-bit ubyte sine of angle 0..179 (each is a 2 degree step), result is in range 0..255
Angles 180..255 will yield a garbage result!
sinr8(x)
``sinr8 (x)``
Fast 8-bit byte sine of angle 0..179 (each is a 2 degree step), result is in range -127..127
Angles 180..255 will yield a garbage result!
cos8u(x)
``cos8u (x)``
Fast 8-bit ubyte cosine of angle 0..255, result is in range 0..255
cos8(x)
``cos8 (x)``
Fast 8-bit byte cosine of angle 0..255, result is in range -127..127
cosr8u(x)
``cosr8u (x)``
Fast 8-bit ubyte cosine of angle 0..179 (each is a 2 degree step), result is in range 0..255
Angles 180..255 will yield a garbage result!
cosr8(x)
``cosr8 (x)``
Fast 8-bit byte cosine of angle 0..179 (each is a 2 degree step), result is in range -127..127
Angles 180..255 will yield a garbage result!

View File

@ -762,8 +762,7 @@ Math
^^^^
abs (x)
Absolute value of an integer. Value returned is an unsigned word.
For floating point numbers, use ``floats.fabs()`` instead.
Returns the absolute value of a number.
min (x, y)
Returns the smallest of x and y. Supported for integer types only, for floats use ``floats.minf()`` instead.

View File

@ -6,7 +6,8 @@ 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()
- add "polymorphism" of min() and max() to several other builtin functions as well (abs, divmod, pop, push) Fix docs.
- 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.
It is documented behavior to now loop 'around' $00 but it's too easy to forget about!
Lot of work because of so many special cases in ForLoopsAsmgen.....