1; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s 2 3%struct.anon1 = type { i32, i32, i32 } 4%struct.anon2 = type { i32, [32 x i32], i32 } 5 6@arr1 = external global [65 x %struct.anon1], align 16 7@arr2 = external global [65 x %struct.anon2], align 16 8 9define void @test1(i64 %x) nounwind { 10entry: 11 %a = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 0 12 %tmp = load i32, i32* %a, align 4 13 %b = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 1 14 %tmp1 = load i32, i32* %b, align 4 15 %sub = sub i32 %tmp, %tmp1 16 %c = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 2 17 %tmp2 = load i32, i32* %c, align 4 18 %add = add nsw i32 %sub, %tmp2 19 switch i32 %add, label %sw.epilog [ 20 i32 1, label %sw.bb.1 21 i32 2, label %sw.bb.2 22 ] 23 24sw.bb.1: ; preds = %entry 25 store i32 111, i32* %b, align 4 26 store i32 222, i32* %c, align 4 27 br label %sw.epilog 28 29sw.bb.2: ; preds = %entry 30 store i32 333, i32* %b, align 4 31 store i32 444, i32* %c, align 4 32 br label %sw.epilog 33 34sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry 35 ret void 36; CHECK-LABEL: test1: 37; CHECK: shlq $2, [[REG1:%[a-z]+]] 38; CHECK: movl arr1([[REG1]],[[REG1]],2), {{.*}} 39; CHECK: leaq arr1+4([[REG1]],[[REG1]],2), [[REG2:%[a-z]+]] 40; CHECK: subl arr1+4([[REG1]],[[REG1]],2), {{.*}} 41; CHECK: leaq arr1+8([[REG1]],[[REG1]],2), [[REG3:%[a-z]+]] 42; CHECK: addl arr1+8([[REG1]],[[REG1]],2), {{.*}} 43; CHECK: movl ${{[1-4]+}}, ([[REG2]]) 44; CHECK: movl ${{[1-4]+}}, ([[REG3]]) 45; CHECK: movl ${{[1-4]+}}, ([[REG2]]) 46; CHECK: movl ${{[1-4]+}}, ([[REG3]]) 47} 48 49define void @test2(i64 %x) nounwind optsize { 50entry: 51 %a = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 0 52 %tmp = load i32, i32* %a, align 4 53 %b = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 1 54 %tmp1 = load i32, i32* %b, align 4 55 %sub = sub i32 %tmp, %tmp1 56 %c = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 2 57 %tmp2 = load i32, i32* %c, align 4 58 %add = add nsw i32 %sub, %tmp2 59 switch i32 %add, label %sw.epilog [ 60 i32 1, label %sw.bb.1 61 i32 2, label %sw.bb.2 62 ] 63 64sw.bb.1: ; preds = %entry 65 store i32 111, i32* %b, align 4 66 store i32 222, i32* %c, align 4 67 br label %sw.epilog 68 69sw.bb.2: ; preds = %entry 70 store i32 333, i32* %b, align 4 71 store i32 444, i32* %c, align 4 72 br label %sw.epilog 73 74sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry 75 ret void 76; CHECK-LABEL: test2: 77; CHECK: shlq $2, [[REG1:%[a-z]+]] 78; CHECK: leaq arr1+4([[REG1]],[[REG1]],2), [[REG2:%[a-z]+]] 79; CHECK: movl -4([[REG2]]), {{.*}} 80; CHECK: subl ([[REG2]]), {{.*}} 81; CHECK: leaq arr1+8([[REG1]],[[REG1]],2), [[REG3:%[a-z]+]] 82; CHECK: addl ([[REG3]]), {{.*}} 83; CHECK: movl ${{[1-4]+}}, ([[REG2]]) 84; CHECK: movl ${{[1-4]+}}, ([[REG3]]) 85; CHECK: movl ${{[1-4]+}}, ([[REG2]]) 86; CHECK: movl ${{[1-4]+}}, ([[REG3]]) 87} 88 89; Check that LEA optimization pass takes into account a resultant address 90; displacement when choosing a LEA instruction for replacing a redundant 91; address recalculation. 92 93define void @test3(i64 %x) nounwind optsize { 94entry: 95 %a = getelementptr inbounds [65 x %struct.anon2], [65 x %struct.anon2]* @arr2, i64 0, i64 %x, i32 2 96 %tmp = load i32, i32* %a, align 4 97 %b = getelementptr inbounds [65 x %struct.anon2], [65 x %struct.anon2]* @arr2, i64 0, i64 %x, i32 0 98 %tmp1 = load i32, i32* %b, align 4 99 %add = add nsw i32 %tmp, %tmp1 100 switch i32 %add, label %sw.epilog [ 101 i32 1, label %sw.bb.1 102 i32 2, label %sw.bb.2 103 ] 104 105sw.bb.1: ; preds = %entry 106 store i32 111, i32* %a, align 4 107 store i32 222, i32* %b, align 4 108 br label %sw.epilog 109 110sw.bb.2: ; preds = %entry 111 store i32 333, i32* %a, align 4 112 store i32 444, i32* %b, align 4 113 br label %sw.epilog 114 115sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry 116 ret void 117; CHECK-LABEL: test3: 118; CHECK: imulq {{.*}}, [[REG1:%[a-z]+]] 119; CHECK: leaq arr2+132([[REG1]]), [[REG2:%[a-z]+]] 120; CHECK: leaq arr2([[REG1]]), [[REG3:%[a-z]+]] 121 122; REG3's definition is closer to movl than REG2's, but the pass still chooses 123; REG2 because it provides the resultant address displacement fitting 1 byte. 124 125; CHECK: movl ([[REG2]]), {{.*}} 126; CHECK: addl ([[REG3]]), {{.*}} 127; CHECK: movl ${{[1-4]+}}, ([[REG2]]) 128; CHECK: movl ${{[1-4]+}}, ([[REG3]]) 129; CHECK: movl ${{[1-4]+}}, ([[REG2]]) 130; CHECK: movl ${{[1-4]+}}, ([[REG3]]) 131} 132 133define void @test4(i64 %x) nounwind minsize { 134entry: 135 %a = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 0 136 %tmp = load i32, i32* %a, align 4 137 %b = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 1 138 %tmp1 = load i32, i32* %b, align 4 139 %sub = sub i32 %tmp, %tmp1 140 %c = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 2 141 %tmp2 = load i32, i32* %c, align 4 142 %add = add nsw i32 %sub, %tmp2 143 switch i32 %add, label %sw.epilog [ 144 i32 1, label %sw.bb.1 145 i32 2, label %sw.bb.2 146 ] 147 148sw.bb.1: ; preds = %entry 149 store i32 111, i32* %b, align 4 150 store i32 222, i32* %c, align 4 151 br label %sw.epilog 152 153sw.bb.2: ; preds = %entry 154 store i32 333, i32* %b, align 4 155 store i32 444, i32* %c, align 4 156 br label %sw.epilog 157 158sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry 159 ret void 160; CHECK-LABEL: test4: 161; CHECK: leaq arr1+4({{.*}}), [[REG2:%[a-z]+]] 162; CHECK: movl -4([[REG2]]), {{.*}} 163; CHECK: subl ([[REG2]]), {{.*}} 164; CHECK: addl 4([[REG2]]), {{.*}} 165; CHECK: movl ${{[1-4]+}}, ([[REG2]]) 166; CHECK: movl ${{[1-4]+}}, 4([[REG2]]) 167; CHECK: movl ${{[1-4]+}}, ([[REG2]]) 168; CHECK: movl ${{[1-4]+}}, 4([[REG2]]) 169} 170