According to this article: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html this code should be valid. At least for GCC, but AFAIK, clang adopted a lot of GCC features.
Since for this flavour of IN instruction I always need A register, I'm specifying it directly with two % signs. Also, I'm using it explicitly in output list - I want its value to go into 'retval' variable. Unfortunately, clang-z80 complains about it (to avoid unnecessary optimizations, I'm building with -O0):
Assembly produced by llc seems reasonable, however, it seems like % and $ are still there!:
read: # @read
BB#0:
push ix
ld ix, -1
add ix, sp
ld sp, ix
ld (ix+0), 0
#APP
in %a, $31
#NO_APP
ld a, (ix+0)
ld ix, 1
add ix, sp
ld sp, ix
pop ix
ret
Seems like all % and $ should go away from my inlineassembly code.
As we can see, old value of register A is preserved before inline assembly block and restored immediately after that (at least, we can see that clobbering list did its job). Still it is useless for me, as I want value obtained by IN to be held in retval variable and then returned by the function...
Of course there is a nasty workaround for this, however, such dirty hacks spoil all benefits of using modern-era compiler infrastructure for immortal z80 devices:
I'm taking advantage of the fact that return value for functions returning 8-bit values is always held in register A. The code above is translated to following assembly:
read: # @read
BB#0:
#APP
in a, 31
ret
#NO_APP
ld a, 0
ret
Seeing unreachable code after first 'ret' makes it even more nasty...
Another question, what assembler are you using to build final binary? llc crashes on -filetype=obj:
I'm trying to compile following snippet of code:
unsigned char read() { unsigned char retval = 0;
asm volatile ("in %%a, $31" : "=a"(retval) : : ); return retval; }
According to this article: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html this code should be valid. At least for GCC, but AFAIK, clang adopted a lot of GCC features. Since for this flavour of IN instruction I always need A register, I'm specifying it directly with two % signs. Also, I'm using it explicitly in output list - I want its value to go into 'retval' variable. Unfortunately, clang-z80 complains about it (to avoid unnecessary optimizations, I'm building with -O0):
bash-3.2$ clang -O0 -S -emit-llvm -c test.c test.c:55:20: error: invalid output constraint '=a' in asm : "=a"(retval) ^ 1 error generated.
Note that while building clang-z80, I've configured it for targeting z80-unknown-none triplet by default.
I rearranged the code:
unsigned char read() { unsigned char retval = 0;
asm volatile ("in %%a, $31\n\t" "ld %0, %%a" : "=r"(retval) : : "%a"); return retval; }
Now clang compiles it fine, unfortunately, llc from llvm-z80 now complains:
bash-3.2$ llc -march=z80 -O0 test.ll error: couldn't allocate output register for constraint 'r'
I rewrote this code once again, now it is completely useless (value from IN is thrown away), however, now both clang and llc are happy:
unsigned char read() { unsigned char retval = 0;
asm volatile ("in %%a, $31" : : : "%a"); return retval; }
Assembly produced by llc seems reasonable, however, it seems like % and $ are still there!:
read: # @read
BB#0:
Seems like all % and $ should go away from my inlineassembly code. As we can see, old value of register A is preserved before inline assembly block and restored immediately after that (at least, we can see that clobbering list did its job). Still it is useless for me, as I want value obtained by IN to be held in retval variable and then returned by the function...
Of course there is a nasty workaround for this, however, such dirty hacks spoil all benefits of using modern-era compiler infrastructure for immortal z80 devices:
unsigned char read() { asm volatile("in a, 31\n\t" "ret" : : :); return 0; }
I'm taking advantage of the fact that return value for functions returning 8-bit values is always held in register A. The code above is translated to following assembly:
read: # @read
BB#0:
Seeing unreachable code after first 'ret' makes it even more nasty...
Another question, what assembler are you using to build final binary? llc crashes on -filetype=obj:
bash-3.2$ llc -march=z80 -O0 -filetype=obj test.ll 0 llc 0x0000000100e3f084 llvm::sys::PrintStackTrace(_sFILE) + 38 1 llc 0x0000000100e3f2b3 PrintStackTraceSignalHandler(void_) + 27 2 llc 0x0000000100e3f7bf SignalHandler(int) + 254 3 libSystem.B.dylib 0x00007fff83db21ba _sigtramp + 26 4 libSystem.B.dylib 0x0000000102819600 _sigtramp + 2124837984 5 llc 0x0000000100932ae7 llvm::LLVMTargetMachine::addPassesToEmitFile(llvm::PassManagerBase&, llvm::formatted_rawostream&, llvm::TargetMachine::CodeGenFileType, bool, void const, void const_) + 1457 6 llc 0x00000001000347e0 compileModule(char**, llvm::LLVMContext&) + 3454 7 llc 0x00000001000349e3 main + 199 8 llc 0x0000000100033574 start + 52 9 llc 0x0000000000000005 start + 4294757061 Stack dump:
Also, sdasz80 (V02.00) nor z80asm (ver. 1.8) want to compile such assembly code format...