1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 2; RUN: opt -passes=instsimplify -S < %s | FileCheck %s 3 4;; The and X, (add Y, -1) pattern is from an earlier instcombine pass which 5;; converted 6 7;; define i64 @f1() #0 { 8;; entry: 9;; %0 = call i64 @llvm.aarch64.sve.cntb(i32 31) 10;; %1 = call i64 @llvm.aarch64.sve.cnth(i32 31) 11;; %rem = urem i64 %0, %1 12;; ret i64 %rem 13;; } 14 15;; into 16 17;; define i64 @f1() #0 { 18;; entry: 19;; %0 = call i64 @llvm.vscale.i64() 20;; %1 = shl nuw nsw i64 %0, 4 21;; %2 = call i64 @llvm.vscale.i64() 22;; %3 = shl nuw nsw i64 %2, 3 23;; %4 = add nsw i64 %3, -1 24;; %rem = and i64 %1, %4 25;; ret i64 %rem 26;; } 27 28;; InstCombine would have folded the original to returning 0 if the vscale 29;; calls were the same Value*, but since there's two of them it doesn't 30;; work and we convert the urem to add/and. CSE then gets rid of the extra 31;; vscale, leaving us with a new pattern to match. This only works because 32;; vscale is known to be a power of 2 (assuming there's a defined range for it). 33 34define i64 @f1() #0 { 35; CHECK-LABEL: define i64 @f1 36; CHECK-SAME: () #[[ATTR0:[0-9]+]] { 37; CHECK-NEXT: entry: 38; CHECK-NEXT: ret i64 0 39; 40entry: 41 %0 = call i64 @llvm.vscale.i64() 42 %1 = shl i64 %0, 4 43 %2 = shl i64 %0, 3 44 %3 = add i64 %2, -1 45 %rem = and i64 %1, %3 46 ret i64 %rem 47} 48 49;; Make sure it works if the value could also be zero. 50define i64 @test_pow2_or_zero(i64 %arg) { 51; CHECK-LABEL: define i64 @test_pow2_or_zero 52; CHECK-SAME: (i64 [[ARG:%.*]]) { 53; CHECK-NEXT: ret i64 0 54; 55 %neg = sub i64 0, %arg 56 %x = and i64 %neg, %arg 57 %shl1 = shl i64 %x, 4 58 %shl2 = shl i64 %x, 3 59 %mask = add i64 %shl2, -1 60 %rem = and i64 %mask, %shl1 61 ret i64 %rem 62} 63 64;; Make sure it doesn't work if the value isn't known to be a power of 2. 65;; In this case a vscale without a `vscale_range` attribute on the function. 66define i64 @no_pow2() { 67; CHECK-LABEL: define i64 @no_pow2() { 68; CHECK-NEXT: entry: 69; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() 70; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], 4 71; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP0]], 3 72; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], -1 73; CHECK-NEXT: [[REM:%.*]] = and i64 [[TMP1]], [[TMP3]] 74; CHECK-NEXT: ret i64 [[REM]] 75; 76entry: 77 %0 = call i64 @llvm.vscale.i64() 78 %1 = shl i64 %0, 4 79 %2 = shl i64 %0, 3 80 %3 = add i64 %2, -1 81 %rem = and i64 %1, %3 82 ret i64 %rem 83} 84 85;; Make sure it doesn't work if the shift on the -1 side is greater 86define i64 @minus_shift_greater(i64 %arg) { 87; CHECK-LABEL: define i64 @minus_shift_greater 88; CHECK-SAME: (i64 [[ARG:%.*]]) { 89; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[ARG]] 90; CHECK-NEXT: [[X:%.*]] = and i64 [[NEG]], [[ARG]] 91; CHECK-NEXT: [[SHL1:%.*]] = shl i64 [[X]], 3 92; CHECK-NEXT: [[SHL2:%.*]] = shl i64 [[X]], 4 93; CHECK-NEXT: [[MASK:%.*]] = add i64 [[SHL2]], -1 94; CHECK-NEXT: [[REM:%.*]] = and i64 [[SHL1]], [[MASK]] 95; CHECK-NEXT: ret i64 [[REM]] 96; 97 %neg = sub i64 0, %arg 98 %x = and i64 %neg, %arg 99 %shl1 = shl i64 %x, 3 100 %shl2 = shl i64 %x, 4 101 %mask = add i64 %shl2, -1 102 %rem = and i64 %shl1, %mask 103 ret i64 %rem 104} 105 106;; Make sure it doesn't work if the subtract isn't one. 107define i64 @sub2(i64 %arg) { 108; CHECK-LABEL: define i64 @sub2 109; CHECK-SAME: (i64 [[ARG:%.*]]) { 110; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[ARG]] 111; CHECK-NEXT: [[X:%.*]] = and i64 [[NEG]], [[ARG]] 112; CHECK-NEXT: [[SHL1:%.*]] = shl i64 [[X]], 4 113; CHECK-NEXT: [[SHL2:%.*]] = shl i64 [[X]], 3 114; CHECK-NEXT: [[MASK:%.*]] = add i64 [[SHL2]], -2 115; CHECK-NEXT: [[REM:%.*]] = and i64 [[SHL1]], [[MASK]] 116; CHECK-NEXT: ret i64 [[REM]] 117; 118 %neg = sub i64 0, %arg 119 %x = and i64 %neg, %arg 120 %shl1 = shl i64 %x, 4 121 %shl2 = shl i64 %x, 3 122 %mask = add i64 %shl2, -2 123 %rem = and i64 %shl1, %mask 124 ret i64 %rem 125} 126 127;; Make sure it doesn't work with a right shift 128;; Make sure it doesn't work if the subtract isn't one. 129define i64 @rightshift(i64 %arg) { 130; CHECK-LABEL: define i64 @rightshift 131; CHECK-SAME: (i64 [[ARG:%.*]]) { 132; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[ARG]] 133; CHECK-NEXT: [[X:%.*]] = and i64 [[NEG]], [[ARG]] 134; CHECK-NEXT: [[SHL1:%.*]] = shl i64 [[X]], 4 135; CHECK-NEXT: [[SHL2:%.*]] = lshr i64 [[X]], 3 136; CHECK-NEXT: [[MASK:%.*]] = add i64 [[SHL2]], -1 137; CHECK-NEXT: [[REM:%.*]] = and i64 [[SHL1]], [[MASK]] 138; CHECK-NEXT: ret i64 [[REM]] 139; 140 %neg = sub i64 0, %arg 141 %x = and i64 %neg, %arg 142 %shl1 = shl i64 %x, 4 143 %shl2 = lshr i64 %x, 3 144 %mask = add i64 %shl2, -1 145 %rem = and i64 %shl1, %mask 146 ret i64 %rem 147} 148 149declare i64 @llvm.vscale.i64() 150 151attributes #0 = { vscale_range(1,16) } 152