[AArch64][GlobalISel] Optimize compare and branch cases with G_INTTOPTR and unknown values.

Since we have distinct types for pointers and scalars, G_INTTOPTRs can sometimes
obstruct attempts to find constant source values. These usually come about when
try to do some kind of null pointer check. Teaching getConstantVRegValWithLookThrough
about this operation allows the CBZ/CBNZ optimization to catch more cases.

This change also improves the case where we can't find a constant source at all.
Previously we would emit a cmp, cset and tbnz for that. Now we try to just emit
a cmp and conditional branch, saving an instruction.

The cumulative code size improvement of this change plus D64354 is 5.5% geomean
on arm64 CTMark -O0.

Differential Revision: https://reviews.llvm.org/D64377

llvm-svn: 365690
This commit is contained in:
Amara Emerson 2019-07-10 19:21:43 +00:00
parent 5f5237c276
commit 7a4d2df04a
5 changed files with 131 additions and 43 deletions

View File

@ -238,6 +238,9 @@ Optional<ValueAndVReg> llvm::getConstantVRegValWithLookThrough(
if (TargetRegisterInfo::isPhysicalRegister(VReg))
return None;
break;
case TargetOpcode::G_INTTOPTR:
VReg = MI->getOperand(1).getReg();
break;
default:
return None;
}

View File

@ -899,12 +899,23 @@ bool AArch64InstructionSelector::selectCompareBranch(
Register LHS = CCMI->getOperand(2).getReg();
Register RHS = CCMI->getOperand(3).getReg();
if (!getConstantVRegVal(RHS, MRI))
auto VRegAndVal = getConstantVRegValWithLookThrough(RHS, MRI);
if (!VRegAndVal)
std::swap(RHS, LHS);
const auto RHSImm = getConstantVRegVal(RHS, MRI);
if (!RHSImm || *RHSImm != 0)
return false;
VRegAndVal = getConstantVRegValWithLookThrough(RHS, MRI);
if (!VRegAndVal || VRegAndVal->Value != 0) {
MachineIRBuilder MIB(I);
// If we can't select a CBZ then emit a cmp + Bcc.
if (!emitIntegerCompare(CCMI->getOperand(2), CCMI->getOperand(3),
CCMI->getOperand(1), MIB))
return false;
const AArch64CC::CondCode CC = changeICMPPredToAArch64CC(
(CmpInst::Predicate)CCMI->getOperand(1).getPredicate());
MIB.buildInstr(AArch64::Bcc, {}, {}).addImm(CC).addMBB(DestMBB);
I.eraseFromParent();
return true;
}
const RegisterBank &RB = *RBI.getRegBank(LHS, MRI, TRI);
if (RB.getID() != AArch64::GPRRegBankID)

View File

@ -1,3 +1,4 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=aarch64-- -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
--- |
@ -5,20 +6,23 @@
define void @cbz_s64() { ret void }
define void @cbnz_s32() { ret void }
define void @cbnz_s64() { ret void }
define hidden void @test_rhs_inttoptr(i64* %p) { ret void }
define hidden void @test_rhs_unknown(i64* %p) { ret void }
...
---
# CHECK-LABEL: name: cbz_s32
name: cbz_s32
legalized: true
regBankSelected: true
# CHECK: body:
# CHECK: bb.0:
# CHECK: %0:gpr32 = COPY $w0
# CHECK: CBZW %0, %bb.1
# CHECK: B %bb.0
body: |
; CHECK-LABEL: name: cbz_s32
; CHECK: bb.0:
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000)
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: CBZW [[COPY]], %bb.1
; CHECK: B %bb.0
; CHECK: bb.1:
bb.0:
liveins: $w0
successors: %bb.0, %bb.1
@ -34,17 +38,18 @@ body: |
...
---
# CHECK-LABEL: name: cbz_s64
name: cbz_s64
legalized: true
regBankSelected: true
# CHECK: body:
# CHECK: bb.0:
# CHECK: %0:gpr64 = COPY $x0
# CHECK: CBZX %0, %bb.1
# CHECK: B %bb.0
body: |
; CHECK-LABEL: name: cbz_s64
; CHECK: bb.0:
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000)
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: CBZX [[COPY]], %bb.1
; CHECK: B %bb.0
; CHECK: bb.1:
bb.0:
liveins: $x0
successors: %bb.0, %bb.1
@ -60,17 +65,18 @@ body: |
...
---
# CHECK-LABEL: name: cbnz_s32
name: cbnz_s32
legalized: true
regBankSelected: true
# CHECK: body:
# CHECK: bb.0:
# CHECK: %0:gpr32 = COPY $w0
# CHECK: CBNZW %0, %bb.1
# CHECK: B %bb.0
body: |
; CHECK-LABEL: name: cbnz_s32
; CHECK: bb.0:
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000)
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: CBNZW [[COPY]], %bb.1
; CHECK: B %bb.0
; CHECK: bb.1:
bb.0:
liveins: $w0
successors: %bb.0, %bb.1
@ -86,17 +92,18 @@ body: |
...
---
# CHECK-LABEL: name: cbnz_s64
name: cbnz_s64
legalized: true
regBankSelected: true
# CHECK: body:
# CHECK: bb.0:
# CHECK: %0:gpr64 = COPY $x0
# CHECK: CBNZX %0, %bb.1
# CHECK: B %bb.0
body: |
; CHECK-LABEL: name: cbnz_s64
; CHECK: bb.0:
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000)
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: CBNZX [[COPY]], %bb.1
; CHECK: B %bb.0
; CHECK: bb.1:
bb.0:
liveins: $x0
successors: %bb.0, %bb.1
@ -110,3 +117,80 @@ body: |
bb.1:
...
---
name: test_rhs_inttoptr
alignment: 2
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: test_rhs_inttoptr
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
; CHECK: CBZX [[COPY]], %bb.2
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: STRXui $xzr, [[COPY]], 0 :: (store 8 into %ir.p)
; CHECK: bb.2:
; CHECK: RET_ReallyLR
bb.1:
successors: %bb.2, %bb.3
liveins: $x0
%0:gpr(p0) = COPY $x0
%2:gpr(s64) = G_CONSTANT i64 0
%1:gpr(p0) = G_INTTOPTR %2(s64)
%4:gpr(s32) = G_ICMP intpred(eq), %0(p0), %1
%3:gpr(s1) = G_TRUNC %4(s32)
G_BRCOND %3(s1), %bb.3
bb.2:
%5:gpr(s64) = G_CONSTANT i64 0
G_STORE %5(s64), %0(p0) :: (store 8 into %ir.p)
bb.3:
RET_ReallyLR
...
---
name: test_rhs_unknown
alignment: 2
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: test_rhs_unknown
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64sp = COPY $x0
; CHECK: [[LDRXui:%[0-9]+]]:gpr64common = LDRXui [[COPY]], 0 :: (load 8 from %ir.p)
; CHECK: $xzr = SUBSXri [[LDRXui]], 42, 0, implicit-def $nzcv
; CHECK: Bcc 0, %bb.2, implicit $nzcv
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: STRXui $xzr, [[COPY]], 0 :: (store 8 into %ir.p)
; CHECK: bb.2:
; CHECK: RET_ReallyLR
bb.1:
successors: %bb.2, %bb.3
liveins: $x0
%0:gpr(p0) = COPY $x0
%2:gpr(s64) = G_CONSTANT i64 42
%4:gpr(s64) = G_CONSTANT i64 0
%1:gpr(s64) = G_LOAD %0(p0) :: (load 8 from %ir.p)
%5:gpr(s32) = G_ICMP intpred(eq), %1(s64), %2
%3:gpr(s1) = G_TRUNC %5(s32)
G_BRCOND %3(s1), %bb.3
bb.2:
%6:gpr(s64) = G_CONSTANT i64 0
G_STORE %6(s64), %0(p0) :: (store 8 into %ir.p)
bb.3:
RET_ReallyLR
...

View File

@ -62,8 +62,7 @@ body: |
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[SUBSWri]], %subreg.sub_32
; CHECK: [[UBFMXri:%[0-9]+]]:gpr64common = UBFMXri [[SUBREG_TO_REG]], 0, 31
; CHECK: $xzr = SUBSXri [[UBFMXri]], 71, 0, implicit-def $nzcv
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 9, implicit $nzcv
; CHECK: TBNZW [[CSINCWr]], 0, %bb.4
; CHECK: Bcc 8, %bb.4, implicit $nzcv
; CHECK: bb.1.entry:
; CHECK: successors: %bb.3(0x2aaaaaab), %bb.4(0x2aaaaaab), %bb.2(0x2aaaaaab)
; CHECK: [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 0

View File

@ -28,12 +28,9 @@ entry:
define float @caller(i8* %error_ref) {
; CHECK-LABEL: caller:
; CHECK: mov [[ID:x[0-9]+]], x0
; CHECK: mov [[ZERO:x[0-9]+]], #0
; CHECK: mov x21, #0
; CHECK: bl {{.*}}foo
; CHECK: mov x0, x21
; CHECK: cmp x21, [[ZERO]]
; CHECK: b.ne
; CHECK: cbnz x21
; Access part of the error object and save it to error_ref
; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]
; CHECK: strb [[CODE]], [{{.*}}[[ID]]]
@ -61,12 +58,10 @@ handler:
define float @caller2(i8* %error_ref) {
; CHECK-LABEL: caller2:
; CHECK: mov [[ID:x[0-9]+]], x0
; CHECK: mov [[ZERO:x[0-9]+]], #0
; CHECK: fmov [[CMP:s[0-9]+]], #1.0
; CHECK: mov x21, #0
; CHECK: bl {{.*}}foo
; CHECK: cmp x21, [[ZERO]]
; CHECK: b.ne
; CHECK: cbnz x21
; CHECK: fcmp s0, [[CMP]]
; CHECK: b.le
; Access part of the error object and save it to error_ref
@ -193,11 +188,9 @@ define float @caller3(i8* %error_ref) {
; CHECK-LABEL: caller3:
; CHECK: mov [[ID:x[0-9]+]], x0
; CHECK: mov [[ZERO:x[0-9]+]], #0
; CHECK: mov x21, #0
; CHECK: bl {{.*}}foo_sret
; CHECK: mov x0, x21
; CHECK: cmp x21, [[ZERO]]
; CHECK: b.ne
; CHECK: cbnz x21
; Access part of the error object and save it to error_ref
; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]
; CHECK: strb [[CODE]], [{{.*}}[[ID]]]
@ -272,15 +265,13 @@ define float @caller4(i8* %error_ref) {
; CHECK-LABEL: caller4:
; CHECK: mov [[ID:x[0-9]+]], x0
; CHECK: mov [[ZERO:x[0-9]+]], #0
; CHECK: stp {{x[0-9]+}}, {{x[0-9]+}}, [sp]
; CHECK: mov x21, #0
; CHECK: str {{x[0-9]+}}, [sp, #16]
; CHECK: bl {{.*}}foo_vararg
; CHECK: mov x0, x21
; CHECK: cmp x21, [[ZERO]]
; CHECK: b.ne
; CHECK: cbnz x21
; Access part of the error object and save it to error_ref
; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]
; CHECK: strb [[CODE]], [{{.*}}[[ID]]]