This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

efficient packing

First, I am using 7.5 so it is an old compiler, but that is the way it is.

I have a number of bit variables that I am trying to pack into a byte. they are scattered all across the bit area

volatile bit var1;
volatile bit var2;
volatile bit var3;

char result;

The compiler won't let me do

          result=   (var1 <<1) | (var2 <<2) | (var3 <<4);

the only way I have been able to get this to work is

           result= var1;
           result= ((((result << 1) | var2)<<1) | var3)<<1);

This results in very inefficient code
           mov a,result
           mov  r7,a

           mov   c,v2
           clr  a
           rlc  A
           orl  A,R7;
           add  A,ACC
           mov  a,r7

           mov  c,var3
           rlc  A
           orl  A,R7
           add  A,ACC
           mov  a,r7
etc.
as compared to:

           mov A,result
           mov c,v2
           rlc a
           mov  c,v3
           rlc a

would be much better.  Does anyone know how this might be forced in C, without resorting to assembly?

I'm wondering if because the ACC and PSW are evenly divisible by 8, whether or not you can use
those and explicitly use the _crol_ intrinsic to accomplish this.  I have not had any luck so far.

In this case memory efficiency is more important than speed.


Parents
  • What happens if you rewrite:

    result=   (var1 <<1) | (var2 <<2) | (var3 <<4);
    


    into:

    result = ((char)var1 <<1) | ((char)var2 <<2) | ((char)var3 <<4);
    


    or:

    result = 0;
    if (var1) result |= 2;
    if (var2) result |= 4;
    if (var3) result |= 8;
    


    or:

    result = (var1 ? 2 : 0) | (var2 ? 4 : 0) | (var3 ? 8 : 0);
    

Reply
  • What happens if you rewrite:

    result=   (var1 <<1) | (var2 <<2) | (var3 <<4);
    


    into:

    result = ((char)var1 <<1) | ((char)var2 <<2) | ((char)var3 <<4);
    


    or:

    result = 0;
    if (var1) result |= 2;
    if (var2) result |= 4;
    if (var3) result |= 8;
    


    or:

    result = (var1 ? 2 : 0) | (var2 ? 4 : 0) | (var3 ? 8 : 0);
    

Children
  • Since the variables are actually bit flags in the

    bit mapped data area, I think converting them to chars will be messy, and large code space.

    However This resulted in a reduction of 17 bytes.

    result = 0;
    if (var1) result |= 2;
    if (var2) result |= 4;
    if (var3) result |= 8;

    result = (var1 ? 2 : 0) | (var2 ? 4 : 0) | (var3 ? 8 : 0);

    WELL.... different code, but because it used a jnb jump chain, it compiled to the exact same size of code as originally the case. There is an OR of 0 on each test.

    I have several of these and need to conserve code space.

    Basically, it is a state dump of the medical device up to a secondary controller, so since I am doing both ends, I can do it pretty much however I want, but I just have about 1K of free flash at this point, so the more memory I can save the better.

    The existing 8051 is a silabs F040 with 64K flash (except that they burn pages 0xFD00 - FFFF for manufacturing test and protection etc.

    Thanks once again for the excellent suggestions.

  • Type casting to char might be messy. But ((char)bitx << 4) doesn't mean the compiler actually have to convert bitx to a char. But it means the compiler must produce a result as if it had - the language standard isn't about expected processor instructions but about expected end results.

    A compiler that happens to have matching optimization rules could still perform single-bit operations on a char-sized temp variable that happens to also be bit-addressable. So something similar to the following - the assembler program has a byte-addressable variable in the bit-addressable region to allow bit operations to set individual bits:
    http://www.keil.com/support/docs/1877.htm