mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-16 08:29:43 +00:00
[AArch64] Optimize some simple TBZ/TBNZ cases.
Summary: Add some AArch64 dag combines to optimize some simple TBZ/TBNZ cases: (tbz (and x, m), b) -> (tbz x, b) (tbz (shl x, c), b) -> (tbz x, b-c) (tbz (shr x, c), b) -> (tbz x, b+c) (tbz (xor x, -1), b) -> (tbnz x, b) Reviewers: jmolloy, mcrosier, t.p.northover Subscribers: aemerson, rengolin, llvm-commits Differential Revision: http://reviews.llvm.org/D15702 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256765 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
d84e2865f6
commit
a1c12525dc
@ -9491,6 +9491,103 @@ static SDValue performBRCONDCombine(SDNode *N,
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
// Optimize some simple tbz/tbnz cases. Returns the new operand and bit to test
|
||||
// as well as whether the test should be inverted. This code is required to
|
||||
// catch these cases (as opposed to standard dag combines) because
|
||||
// AArch64ISD::TBZ is matched during legalization.
|
||||
static SDValue getTestBitOperand(SDValue Op, unsigned &Bit, bool &Invert,
|
||||
SelectionDAG &DAG) {
|
||||
|
||||
if (!Op->hasOneUse())
|
||||
return Op;
|
||||
|
||||
// We don't handle undef/constant-fold cases below, as they should have
|
||||
// already been taken care of (e.g. and of 0, test of undefined shifted bits,
|
||||
// etc.)
|
||||
|
||||
// (tbz (trunc x), b) -> (tbz x, b)
|
||||
// This case is just here to enable more of the below cases to be caught.
|
||||
if (Op->getOpcode() == ISD::TRUNCATE &&
|
||||
Bit < Op->getValueType(0).getSizeInBits()) {
|
||||
return getTestBitOperand(Op->getOperand(0), Bit, Invert, DAG);
|
||||
}
|
||||
|
||||
if (Op->getNumOperands() != 2)
|
||||
return Op;
|
||||
|
||||
auto *C = dyn_cast<ConstantSDNode>(Op->getOperand(1));
|
||||
if (!C)
|
||||
return Op;
|
||||
|
||||
switch (Op->getOpcode()) {
|
||||
default:
|
||||
return Op;
|
||||
|
||||
// (tbz (and x, m), b) -> (tbz x, b)
|
||||
case ISD::AND:
|
||||
if ((C->getZExtValue() >> Bit) & 1)
|
||||
return getTestBitOperand(Op->getOperand(0), Bit, Invert, DAG);
|
||||
return Op;
|
||||
|
||||
// (tbz (shl x, c), b) -> (tbz x, b-c)
|
||||
case ISD::SHL:
|
||||
if (C->getZExtValue() <= Bit &&
|
||||
(Bit - C->getZExtValue()) < Op->getValueType(0).getSizeInBits()) {
|
||||
Bit = Bit - C->getZExtValue();
|
||||
return getTestBitOperand(Op->getOperand(0), Bit, Invert, DAG);
|
||||
}
|
||||
return Op;
|
||||
|
||||
// (tbz (sra x, c), b) -> (tbz x, b+c) or (tbz x, msb) if b+c is > # bits in x
|
||||
case ISD::SRA:
|
||||
Bit = Bit + C->getZExtValue();
|
||||
if (Bit >= Op->getValueType(0).getSizeInBits())
|
||||
Bit = Op->getValueType(0).getSizeInBits() - 1;
|
||||
return getTestBitOperand(Op->getOperand(0), Bit, Invert, DAG);
|
||||
|
||||
// (tbz (srl x, c), b) -> (tbz x, b+c)
|
||||
case ISD::SRL:
|
||||
if ((Bit + C->getZExtValue()) < Op->getValueType(0).getSizeInBits()) {
|
||||
Bit = Bit + C->getZExtValue();
|
||||
return getTestBitOperand(Op->getOperand(0), Bit, Invert, DAG);
|
||||
}
|
||||
return Op;
|
||||
|
||||
// (tbz (xor x, -1), b) -> (tbnz x, b)
|
||||
case ISD::XOR:
|
||||
if ((C->getZExtValue() >> Bit) & 1)
|
||||
Invert = !Invert;
|
||||
return getTestBitOperand(Op->getOperand(0), Bit, Invert, DAG);
|
||||
}
|
||||
}
|
||||
|
||||
// Optimize test single bit zero/non-zero and branch.
|
||||
static SDValue performTBZCombine(SDNode *N,
|
||||
TargetLowering::DAGCombinerInfo &DCI,
|
||||
SelectionDAG &DAG) {
|
||||
unsigned Bit = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue();
|
||||
bool Invert = false;
|
||||
SDValue TestSrc = N->getOperand(1);
|
||||
SDValue NewTestSrc = getTestBitOperand(TestSrc, Bit, Invert, DAG);
|
||||
|
||||
if (TestSrc == NewTestSrc)
|
||||
return SDValue();
|
||||
|
||||
unsigned NewOpc = N->getOpcode();
|
||||
if (Invert) {
|
||||
if (NewOpc == AArch64ISD::TBZ)
|
||||
NewOpc = AArch64ISD::TBNZ;
|
||||
else {
|
||||
assert(NewOpc == AArch64ISD::TBNZ);
|
||||
NewOpc = AArch64ISD::TBZ;
|
||||
}
|
||||
}
|
||||
|
||||
SDLoc DL(N);
|
||||
return DAG.getNode(NewOpc, DL, MVT::Other, N->getOperand(0), NewTestSrc,
|
||||
DAG.getConstant(Bit, DL, MVT::i64), N->getOperand(3));
|
||||
}
|
||||
|
||||
// vselect (v1i1 setcc) ->
|
||||
// vselect (v1iXX setcc) (XX is the size of the compared operand type)
|
||||
// FIXME: Currently the type legalizer can't handle VSELECT having v1i1 as
|
||||
@ -9642,6 +9739,9 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
|
||||
return performSTORECombine(N, DCI, DAG, Subtarget);
|
||||
case AArch64ISD::BRCOND:
|
||||
return performBRCONDCombine(N, DCI, DAG);
|
||||
case AArch64ISD::TBNZ:
|
||||
case AArch64ISD::TBZ:
|
||||
return performTBZCombine(N, DCI, DAG);
|
||||
case AArch64ISD::CSEL:
|
||||
return performCONDCombine(N, DCI, DAG, 2, 3);
|
||||
case AArch64ISD::DUP:
|
||||
|
@ -256,3 +256,106 @@ if.then:
|
||||
if.end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test14(i1 %cond) {
|
||||
; CHECK-LABEL: @test14
|
||||
br i1 %cond, label %if.end, label %if.then
|
||||
|
||||
; CHECK-NOT: and
|
||||
; CHECK: tbnz w0, #0
|
||||
|
||||
if.then:
|
||||
call void @t()
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test15(i1 %cond) {
|
||||
; CHECK-LABEL: @test15
|
||||
%cond1 = xor i1 %cond, -1
|
||||
br i1 %cond1, label %if.then, label %if.end
|
||||
|
||||
; CHECK-NOT: movn
|
||||
; CHECK: tbnz w0, #0
|
||||
|
||||
if.then:
|
||||
call void @t()
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test16(i64 %in) {
|
||||
; CHECK-LABEL: @test16
|
||||
%shl = shl i64 %in, 3
|
||||
%and = and i64 %shl, 32
|
||||
%cond = icmp eq i64 %and, 0
|
||||
br i1 %cond, label %then, label %end
|
||||
|
||||
; CHECK-NOT: lsl
|
||||
; CHECK: tbnz w0, #2
|
||||
|
||||
then:
|
||||
call void @t()
|
||||
br label %end
|
||||
|
||||
end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test17(i64 %in) {
|
||||
; CHECK-LABEL: @test17
|
||||
%shr = ashr i64 %in, 3
|
||||
%and = and i64 %shr, 1
|
||||
%cond = icmp eq i64 %and, 0
|
||||
br i1 %cond, label %then, label %end
|
||||
|
||||
; CHECK-NOT: lsr
|
||||
; CHECK: tbnz w0, #3
|
||||
|
||||
then:
|
||||
call void @t()
|
||||
br label %end
|
||||
|
||||
end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test18(i32 %in) {
|
||||
; CHECK-LABEL: @test18
|
||||
%shr = ashr i32 %in, 2
|
||||
%cond = icmp sge i32 %shr, 0
|
||||
br i1 %cond, label %then, label %end
|
||||
|
||||
; CHECK-NOT: asr
|
||||
; CHECK: tbnz w0, #31
|
||||
|
||||
then:
|
||||
call void @t()
|
||||
br label %end
|
||||
|
||||
end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test19(i64 %in) {
|
||||
; CHECK-LABEL: @test19
|
||||
%shl = lshr i64 %in, 3
|
||||
%trunc = trunc i64 %shl to i32
|
||||
%and = and i32 %trunc, 1
|
||||
%cond = icmp eq i32 %and, 0
|
||||
br i1 %cond, label %then, label %end
|
||||
|
||||
; CHECK-NOT: ubfx
|
||||
; CHECK: tbnz w0, #3
|
||||
|
||||
then:
|
||||
call void @t()
|
||||
br label %end
|
||||
|
||||
end:
|
||||
ret void
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user