1

I've been trying to use SDCC to compile extremely lightweight C programs to run on a TI83 calculator (yes, you can do that). Being an old calculator, it doesn't have much RAM to store the program, and the processor is extremely slow. I wrote code similar to *((char*)(x/8)) |= 0x80>>(x&7) as a simple routine to turn on a single bit where x is a signed char. The problem is, SDCC implements the C standard of upcasting everything into 16 bit ints, which adds one layer of complexity, then it misses out on the fact that x/8 can be achieved by bitshifts and implements an entire inline division algorithm.

My question is: Can I redefine the arithmetic operators to avoid upcasting where possible? And perhaps secondly, can I define the division operation once, then call it several times to avoid massive file sizes?

EDIT: I realized a lot of the problems caused by my code reside in the type of the variables in question, as only unsigned division can have this kind of optimization. The questions of redefining operators and moving the operations to a seperate, single location still stand.

pi_squared
  • 91
  • 6
  • 2
    Can you compile with optimization? If not, can you make it explicit? Because without C++ you cannot redefine operators. Alternatively, you can call a macro that handles special cases like this. – S.S. Anne Feb 08 '20 at 20:24
  • You can write macros and/or inline functions in C; it does *not* have operator overloading. Unless you mean improving the compiler to emit better code for easy divisions. – Peter Cordes Feb 08 '20 at 20:31
  • 1
    From what I have tested, the only 16 bit thing in there is the `(char*)` for memory access. Both `x` and the `0x80` are done using 8 bit shifts. Note it may work better with a lookup table because it uses a loop. – Jester Feb 08 '20 at 21:19
  • The problem is C compilers use implicit conversion from any smaller datatype (say, 8 bits) to ints (16 bits) when an arithmetic operator is present. – pi_squared Feb 08 '20 at 21:27
  • 2
    My version of sdcc doesn't. – Jester Feb 08 '20 at 21:37
  • 4
    I have checked. The compiler may optimize things if the result is the same as defined by the standard. `x/8` is done by `rrca; rrca; rrca; and a, #0x1f`. Clearly 8 bit. `0x80 >> (x&7)` was done by `srl e` in a loop. Also 8 bit. sdcc Version 3.5.0 #9253 (Mar 19 2016) (Linux). – Jester Feb 08 '20 at 22:11
  • Seems like an X-Y problem. You have a problem, and have thought of a way of solving it, but do not know how to implement that solution or even if it is feasible. Better to simply ask about your original problem than to ask about your problematic and probably flawed solution. SDCC supports inline assembler, or you could simply use a `>> 3` - it is not clear why you wouldn't. Also SDCC is open source - if you think you can improve it, go ahead. – Clifford Feb 08 '20 at 23:03
  • 2
    Btw @pi_squared, there is an LLVM backend for Z80, and if you use it with clang you could certainly write your own optimization passes to precisely control stuff like this (but I doubt it would have this problem in general based on the 'generic' nature of this mis-optimization!) https://olduino.wordpress.com/2014/12/30/llvm-for-the-z80-another-source-of-inspiration/ – BadZen Feb 08 '20 at 23:04
  • Perhaps post a complete example, along with the assembly it produces, and what you would like to see? – BadZen Feb 08 '20 at 23:07
  • 1
    If you have a "version" of SDCC that does not behave as others expect, it is surely worth mentioning what version you are using. Also what compiler options you are using, and an actual code example that shows the problem not code that is merely "similar". – Clifford Feb 08 '20 at 23:19
  • The real problems hampering this routine are types of x and the literal 8. If x is represented as being signed, the routine will try and account for the possibility of it being, say, -64/8. Also, by default, a literal 8 is a signed 16 bit int. The correct code would be something like `*((char*)(((unsigned char)x)/(unsigned char)8)) |= ((unsigned char)0x80)>>(x&7)` Earlier in my program I had typedef'd byte as signed char, and ubyte as unsigned char. – pi_squared Feb 08 '20 at 23:55
  • @BadZen AFAIK from reading the mailing lists of SDCC, LLVM has no *backend for Z80*. LLVM has a backend for emitting C, which can be translated by SDCC for the target system. So LLVM can be used as an optimizing *frontend* with SDCC as the backend. – the busybee Feb 09 '20 at 10:01
  • Unrelated to the OP, but for the sake of clarification, a member of the TI calculator programming community has actually written a Z80 (and eZ80) backend and is currently in active use by that community. See this: https://github.com/jacobly0/llvm-project – Zeda Feb 12 '20 at 12:30

0 Answers0