Shop OBEX P1 Docs P2 Docs Learn Events
LLVM Backend for Propeller 2 - Page 13 — Parallax Forums

LLVM Backend for Propeller 2

1789101113»

Comments

  • Is long long (64) bit supported?

    I have this code that generates two different answers and don't know if this is correct:

    int main(int argc, char** argv)
    {
        long long t;
        int d1;
        unsigned int c5;
        int x;
    
        printf("Starting\n");
    
        x = rand() % 10;
        printf("Rand: %d\n", x);
    
        d1 = 8052495 + x;
        c5 = 31559;
    
        t = d1 - (c5 << 8);
        x = d1 - (c5 << 8);
    
        printf("t: %lld, x: %d\n", t, x);
    
        printf("Done\n");
    
        while (1)
        {
            wait(500);
        }
    }
    

    The long value is 4294941851 were the int value is -25445 which is the answer I was looking for.

    Mike

  • 64 bit ints and doubles should work, but I haven't tested them thoroughly, so if you find bugs, let me know, but I've been using them and having found any issues yet. Many floating point operations aren't supported yet (the code is there, I just need to actually enable compiling it into the library. I've been doing it piece by piece to avoid adding a ton of code at once and then hunting down bugs later).

  • @iseries I just merged in a rewrite of stdio and your SD card code. I haven't tested the sd stuff, and the changes to stdio shouldn't be breaking anything, EXCEPT I removed simple_printf. After the rewrite of printf, it didn't really makes sense to keep simple_printf since it was only slightly smaller and faster, not enough to keep both implementations. Let me know if you run into any issues.

  • Yes, the SD card functions has a bug in it and I didn't know how to send an updated version to an alread submitted pull request.

    Apparently all I had to do was update it.

    Anyway I need to send you an update to the SD card functions. Also hopefully the memory functions that I updated and you merged in work for you.

    Mike

  • Submitted update SD driver code.

    Speed test program that was used:

    #include <stdio.h>
    #include <sys/time.h>
    #include <stdlib.h>
    #include <propeller.h>
    #include <sys/sdcard.h>
    
    uint32_t randfill(uint32_t *, size_t);
    int  compare(uint32_t *, uint32_t *, size_t);
    
    #define PIN_SS   23
    #define PIN_MISO 20
    #define PIN_CLK  21
    #define PIN_MOSI 22
    
    uint32_t  data1[25000];
    uint32_t  data2[25000];
    struct tm tv;
    
    
    int main(int argc, char** argv)
    {
        FILE  *fh;
        uint32_t  ticks;
        time_t t;
        struct timeval x;
    
        tv.tm_year = 2022 - 1900;
        tv.tm_mon = 3;
        tv.tm_mday = 7;
        tv.tm_hour = 6;
        tv.tm_min = 0;
        tv.tm_sec = 0;
        t = mktime(&tv);
        x.tv_sec = t;
        x.tv_usec = 0;
    
        settimeofday(&x, 0);
    
        printf( " clkfreq = %d   clkmode = 0x%x\n", _clkfreq, _clkmode);
        printf( " Randfill ticks = %d\n", randfill( data1, sizeof(data1) ) );
    
        printf( " Mounting: " );
        sd_mount(0, PIN_SS, PIN_CLK, PIN_MOSI, PIN_MISO);
    
        if( (fh = fopen( "SD0:/speed2.bin", "w" )) > 0 )
        {
            ticks = getms();
            fwrite( data1, 1, sizeof(data1), fh );
            fclose( fh );
            ticks = getms() - ticks;
            printf( " Writing %u bytes at %u kB/s\n", sizeof(data1), (sizeof(data1) * 1000 / ticks + 512) >> 10 );
        } else  printf( " SD card write error!\n" );
    
        if( (fh = fopen( "SD0:/speed2.bin", "r" )) > 0 )
        {
            ticks = getms();
            fread( data2, 1, sizeof(data2), fh );
            fclose( fh );
            ticks = getms() - ticks;
            printf( " Reading %u bytes at %u kB/s\n", sizeof(data2), (sizeof(data2) * 1000 / ticks + 512) >> 10 );
            if( compare( data1, data2, sizeof(data2) ) )  printf( " Matches!  :)\n" );
            else    printf( " Mis-matches!  :(\n" );
        } else  printf( " SD card read error!\n" );
    
        while (1)
        {
            waitms(500);
        }
    }
    
    uint32_t  randfill( uint32_t *addr, size_t size )
    {
        uint32_t  ticks;
    
        size >>= 2;
        ticks = _cnt();
        do {
            *(addr++) = rand();
        } while( --size );
    
        return( _cnt() - ticks );
    }
    
    
    int  compare( uint32_t *addr1, uint32_t *addr2, size_t size )
    {
        uint32_t  pass = 1;
    
        size >>= 2;
        do {
            if( *(addr1++) != *(addr2++) )  pass = 0;
        } while( --size );
    
        return( pass );
    }
    

    Mike

  • roglohrogloh Posts: 6,293
    edited 2026-03-17 03:39

    Hi @n_ermosh finally got around to downloading LLVM on my M2 Pro based Mac to have a brief look. Not sure if you are still actively working on it or not. I downloaded the latest from your github source at ne75/p2llvm.

    Hit a few problems along the way so I thought I'd mention them in case you wanted to figure it out. It seems to be related to the use of the modulus % operator in C which is being converted to QUREM psuedo instruction presumably for later access via the Cordic.

    I've found a handful of failing files crashing LLVM Clang with an assert condition and so far the common denominator is always the use of the % operator.

    Assertion failed: ((I.atEnd() || std::next(I) == def_instr_end()) && "getVRegDef assumes a single definition or no definition"), function getVRegDef, file MachineRegisterInfo.cpp, line 404.

    This simple code below is enough to trigger it if you build with LLVM Clang using the P2 as the target. I was using the build of LLVM included in your latest tree as a submodule which I also built locally on my Mac M2 for acting as the P2 cross compiler.

    #include <stdint.h>
    uint32_t rand_seed = 2223;
    
    uint32_t rand(uint32_t min, uint32_t max)
    {
        return (rand_seed % max)+min;
    }
    

    In my digging into this problem I tried to decipher a few things using -emit-llvm on the clang command line and then passing the output file to "llc --print-after-isel" which shows this:

    # After Instruction Selection:
    # Machine code for function rand: IsSSA, TracksLiveness
    Frame Objects:
      fi#-1: size=4, align=1, fixed, at location [SP]
    Function Live Ins: $r0 in %0, $r1 in %1
    
    bb.0.entry:
      liveins: $r0, $r1
      %1:p2gpr = COPY $r1
      %0:p2gpr = COPY $r0
      %2:p2gpr = MOVri @rand_seed, 15, 0
      %3:p2gpr = RDLONGrr killed %2:p2gpr, 15, 0 :: (dereferenceable load (s32) from @rand_seed, !tbaa !3)
      %4:p2gpr = QUREM killed %3:p2gpr, %1:p2gpr
      %5:p2gpr = ADDrr %4:p2gpr(tied-def 0), %0:p2gpr, 15, 0
      $r31 = COPY %5:p2gpr
      RETA 15, 0, implicit $r31
    
    # End machine code for function rand.
    
    Assertion failed: ((I.atEnd() || std::next(I) == def_instr_end()) && "getVRegDef assumes a single definition or no definition"), function getVRegDef, file MachineRegisterInfo.cpp, line 404.
    PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
    Stack dump:
    0.      Program arguments: /Users/roger/Applications/p2llvm/bin/llc --print-after-isel math.bc
    1.      Running pass 'Function Pass Manager' on module 'math.bc'.
    2.      Running pass 'Live Variable Analysis' on function '@rand'
    Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
    0  llc                      0x0000000101ed7ffc llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 80
    1  llc                      0x0000000101ed85a0 PrintStackTraceSignalHandler(void*) + 28
    2  llc                      0x0000000101ed6578 llvm::sys::RunSignalHandlers() + 140
    3  llc                      0x0000000101ed9a94 SignalHandler(int) + 276
    4  libsystem_platform.dylib 0x000000018797ea24 _sigtramp + 56
    5  libsystem_pthread.dylib  0x000000018794fc28 pthread_kill + 288
    6  libsystem_c.dylib        0x000000018785dae8 abort + 180
    7  libsystem_c.dylib        0x000000018785ce44 err + 0
    8  llc                      0x0000000100b733b4 llvm::MachineRegisterInfo::getVRegDef(llvm::Register) const + 200
    9  llc                      0x000000010098a888 llvm::LiveVariables::HandleVirtRegUse(llvm::Register, llvm::MachineBasicBlock*, llvm::MachineInstr&) + 64
    10 llc                      0x000000010098d54c llvm::LiveVariables::runOnInstr(llvm::MachineInstr&, llvm::SmallVectorImpl<unsigned int>&) + 856
    11 llc                      0x000000010098d9bc llvm::LiveVariables::runOnBlock(llvm::MachineBasicBlock*, unsigned int) + 488
    12 llc                      0x000000010098e0b4 llvm::LiveVariables::runOnMachineFunction(llvm::MachineFunction&) + 428
    13 llc                      0x0000000100a7f7ac llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 456
    14 llc                      0x00000001011eecec llvm::FPPassManager::runOnFunction(llvm::Function&) + 536
    15 llc                      0x00000001011f609c llvm::FPPassManager::runOnModule(llvm::Module&) + 116
    16 llc                      0x00000001011ef5ac (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) + 672
    17 llc                      0x00000001011ef134 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 288
    18 llc                      0x00000001011f64ac llvm::legacy::PassManager::run(llvm::Module&) + 36
    19 llc                      0x00000001000bf494 compileModule(char**, llvm::LLVMContext&) + 4696
    20 llc                      0x00000001000bda50 main + 1156
    21 dyld                     0x00000001875f7fd8 start + 2412
    
    

    So I'm guessing there is some problem with the QUREM "instruction" not doing the QDIV and taking the result from the GETQY or something like that before returning.

    This same problem seems to also prevent me from completing the build of your P2 C library as the file(s) it fails on include the % operator in the C code. It fails on some time functions - I identified strftime.c and localtim.c failing so far, could be more although it got to 96% so it was close! EDIT: no it's just those two files with the % operator, and when I commented out the lines with the modulus, it let the build complete and install the (now broken) libc.a file to the LLVM installation folder.

     python3 build.py --skip_llvm --skip_libp2 --install /Users/roger/Applications/p2llvm
    [  1%] Building C object time/CMakeFiles/time.dir/strftime.c.obj
    [ 15%] Built target misc
    [ 33%] Built target string
    [ 38%] Built target math
    [ 60%] Built target wchar
    [ 90%] Built target stdlib
    [ 91%] Built target stdio
    [ 91%] Building C object time/CMakeFiles/time.dir/localtim.c.obj
    [ 96%] Built target drivers
    Assertion failed: ((I.atEnd() || std::next(I) == def_instr_end()) && "getVRegDef assumes a single definition or no definition"), function getVRegDef, file MachineRegisterInfo.cpp, line 404.
    PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace, preprocessed source, and associated run script.
    Stack dump:
    0.  Program arguments: /Users/roger/Applications/p2llvm/bin/clang -I/Users/roger/Documents/Code/p2llvm/libc/include -Wall -Werror -ffunction-sections -fdata-sections -Oz -fno-exceptions --target=p2 -MD -MT time/CMakeFiles/time.dir/strftime.c.obj -MF CMakeFiles/time.dir/strftime.c.obj.d -o CMakeFiles/time.dir/strftime.c.obj -c /Users/roger/Documents/Code/p2llvm/libc/time/strftime.c
    1.  <eof> parser at end of file
    2.  Code generation
    3.  Running pass 'Function Pass Manager' on module '/Users/roger/Documents/Code/p2llvm/libc/time/strftime.c'.
    4.  Running pass 'Live Variable Analysis' on function '@strftime'
    

    I also had a minor issue of the install scripts not fully working outright due to not finding some propeller.h and propeller2.h include files and stuff about missing stdio.h for files that included that. I just copied those files over to the include folder manually and commented out these unnecessary(?) #include <stdio.h> lines and was able to get it to complete the build of the libp2 but unfortunately it doesn't work out of the box from a clean slate so to speak.

  • roglohrogloh Posts: 6,293
    edited 2026-03-17 04:05

    With respect to the prior post, I am wondering if this assert is something related to this P2 specific code below in P2ExpandPseudos.cpp that expands the Pseudo instructions where you mentioned in the comment a need to call GETQX first to flush it because I noticed that step was not happening for QUDIV which presumably works okay - although I should really try to go double check that too:

    void P2ExpandPseudos::expand_QUREM(MachineFunction &MF, MachineBasicBlock::iterator SII) {
        MachineInstr &SI = *SII;
    
        LLVM_DEBUG(errs()<<"== lower pseudo unsigned remainder\n");
        LLVM_DEBUG(SI.dump());
    
        BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(P2::QDIVrr))
                .addReg(SI.getOperand(1).getReg())
                .addReg(SI.getOperand(2).getReg())
                .addImm(P2::ALWAYS);
    
        // first call getqx so that we flush it out of the cordic. This is in case another cordic operation
        // after this calls get qx before it's done. 
        BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(P2::GETQX), SI.getOperand(0).getReg())
                .addReg(P2::QX)
                .addImm(P2::ALWAYS)
                .addImm(P2::NOEFF);
        BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(P2::GETQY), SI.getOperand(0).getReg())
                .addReg(P2::QY)
                .addImm(P2::ALWAYS)
                .addImm(P2::NOEFF);
    
        SI.eraseFromParent();
    }
    

    Here's what you do for QUDIV which is one instruction less.

    void P2ExpandPseudos::expand_QUDIV(MachineFunction &MF, MachineBasicBlock::iterator SII) {
        MachineInstr &SI = *SII;
    
        LLVM_DEBUG(errs()<<"== lower pseudo unsigned division\n");
        LLVM_DEBUG(SI.dump());
    
        BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(P2::QDIVrr))
                .addReg(SI.getOperand(1).getReg())
                .addReg(SI.getOperand(2).getReg())
                .addImm(P2::ALWAYS);
        BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(P2::GETQX), SI.getOperand(0).getReg())
                .addReg(P2::QX)
                .addImm(P2::ALWAYS)
                .addImm(P2::NOEFF);
    
        SI.eraseFromParent();
    }
    

    UPDATE: So when I removed the extra GETQX from QUREM and rebuilt LLVM it didn't crash anymore with that assert if I use the % operator in C code. :smile: So it would appear that this possible QX issue needs to be resolved in a different way somehow.

    +#if 0
         BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(P2::GETQX), SI.getOperand(0).getReg())
                 .addReg(P2::QX)
                 .addImm(P2::ALWAYS)
                 .addImm(P2::NOEFF);
    +#endif
    
Sign In or Register to comment.