Amara Emerson 03bce0bf4e [GlobalISel][Localizer] Don't localize phi operands which are used more than once in the phi.
The current algorithm just tries to localize defs as far as they can go, and in
the case of G_PHI operands, it clones the def into the predecessor block for
each incoming edge. When multiple edges have the same register value, this can
cause unnecessary code bloat, and inhibit later optimizations.

This change checks if a given phi operand is unique in the phi, if not the
def of that register is not localized to the predecessor.

Differential Revision: https://reviews.llvm.org/D95406
2021-01-25 17:48:04 -08:00

609 lines
20 KiB
YAML

# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -O0 -mtriple=aarch64-apple-ios -run-pass=localizer -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=CHECK
# Test the localizer.
--- |
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
define void @local_use() { ret void }
define void @non_local_1use() { ret void }
define void @non_local_2uses() { ret void }
define void @non_local_phi_use() { ret void }
define void @non_local_phi_use_followed_by_use() { ret void }
define void @non_local_phi_use_followed_by_use_fi() { ret void }
define void @float_non_local_phi_use_followed_by_use_fi() { ret void }
define void @non_local_phi() { ret void }
define void @non_local_label() { ret void }
@var1 = common global i32 0, align 4
@var2 = common global i32 0, align 4
@var3 = common global i32 0, align 4
@var4 = common global i32 0, align 4
define i32 @intrablock_with_globalvalue() {
entry:
%0 = load i32, i32* @var1, align 4
%cmp = icmp eq i32 %0, 1
br i1 %cmp, label %if.then, label %if.end
if.then:
store i32 2, i32* @var2, align 4
store i32 3, i32* @var1, align 4
store i32 2, i32* @var3, align 4
store i32 3, i32* @var1, align 4
br label %if.end
if.end:
ret i32 0
}
define i32 @adrp_add() {
entry:
%0 = load i32, i32* @var1, align 4
%cmp = icmp eq i32 %0, 1
br i1 %cmp, label %if.then, label %if.end
if.then:
store i32 2, i32* @var2, align 4
store i32 3, i32* @var1, align 4
store i32 2, i32* @var3, align 4
store i32 3, i32* @var1, align 4
br label %if.end
if.end:
ret i32 0
}
define void @test_inttoptr() { ret void }
define void @many_local_use_intra_block() { ret void }
define void @non_local_phi_use_nonunique() { ret void }
...
---
name: local_use
legalized: true
regBankSelected: true
body: |
bb.0:
; CHECK-LABEL: name: local_use
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
%0:gpr(s32) = G_CONSTANT i32 1
%1:gpr(s32) = G_ADD %0, %0
...
---
name: non_local_1use
legalized: true
regBankSelected: true
body: |
; CHECK-LABEL: name: non_local_1use
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: bb.1:
; CHECK: [[C1:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD1:%[0-9]+]]:gpr(s32) = G_ADD [[C1]], [[ADD]]
; Existing registers should be left untouched
; The newly created reg should be on the same regbank/regclass as its origin.
bb.0:
successors: %bb.1
%0:gpr(s32) = G_CONSTANT i32 1
%1:gpr(s32) = G_ADD %0, %0
bb.1:
%2:gpr(s32) = G_ADD %0, %1
...
---
name: non_local_2uses
legalized: true
regBankSelected: true
body: |
; CHECK-LABEL: name: non_local_2uses
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: bb.1:
; CHECK: [[C1:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD1:%[0-9]+]]:gpr(s32) = G_ADD [[C1]], [[C1]]
; Existing registers should be left untouched
; The newly created reg should be on the same regbank/regclass as its origin.
bb.0:
successors: %bb.1
%0:gpr(s32) = G_CONSTANT i32 1
%1:gpr(s32) = G_ADD %0, %0
bb.1:
%2:gpr(s32) = G_ADD %0, %0
...
---
name: non_local_phi_use
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: non_local_phi_use
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: [[C1:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: bb.2:
; CHECK: [[PHI:%[0-9]+]]:gpr(s32) = PHI [[C1]](s32), %bb.1
; CHECK: [[ADD1:%[0-9]+]]:gpr(s32) = G_ADD [[PHI]], [[PHI]]
; Existing registers should be left untouched
; The newly created reg should be on the same regbank/regclass as its origin.
bb.0:
successors: %bb.1
%0:gpr(s32) = G_CONSTANT i32 1
%1:gpr(s32) = G_ADD %0, %0
bb.1:
successors: %bb.2
bb.2:
%3:gpr(s32) = PHI %0(s32), %bb.1
%2:gpr(s32) = G_ADD %3, %3
...
---
name: non_local_phi_use_followed_by_use
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: non_local_phi_use_followed_by_use
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: [[C1:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: bb.2:
; CHECK: [[PHI:%[0-9]+]]:gpr(s32) = PHI [[C1]](s32), %bb.1
; CHECK: [[C2:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD1:%[0-9]+]]:gpr(s32) = G_ADD [[PHI]], [[C2]]
; Existing registers should be left untouched
; The newly created reg should be on the same regbank/regclass as its origin.
bb.0:
successors: %bb.1
%0:gpr(s32) = G_CONSTANT i32 1
%1:gpr(s32) = G_ADD %0, %0
bb.1:
successors: %bb.2
bb.2:
%3:gpr(s32) = PHI %0(s32), %bb.1
%2:gpr(s32) = G_ADD %3, %0
...
---
name: non_local_phi_use_followed_by_use_fi
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: non_local_phi_use_followed_by_use_fi
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: [[FRAME_INDEX:%[0-9]+]]:gpr(s32) = G_FRAME_INDEX 1
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[FRAME_INDEX]], [[FRAME_INDEX]]
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: [[FRAME_INDEX1:%[0-9]+]]:gpr(s32) = G_FRAME_INDEX 1
; CHECK: bb.2:
; CHECK: [[PHI:%[0-9]+]]:gpr(s32) = PHI [[FRAME_INDEX1]](s32), %bb.1
; CHECK: [[FRAME_INDEX2:%[0-9]+]]:gpr(s32) = G_FRAME_INDEX 1
; CHECK: [[ADD1:%[0-9]+]]:gpr(s32) = G_ADD [[PHI]], [[FRAME_INDEX2]]
; Existing registers should be left untouched
; The newly created reg should be on the same regbank/regclass as its origin.
bb.0:
successors: %bb.1
%0:gpr(s32) = G_FRAME_INDEX 1
%1:gpr(s32) = G_ADD %0, %0
bb.1:
successors: %bb.2
bb.2:
%3:gpr(s32) = PHI %0(s32), %bb.1
%2:gpr(s32) = G_ADD %3, %0
...
---
name: float_non_local_phi_use_followed_by_use_fi
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: float_non_local_phi_use_followed_by_use_fi
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: [[C:%[0-9]+]]:fpr(s32) = G_FCONSTANT float 1.000000e+00
; CHECK: [[FADD:%[0-9]+]]:fpr(s32) = G_FADD [[C]], [[C]]
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: [[C1:%[0-9]+]]:fpr(s32) = G_FCONSTANT float 1.000000e+00
; CHECK: bb.2:
; CHECK: [[PHI:%[0-9]+]]:fpr(s32) = PHI [[C1]](s32), %bb.1
; CHECK: [[C2:%[0-9]+]]:fpr(s32) = G_FCONSTANT float 1.000000e+00
; CHECK: [[FADD1:%[0-9]+]]:fpr(s32) = G_FADD [[PHI]], [[C2]]
; Existing registers should be left untouched
; The newly created reg should be on the same regbank/regclass as its origin.
bb.0:
successors: %bb.1
%0:fpr(s32) = G_FCONSTANT float 1.0
%1:fpr(s32) = G_FADD %0, %0
bb.1:
successors: %bb.2
bb.2:
%3:fpr(s32) = PHI %0(s32), %bb.1
%2:fpr(s32) = G_FADD %3, %0
...
---
# Make sure we don't insert a constant before PHIs.
# This used to happen for loops of one basic block.
name: non_local_phi
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: non_local_phi
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: [[C:%[0-9]+]]:fpr(s32) = G_FCONSTANT float 1.000000e+00
; CHECK: [[FADD:%[0-9]+]]:fpr(s32) = G_FADD [[C]], [[C]]
; CHECK: bb.1:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: [[PHI:%[0-9]+]]:fpr(s32) = PHI [[FADD]](s32), %bb.0, %4(s32), %bb.1
; CHECK: [[C1:%[0-9]+]]:fpr(s32) = G_FCONSTANT float 1.000000e+00
; CHECK: [[FADD1:%[0-9]+]]:fpr(s32) = G_FADD [[PHI]], [[FADD]]
; CHECK: G_BR %bb.1
; Existing registers should be left untouched
; The newly created reg should be on the same regbank/regclass as its origin.
bb.0:
successors: %bb.1
%0:fpr(s32) = G_FCONSTANT float 1.0
%1:fpr(s32) = G_FADD %0, %0
bb.1:
successors: %bb.1
%3:fpr(s32) = PHI %1(s32), %bb.0, %0(s32), %bb.1
%2:fpr(s32) = G_FADD %3, %1
G_BR %bb.1
...
---
# Make sure we don't insert a constant before EH_LABELs.
name: non_local_label
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: non_local_label
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: liveins: $s0
; CHECK: [[COPY:%[0-9]+]]:fpr(s32) = COPY $s0
; CHECK: [[C:%[0-9]+]]:fpr(s32) = G_FCONSTANT float 1.000000e+00
; CHECK: bb.1:
; CHECK: successors: %bb.1(0x80000000)
; CHECK: EH_LABEL 1
; CHECK: [[C1:%[0-9]+]]:fpr(s32) = G_FCONSTANT float 1.000000e+00
; CHECK: [[FADD:%[0-9]+]]:fpr(s32) = G_FADD [[COPY]], [[C1]]
; CHECK: G_BR %bb.1
; Existing registers should be left untouched
; The newly created reg should be on the same regbank/regclass as its origin.
bb.0:
liveins: $s0
successors: %bb.1
%0:fpr(s32) = COPY $s0
%1:fpr(s32) = G_FCONSTANT float 1.0
bb.1:
successors: %bb.1
EH_LABEL 1
%2:fpr(s32) = G_FADD %0, %1
G_BR %bb.1
...
---
name: intrablock_with_globalvalue
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: intrablock_with_globalvalue
; CHECK: bb.0.entry:
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 2
; CHECK: [[GV:%[0-9]+]]:gpr(p0) = G_GLOBAL_VALUE @var2
; CHECK: [[C1:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 3
; CHECK: [[GV1:%[0-9]+]]:gpr(p0) = G_GLOBAL_VALUE @var3
; CHECK: [[C2:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 0
; CHECK: [[GV2:%[0-9]+]]:gpr(p0) = G_GLOBAL_VALUE @var1
; CHECK: [[LOAD:%[0-9]+]]:gpr(s32) = G_LOAD [[GV2]](p0) :: (load 4 from @var1)
; CHECK: [[C3:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ICMP:%[0-9]+]]:gpr(s32) = G_ICMP intpred(eq), [[LOAD]](s32), [[C3]]
; CHECK: [[TRUNC:%[0-9]+]]:gpr(s1) = G_TRUNC [[ICMP]](s32)
; CHECK: G_BRCOND [[TRUNC]](s1), %bb.1
; CHECK: G_BR %bb.2
; CHECK: bb.1.if.then:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: [[GV3:%[0-9]+]]:gpr(p0) = G_GLOBAL_VALUE @var2
; CHECK: [[C4:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 2
; CHECK: G_STORE [[C4]](s32), [[GV3]](p0) :: (store 4 into @var2)
; CHECK: [[C5:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 3
; CHECK: [[GV4:%[0-9]+]]:gpr(p0) = G_GLOBAL_VALUE @var1
; CHECK: G_STORE [[C5]](s32), [[GV4]](p0) :: (store 4 into @var1)
; CHECK: [[GV5:%[0-9]+]]:gpr(p0) = G_GLOBAL_VALUE @var3
; CHECK: G_STORE [[C4]](s32), [[GV5]](p0) :: (store 4 into @var3)
; CHECK: G_STORE [[C5]](s32), [[GV4]](p0) :: (store 4 into @var1)
; CHECK: bb.2.if.end:
; CHECK: [[C6:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 0
; CHECK: $w0 = COPY [[C6]](s32)
; CHECK: RET_ReallyLR implicit $w0
; Some of these instructions are dead. We're checking that the other instructions are
; sunk immediately before their first user in the if.then block or as close as possible.
bb.1.entry:
%1:gpr(p0) = G_GLOBAL_VALUE @var1
%2:gpr(s32) = G_CONSTANT i32 1
%4:gpr(s32) = G_CONSTANT i32 2
%5:gpr(p0) = G_GLOBAL_VALUE @var2
%6:gpr(s32) = G_CONSTANT i32 3
%7:gpr(p0) = G_GLOBAL_VALUE @var3
%8:gpr(s32) = G_CONSTANT i32 0
%0:gpr(s32) = G_LOAD %1(p0) :: (load 4 from @var1)
%9:gpr(s32) = G_ICMP intpred(eq), %0(s32), %2
%3:gpr(s1) = G_TRUNC %9(s32)
G_BRCOND %3(s1), %bb.2
G_BR %bb.3
bb.2.if.then:
G_STORE %4(s32), %5(p0) :: (store 4 into @var2)
G_STORE %6(s32), %1(p0) :: (store 4 into @var1)
G_STORE %4(s32), %7(p0) :: (store 4 into @var3)
G_STORE %6(s32), %1(p0) :: (store 4 into @var1)
bb.3.if.end:
$w0 = COPY %8(s32)
RET_ReallyLR implicit $w0
...
---
name: adrp_add
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: adrp_add
; CHECK: bb.0.entry:
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK: [[ADRP:%[0-9]+]]:gpr64(p0) = ADRP target-flags(aarch64-page) @var1
; CHECK: %addlow1:gpr(p0) = G_ADD_LOW [[ADRP]](p0), target-flags(aarch64-pageoff, aarch64-nc) @var1
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 2
; CHECK: [[ADRP1:%[0-9]+]]:gpr64(p0) = ADRP target-flags(aarch64-page) @var2
; CHECK: %addlow2:gpr(p0) = G_ADD_LOW [[ADRP1]](p0), target-flags(aarch64-pageoff, aarch64-nc) @var2
; CHECK: [[C1:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 3
; CHECK: [[ADRP2:%[0-9]+]]:gpr64(p0) = ADRP target-flags(aarch64-page) @var3
; CHECK: %addlow3:gpr(p0) = G_ADD_LOW [[ADRP2]](p0), target-flags(aarch64-pageoff, aarch64-nc) @var3
; CHECK: [[C2:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 0
; CHECK: [[LOAD:%[0-9]+]]:gpr(s32) = G_LOAD [[ADRP]](p0) :: (load 4 from @var1)
; CHECK: [[C3:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ICMP:%[0-9]+]]:gpr(s32) = G_ICMP intpred(eq), [[LOAD]](s32), [[C3]]
; CHECK: [[TRUNC:%[0-9]+]]:gpr(s1) = G_TRUNC [[ICMP]](s32)
; CHECK: G_BRCOND [[TRUNC]](s1), %bb.1
; CHECK: G_BR %bb.2
; CHECK: bb.1.if.then:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: [[ADRP3:%[0-9]+]]:gpr64(p0) = ADRP target-flags(aarch64-page) @var2
; CHECK: [[ADD_LOW:%[0-9]+]]:gpr(p0) = G_ADD_LOW [[ADRP3]](p0), target-flags(aarch64-pageoff, aarch64-nc) @var2
; CHECK: [[C4:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 2
; CHECK: G_STORE [[C4]](s32), [[ADD_LOW]](p0) :: (store 4 into @var2)
; CHECK: [[C5:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 3
; CHECK: [[ADRP4:%[0-9]+]]:gpr64(p0) = ADRP target-flags(aarch64-page) @var1
; CHECK: [[ADD_LOW1:%[0-9]+]]:gpr(p0) = G_ADD_LOW [[ADRP4]](p0), target-flags(aarch64-pageoff, aarch64-nc) @var1
; CHECK: G_STORE [[C5]](s32), [[ADD_LOW1]](p0) :: (store 4 into @var1)
; CHECK: [[ADRP5:%[0-9]+]]:gpr64(p0) = ADRP target-flags(aarch64-page) @var3
; CHECK: [[ADD_LOW2:%[0-9]+]]:gpr(p0) = G_ADD_LOW [[ADRP5]](p0), target-flags(aarch64-pageoff, aarch64-nc) @var3
; CHECK: G_STORE [[C4]](s32), [[ADD_LOW2]](p0) :: (store 4 into @var3)
; CHECK: G_STORE [[C5]](s32), [[ADD_LOW1]](p0) :: (store 4 into @var1)
; CHECK: bb.2.if.end:
; CHECK: [[C6:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 0
; CHECK: $w0 = COPY [[C6]](s32)
; CHECK: RET_ReallyLR implicit $w0
; Some of these instructions are dead.
bb.1.entry:
%1:gpr64(p0) = ADRP target-flags(aarch64-page) @var1
%addlow1:gpr(p0) = G_ADD_LOW %1(p0), target-flags(aarch64-pageoff, aarch64-nc) @var1
%2:gpr(s32) = G_CONSTANT i32 1
%4:gpr(s32) = G_CONSTANT i32 2
%5:gpr64(p0) = ADRP target-flags(aarch64-page) @var2
%addlow2:gpr(p0) = G_ADD_LOW %5(p0), target-flags(aarch64-pageoff, aarch64-nc) @var2
%6:gpr(s32) = G_CONSTANT i32 3
%7:gpr64(p0) = ADRP target-flags(aarch64-page) @var3
%addlow3:gpr(p0) = G_ADD_LOW %7(p0), target-flags(aarch64-pageoff, aarch64-nc) @var3
%8:gpr(s32) = G_CONSTANT i32 0
%0:gpr(s32) = G_LOAD %1(p0) :: (load 4 from @var1)
%9:gpr(s32) = G_ICMP intpred(eq), %0(s32), %2
%3:gpr(s1) = G_TRUNC %9(s32)
G_BRCOND %3(s1), %bb.2
G_BR %bb.3
bb.2.if.then:
G_STORE %4(s32), %addlow2(p0) :: (store 4 into @var2)
G_STORE %6(s32), %addlow1(p0) :: (store 4 into @var1)
G_STORE %4(s32), %addlow3(p0) :: (store 4 into @var3)
G_STORE %6(s32), %addlow1(p0) :: (store 4 into @var1)
bb.3.if.end:
$w0 = COPY %8(s32)
RET_ReallyLR implicit $w0
...
---
name: test_inttoptr
alignment: 4
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: test_inttoptr
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK: liveins: $w0, $x1
; CHECK: [[COPY:%[0-9]+]]:gpr(s32) = COPY $w0
; CHECK: [[COPY1:%[0-9]+]]:gpr(p0) = COPY $x1
; CHECK: [[C:%[0-9]+]]:gpr(s64) = G_CONSTANT i64 0
; CHECK: [[INTTOPTR:%[0-9]+]]:gpr(p0) = G_INTTOPTR [[C]](s64)
; CHECK: [[C1:%[0-9]+]]:gpr(s64) = G_CONSTANT i64 128
; CHECK: [[INTTOPTR1:%[0-9]+]]:gpr(p0) = G_INTTOPTR [[C1]](s64)
; CHECK: [[C2:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 0
; CHECK: [[ICMP:%[0-9]+]]:gpr(s32) = G_ICMP intpred(eq), [[COPY]](s32), [[C2]]
; CHECK: [[TRUNC:%[0-9]+]]:gpr(s1) = G_TRUNC [[ICMP]](s32)
; CHECK: G_BRCOND [[TRUNC]](s1), %bb.1
; CHECK: G_BR %bb.2
; CHECK: bb.1:
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[COPY]], [[COPY]]
; CHECK: G_STORE [[ADD]](s32), [[COPY1]](p0) :: (store 4)
; CHECK: [[C3:%[0-9]+]]:gpr(s64) = G_CONSTANT i64 128
; CHECK: [[INTTOPTR2:%[0-9]+]]:gpr(p0) = G_INTTOPTR [[C3]](s64)
; CHECK: $x0 = COPY [[INTTOPTR2]](p0)
; CHECK: RET_ReallyLR implicit $x0
; CHECK: bb.2:
; CHECK: [[C4:%[0-9]+]]:gpr(s64) = G_CONSTANT i64 0
; CHECK: [[INTTOPTR3:%[0-9]+]]:gpr(p0) = G_INTTOPTR [[C4]](s64)
; CHECK: $x0 = COPY [[INTTOPTR3]](p0)
; CHECK: RET_ReallyLR implicit $x0
bb.1:
liveins: $w0, $x1
%0:gpr(s32) = COPY $w0
%1:gpr(p0) = COPY $x1
%2:gpr(s64) = G_CONSTANT i64 128
%4:gpr(s32) = G_CONSTANT i32 0
%7:gpr(s64) = G_CONSTANT i64 0
%6:gpr(p0) = G_INTTOPTR %7(s64)
%3:gpr(p0) = G_INTTOPTR %2(s64)
%9:gpr(s32) = G_ICMP intpred(eq), %0(s32), %4
%5:gpr(s1) = G_TRUNC %9(s32)
G_BRCOND %5(s1), %bb.2
G_BR %bb.3
bb.2:
%8:gpr(s32) = G_ADD %0, %0
G_STORE %8(s32), %1(p0) :: (store 4)
$x0 = COPY %3(p0)
RET_ReallyLR implicit $x0
bb.3:
$x0 = COPY %6(p0)
RET_ReallyLR implicit $x0
...
---
name: many_local_use_intra_block
legalized: true
regBankSelected: true
body: |
bb.0:
; CHECK-LABEL: name: many_local_use_intra_block
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: [[ADD1:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: [[ADD2:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: [[ADD3:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: [[ADD4:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: [[C1:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 2
; CHECK: [[ADD5:%[0-9]+]]:gpr(s32) = G_ADD [[C1]], [[C1]]
%0:gpr(s32) = G_CONSTANT i32 1
%1:gpr(s32) = G_CONSTANT i32 2
%2:gpr(s32) = G_ADD %0, %0
%3:gpr(s32) = G_ADD %0, %0
%4:gpr(s32) = G_ADD %0, %0
%5:gpr(s32) = G_ADD %0, %0
%6:gpr(s32) = G_ADD %0, %0
%7:gpr(s32) = G_ADD %1, %1
...
---
name: non_local_phi_use_nonunique
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: non_local_phi_use_nonunique
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK: [[C:%[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
; CHECK: [[ADD:%[0-9]+]]:gpr(s32) = G_ADD [[C]], [[C]]
; CHECK: %cmp:gpr(s32) = G_ICMP intpred(eq), [[ADD]](s32), [[C]]
; CHECK: %cond:gpr(s1) = G_TRUNC %cmp(s32)
; CHECK: G_BRCOND %cond(s1), %bb.1
; CHECK: G_BR %bb.2
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: bb.2:
; CHECK: [[PHI:%[0-9]+]]:gpr(s32) = G_PHI [[C]](s32), %bb.1
; CHECK: [[ADD1:%[0-9]+]]:gpr(s32) = G_ADD [[PHI]], [[PHI]]
; Don't localize the 1 into bb.1, because there are multiple edges
; using that register.
bb.0:
successors: %bb.1, %bb.2
%0:gpr(s32) = G_CONSTANT i32 1
%1:gpr(s32) = G_ADD %0, %0
%cmp:gpr(s32) = G_ICMP intpred(eq), %1(s32), %0
%cond:gpr(s1) = G_TRUNC %cmp(s32)
G_BRCOND %cond(s1), %bb.1
G_BR %bb.2
bb.1:
successors: %bb.2
bb.2:
%3:gpr(s32) = G_PHI %0(s32), %bb.1, %0(s32), %bb.0
%2:gpr(s32) = G_ADD %3, %3
...