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:
Nate Begeman 2005-03-31 23:55:40 +00:00
parent 5e99dd9c2b
commit 3e89716ad7

View File

@ -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);