llvm/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir

# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s
# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - \
# RUN:   -debug-only=aarch64-prelegalizer-combiner,gi-combiner 2>&1 >/dev/null \
# RUN:   | FileCheck %s --check-prefix=CHECK-WORKLIST

# REQUIRES: asserts

--- |
  target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
  target triple = "aarch64--"

  define void @multiple_copies(ptr %addr) {
  entry:
    br i1 0, label %if, label %else
  if:
    br label %exit
  else:
    br label %exit
  exit:
    ret void
  }

  define void @sink_to_phi_trivially_dominating(ptr %addr) {
  entry:
    br i1 0, label %if, label %exit
  if:
    br label %exit
  exit:
    ret void
  }

  define void @sink_to_phi_nondominating(ptr %addr) {
  entry:
    br i1 0, label %if, label %else
  if:
    br label %exit
  else:
    br label %exit
  exit:
    ret void
  }

  define void @sink_to_phi_emptyblock(ptr %addr) {
  entry:
    br i1 0, label %if, label %else
  if:
    br label %exit
  else:
    br label %else2
  else2:
    br label %exit
  exit:
    ret void
  }

  define void @use_doesnt_def_anything(ptr %addr) {
  entry:
    ret void
  }

  define void @op0_isnt_a_reg(ptr %addr) {
  entry:
    ret void
  }
...

---
name:            multiple_copies
# CHECK-LABEL: name: multiple_copies
tracksRegLiveness: true
body: |
  bb.0.entry:
    liveins: $x0, $w1
    successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
    ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
    %0:_(p0) = COPY $x0
    %1:_(s32) = COPY $w1
    %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
    %3:_(s32) = G_SEXT %2
    %4:_(s32) = G_CONSTANT i32 1
    %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
    G_BRCOND %5:_(s1), %bb.1
    G_BR %bb.2.else
  bb.1.if:
  ; CHECK: bb.1.if:
    successors: %bb.3(0x80000000)
    %10:_(s8) = G_CONSTANT i8 1
    ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
    %6:_(s8) = G_ADD %2, %10
    ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
    G_BR %bb.3.exit
  bb.2.else:
  ; CHECK: bb.2.else:
    successors: %bb.3(0x80000000)
    %11:_(s8) = G_CONSTANT i8 1
    ; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
    %7:_(s8) = G_SUB %2, %11
    ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_SUB [[T3]], {{.*}}
    G_BR %bb.3.exit
  bb.3.exit:
  ; CHECK: bb.3.exit:
    %8:_(s8) = G_PHI %6:_(s8), %bb.1, %7:_(s8), %bb.2
    ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
    %9:_(s32) = G_ZEXT %8
    ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
    ; CHECK: $w0 = COPY [[T0]](s32)
    ; CHECK: $w1 = COPY [[T6]](s32)
    $w0 = COPY %3
    $w1 = COPY %9

# Check that we report the correct modifications to the observer. This acts as
# a test of the debug output and a test.
#
# CHECK-WORKLIST-LABEL: Generic MI Combiner for: multiple_copies
# CHECK-WORKLIST:       Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
# CHECK-WORKLIST:       Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8)
# CHECK-WORKLIST-DAG:   Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
# CHECK-WORKLIST-DAG:   Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_
# CHECK-WORKLIST-DAG:   Changed: [[IN3]]:_(s8) = G_ADD [[NEW1:%[0-9]+]]:_, [[IN4]]:_
# CHECK-WORKLIST-DAG:   Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_
# CHECK-WORKLIST-DAG:   Changed: [[IN5]]:_(s8) = G_SUB [[NEW2:%[0-9]+]]:_, [[IN6]]:_
# CHECK-WORKLIST-DAG:   Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8)
# CHECK-WORKLIST-DAG:   Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
# CHECK-WORKLIST-DAG:   Created: [[NEW1]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
# CHECK-WORKLIST-DAG:   Created: [[NEW2]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
# CHECK-WORKLIST:       Try combining
...

---
name:            sink_to_phi_trivially_dominating
# CHECK-LABEL: name: sink_to_phi_trivially_dominating
# This test currently tests that we don't sink if we would sink to a phi. This
# is needed to avoid inserting into the middle of the leading G_PHI instructions
# of a BB
tracksRegLiveness: true
body: |
  bb.0.entry:
    liveins: $x0, $w1
    successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
    ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
    %0:_(p0) = COPY $x0
    %1:_(s32) = COPY $w1
    %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
    ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
    %3:_(s32) = G_SEXT %2
    %4:_(s32) = G_CONSTANT i32 1
    %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
    G_BRCOND %5:_(s1), %bb.1
    G_BR %bb.2.exit
  bb.1.if:
  ; CHECK: bb.1.if:
    successors: %bb.2(0x80000000)
    %10:_(s8) = G_CONSTANT i8 1
    ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
    %6:_(s8) = G_ADD %2, %10
    ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
    G_BR %bb.2.exit
  bb.2.exit:
  ; CHECK: bb.2.exit:
    %8:_(s8) = G_PHI %6:_(s8), %bb.1, %2:_(s8), %bb.0
    ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
    %9:_(s32) = G_ZEXT %8
    ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
    ; CHECK: $w0 = COPY [[T0]](s32)
    ; CHECK: $w1 = COPY [[T6]](s32)
    $w0 = COPY %3
    $w1 = COPY %9
...

---
name:            sink_to_phi_nondominating
# CHECK-LABEL: name: sink_to_phi_nondominating
tracksRegLiveness: true
body: |
  bb.0.entry:
    liveins: $x0, $w1
    successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
    ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
    %0:_(p0) = COPY $x0
    %1:_(s32) = COPY $w1
    %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
    %3:_(s32) = G_CONSTANT i32 1
    %4:_(s1) = G_ICMP intpred(ne), %1:_(s32), %3:_
    G_BRCOND %4:_(s1), %bb.1
    G_BR %bb.2.else
  bb.1.if:
  ; CHECK: bb.1.if:
    successors: %bb.3(0x80000000)
    %5:_(s8) = G_CONSTANT i8 1
    ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
    %6:_(s8) = G_ADD %2, %5
    ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
    G_BR %bb.3.exit
  bb.2.else:
  ; CHECK: bb.2.else:
    successors: %bb.3(0x80000000)
    %7:_(s8) = G_CONSTANT i8 1
    ; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
    %8:_(s8) = G_SUB %2, %7
    ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_SUB [[T3]], {{.*}}
    G_BR %bb.3.exit
  bb.3.exit:
  ; CHECK: bb.3.exit:
    %9:_(s8) = G_PHI %6:_(s8), %bb.1, %8:_(s8), %bb.2
    ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
    %10:_(s32) = G_SEXT %2
    %11:_(s32) = G_ZEXT %9
    ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
    ; CHECK: $w0 = COPY [[T0]](s32)
    ; CHECK: $w1 = COPY [[T6]](s32)
    $w0 = COPY %10
    $w1 = COPY %11
# CHECK-WORKLIST-LABEL: Generic MI Combiner for: sink_to_phi_nondominating
# CHECK-WORKLIST:       Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
# CHECK-WORKLIST:       Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8)
# CHECK-WORKLIST-DAG:   Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
# CHECK-WORKLIST-DAG:   Creating: G_TRUNC
# CHECK-WORKLIST-DAG:   Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_
# CHECK-WORKLIST-DAG:   Changed: [[IN3]]:_(s8) = G_ADD [[OUT1:%[0-9]+]]:_, [[IN4]]:_
# CHECK-WORKLIST-DAG:   Creating: G_TRUNC
# CHECK-WORKLIST-DAG:   Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_
# CHECK-WORKLIST-DAG:   Changed: [[IN5]]:_(s8) = G_SUB [[OUT2:%[0-9]+]]:_, [[IN6]]:_
# CHECK-WORKLIST-DAG:   Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8)
# CHECK-WORKLIST-DAG:   Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
# CHECK-WORKLIST-DAG:   Created: [[OUT1]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
# CHECK-WORKLIST-DAG:   Created: [[OUT2]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
# CHECK-WORKLIST:       Try combining
...

---
name:            sink_to_phi_emptyblock
# CHECK-LABEL: name: sink_to_phi_emptyblock
tracksRegLiveness: true
body: |
  bb.0.entry:
    liveins: $x0, $w1
    successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
    ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
    %0:_(p0) = COPY $x0
    %1:_(s32) = COPY $w1
    %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
    %3:_(s32) = G_SEXT %2
    %4:_(s32) = G_CONSTANT i32 1
    %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
    G_BRCOND %5:_(s1), %bb.1
    G_BR %bb.2.else
  bb.1.if:
  ; CHECK: bb.1.if:
    successors: %bb.4(0x80000000)
    %10:_(s8) = G_CONSTANT i8 1
    ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
    %6:_(s8) = G_ADD %2, %10
    ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
    G_BR %bb.4.exit
  bb.2.else:
  ; CHECK: bb.2.else:
    successors: %bb.3(0x80000000)
    G_BR %bb.3.else2
  bb.3.else2:
  ; CHECK: bb.3.else2:
    successors: %bb.4(0x80000000)
    ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
    ; Fallthrough
  bb.4.exit:
  ; CHECK: bb.4.exit:
    %8:_(s8) = G_PHI %6:_(s8), %bb.1, %2:_(s8), %bb.3
    ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
    %9:_(s32) = G_ZEXT %8
    ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
    ; CHECK: $w0 = COPY [[T0]](s32)
    ; CHECK: $w1 = COPY [[T6]](s32)
    $w0 = COPY %3
    $w1 = COPY %9
...

---
name:            use_doesnt_def_anything
# CHECK-LABEL: name: use_doesnt_def_anything
# Check that we don't crash when inspecting a use that doesn't define anything.
# The real issue which was that the combine rule was looking through
# non-truncates as if they were truncates and attempting to obtain the result
# register. It would usually go on to make the right overall decision anyway but
# would sometimes crash on things like (SOME_INTRINSIC imm). This test covers
# the case that it would recover from.
tracksRegLiveness: true
body: |
  bb.0.entry:
    liveins: $x0, $w1
    %0:_(p0) = COPY $x0
    %1:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
    ; CHECK: %1:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr)
    G_STORE %1(s8), %0(p0) :: (store (s8) into %ir.addr)
    ; CHECK: G_STORE %1(s8), %0(p0) :: (store (s8) into %ir.addr)
...

---
name:            op0_isnt_a_reg
# CHECK-LABEL: name: op0_isnt_a_reg
# This test covers the variant of use_doesnt_def_anything that would crash.
tracksRegLiveness: true
body: |
  bb.0.entry:
    liveins: $x0, $w1
    %0:_(p0) = COPY $x0
    %1:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
    ; CHECK: %1:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr)
    G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.hint), %1(s8)
    ; CHECK: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.hint), %1(s8)
...