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