[all-commits] [llvm/llvm-project] 729f3b: [ARM] Select ssat for saturating clamps with a non...

KavinSai-synthara via All-commits all-commits at lists.llvm.org
Wed Jun 24 07:39:04 PDT 2026


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 729f3bfbec19065c33593b95db251321dadb0e9c
      https://github.com/llvm/llvm-project/commit/729f3bfbec19065c33593b95db251321dadb0e9c
  Author: KavinSai-synthara <kavin.sai at synthara.ai>
  Date:   2026-06-24 (Wed, 24 Jun 2026)

  Changed paths:
    M llvm/lib/Target/ARM/ARMISelLowering.cpp
    A llvm/test/CodeGen/ARM/ssat-offset.ll

  Log Message:
  -----------
  [ARM] Select ssat for saturating clamps with a non-zero offset (#203854)

### Summary

On ARM/Thumb2, a saturating clamp to a signed range that is not centered
on zero is *not* matched to `ssat`, even though it can be potentially
matched to `ssat`. The backend instead emits a long explicit
compare/select clamp.

This pattern is extremely common in quantized ML code: an int8
requantize is `clamp(accumulator + output_zero_point, -128, 127)`, and
whenever the output zero_point != 0, the instruction count regress from
one ssat to ~10 instructions.

The root cause is that InstCombine canonically **sinks the constant out
of the min/max** — `clamp(X + C, -128, 127)` becomes `clamp(X, -128-C,
127-C) + C` — and the backend's SSAT matcher
(`PerformMinMaxToSatCombine`) only handles a clamp whose bounds already
form a saturation range. The offset of the form (`[-128-C, 127-C]`,
width 256 = 2⁸) falls through to a generic clamp.

#### Reproducer

```c
#include <stdint.h>
int8_t requant_offset(int32_t acc) {   // output zero-point = 96
    int32_t v = (acc >> 8) + 96;
    if (v < -128) v = -128;
    if (v >  127) v =  127;
    return (int8_t)v;
}
int8_t requant_zero(int32_t acc) {      // output zero-point = 0  (for contrast)
    int32_t v = (acc >> 8);
    if (v < -128) v = -128;
    if (v >  127) v =  127;
    return (int8_t)v;
}
```

```
clang -O2 --target=thumbv7em-none-eabihf -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -S issue.c
```

**Actual** 
`requant_offset` (zero-point 96):
```asm
asrs   r1, r0, #8
cmn.w  r1, #224
mvn    r1, #223
it     gt
asrgt  r1, r0, #8
cmp    r1, #31
it     ge
movge  r1, #31
add.w  r0, r1, #96
sxtb   r0, r0
```

`requant_zero` (zero-point 0):
```asm
ssat   r0, #8, r0, asr #8
```

#### Expected

`requant_offset` should select `ssat`, e.g.:
```asm
movs   r1, #96
add.w  r0, r1, r0, asr #8
ssat   r0, #8, r0
subs   r0, #96
```

#### Why this is sound

A clamp whose width (hi − lo + 1) is a power of two is just an `ssat`
shifted off zero by constant C.

```
clamp(X, lo, hi) == ssat_k(X − C) + C,   C = lo + 2^(k-1)
```

e.g. `clamp(X, −224, 31)` == `clamp(X+96, (-225+96), (31+96)) - 96` ==
`ssat8(X + 96) − 96`

Assisted-by: Claude



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list