mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-26 22:26:16 +00:00
fsel generation for f32 and f64 select
generate compare immediate for integer compare with constant fold setcc into branch fold setcc into select Code generation quality for Shootout is now on par with the Simple ISel git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@20968 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
5e99dd9c2b
commit
3e89716ad7
@ -54,6 +54,9 @@ namespace {
|
|||||||
setOperationAction(ISD::SEXTLOAD, MVT::i1, Expand);
|
setOperationAction(ISD::SEXTLOAD, MVT::i1, Expand);
|
||||||
setOperationAction(ISD::SEXTLOAD, MVT::i8, Expand);
|
setOperationAction(ISD::SEXTLOAD, MVT::i8, Expand);
|
||||||
|
|
||||||
|
addLegalFPImmediate(+0.0); // Necessary for FSEL
|
||||||
|
addLegalFPImmediate(-0.0); //
|
||||||
|
|
||||||
computeRegisterProperties();
|
computeRegisterProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,7 +481,7 @@ public:
|
|||||||
/// placed in Imm.
|
/// placed in Imm.
|
||||||
///
|
///
|
||||||
static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
|
static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
|
||||||
unsigned& Imm) {
|
unsigned& Imm, bool U = false) {
|
||||||
if (N.getOpcode() != ISD::Constant) return 0;
|
if (N.getOpcode() != ISD::Constant) return 0;
|
||||||
|
|
||||||
int v = (int)cast<ConstantSDNode>(N)->getSignExtended();
|
int v = (int)cast<ConstantSDNode>(N)->getSignExtended();
|
||||||
@ -498,9 +501,33 @@ static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
|
|||||||
case ISD::MUL:
|
case ISD::MUL:
|
||||||
if (v <= 32767 && v >= -32768) { Imm = v & 0xFFFF; return 1; }
|
if (v <= 32767 && v >= -32768) { Imm = v & 0xFFFF; return 1; }
|
||||||
break;
|
break;
|
||||||
|
case ISD::SETCC:
|
||||||
|
if (U && (v >= 0 && v <= 65535)) { Imm = v & 0xFFFF; return 1; }
|
||||||
|
if (!U && (v <= 32767 && v >= -32768)) { Imm = v & 0xFFFF; return 1; }
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// getBCCForSetCC - Returns the PowerPC condition branch mnemonic corresponding
|
||||||
|
/// to Condition. If the Condition is unordered or unsigned, the bool argument
|
||||||
|
/// U is set to true, otherwise it is set to false.
|
||||||
|
static unsigned getBCCForSetCC(unsigned Condition, bool& U) {
|
||||||
|
U = false;
|
||||||
|
switch (Condition) {
|
||||||
|
default: assert(0 && "Unknown condition!"); abort();
|
||||||
|
case ISD::SETEQ: return PPC::BEQ;
|
||||||
|
case ISD::SETNE: return PPC::BNE;
|
||||||
|
case ISD::SETULT: U = true;
|
||||||
|
case ISD::SETLT: return PPC::BLT;
|
||||||
|
case ISD::SETULE: U = true;
|
||||||
|
case ISD::SETLE: return PPC::BLE;
|
||||||
|
case ISD::SETUGT: U = true;
|
||||||
|
case ISD::SETGT: return PPC::BGT;
|
||||||
|
case ISD::SETUGE: U = true;
|
||||||
|
case ISD::SETGE: return PPC::BGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getGlobalBaseReg - Output the instructions required to put the
|
/// getGlobalBaseReg - Output the instructions required to put the
|
||||||
@ -539,15 +566,39 @@ void ISel::SelectBranchCC(SDOperand N)
|
|||||||
assert(N.getOpcode() == ISD::BRCOND && "Not a BranchCC???");
|
assert(N.getOpcode() == ISD::BRCOND && "Not a BranchCC???");
|
||||||
MachineBasicBlock *Dest =
|
MachineBasicBlock *Dest =
|
||||||
cast<BasicBlockSDNode>(N.getOperand(2))->getBasicBlock();
|
cast<BasicBlockSDNode>(N.getOperand(2))->getBasicBlock();
|
||||||
unsigned Opc;
|
|
||||||
|
unsigned Opc, Tmp1, Tmp2;
|
||||||
Select(N.getOperand(0)); //chain
|
Select(N.getOperand(0)); //chain
|
||||||
SDOperand CC = N.getOperand(1);
|
|
||||||
|
// If the first operand to the select is a SETCC node, then we can fold it
|
||||||
//Give up and do the stupid thing
|
// into the branch that selects which value to return.
|
||||||
unsigned Tmp1 = SelectExpr(CC);
|
SetCCSDNode* SetCC = dyn_cast<SetCCSDNode>(N.getOperand(1).Val);
|
||||||
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
if (SetCC && N.getOperand(1).getOpcode() == ISD::SETCC &&
|
||||||
BuildMI(BB, PPC::BNE, 2).addReg(PPC::CR0).addMBB(Dest);
|
MVT::isInteger(SetCC->getOperand(0).getValueType())) {
|
||||||
|
bool U;
|
||||||
|
Opc = getBCCForSetCC(SetCC->getCondition(), U);
|
||||||
|
Tmp1 = SelectExpr(SetCC->getOperand(0));
|
||||||
|
|
||||||
|
// Pass the optional argument U to canUseAsImmediateForOpcode for SETCC,
|
||||||
|
// so that it knows whether the SETCC immediate range is signed or not.
|
||||||
|
if (1 == canUseAsImmediateForOpcode(SetCC->getOperand(1), ISD::SETCC,
|
||||||
|
Tmp2, U)) {
|
||||||
|
if (U)
|
||||||
|
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(Tmp2);
|
||||||
|
else
|
||||||
|
BuildMI(BB, PPC::CMPWI, 2, PPC::CR0).addReg(Tmp1).addSImm(Tmp2);
|
||||||
|
} else {
|
||||||
|
Tmp2 = SelectExpr(SetCC->getOperand(1));
|
||||||
|
BuildMI(BB, U ? PPC::CMPLW : PPC::CMPW, 2, PPC::CR0).addReg(Tmp1)
|
||||||
|
.addReg(Tmp2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Tmp1 = SelectExpr(N.getOperand(1));
|
||||||
|
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
||||||
|
Opc = PPC::BNE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildMI(BB, Opc, 2).addReg(PPC::CR0).addMBB(Dest);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,10 +616,77 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
|
|||||||
assert(0 && "Node not handled!\n");
|
assert(0 && "Node not handled!\n");
|
||||||
|
|
||||||
case ISD::SELECT: {
|
case ISD::SELECT: {
|
||||||
Tmp1 = SelectExpr(N.getOperand(0)); //Cond
|
// Attempt to generate FSEL. We can do this whenever we have an FP result,
|
||||||
|
// and an FP comparison in the SetCC node.
|
||||||
// FIXME: generate FSEL here
|
SetCCSDNode* SetCC = dyn_cast<SetCCSDNode>(N.getOperand(0).Val);
|
||||||
|
if (SetCC && N.getOperand(0).getOpcode() == ISD::SETCC &&
|
||||||
|
!MVT::isInteger(SetCC->getOperand(0).getValueType()) &&
|
||||||
|
SetCC->getCondition() != ISD::SETEQ &&
|
||||||
|
SetCC->getCondition() != ISD::SETNE) {
|
||||||
|
MVT::ValueType VT = SetCC->getOperand(0).getValueType();
|
||||||
|
Tmp1 = SelectExpr(SetCC->getOperand(0)); // Val to compare against
|
||||||
|
unsigned TV = SelectExpr(N.getOperand(1)); // Use if TRUE
|
||||||
|
unsigned FV = SelectExpr(N.getOperand(2)); // Use if FALSE
|
||||||
|
|
||||||
|
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(SetCC->getOperand(1));
|
||||||
|
if (CN && (CN->isExactlyValue(-0.0) || CN->isExactlyValue(0.0))) {
|
||||||
|
switch(SetCC->getCondition()) {
|
||||||
|
default: assert(0 && "Invalid FSEL condition"); abort();
|
||||||
|
case ISD::SETULT:
|
||||||
|
case ISD::SETLT:
|
||||||
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp1).addReg(FV).addReg(TV);
|
||||||
|
return Result;
|
||||||
|
case ISD::SETUGE:
|
||||||
|
case ISD::SETGE:
|
||||||
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp1).addReg(TV).addReg(FV);
|
||||||
|
return Result;
|
||||||
|
case ISD::SETUGT:
|
||||||
|
case ISD::SETGT: {
|
||||||
|
Tmp2 = MakeReg(VT);
|
||||||
|
BuildMI(BB, PPC::FNEG, 1, Tmp2).addReg(Tmp1);
|
||||||
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp2).addReg(FV).addReg(TV);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
case ISD::SETULE:
|
||||||
|
case ISD::SETLE: {
|
||||||
|
Tmp2 = MakeReg(VT);
|
||||||
|
BuildMI(BB, PPC::FNEG, 1, Tmp2).addReg(Tmp1);
|
||||||
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp2).addReg(TV).addReg(FV);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Opc = (MVT::f64 == VT) ? PPC::FSUB : PPC::FSUBS;
|
||||||
|
Tmp2 = SelectExpr(SetCC->getOperand(1));
|
||||||
|
Tmp3 = MakeReg(VT);
|
||||||
|
switch(SetCC->getCondition()) {
|
||||||
|
default: assert(0 && "Invalid FSEL condition"); abort();
|
||||||
|
case ISD::SETULT:
|
||||||
|
case ISD::SETLT:
|
||||||
|
BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
|
||||||
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(FV).addReg(TV);
|
||||||
|
return Result;
|
||||||
|
case ISD::SETUGE:
|
||||||
|
case ISD::SETGE:
|
||||||
|
BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
|
||||||
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(TV).addReg(FV);
|
||||||
|
return Result;
|
||||||
|
case ISD::SETUGT:
|
||||||
|
case ISD::SETGT:
|
||||||
|
BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
|
||||||
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(FV).addReg(TV);
|
||||||
|
return Result;
|
||||||
|
case ISD::SETULE:
|
||||||
|
case ISD::SETLE:
|
||||||
|
BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
|
||||||
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(TV).addReg(FV);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(0 && "Should never get here");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Create an iterator with which to insert the MBB for copying the false
|
// Create an iterator with which to insert the MBB for copying the false
|
||||||
// value and the MBB to hold the PHI instruction for this SetCC.
|
// value and the MBB to hold the PHI instruction for this SetCC.
|
||||||
MachineBasicBlock *thisMBB = BB;
|
MachineBasicBlock *thisMBB = BB;
|
||||||
@ -582,6 +700,7 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
|
|||||||
// cmpTY cr0, r1, r2
|
// cmpTY cr0, r1, r2
|
||||||
// bCC copy1MBB
|
// bCC copy1MBB
|
||||||
// fallthrough --> copy0MBB
|
// fallthrough --> copy0MBB
|
||||||
|
Tmp1 = SelectExpr(N.getOperand(0)); //Cond
|
||||||
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
||||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||||
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
||||||
@ -1085,24 +1204,29 @@ unsigned ISel::SelectExpr(SDOperand N) {
|
|||||||
bool U = false;
|
bool U = false;
|
||||||
bool IsInteger = MVT::isInteger(SetCC->getOperand(0).getValueType());
|
bool IsInteger = MVT::isInteger(SetCC->getOperand(0).getValueType());
|
||||||
|
|
||||||
switch (SetCC->getCondition()) {
|
|
||||||
default: Node->dump(); assert(0 && "Unknown comparison!");
|
|
||||||
case ISD::SETEQ: Opc = PPC::BEQ; break;
|
|
||||||
case ISD::SETNE: Opc = PPC::BNE; break;
|
|
||||||
case ISD::SETULT: U = true;
|
|
||||||
case ISD::SETLT: Opc = PPC::BLT; break;
|
|
||||||
case ISD::SETULE: U = true;
|
|
||||||
case ISD::SETLE: Opc = PPC::BLE; break;
|
|
||||||
case ISD::SETUGT: U = true;
|
|
||||||
case ISD::SETGT: Opc = PPC::BGT; break;
|
|
||||||
case ISD::SETUGE: U = true;
|
|
||||||
case ISD::SETGE: Opc = PPC::BGE; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Is there a situation in which we would ever need to emit fcmpo?
|
// FIXME: Is there a situation in which we would ever need to emit fcmpo?
|
||||||
static const unsigned CompareOpcodes[] =
|
static const unsigned CompareOpcodes[] =
|
||||||
{ PPC::FCMPU, PPC::FCMPU, PPC::CMPW, PPC::CMPLW };
|
{ PPC::FCMPU, PPC::FCMPU, PPC::CMPW, PPC::CMPLW };
|
||||||
unsigned CompareOpc = CompareOpcodes[2 * IsInteger + U];
|
|
||||||
|
// Set the branch opcode to use below
|
||||||
|
Opc = getBCCForSetCC(SetCC->getCondition(), U);
|
||||||
|
|
||||||
|
// Try and use an integer compare with immediate, if applicable.
|
||||||
|
// Normal setcc uses the sign-extended immediate range, unsigned setcc
|
||||||
|
// uses the zero extended immediate range.
|
||||||
|
if (IsInteger &&
|
||||||
|
1 == canUseAsImmediateForOpcode(N.getOperand(1), opcode, Tmp2, U)) {
|
||||||
|
Tmp1 = SelectExpr(N.getOperand(0));
|
||||||
|
if (U)
|
||||||
|
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(Tmp2);
|
||||||
|
else
|
||||||
|
BuildMI(BB, PPC::CMPWI, 2, PPC::CR0).addReg(Tmp1).addSImm(Tmp2);
|
||||||
|
} else {
|
||||||
|
Tmp1 = SelectExpr(N.getOperand(0));
|
||||||
|
Tmp2 = SelectExpr(N.getOperand(1));
|
||||||
|
unsigned CompareOpc = CompareOpcodes[2 * IsInteger + U];
|
||||||
|
BuildMI(BB, CompareOpc, 2, PPC::CR0).addReg(Tmp1).addReg(Tmp2);
|
||||||
|
}
|
||||||
|
|
||||||
// Create an iterator with which to insert the MBB for copying the false
|
// Create an iterator with which to insert the MBB for copying the false
|
||||||
// value and the MBB to hold the PHI instruction for this SetCC.
|
// value and the MBB to hold the PHI instruction for this SetCC.
|
||||||
@ -1116,9 +1240,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
|
|||||||
// cmpTY cr0, r1, r2
|
// cmpTY cr0, r1, r2
|
||||||
// %TrueValue = li 1
|
// %TrueValue = li 1
|
||||||
// bCC sinkMBB
|
// bCC sinkMBB
|
||||||
Tmp1 = SelectExpr(N.getOperand(0));
|
|
||||||
Tmp2 = SelectExpr(N.getOperand(1));
|
|
||||||
BuildMI(BB, CompareOpc, 2, PPC::CR0).addReg(Tmp1).addReg(Tmp2);
|
|
||||||
unsigned TrueValue = MakeReg(MVT::i32);
|
unsigned TrueValue = MakeReg(MVT::i32);
|
||||||
BuildMI(BB, PPC::LI, 1, TrueValue).addSImm(1);
|
BuildMI(BB, PPC::LI, 1, TrueValue).addSImm(1);
|
||||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||||
@ -1152,8 +1273,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case ISD::SELECT: {
|
case ISD::SELECT: {
|
||||||
Tmp1 = SelectExpr(N.getOperand(0)); //Cond
|
|
||||||
|
|
||||||
// Create an iterator with which to insert the MBB for copying the false
|
// Create an iterator with which to insert the MBB for copying the false
|
||||||
// value and the MBB to hold the PHI instruction for this SetCC.
|
// value and the MBB to hold the PHI instruction for this SetCC.
|
||||||
MachineBasicBlock *thisMBB = BB;
|
MachineBasicBlock *thisMBB = BB;
|
||||||
@ -1161,17 +1280,44 @@ unsigned ISel::SelectExpr(SDOperand N) {
|
|||||||
ilist<MachineBasicBlock>::iterator It = BB;
|
ilist<MachineBasicBlock>::iterator It = BB;
|
||||||
++It;
|
++It;
|
||||||
|
|
||||||
|
// If the first operand to the select is a SETCC node, then we can fold it
|
||||||
|
// into the branch that selects which value to return.
|
||||||
|
SetCCSDNode* SetCC = dyn_cast<SetCCSDNode>(N.getOperand(0).Val);
|
||||||
|
if (SetCC && N.getOperand(0).getOpcode() == ISD::SETCC &&
|
||||||
|
MVT::isInteger(SetCC->getOperand(0).getValueType())) {
|
||||||
|
bool U;
|
||||||
|
Opc = getBCCForSetCC(SetCC->getCondition(), U);
|
||||||
|
Tmp1 = SelectExpr(SetCC->getOperand(0));
|
||||||
|
|
||||||
|
// Pass the optional argument U to canUseAsImmediateForOpcode for SETCC,
|
||||||
|
// so that it knows whether the SETCC immediate range is signed or not.
|
||||||
|
if (1 == canUseAsImmediateForOpcode(SetCC->getOperand(1), ISD::SETCC,
|
||||||
|
Tmp2, U)) {
|
||||||
|
if (U)
|
||||||
|
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(Tmp2);
|
||||||
|
else
|
||||||
|
BuildMI(BB, PPC::CMPWI, 2, PPC::CR0).addReg(Tmp1).addSImm(Tmp2);
|
||||||
|
} else {
|
||||||
|
Tmp2 = SelectExpr(SetCC->getOperand(1));
|
||||||
|
BuildMI(BB, U ? PPC::CMPLW : PPC::CMPW, 2, PPC::CR0).addReg(Tmp1)
|
||||||
|
.addReg(Tmp2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Tmp1 = SelectExpr(N.getOperand(0)); //Cond
|
||||||
|
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
||||||
|
Opc = PPC::BNE;
|
||||||
|
}
|
||||||
|
|
||||||
// thisMBB:
|
// thisMBB:
|
||||||
// ...
|
// ...
|
||||||
// TrueVal = ...
|
// TrueVal = ...
|
||||||
// cmpTY cr0, r1, r2
|
// cmpTY cr0, r1, r2
|
||||||
// bCC copy1MBB
|
// bCC copy1MBB
|
||||||
// fallthrough --> copy0MBB
|
// fallthrough --> copy0MBB
|
||||||
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
|
||||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||||
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
||||||
unsigned TrueValue = SelectExpr(N.getOperand(1)); //Use if TRUE
|
unsigned TrueValue = SelectExpr(N.getOperand(1)); //Use if TRUE
|
||||||
BuildMI(BB, PPC::BNE, 2).addReg(PPC::CR0).addMBB(sinkMBB);
|
BuildMI(BB, Opc, 2).addReg(PPC::CR0).addMBB(sinkMBB);
|
||||||
MachineFunction *F = BB->getParent();
|
MachineFunction *F = BB->getParent();
|
||||||
F->getBasicBlockList().insert(It, copy0MBB);
|
F->getBasicBlockList().insert(It, copy0MBB);
|
||||||
F->getBasicBlockList().insert(It, sinkMBB);
|
F->getBasicBlockList().insert(It, sinkMBB);
|
||||||
|
Loading…
Reference in New Issue
Block a user