https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82274
--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> --- internal-fn.c implements here whatever we have written in libgcc2.c for __mulvti3 (for 64-bit arches) or __mulvdi3 (for 32-bit arches). And it seems this is (hopefully the only) incorrectly handled special case. That routine first handles the case where both operands are within range of sign-extended half-sized integers (never overflows), then when one of them is and the other is arbitrary (or vice versa, mul is commutative) - this one needs 2 multiplications and sometimes overflows, sometimes doesn't, then when both of them are within the range of max signed half type + 1 to max unsigned half type, then when one of them is in that range and other is in range of minus (max unsigned half type + 1) to (min signed half type - 1) and finally when both are of the latter kind (everything else is always overflow). That last case is: if (uu.s.high == (Wtype) -1 && vv.s.high == (Wtype) - 1) { DWunion ww = {.ll = (UDWtype) (UWtype) uu.s.low * (UDWtype) (UWtype) vv.s.low}; ww.s.high -= uu.s.low; ww.s.high -= vv.s.low; if (__builtin_expect (ww.s.high >= 0, 1)) return ww.ll; } If both uu.s.low == vv.s.low == 0, then we return 0 even when there is overflow. Wonder if ww.s.high >= 0 && ww.ll wouldn't be sufficient.