Subtilis: A new BASIC compiler for RiscOS

handy tools that can assist in the development of new software
Post Reply
markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Fri Aug 07, 2020 1:28 pm

You know how it is. You find a load of old computers in your dad's garage. You spent ridiculous amounts of time and money trying to fix them up, connect them to modern displays and find room for them. You then sit down to write that game you always wanted to write as 15 year old but never quite knew how. Here's how this scenario played out in my small London home in 2017.

"Now how do I do structures in BASIC again. Oh wow" and then ten minutes later "H'mm, this is kind of slow. What I really need is some sort of compiler". Three years later my A3000 port of Rebelstar is still no more than a few peeks and pokes in a tokenized BASIC file; but I have written a compiler...

Now before anybody gets too excited, note the following.

1. This is not a BBC BASIC compiler. The language, Subtilis, ressembles and is inpsired by BBC BASIC, but it is not and will never be compatible with it. For one thing, it parses ASCII files rather than tokenized BASIC files. In addition, the grammar is slightly different in places, there's a ton of keywords that aren't implemented and will never be implemented, e.g., GOSUB, READ, DATA, EVAL (well I might do a cut down version of EVAL at some point), RESTORE and many others. As time goes on, and I add more features to Subtilis, it's likely to diverge further and further from BBC BASIC.

2. It's massively untested and massively unfinished. A whole pile of the keywords are missing, including INPUT! There's no optimizer, no linker (so you're currently restricted to a single source file), no assembler, no error-recovery (so you get one terse parse error and that's it), and very little documentation, etc. There are also a pile of known bugs that I haven't got around to fixing yet (and presumably lots of unknown ones). To make matters worse, I still haven't implemented structures. I have just finished implementing strings though, and since you can now write Hello World in Subtilis, I thought the time had come to post about it.

Given the current state of the project, I'm not going to release any binaries for the compiler just yet, but for those of you among us who enjoy messing around with other people's, buggy, unfinished, under-documented code, then head on over to https://github.com/markdryan/subtilis. I'll leave the rest of you with the following attachment, compiled this morning with Subtilis. It's a statically compiled, absolute binary. To run, unzip it, copy the file to your Archimedes or RiscPC of choice, set the file type to Absolute and double click on it (at your own risk).
Attachments
RunImage.zip
(2.39 KiB) Downloaded 14 times

User avatar
IanS
Posts: 1437
Joined: Mon Aug 31, 2009 7:02 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by IanS » Fri Aug 07, 2020 1:45 pm

markdryan wrote:
Fri Aug 07, 2020 1:28 pm
I'll leave the rest of you with the following attachment, compiled this morning with Subtilis. It's a statically compiled, absolute binary. To run, unzip it, copy the file to your Archimedes or RiscPC of choice, set the file type to Absolute and double click on it (at your own risk).
That works. Do you have the source for that, to see how it compares to BBC Basic?

User avatar
daveejhitchins
Posts: 6004
Joined: Wed Jun 13, 2012 6:23 pm
Location: Newton Aycliffe, County Durham
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by daveejhitchins » Fri Aug 07, 2020 1:52 pm

Never thought I'd see the day :shock:

Well done . . .

Dave H.

User avatar
davidb
Posts: 2907
Joined: Sun Nov 11, 2007 10:11 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by davidb » Fri Aug 07, 2020 2:09 pm

It's always good to see people experimenting with languages and compilers. :)

Well done on your achievements so far! :D

markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Fri Aug 07, 2020 2:09 pm

Whenever, I tell anyone I'm writing a compiler, the first thing they ask me is how's the performance. So to pre-empt this question let me start by saying the performance is okay but not great. This is understandable really as there's no optimizer yet and the register allocator is, to be polite, a little naive. Integer performance is reasonably okay, floating point performance is awful (although it might be okay if you have an FPA accelerator, which I don't) and string performance is mixed. My plan is to add the missing features to the language, build the toolset and then establish a large body of Subtilis source code I can use to test and benchmark the compiler. When I have this, I'll do the optimizer and re-write the register allocator. With this in mind, I've started to collect a set of benchmarks in a repository (https://github.com/markdryan/basic-benchmarks). Most of these benchmarks were originally written by people on the forum and it's not clear to me how they're licensed. If anyone would like me to remove the code from my repo, please let me know. The original source of each of the benchmarks is noted in comments at the top of the code.

Anyway, here are the benchmark results for BBC Basic V (RiscOS 4.39), Subtilis (68b5f4b), and ABC 4.18. All these results were obtained on my 130MB Strong ARM RiscPC running RiscOS 4.39. All the benchmarks were run directly from the desktop. For these first set of benchmarks, lower scores are better.

Mandel
  • BBC BASIC : 29.2
  • Subtilis : 33.68
  • ABC : 42.92
Here we see the poor performance of floating point. The reason for this is that Subtilis is using the FPA instruction set. My RiscPC doesn't have an FPA accelerator so the floating point is handled by the FPE, which seems to be very slow. On the plus side, Subtilis is performing better than ABC here, which also uses the FPE. Also note that Subtilis is using 64 bit floats as opposed to 32 bit floats used by ABC and 40 bit floats by BBC BASIC. So you get a little bit more accuracy here.

Fannkuch
  • BBC BASIC : 625
  • Subtilis : 25
  • ABC : 39
Both compilers do well on this one. Subtilis is 25x times faster than BBC BASIC on this benchmark.

Life
  • BBC BASIC : 1535
  • Subtilis : 211
  • ABC : n/a
This benchmark wouldn't compile under ABC. It doesn't seem to support swap on arrays. However, we can see Subtilis is about 7x faster than BBC BASIC here.

Sieve
  • BBC BASIC : 26
  • Subtilis : 5
  • ABC : 9
Here we see a 5x speed improvement.

Finally, I ran some of the micro benchmarks in ClockSp through BBC BASIC on the RiscPC and the compilers. The results here are more mixed, although we see the same patterns; integer good, floating point awful, strings okay. Note I had to disable some of the tests for ABC as it was optimising the entire tests away, which is quite impressive and is something that Subtilis cannot yet do. Going forward though I guess we should be able to optimise away some of these benchmarks. In the meantime, here are the results. Note in these benchmarks, bigger is better.

Real REPEAT Loop
  • BBC BASIC : 2204
  • Subtilis : 1389
  • ABC : 1322
Integer REPEAT loop
  • BBC BASIC : 1659
  • Subtilis : 34142
  • ABC : 7468
Real FOR loop
  • BBC BASIC : 2064
  • Subtilis : 208
  • ABC : n/a
Yikes, this one is horrible. The local register allocator in conjunction with the FPE yield a horrible result.

Integer FOR loop
  • BBC BASIC : 1854
  • Subtilis : 3869
  • ABC : n/a
Trig/Log Test
  • BBC BASIC : 12509
  • Subtilis : 1600
  • ABC : 1563
String Manipulation
  • BBC BASIC : 3277
  • Subtilis : 6165
  • ABC : 6062
Note, I've modified this benchmark to use DIV instead of /, otherwise the results for ABC and Subtilis are skewed by the floating point calculations. Also, note that Subtilis's strings are unlimited in length, so it's at a disadvantage in this benchmark.

Procedure Call
  • BBC BASIC : 3571
  • Subtilis : 9252
  • ABC : 2605

markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Fri Aug 07, 2020 2:10 pm

daveejhitchins wrote:
Fri Aug 07, 2020 1:52 pm
Never thought I'd see the day :shock:
Neither to be honest, did I.

markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Fri Aug 07, 2020 2:15 pm

IanS wrote:
Fri Aug 07, 2020 1:45 pm
That works. Do you have the source for that, to see how it compares to BBC Basic?

Code: Select all

MODE 2

LOCAL DIM coords(43)
coords() = 0,0,0,2,0,-2,0,4,0,-4,0,5,0,-5,
    -2,2,2,-2,-2,-2,2,2,
     3,3,4,4,
     3,-3,4,-4,
    -3,-3,-4,-4,
    -3,3,-4,4,
    10,-6,-255,-255

VDU [23;8202;0;0;0;]
B%=0
FOR C%=0 TO 15
  IF C%=8 THEN B%=7 ENDIF
  VDU [19,C%,B%;0;]
NEXT

VDU [19,2,2;0;19,10,2;0;]
VDU [19,4,3;0;19,12,3;0;]
VDU [19,6,1;0;19,14,1;0;]
VDU [29,640;564;]

p=0.001

G%=0
PROCcircle(PI/20,0,2,0)
PROCcircle(PI/20,PI/5,4,0)
PROCcircle(PI/20,-PI/5,6,0)
S%=40
GCOL 0,8
counter% := 0
LOCAL X%
REPEAT
  X% = coords(counter%)
  Y% := coords(counter%+1)
  counter% += 2
  IF X%<>-255 THEN PROCsquare(X%,Y%) ENDIF
UNTIL X%=-255

G%=1
PROCcircle(PI/20,0,2,PI)
PROCcircle(PI/20,PI/5,4,PI)
PROCcircle(PI/20,-PI/5,6,PI)
C%=0
D%=1
REPEAT
    T% := TIME
    VDU [19,2+C%,2;0;19,10+C%,2;0;]
    VDU [19,2+D%,0;0;19,10+D%,7;0;]
    VDU [19,4+C%,3;0;19,12+C%,3;0;]
    VDU [19,4+D%,0;0;19,12+D%,7;0;]
    VDU [19,6+C%,1;0;19,14+C%,1;0;]
    VDU [19,6+D%,0;0;19,14+D%,7;0;]
    D%=C%
    C%=C%EOR1
    REPEAT UNTIL TIME>8+T%
UNTIL FALSE

DEF PROCsquare(X%,Y%)
  Y%=Y%-2
  MOVE X%*S%+S%,Y%*S%-S%
  MOVE X%*S%-S%,Y%*S%-S%
  PLOT 85,X%*S%+S%,Y%*S%+S%
  PLOT 85,X%*S%-S%,Y%*S%+S%
ENDPROC

DEF PROCcircle(xr,zr,c,b)
  C%=0
  FOR a := b TO PI+b STEP PI/48
    GCOL G%,c+C%
    Z% := SIN(a)*450
    X% := COS(a)*450
    Y% := 0
    IF xr <> 0 THEN
        T1% := COS(xr)*Y%+SIN(xr)*Z%
        T2% := -SIN(xr)*Y%+COS(xr)*Z%
        Y% = T1%
        Z% = T2%
    ENDIF
    IF zr<>0 THEN
        T1% := COS(zr)*X%+SIN(zr)*Y%
        T2% :=- SIN(zr)*X%+COS(zr)*Y%
        X% = T1%
        Y% = T2%
    ENDIF
    X%=X%/((Z%+1000)*p)
    Y%=Y%/((Z%+1000)*p)
    PLOT 69,X%,Y%
    PLOT 69,X%,Y%+4
    C%=C% EOR 1
  NEXT
ENDPROC
Needless to say I didn't write this from scratch. It's a modified version that appeared on the stardot logo thread. I think I modified this one (viewtopic.php?f=5&t=19431&hilit=stardot+logo#p270353) by ChrisB.

Note the lack of a DATA statement, the square brackets around the VDU statements, and variable declaration with := which creates a local variable.

User avatar
Dave Footitt
Posts: 930
Joined: Thu Jun 22, 2006 10:31 am
Location: Abandoned Uranium Workings
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by Dave Footitt » Fri Aug 07, 2020 10:07 pm

Looks interesting Mark I really enjoyed your talk on it =D>

markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Sun Aug 23, 2020 12:59 pm

There's been a few little updates to Subtilis since I last posted. I've fixed some bugs and added two new keywords; GET$ and VAL.

VAL is one of those compiler unfriendly keywords where the return type of the expression it generates cannot always be known at compile time. The compiler has to assume that it will be a floating point expression and so VAL is implemented by converting a string to a floating point number using floating point arithmetic, which is wonderfully slow on most Archimedes. For this reason, I've added variant of VAL which takes an extra parameter. The extra parameter denotes the base of the number represented by the string in the first parameter, and when specified, forces Subtilis to perform a string to integer conversion using integer arithmetic. For example,

Code: Select all

print val("256", 10)
print val("100", 16)
will print

Code: Select all

256
256
Valid values for the base are 2-10 and 16. The floating point version of VAL doesn't yet support 'E', but at least this is consistent with the lexer which doesn't either.

I was planning to implement INSTR next, but I've been working on strings for almost 6 months now and am suffering from a case of string fatigue. So instead, I'm going to start looking at SYS and the assembler.

markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Sat Sep 19, 2020 9:33 am

I've added support for SYS calls. SYS calls mostly work as expected with one big limitation. The id of the SYS call needs to be known at compile time. It can be an integer or a string, but it needs to be constant. So you can do

Code: Select all

sys &6a
or

Code: Select all

sys "OS_Reset"
but not

Code: Select all

a% := &6a
sys a%
On the plus side, knowing the id of the SYS call at compile time allows us to perform some optimisations. Firstly, the conversion from the name of the SYS call ("OS_Reset") to the integer ID (&6a) needed to generate the SWI instruction can be done at compile time. The two code samples above then generate the exact same code. The other advantage is that the compiler knows which registers the various SYS calls corrupt, and it passes this information to the register allocator. This means that we don't necessarily need to preserve and restore all registers when making a SYS call. For example, if we do a

Code: Select all

sys "OS_Write0", "hello world"
The compiler knows that "OS_Write0" only corrupts R0 and so it only needs to preserve and restore R0 and it will only do that if the value in R0 is still needed by the function. This works better for some SYS calls than others. It's not so useful for SYS calls that have multiple entry points such as "OS_SpriteOP", but it does still help a little. A maximum of 6 registers will be preserved and restored when making a call to "OS_SpriteOp".

The other problem is that to make this work, the compiler needs to know about all the RiscOS SYS calls, and for the time being it only knows about a subset of them. For example, it doesn't currently know anything about the WIMP. I'll add these missing calls over time. I'll probably also allow the programmer to make a sys call using a constant integer ID that the compiler doesn't recognize. Such calls will be slower however as the compiler will need to assume all the registers have been corrupted.

For more information about SYS calls in Subtilis check out https://github.com/markdryan/subtilis/b ... lis.md#sys.

Now we can do SYS calls, we can do sprites. So there's probably enough working in Subtilis to write a simple (silent) game now. I did consider giving this a go, but decided that Subtilis was still a bit too irritating to develop in right now, so I'll continue with the language improvements and missing features for the being. Next on the list is GCOL TINT and COLOUR TINT.

PMF
Posts: 10
Joined: Sun Sep 06, 2020 2:13 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by PMF » Thu Oct 01, 2020 4:54 pm

Hi I'd be interested to see how you arrived at some of your figures for ABC, and in particular if you chose to make use of some of its optional optimisation features.

There are a bunch of compiler directives that can be used to tell it that you know what you are doing, and that strict adherance to some of the features of BBC Basic can be skipped. These make a huge difference to the overall speed.

For example -- you can turn off Array Bounds Checking - so that it doesn't generate loads of tediuos compare instructions for all the array indecies.

-- You can turn off Zeroing of the contents of local variables - which speeds up entry to proceedures.

-- And if you are using ! operators you can promise that they are 4-byte aligned and so it can use just one instruction rather than the whole song-and-dance sequence.

To do these try REM {NOZEROLOCALS} and REM {ALIGNEDPLING} and REM {NOARRAYCHECK} in the start of your program - Might be interesting

Paul
Paul Fellows
Head of Languages, Acornsoft, 1983-85
Microsystems Software Manager, Acorn 85-88

PMF
Posts: 10
Joined: Sun Sep 06, 2020 2:13 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by PMF » Thu Oct 01, 2020 6:12 pm

In fact here are a list of the handy compiler directives that you can use to tune the code that ABC Generates

REM {NOSTACKCHECK} turn off stack checking - this speeds up PROC and FN calls a lot

REM {NOESCAPECHECK} turns off the placement of a call to SWi OS_EscapeCheck between each statement. This is necessary for the strict behaviour, but very slow. If you want to escape from the code use this with its partner REM {ESCAPECHECK} selectively to control where the checks get done

REM {NOGOTOSUSED} If you promise me not to use GOTOs then I can remember whats in registers from one statement to another, without fear of you jumping into the middle and stuffing up. It also means I don't need to add a table of where all the GOTO targets might be on the end of your code, so it will be smaller.

REM {NOZEROLOCALS} Don't labouriously write zero into every newly instanced local varaible only to have it overwritten shortly afterwards.

REM {SYSCONSTONLY} and REM {SYSKNOWNONLY} With these I can guarentee to generate the native SWI call rather than code to have to go and look up the name of the SWI at runtime.

REM {ALIGNEDPLING} promise that all your use of ! is 4-byte aligned and I'll generate LDR and STR instructions that assume it too. Otherwise, we get to pick up the bytes one at a time and mash them together. Again, you could use these selectively arount different bits of code if there were certain sections that could be relied on the be aligned and others that might not be.

REM{NOARRAYCHECK} dont bother checking array indecies for out of bounds. Saves a reasonable number of instructions for array accesses

A bunch of these are ganged-together by the -quick option which can be added to the command line and which there was once a UI check box for in version 3 of the compiler, I think it has vanished in later ones.

There are more of these directives to deal with more code-saving measures... such as not clearing out registers on return from a SWI call

Anyway, just interested to see how this sits with what your doing - for me there was always the conflict between "Compatibility" with the range of things that could be writen for the interpreter and "Performance" where dropping certain checks saved lots of code - my answer was to default to the former, but offer the latter through the simple use of these directives.
Paul Fellows
Head of Languages, Acornsoft, 1983-85
Microsystems Software Manager, Acorn 85-88

markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Thu Oct 01, 2020 7:47 pm

Paul, thanks for all the information. This is excellent. Someone to discuss BASIC compilers with :-).

The sources for all the benchmarks I used are here https://github.com/markdryan/basic-benchmarks. I built them using the version of ABC that came with my copy of the DDE purchased from ROOL about 3 years ago. The version number of the DDE is 28d. I didn't enable any specific optimisations when compiling with ABC. I just dragged the BASIC programs to the ABC icon and executed the resulting binary. Reading your posts I think I need to re-run the ABC benchmarks with some of these optmisation enabled to get a fairer result. I'll try this out at the weekend.

These ones I'm not going to enable

REM {NOARRAYCHECK}
REM {NOZEROLOCALS}
REM {ALIGNEDPLING}

Subtilis always bounds checks arrays and always zeros locals and arrays and there's no way to tell it not to do so. Also, Subtilis doesn't support the indirection operators so none of the benchmarks I ran make use of these.

These I am

REM {NOESCAPECHECK}
REM {ESCAPECHECK}

Subtilis does check for the escape button but only does so at the start of each iteration of a loop and on entries to procedures and functions. So I can modify the ABC BASIC benchmarks to do the same thing to make things fairer. This is going to make a big difference I imagine.

REM {NOGOTOSUSED}

Subtilis doesn't support GOTO and so it's only fair to enable this.

REM {NOSTACKCHECK}

I need to enable this as well. It's on my TODO list, but right now, Subtilis doesn't check for stack overflow on procedure call. It will happily overwrite the heap for fun and profit. So for the time being I will enable this one to make things fairer.

REM {SYSCONSTONLY} and REM {SYSKNOWNONLY}

Subtilis doesn't support non constant SWI names, either strings or integers, so it's only fair to enable this one as well.
There are more of these directives to deal with more code-saving measures... such as not clearing out registers on return from a SWI call
This one might be worth enabling. What does it do exactly? Subtilis only preserves and restores the registers that may be corrupted by a syscall and also are still live, i.e., still needed by the function. The other registers remain unchanged by a call to SYS. It also doesn't zero any of the registers not explicitly specified in the input or output lists, which BBC BASIC appears to do. I actually wasted a couple of hours the other day trying to figure out why the rocks example in chapter 4 of the Archimedes Game Makers Manual (http://www.riscos.com/support/developer ... .htm#l0046) didn't work in Subtilis. The reason was that the rocks example doesn't provide all the trailing parameters expected by some of the SYS calls it makes. It seems to assume that the parameters it doesn't pass will default to zero, and in BBC BASIC they appear to do so.
Anyway, just interested to see how this sits with what your doing - for me there was always the conflict between "Compatibility" with the range of things that could be writen for the interpreter and "Performance" where dropping certain checks saved lots of code
I guess things are simpler for me as I broke compatibility with BBC BASIC on day one when I decided to use text rather than tokenized source files. Since then I've taken all sorts of liberties with the language.

Regarding compiler options, currently there are none. I will probably have to add some, like the ability to turn off escape checking, but I intend to keep these few in number. I haven't written the optimizer yet, but when I write it, it will always be on. There won't be any way to disable it. My current plan is that the options that are provided would be specified in a text file in the same directory as the rest of the source code, rather than inline in the code or via compiler options. None of this is implemented yet.

I have some questions about ABC, if you have time

1. How do you generate sys calls when the SYS call id is not known at compile time? Are you using self modifying code?
2. I noticed that ABC was executing some of the ClockSP benchmarks in 0 seconds, causing a division by zero error in ClockSP itself. Does it optimise away code like

Code: Select all

FOR i% = 0 TO 10000 : NEXT i%
to

Code: Select all

i% = 10000
?

markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Sat Oct 03, 2020 2:03 pm

I've been playing around with the optimisation options in ABC a little and the results are quite interesting. The first thing I tried was to enable the following options:

Code: Select all

REM {NOESCAPECHECK}
REM {NOGOTOSUSED}
REM {NOSTACKCHECK}
REM {SYSCONSTONLY}
REM {SYSKNOWNONLY}
Additionally, I placed a

Code: Select all

REM {ESCAPECHECK}
at the start of every procedure, function and loop. As far as I can tell, this set of options matches most closely what Subtilis does. I then re-ran some of the larger benchmarks but didn't see much difference.


Mandel:

  • Subtilis : 33.68
  • ABC : 42.92
  • ABC Opt Escape 42.93


Fannkuch:

  • Subtilis : 25
  • ABC: 39
  • ABC Opt Escape : 39


Sieve:

  • Subtilis : 5
  • ABC : 9
  • ABC Opt Escape: 9



I then removed all the

Code: Select all

REM {ESCAPECHECK}
statements in the ABC code and also disabled escape checking in Subtilis. There's an internal setting in Subtilis that allows you to do this, although it's not currently exposed to the user so requires a recompile to disable. This had a dramatic effect on ABC's performance in two of the benchmarks. Remember, smaller is better for these benchmarks.


Fannkuch:

  • Subtilis : 25
  • Subtilis No Escape : 21
  • ABC: 39
  • ABC Opt No Escape : 17


Sieve:

  • Subtilis : 5
  • Subtilis No Escape : 5
  • ABC : 9
  • ABC Opt No Escape: 5


Mandel:

  • Subtilis : 33.68
  • Subtilis No escape : 33.52
  • ABC : 42.92
  • ABC Opt No Escape 42.07


As the results for Sieve seemed to be tied I created a new version of the benchmark which increased the maximum number of iterations to 500000 to see whether there were any differences between the compilers.

Sieve 500000:
  • Subtilis No Escape : 27
  • ABC Opt No Escape: 30


It turns out there was a small difference.

In summary, ABC seems to be quite far ahead now in the Fannkuch benchmark, Subtilis is still far ahead in the mandel benchmark and it also does a little bit better in Sieve.

I also re-ran ClockSp with escape handling turned off for both compilers.

Subtilis No Escape
  • Real REPEAT Loop: 1408
  • Integer REPEAT Loop: 70294
  • REAL FOR Loop: 209
  • Integer FOR Loop: 6768
  • Trig/Log Test: 1598
  • String Manipulation: 6223
  • Procedure Call: 16735


ABC No Escape
  • Real REPEAT Loop: 1448
  • Integer REPEAT Loop: 59750
  • REAL FOR Loop: n/a
  • Integer FOR Loop: n/a
  • Trig/Log Test: 1570
  • String Manipulation: 6217
  • Procedure Call: 21756



ABC is doing better than Subtilis in general on these microbenchmarks. It's ahead on the for loops and procedure call but behind on the integer REPEAT loop. There's not much difference between the compilers with the other benchmarks.

It's hard to draw too many conclusions from this limited set of benchmarks, but the trend I'm seeing here is that ABC's escape handling seems to have a much bigger impact on the benchmark results than Subtilis's, even when both compilers are checking for escapes at the same locations in the code. With escape handling turned off there's not too much difference between the compilers. Subtilis does better on some benchmarks, ABC on others.

Regarding escape handling, Subtilis checks for the escape button at the entry to every loop, procedure and function call. It does so however, not by calling OS_EscapeCheck, but by reading an internal variable, stored in memory that is set by an escape handler, initialised right at the start of the program. Perhaps, this explains the apparent difference in performance of escape handling between the two compilers.

The source code for all the benchmarks I ran can be found here: https://github.com/markdryan/basic-benchmarks. I used the same version of the compilers that were mentioned in my initial benchmark post above. I'll update this original post later on with the results for escape checking disabled.

markdryan
Posts: 166
Joined: Sun Aug 20, 2017 11:37 pm
Contact:

Re: Subtilis: A new BASIC compiler for RiscOS

Post by markdryan » Sat Nov 21, 2020 10:13 pm

Subtilis now has an assembler. Currently, it supports all the ARM2 instructions and most of the FPA instructions. WFC, RFC, LFM and SFM aren't implemented yet. The assembler works differently to the BBC BASIC assembler. Assembly takes place at compile time rather than runtime. Inline assembly is not supported but it is possible to mix BASIC and assembly code in the same source file. Functions and procedures may be written in one of two different languages; BASIC or ARM assembly. The assembler is strongly typed and supports strings, integers, doubles, integer registers, FPA registers and identifiers. It also supports most of the BASIC expression syntax and functions, e.g, STRING$ and COS. There are no macros but there is a simple FOR loop for generating code at compile time. You can also define constants. Here's an example of what the assembler looks like

Code: Select all

MODE 1
PROCbanner

def PROCbanner
[
	def screen_width = 40
	def header = STRING$(screen_width,"*")
	def gap = STRING$(13," ")

	ADR R0, header_label
	SWI "OS_Write0"
	SWI "OS_NewLine"
	ADR R0, message
	SWI "OS_Write0"
	SWI "OS_NewLine"
	ADR R0, header_label
	SWI "OS_Write0"
	SWI "OS_NewLine"
	MOV PC, R14

header_label
	EQUS header
message
	EQUS "*" + gap + "Hello World!" + gap + "*"
]
Note the use of def (borrowed from ABC) to define constants, named sys calls which are translated at compile time, STRING$ and string concatenation.

There's an example of the FOR loop here https://github.com/markdryan/subtilis/b ... s/demo#L54 where it's used to create a table of coordinates for a SIN wave at compile time and also here https://github.com/markdryan/subtilis/b ... es/regs#L3 where it's used to initialise a bunch of registers.

There are still a few things missing, such as not being able to call other functions and procedures from an assembly language procedure. However, there's enough of it working now for me to move onto the next phase of the project. There's a small amount of documentation available about the assembler here: https://github.com/markdryan/subtilis/b ... #assembler.

Some fun facts about Subtilis. It's now almost 60000 lines of C code. It takes 2.5 seconds to build on my Haswell laptop, 9.5 minutes to build with the DDE on a StrongARM RiscPC. The RiscOS binary, compiled with -Otime, is 177kb. It runs fairly well on the RiscPC with most examples, which in fairness are all pretty small at the moment, taking about a second to compile. It does run on an A3000 but it's a bit too slow. The Fannkuch benchmark https://github.com/markdryan/basic-benc ... /FannkuchS takes 50 seconds to compile. The bottleneck in the compiler is the register allocator so hopefully things will speed up when I re-write it next year. The assembler, which doesn't use the register allocator is much quicker and is probably usable on the A3000 right now, as long as you keep the BASIC to a minimum. This small example https://github.com/markdryan/subtilis/b ... s/arm_fill takes 5 seconds to build on the A3000.

Post Reply

Return to “development tools”