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.
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.
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.
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.
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. So it would appear that this possible QX issue needs to be resolved in a different way somehow.
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
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:
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.
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.
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.
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