This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch,avr]: Better support for single bit operations


Hi all.

Evaluating avr-gcc 4.x I observed some deficiencies of its coce quality for single bit operations.

A specific case is this one:

#define REG (*(((unsigned char volatile *) 0x20)))

unsigned char extract_sfrbit_1()
{
    unsigned char i = 0;

    if (REG & 64) i = 1;

    return i;
}

avr-gcc 4.4.0 (same for 4.3.2) compiles this with -O[123s] to

extract_sfrbit_1:
/* prologue: function */
/* frame size = 0 */
	in r24,32-0x20	 ;  6	*movqi/4	[length = 1]
	ldi r25,lo8(0)	 ;  26	*movqi/2	[length = 1]
	ldi r18,6	 ;  31	*lshrhi3_const/5	[length = 5]
1:	lsr r25
	ror r24
	dec r18
	brne 1b
	andi r24,lo8(1)	 ;  14	andqi3/2	[length = 1]
/* epilogue start */
	ret	 ;  29	return	[length = 1]

I added a patch that fixes some problems of that kind. 

Consider the patch as a proposal. I did not investigate in expanding "extzv" in order
to keep changes minimal.

The patch 
-- defines new, anonymous insns that enable insn combine (pass .combine) to optimize this
-- introduces a new insn attribute "adjust_len" in {"no","yes"} 
-- introduces some mode iterators for int modes
-- introduces %. to ease outputting of a bit in print_operand()
-- introduce some constraints and an operator predicate
-- most insns use BST and/or BLD to manipulate the bit
-- with the exception of mode iterators, the patch works the same way even for GCC 3.x

There is also a C file bitmov.c attached that can be used to show the effects of the patch.
Compiled with -Os -fno-split-wide-types the size if the object file is (without/with patch):

   text	   data	    bss	    dec	    hex	filename
    814	      0	     16	    830	    33e	bitmov-nopatch.o
    586	      0	     16	    602	    25a	bitmov-patch.o

The C snippet above is translated to

extract_sfrbit_1:
/* prologue: function */
/* frame size = 0 */
	in r24,32-0x20	 ;  6	*movqi/4	[length = 1]
	bst r24,6	 ;  14	*extract_bitQIqi	[length = 3]
	clr r24
	bld r24,0
/* epilogue start */
	ret	 ;  27	return	[length = 1]

This is not optimal but better than a shift loop.

regards

Georg-Johann

Attachment: bitmov-patch.s
Description: Binary data

Attachment: bitmov-nopatch.s
Description: Binary data

#define REG (*(((unsigned char volatile *) 0x20)))

typedef union
{
    struct
    {
        unsigned b0:1;
        unsigned b1:1;
        unsigned b2:1;
        unsigned b3:1;
        unsigned b4:1;
        unsigned b5:1;
        unsigned b6:1;
        unsigned b7:1;
    };
   
    unsigned char c;
} u_t;

u_t s, t;

unsigned char i;
unsigned short g, h;
char z,y;

/**************************************/


void test_andsi3 (long long a, long b)
{
    static long l1, l2;

    l1 = b & ~(1l << 0);
    l2 = a & ~(1l << 12);
}

void test_iori3 (long long a, long b)
{
    static long l1, l2;

    l1 = b | (1l << 0);
    l2 = a | (1l << 12);
}

unsigned char extract_sfrbit_1()
{
    unsigned char i = 0;

    if (REG & 64) i = 1;

    return i;
}

void insert_1_bitashift (unsigned char b)
{
    s.b6 = t.b6;
}

unsigned char shiftrt_and1 (unsigned char c)
{
    i = (c >> 4) & 1;
    return c;
}

unsigned char shiftrt_1_bit (unsigned char c)
{
    i = (c >> 4) & 2;
    return c;
}

unsigned char ashift_1_bit (unsigned char c)
{
    i = (c << 5) & 64;
    return c;
}


void extract_sfrbit_2()
{
    unsigned char j = 0;

    if (REG & 64) j = 1;

    i = j;
}

int extract_gprbit (int i)
{
    return (i & (1 << 14)) ? 1 : 0;
}

void bar()
{
    if (REG & 64)
        i = 0;

    s.b6 = i;

    if (i & 2)
        REG |= 64;
}

void movebit_ashift()
{
    s.b6 = s.b5;
    s.b7 = s.b3;
}

void movebit_shiftrt()
{
    s.b3 = s.b7;
    s.b5 = s.b6;
}

void movebit_07()
{
    s.b0 = s.b7;
}

void movebit_71()
{
    s.b7 = s.b1;
}

void movebit_70()
{
    s.b7 = s.b0;
}

unsigned char revert (unsigned char n)
{
    u_t u = {.c = n};
    u_t v;

    v.b0 = u.b7;
    v.b1 = u.b6;
    v.b2 = u.b5;
    v.b3 = u.b4;
    v.b4 = u.b3;
    v.b5 = u.b2;
    v.b6 = u.b1;
    v.b7 = u.b0;

    return v.c;
}

void test_sfrbit ()
{
    if ((REG >> 6) & 1)
        y = 1;
}

void test_gprbit (unsigned char reg)
{
    if (1 & (reg >> 6))
        y = 1;
}

void get_longbit (long x)
{
    i = (x >> 25) & 1;

    s.b3 = (x & (1ul << 14)) ? 1 : 0;
    s.b0 = (x & (1ul << 24)) ? 1 : 0;
}

unsigned char copy (unsigned char n)
{
    u_t u = {.c = n};
    u_t v = {.c = i};

    v.b0 = u.b0;
    v.b4 = u.b4;
    v.b7 = u.b7;

    return v.c;
}

unsigned char is_ne0 (unsigned char n)
{
    u_t u = {.c = n};

    return u.b0 | u.b1 | u.b2 | u.b3 | u.b4 | u.b5 | u.b6 | u.b7;
}

Attachment: bit1-trunk-142584.patch
Description: Binary data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]