Reported by Static Analyzer Tool, Coverity:
Bad bit shift operation The operation may have an undefined behavior or yield an unexpected result. In <unnamed>::SVEEmitter::encodeFlag(unsigned long long, llvm::StringRef): A bit shift operation has a shift amount which is too large or has a negative value.
// Returns the SVETypeFlags for a given value and mask. uint64_t encodeFlag(uint64_t V, StringRef MaskName) const { auto It = FlagTypes.find(MaskName); //Condition It != llvm::StringMap<unsigned long long, llvm::MallocAllocator>::const_iterator const(this->FlagTypes.end()), taking true branch. if (It != FlagTypes.end()) { uint64_t Mask = It->getValue(); //return_constant: Function call llvm::countr_zero(Mask) may return 64. //assignment: Assigning: Shift = llvm::countr_zero(Mask). The value of Shift is now 64. unsigned Shift = llvm::countr_zero(Mask); //Bad bit shift operation (BAD_SHIFT) //large_shift: In expression V << Shift, left shifting by more than 63 bits has undefined behavior. The shift amount, Shift, is 64. return (V << Shift) & Mask; } llvm_unreachable("Unsupported flag"); }
The only invalid value for Shift is 64 since a zero Mask is the only case where llvm::countr_zero will end up being 64.
This patch adds an assert that Mask != 0, since that would be an invalid mask.
Shouldn't this be: assert(Shift < 64 &&"...")?
expr.shift (https://eel.is/c++draft/expr.shift) says:
uint64 stays as an unsigned long, so it is still 64 bits, so the only invalid value for Shift is 64 (though >64 is 'nonsense', but only impossible because of llvm::countr_zero).
One thing to consider: I wonder if we should instead be changing the 'shift' to be:
(V << (Shift % 64)) && Mask ? It looks like arm_sve.td has the NoFlags value as zero, which I think will end up going through here possibly (or at least, inserted into FlagTypes.
So I suspect an assert might not be sufficient, since a 64 bit shift is possible in that case (since a zero 'Mask' is the only case where countr_zero will end up being 64).