A
Andrew Oakley
I'm trying to fix up some code that uses a signed integer to store
various formed of packed data. Signed integer values are sometimes
present in the top 29 bits. The current code does:
signed int data;
data = ... | value << 3; // store value in top bits
value = data >> 3; //get value out of top bits
This is somewhat broken as shifting of negative numbers is
implementation defined. It also gets very hard to read.
I've got some new code that looks more like this:
static unsigned int store_signed(signed int i, unsigned char len) {
return (i < 0) ? (1 << len) - ((unsigned int)-i) : i;
}
static signed int load_signed(unsigned int i, unsigned char len) {
return (i & ((1 << (len - 1)) - 1)) - (i & (1 << (len - 1)));
}
struct {
unsigned int something_else:3;
unsigned int value:29;
} data;
data.something_else = ...
data.value = store_signed(value, 29);
value = load_signed(data.value, 29);
Using bitfields I can get rid of the excessive bitwise manipulations
happening in the program, which should make it much clearer. The load
and store routines turn the signed values into unsigned values so that
they can be stored in the bitfields (behaviour with signed bitfield
values is also implementation defined).
The store_signed routine is fast - GCC removes the lot, and we end up
with the same code as before, but I can't get the load_signed one to
generate the nice compact code that I want - a single sar (shift
arithmetic right) to do the unpacking and sign extension.
Any ideas would be appreciated - the only real constraint is that I
have to keep the same binary format as before.
various formed of packed data. Signed integer values are sometimes
present in the top 29 bits. The current code does:
signed int data;
data = ... | value << 3; // store value in top bits
value = data >> 3; //get value out of top bits
This is somewhat broken as shifting of negative numbers is
implementation defined. It also gets very hard to read.
I've got some new code that looks more like this:
static unsigned int store_signed(signed int i, unsigned char len) {
return (i < 0) ? (1 << len) - ((unsigned int)-i) : i;
}
static signed int load_signed(unsigned int i, unsigned char len) {
return (i & ((1 << (len - 1)) - 1)) - (i & (1 << (len - 1)));
}
struct {
unsigned int something_else:3;
unsigned int value:29;
} data;
data.something_else = ...
data.value = store_signed(value, 29);
value = load_signed(data.value, 29);
Using bitfields I can get rid of the excessive bitwise manipulations
happening in the program, which should make it much clearer. The load
and store routines turn the signed values into unsigned values so that
they can be stored in the bitfields (behaviour with signed bitfield
values is also implementation defined).
The store_signed routine is fast - GCC removes the lot, and we end up
with the same code as before, but I can't get the load_signed one to
generate the nice compact code that I want - a single sar (shift
arithmetic right) to do the unpacking and sign extension.
Any ideas would be appreciated - the only real constraint is that I
have to keep the same binary format as before.