Skip to content

[X86] Poor codegen when accessing a single bit of very large integers #164225

@RKSimon

Description

@RKSimon

https://godbolt.org/z/WG3fK6vaz

bool get512(_BitInt(512) x, unsigned i) { _BitInt(512) k = 1; return (x & (k << i)) != 0; }

results in a huge amount of expanded shift and bit logic, even though we know that we could access a single legal word directly (assumes little endian):

bool get512m(_BitInt(512) x, unsigned i) { i %= 512; // not really necessary, but basic bounds check const uint64_t *p = (const uint64_t *)&x; uint64_t r = p[i / 64]; return (r & (1 << (i/64))) != 0; }

Cases where we're altering single bits could be simplified similarly:

void clear512(_BitInt(512) &x, unsigned i) { _BitInt(512) k = 1; x &= ~(k << i); } void flip512(_BitInt(512) &x, unsigned i) { _BitInt(512) k = 1; x ^= (k << i); } void set512(_BitInt(512) &x, unsigned i) { _BitInt(512) k = 1; x |= (k << i); } void init512(_BitInt(512) &x, bool v, unsigned i) { _BitInt(512) k = 1; _BitInt(512) m = (unsigned)v & 1; x &= ~(k << i); x |= (m << i); }

vs

void clear512m(_BitInt(512) &x, unsigned i) { i %= 512; uint64_t *p = (uint64_t *)&x; uint64_t *r = p + (i / 64); *r &= ~(1 << (i % 64)); } void flip512m(_BitInt(512) &x, unsigned i) { i %= 512; uint64_t *p = (uint64_t *)&x; uint64_t *r = p + (i / 64); *r ^= ~(1 << (i % 64)); } void set512m(_BitInt(512) &x, unsigned i) { i %= 512; uint64_t *p = (uint64_t *)&x; uint64_t *r = p + (i / 64); *r |= (1 << (i % 64)); } void init512m(_BitInt(512) &x, bool v, unsigned i) { i %= 512; uint64_t *p = (uint64_t *)&x; uint64_t *r = p + (i / 64); *r &= ~(1 << (i % 64)); *r |= (((unsigned)v & 1) << (i % 64)); }

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions