This is an archive of the discontinued LLVM Phabricator instance.

[APInt] Add setLowBits/setHighBits methods to APInt.
ClosedPublic

Authored by craig.topper on Mar 1 2017, 11:10 PM.

Details

Summary

There are quite a few places in the code base that do something like the following to set the high or low bits in an APInt.

KnownZero |= APInt::getHighBitsSet(BitWidth, BitWidth - 1);

For BitWidths larger than 64 this creates a short lived APInt with malloced storage. I think it might even call malloc twice. Its better to just provide methods that can set the necessary bits without the temporary APInt.

I'll update usages that benefit in a separate patch.

Diff Detail

Repository
rL LLVM

Event Timeline

craig.topper created this revision.

Fixed a copy/paste mistake

Add a clearUpperBits call to the fast part of setHighBits along with a test case.

davide edited edge metadata.Mar 1 2017, 11:47 PM

Reducing malloc() traffic is generally a good thing, so is this patch. It's particularly slow on some systems (Windows), and FWIW, not great also on Linux with the default allocator (I ended up replacing my malloc() with tcmalloc everywhere, but that's a story for another day). That said, I'm curious if you're actually able to measure any compile time reduction with this change on the cases you plan to switch.

davide added inline comments.Mar 1 2017, 11:50 PM
include/llvm/ADT/APInt.h
1253 ↗(On Diff #90287)

Please end comments with a full stop (here and everywhere else). I know we're a bit inconsistent in this file, but we should get this right for newly introduced code.

Add periods at the end of comments.

I haven't tried to measure any compile time differences. I was just inspired by Simon's patch for setBits and observing that ORing getLowBits/getHighBits was a common idiom in some places like ValueTracking. I assume we aren't often dealing larger than 64-bit numbers there on most types of compiled code.

RKSimon edited edge metadata.Mar 2 2017, 1:05 PM

Wouldn't the getHighBitsSet/getLowBitsSet statics benefit from using this?

@RKSimon , yes I think getLowBitsSet/getHighBitsSet would also benefit. I think they are mallocing twice due to the getAllOnes and then shifting. So I think we should be able to just create an all 0s APInt then call setLowBits/setHighBits instead and save one of the mallocs.

hans edited edge metadata.Mar 2 2017, 1:37 PM

The code looks fine to me, but I wonder if this buys much compared to APInt::setBits, which can easily be used to set only low or high bits. (The single-word case of that should probably be provided in an inline method actually?)

I'm definitely going to look at moving some of setBits inline. I'm also planning to fix getBitsSet to use setBits. I might even fix setBits to support loBit > hiBit like getBitsSet supports.

I think it at least makes sense to have setLowBits/setHighBits as convenience methods. Particularly for setHighBits the caller shouldn't have to write setBits(BitWidth, BitWidth - hiBitsToSet).

hans added a comment.Mar 2 2017, 4:31 PM

I think it at least makes sense to have setLowBits/setHighBits as convenience methods. Particularly for setHighBits the caller shouldn't have to write setBits(BitWidth, BitWidth - hiBitsToSet).

Yes, agreed.

Make some portions of setBits inline. Use it to implement setLowBits and setHighBits.

I might even fix setBits to support loBit > hiBit like getBitsSet supports.

I'm not sure about this, which is why I didn't implement that way originally. Uses of getBitsSet are quite rare (and often could be replaced with simpler alternatives) - I'm still not sure if there are any uses of the 'wraparound' ability (or whether they are intentional....).

hans added inline comments.Mar 3 2017, 9:25 AM
lib/Support/APInt.cpp
575 ↗(On Diff #90428)

This comment isn't really true anymore since you're only creating loMask (and when it gets left-shifted later, the name loMask isn't really appropriate anymore).

It might make sense to keep these two cases separate and let the compiler handle the redundant instructions.

I see the logic is changing a little, with hiWord now referring to whichWord(hiBit) instead of whichWord(hiBit - 1). Did you find a bug, or is this just trying to make the code clearer?

craig.topper added inline comments.Mar 3 2017, 11:14 AM
lib/Support/APInt.cpp
575 ↗(On Diff #90428)

No bug. Was just trying to see if I could do it with less -1. I'll change it back to replicating the redundant instructions again.

Cleanup the comments in setBitsSlowCase. Modify the implementation to just AND the low and high masks together when loWord and hiWord are the same.

hans accepted this revision.Mar 6 2017, 9:58 AM

lgtm

include/llvm/ADT/APInt.h
226 ↗(On Diff #90562)

Nit: the other methods use /// to get doxygen comments.

unittests/ADT/APIntTest.cpp
1664 ↗(On Diff #90562)

Nit: looks like an extra newline here.

This revision is now accepted and ready to land.Mar 6 2017, 9:58 AM
This revision was automatically updated to reflect the committed changes.