mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-09 11:25:55 +00:00
Properly emit range comparisons for switch cases, where neighbour cases
go to the same destination. Now we're producing really good code for switch-lower-feature.ll testcase git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35672 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -15,6 +15,8 @@
|
|||||||
#define LLVM_ADT_BITVECTOR_H
|
#define LLVM_ADT_BITVECTOR_H
|
||||||
|
|
||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
|
@@ -82,15 +82,17 @@ public:
|
|||||||
/// SDISel for the code generation of additional basic blocks needed by multi-
|
/// SDISel for the code generation of additional basic blocks needed by multi-
|
||||||
/// case switch statements.
|
/// case switch statements.
|
||||||
struct CaseBlock {
|
struct CaseBlock {
|
||||||
CaseBlock(ISD::CondCode cc, Value *cmplhs, Value *cmprhs,
|
CaseBlock(ISD::CondCode cc, Value *cmplhs, Value *cmprhs, Value *cmpmiddle,
|
||||||
MachineBasicBlock *truebb, MachineBasicBlock *falsebb,
|
MachineBasicBlock *truebb, MachineBasicBlock *falsebb,
|
||||||
MachineBasicBlock *me)
|
MachineBasicBlock *me)
|
||||||
: CC(cc), CmpLHS(cmplhs), CmpRHS(cmprhs),
|
: CC(cc), CmpLHS(cmplhs), CmpMHS(cmpmiddle), CmpRHS(cmprhs),
|
||||||
TrueBB(truebb), FalseBB(falsebb), ThisBB(me) {}
|
TrueBB(truebb), FalseBB(falsebb), ThisBB(me) {}
|
||||||
// CC - the condition code to use for the case block's setcc node
|
// CC - the condition code to use for the case block's setcc node
|
||||||
ISD::CondCode CC;
|
ISD::CondCode CC;
|
||||||
// CmpLHS/CmpRHS - The LHS/RHS of the comparison to emit.
|
// CmpLHS/CmpRHS/CmpMHS - The LHS/MHS/RHS of the comparison to emit.
|
||||||
Value *CmpLHS, *CmpRHS;
|
// Emit by default LHS op RHS. MHS is used for range comparisons:
|
||||||
|
// If MHS is not null: (LHS <= MHS) and (MHS <= RHS).
|
||||||
|
Value *CmpLHS, *CmpMHS, *CmpRHS;
|
||||||
// TrueBB/FalseBB - the block to branch to if the setcc is true/false.
|
// TrueBB/FalseBB - the block to branch to if the setcc is true/false.
|
||||||
MachineBasicBlock *TrueBB, *FalseBB;
|
MachineBasicBlock *TrueBB, *FalseBB;
|
||||||
// ThisBB - the block into which to emit the code for the setcc and branches
|
// ThisBB - the block into which to emit the code for the setcc and branches
|
||||||
|
@@ -12,9 +12,11 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#define DEBUG_TYPE "isel"
|
#define DEBUG_TYPE "isel"
|
||||||
|
#include "llvm/ADT/BitVector.h"
|
||||||
#include "llvm/Analysis/AliasAnalysis.h"
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
#include "llvm/CodeGen/SelectionDAGISel.h"
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||||||
#include "llvm/CodeGen/ScheduleDAG.h"
|
#include "llvm/CodeGen/ScheduleDAG.h"
|
||||||
|
#include "llvm/Constants.h"
|
||||||
#include "llvm/CallingConv.h"
|
#include "llvm/CallingConv.h"
|
||||||
#include "llvm/DerivedTypes.h"
|
#include "llvm/DerivedTypes.h"
|
||||||
#include "llvm/Function.h"
|
#include "llvm/Function.h"
|
||||||
@@ -358,11 +360,26 @@ class SelectionDAGLowering {
|
|||||||
/// analysis.
|
/// analysis.
|
||||||
std::vector<SDOperand> PendingLoads;
|
std::vector<SDOperand> PendingLoads;
|
||||||
|
|
||||||
/// Case - A pair of values to record the Value for a switch case, and the
|
/// Case - A struct to record the Value for a switch case, and the
|
||||||
/// case's target basic block.
|
/// case's target basic block.
|
||||||
typedef std::pair<Constant*, MachineBasicBlock*> Case;
|
struct Case {
|
||||||
typedef std::vector<Case>::iterator CaseItr;
|
Constant* Low;
|
||||||
typedef std::pair<CaseItr, CaseItr> CaseRange;
|
Constant* High;
|
||||||
|
MachineBasicBlock* BB;
|
||||||
|
|
||||||
|
Case() : Low(0), High(0), BB(0) { }
|
||||||
|
Case(Constant* low, Constant* high, MachineBasicBlock* bb) :
|
||||||
|
Low(low), High(high), BB(bb) { }
|
||||||
|
uint64_t size() const {
|
||||||
|
uint64_t rHigh = cast<ConstantInt>(High)->getSExtValue();
|
||||||
|
uint64_t rLow = cast<ConstantInt>(Low)->getSExtValue();
|
||||||
|
return (rHigh - rLow + 1ULL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Case> CaseVector;
|
||||||
|
typedef CaseVector::iterator CaseItr;
|
||||||
|
typedef std::pair<CaseItr, CaseItr> CaseRange;
|
||||||
|
|
||||||
/// CaseRec - A struct with ctor used in lowering switches to a binary tree
|
/// CaseRec - A struct with ctor used in lowering switches to a binary tree
|
||||||
/// of conditional branches.
|
/// of conditional branches.
|
||||||
@@ -382,15 +399,21 @@ class SelectionDAGLowering {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<CaseRec> CaseRecVector;
|
typedef std::vector<CaseRec> CaseRecVector;
|
||||||
|
|
||||||
/// The comparison function for sorting Case values.
|
/// The comparison function for sorting the switch case values in the vector.
|
||||||
|
/// WARNING: Case ranges should be disjoint!
|
||||||
struct CaseCmp {
|
struct CaseCmp {
|
||||||
bool operator () (const Case& C1, const Case& C2) {
|
bool operator () (const Case& C1,
|
||||||
assert(isa<ConstantInt>(C1.first) && isa<ConstantInt>(C2.first));
|
const Case& C2) {
|
||||||
return cast<const ConstantInt>(C1.first)->getSExtValue() <
|
|
||||||
cast<const ConstantInt>(C2.first)->getSExtValue();
|
assert(isa<ConstantInt>(C1.Low) && isa<ConstantInt>(C2.High));
|
||||||
|
const ConstantInt* CI1 = cast<const ConstantInt>(C1.Low);
|
||||||
|
const ConstantInt* CI2 = cast<const ConstantInt>(C2.High);
|
||||||
|
return CI1->getValue().slt(CI2->getValue());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsigned Clusterify(CaseVector& Cases, const SwitchInst &SI);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// TLI - This is information that describes the available target features we
|
// TLI - This is information that describes the available target features we
|
||||||
@@ -912,14 +935,14 @@ void SelectionDAGLowering::FindMergedConditions(Value *Cond,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SelectionDAGISel::CaseBlock CB(Condition, BOp->getOperand(0),
|
SelectionDAGISel::CaseBlock CB(Condition, BOp->getOperand(0),
|
||||||
BOp->getOperand(1), TBB, FBB, CurBB);
|
BOp->getOperand(1), NULL, TBB, FBB, CurBB);
|
||||||
SwitchCases.push_back(CB);
|
SwitchCases.push_back(CB);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a CaseBlock record representing this branch.
|
// Create a CaseBlock record representing this branch.
|
||||||
SelectionDAGISel::CaseBlock CB(ISD::SETEQ, Cond, ConstantInt::getTrue(),
|
SelectionDAGISel::CaseBlock CB(ISD::SETEQ, Cond, ConstantInt::getTrue(),
|
||||||
TBB, FBB, CurBB);
|
NULL, TBB, FBB, CurBB);
|
||||||
SwitchCases.push_back(CB);
|
SwitchCases.push_back(CB);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1058,7 +1081,7 @@ void SelectionDAGLowering::visitBr(BranchInst &I) {
|
|||||||
|
|
||||||
// Create a CaseBlock record representing this branch.
|
// Create a CaseBlock record representing this branch.
|
||||||
SelectionDAGISel::CaseBlock CB(ISD::SETEQ, CondVal, ConstantInt::getTrue(),
|
SelectionDAGISel::CaseBlock CB(ISD::SETEQ, CondVal, ConstantInt::getTrue(),
|
||||||
Succ0MBB, Succ1MBB, CurMBB);
|
NULL, Succ0MBB, Succ1MBB, CurMBB);
|
||||||
// Use visitSwitchCase to actually insert the fast branch sequence for this
|
// Use visitSwitchCase to actually insert the fast branch sequence for this
|
||||||
// cond branch.
|
// cond branch.
|
||||||
visitSwitchCase(CB);
|
visitSwitchCase(CB);
|
||||||
@@ -1070,16 +1093,36 @@ void SelectionDAGLowering::visitSwitchCase(SelectionDAGISel::CaseBlock &CB) {
|
|||||||
SDOperand Cond;
|
SDOperand Cond;
|
||||||
SDOperand CondLHS = getValue(CB.CmpLHS);
|
SDOperand CondLHS = getValue(CB.CmpLHS);
|
||||||
|
|
||||||
// Build the setcc now, fold "(X == true)" to X and "(X == false)" to !X to
|
// Build the setcc now.
|
||||||
// handle common cases produced by branch lowering.
|
if (CB.CmpMHS == NULL) {
|
||||||
if (CB.CmpRHS == ConstantInt::getTrue() && CB.CC == ISD::SETEQ)
|
// Fold "(X == true)" to X and "(X == false)" to !X to
|
||||||
Cond = CondLHS;
|
// handle common cases produced by branch lowering.
|
||||||
else if (CB.CmpRHS == ConstantInt::getFalse() && CB.CC == ISD::SETEQ) {
|
if (CB.CmpRHS == ConstantInt::getTrue() && CB.CC == ISD::SETEQ)
|
||||||
SDOperand True = DAG.getConstant(1, CondLHS.getValueType());
|
Cond = CondLHS;
|
||||||
Cond = DAG.getNode(ISD::XOR, CondLHS.getValueType(), CondLHS, True);
|
else if (CB.CmpRHS == ConstantInt::getFalse() && CB.CC == ISD::SETEQ) {
|
||||||
} else
|
SDOperand True = DAG.getConstant(1, CondLHS.getValueType());
|
||||||
Cond = DAG.getSetCC(MVT::i1, CondLHS, getValue(CB.CmpRHS), CB.CC);
|
Cond = DAG.getNode(ISD::XOR, CondLHS.getValueType(), CondLHS, True);
|
||||||
|
} else
|
||||||
|
Cond = DAG.getSetCC(MVT::i1, CondLHS, getValue(CB.CmpRHS), CB.CC);
|
||||||
|
} else {
|
||||||
|
assert(CB.CC == ISD::SETLE && "Can handle only LE ranges now");
|
||||||
|
|
||||||
|
uint64_t Low = cast<ConstantInt>(CB.CmpLHS)->getSExtValue();
|
||||||
|
uint64_t High = cast<ConstantInt>(CB.CmpRHS)->getSExtValue();
|
||||||
|
|
||||||
|
SDOperand CmpOp = getValue(CB.CmpMHS);
|
||||||
|
MVT::ValueType VT = CmpOp.getValueType();
|
||||||
|
|
||||||
|
if (cast<ConstantInt>(CB.CmpLHS)->isMinValue(true)) {
|
||||||
|
Cond = DAG.getSetCC(MVT::i1, CmpOp, DAG.getConstant(High, VT), ISD::SETLE);
|
||||||
|
} else {
|
||||||
|
SDOperand SUB = DAG.getNode(ISD::SUB, VT, CmpOp, DAG.getConstant(Low, VT));
|
||||||
|
Cond = DAG.getSetCC(MVT::i1, SUB,
|
||||||
|
DAG.getConstant(High-Low, VT), ISD::SETULE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Set NextBlock to be the MBB immediately after the current one, if any.
|
// 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.
|
// This is used to avoid emitting unnecessary branches to the next block.
|
||||||
MachineBasicBlock *NextBlock = 0;
|
MachineBasicBlock *NextBlock = 0;
|
||||||
@@ -1218,7 +1261,7 @@ void SelectionDAGLowering::visitInvoke(InvokeInst &I, bool AsTerminator) {
|
|||||||
void SelectionDAGLowering::visitUnwind(UnwindInst &I) {
|
void SelectionDAGLowering::visitUnwind(UnwindInst &I) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// handleSmaaSwitchCaseRange - Emit a series of specific tests (suitable for
|
/// handleSmallSwitchCaseRange - Emit a series of specific tests (suitable for
|
||||||
/// small case ranges).
|
/// small case ranges).
|
||||||
bool SelectionDAGLowering::handleSmallSwitchRange(CaseRec& CR,
|
bool SelectionDAGLowering::handleSmallSwitchRange(CaseRec& CR,
|
||||||
CaseRecVector& WorkList,
|
CaseRecVector& WorkList,
|
||||||
@@ -1230,7 +1273,7 @@ bool SelectionDAGLowering::handleSmallSwitchRange(CaseRec& CR,
|
|||||||
unsigned Size = CR.Range.second - CR.Range.first;
|
unsigned Size = CR.Range.second - CR.Range.first;
|
||||||
if (Size >=3)
|
if (Size >=3)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Get the MachineFunction which holds the current MBB. This is used when
|
// Get the MachineFunction which holds the current MBB. This is used when
|
||||||
// inserting any additional MBBs necessary to represent the switch.
|
// inserting any additional MBBs necessary to represent the switch.
|
||||||
MachineFunction *CurMF = CurMBB->getParent();
|
MachineFunction *CurMF = CurMBB->getParent();
|
||||||
@@ -1248,11 +1291,11 @@ bool SelectionDAGLowering::handleSmallSwitchRange(CaseRec& CR,
|
|||||||
// "if (X == 6 || X == 4)" -> "if ((X|2) == 6)"
|
// "if (X == 6 || X == 4)" -> "if ((X|2) == 6)"
|
||||||
|
|
||||||
// Rearrange the case blocks so that the last one falls through if possible.
|
// Rearrange the case blocks so that the last one falls through if possible.
|
||||||
if (NextBlock && Default != NextBlock && BackCase.second != NextBlock) {
|
if (NextBlock && Default != NextBlock && BackCase.BB != NextBlock) {
|
||||||
// The last case block won't fall through into 'NextBlock' if we emit the
|
// The last case block won't fall through into 'NextBlock' if we emit the
|
||||||
// branches in this order. See if rearranging a case value would help.
|
// branches in this order. See if rearranging a case value would help.
|
||||||
for (CaseItr I = CR.Range.first, E = CR.Range.second-1; I != E; ++I) {
|
for (CaseItr I = CR.Range.first, E = CR.Range.second-1; I != E; ++I) {
|
||||||
if (I->second == NextBlock) {
|
if (I->BB == NextBlock) {
|
||||||
std::swap(*I, BackCase);
|
std::swap(*I, BackCase);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1272,9 +1315,19 @@ bool SelectionDAGLowering::handleSmallSwitchRange(CaseRec& CR,
|
|||||||
// If the last case doesn't match, go to the default block.
|
// If the last case doesn't match, go to the default block.
|
||||||
FallThrough = Default;
|
FallThrough = Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionDAGISel::CaseBlock CB(ISD::SETEQ, SV, I->first,
|
Value *RHS, *LHS, *MHS;
|
||||||
I->second, FallThrough, CurBlock);
|
ISD::CondCode CC;
|
||||||
|
if (I->High == I->Low) {
|
||||||
|
// This is just small small case range :) containing exactly 1 case
|
||||||
|
CC = ISD::SETEQ;
|
||||||
|
LHS = SV; RHS = I->High; MHS = NULL;
|
||||||
|
} else {
|
||||||
|
CC = ISD::SETLE;
|
||||||
|
LHS = I->Low; MHS = SV; RHS = I->High;
|
||||||
|
}
|
||||||
|
SelectionDAGISel::CaseBlock CB(CC, LHS, RHS, MHS,
|
||||||
|
I->BB, FallThrough, CurBlock);
|
||||||
|
|
||||||
// If emitting the first comparison, just call visitSwitchCase to emit the
|
// If emitting the first comparison, just call visitSwitchCase to emit the
|
||||||
// code into the current block. Otherwise, push the CaseBlock onto the
|
// code into the current block. Otherwise, push the CaseBlock onto the
|
||||||
@@ -1302,18 +1355,27 @@ bool SelectionDAGLowering::handleJTSwitchCase(CaseRec& CR,
|
|||||||
// Size is the number of Cases represented by this range.
|
// Size is the number of Cases represented by this range.
|
||||||
unsigned Size = CR.Range.second - CR.Range.first;
|
unsigned Size = CR.Range.second - CR.Range.first;
|
||||||
|
|
||||||
uint64_t First = cast<ConstantInt>(FrontCase.first)->getSExtValue();
|
int64_t First = cast<ConstantInt>(FrontCase.Low)->getSExtValue();
|
||||||
uint64_t Last = cast<ConstantInt>(BackCase.first)->getSExtValue();
|
int64_t Last = cast<ConstantInt>(BackCase.High)->getSExtValue();
|
||||||
|
|
||||||
|
uint64_t TSize = 0;
|
||||||
|
for (CaseItr I = CR.Range.first, E = CR.Range.second;
|
||||||
|
I!=E; ++I)
|
||||||
|
TSize += I->size();
|
||||||
|
|
||||||
if ((!TLI.isOperationLegal(ISD::BR_JT, MVT::Other) &&
|
if ((!TLI.isOperationLegal(ISD::BR_JT, MVT::Other) &&
|
||||||
!TLI.isOperationLegal(ISD::BRIND, MVT::Other)) ||
|
!TLI.isOperationLegal(ISD::BRIND, MVT::Other)) ||
|
||||||
Size <= 5)
|
Size <= 5)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
double Density = (double)Size / (double)((Last - First) + 1ULL);
|
double Density = (double)TSize / (double)((Last - First) + 1ULL);
|
||||||
if (Density < 0.3125)
|
if (Density < 0.4)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
DOUT << "Lowering jump table\n"
|
||||||
|
<< "First entry: " << First << ". Last entry: " << Last << "\n"
|
||||||
|
<< "Size: " << TSize << ". Density: " << Density << "\n";
|
||||||
|
|
||||||
// Get the MachineFunction which holds the current MBB. This is used when
|
// Get the MachineFunction which holds the current MBB. This is used when
|
||||||
// inserting any additional MBBs necessary to represent the switch.
|
// inserting any additional MBBs necessary to represent the switch.
|
||||||
MachineFunction *CurMF = CurMBB->getParent();
|
MachineFunction *CurMF = CurMBB->getParent();
|
||||||
@@ -1342,19 +1404,21 @@ bool SelectionDAGLowering::handleJTSwitchCase(CaseRec& CR,
|
|||||||
// the default BB.
|
// the default BB.
|
||||||
std::vector<MachineBasicBlock*> DestBBs;
|
std::vector<MachineBasicBlock*> DestBBs;
|
||||||
int64_t TEI = First;
|
int64_t TEI = First;
|
||||||
for (CaseItr I = CR.Range.first, E = CR.Range.second; I != E; ++TEI)
|
for (CaseItr I = CR.Range.first, E = CR.Range.second; I != E; ++TEI) {
|
||||||
if (cast<ConstantInt>(I->first)->getSExtValue() == TEI) {
|
int64_t Low = cast<ConstantInt>(I->Low)->getSExtValue();
|
||||||
DestBBs.push_back(I->second);
|
int64_t High = cast<ConstantInt>(I->High)->getSExtValue();
|
||||||
++I;
|
|
||||||
|
if ((Low <= TEI) && (TEI <= High)) {
|
||||||
|
DestBBs.push_back(I->BB);
|
||||||
|
if (TEI==High)
|
||||||
|
++I;
|
||||||
} else {
|
} else {
|
||||||
DestBBs.push_back(Default);
|
DestBBs.push_back(Default);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update successor info. Add one edge to each unique successor.
|
// Update successor info. Add one edge to each unique successor.
|
||||||
// Vector bool would be better, but vector<bool> is really slow.
|
BitVector SuccsHandled(CR.CaseBB->getParent()->getNumBlockIDs());
|
||||||
std::vector<unsigned char> SuccsHandled;
|
|
||||||
SuccsHandled.resize(CR.CaseBB->getParent()->getNumBlockIDs());
|
|
||||||
|
|
||||||
for (std::vector<MachineBasicBlock*>::iterator I = DestBBs.begin(),
|
for (std::vector<MachineBasicBlock*>::iterator I = DestBBs.begin(),
|
||||||
E = DestBBs.end(); I != E; ++I) {
|
E = DestBBs.end(); I != E; ++I) {
|
||||||
if (!SuccsHandled[(*I)->getNumber()]) {
|
if (!SuccsHandled[(*I)->getNumber()]) {
|
||||||
@@ -1404,30 +1468,38 @@ bool SelectionDAGLowering::handleBTSplitSwitchCase(CaseRec& CR,
|
|||||||
// Size is the number of Cases represented by this range.
|
// Size is the number of Cases represented by this range.
|
||||||
unsigned Size = CR.Range.second - CR.Range.first;
|
unsigned Size = CR.Range.second - CR.Range.first;
|
||||||
|
|
||||||
uint64_t First = cast<ConstantInt>(FrontCase.first)->getSExtValue();
|
int64_t First = cast<ConstantInt>(FrontCase.Low)->getSExtValue();
|
||||||
uint64_t Last = cast<ConstantInt>(BackCase.first)->getSExtValue();
|
int64_t Last = cast<ConstantInt>(BackCase.High)->getSExtValue();
|
||||||
double Density = 0;
|
double Density = 0;
|
||||||
CaseItr Pivot;
|
CaseItr Pivot = CR.Range.first + Size/2;
|
||||||
|
|
||||||
// Select optimal pivot, maximizing sum density of LHS and RHS. This will
|
// Select optimal pivot, maximizing sum density of LHS and RHS. This will
|
||||||
// (heuristically) allow us to emit JumpTable's later.
|
// (heuristically) allow us to emit JumpTable's later.
|
||||||
unsigned LSize = 1;
|
uint64_t TSize = 0;
|
||||||
unsigned RSize = Size-1;
|
for (CaseItr I = CR.Range.first, E = CR.Range.second;
|
||||||
|
I!=E; ++I)
|
||||||
|
TSize += I->size();
|
||||||
|
|
||||||
|
uint64_t LSize = FrontCase.size();
|
||||||
|
uint64_t RSize = TSize-LSize;
|
||||||
for (CaseItr I = CR.Range.first, J=I+1, E = CR.Range.second;
|
for (CaseItr I = CR.Range.first, J=I+1, E = CR.Range.second;
|
||||||
J!=E; ++I, ++J, ++LSize, --RSize) {
|
J!=E; ++I, ++J) {
|
||||||
uint64_t LEnd = cast<ConstantInt>(I->first)->getSExtValue();
|
int64_t LEnd = cast<ConstantInt>(I->High)->getSExtValue();
|
||||||
uint64_t RBegin = cast<ConstantInt>(J->first)->getSExtValue();
|
int64_t RBegin = cast<ConstantInt>(J->Low)->getSExtValue();
|
||||||
double LDensity = (double)LSize / (double)((LEnd - First) + 1ULL);
|
double LDensity = (double)LSize / (double)((LEnd - First) + 1ULL);
|
||||||
double RDensity = (double)RSize / (double)((Last - RBegin) + 1ULL);
|
double RDensity = (double)RSize / (double)((Last - RBegin) + 1ULL);
|
||||||
if (Density < (LDensity + RDensity)) {
|
if (Density < (LDensity + RDensity)) {
|
||||||
Pivot = J;
|
Pivot = J;
|
||||||
Density = LDensity + RDensity;
|
Density = LDensity + RDensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LSize += J->size();
|
||||||
|
RSize -= J->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
CaseRange LHSR(CR.Range.first, Pivot);
|
CaseRange LHSR(CR.Range.first, Pivot);
|
||||||
CaseRange RHSR(Pivot, CR.Range.second);
|
CaseRange RHSR(Pivot, CR.Range.second);
|
||||||
Constant *C = Pivot->first;
|
Constant *C = Pivot->Low;
|
||||||
MachineBasicBlock *FalseBB = 0, *TrueBB = 0;
|
MachineBasicBlock *FalseBB = 0, *TrueBB = 0;
|
||||||
|
|
||||||
// We know that we branch to the LHS if the Value being switched on is
|
// We know that we branch to the LHS if the Value being switched on is
|
||||||
@@ -1437,10 +1509,10 @@ bool SelectionDAGLowering::handleBTSplitSwitchCase(CaseRec& CR,
|
|||||||
// Pivot's Value, then we can branch directly to the LHS's Target,
|
// Pivot's Value, then we can branch directly to the LHS's Target,
|
||||||
// rather than creating a leaf node for it.
|
// rather than creating a leaf node for it.
|
||||||
if ((LHSR.second - LHSR.first) == 1 &&
|
if ((LHSR.second - LHSR.first) == 1 &&
|
||||||
LHSR.first->first == CR.GE &&
|
LHSR.first->High == CR.GE &&
|
||||||
cast<ConstantInt>(C)->getZExtValue() ==
|
cast<ConstantInt>(C)->getSExtValue() ==
|
||||||
(cast<ConstantInt>(CR.GE)->getZExtValue() + 1ULL)) {
|
(cast<ConstantInt>(CR.GE)->getSExtValue() + 1LL)) {
|
||||||
TrueBB = LHSR.first->second;
|
TrueBB = LHSR.first->BB;
|
||||||
} else {
|
} else {
|
||||||
TrueBB = new MachineBasicBlock(LLVMBB);
|
TrueBB = new MachineBasicBlock(LLVMBB);
|
||||||
CurMF->getBasicBlockList().insert(BBI, TrueBB);
|
CurMF->getBasicBlockList().insert(BBI, TrueBB);
|
||||||
@@ -1452,9 +1524,9 @@ bool SelectionDAGLowering::handleBTSplitSwitchCase(CaseRec& CR,
|
|||||||
// is CR.LT - 1, then we can branch directly to the target block for
|
// is CR.LT - 1, then we can branch directly to the target block for
|
||||||
// the current Case Value, rather than emitting a RHS leaf node for it.
|
// the current Case Value, rather than emitting a RHS leaf node for it.
|
||||||
if ((RHSR.second - RHSR.first) == 1 && CR.LT &&
|
if ((RHSR.second - RHSR.first) == 1 && CR.LT &&
|
||||||
cast<ConstantInt>(RHSR.first->first)->getZExtValue() ==
|
cast<ConstantInt>(RHSR.first->Low)->getSExtValue() ==
|
||||||
(cast<ConstantInt>(CR.LT)->getZExtValue() - 1ULL)) {
|
(cast<ConstantInt>(CR.LT)->getSExtValue() - 1LL)) {
|
||||||
FalseBB = RHSR.first->second;
|
FalseBB = RHSR.first->BB;
|
||||||
} else {
|
} else {
|
||||||
FalseBB = new MachineBasicBlock(LLVMBB);
|
FalseBB = new MachineBasicBlock(LLVMBB);
|
||||||
CurMF->getBasicBlockList().insert(BBI, FalseBB);
|
CurMF->getBasicBlockList().insert(BBI, FalseBB);
|
||||||
@@ -1464,8 +1536,8 @@ bool SelectionDAGLowering::handleBTSplitSwitchCase(CaseRec& CR,
|
|||||||
// Create a CaseBlock record representing a conditional branch to
|
// Create a CaseBlock record representing a conditional branch to
|
||||||
// the LHS node if the value being switched on SV is less than C.
|
// the LHS node if the value being switched on SV is less than C.
|
||||||
// Otherwise, branch to LHS.
|
// Otherwise, branch to LHS.
|
||||||
SelectionDAGISel::CaseBlock CB(ISD::SETLT, SV, C, TrueBB, FalseBB,
|
SelectionDAGISel::CaseBlock CB(ISD::SETLT, SV, C, NULL,
|
||||||
CR.CaseBB);
|
TrueBB, FalseBB, CR.CaseBB);
|
||||||
|
|
||||||
if (CR.CaseBB == CurMBB)
|
if (CR.CaseBB == CurMBB)
|
||||||
visitSwitchCase(CB);
|
visitSwitchCase(CB);
|
||||||
@@ -1475,16 +1547,57 @@ bool SelectionDAGLowering::handleBTSplitSwitchCase(CaseRec& CR,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectionDAGLowering::visitSwitch(SwitchInst &I) {
|
// Clusterify - Transform simple list of Cases into list of CaseRange's
|
||||||
|
unsigned SelectionDAGLowering::Clusterify(CaseVector& Cases,
|
||||||
|
const SwitchInst& SI) {
|
||||||
|
unsigned numCmps = 0;
|
||||||
|
|
||||||
|
// Start with "simple" cases
|
||||||
|
for (unsigned i = 1; i < SI.getNumSuccessors(); ++i) {
|
||||||
|
MachineBasicBlock *SMBB = FuncInfo.MBBMap[SI.getSuccessor(i)];
|
||||||
|
Cases.push_back(Case(SI.getSuccessorValue(i),
|
||||||
|
SI.getSuccessorValue(i),
|
||||||
|
SMBB));
|
||||||
|
}
|
||||||
|
sort(Cases.begin(), Cases.end(), CaseCmp());
|
||||||
|
|
||||||
|
// Merge case into clusters
|
||||||
|
if (Cases.size()>=2)
|
||||||
|
for (CaseItr I=Cases.begin(), J=++(Cases.begin()), E=Cases.end(); J!=E; ) {
|
||||||
|
int64_t nextValue = cast<ConstantInt>(J->Low)->getSExtValue();
|
||||||
|
int64_t currentValue = cast<ConstantInt>(I->High)->getSExtValue();
|
||||||
|
MachineBasicBlock* nextBB = J->BB;
|
||||||
|
MachineBasicBlock* currentBB = I->BB;
|
||||||
|
|
||||||
|
// If the two neighboring cases go to the same destination, merge them
|
||||||
|
// into a single case.
|
||||||
|
if ((nextValue-currentValue==1) && (currentBB == nextBB)) {
|
||||||
|
I->High = J->High;
|
||||||
|
J = Cases.erase(J);
|
||||||
|
} else {
|
||||||
|
I = J++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CaseItr I=Cases.begin(), E=Cases.end(); I!=E; ++I, ++numCmps) {
|
||||||
|
if (I->Low != I->High)
|
||||||
|
// A range counts double, since it requires two compares.
|
||||||
|
++numCmps;
|
||||||
|
}
|
||||||
|
|
||||||
|
return numCmps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionDAGLowering::visitSwitch(SwitchInst &SI) {
|
||||||
// Figure out which block is immediately after the current one.
|
// Figure out which block is immediately after the current one.
|
||||||
MachineBasicBlock *NextBlock = 0;
|
MachineBasicBlock *NextBlock = 0;
|
||||||
MachineFunction::iterator BBI = CurMBB;
|
MachineFunction::iterator BBI = CurMBB;
|
||||||
|
|
||||||
MachineBasicBlock *Default = FuncInfo.MBBMap[I.getDefaultDest()];
|
MachineBasicBlock *Default = FuncInfo.MBBMap[SI.getDefaultDest()];
|
||||||
|
|
||||||
// If there is only the default destination, branch to it if it is not the
|
// If there is only the default destination, branch to it if it is not the
|
||||||
// next basic block. Otherwise, just fall through.
|
// next basic block. Otherwise, just fall through.
|
||||||
if (I.getNumOperands() == 2) {
|
if (SI.getNumOperands() == 2) {
|
||||||
// Update machine-CFG edges.
|
// Update machine-CFG edges.
|
||||||
|
|
||||||
// If this is not a fall-through branch, emit the branch.
|
// If this is not a fall-through branch, emit the branch.
|
||||||
@@ -1499,18 +1612,15 @@ void SelectionDAGLowering::visitSwitch(SwitchInst &I) {
|
|||||||
// If there are any non-default case statements, create a vector of Cases
|
// If there are any non-default case statements, create a vector of Cases
|
||||||
// representing each one, and sort the vector so that we can efficiently
|
// representing each one, and sort the vector so that we can efficiently
|
||||||
// create a binary search tree from them.
|
// create a binary search tree from them.
|
||||||
std::vector<Case> Cases;
|
CaseVector Cases;
|
||||||
|
unsigned numCmps = Clusterify(Cases, SI);
|
||||||
|
DOUT << "Clusterify finished. Total clusters: " << Cases.size()
|
||||||
|
<< ". Total compares: " << numCmps << "\n";
|
||||||
|
|
||||||
for (unsigned i = 1; i < I.getNumSuccessors(); ++i) {
|
|
||||||
MachineBasicBlock *SMBB = FuncInfo.MBBMap[I.getSuccessor(i)];
|
|
||||||
Cases.push_back(Case(I.getSuccessorValue(i), SMBB));
|
|
||||||
}
|
|
||||||
std::sort(Cases.begin(), Cases.end(), CaseCmp());
|
|
||||||
|
|
||||||
// Get the Value to be switched on and default basic blocks, which will be
|
// Get the Value to be switched on and default basic blocks, which will be
|
||||||
// inserted into CaseBlock records, representing basic blocks in the binary
|
// inserted into CaseBlock records, representing basic blocks in the binary
|
||||||
// search tree.
|
// search tree.
|
||||||
Value *SV = I.getOperand(0);
|
Value *SV = SI.getOperand(0);
|
||||||
|
|
||||||
// Push the initial CaseRec onto the worklist
|
// Push the initial CaseRec onto the worklist
|
||||||
CaseRecVector WorkList;
|
CaseRecVector WorkList;
|
||||||
|
47
test/CodeGen/Generic/switch-lower-feature-2.ll
Normal file
47
test/CodeGen/Generic/switch-lower-feature-2.ll
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep jb | wc -l | grep 1 &&
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep \$6 | wc -l | grep 2 &&
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep 1024 | wc -l | grep 1 &&
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep 1023 | wc -l | grep 1 &&
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep 119 | wc -l | grep 1 &&
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep JTI | wc -l | grep 2 &&
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep jg | wc -l | grep 1 &&
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep ja | wc -l | grep 1 &&
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep js | wc -l | grep 1
|
||||||
|
|
||||||
|
define i32 @main(i32 %tmp158) {
|
||||||
|
entry:
|
||||||
|
switch i32 %tmp158, label %bb336 [
|
||||||
|
i32 -2147483648, label %bb338
|
||||||
|
i32 -2147483647, label %bb338
|
||||||
|
i32 -2147483646, label %bb338
|
||||||
|
i32 120, label %bb338
|
||||||
|
i32 121, label %bb339
|
||||||
|
i32 122, label %bb340
|
||||||
|
i32 123, label %bb341
|
||||||
|
i32 124, label %bb342
|
||||||
|
i32 125, label %bb343
|
||||||
|
i32 126, label %bb336
|
||||||
|
i32 1024, label %bb338
|
||||||
|
i32 0, label %bb338
|
||||||
|
i32 1, label %bb338
|
||||||
|
i32 2, label %bb338
|
||||||
|
i32 3, label %bb338
|
||||||
|
i32 4, label %bb338
|
||||||
|
i32 5, label %bb338
|
||||||
|
]
|
||||||
|
bb336:
|
||||||
|
ret i32 10
|
||||||
|
bb338:
|
||||||
|
ret i32 11
|
||||||
|
bb339:
|
||||||
|
ret i32 12
|
||||||
|
bb340:
|
||||||
|
ret i32 13
|
||||||
|
bb341:
|
||||||
|
ret i32 14
|
||||||
|
bb342:
|
||||||
|
ret i32 15
|
||||||
|
bb343:
|
||||||
|
ret i32 18
|
||||||
|
|
||||||
|
}
|
@@ -1,10 +1,10 @@
|
|||||||
; RUN: llvm-as < %s | llc -march=x86 -o - | grep \$5 | wc -l | grep 1 &&
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep \$7 | wc -l | grep 1 &&
|
||||||
; RUN: llvm-as < %s | llc -march=x86 -o - | grep \$6 | wc -l | grep 1 &&
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep \$6 | wc -l | grep 1 &&
|
||||||
; RUN: llvm-as < %s | llc -march=x86 -o - | grep 1024 | wc -l | grep 1 &&
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep 1024 | wc -l | grep 1 &&
|
||||||
; RUN: llvm-as < %s | llc -march=x86 -o - | grep 1023 | wc -l | grep 1 &&
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep 1023 | wc -l | grep 1 &&
|
||||||
; RUN: llvm-as < %s | llc -march=x86 -o - | grep 1024 | wc -l | grep 1 &&
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep jg | wc -l | grep 1 &&
|
||||||
; RUN: llvm-as < %s | llc -march=x86 -o - | grep jg | wc -l | grep 2 &&
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep jb | wc -l | grep 1 &&
|
||||||
; RUN: llvm-as < %s | llc -march=x86 -o - | grep ja | wc -l | grep 2 &&
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep jae | wc -l | grep 1 &&
|
||||||
; RUN: llvm-as < %s | llc -march=x86 -o - | grep je | wc -l | grep 1
|
; RUN: llvm-as < %s | llc -march=x86 -o - | grep je | wc -l | grep 1
|
||||||
|
|
||||||
define i32 @main(i32 %tmp158) {
|
define i32 @main(i32 %tmp158) {
|
||||||
|
Reference in New Issue
Block a user