Philip Reames and I are debating the semantics of x.with.overflow and I wanted to see if I could get a ruling here:
My read of the langref is that the overflow bit and the result of the operation are independent of each other. In other words, we can count on the result of add.with.overflow being the same as the result of a (non-nsw) add, even in the case where an overflow occurs. Is that right?
That matches my understanding. Otherwise I guess you'd be talking about a saturating operation.
Or do you mean that the result of an add may not even be defined? In that case would reading it be considered UB in the case where the overflow bit was set?
> Or do you mean that the result of an add may not even be defined? In that case would reading it be considered UB in the case where the overflow bit was set?
Yeah, this is the case I'm worried about: that for example sadd.with.overflow(INT_MAX, 1) might be designed to return { poison, true } instead of giving a useful result in the first element of the struct.
Or do you mean that the result of an add may not even be defined? In that case would reading it be considered UB in the case where the overflow bit was set?
Yeah, this is the case I'm worried about: that for example sadd.with.overflow(INT_MAX, 1) might be designed to return { poison, true } instead of giving a useful result in the first element of the struct.
Any argument against that? I guess that would be the most natural definition given the motivation to have these intrinsics (e.g., check if the 'nmemb * size' operation of calloc overflows; if so return null).
InstCombine will remove these instrinsics if the overflow bit is unused, for example. AFAICT, InstCombine never adds nsw/nuw to the replacements. I didn't check GVN. But I think they should unless there's some reason not to.
Or do you mean that the result of an add may not even be defined? In that
case would reading it be considered UB in the case where the overflow bit
was set?
Yeah, this is the case I'm worried about: that for example
sadd.with.overflow(INT_MAX, 1) might be designed to return { poison, true }
instead of giving a useful result in the first element of the struct.
"Otherwise, the builtin will return 1 and the result will be equal to the
unique value that is equivalent to the mathematically-correct result modulo
two raised to the k power, where k is the number of bits in the result
type. The behavior of these builtins is well-defined for all argument
values."
Now if we _know_ that the arithmetic result is used only if it does not overflow, then we can "pretend" that the arithmetic was nsw/nuw. This is what I tried to do in http://reviews.llvm.org/rL265912, but I had to back out the change due to an unrelated issue with SCEV.
Ok, thanks folks. Sounds like it's clear that x.with.overflow performs two's complement operations. Should I patch the LangRef to be more explicit about this?
Ok, thanks folks. Sounds like it's clear that x.with.overflow performs
two's complement operations. Should I patch the LangRef to be more
explicit about this?
Ok, thanks folks. Sounds like it's clear that x.with.overflow performs
two's complement operations. Should I patch the LangRef to be more
explicit about this?