Compiler projects using llvm
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -debugify-and-strip-all-safe -enable-machine-outliner=never -verify-machineinstrs %s -o - -mtriple=aarch64-linux-gnu -aarch64-enable-atomic-cfg-tidy=0 | FileCheck %s
; RUN: llc -debugify-and-strip-all-safe -global-isel -enable-machine-outliner=never -verify-machineinstrs %s -o - -mtriple=aarch64-linux-gnu -aarch64-enable-atomic-cfg-tidy=0 | FileCheck %s

define i32 @add_z_i8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: add_z_i8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add w0, w1, w0, uxtb
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i32
  %r = add i32 %lhs, %vz
  ret i32 %r
}

define i32 @add_z_shli8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: add_z_shli8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add w0, w1, w0, uxtb #3
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i32
  %s = shl i32 %vz, 3
  %r = add i32 %lhs, %s
  ret i32 %r
}

define i64 @add_z_i8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_z_i8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    add x0, x1, w0, uxtb
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i64
  %r = add i64 %lhs, %vz
  ret i64 %r
}

define i64 @add_z_shli8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_z_shli8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    add x0, x1, w0, uxtb #3
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i64
  %s = shl i64 %vz, 3
  %r = add i64 %lhs, %s
  ret i64 %r
}

define i32 @add_s_i8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: add_s_i8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add w0, w1, w0, sxtb
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i32
  %r = add i32 %lhs, %vz
  ret i32 %r
}

define i32 @add_s_shli8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: add_s_shli8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add w0, w1, w0, sxtb #3
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i32
  %s = shl i32 %vz, 3
  %r = add i32 %lhs, %s
  ret i32 %r
}

define i64 @add_s_i8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_s_i8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    add x0, x1, w0, sxtb
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i64
  %r = add i64 %lhs, %vz
  ret i64 %r
}

define i64 @add_s_shli8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_s_shli8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    add x0, x1, w0, sxtb #3
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i64
  %s = shl i64 %vz, 3
  %r = add i64 %lhs, %s
  ret i64 %r
}

define i32 @add_z_i16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: add_z_i16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add w0, w1, w0, uxth
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i32
  %r = add i32 %lhs, %vz
  ret i32 %r
}

define i32 @add_z_shli16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: add_z_shli16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add w0, w1, w0, uxth #3
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i32
  %s = shl i32 %vz, 3
  %r = add i32 %lhs, %s
  ret i32 %r
}

define i64 @add_z_i16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_z_i16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    add x0, x1, w0, uxth
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i64
  %r = add i64 %lhs, %vz
  ret i64 %r
}

define i64 @add_z_shli16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_z_shli16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    add x0, x1, w0, uxth #3
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i64
  %s = shl i64 %vz, 3
  %r = add i64 %lhs, %s
  ret i64 %r
}

define i64 @add_z_i32i64(i32 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_z_i32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x0, x1, w0, uxtw
; CHECK-NEXT:    ret
  %vz = zext i32 %v to i64
  %r = add i64 %lhs, %vz
  ret i64 %r
}

define i64 @add_z_shli32i64(i32 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_z_shli32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x0, x1, w0, uxtw #3
; CHECK-NEXT:    ret
  %vz = zext i32 %v to i64
  %s = shl i64 %vz, 3
  %r = add i64 %lhs, %s
  ret i64 %r
}

define i32 @add_s_i16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: add_s_i16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add w0, w1, w0, sxth
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i32
  %r = add i32 %lhs, %vz
  ret i32 %r
}

define i32 @add_s_shli16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: add_s_shli16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add w0, w1, w0, sxth #3
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i32
  %s = shl i32 %vz, 3
  %r = add i32 %lhs, %s
  ret i32 %r
}

define i64 @add_s_i16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_s_i16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    add x0, x1, w0, sxth
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i64
  %r = add i64 %lhs, %vz
  ret i64 %r
}

define i64 @add_s_shli16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_s_shli16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    add x0, x1, w0, sxth #3
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i64
  %s = shl i64 %vz, 3
  %r = add i64 %lhs, %s
  ret i64 %r
}

define i64 @add_s_i32i64(i32 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_s_i32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x0, x1, w0, sxtw
; CHECK-NEXT:    ret
  %vz = sext i32 %v to i64
  %r = add i64 %lhs, %vz
  ret i64 %r
}

define i64 @add_s_shli32i64(i32 %v, i64 %lhs) minsize {
; CHECK-LABEL: add_s_shli32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x0, x1, w0, sxtw #3
; CHECK-NEXT:    ret
  %vz = sext i32 %v to i64
  %s = shl i64 %vz, 3
  %r = add i64 %lhs, %s
  ret i64 %r
}

define i32 @sub_z_i8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: sub_z_i8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub w0, w1, w0, uxtb
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i32
  %r = sub i32 %lhs, %vz
  ret i32 %r
}

define i32 @sub_z_shli8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: sub_z_shli8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub w0, w1, w0, uxtb #3
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i32
  %s = shl i32 %vz, 3
  %r = sub i32 %lhs, %s
  ret i32 %r
}

define i64 @sub_z_i8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_z_i8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    sub x0, x1, w0, uxtb
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i64
  %r = sub i64 %lhs, %vz
  ret i64 %r
}

define i64 @sub_z_shli8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_z_shli8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    sub x0, x1, w0, uxtb #3
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i64
  %s = shl i64 %vz, 3
  %r = sub i64 %lhs, %s
  ret i64 %r
}

define i32 @sub_s_i8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: sub_s_i8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub w0, w1, w0, sxtb
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i32
  %r = sub i32 %lhs, %vz
  ret i32 %r
}

define i32 @sub_s_shli8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: sub_s_shli8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub w0, w1, w0, sxtb #3
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i32
  %s = shl i32 %vz, 3
  %r = sub i32 %lhs, %s
  ret i32 %r
}

define i64 @sub_s_i8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_s_i8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    sub x0, x1, w0, sxtb
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i64
  %r = sub i64 %lhs, %vz
  ret i64 %r
}

define i64 @sub_s_shli8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_s_shli8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    sub x0, x1, w0, sxtb #3
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i64
  %s = shl i64 %vz, 3
  %r = sub i64 %lhs, %s
  ret i64 %r
}

define i32 @sub_z_i16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: sub_z_i16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub w0, w1, w0, uxth
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i32
  %r = sub i32 %lhs, %vz
  ret i32 %r
}

define i32 @sub_z_shli16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: sub_z_shli16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub w0, w1, w0, uxth #3
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i32
  %s = shl i32 %vz, 3
  %r = sub i32 %lhs, %s
  ret i32 %r
}

define i64 @sub_z_i16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_z_i16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    sub x0, x1, w0, uxth
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i64
  %r = sub i64 %lhs, %vz
  ret i64 %r
}

define i64 @sub_z_shli16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_z_shli16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    sub x0, x1, w0, uxth #3
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i64
  %s = shl i64 %vz, 3
  %r = sub i64 %lhs, %s
  ret i64 %r
}

define i64 @sub_z_i32i64(i32 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_z_i32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub x0, x1, w0, uxtw
; CHECK-NEXT:    ret
  %vz = zext i32 %v to i64
  %r = sub i64 %lhs, %vz
  ret i64 %r
}

define i64 @sub_z_shli32i64(i32 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_z_shli32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub x0, x1, w0, uxtw #3
; CHECK-NEXT:    ret
  %vz = zext i32 %v to i64
  %s = shl i64 %vz, 3
  %r = sub i64 %lhs, %s
  ret i64 %r
}

define i32 @sub_s_i16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: sub_s_i16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub w0, w1, w0, sxth
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i32
  %r = sub i32 %lhs, %vz
  ret i32 %r
}

define i32 @sub_s_shli16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: sub_s_shli16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub w0, w1, w0, sxth #3
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i32
  %s = shl i32 %vz, 3
  %r = sub i32 %lhs, %s
  ret i32 %r
}

define i64 @sub_s_i16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_s_i16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    sub x0, x1, w0, sxth
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i64
  %r = sub i64 %lhs, %vz
  ret i64 %r
}

define i64 @sub_s_shli16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_s_shli16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    sub x0, x1, w0, sxth #3
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i64
  %s = shl i64 %vz, 3
  %r = sub i64 %lhs, %s
  ret i64 %r
}

define i64 @sub_s_i32i64(i32 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_s_i32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub x0, x1, w0, sxtw
; CHECK-NEXT:    ret
  %vz = sext i32 %v to i64
  %r = sub i64 %lhs, %vz
  ret i64 %r
}

define i64 @sub_s_shli32i64(i32 %v, i64 %lhs) minsize {
; CHECK-LABEL: sub_s_shli32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub x0, x1, w0, sxtw #3
; CHECK-NEXT:    ret
  %vz = sext i32 %v to i64
  %s = shl i64 %vz, 3
  %r = sub i64 %lhs, %s
  ret i64 %r
}

define i32 @cmp_s_i8i32(i8 %v, i32 %lhs) minsize {
; CHECK-LABEL: cmp_s_i8i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    cmp w1, w0, uxtb
; CHECK-NEXT:    b.ge .LBB40_2
; CHECK-NEXT:  // %bb.1: // %then
; CHECK-NEXT:    mov w0, #1
; CHECK-NEXT:    ret
; CHECK-NEXT:  .LBB40_2: // %end
; CHECK-NEXT:    mov w0, w1
; CHECK-NEXT:    ret
  %vz = zext i8 %v to i32
  %c = icmp slt i32 %lhs, %vz
  br i1 %c, label %then, label %end
then:
  ret i32 1
end:
  ret i32 %lhs
}

define i64 @cmp_s_i8i64(i8 %v, i64 %lhs) minsize {
; CHECK-LABEL: cmp_s_i8i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    cmp x1, w0, sxtb
; CHECK-NEXT:    b.ge .LBB41_2
; CHECK-NEXT:  // %bb.1: // %then
; CHECK-NEXT:    mov w0, #1
; CHECK-NEXT:    ret
; CHECK-NEXT:  .LBB41_2: // %end
; CHECK-NEXT:    mov x0, x1
; CHECK-NEXT:    ret
  %vz = sext i8 %v to i64
  %c = icmp slt i64 %lhs, %vz
  br i1 %c, label %then, label %end
then:
  ret i64 1
end:
  ret i64 %lhs
}

define i32 @cmp_s_i16i32(i16 %v, i32 %lhs) minsize {
; CHECK-LABEL: cmp_s_i16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    cmp w1, w0, uxth
; CHECK-NEXT:    b.ge .LBB42_2
; CHECK-NEXT:  // %bb.1: // %then
; CHECK-NEXT:    mov w0, #1
; CHECK-NEXT:    ret
; CHECK-NEXT:  .LBB42_2: // %end
; CHECK-NEXT:    mov w0, w1
; CHECK-NEXT:    ret
  %vz = zext i16 %v to i32
  %c = icmp slt i32 %lhs, %vz
  br i1 %c, label %then, label %end
then:
  ret i32 1
end:
  ret i32 %lhs
}

define i64 @cmp_s_i16i64(i16 %v, i64 %lhs) minsize {
; CHECK-LABEL: cmp_s_i16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
; CHECK-NEXT:    cmp x1, w0, sxth
; CHECK-NEXT:    b.ge .LBB43_2
; CHECK-NEXT:  // %bb.1: // %then
; CHECK-NEXT:    mov w0, #1
; CHECK-NEXT:    ret
; CHECK-NEXT:  .LBB43_2: // %end
; CHECK-NEXT:    mov x0, x1
; CHECK-NEXT:    ret
  %vz = sext i16 %v to i64
  %c = icmp slt i64 %lhs, %vz
  br i1 %c, label %then, label %end
then:
  ret i64 1
end:
  ret i64 %lhs
}


; Check that implicit zext from w reg write is used instead of uxtw form of add.
define dso_local i64 @add_fold_uxtw(i32 %x, i64 %y) {
; CHECK-LABEL: add_fold_uxtw:
; CHECK:       // %bb.0: // %entry
; CHECK-NEXT:    and w8, w0, #0x3
; CHECK-NEXT:    add x0, x1, x8
; CHECK-NEXT:    ret
entry:
  %m = and i32 %x, 3
  %ext = zext i32 %m to i64
  %ret = add i64 %y, %ext
  ret i64 %ret
}

; Check that implicit zext from w reg write is used instead of uxtw
; form of sub and that mov WZR is folded to form a neg instruction.
define dso_local i64 @sub_fold_uxtw_xzr(i32 %x)  {
; CHECK-LABEL: sub_fold_uxtw_xzr:
; CHECK:       // %bb.0: // %entry
; CHECK-NEXT:    and w8, w0, #0x3
; CHECK-NEXT:    neg x0, x8
; CHECK-NEXT:    ret
entry:
  %m = and i32 %x, 3
  %ext = zext i32 %m to i64
  %ret = sub i64 0, %ext
  ret i64 %ret
}

; Check that implicit zext from w reg write is used instead of uxtw form of subs/cmp.
define dso_local i1 @cmp_fold_uxtw(i32 %x, i64 %y) {
; CHECK-LABEL: cmp_fold_uxtw:
; CHECK:       // %bb.0: // %entry
; CHECK-NEXT:    and w8, w0, #0x3
; CHECK-NEXT:    cmp x1, x8
; CHECK-NEXT:    cset w0, eq
; CHECK-NEXT:    ret
entry:
  %m = and i32 %x, 3
  %ext = zext i32 %m to i64
  %ret = icmp eq i64 %y, %ext
  ret i1 %ret
}

; Check that implicit zext from w reg write is used instead of uxtw
; form of add, leading to madd selection.
define dso_local i64 @madd_fold_uxtw(i32 %x, i64 %y) {
; CHECK-LABEL: madd_fold_uxtw:
; CHECK:       // %bb.0: // %entry
; CHECK-NEXT:    and w8, w0, #0x3
; CHECK-NEXT:    madd x0, x1, x1, x8
; CHECK-NEXT:    ret
entry:
  %m = and i32 %x, 3
  %ext = zext i32 %m to i64
  %mul = mul i64 %y, %y
  %ret = add i64 %mul, %ext
  ret i64 %ret
}

; Check that implicit zext from w reg write is used instead of uxtw
; form of sub, leading to sub/cmp folding.
; Check that implicit zext from w reg write is used instead of uxtw form of subs/cmp.
define dso_local i1 @cmp_sub_fold_uxtw(i32 %x, i64 %y, i64 %z) {
; CHECK-LABEL: cmp_sub_fold_uxtw:
; CHECK:       // %bb.0: // %entry
; CHECK-NEXT:    and w8, w0, #0x3
; CHECK-NEXT:    cmp x2, x8
; CHECK-NEXT:    cset w0, eq
; CHECK-NEXT:    ret
entry:
  %m = and i32 %x, 3
  %ext = zext i32 %m to i64
  %sub = sub i64 %z, %ext
  %ret = icmp eq i64 %sub, 0
  ret i1 %ret
}

; Check that implicit zext from w reg write is used instead of uxtw
; form of add and add of -1 gets selected as sub.
define dso_local i64 @add_imm_fold_uxtw(i32 %x) {
; CHECK-LABEL: add_imm_fold_uxtw:
; CHECK:       // %bb.0: // %entry
; CHECK-NEXT:    and w8, w0, #0x3
; CHECK-NEXT:    sub x0, x8, #1
; CHECK-NEXT:    ret
entry:
  %m = and i32 %x, 3
  %ext = zext i32 %m to i64
  %ret = add i64 %ext, -1
  ret i64 %ret
}

; Check that implicit zext from w reg write is used instead of uxtw
; form of add and add lsl form gets selected.
define dso_local i64 @add_lsl_fold_uxtw(i32 %x, i64 %y) {
; CHECK-LABEL: add_lsl_fold_uxtw:
; CHECK:       // %bb.0: // %entry
; CHECK-NEXT:    orr w8, w0, #0x3
; CHECK-NEXT:    add x0, x8, x1, lsl #3
; CHECK-NEXT:    ret
entry:
  %m = or i32 %x, 3
  %ext = zext i32 %m to i64
  %shift = shl i64 %y, 3
  %ret = add i64 %ext, %shift
  ret i64 %ret
}