mirror of
https://github.com/irmen/prog8.git
synced 2025-11-02 13:16:07 +00:00
remove "@split" tag
The default is to split word arrays. If you need your word array to not be split, use @nosplit on the array.
This commit is contained in:
@@ -530,6 +530,5 @@ enum class ZeropageWish {
|
||||
|
||||
enum class SplitWish {
|
||||
DONTCARE,
|
||||
SPLIT,
|
||||
NOSPLIT
|
||||
}
|
||||
@@ -1261,12 +1261,12 @@ $repeatLabel""")
|
||||
// print a message when more optimal code is possible for 65C02 cpu
|
||||
val variable = symbolTable.lookup(arrayVariable.name)!!
|
||||
if(variable is StStaticVariable && variable.length!!<=128u)
|
||||
errors.info("the jump address array is @split, but @nosplit would create more efficient code here", jump.position)
|
||||
errors.info("the jump address array is split, but @nosplit would create more efficient code here", jump.position)
|
||||
}
|
||||
} else {
|
||||
// print a message when more optimal code is possible for 6502 cpu
|
||||
if(!arrayIdx.splitWords)
|
||||
errors.info("the jump address array is @nosplit, but @split would create more efficient code here", jump.position)
|
||||
errors.info("the jump address array is @nosplit, but split would create more efficient code here", jump.position)
|
||||
}
|
||||
}
|
||||
// we can do the address evaluation right now and just use a temporary pointer variable
|
||||
|
||||
@@ -1038,7 +1038,7 @@ _doplot beq +
|
||||
|
||||
; y*40 lookup table. Pretty compact because it all fits in a word and we only need 240 y positions.
|
||||
; a y*80 lookup table would be very large (lo,mid,hi for 480 values...)
|
||||
uword[240] @split @shared times40 = [
|
||||
uword[240] @shared times40 = [
|
||||
0, 40, 80, 120, 160, 200, 240, 280, 320, 360, 400, 440, 480, 520, 560, 600,
|
||||
640, 680, 720, 760, 800, 840, 880, 920, 960, 1000, 1040, 1080, 1120, 1160,
|
||||
1200, 1240, 1280, 1320, 1360, 1400, 1440, 1480, 1520, 1560, 1600, 1640, 1680,
|
||||
|
||||
@@ -1090,8 +1090,8 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
if(decl.datatype.isPointerArray) {
|
||||
if(decl.splitwordarray!= SplitWish.SPLIT)
|
||||
errors.err("pointer arrays can only be @split", decl.position)
|
||||
if(decl.splitwordarray==SplitWish.NOSPLIT)
|
||||
errors.err("pointer arrays can only be split", decl.position)
|
||||
}
|
||||
|
||||
if(decl.datatype.isStructInstance && decl.origin!=VarDeclOrigin.SUBROUTINEPARAM) {
|
||||
|
||||
@@ -71,12 +71,11 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
// check splitting of word arrays
|
||||
if(decl.splitwordarray != SplitWish.DONTCARE && !decl.datatype.isWordArray && !decl.datatype.isPointerArray) {
|
||||
if(decl.origin != VarDeclOrigin.ARRAYLITERAL)
|
||||
errors.err("@split and @nosplit are for word or pointer arrays only", decl.position)
|
||||
errors.err("@nosplit is for word or pointer arrays only", decl.position)
|
||||
}
|
||||
|
||||
if(decl.datatype.isWordArray) {
|
||||
var changeDataType: DataType?
|
||||
var changeSplit: SplitWish = decl.splitwordarray
|
||||
when(decl.splitwordarray) {
|
||||
SplitWish.DONTCARE -> {
|
||||
changeDataType = if(decl.datatype.isSplitWordArray) null else {
|
||||
@@ -86,16 +85,6 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
else
|
||||
DataType.arrayFor(eltDt.base)
|
||||
}
|
||||
changeSplit = SplitWish.SPLIT
|
||||
}
|
||||
SplitWish.SPLIT -> {
|
||||
changeDataType = if(decl.datatype.isSplitWordArray) null else {
|
||||
val eltDt = decl.datatype.elementType()
|
||||
if(eltDt.isPointer)
|
||||
TODO("convert array of pointers to split words array type")
|
||||
else
|
||||
DataType.arrayFor(eltDt.base)
|
||||
}
|
||||
}
|
||||
SplitWish.NOSPLIT -> {
|
||||
changeDataType = if(decl.datatype.isSplitWordArray && !decl.datatype.elementType().isPointer)
|
||||
@@ -109,7 +98,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
value = ArrayLiteral(InferredTypes.knownFor(changeDataType), value.value, value.position)
|
||||
}
|
||||
val newDecl = VarDecl(decl.type, decl.origin, changeDataType, decl.zeropage,
|
||||
changeSplit, decl.arraysize, decl.name, decl.names,
|
||||
decl.splitwordarray, decl.arraysize, decl.name, decl.names,
|
||||
value, decl.sharedWithAsm, decl.alignment, decl.dirty, decl.position)
|
||||
return listOf(IAstModification.ReplaceNode(decl, newDecl, parent))
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila
|
||||
if(addrOf!=null) {
|
||||
val identType = addrOf.identifier?.inferType(program)?.getOrUndef()
|
||||
if(identType?.isSplitWordArray==true) {
|
||||
return Pair("argument ${mismatch + 1} type mismatch, was: $actual (because arg is a @split word array) expected: $expected", call.args[mismatch].position)
|
||||
return Pair("argument ${mismatch + 1} type mismatch, was: $actual (because arg is a split word array) expected: $expected", call.args[mismatch].position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1951,7 +1951,7 @@ main {
|
||||
val src="""
|
||||
main {
|
||||
sub start() {
|
||||
uword[10] @split @shared splitarray
|
||||
uword[10] @shared splitarray
|
||||
uword[10] @nosplit @shared nosplitarray
|
||||
|
||||
^^uword ptr1 = &&splitarray
|
||||
@@ -1992,9 +1992,9 @@ main {
|
||||
errors.errors.size shouldBe 3
|
||||
errors.warnings.size shouldBe 0
|
||||
errors.infos.size shouldBe 0
|
||||
errors.errors[0] shouldContain "pointer arrays can only be @split"
|
||||
errors.errors[1] shouldContain "was: ^^ubyte (because arg is a @split word array) expected: ^^main.Node"
|
||||
errors.errors[2] shouldContain "was: ^^ubyte (because arg is a @split word array) expected: ^^main.Node"
|
||||
errors.errors[0] shouldContain "pointer arrays can only be split"
|
||||
errors.errors[1] shouldContain "was: ^^ubyte (because arg is a split word array) expected: ^^main.Node"
|
||||
errors.errors[2] shouldContain "was: ^^ubyte (because arg is a split word array) expected: ^^main.Node"
|
||||
}
|
||||
|
||||
test("passing split array of structpointers to a subroutine in various forms should be param type ptr to ubyte (the lsb part of the split array)") {
|
||||
@@ -2005,7 +2005,7 @@ main {
|
||||
}
|
||||
|
||||
sub start() {
|
||||
^^Node[10] @split nodearray
|
||||
^^Node[10] nodearray
|
||||
func(&&nodearray)
|
||||
func(&nodearray)
|
||||
func(nodearray)
|
||||
|
||||
@@ -1129,30 +1129,26 @@ thing {
|
||||
}
|
||||
}
|
||||
|
||||
test("pointer arrays are always split") {
|
||||
test("pointer arrays are split by default") {
|
||||
val src="""
|
||||
%option enable_floats
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
^^bool[10] @split @shared barray
|
||||
^^word[10] @split @shared warray
|
||||
^^float[10] @split @shared farray
|
||||
|
||||
^^bool[10] @shared barrayns
|
||||
^^word[10] @shared warrayns
|
||||
^^float[10] @shared farrayns
|
||||
^^bool[10] @shared barray
|
||||
^^word[10] @shared warray
|
||||
^^float[10] @shared farray
|
||||
}
|
||||
}"""
|
||||
|
||||
val result = compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false)!!
|
||||
val st = result.compilerAst.entrypoint.statements
|
||||
st.size shouldBe 7
|
||||
st.size shouldBe 4
|
||||
val decls = st.filterIsInstance<VarDecl>()
|
||||
decls.size shouldBe 6
|
||||
decls.size shouldBe 3
|
||||
decls.all { it.datatype.sub!=null } shouldBe true
|
||||
decls.all { it.datatype.isPointerArray } shouldBe true
|
||||
decls.all { it.datatype.isPointerArray } shouldBe true
|
||||
decls.all { it.datatype.isSplitWordArray } shouldBe true
|
||||
}
|
||||
|
||||
test("on..call in nested scope compiles correctly with temp variable introduced") {
|
||||
|
||||
@@ -80,8 +80,8 @@ def make_test_array(datatype, comparison: C):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_cmp_array() {")
|
||||
print(f""" {datatype} @shared x
|
||||
{datatype}[] @split values = [0, 0]
|
||||
{datatype}[] @split sources = [0, 0]
|
||||
{datatype}[] values = [0, 0]
|
||||
{datatype}[] sources = [0, 0]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
|
||||
@@ -36,9 +36,9 @@ main {{
|
||||
test_is_var()
|
||||
txt.print("\\n!=var: ")
|
||||
test_not_var()
|
||||
txt.print("\\n==array[] @split: ")
|
||||
txt.print("\\n==array[] split: ")
|
||||
test_is_array_splitw()
|
||||
txt.print("\\n!=array[] @split: ")
|
||||
txt.print("\\n!=array[] split: ")
|
||||
test_not_array_splitw()
|
||||
txt.print("\\n==expr: ")
|
||||
test_is_expr()
|
||||
@@ -97,7 +97,7 @@ nonzero_values = {
|
||||
def make_test_is_zero(datatype):
|
||||
print(f"""
|
||||
sub test_is_zero() {{
|
||||
{datatype}[] @split sources = [9999, 9999]
|
||||
{datatype}[] sources = [9999, 9999]
|
||||
success = 0
|
||||
|
||||
sources[1]={zero_values[datatype]}
|
||||
@@ -155,7 +155,7 @@ skip4:
|
||||
def make_test_not_zero(datatype):
|
||||
print(f"""
|
||||
sub test_not_zero() {{
|
||||
{datatype}[] @split sources = [9999, 9999]
|
||||
{datatype}[] sources = [9999, 9999]
|
||||
success = 0
|
||||
|
||||
sources[1]={nonzero_values[datatype]}
|
||||
@@ -229,7 +229,7 @@ testnumbers = {
|
||||
def make_test_is_number(datatype, equals):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_is_number() {" if equals else " sub test_not_number() {")
|
||||
print(f""" {datatype}[] @split sources = [9999, 9999]
|
||||
print(f""" {datatype}[] sources = [9999, 9999]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
@@ -286,8 +286,8 @@ skip{test_index}b:
|
||||
def make_test_is_var(datatype, equals):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_is_var() {" if equals else " sub test_not_var() {")
|
||||
print(f""" {datatype}[] @split sources = [9999, 9999]
|
||||
{datatype}[] @split values = [8888,8888]
|
||||
print(f""" {datatype}[] sources = [9999, 9999]
|
||||
{datatype}[] values = [8888,8888]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
@@ -346,8 +346,8 @@ def make_test_is_array(datatype, equals):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_is_array_splitw() {" if equals else " sub test_not_array_splitw() {")
|
||||
print(f"""
|
||||
{datatype}[] @split values = [9999, 8888]
|
||||
{datatype}[] @split sources = [9999, 8888]
|
||||
{datatype}[] values = [9999, 8888]
|
||||
{datatype}[] sources = [9999, 8888]
|
||||
success = 0""")
|
||||
expected = 0
|
||||
test_index = 0
|
||||
@@ -441,7 +441,7 @@ skip{test_index}d:
|
||||
def make_test_is_expr(datatype, equals):
|
||||
numbers = testnumbers[datatype]
|
||||
print(" sub test_is_expr() {" if equals else " sub test_not_expr() {")
|
||||
print(f""" {datatype}[] @split sources = [9999, 9999]
|
||||
print(f""" {datatype}[] sources = [9999, 9999]
|
||||
cx16.r4 = 1
|
||||
cx16.r5 = 1
|
||||
success = 0""")
|
||||
|
||||
@@ -137,7 +137,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
|
||||
override fun visitVardecl(ctx: VardeclContext): VarDecl {
|
||||
val tags = ctx.TAG().map { it.text }
|
||||
val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@split", "@nosplit", "@shared", "@alignword", "@alignpage", "@align64", "@dirty")
|
||||
val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@nosplit", "@shared", "@alignword", "@alignpage", "@align64", "@dirty")
|
||||
for(tag in tags) {
|
||||
if(tag !in validTags)
|
||||
throw SyntaxError("invalid variable tag '$tag'", ctx.toPosition())
|
||||
@@ -167,17 +167,12 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
DataType.arrayFor(baseDt.base, split!=SplitWish.NOSPLIT)
|
||||
}
|
||||
|
||||
val splitWords = if(split==SplitWish.DONTCARE) {
|
||||
if(dt.isPointerArray) SplitWish.SPLIT // pointer arrays are always @split by default
|
||||
else split
|
||||
} else split
|
||||
|
||||
return VarDecl(
|
||||
VarDeclType.VAR, // can be changed to MEMORY or CONST as required
|
||||
VarDeclOrigin.USERCODE,
|
||||
dt,
|
||||
zp,
|
||||
splitWords,
|
||||
split,
|
||||
arrayIndex,
|
||||
name,
|
||||
if(identifiers.size==1) emptyList() else identifiers,
|
||||
@@ -486,7 +481,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
override fun visitSub_param(pctx: Sub_paramContext): SubroutineParameter {
|
||||
val decl = pctx.vardecl()
|
||||
val tags = decl.TAG().map { t -> t.text }
|
||||
val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@split", "@nosplit", "@shared")
|
||||
val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@nosplit", "@shared")
|
||||
for(tag in tags) {
|
||||
if(tag !in validTags)
|
||||
throw SyntaxError("invalid parameter tag '$tag'", pctx.toPosition())
|
||||
@@ -724,7 +719,6 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
private fun getSplitOption(tags: List<String>): SplitWish {
|
||||
return when {
|
||||
"@nosplit" in tags -> SplitWish.NOSPLIT
|
||||
"@split" in tags -> SplitWish.SPLIT
|
||||
else -> SplitWish.DONTCARE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ class VarDecl(
|
||||
fun createAutoOptionalSplit(array: ArrayLiteral): VarDecl {
|
||||
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
||||
val arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") }
|
||||
val split = if(arrayDt.isSplitWordArray) SplitWish.SPLIT else if(arrayDt.isWordArray) SplitWish.NOSPLIT else SplitWish.DONTCARE
|
||||
val split = if(arrayDt.isSplitWordArray) SplitWish.DONTCARE else if(arrayDt.isWordArray) SplitWish.NOSPLIT else SplitWish.DONTCARE
|
||||
val arraysize = ArrayIndex.forArray(array)
|
||||
return VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, arrayDt, ZeropageWish.NOT_IN_ZEROPAGE,
|
||||
split, arraysize, autoVarName, emptyList(), array,
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
remove "@split" tag SplitWish.NOSPLIT
|
||||
|
||||
|
||||
|
||||
LONG TYPE
|
||||
---------
|
||||
- implement the other comparison operators (<,>,<=,>=) on longs
|
||||
|
||||
@@ -358,7 +358,7 @@ See also :ref:`pointervars` and the chapter about it :ref:`pointers`.
|
||||
|
||||
**LSB/MSB split word and str arrays:**
|
||||
|
||||
As an optimization, (u)word arrays and str arrays are split by the compiler in memory as two separate arrays,
|
||||
As an optimization, (u)word arrays, pointer arrays, and str arrays are split by the compiler in memory as two separate arrays,
|
||||
one with the LSBs and one with the MSBs of the word values. This is more efficient to access by the 6502 cpu.
|
||||
It also allows a maximum length of 256 for word arrays, where normally it would have been 128.
|
||||
|
||||
@@ -366,13 +366,14 @@ For normal prog8 array indexing, the compiler takes care of the distiction for y
|
||||
*But for assembly code, or code that otherwise accesses the array elements directly, you have to be aware of the distinction from 'normal' arrays.*
|
||||
In the assembly code, the array is generated as two byte arrays namely ``name_lsb`` and ``name_msb``, immediately following eachother in memory.
|
||||
|
||||
The ``@nosplit`` tag can be added to the variable declaration to *never* split the array. This is useful for compatibility with
|
||||
The ``@nosplit`` tag can be added to the variable declaration to *not* split the array. This is useful for compatibility with
|
||||
code that expects the words to be sequentially in memory (such as the cx16.FB_set_palette routine).
|
||||
|
||||
.. note::
|
||||
Most but not all array operations are supported yet on "split word arrays".
|
||||
If you get a compiler error message, simply revert to a regular sequential word array using ``@nosplit``,
|
||||
and please report the issue.
|
||||
Some obscure array operations may not yet be supported on "split word arrays".
|
||||
If you get a compiler error message hinting that this is the case,
|
||||
simply revert to a regular sequential word array using ``@nosplit``, and please report the issue so that
|
||||
the missing function can be added.
|
||||
|
||||
.. note::
|
||||
Array literals are stored as split arrays if they're initializing a split word array, otherwise,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<option name="HAS_STRING_ESCAPES" value="true" />
|
||||
</options>
|
||||
<keywords keywords="&;&&;&<;&>;->;@;^^;alias;and;as;asmsub;break;clobbers;continue;do;downto;else;extsub;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;on;or;repeat;return;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" />
|
||||
<keywords2 keywords="%address;%align;%asm;%asmbinary;%asminclude;%breakpoint;%encoding;%import;%ir;%jmptable;%launcher;%memtop;%option;%output;%zeropage;%zpallowed;%zpreserved;@align64;@alignpage;@alignword;@bank;@dirty;@nosplit;@nozp;@requirezp;@shared;@split;@zp;atascii:;c64os:;cp437:;default:;iso16:;iso5:;iso:;kata:;petscii:;sc:" />
|
||||
<keywords2 keywords="%address;%align;%asm;%asmbinary;%asminclude;%breakpoint;%encoding;%import;%ir;%jmptable;%launcher;%memtop;%option;%output;%zeropage;%zpallowed;%zpreserved;@align64;@alignpage;@alignword;@bank;@dirty;@nosplit;@nozp;@requirezp;@shared;@zp;atascii:;c64os:;cp437:;default:;iso16:;iso5:;iso:;kata:;petscii:;sc:" />
|
||||
<keywords3 keywords="^^bool;^^byte;^^float;^^long;^^str;^^ubyte;^^uword;^^word;bool;byte;const;float;long;str;struct;ubyte;uword;void;word" />
|
||||
<keywords4 keywords="abs;bmx;call;callfar;callfar2;cbm;clamp;cmp;conv;cx16;defer;diskio;divmod;floats;len;lsb;lsw;math;max;memory;min;mkword;msb;msw;offsetof;peek;peekbool;peekf;peekw;poke;pokebool;pokef;pokew;psg;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sqrt;strings;sys;txt;verafx" />
|
||||
</highlighting>
|
||||
|
||||
@@ -43,7 +43,7 @@ syn region prog8ArrayType matchgroup=prog8Type
|
||||
\ start="\<\%(u\?byte\|u\?word\|float\|str\|bool\)\[" end="\]"
|
||||
\ transparent
|
||||
syn keyword prog8StorageClass const
|
||||
syn match prog8StorageClass "\(^\|\s\)\(@zp\|@bank\|@shared\|@split\|@nosplit\|@nozp\|@requirezp\|@align64\|@alignword\|@alignpage\|@dirty\)\>"
|
||||
syn match prog8StorageClass "\(^\|\s\)\(@zp\|@bank\|@shared\|@nosplit\|@nozp\|@requirezp\|@align64\|@alignword\|@alignpage\|@dirty\)\>"
|
||||
|
||||
syn region prog8Block start="{" end="}" transparent
|
||||
syn region prog8Expression start="(" end=")" transparent
|
||||
|
||||
Reference in New Issue
Block a user