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