<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/149685>149685</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[AArch64] Fold `cmp a, b; sub a, c; ccmp a, c` into `subs a, c; ccmp a, b`
</td>
</tr>
<tr>
<th>Labels</th>
<td>
backend:AArch64,
missed-optimization
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
Kmeakin
</td>
</tr>
</table>
<pre>
Consider this rust function for indexing into a slice:
https://godbolt.org/z/fsfdxPs8e
```rust
#[inline(never)]
pub fn get(slice: &[u8], range: std::ops::Range<usize>) -> Option<&[u8]> {
slice.get(range)
}
```
on AArch64, this produces
```asm
;; parameters:
;; x0: slice.ptr
;; x1: slice.len
;; x2: range.start
;; x3: range.end
;;
;; return:
;; x0: ret.ptr
;; x1: ret.len
example::get::h40fd170020d218c4:
cmp x3, x1 ;; range.end <=> slice.len
add x8, x0, x2 ;; new_ptr = slice.ptr + range.start
sub x1, x3, x2 ;; ret.len = range.end - range.start
ccmp x3, x2, #0, ls ;; range.end <=> range.start
csel x0, xzr, x8, lo ;; ret.ptr = (range.start > range.end || range.end > slice.len) ? null : new_ptr
ret
```
Notice that the comparison between `range.end` and `range.start` is performed twice:
* In `sub x1, x3, x2`, we calculate `range.end - range.start` (without setting flags)
* In `ccmp x3, x2, #0, ls`, we calculate `range.end - range.start` again, this time only to modify the flags
We could avoid the redundant calculation by performing the subtraction and setting the flags in the same instruction (`subs`) and using `ccmp` for comparing `range.end` with `slice.len`:
```asm
;; x0: slice.ptr
;; x1: slice.len
;; x2: range.start
;; x3: range.end
;;
;; return:
;; x0: ret.ptr
;; x1: ret.len
add x8, x0, x2 ;; new_ptr = slice.ptr + range.start
subs x9, x3, x2 ;; new_len = range.end - range.start and set flags
ccmp x3, x1, #0, lo ;; range.end <=> range.start
csel x0, xzr, x8, ls ;; ret.ptr = (range.start > range.end || range.end > slice.len) ? null : new_ptr
mov x1, x9 ;; ret.len = new_len
ret
```
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzUVk-P66YX_TRkgybCEDv2Iov8eZF--klt1U2XFQaS0IfBAjyTmU9fXbATZ5rXp1btolYUD1w4955zyRl4CPpsldqgcofKw4IP8eL85v-d4l-1XbROvm_2zgYtlcfxogP2Q4j4NFgRtbP45DzWVqqrtmesbXSY42C0UIhtEYHPJcY-wIgeET2enWydiUvnz4gePxA9nsJJXn8KtYLlFckfSAJjylC509ZoqxCtrXpVHtEGlQdEtv3Q4pPFZxURraecGNEKlbuhhjV0jz235zQfooQi2Nblatj25xzaD0F_KMS-INrgF8S-4B97oIbYfo7FvmC03iGyzfSWOW2Gpw3Uuj7MGWTyzuLt1otLtYJikn69d3IQKswX89DBkO0Q2-Gee96pqHwYNczTV5JopOR99LNAcQ8YZWcBCoFU4jJE7uMsxO4hZeUtcF_hVRy8fVKBV_FZfpjO2dWVd71RWWSQKf1xWZGTLNaEUCJpUYtVhsbjI7o-va8MhLoWeCpjKhFDP1jqw5zqtJ9LmffXaT9J33QMjlhWvf3aR48RO9x1xIjuPmk0YYahzZhFQmPPMEfaCfNe68s3EMVIc8KCb0RZqtaEGeoT1t9ADMokxMz4w6dXEsG4hyon5tOpzVD4Dp3SrfdovX_IP9ebNhixI7aDMRiaPioK9XgV_3j8f3BRC4XjhUccLwoL1_Xc6-AsblV8UyBcRe7HsCKYQ9JpLrOtCIbfjfIn5zslcXy7-wvd4v8lkOfNgkroPgXeFBbciMHwqB6yfupWRUCiNx0vbog4qBjB2k6Gn8P4Q7_l_PN2jrn_Ql5-5trejCLqTmFnzTuODndO6tN7EjGXkvT9BSQdjMT81WmZol7JwUpu4y0r2HT7PukHZGBdGNroeTZx0HwiesuAtc0LeaewtiH6Ia9GtM56Z4ZN2j4E2DxqAlzgH8PY7hx46DLIm7p2O1oVGTv61BP_M-b3HT_6-04UElrzxIke_O07XjS1-naIvuFMxcNRdg-O9494U_jkof-yO41P517nJtHg-fPE0UdFn_jbQm6YbFjDF2pTrEvaVNWa1ovLplTlei3qgpekqkrBmrpZl8XqJIuyFvWqXugNJbQk66KhrKCkXvKGkpKoSvC6pVIwtCKq49osjXnt4KK00CEMalOsmqouF4a3yoR0X6O05eIrHGG2vV0zwIUQpZ0OQckX10fd6Y_kAhArDwu_AeCXdjgHtCJGhxjuqaKOJl0GJ7zygI_OJE-GI8JBuBZ0AsNNIwEjcQuK5NdwExxd4umqFjQcvNl8uh7qeBnapXAdokcoany99N79pkRE9JjECIgeRz1eN_T3AAAA__8aER84">