1# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s 2# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - \ 3# RUN: -debug-only=aarch64-prelegalizer-combiner,gi-combiner 2>&1 >/dev/null \ 4# RUN: | FileCheck %s --check-prefix=CHECK-WORKLIST 5 6# REQUIRES: asserts 7 8--- | 9 target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 10 target triple = "aarch64--" 11 12 define void @multiple_copies(ptr %addr) { 13 entry: 14 br i1 0, label %if, label %else 15 if: 16 br label %exit 17 else: 18 br label %exit 19 exit: 20 ret void 21 } 22 23 define void @sink_to_phi_trivially_dominating(ptr %addr) { 24 entry: 25 br i1 0, label %if, label %exit 26 if: 27 br label %exit 28 exit: 29 ret void 30 } 31 32 define void @sink_to_phi_nondominating(ptr %addr) { 33 entry: 34 br i1 0, label %if, label %else 35 if: 36 br label %exit 37 else: 38 br label %exit 39 exit: 40 ret void 41 } 42 43 define void @sink_to_phi_emptyblock(ptr %addr) { 44 entry: 45 br i1 0, label %if, label %else 46 if: 47 br label %exit 48 else: 49 br label %else2 50 else2: 51 br label %exit 52 exit: 53 ret void 54 } 55 56 define void @use_doesnt_def_anything(ptr %addr) { 57 entry: 58 ret void 59 } 60 61 define void @op0_isnt_a_reg(ptr %addr) { 62 entry: 63 ret void 64 } 65... 66 67--- 68name: multiple_copies 69# CHECK-LABEL: name: multiple_copies 70tracksRegLiveness: true 71body: | 72 bb.0.entry: 73 liveins: $x0, $w1 74 successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%) 75 ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD 76 %0:_(p0) = COPY $x0 77 %1:_(s32) = COPY $w1 78 %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr) 79 %3:_(s32) = G_SEXT %2 80 %4:_(s32) = G_CONSTANT i32 1 81 %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_ 82 G_BRCOND %5:_(s1), %bb.1 83 G_BR %bb.2.else 84 bb.1.if: 85 ; CHECK: bb.1.if: 86 successors: %bb.3(0x80000000) 87 %10:_(s8) = G_CONSTANT i8 1 88 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32) 89 %6:_(s8) = G_ADD %2, %10 90 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}} 91 G_BR %bb.3.exit 92 bb.2.else: 93 ; CHECK: bb.2.else: 94 successors: %bb.3(0x80000000) 95 %11:_(s8) = G_CONSTANT i8 1 96 ; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32) 97 %7:_(s8) = G_SUB %2, %11 98 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_ADD [[T3]], {{.*}} 99 G_BR %bb.3.exit 100 bb.3.exit: 101 ; CHECK: bb.3.exit: 102 %8:_(s8) = G_PHI %6:_(s8), %bb.1, %7:_(s8), %bb.2 103 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8) 104 %9:_(s32) = G_ZEXT %8 105 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8) 106 ; CHECK: $w0 = COPY [[T0]](s32) 107 ; CHECK: $w1 = COPY [[T6]](s32) 108 $w0 = COPY %3 109 $w1 = COPY %9 110 111# Check that we report the correct modifications to the observer. This acts as 112# a test of the debug output and a test. 113# 114# CHECK-WORKLIST-LABEL: Generic MI Combiner for: multiple_copies 115# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load (s8) from %ir.addr) 116# CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8) 117# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr) 118# CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_ 119# CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[NEW1:%[0-9]+]]:_, [[IN4]]:_ 120# CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_ 121# CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[NEW2:%[0-9]+]]:_, [[IN6]]:_ 122# CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8) 123# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr) 124# CHECK-WORKLIST-DAG: Created: [[NEW1]]:_(s8) = G_TRUNC [[IN2]]:_(s32) 125# CHECK-WORKLIST-DAG: Created: [[NEW2]]:_(s8) = G_TRUNC [[IN2]]:_(s32) 126# CHECK-WORKLIST: Try combining 127... 128 129--- 130name: sink_to_phi_trivially_dominating 131# CHECK-LABEL: name: sink_to_phi_trivially_dominating 132# This test currently tests that we don't sink if we would sink to a phi. This 133# is needed to avoid inserting into the middle of the leading G_PHI instructions 134# of a BB 135tracksRegLiveness: true 136body: | 137 bb.0.entry: 138 liveins: $x0, $w1 139 successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%) 140 ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD 141 %0:_(p0) = COPY $x0 142 %1:_(s32) = COPY $w1 143 %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr) 144 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32) 145 %3:_(s32) = G_SEXT %2 146 %4:_(s32) = G_CONSTANT i32 1 147 %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_ 148 G_BRCOND %5:_(s1), %bb.1 149 G_BR %bb.2.exit 150 bb.1.if: 151 ; CHECK: bb.1.if: 152 successors: %bb.2(0x80000000) 153 %10:_(s8) = G_CONSTANT i8 1 154 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32) 155 %6:_(s8) = G_ADD %2, %10 156 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}} 157 G_BR %bb.2.exit 158 bb.2.exit: 159 ; CHECK: bb.2.exit: 160 %8:_(s8) = G_PHI %6:_(s8), %bb.1, %2:_(s8), %bb.0 161 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8) 162 %9:_(s32) = G_ZEXT %8 163 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8) 164 ; CHECK: $w0 = COPY [[T0]](s32) 165 ; CHECK: $w1 = COPY [[T6]](s32) 166 $w0 = COPY %3 167 $w1 = COPY %9 168... 169 170--- 171name: sink_to_phi_nondominating 172# CHECK-LABEL: name: sink_to_phi_nondominating 173tracksRegLiveness: true 174body: | 175 bb.0.entry: 176 liveins: $x0, $w1 177 successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%) 178 ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD 179 %0:_(p0) = COPY $x0 180 %1:_(s32) = COPY $w1 181 %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr) 182 %3:_(s32) = G_CONSTANT i32 1 183 %4:_(s1) = G_ICMP intpred(ne), %1:_(s32), %3:_ 184 G_BRCOND %4:_(s1), %bb.1 185 G_BR %bb.2.else 186 bb.1.if: 187 ; CHECK: bb.1.if: 188 successors: %bb.3(0x80000000) 189 %5:_(s8) = G_CONSTANT i8 1 190 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32) 191 %6:_(s8) = G_ADD %2, %5 192 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}} 193 G_BR %bb.3.exit 194 bb.2.else: 195 ; CHECK: bb.2.else: 196 successors: %bb.3(0x80000000) 197 %7:_(s8) = G_CONSTANT i8 1 198 ; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32) 199 %8:_(s8) = G_SUB %2, %7 200 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_ADD [[T3]], {{.*}} 201 G_BR %bb.3.exit 202 bb.3.exit: 203 ; CHECK: bb.3.exit: 204 %9:_(s8) = G_PHI %6:_(s8), %bb.1, %8:_(s8), %bb.2 205 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8) 206 %10:_(s32) = G_SEXT %2 207 %11:_(s32) = G_ZEXT %9 208 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8) 209 ; CHECK: $w0 = COPY [[T0]](s32) 210 ; CHECK: $w1 = COPY [[T6]](s32) 211 $w0 = COPY %10 212 $w1 = COPY %11 213# CHECK-WORKLIST-LABEL: Generic MI Combiner for: sink_to_phi_nondominating 214# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load (s8) from %ir.addr) 215# CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8) 216# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr) 217# CHECK-WORKLIST-DAG: Creating: G_TRUNC 218# CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_ 219# CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[OUT1:%[0-9]+]]:_, [[IN4]]:_ 220# CHECK-WORKLIST-DAG: Creating: G_TRUNC 221# CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_ 222# CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[OUT2:%[0-9]+]]:_, [[IN6]]:_ 223# CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8) 224# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr) 225# CHECK-WORKLIST-DAG: Created: [[OUT1]]:_(s8) = G_TRUNC [[IN2]]:_(s32) 226# CHECK-WORKLIST-DAG: Created: [[OUT2]]:_(s8) = G_TRUNC [[IN2]]:_(s32) 227# CHECK-WORKLIST: Try combining 228... 229 230--- 231name: sink_to_phi_emptyblock 232# CHECK-LABEL: name: sink_to_phi_emptyblock 233tracksRegLiveness: true 234body: | 235 bb.0.entry: 236 liveins: $x0, $w1 237 successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%) 238 ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD 239 %0:_(p0) = COPY $x0 240 %1:_(s32) = COPY $w1 241 %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr) 242 %3:_(s32) = G_SEXT %2 243 %4:_(s32) = G_CONSTANT i32 1 244 %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_ 245 G_BRCOND %5:_(s1), %bb.1 246 G_BR %bb.2.else 247 bb.1.if: 248 ; CHECK: bb.1.if: 249 successors: %bb.4(0x80000000) 250 %10:_(s8) = G_CONSTANT i8 1 251 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32) 252 %6:_(s8) = G_ADD %2, %10 253 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}} 254 G_BR %bb.4.exit 255 bb.2.else: 256 ; CHECK: bb.2.else: 257 successors: %bb.3(0x80000000) 258 G_BR %bb.3.else2 259 bb.3.else2: 260 ; CHECK: bb.3.else2: 261 successors: %bb.4(0x80000000) 262 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32) 263 ; Fallthrough 264 bb.4.exit: 265 ; CHECK: bb.4.exit: 266 %8:_(s8) = G_PHI %6:_(s8), %bb.1, %2:_(s8), %bb.3 267 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8) 268 %9:_(s32) = G_ZEXT %8 269 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8) 270 ; CHECK: $w0 = COPY [[T0]](s32) 271 ; CHECK: $w1 = COPY [[T6]](s32) 272 $w0 = COPY %3 273 $w1 = COPY %9 274... 275 276--- 277name: use_doesnt_def_anything 278# CHECK-LABEL: name: use_doesnt_def_anything 279# Check that we don't crash when inspecting a use that doesn't define anything. 280# The real issue which was that the combine rule was looking through 281# non-truncates as if they were truncates and attempting to obtain the result 282# register. It would usually go on to make the right overall decision anyway but 283# would sometimes crash on things like (SOME_INTRINSIC imm). This test covers 284# the case that it would recover from. 285tracksRegLiveness: true 286body: | 287 bb.0.entry: 288 liveins: $x0, $w1 289 %0:_(p0) = COPY $x0 290 %1:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr) 291 ; CHECK: %1:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr) 292 G_STORE %1(s8), %0(p0) :: (store (s8) into %ir.addr) 293 ; CHECK: G_STORE %1(s8), %0(p0) :: (store (s8) into %ir.addr) 294... 295 296--- 297name: op0_isnt_a_reg 298# CHECK-LABEL: name: op0_isnt_a_reg 299# This test covers the variant of use_doesnt_def_anything that would crash. 300tracksRegLiveness: true 301body: | 302 bb.0.entry: 303 liveins: $x0, $w1 304 %0:_(p0) = COPY $x0 305 %1:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr) 306 ; CHECK: %1:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr) 307 G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.hint), %1(s8) 308 ; CHECK: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.hint), %1(s8) 309... 310