Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[AArch64][GlobalISel] Fold G_AND into G_BRCOND
When the G_BRCOND is fed by a eq or ne G_ICMP, it may be possible to fold a G_AND into the branch by producing a tbnz/tbz instead. This happens when 1. We have a ne/eq G_ICMP feeding into the G_BRCOND 2. The G_ICMP is a comparison against 0 3. One of the operands of the G_AND is a power of 2 constant This is very similar to the code in AArch64TargetLowering::LowerBR_CC. Add opt-and-tbnz-tbz to test this. Differential Revision: https://reviews.llvm.org/D73573
- Loading branch information
Jessica Paquette
committed
Jan 28, 2020
1 parent
4e799ad
commit dba29f7
Showing
2 changed files
with
330 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
257 changes: 257 additions & 0 deletions
257
llvm/test/CodeGen/AArch64/GlobalISel/opt-and-tbnz-tbz.mir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py | ||
# RUN: llc -mtriple aarch64-unknown-unknown -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s | ||
# | ||
# Verify that we can fold G_AND into G_BRCOND when all of the following hold: | ||
# 1. We have a ne/eq G_ICMP feeding into the G_BRCOND | ||
# 2. The G_ICMP is being compared against 0 | ||
# 3. One of the operands of the G_AND is a power of 2 | ||
# | ||
# If all of these hold, we should produce a tbnz or a tbz. | ||
... | ||
--- | ||
name: tbnz_and_s64 | ||
alignment: 4 | ||
legalized: true | ||
regBankSelected: true | ||
body: | | ||
; CHECK-LABEL: name: tbnz_and_s64 | ||
; CHECK: bb.0: | ||
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) | ||
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 | ||
; CHECK: TBNZX [[COPY]], 3, %bb.1 | ||
; CHECK: B %bb.0 | ||
; CHECK: bb.1: | ||
; CHECK: RET_ReallyLR | ||
bb.0: | ||
successors: %bb.0, %bb.1 | ||
liveins: $x0 | ||
%0:gpr(s64) = COPY $x0 | ||
%1:gpr(s64) = G_CONSTANT i64 8 ; Power of 2 => TBNZ uses 3 as mask | ||
%3:gpr(s64) = G_CONSTANT i64 0 | ||
%2:gpr(s64) = G_AND %0, %1 | ||
%5:gpr(s32) = G_ICMP intpred(ne), %2(s64), %3 | ||
%4:gpr(s1) = G_TRUNC %5(s32) | ||
G_BRCOND %4(s1), %bb.1 | ||
G_BR %bb.0 | ||
bb.1: | ||
RET_ReallyLR | ||
... | ||
--- | ||
name: tbz_and_s64 | ||
alignment: 4 | ||
legalized: true | ||
regBankSelected: true | ||
tracksRegLiveness: true | ||
body: | | ||
; CHECK-LABEL: name: tbz_and_s64 | ||
; CHECK: bb.0: | ||
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) | ||
; CHECK: liveins: $x0 | ||
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 | ||
; CHECK: TBZX [[COPY]], 4, %bb.1 | ||
; CHECK: B %bb.0 | ||
; CHECK: bb.1: | ||
; CHECK: RET_ReallyLR | ||
bb.0: | ||
successors: %bb.0, %bb.1 | ||
liveins: $x0 | ||
%0:gpr(s64) = COPY $x0 | ||
%1:gpr(s64) = G_CONSTANT i64 16 ; Power of 2 => TBNZ uses 4 as mask | ||
%3:gpr(s64) = G_CONSTANT i64 0 | ||
%2:gpr(s64) = G_AND %0, %1 | ||
%5:gpr(s32) = G_ICMP intpred(eq), %2(s64), %3 | ||
%4:gpr(s1) = G_TRUNC %5(s32) | ||
G_BRCOND %4(s1), %bb.1 | ||
G_BR %bb.0 | ||
bb.1: | ||
RET_ReallyLR | ||
... | ||
--- | ||
name: tbnz_and_s32 | ||
alignment: 4 | ||
legalized: true | ||
regBankSelected: true | ||
tracksRegLiveness: true | ||
body: | | ||
; CHECK-LABEL: name: tbnz_and_s32 | ||
; CHECK: bb.0: | ||
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) | ||
; CHECK: liveins: $w0 | ||
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 | ||
; CHECK: TBNZW [[COPY]], 0, %bb.1 | ||
; CHECK: B %bb.0 | ||
; CHECK: bb.1: | ||
; CHECK: RET_ReallyLR | ||
bb.0: | ||
successors: %bb.0, %bb.1 | ||
liveins: $w0 | ||
%0:gpr(s32) = COPY $w0 | ||
%1:gpr(s32) = G_CONSTANT i32 1 ; Power of 2 => TBNZ uses 0 as mask | ||
%3:gpr(s32) = G_CONSTANT i32 0 | ||
%2:gpr(s32) = G_AND %0, %1 | ||
%5:gpr(s32) = G_ICMP intpred(ne), %2(s32), %3 | ||
%4:gpr(s1) = G_TRUNC %5(s32) | ||
G_BRCOND %4(s1), %bb.1 | ||
G_BR %bb.0 | ||
bb.1: | ||
RET_ReallyLR | ||
... | ||
--- | ||
name: tbz_and_s32 | ||
alignment: 4 | ||
legalized: true | ||
regBankSelected: true | ||
tracksRegLiveness: true | ||
body: | | ||
; CHECK-LABEL: name: tbz_and_s32 | ||
; CHECK: bb.0: | ||
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) | ||
; CHECK: liveins: $w0 | ||
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 | ||
; CHECK: TBZW [[COPY]], 0, %bb.1 | ||
; CHECK: B %bb.0 | ||
; CHECK: bb.1: | ||
; CHECK: RET_ReallyLR | ||
bb.0: | ||
successors: %bb.0, %bb.1 | ||
liveins: $w0 | ||
%0:gpr(s32) = COPY $w0 | ||
%1:gpr(s32) = G_CONSTANT i32 1 ; Power of 2 => TBNZ uses 0 as mask | ||
%3:gpr(s32) = G_CONSTANT i32 0 | ||
%2:gpr(s32) = G_AND %0, %1 | ||
%5:gpr(s32) = G_ICMP intpred(eq), %2(s32), %3 | ||
%4:gpr(s1) = G_TRUNC %5(s32) | ||
G_BRCOND %4(s1), %bb.1 | ||
G_BR %bb.0 | ||
bb.1: | ||
RET_ReallyLR | ||
... | ||
--- | ||
name: dont_fold_and_lt | ||
alignment: 4 | ||
legalized: true | ||
regBankSelected: true | ||
tracksRegLiveness: true | ||
body: | | ||
; CHECK-LABEL: name: dont_fold_and_lt | ||
; CHECK: bb.0: | ||
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) | ||
; CHECK: liveins: $w0 | ||
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 | ||
; CHECK: $wzr = ANDSWri [[COPY]], 0, implicit-def $nzcv | ||
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv | ||
; CHECK: TBNZW [[CSINCWr]], 0, %bb.1 | ||
; CHECK: B %bb.0 | ||
; CHECK: bb.1: | ||
; CHECK: RET_ReallyLR | ||
bb.0: | ||
successors: %bb.0, %bb.1 | ||
liveins: $w0 | ||
%0:gpr(s32) = COPY $w0 | ||
%1:gpr(s32) = G_CONSTANT i32 1 | ||
%3:gpr(s32) = G_CONSTANT i32 0 | ||
%2:gpr(s32) = G_AND %0, %1 | ||
%5:gpr(s32) = G_ICMP intpred(slt), %2(s32), %3 | ||
%4:gpr(s1) = G_TRUNC %5(s32) | ||
G_BRCOND %4(s1), %bb.1 | ||
G_BR %bb.0 | ||
bb.1: | ||
RET_ReallyLR | ||
... | ||
--- | ||
name: dont_fold_and_gt | ||
alignment: 4 | ||
legalized: true | ||
regBankSelected: true | ||
tracksRegLiveness: true | ||
body: | | ||
; CHECK-LABEL: name: dont_fold_and_gt | ||
; CHECK: bb.0: | ||
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) | ||
; CHECK: liveins: $w0 | ||
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 | ||
; CHECK: $wzr = ANDSWri [[COPY]], 0, implicit-def $nzcv | ||
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 13, implicit $nzcv | ||
; CHECK: TBNZW [[CSINCWr]], 0, %bb.1 | ||
; CHECK: B %bb.0 | ||
; CHECK: bb.1: | ||
; CHECK: RET_ReallyLR | ||
bb.0: | ||
successors: %bb.0, %bb.1 | ||
liveins: $w0 | ||
%0:gpr(s32) = COPY $w0 | ||
%1:gpr(s32) = G_CONSTANT i32 1 | ||
%3:gpr(s32) = G_CONSTANT i32 0 | ||
%2:gpr(s32) = G_AND %0, %1 | ||
%5:gpr(s32) = G_ICMP intpred(sgt), %2(s32), %3 | ||
%4:gpr(s1) = G_TRUNC %5(s32) | ||
G_BRCOND %4(s1), %bb.1 | ||
G_BR %bb.0 | ||
bb.1: | ||
RET_ReallyLR | ||
... | ||
--- | ||
name: dont_fold_and_not_power_of_2 | ||
alignment: 4 | ||
legalized: true | ||
regBankSelected: true | ||
body: | | ||
; CHECK-LABEL: name: dont_fold_and_not_power_of_2 | ||
; CHECK: bb.0: | ||
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) | ||
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 | ||
; CHECK: [[ANDXri:%[0-9]+]]:gpr64common = ANDXri [[COPY]], 4098 | ||
; CHECK: CBNZX [[ANDXri]], %bb.1 | ||
; CHECK: B %bb.0 | ||
; CHECK: bb.1: | ||
; CHECK: RET_ReallyLR | ||
bb.0: | ||
successors: %bb.0, %bb.1 | ||
liveins: $x0 | ||
%0:gpr(s64) = COPY $x0 | ||
%1:gpr(s64) = G_CONSTANT i64 7 | ||
%3:gpr(s64) = G_CONSTANT i64 0 | ||
%2:gpr(s64) = G_AND %0, %1 | ||
%5:gpr(s32) = G_ICMP intpred(ne), %2(s64), %3 | ||
%4:gpr(s1) = G_TRUNC %5(s32) | ||
G_BRCOND %4(s1), %bb.1 | ||
G_BR %bb.0 | ||
bb.1: | ||
RET_ReallyLR | ||
... | ||
--- | ||
name: dont_fold_cmp_not_0 | ||
alignment: 4 | ||
legalized: true | ||
regBankSelected: true | ||
body: | | ||
; CHECK-LABEL: name: dont_fold_cmp_not_0 | ||
; CHECK: bb.0: | ||
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) | ||
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 | ||
; CHECK: [[ANDXri:%[0-9]+]]:gpr64sp = ANDXri [[COPY]], 8064 | ||
; CHECK: $xzr = SUBSXri [[ANDXri]], 4, 0, implicit-def $nzcv | ||
; CHECK: Bcc 1, %bb.1, implicit $nzcv | ||
; CHECK: B %bb.0 | ||
; CHECK: bb.1: | ||
; CHECK: RET_ReallyLR | ||
bb.0: | ||
successors: %bb.0, %bb.1 | ||
liveins: $x0 | ||
%0:gpr(s64) = COPY $x0 | ||
%1:gpr(s64) = G_CONSTANT i64 4 | ||
%3:gpr(s64) = G_CONSTANT i64 4 | ||
%2:gpr(s64) = G_AND %0, %1 | ||
%5:gpr(s32) = G_ICMP intpred(ne), %2(s64), %3 | ||
%4:gpr(s1) = G_TRUNC %5(s32) | ||
G_BRCOND %4(s1), %bb.1 | ||
G_BR %bb.0 | ||
bb.1: | ||
RET_ReallyLR |