LLVM-MOS

Chat about anything CX16 related that doesn't fit elsewhere
DigitalMonk
Posts: 27
Joined: Tue Apr 27, 2021 2:44 pm

LLVM-MOS

Post by DigitalMonk »



12 minutes ago, Serentty said:




One important thing not to miss is the list of free zero page locations.



Yeah...  I was really hoping I could just slip by on those...  A lot of them are BASIC workspaces that shouldn't matter much, but there are also KERNAL workspaces that would be very bad to stomp on.  I'll have to break out all my ZP memory maps and compare them. 

I'm really glad that the number of pseudo-registers and their locations is completely configurable through just text files.

Once I can get all my stuff running, I will make a cleanup pass to make sure I don't have "hackery" left sitting around, and then I'll definitely send a pull-request...  Hmmm, gotta fork the repo inside GitHub first, probably, instead of just messing with it on my local machine ?

User avatar
StephenHorn
Posts: 565
Joined: Tue Apr 28, 2020 12:00 am
Contact:

LLVM-MOS

Post by StephenHorn »


By the way, does LLVM-MOS include a way to implement interrupt routines in C++?

Developer for Box16, the other X16 emulator. (Box16 on GitHub)
I also accept pull requests for x16emu, the official X16 emulator. (x16-emulator on GitHub)
Serentty
Posts: 13
Joined: Sat Jun 26, 2021 10:51 am

LLVM-MOS

Post by Serentty »


This is what I put in the linker script for the X16 (at the bottom—the rest is the same as the C64).


Quote




PROVIDE(__rc0 = 0x0002);

INCLUDE imag_reg/125.ld

ASSERT(__rc0 == 0x0002, "Inconsistent zero page map.")

ASSERT(__rc125 == 0x007f, "Inconsistent zero page map.")



__stack = 0xBFFF;



This should match the locations of the free zero page space. Also, since I haven't used banking yet, I placed the software stack (which doesn't get used that often thanks to the static stack optimization) in the banked area to give the maximum possible space for my program. I imagine that you would want this to be in low RAM in actual practice, though.

DigitalMonk
Posts: 27
Joined: Tue Apr 27, 2021 2:44 pm

LLVM-MOS

Post by DigitalMonk »



20 minutes ago, StephenHorn said:




By the way, does LLVM-MOS include a way to implement interrupt routines in C++?



First, their focus has been on clang, not clang++, so I'm not sure how much C++ support is present (I would expect all the language features to be there because that's a front-end common thing, but I know that the runtime library doesn't exist because that's a backend supplied library and they haven't worked on it yet).  I do want to start poking around with C++ language features, just to see how they go, but I want to get all my platforms working again first.

Second, I'd swear that I've seen somewhere (thought it was this thread, but can't find it) that interrupt handlers couldn't be written yet because of an implementation detail about how they handle function calls...  __BUT__ I've been trying to compare and contrast 5 different C compilers, so I could very easily be thinking of one of the others...

Serentty
Posts: 13
Joined: Sat Jun 26, 2021 10:51 am

LLVM-MOS

Post by Serentty »


Oh yeah, with all due respect to @SlithyMatt (Hi, I love your videos!), I've been trying to push the limits of how high-level I can write my code and still have it compile down to the same assembly as if I had written it in a low-level style, and the sheer amount of optimization that LLVM does makes a lot of stuff which is higher-level than C useful without being slower.



I just had a cool idea that worked out very well. Initially, I just wrote a simple copy_to_vram() function that copied blocks of data into VRAM using the autoincrement feature of the VERA. But then it occurred to me that this could be more general. Instead of making the function take data directly, I could instead make it take an iterator. Now, I can encapsulate the concept of writing something to VRAM with autoincrement, even if it's being calculated on the fly, without having to write code for autoincrement in the calculation code. The concept is very similar to passing in a closure or a generator. It goes without saying that the compiled assembly was the same when I tell it to iterate over an array. I've heard people talk about how powerful iterators are and how they're more than just a replacement for indexed loops, but this is the first time I've run into a situation like this where they're very handy. It allows me to separate the high-level calculations from the low-level bit fiddling and memory accesses, but have them compiled to be all mixed together the way you would writing the assembly by hand.



I also write functions to set VERA registers which take lots of different enumerations, and constant folding can turn something like this:

 


Quote





Layer::One.set_config(MapDimension::Tiles32,
MapDimension::Tiles32,
T256C::Off,
Bitmap::On,
ColourDepth::Bits4);



Into this:

 


Quote





lda #6
sta 40756





In terms of bad generated assembly, most of the limitations at the moment have to do with making the best use of the 6502's instruction set—it doesn't know about all of the NMOS instructions yet, and absolutely none of the CMOS ones. But that's something which isn't hard to fix, and is being worked on. So far I haven't run into a single case of bad assembly where the cause was my code being too high-level, and LLVM's optimization's not being able to make it lower-level, instead of the immaturity of the backend, and it not being able to make the best use of the instructions.

Serentty
Posts: 13
Joined: Sat Jun 26, 2021 10:51 am

LLVM-MOS

Post by Serentty »



17 minutes ago, DigitalMonk said:




First, their focus has been on clang, not clang++, so I'm not sure how much C++ support is present (I would expect all the language features to be there because that's a front-end common thing, but I know that the runtime library doesn't exist because that's a backend supplied library and they haven't worked on it yet).  I do want to start poking around with C++ language features, just to see how they go, but I want to get all my platforms working again first.



This makes me thankful how Rust divides its standard library between freestanding and non-freestanding parts, so huge swaths of it are already available on the Commander X16, and indeed even the VIC-20. I suppose I'm living up to the Rust programmer stereotype by taking every opportunity to praise it relative to C++. ?


Quote




Second, I'd swear that I've seen somewhere (thought it was this thread, but can't find it) that interrupt handlers couldn't be written yet because of an implementation detail about how they handle function calls...  __BUT__ I've been trying to compare and contrast 5 different C compilers, so I could very easily be thinking of one of the others...



That's correct. There's an optimization pass which checks to see which functions are recursive (even if indirectly). If a function is not recursive, as most are not, then instead of putting local variables on the stack, it allocates memory statically for them. In the future, the plan is also to check to see if two functions can ever be running at the same time, and if they can't be, to make them share the same memory for their locals. It's all very fascinating stuff. But the effect of this is that if you call a function from an interrupt handler, you could very well be violating the assumption that there can't be multiple instances of that function running at once, and overwrite the locals of the instance.



I actually have managed to write an interrupt handler in Rust for the Commodore 64 regardless, but only because the last thing my program did was set up a raster interrupt, and then just wait for it every frame, doing all further processing in interrupts. So interrupts are perfectly usable if you never have to come back from them. ? I managed to get a sprite bouncing around in the style of the old DVD screensaver. And then I increased it to eight at once.

Scott Robison
Posts: 952
Joined: Fri Mar 19, 2021 9:06 pm

LLVM-MOS

Post by Scott Robison »



20 minutes ago, Serentty said:




This makes me thankful how Rust divides its standard library between freestanding and non-freestanding parts, so huge swaths of it are already available on the Commander X16, and indeed even the VIC-20. I suppose I'm living up to the Rust programmer stereotype by taking every opportunity to praise it relative to C++. ?



Really, you're living up to the stereotype of all language evangelists. Python, Rust, C++, Java, Assembly... it's as much religion as it is art and science. ?

Greg King
Posts: 162
Joined: Wed Jul 08, 2020 1:14 pm

LLVM-MOS

Post by Greg King »



1 hour ago, Serentty said:




PROVIDE(__rc0 = 0x0002);

INCLUDE imag_reg/125.ld

ASSERT(__rc0 == 0x0002, "Inconsistent zero page map.")

ASSERT(__rc125 == 0x007f, "Inconsistent zero page map.")



There are two register lists:


  1. pseudo-registers (used by X16's Kernal)


  2. imaginary registers (used by LLVM-MOS)


Be careful how much you overlap them!  Imaginary register "__rs0" is used as the permanent soft-stack pointer.

DigitalMonk
Posts: 27
Joined: Tue Apr 27, 2021 2:44 pm

LLVM-MOS

Post by DigitalMonk »



2 minutes ago, Greg King said:




There are two register lists:




  1. pseudo-registers (used by X16's Kernal)


  2. imaginary registers (used by LLVM-MOS)




Be careful how much you overlap them!  Imaginary register "__rs0" is used as the permanent soft-stack pointer.



Whoops!  Sorry for mis-using the term "pseudo-registers" when I was talking about "imaginary registers"...  I haven't started X16 programming yet, so I was just thinking about imaginary registers LLVM-MOS uses for PET/VIC/C64/C128/Atari/etc.

mysterymath
Posts: 1
Joined: Fri Aug 12, 2022 4:22 pm

LLVM-MOS

Post by mysterymath »


Thanks to Mikael Lund, the LLVM-MOS SDK now has a native Commander X16 target (`cx-16`) including the hardware register definitions from cc65. 

There's also been quite a few developments in code generation since we last checked in:


  • Static stack regions for functions that can be proven never to be simultaneously active can now overlap, just like a software stack. 


  • A whole-program analysis assigns available zero page locations beyond the imaginary register bank to global variables and local values. The benefit of each assignment is computed based on estimated hit counts for each instruction, then assignments occur best-first for the whole program until available zero page is consumed. Like static stacks, same zero page locations can be reused by different functions. You can also reserve zero page from that allocated to the compiler for manual use in assembly.


  • A ton of miscellaneous optimizations; for example, increments and comparisons to zero at the end of loops are greatly improved.


Post Reply