| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | 
 | ; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s | 
 |  | 
 | declare i16 @llvm.ushl.sat.i16(i16, i16) | 
 | declare <2 x i16> @llvm.ushl.sat.v2i16(<2 x i16>, <2 x i16>) | 
 |  | 
 | ; fold (shlsat undef, x) -> 0 | 
 | define i16 @combine_shl_undef(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shl_undef: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    mov w0, wzr | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 undef, i16 %y) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; fold (shlsat x, undef) -> undef | 
 | define i16 @combine_shl_by_undef(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shl_by_undef: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 %x, i16 undef) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; fold (shlsat poison, x) -> 0 | 
 | define i16 @combine_shl_poison(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shl_poison: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    mov w0, wzr | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 poison, i16 %y) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; fold (shlsat x, poison) -> undef | 
 | define i16 @combine_shl_by_poison(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shl_by_poison: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 %x, i16 poison) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; fold (shlsat x, bitwidth) -> undef | 
 | define i16 @combine_shl_by_bitwidth(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shl_by_bitwidth: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 %x, i16 16) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; fold (ushlsat 0, x) -> 0 | 
 | define i16 @combine_shl_zero(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shl_zero: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    mov w0, wzr | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 0, i16 %y) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; fold (ushlsat x, 0) -> x | 
 | define i16 @combine_shlsat_by_zero(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shlsat_by_zero: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 %x, i16 0) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; fold (ushlsat c1, c2) -> c3 | 
 | define i16 @combine_shlsat_constfold(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shlsat_constfold: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    mov w0, #32 | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 8, i16 2) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; fold (ushlsat c1, c2) -> sat max | 
 | define i16 @combine_shlsat_satmax(i16 %x, i16 %y) nounwind { | 
 | ; CHECK-LABEL: combine_shlsat_satmax: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    mov w0, #65535 | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 8, i16 15) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 |  | 
 | declare void @sink2xi16(i16, i16) | 
 |  | 
 | ; fold (ushlsat c1, c2) -> c3 , c1/c2/c3 being vectors | 
 | define void @combine_shlsat_vector() nounwind { | 
 | ; CHECK-LABEL: combine_shlsat_vector: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill | 
 | ; CHECK-NEXT:    mov w0, #32 | 
 | ; CHECK-NEXT:    mov w1, #65535 | 
 | ; CHECK-NEXT:    bl sink2xi16 | 
 | ; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload | 
 | ; CHECK-NEXT:    ret | 
 |   %tmp = call <2 x i16> @llvm.ushl.sat.v2i16(<2 x i16><i16 8, i16 8>, | 
 |                                              <2 x i16><i16 2, i16 15>) | 
 |   ; Pass elements as arguments in a call to get CHECK statements that verify | 
 |   ; the constant folding. | 
 |   %e0 = extractelement <2 x i16> %tmp, i16 0 | 
 |   %e1 = extractelement <2 x i16> %tmp, i16 1 | 
 |   call void @sink2xi16(i16 %e0, i16 %e1) | 
 |   ret void | 
 | } | 
 |  | 
 | ; Fold shlsat -> shl, if known not to saturate. | 
 | define i16 @combine_shlsat_to_shl(i16 %x) nounwind { | 
 | ; CHECK-LABEL: combine_shlsat_to_shl: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    and w0, w0, #0xfffffffc | 
 | ; CHECK-NEXT:    ret | 
 |   %x2 = lshr i16 %x, 2 | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 %x2, i16 2) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; Do not fold shlsat -> shl. | 
 | define i16 @combine_shlsat_to_shl_no_fold(i16 %x) nounwind { | 
 | ; CHECK-LABEL: combine_shlsat_to_shl_no_fold: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    and w8, w0, #0xfffc | 
 | ; CHECK-NEXT:    lsl w9, w8, #17 | 
 | ; CHECK-NEXT:    lsl w8, w8, #14 | 
 | ; CHECK-NEXT:    cmp w8, w9, lsr #3 | 
 | ; CHECK-NEXT:    csinv w8, w9, wzr, eq | 
 | ; CHECK-NEXT:    lsr w0, w8, #16 | 
 | ; CHECK-NEXT:    ret | 
 |   %x2 = lshr i16 %x, 2 | 
 |   %tmp = call i16 @llvm.ushl.sat.i16(i16 %x2, i16 3) | 
 |   ret i16 %tmp | 
 | } | 
 |  | 
 | ; Fold shlsat -> shl, if known not to saturate. | 
 | define <2 x i16> @combine_shlsat_to_shl_vec(<2 x i8> %a) nounwind { | 
 | ; CHECK-LABEL: combine_shlsat_to_shl_vec: | 
 | ; CHECK:       // %bb.0: | 
 | ; CHECK-NEXT:    shl v0.2s, v0.2s, #8 | 
 | ; CHECK-NEXT:    ret | 
 |   %ext = zext <2 x i8> %a to <2 x i16> | 
 |   %tmp = call <2 x i16> @llvm.ushl.sat.v2i16( | 
 |                           <2 x i16> %ext, | 
 |                           <2 x i16> <i16 8, i16 8>) | 
 |   ret <2 x i16> %tmp | 
 | } |