[gnu.gcc.bug] Bitfield inefficiencies

ccplumb@rose.waterloo.edu (Colin Plumb) (10/21/89)

(Low-priority item... I'm much more annoyed at that "tried and true"
tool, dbx.  GDB isn't installed properly locally, so I gotta use this
abomination of a debugger the hangs when asked to print a void *.
Still, it seems worth mentioning)

"I am only an egg" but this annoys me...

When compiling some code that includes the structure:

typedef struct _node {
	unsigned value:30;
	Colour lcolour:1, rcolour:1;
	Pointer left, right;
} Node;

On a VAX running 4.3BSD plus local hacks and GCC 1.36 (presumably the detailed
environment is unnecessary), gcc -O -S spits out lots of extzv instructions
when accessing the fields.  I was hoping it would use masks.  Writing
the masks code myself on some heavily-used code (enclosed below... it's
traversing a 2-3-4-tree implemented as a red-black tree) results in a >20%
speedup.  Ideally, checking one bit should test for negative if it's
the high bit and use blb, tst or bb on others.  The value field should
be accessed as bicl3 $0xc0000000, (r0), r1, not extzv $0, $30, (r0), r1.

Also, initialising all 3 bitfields on 3 consecutive lines results in
an insv and two bisb2's instead of one 32-bit assignment.

All this is both with and without -O.  -fforce-mem, -fstrength-reduce and
-fcombine-args do not change this behaviour.

I keep crowing that GCC lets one stop trying to optimise the assembler
output via source code, so it's annoying to be proved wrong...
-- 
	-Colin

--- sample code ---
typedef enum _colour { BLACK, RED } Colour;

typedef union _pointer { void *v; struct _node *n; } Pointer;

typedef struct _node {
	unsigned value:30;
	Colour lcolour:1, rcolour:1;
	Pointer left, right;
} Node;

typedef struct _tree { int size; int level; Pointer p; } Tree;

void **index(Tree *t, register unsigned int i)
{
	register int level = t->level;
	register Pointer *cur = &t->p;

	if (i >= t->size)
		return (void **)0;
	while (level--) {
		if (i < cur->n->value) {
			if(!cur->n->lcolour) {
				cur = &cur->n->left;
				continue;
			}
			cur = &cur->n->left;
		} else {
			i -= cur->n->value;
			if(!cur->n->rcolour) {
				cur = &cur->n->right;
				continue;
			}
			cur = &cur->n->right;
		}
		if (i < cur->n->value) {
			cur = &cur->n->left;
		} else {
			i -= cur->n->value;
			cur = &cur->n->right;
		}
	}
	return &cur->v;
}