mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-14 23:48:49 +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::i8, Expand);
|
||||
|
||||
addLegalFPImmediate(+0.0); // Necessary for FSEL
|
||||
addLegalFPImmediate(-0.0); //
|
||||
|
||||
computeRegisterProperties();
|
||||
}
|
||||
|
||||
@ -478,7 +481,7 @@ public:
|
||||
/// placed in Imm.
|
||||
///
|
||||
static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
|
||||
unsigned& Imm) {
|
||||
unsigned& Imm, bool U = false) {
|
||||
if (N.getOpcode() != ISD::Constant) return 0;
|
||||
|
||||
int v = (int)cast<ConstantSDNode>(N)->getSignExtended();
|
||||
@ -498,9 +501,33 @@ static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
|
||||
case ISD::MUL:
|
||||
if (v <= 32767 && v >= -32768) { Imm = v & 0xFFFF; return 1; }
|
||||
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;
|
||||
}
|
||||
|
||||
/// 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
|
||||
@ -539,15 +566,39 @@ void ISel::SelectBranchCC(SDOperand N)
|
||||
assert(N.getOpcode() == ISD::BRCOND && "Not a BranchCC???");
|
||||
MachineBasicBlock *Dest =
|
||||
cast<BasicBlockSDNode>(N.getOperand(2))->getBasicBlock();
|
||||
unsigned Opc;
|
||||
|
||||
|
||||
unsigned Opc, Tmp1, Tmp2;
|
||||
Select(N.getOperand(0)); //chain
|
||||
SDOperand CC = N.getOperand(1);
|
||||
|
||||
//Give up and do the stupid thing
|
||||
unsigned Tmp1 = SelectExpr(CC);
|
||||
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
||||
BuildMI(BB, PPC::BNE, 2).addReg(PPC::CR0).addMBB(Dest);
|
||||
|
||||
// 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(1).Val);
|
||||
if (SetCC && N.getOperand(1).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(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;
|
||||
}
|
||||
|
||||
@ -565,10 +616,77 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
|
||||
assert(0 && "Node not handled!\n");
|
||||
|
||||
case ISD::SELECT: {
|
||||
Tmp1 = SelectExpr(N.getOperand(0)); //Cond
|
||||
|
||||
// FIXME: generate FSEL here
|
||||
|
||||
// Attempt to generate FSEL. We can do this whenever we have an FP result,
|
||||
// and an FP comparison in the SetCC node.
|
||||
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
|
||||
// value and the MBB to hold the PHI instruction for this SetCC.
|
||||
MachineBasicBlock *thisMBB = BB;
|
||||
@ -582,6 +700,7 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
|
||||
// cmpTY cr0, r1, r2
|
||||
// bCC copy1MBB
|
||||
// fallthrough --> copy0MBB
|
||||
Tmp1 = SelectExpr(N.getOperand(0)); //Cond
|
||||
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
||||
@ -1085,24 +1204,29 @@ unsigned ISel::SelectExpr(SDOperand N) {
|
||||
bool U = false;
|
||||
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?
|
||||
static const unsigned CompareOpcodes[] =
|
||||
{ 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
|
||||
// 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
|
||||
// %TrueValue = li 1
|
||||
// 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);
|
||||
BuildMI(BB, PPC::LI, 1, TrueValue).addSImm(1);
|
||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||
@ -1152,8 +1273,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
|
||||
return 0;
|
||||
|
||||
case ISD::SELECT: {
|
||||
Tmp1 = SelectExpr(N.getOperand(0)); //Cond
|
||||
|
||||
// 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.
|
||||
MachineBasicBlock *thisMBB = BB;
|
||||
@ -1161,17 +1280,44 @@ unsigned ISel::SelectExpr(SDOperand N) {
|
||||
ilist<MachineBasicBlock>::iterator It = BB;
|
||||
++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:
|
||||
// ...
|
||||
// TrueVal = ...
|
||||
// cmpTY cr0, r1, r2
|
||||
// bCC copy1MBB
|
||||
// fallthrough --> copy0MBB
|
||||
BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
|
||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
||||
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();
|
||||
F->getBasicBlockList().insert(It, copy0MBB);
|
||||
F->getBasicBlockList().insert(It, sinkMBB);
|
||||
|
Loading…
Reference in New Issue
Block a user