[llvm] 050cd44 - [AArch64][GlobalISel] Fix TBNZ/TBZ opcode selection
Jessica Paquette via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 29 13:11:57 PST 2020
Author: Jessica Paquette
Date: 2020-01-29T13:11:18-08:00
New Revision: 050cd443ca7c9dc9da9d2dcdfb4070bee7185c4e
URL: https://github.com/llvm/llvm-project/commit/050cd443ca7c9dc9da9d2dcdfb4070bee7185c4e
DIFF: https://github.com/llvm/llvm-project/commit/050cd443ca7c9dc9da9d2dcdfb4070bee7185c4e.diff
LOG: [AArch64][GlobalISel] Fix TBNZ/TBZ opcode selection
When the bit is <= 32, we have to use the W register variant for TB(N)Z.
This is because of the way the instruction is encoded.
Differential Revision: https://reviews.llvm.org/D73660
Added:
Modified:
llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
llvm/test/CodeGen/AArch64/GlobalISel/opt-and-tbnz-tbz.mir
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
index bfa329b1fe94..15dbb6a23c50 100644
--- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
@@ -1016,18 +1016,13 @@ bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
return false;
MachineRegisterInfo &MRI = *MIB.getMRI();
- unsigned Opc = 0;
Register TestReg = AndInst->getOperand(1).getReg();
- unsigned TestSize = MRI.getType(TestReg).getSizeInBits();
// Only support EQ and NE. If we have LT, then it *is* possible to fold, but
// we don't want to do this. When we have an AND and LT, we need a TST/ANDS,
// so folding would be redundant.
- if (Pred == CmpInst::Predicate::ICMP_EQ)
- Opc = TestSize == 32 ? AArch64::TBZW : AArch64::TBZX;
- else if (Pred == CmpInst::Predicate::ICMP_NE)
- Opc = TestSize == 32 ? AArch64::TBNZW : AArch64::TBNZX;
- else
+ if (Pred != CmpInst::Predicate::ICMP_EQ &&
+ Pred != CmpInst::Predicate::ICMP_NE)
return false;
// Check if the AND has a constant on its RHS which we can use as a mask.
@@ -1039,6 +1034,20 @@ bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
return false;
uint64_t Bit = Log2_64(static_cast<uint64_t>(MaybeBit->Value));
+ // Choose the correct TB(N)Z opcode to use.
+ unsigned Opc = 0;
+ if (Bit < 32) {
+ // When the bit is less than 32, we have to use a TBZW even if we're on a 64
+ // bit register.
+ Opc = Pred == CmpInst::Predicate::ICMP_EQ ? AArch64::TBZW : AArch64::TBNZW;
+ TestReg = narrowExtendRegIfNeeded(TestReg, MIB);
+ } else {
+ // Same idea for when Bit >= 32. We don't have to narrow here, because if
+ // Bit > 32, then the G_CONSTANT must be outside the range of valid 32-bit
+ // values. So, we must have a s64.
+ Opc = Pred == CmpInst::Predicate::ICMP_EQ ? AArch64::TBZX : AArch64::TBNZX;
+ }
+
// Construct the branch.
auto BranchMI =
MIB.buildInstr(Opc).addReg(TestReg).addImm(Bit).addMBB(DstMBB);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/opt-and-tbnz-tbz.mir b/llvm/test/CodeGen/AArch64/GlobalISel/opt-and-tbnz-tbz.mir
index 525bbe588142..d2042bee9c4b 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/opt-and-tbnz-tbz.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/opt-and-tbnz-tbz.mir
@@ -9,16 +9,16 @@
# If all of these hold, we should produce a tbnz or a tbz.
...
---
-name: tbnz_and_s64
+name: tbnzx_and
alignment: 4
legalized: true
regBankSelected: true
body: |
- ; CHECK-LABEL: name: tbnz_and_s64
+ ; CHECK-LABEL: name: tbnzx_and
; 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: TBNZX [[COPY]], 33, %bb.1
; CHECK: B %bb.0
; CHECK: bb.1:
; CHECK: RET_ReallyLR
@@ -26,7 +26,7 @@ body: |
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
+ %1:gpr(s64) = G_CONSTANT i64 8589934592 ; Bit number 33 => TBNZX
%3:gpr(s64) = G_CONSTANT i64 0
%2:gpr(s64) = G_AND %0, %1
%5:gpr(s32) = G_ICMP intpred(ne), %2(s64), %3
@@ -38,18 +38,18 @@ body: |
...
---
-name: tbz_and_s64
+name: tbzx_and
alignment: 4
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
- ; CHECK-LABEL: name: tbz_and_s64
+ ; CHECK-LABEL: name: tbzx_and
; 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: TBZX [[COPY]], 33, %bb.1
; CHECK: B %bb.0
; CHECK: bb.1:
; CHECK: RET_ReallyLR
@@ -57,7 +57,7 @@ body: |
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
+ %1:gpr(s64) = G_CONSTANT i64 8589934592 ; Bit number 33 => TBNZX
%3:gpr(s64) = G_CONSTANT i64 0
%2:gpr(s64) = G_AND %0, %1
%5:gpr(s32) = G_ICMP intpred(eq), %2(s64), %3
@@ -69,13 +69,13 @@ body: |
...
---
-name: tbnz_and_s32
+name: tbnzw_and
alignment: 4
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
- ; CHECK-LABEL: name: tbnz_and_s32
+ ; CHECK-LABEL: name: tbnzw_and
; CHECK: bb.0:
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000)
; CHECK: liveins: $w0
@@ -88,7 +88,7 @@ body: |
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
+ %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(ne), %2(s32), %3
@@ -100,13 +100,13 @@ body: |
...
---
-name: tbz_and_s32
+name: tbzw_and
alignment: 4
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
- ; CHECK-LABEL: name: tbz_and_s32
+ ; CHECK-LABEL: name: tbzw_and
; CHECK: bb.0:
; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000)
; CHECK: liveins: $w0
@@ -119,7 +119,7 @@ body: |
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
+ %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(eq), %2(s32), %3
More information about the llvm-commits
mailing list