Hacker News new | ask | show | jobs
by Dylan16807 4296 days ago
Maybe you shouldn't care about cycles, but using a loop for something that can be done without branches is a definite cognitive overhead.

If we want to avoid bit twiddling, how about this:

(mqhp->mq_maxsz + MQ_ALIGNSIZE - 1) / MQ_ALIGNSIZE * MQ_ALIGNSIZE;

I would expect a compiler to emit the same instructions as the original, but at worst you would have an add and two shifts rather than jumps or complex float operations.

1 comments

Provided everything is unsigned, this should result in something somewhat similar. I think this form also makes it clearer what's going on.

Assume MQ_ALIGNSIZE is a power of two. Then if N is the power, MQ_ALIGNSIZE is 1<<N. Then you can replace divisions by right shifts, and multiplications by left shifts, and turn the expression into (value+(1<<N)-1)>>N<<N.

Consider x>>N<<N. The (unsigned - i.e., guaranteed zero-filling) right shift discards the bottom N bits, and then the left shift puts the remaining bits back where they were. The net result is to mask off the bottom N bits of x.

Another way of putting that would be x&~((1<<N)-1) - hopefully that is clear. In our example, 1<<N is MQ_ALIGNSIZE. So we have x&~(MQ_ALIGNSIZE-1), or, overall, (x+MQ_ALIGNSIZE-1)&~(MQ_ALIGNSIZE-1).

I suppose it's possible a compiler could transform this, or the divide-and-multiply version, into the add-then-and version, given enough things that are compile-time constants. But personally if I knew the alignment would be a power of two - which it pretty much always is - I'd just write the code I want. Life is usually simpler that way.