; 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
}