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).