First off, the flags and pointers are a complete pain to predict their behavior. They often do not seem logical. The reason behind this is that a) crossing clock domains is very difficult and b) they are very robust.
The read/write pointers are just free-running counters, so the only way of knowing where you're at is to compare to the other one, and that means crossing clock domains. That also means encoding the count values as gray codes, de-metastabilizing transfers into the other domain, and then comparing. Then you have to take into account that the FIFO handles some pretty off clock rates. Let's say you write to the FIFO with a 4ns clock and read with a 10ns clock. You could get two writes without the read clock having a single clock to update you of any changes, so anything in that domain(rdempty, rdusedwds) is going to be off by 2.
The common complaint(although I haven't seen it recently) is that a flag goes high before the FIFO is empty. For example, it might say it's empty, but you know you haven't read everything out, but then a clock or two later, even though nothing's happened, the empty flag goes low and you can read the rest out(this might occur at the full side and not the empty, I can't remember). The reason for this is that the FIFO has to guess that under worst case conditions with different clock rates, it could be empty.
(I've seen people design their own FIFOs, and it's easy to create something that works nicely under a few tests, but over time they always run into weird corner cases where data gets dropped, the FIFO rolls over, or something else like that.)
So I basically write logic that follows the rdempty and wrfull flags, i.e. it won't read or write when told not to. The usedwds are useful as general fullnes, i.e. am I 1/4th full or 3/4ths full, but do not rely on at the full/empty boundaries.
One other case I've seen is the "I know I fill the FIFO with 256 consecutive writes, and then read it out with 256 consecutive reads, so if the full/empty flag goes early, I have no way to back-pressure my system. The solution for that is to disable the protection circuitry in the Megawizard and just let it go, i.e. you may write when the FIFO thinks it's full, but if you know it's not, it works out. Of course if you're assumptions on the design's behavior is wrong, it could cause problems.