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