Shop Learn
Using p2llvm — Parallax Forums

Using p2llvm

David BetzDavid Betz Posts: 14,447

I thought I would remove my questions about using p2llvm from the thread addressing upstreaming the p2llvm source code.

I got a simple "Hello, world" program working and now I'm trying to compile my xlisp interpreter. It looks like my first problem is that setjmp/longjmp are not supported by p2llvm. Would it be relatively easy to add them?

dbetz@Davids-Mini-2 xlisp % make TARGET=p2llvm
/opt/p2llvm/bin/clang -fno-exceptions --target=p2 -Dprintf=__simple_printf -Wall -DUNIX -Iinclude -c src/xlapi.c -o obj/lib/xlapi.o
src/xlapi.c:39:16: warning: incompatible pointer types passing 'jmp_buf' (aka 'unsigned long [9]') to parameter of type 'void **' [-Wincompatible-pointer-types]
    if (setjmp(target.target) != 0) {
               ^~~~~~~~~~~~~
src/xlapi.c:39:9: error: __builtin_setjmp is not supported for the current target
    if (setjmp(target.target) != 0) {
        ^~~~~~~~~~~~~~~~~~~~~
/opt/p2llvm/bin/../libc/include/setjmp.h:16:16: note: expanded from macro 'setjmp'
#define setjmp __builtin_setjmp

Comments

  • As a followup to my previous message, have you defined the ABI for p2llvm somewhere? To write setjmp/longjmp it is necessary to understand what registers need to be saved by setjmp so longjmp can restore them to the correct state.

  • Regarding setjmp/longjmp, I'm not super familiar with what those do as I've never used them, but my understanding is it's a C library thing, not strictly a compiler level thing, right? The C library needs some love for sure, but I'm guessing it shouldn't be too hard to add. However if it's a builtin, then maybe it needs to go into libp2. In either case, shouldn't be hard if I understand the functionality correctly. Is that something you would want to take a stab at?

    Regarding an ABI, I don't have a formal document, but it's on the list. However, most of the necessary info should be in the various docs I've written here: https://github.com/ne75/p2llvm/tree/master/docs. Maybe today I'll start the actual ABI, cause that could unlock other people to make improvements to the C library/P2 library and fix things like this.

  • @n_ermosh said:
    Regarding setjmp/longjmp, I'm not super familiar with what those do as I've never used them, but my understanding is it's a C library thing, not strictly a compiler level thing, right? The C library needs some love for sure, but I'm guessing it shouldn't be too hard to add. However if it's a builtin, then maybe it needs to go into libp2. In either case, shouldn't be hard if I understand the functionality correctly. Is that something you would want to take a stab at?

    Regarding an ABI, I don't have a formal document, but it's on the list. However, most of the necessary info should be in the various docs I've written here: https://github.com/ne75/p2llvm/tree/master/docs. Maybe today I'll start the actual ABI, cause that could unlock other people to make improvements to the C library/P2 library and fix things like this.

    I'll take a look at your document. I don't really need a formal ABI document. I just need to know what registers have to be preserved.

  • @"David Betz" said:

    @n_ermosh said:
    Regarding setjmp/longjmp, I'm not super familiar with what those do as I've never used them, but my understanding is it's a C library thing, not strictly a compiler level thing, right? The C library needs some love for sure, but I'm guessing it shouldn't be too hard to add. However if it's a builtin, then maybe it needs to go into libp2. In either case, shouldn't be hard if I understand the functionality correctly. Is that something you would want to take a stab at?

    Regarding an ABI, I don't have a formal document, but it's on the list. However, most of the necessary info should be in the various docs I've written here: https://github.com/ne75/p2llvm/tree/master/docs. Maybe today I'll start the actual ABI, cause that could unlock other people to make improvements to the C library/P2 library and fix things like this.

    I'll take a look at your document. I don't really need a formal ABI document. I just need to know what registers have to be preserved.

    Cool. In theory, it should just be r0-r31 and ptra, if I understand how setjmp works correctly.

  • @n_ermosh Can you point me to some assembly code in the p2llvm project? I will try writing setjmp/longjmp but I'd like to see some assembly code that works with the p2llvm runtime library.

  • n_ermoshn_ermosh Posts: 145
    edited 2022-01-09 23:25

    Here's a basic one that is implementing left shift as a light example: https://github.com/ne75/p2llvm/blob/master/libp2/lib/builtins/ashldi3.c
    Here's an example of inline assembly, mixing C and asm: https://github.com/ne75/p2llvm/blob/master/libp2/lib/propeller2.c#L27-L37
    Here's my debugger program that's much larger: https://github.com/ne75/p2llvm/blob/master/libp2/lib/p2db/p2db.c

    Also for reference, this is where all instructions are defined: https://github.com/ne75/llvm-project/blob/edea2b509def0b02fd3f291ca0af6a9244158d52/llvm/lib/Target/P2/P2InstrInfo.td. It's not a clean list, but if you search for a specific mnemonic, if it's not there, then it's not yet implemented.

  • Thanks!!

  • David BetzDavid Betz Posts: 14,447
    edited 2022-01-11 03:29

    I'm trying to understand the code that is generated by p2llvm. I wrote this function:

    #define __JBLEN 32
    typedef unsigned long xjmp_buf[__JBLEN];
    
    int  setjmp(xjmp_buf env)
    {
        env[0] = 1;
        return 0;
    }
    

    It compiled to this:

        .text
        .file   "test.c"
        .globl  setjmp                          '' -- Begin function setjmp
        .type   setjmp,@function
    setjmp:                                 '' @setjmp
    '' %bb.0:
                 wrlong r0, #353
                 add ptra, #4   
                 wrlong r0, #319
                 rdlong r0, #319    
                 wrlong #1, r0
                 mov r0, #0 
                 mov r31, r0    
                 sub ptra, #4   
                 rdlong r0, #351    
                 reta   
    .Lfunc_end0:
        .size   setjmp, .Lfunc_end0-setjmp
                                            '' -- End function
    

    What are the locations #353, #319, and #351 used for? I thought at first they were just the absolute addresses of registers but r0 starts at $1d3=464 according to the docs. What are #353, #319, and #351 used for?

  • Those are the “special immediates” that’s cause rd/wrlong to operate on PTRA, I just don’t have them print out as a nice ptra expression. See pages 66-68 of the silicon docs.

    The generated code you posted does the following (and looks to be correct):

    • push r0 to the stack at the start of the call frame
    • Allocate 4 bytes on the stack for the incoming argument
    • Save the incoming argument (env) in r0 to the stack
    • Read env from the stack
    • Write 1 to env,
    • Move 0 into the return register (r31) and return.

    I’m guessing you didn’t enable optimization when compiling, so the code will be relatively inefficient.

  • @n_ermosh said:
    Those are the “special immediates” that’s cause rd/wrlong to operate on PTRA, I just don’t have them print out as a nice ptra expression. See pages 66-68 of the silicon docs.

    The generated code you posted does the following (and looks to be correct):

    • push r0 to the stack at the start of the call frame
    • Allocate 4 bytes on the stack for the incoming argument
    • Save the incoming argument (env) in r0 to the stack
    • Read env from the stack
    • Write 1 to env,
    • Move 0 into the return register (r31) and return.

    I’m guessing you didn’t enable optimization when compiling, so the code will be relatively inefficient.

    @n_ermosh said:
    Those are the “special immediates” that’s cause rd/wrlong to operate on PTRA, I just don’t have them print out as a nice ptra expression. See pages 66-68 of the silicon docs.

    The generated code you posted does the following (and looks to be correct):

    • push r0 to the stack at the start of the call frame
    • Allocate 4 bytes on the stack for the incoming argument
    • Save the incoming argument (env) in r0 to the stack
    • Read env from the stack
    • Write 1 to env,
    • Move 0 into the return register (r31) and return.

    I’m guessing you didn’t enable optimization when compiling, so the code will be relatively inefficient.

    @n_ermosh said:
    Those are the “special immediates” that’s cause rd/wrlong to operate on PTRA, I just don’t have them print out as a nice ptra expression. See pages 66-68 of the silicon docs.

    The generated code you posted does the following (and looks to be correct):

    • push r0 to the stack at the start of the call frame
    • Allocate 4 bytes on the stack for the incoming argument
    • Save the incoming argument (env) in r0 to the stack
    • Read env from the stack
    • Write 1 to env,
    • Move 0 into the return register (r31) and return.

    I’m guessing you didn’t enable optimization when compiling, so the code will be relatively inefficient.

  • Correct. I didn't use any optimization. Thanks for your description.

Sign In or Register to comment.