[llvm] [X86] Lower vector unsigned integer division through f64 division (PR #205263)

Adam Scott via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 30 02:16:00 PDT 2026


as4230 wrote:

> For u8/u16, it should be vdivps rather than vdivpd?



> https://llvm.org/docs/LangRef.html#i-sdiv
> 
> > The value produced is the signed integer quotient of the two operands rounded towards zero.
> > Note that signed integer division and unsigned integer division are distinct operations; for unsigned integer division, use ‘udiv’.
> > Division by zero is undefined behavior. For vectors, if any element of the divisor is zero, the operation has undefined >behavior. Overflow also leads to undefined behavior; this is a rare case, but can occur, for example, by doing a 32-bit >division of -2147483648 by -1.
> > If the exact keyword is present, the result value of the sdiv is a [poison value](https://llvm.org/docs/LangRef.html#poisonvalues) if the result would be rounded.
> 
> Sounds like unnecessary to limit this to unsigned?

Yes and yes. I think this covers the same cases as magic multiply, just for variable divisors instead of constants, so I threw in urem and srem too.

I ran a sort of grid search over cases like this:

```
define <16 x i8> @ud8(<16 x i8> %a, <16 x i8> %b) {
  %r = udiv <16 x i8> %a, %b
  ret <16 x i8> %r
}
```
and counted instructions before and after the fold (sd = signed divide, ur = unsigned remainder, and so on, and a * means the fold came out worse):

```
case   SSE2 s->f     AVX1 s->f     AVX2 s->f     AVX512 s->f
ud8     96->39        108->33       108->21       108->9
ur8     82->50         97->41        97->27        97->13
sd8     96->40        108->33       108->21       108->9
sr8     82->49         97->41        97->28        97->13
ud16    48->21         42->15        42->10        42->9
ur16    48->25         42->17        42->12        42->11
sd16    48->18         42->16        42->10        42->9
sr16    48->20         42->18        42->12        42->11
ud32    31->35 *       22->21        22->17        22->6
ur32    31->45 *       22->23 *       22->19        22->8
sd32    31->12         22->6          22->6         22->6
sr32    31->20         22->8          22->8         22->8
```

The only cases that lose are unsigned i32 on SSE2 and AVX1, where the f64 to u32 conversion has no real instruction and gets emulated. So I lowered the guard down to SSE2 and just bail unsigned i32 below AVX2. The i64 path handles signed and rem now too.

https://github.com/llvm/llvm-project/pull/205263


More information about the llvm-commits mailing list