adding setlsb() and setmsb() builtin functions

This commit is contained in:
Irmen de Jong 2023-09-15 01:23:47 +02:00
parent 31c132c2eb
commit 95e4490a8a
10 changed files with 126 additions and 19 deletions

View File

@ -70,6 +70,8 @@ class FSignature(val pure: Boolean, // does it have side effects?
val BuiltinFunctions: Map<String, FSignature> = mapOf( val BuiltinFunctions: Map<String, FSignature> = mapOf(
// this set of function have no return value and operate in-place: // this set of function have no return value and operate in-place:
"setlsb" to FSignature(false, listOf(FParam("variable", arrayOf(DataType.WORD, DataType.UWORD)), FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), null),
"setmsb" to FSignature(false, listOf(FParam("variable", arrayOf(DataType.WORD, DataType.UWORD)), FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), null),
"rol" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), "rol" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
"ror" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), "ror" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
"rol2" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), "rol2" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
@ -131,4 +133,4 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
"callfar" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD), "callfar" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD),
) )
val InplaceModifyingBuiltinFunctions = setOf("rol", "ror", "rol2", "ror2", "sort", "reverse") val InplaceModifyingBuiltinFunctions = setOf("setlsb", "setmsb", "rol", "ror", "rol2", "ror2", "sort", "reverse")

View File

@ -41,6 +41,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
"rol2" -> funcRol2(fcall) "rol2" -> funcRol2(fcall)
"ror" -> funcRor(fcall) "ror" -> funcRor(fcall)
"ror2" -> funcRor2(fcall) "ror2" -> funcRor2(fcall)
"setlsb" -> funcSetLsbMsb(fcall, false)
"setmsb" -> funcSetLsbMsb(fcall, true)
"sort" -> funcSort(fcall) "sort" -> funcSort(fcall)
"reverse" -> funcReverse(fcall) "reverse" -> funcReverse(fcall)
"memory" -> funcMemory(fcall, discardResult, resultRegister) "memory" -> funcMemory(fcall, discardResult, resultRegister)
@ -609,6 +611,10 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE) asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE)
} }
private fun funcSetLsbMsb(fcall: PtBuiltinFunctionCall, msb: Boolean) {
TODO("setlsb/setmsb for $fcall")
}
private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
translateArguments(fcall, scope) translateArguments(fcall, scope)
val dt = fcall.args.single().type val dt = fcall.args.single().type

View File

@ -40,6 +40,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
"max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(call) "max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(call)
"sort" -> funcSort(call) "sort" -> funcSort(call)
"reverse" -> funcReverse(call) "reverse" -> funcReverse(call)
"setlsb" -> funcSetLsbMsb(call, false)
"setmsb" -> funcSetLsbMsb(call, true)
"rol" -> funcRolRor(Opcode.ROXL, call) "rol" -> funcRolRor(Opcode.ROXL, call)
"ror" -> funcRolRor(Opcode.ROXR, call) "ror" -> funcRolRor(Opcode.ROXR, call)
"rol2" -> funcRolRor(Opcode.ROL, call) "rol2" -> funcRolRor(Opcode.ROL, call)
@ -576,6 +578,78 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
return ExpressionCodeResult(result, vmDt, -1, -1) return ExpressionCodeResult(result, vmDt, -1, -1)
} }
private fun funcSetLsbMsb(call: PtBuiltinFunctionCall, msb: Boolean): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val target = call.args[0]
when(target) {
is PtIdentifier -> {
val valueTr = exprGen.translateExpression(call.args[1])
addToResult(result, valueTr, valueTr.resultReg, -1)
result += IRCodeChunk(null, null).also {
val pointerReg = codeGen.registers.nextFree()
it += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=pointerReg, labelSymbol = target.name)
if(msb)
it += IRInstruction(Opcode.INC, IRDataType.WORD, reg1=pointerReg)
it += IRInstruction(Opcode.STOREI, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=pointerReg)
// TODO use STOREZI if the value is zero
}
}
is PtArrayIndexer -> {
require(!target.usesPointerVariable)
if(target.splitWords) {
val varName = target.variable.name + if(msb) "_msb" else "_lsb"
val valueTr = exprGen.translateExpression(call.args[1])
addToResult(result, valueTr, valueTr.resultReg, -1)
val constIndex = target.index.asConstInteger()
if(constIndex!=null) {
val offsetReg = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=offsetReg, immediate = constIndex)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=offsetReg, labelSymbol = varName)
// TODO: use STOREZX if the value is zero
}
} else {
val indexTr = exprGen.translateExpression(target.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=indexTr.resultReg, labelSymbol = varName)
// TODO: use STOREZX if the value is zero
}
}
}
else {
val valueTr = exprGen.translateExpression(call.args[1])
addToResult(result, valueTr, valueTr.resultReg, -1)
val eltSize = codeGen.program.memsizer.memorySize(target.type)
val constIndex = target.index.asConstInteger()
if(constIndex!=null) {
val offsetReg = codeGen.registers.nextFree()
val offset = eltSize*constIndex + if(msb) 1 else 0
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=offsetReg, immediate = offset)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=offsetReg, labelSymbol = target.variable.name)
// TODO: use STOREZX if the value is zero
}
} else {
val indexTr = exprGen.translateExpression(target.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
result += IRCodeChunk(null, null).also {
if(eltSize>1)
it += codeGen.multiplyByConst(IRDataType.BYTE, indexTr.resultReg, eltSize)
if(msb)
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexTr.resultReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=indexTr.resultReg, labelSymbol = target.variable.name)
// TODO: use STOREZX if the value is zero
}
}
}
}
else -> throw AssemblyError("weird target for setlsb/setmsb: $target")
}
return ExpressionCodeResult(result, IRDataType.WORD, -1, -1)
}
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunks { private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunks {
val assignment = PtAssignment(target.position) val assignment = PtAssignment(target.position)
val assignTarget = PtAssignTarget(target.position) val assignTarget = PtAssignTarget(target.position)

View File

@ -6,10 +6,10 @@ package prog8.buildversion
const val MAVEN_GROUP = "prog8" const val MAVEN_GROUP = "prog8"
const val MAVEN_NAME = "compiler" const val MAVEN_NAME = "compiler"
const val VERSION = "9.5-SNAPSHOT" const val VERSION = "9.5-SNAPSHOT"
const val GIT_REVISION = 4097 const val GIT_REVISION = 4101
const val GIT_SHA = "UNKNOWN" const val GIT_SHA = "31c132c2ebfef803ae197489fc7eaf56642501ac"
const val GIT_DATE = "2023-09-08T19:29:49Z" const val GIT_DATE = "2023-09-14T21:04:23Z"
const val GIT_BRANCH = "master" const val GIT_BRANCH = "master"
const val BUILD_DATE = "2023-09-12T19:47:42Z" const val BUILD_DATE = "2023-09-14T21:06:25Z"
const val BUILD_UNIX_TIME = 1694548062963L const val BUILD_UNIX_TIME = 1694725585234L
const val DIRTY = 1 const val DIRTY = 1

View File

@ -1183,8 +1183,13 @@ internal class AstChecker(private val program: Program,
if(funcName[0] in InplaceModifyingBuiltinFunctions) { if(funcName[0] in InplaceModifyingBuiltinFunctions) {
// in-place modification, can't be done on literals // in-place modification, can't be done on literals
if(functionCallStatement.args.any { it !is IdentifierReference && it !is ArrayIndexedExpression && it !is DirectMemoryRead }) { if(funcName[0]=="setlsb" || funcName[0]=="setmsb") {
errors.err("invalid argument to a in-place modifying function", functionCallStatement.args.first().position) val firstArg = functionCallStatement.args[0]
if(firstArg !is IdentifierReference && firstArg !is ArrayIndexedExpression)
errors.err("invalid argument to a in-place modifying function", functionCallStatement.args.first().position)
} else {
if(functionCallStatement.args.any { it !is IdentifierReference && it !is ArrayIndexedExpression && it !is DirectMemoryRead })
errors.err("invalid argument to a in-place modifying function", functionCallStatement.args.first().position)
} }
} }

View File

@ -909,6 +909,12 @@ ror2 (x)
Modifies in-place, doesn't return a value (so can't be used in an expression). Modifies in-place, doesn't return a value (so can't be used in an expression).
You can ror a memory location directly by using the direct memory access syntax, so like ``ror2(@($5000))`` You can ror a memory location directly by using the direct memory access syntax, so like ``ror2(@($5000))``
setlsb (x, value)
Sets the least significant byte of word variable x to a new value. Leaves the MSB untouched.
setmsb (x, value)
Sets the most significant byte of word variable x to a new value. Leaves the LSB untouched.
sizeof (name) sizeof (name)
Number of bytes that the object 'name' occupies in memory. This is a constant determined by the data type of Number of bytes that the object 'name' occupies in memory. This is a constant determined by the data type of
the object. For instance, for a variable of type uword, the sizeof is 2. the object. For instance, for a variable of type uword, the sizeof is 2.

View File

@ -1,6 +1,8 @@
TODO TODO
==== ====
- allow taking address of array variable (now gives parser error)
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
- IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction - IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction
- IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified! - IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified!

View File

@ -3,20 +3,31 @@
main { main {
sub start() { sub start() {
uword zz = 0 uword zz = $ea45
txt.print_uwhex(zz, true)
txt.nl()
@(&zz) = 1 setlsb(zz, $11)
txt.print_uw(zz) txt.print_uwhex(zz, true)
txt.nl() txt.nl()
@(&zz+1) = 2 setmsb(zz, $22)
txt.print_uw(zz) txt.print_uwhex(zz, true)
txt.nl() txt.nl()
ubyte bb
bb = @(&zz)
txt.print_ub(bb)
txt.nl() txt.nl()
bb = @(&zz+1)
txt.print_ub(bb) uword[] array = [$1234,$5678,$abcd] ; TODO also with @split
ubyte one = 1
ubyte two = 2
txt.print_uwhex(array[1], true)
txt.nl()
txt.print_uwhex(array[2], true)
txt.nl()
setlsb(array[one],$ff)
setmsb(array[two],$00)
txt.print_uwhex(array[1], true)
txt.nl()
txt.print_uwhex(array[2], true)
txt.nl() txt.nl()
} }
} }

View File

@ -189,6 +189,7 @@ expression :
arrayindexed: arrayindexed:
scoped_identifier arrayindex scoped_identifier arrayindex
// TODO to allow chained array indexing: | arrayindexed arrayindex // TODO to allow chained array indexing: | arrayindexed arrayindex
// TODO or even to allow array indexing on any uword address value: | expression arrayindex
; ;

View File

@ -14,7 +14,7 @@
<keywords keywords="&amp;;-&gt;;@;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" /> <keywords keywords="&amp;;-&gt;;@;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" />
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%ir;%launcher;%option;%output;%zeropage;%zpreserved;iso:;petscii:;sc:" /> <keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%ir;%launcher;%option;%output;%zeropage;%zpreserved;iso:;petscii:;sc:" />
<keywords3 keywords="@requirezp;@shared;@split;@zp;bool;byte;const;float;str;ubyte;uword;void;word" /> <keywords3 keywords="@requirezp;@shared;@split;@zp;bool;byte;const;float;str;ubyte;uword;void;word" />
<keywords4 keywords="abs;all;any;callfar;callram;callrom;clamp;cmp;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;reverse;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;sgn;sizeof;sort;sqrt;swap;|&gt;" /> <keywords4 keywords="abs;all;any;callfar;callram;callrom;clamp;cmp;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;reverse;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sort;sqrt;swap;|&gt;" />
</highlighting> </highlighting>
<extensionMap> <extensionMap>
<mapping ext="p8" /> <mapping ext="p8" />