forked from OSchip/llvm-project
Avoid zero extend bit test operands to pointer type if all the masks fit in
the original type of the switch statement key. rdar://8781238 llvm-svn: 122935
This commit is contained in:
parent
3b949bcaf3
commit
ac730dd2d1
|
@ -1615,12 +1615,28 @@ void SelectionDAGBuilder::visitBitTestHeader(BitTestBlock &B,
|
|||
Sub, DAG.getConstant(B.Range, VT),
|
||||
ISD::SETUGT);
|
||||
|
||||
SDValue ShiftOp = DAG.getZExtOrTrunc(Sub, getCurDebugLoc(),
|
||||
TLI.getPointerTy());
|
||||
// Determine the type of the test operands.
|
||||
bool UsePtrType = false;
|
||||
if (!TLI.isTypeLegal(VT))
|
||||
UsePtrType = true;
|
||||
else {
|
||||
for (unsigned i = 0, e = B.Cases.size(); i != e; ++i)
|
||||
if ((uint64_t)((int64_t)B.Cases[i].Mask >> VT.getSizeInBits()) + 1 >= 2) {
|
||||
// Switch table case range are encoded into series of masks.
|
||||
// Just use pointer type, it's guaranteed to fit.
|
||||
UsePtrType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (UsePtrType) {
|
||||
VT = TLI.getPointerTy();
|
||||
Sub = DAG.getZExtOrTrunc(Sub, getCurDebugLoc(), VT);
|
||||
}
|
||||
|
||||
B.Reg = FuncInfo.CreateReg(TLI.getPointerTy());
|
||||
B.RegVT = VT;
|
||||
B.Reg = FuncInfo.CreateReg(VT);
|
||||
SDValue CopyTo = DAG.getCopyToReg(getControlRoot(), getCurDebugLoc(),
|
||||
B.Reg, ShiftOp);
|
||||
B.Reg, Sub);
|
||||
|
||||
// Set NextBlock to be the MBB immediately after the current one, if any.
|
||||
// This is used to avoid emitting unnecessary branches to the next block.
|
||||
|
@ -1646,36 +1662,34 @@ void SelectionDAGBuilder::visitBitTestHeader(BitTestBlock &B,
|
|||
}
|
||||
|
||||
/// visitBitTestCase - this function produces one "bit test"
|
||||
void SelectionDAGBuilder::visitBitTestCase(MachineBasicBlock* NextMBB,
|
||||
void SelectionDAGBuilder::visitBitTestCase(BitTestBlock &BB,
|
||||
MachineBasicBlock* NextMBB,
|
||||
unsigned Reg,
|
||||
BitTestCase &B,
|
||||
MachineBasicBlock *SwitchBB) {
|
||||
SDValue ShiftOp = DAG.getCopyFromReg(getControlRoot(), getCurDebugLoc(), Reg,
|
||||
TLI.getPointerTy());
|
||||
EVT VT = BB.RegVT;
|
||||
SDValue ShiftOp = DAG.getCopyFromReg(getControlRoot(), getCurDebugLoc(),
|
||||
Reg, VT);
|
||||
SDValue Cmp;
|
||||
if (CountPopulation_64(B.Mask) == 1) {
|
||||
// Testing for a single bit; just compare the shift count with what it
|
||||
// would need to be to shift a 1 bit in that position.
|
||||
Cmp = DAG.getSetCC(getCurDebugLoc(),
|
||||
TLI.getSetCCResultType(ShiftOp.getValueType()),
|
||||
TLI.getSetCCResultType(VT),
|
||||
ShiftOp,
|
||||
DAG.getConstant(CountTrailingZeros_64(B.Mask),
|
||||
TLI.getPointerTy()),
|
||||
DAG.getConstant(CountTrailingZeros_64(B.Mask), VT),
|
||||
ISD::SETEQ);
|
||||
} else {
|
||||
// Make desired shift
|
||||
SDValue SwitchVal = DAG.getNode(ISD::SHL, getCurDebugLoc(),
|
||||
TLI.getPointerTy(),
|
||||
DAG.getConstant(1, TLI.getPointerTy()),
|
||||
ShiftOp);
|
||||
SDValue SwitchVal = DAG.getNode(ISD::SHL, getCurDebugLoc(), VT,
|
||||
DAG.getConstant(1, VT), ShiftOp);
|
||||
|
||||
// Emit bit tests and jumps
|
||||
SDValue AndOp = DAG.getNode(ISD::AND, getCurDebugLoc(),
|
||||
TLI.getPointerTy(), SwitchVal,
|
||||
DAG.getConstant(B.Mask, TLI.getPointerTy()));
|
||||
VT, SwitchVal, DAG.getConstant(B.Mask, VT));
|
||||
Cmp = DAG.getSetCC(getCurDebugLoc(),
|
||||
TLI.getSetCCResultType(AndOp.getValueType()),
|
||||
AndOp, DAG.getConstant(0, TLI.getPointerTy()),
|
||||
TLI.getSetCCResultType(VT),
|
||||
AndOp, DAG.getConstant(0, VT),
|
||||
ISD::SETNE);
|
||||
}
|
||||
|
||||
|
@ -2219,7 +2233,7 @@ bool SelectionDAGBuilder::handleBitTestsSwitchCase(CaseRec& CR,
|
|||
}
|
||||
|
||||
BitTestBlock BTB(lowBound, cmpRange, SV,
|
||||
-1U, (CR.CaseBB == SwitchBB),
|
||||
-1U, MVT::Other, (CR.CaseBB == SwitchBB),
|
||||
CR.CaseBB, Default, BTC);
|
||||
|
||||
if (CR.CaseBB == SwitchBB)
|
||||
|
|
|
@ -258,15 +258,16 @@ private:
|
|||
|
||||
struct BitTestBlock {
|
||||
BitTestBlock(APInt F, APInt R, const Value* SV,
|
||||
unsigned Rg, bool E,
|
||||
unsigned Rg, EVT RgVT, bool E,
|
||||
MachineBasicBlock* P, MachineBasicBlock* D,
|
||||
const BitTestInfo& C):
|
||||
First(F), Range(R), SValue(SV), Reg(Rg), Emitted(E),
|
||||
First(F), Range(R), SValue(SV), Reg(Rg), RegVT(RgVT), Emitted(E),
|
||||
Parent(P), Default(D), Cases(C) { }
|
||||
APInt First;
|
||||
APInt Range;
|
||||
const Value *SValue;
|
||||
unsigned Reg;
|
||||
EVT RegVT;
|
||||
bool Emitted;
|
||||
MachineBasicBlock *Parent;
|
||||
MachineBasicBlock *Default;
|
||||
|
@ -435,7 +436,8 @@ public:
|
|||
void visitSwitchCase(CaseBlock &CB,
|
||||
MachineBasicBlock *SwitchBB);
|
||||
void visitBitTestHeader(BitTestBlock &B, MachineBasicBlock *SwitchBB);
|
||||
void visitBitTestCase(MachineBasicBlock* NextMBB,
|
||||
void visitBitTestCase(BitTestBlock &BB,
|
||||
MachineBasicBlock* NextMBB,
|
||||
unsigned Reg,
|
||||
BitTestCase &B,
|
||||
MachineBasicBlock *SwitchBB);
|
||||
|
|
|
@ -1017,12 +1017,14 @@ SelectionDAGISel::FinishBasicBlock() {
|
|||
FuncInfo->InsertPt = FuncInfo->MBB->end();
|
||||
// Emit the code
|
||||
if (j+1 != ej)
|
||||
SDB->visitBitTestCase(SDB->BitTestCases[i].Cases[j+1].ThisBB,
|
||||
SDB->visitBitTestCase(SDB->BitTestCases[i],
|
||||
SDB->BitTestCases[i].Cases[j+1].ThisBB,
|
||||
SDB->BitTestCases[i].Reg,
|
||||
SDB->BitTestCases[i].Cases[j],
|
||||
FuncInfo->MBB);
|
||||
else
|
||||
SDB->visitBitTestCase(SDB->BitTestCases[i].Default,
|
||||
SDB->visitBitTestCase(SDB->BitTestCases[i],
|
||||
SDB->BitTestCases[i].Default,
|
||||
SDB->BitTestCases[i].Reg,
|
||||
SDB->BitTestCases[i].Cases[j],
|
||||
FuncInfo->MBB);
|
||||
|
|
|
@ -49,3 +49,33 @@ sw.epilog: ; preds = %sw.default, %sw.bb4
|
|||
}
|
||||
|
||||
declare void @foo(i32)
|
||||
|
||||
; Don't zero extend the test operands to pointer type if it can be avoided.
|
||||
; rdar://8781238
|
||||
define void @test2(i32 %x) nounwind ssp {
|
||||
; CHECK: test2:
|
||||
; CHECK: cmpl $6
|
||||
; CHECK: ja
|
||||
|
||||
; CHECK-NEXT: movl $91
|
||||
; CHECK-NOT: movl
|
||||
; CHECK-NEXT: btl
|
||||
; CHECK-NEXT: jb
|
||||
entry:
|
||||
switch i32 %x, label %if.end [
|
||||
i32 6, label %if.then
|
||||
i32 4, label %if.then
|
||||
i32 3, label %if.then
|
||||
i32 1, label %if.then
|
||||
i32 0, label %if.then
|
||||
]
|
||||
|
||||
if.then: ; preds = %entry, %entry, %entry, %entry, %entry
|
||||
tail call void @bar() nounwind
|
||||
ret void
|
||||
|
||||
if.end: ; preds = %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @bar()
|
||||
|
|
Loading…
Reference in New Issue