1; RUN: opt < %s -slsr -gvn -S | FileCheck %s 2 3target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64" 4 5define void @slsr1(i32 %b, i32 %s) { 6; CHECK-LABEL: @slsr1( 7 ; foo(b * s); 8 %mul0 = mul i32 %b, %s 9; CHECK: mul i32 10; CHECK-NOT: mul i32 11 call void @foo(i32 %mul0) 12 13 ; foo((b + 1) * s); 14 %b1 = add i32 %b, 1 15 %mul1 = mul i32 %b1, %s 16 call void @foo(i32 %mul1) 17 18 ; foo((b + 2) * s); 19 %b2 = add i32 %b, 2 20 %mul2 = mul i32 %b2, %s 21 call void @foo(i32 %mul2) 22 23 ret void 24} 25 26define void @non_canonicalized(i32 %b, i32 %s) { 27; CHECK-LABEL: @non_canonicalized( 28 ; foo(b * s); 29 %mul0 = mul i32 %b, %s 30; CHECK: mul i32 31; CHECK-NOT: mul i32 32 call void @foo(i32 %mul0) 33 34 ; foo((1 + b) * s); 35 %b1 = add i32 1, %b 36 %mul1 = mul i32 %b1, %s 37 call void @foo(i32 %mul1) 38 39 ; foo((2 + b) * s); 40 %b2 = add i32 2, %b 41 %mul2 = mul i32 %b2, %s 42 call void @foo(i32 %mul2) 43 44 ret void 45} 46 47define void @or(i32 %a, i32 %s) { 48 %b = shl i32 %a, 1 49; CHECK-LABEL: @or( 50 ; foo(b * s); 51 %mul0 = mul i32 %b, %s 52; CHECK: [[base:[^ ]+]] = mul i32 53 call void @foo(i32 %mul0) 54 55 ; foo((b | 1) * s); 56 %b1 = or i32 %b, 1 57 %mul1 = mul i32 %b1, %s 58; CHECK: add i32 [[base]], %s 59 call void @foo(i32 %mul1) 60 61 ; foo((b | 2) * s); 62 %b2 = or i32 %b, 2 63 %mul2 = mul i32 %b2, %s 64; CHECK: mul i32 %b2, %s 65 call void @foo(i32 %mul2) 66 67 ret void 68} 69 70; foo(a * b) 71; foo((a + 1) * b) 72; foo(a * (b + 1)) 73; foo((a + 1) * (b + 1)) 74define void @slsr2(i32 %a, i32 %b) { 75; CHECK-LABEL: @slsr2( 76 %a1 = add i32 %a, 1 77 %b1 = add i32 %b, 1 78 %mul0 = mul i32 %a, %b 79; CHECK: mul i32 80; CHECK-NOT: mul i32 81 %mul1 = mul i32 %a1, %b 82 %mul2 = mul i32 %a, %b1 83 %mul3 = mul i32 %a1, %b1 84 85 call void @foo(i32 %mul0) 86 call void @foo(i32 %mul1) 87 call void @foo(i32 %mul2) 88 call void @foo(i32 %mul3) 89 90 ret void 91} 92 93; The bump is a multiple of the stride. 94; 95; foo(b * s); 96; foo((b + 2) * s); 97; foo((b + 4) * s); 98; => 99; mul0 = b * s; 100; bump = s * 2; 101; mul1 = mul0 + bump; // GVN ensures mul1 and mul2 use the same bump. 102; mul2 = mul1 + bump; 103define void @slsr3(i32 %b, i32 %s) { 104; CHECK-LABEL: @slsr3( 105 %mul0 = mul i32 %b, %s 106; CHECK: mul i32 107 call void @foo(i32 %mul0) 108 109 %b1 = add i32 %b, 2 110 %mul1 = mul i32 %b1, %s 111; CHECK: [[BUMP:%[a-zA-Z0-9]+]] = shl i32 %s, 1 112; CHECK: %mul1 = add i32 %mul0, [[BUMP]] 113 call void @foo(i32 %mul1) 114 115 %b2 = add i32 %b, 4 116 %mul2 = mul i32 %b2, %s 117; CHECK: %mul2 = add i32 %mul1, [[BUMP]] 118 call void @foo(i32 %mul2) 119 120 ret void 121} 122 123; Do not rewrite a candidate if its potential basis does not dominate it. 124; 125; if (cond) 126; foo(a * b); 127; foo((a + 1) * b); 128define void @not_dominate(i1 %cond, i32 %a, i32 %b) { 129; CHECK-LABEL: @not_dominate( 130entry: 131 %a1 = add i32 %a, 1 132 br i1 %cond, label %then, label %merge 133 134then: 135 %mul0 = mul i32 %a, %b 136; CHECK: %mul0 = mul i32 %a, %b 137 call void @foo(i32 %mul0) 138 br label %merge 139 140merge: 141 %mul1 = mul i32 %a1, %b 142; CHECK: %mul1 = mul i32 %a1, %b 143 call void @foo(i32 %mul1) 144 ret void 145} 146 147declare void @foo(i32) 148