1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2 ; RUN: llc < %s -mtriple=aarch64-unknown-unknown | FileCheck %s 3 4 ; Check that under certain conditions we can factor out a rotate 5 ; from the following idioms: 6 ; (a*c0) >> s1 | (a*c1) 7 ; (a/c0) << s1 | (a/c1) 8 ; This targets cases where instcombine has folded a shl/srl/mul/udiv 9 ; with one of the shifts from the rotate idiom 10 11 define i64 @ror_extract_shl(i64 %i) nounwind { 12 ; CHECK-LABEL: ror_extract_shl: 13 ; CHECK: // %bb.0: 14 ; CHECK-NEXT: lsl x8, x0, #3 15 ; CHECK-NEXT: ror x0, x8, #57 16 ; CHECK-NEXT: ret 17 %lhs_mul = shl i64 %i, 3 18 %rhs_mul = shl i64 %i, 10 19 %lhs_shift = lshr i64 %lhs_mul, 57 20 %out = or i64 %lhs_shift, %rhs_mul 21 ret i64 %out 22 } 23 24 define i32 @ror_extract_shrl(i32 %i) nounwind { 25 ; CHECK-LABEL: ror_extract_shrl: 26 ; CHECK: // %bb.0: 27 ; CHECK-NEXT: lsr w8, w0, #3 28 ; CHECK-NEXT: ror w0, w8, #4 29 ; CHECK-NEXT: ret 30 %lhs_div = lshr i32 %i, 7 31 %rhs_div = lshr i32 %i, 3 32 %rhs_shift = shl i32 %rhs_div, 28 33 %out = or i32 %lhs_div, %rhs_shift 34 ret i32 %out 35 } 36 37 define i32 @ror_extract_mul(i32 %i) nounwind { 38 ; CHECK-LABEL: ror_extract_mul: 39 ; CHECK: // %bb.0: 40 ; CHECK-NEXT: add w8, w0, w0, lsl #3 41 ; CHECK-NEXT: ror w0, w8, #25 42 ; CHECK-NEXT: ret 43 %lhs_mul = mul i32 %i, 9 44 %rhs_mul = mul i32 %i, 1152 45 %lhs_shift = lshr i32 %lhs_mul, 25 46 %out = or i32 %lhs_shift, %rhs_mul 47 ret i32 %out 48 } 49 50 define i64 @ror_extract_udiv(i64 %i) nounwind { 51 ; CHECK-LABEL: ror_extract_udiv: 52 ; CHECK: // %bb.0: 53 ; CHECK-NEXT: mov x8, #-6148914691236517206 54 ; CHECK-NEXT: movk x8, #43691 55 ; CHECK-NEXT: umulh x8, x0, x8 56 ; CHECK-NEXT: lsr x8, x8, #1 57 ; CHECK-NEXT: ror x0, x8, #4 58 ; CHECK-NEXT: ret 59 %lhs_div = udiv i64 %i, 3 60 %rhs_div = udiv i64 %i, 48 61 %lhs_shift = shl i64 %lhs_div, 60 62 %out = or i64 %lhs_shift, %rhs_div 63 ret i64 %out 64 } 65 66 define i64 @ror_extract_mul_with_mask(i64 %i) nounwind { 67 ; CHECK-LABEL: ror_extract_mul_with_mask: 68 ; CHECK: // %bb.0: 69 ; CHECK-NEXT: add x8, x0, x0, lsl #3 70 ; CHECK-NEXT: ror x8, x8, #57 71 ; CHECK-NEXT: and x0, x8, #0xff 72 ; CHECK-NEXT: ret 73 %lhs_mul = mul i64 %i, 1152 74 %rhs_mul = mul i64 %i, 9 75 %lhs_and = and i64 %lhs_mul, 160 76 %rhs_shift = lshr i64 %rhs_mul, 57 77 %out = or i64 %lhs_and, %rhs_shift 78 ret i64 %out 79 } 80 81 ; Result would undershift 82 define i64 @no_extract_shl(i64 %i) nounwind { 83 ; CHECK-LABEL: no_extract_shl: 84 ; CHECK: // %bb.0: 85 ; CHECK-NEXT: lsl x8, x0, #10 86 ; CHECK-NEXT: bfxil x8, x0, #52, #7 87 ; CHECK-NEXT: mov x0, x8 88 ; CHECK-NEXT: ret 89 %lhs_mul = shl i64 %i, 5 90 %rhs_mul = shl i64 %i, 10 91 %lhs_shift = lshr i64 %lhs_mul, 57 92 %out = or i64 %lhs_shift, %rhs_mul 93 ret i64 %out 94 } 95 96 ; Result would overshift 97 define i32 @no_extract_shrl(i32 %i) nounwind { 98 ; CHECK-LABEL: no_extract_shrl: 99 ; CHECK: // %bb.0: 100 ; CHECK-NEXT: lsr w8, w0, #3 101 ; CHECK-NEXT: lsr w0, w0, #9 102 ; CHECK-NEXT: bfi w0, w8, #28, #4 103 ; CHECK-NEXT: ret 104 %lhs_div = lshr i32 %i, 3 105 %rhs_div = lshr i32 %i, 9 106 %lhs_shift = shl i32 %lhs_div, 28 107 %out = or i32 %lhs_shift, %rhs_div 108 ret i32 %out 109 } 110 111 ; Can factor 128 from 2304, but result is 18 instead of 9 112 define i64 @no_extract_mul(i64 %i) nounwind { 113 ; CHECK-LABEL: no_extract_mul: 114 ; CHECK: // %bb.0: 115 ; CHECK-NEXT: add x8, x0, x0, lsl #3 116 ; CHECK-NEXT: lsr x0, x8, #57 117 ; CHECK-NEXT: bfi x0, x8, #8, #56 118 ; CHECK-NEXT: ret 119 %lhs_mul = mul i64 %i, 2304 120 %rhs_mul = mul i64 %i, 9 121 %rhs_shift = lshr i64 %rhs_mul, 57 122 %out = or i64 %lhs_mul, %rhs_shift 123 ret i64 %out 124 } 125 126 ; Can't evenly factor 16 from 49 127 define i32 @no_extract_udiv(i32 %i) nounwind { 128 ; CHECK-LABEL: no_extract_udiv: 129 ; CHECK: // %bb.0: 130 ; CHECK-NEXT: mov w8, #43691 131 ; CHECK-NEXT: mov w9, #33437 132 ; CHECK-NEXT: movk w8, #43690, lsl #16 133 ; CHECK-NEXT: movk w9, #21399, lsl #16 134 ; CHECK-NEXT: umull x8, w0, w8 135 ; CHECK-NEXT: umull x9, w0, w9 136 ; CHECK-NEXT: lsr x8, x8, #33 137 ; CHECK-NEXT: lsr x9, x9, #32 138 ; CHECK-NEXT: extr w0, w8, w9, #4 139 ; CHECK-NEXT: ret 140 %lhs_div = udiv i32 %i, 3 141 %rhs_div = udiv i32 %i, 49 142 %lhs_shift = shl i32 %lhs_div, 28 143 %out = or i32 %lhs_shift, %rhs_div 144 ret i32 %out 145 } 146