mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-09 21:32:49 +00:00
Pattern match bitfield insert, which helps shift long by immediate, among
other things. llvm-svn: 21127
This commit is contained in:
parent
6c5e4c3bb1
commit
b890f32ac9
@ -489,6 +489,7 @@ public:
|
||||
|
||||
unsigned getGlobalBaseReg();
|
||||
unsigned getConstDouble(double floatVal, unsigned Result);
|
||||
bool SelectBitfieldInsert(SDOperand OR, unsigned Result);
|
||||
unsigned SelectSetCR0(SDOperand CC);
|
||||
unsigned SelectExpr(SDOperand N);
|
||||
unsigned SelectExprFP(SDOperand N, unsigned Result);
|
||||
@ -510,6 +511,61 @@ static unsigned ExactLog2(unsigned Val) {
|
||||
return Count;
|
||||
}
|
||||
|
||||
// IsRunOfOnes - returns true if Val consists of one contiguous run of 1's with
|
||||
// any number of 0's on either side. the 1's are allowed to wrap from LSB to
|
||||
// MSB. so 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs. 0x0F0F0000 is
|
||||
// not, since all 1's are not contiguous.
|
||||
static bool IsRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) {
|
||||
bool isRun = true;
|
||||
MB = 0;
|
||||
ME = 0;
|
||||
|
||||
// look for first set bit
|
||||
int i = 0;
|
||||
for (; i < 32; i++) {
|
||||
if ((Val & (1 << (31 - i))) != 0) {
|
||||
MB = i;
|
||||
ME = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// look for last set bit
|
||||
for (; i < 32; i++) {
|
||||
if ((Val & (1 << (31 - i))) == 0)
|
||||
break;
|
||||
ME = i;
|
||||
}
|
||||
|
||||
// look for next set bit
|
||||
for (; i < 32; i++) {
|
||||
if ((Val & (1 << (31 - i))) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// if we exhausted all the bits, we found a match at this point for 0*1*0*
|
||||
if (i == 32)
|
||||
return true;
|
||||
|
||||
// since we just encountered more 1's, if it doesn't wrap around to the
|
||||
// most significant bit of the word, then we did not find a match to 1*0*1* so
|
||||
// exit.
|
||||
if (MB != 0)
|
||||
return false;
|
||||
|
||||
// look for last set bit
|
||||
for (MB = i; i < 32; i++) {
|
||||
if ((Val & (1 << (31 - i))) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// if we exhausted all the bits, then we found a match for 1*0*1*, otherwise,
|
||||
// the value is not a run of ones.
|
||||
if (i == 32)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getImmediateForOpcode - This method returns a value indicating whether
|
||||
/// the ConstantSDNode N can be used as an immediate to Opcode. The return
|
||||
/// values are either 0, 1 or 2. 0 indicates that either N is not a
|
||||
@ -769,6 +825,78 @@ unsigned ISel::getConstDouble(double doubleVal, unsigned Result=0) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// SelectBitfieldInsert - turn an or of two masked values into
|
||||
/// the rotate left word immediate then mask insert (rlwimi) instruction.
|
||||
/// Returns true on success, false if the caller still needs to select OR.
|
||||
///
|
||||
/// Patterns matched:
|
||||
/// 1. or shl, and 5. or and, and
|
||||
/// 2. or and, shl 6. or shl, shr
|
||||
/// 3. or shr, and 7. or shr, shl
|
||||
/// 4. or and, shr
|
||||
bool ISel::SelectBitfieldInsert(SDOperand OR, unsigned Result) {
|
||||
unsigned TgtMask = 0xFFFFFFFF, InsMask = 0xFFFFFFFF, Amount = 0;
|
||||
unsigned Op0Opc = OR.getOperand(0).getOpcode();
|
||||
unsigned Op1Opc = OR.getOperand(1).getOpcode();
|
||||
|
||||
// Verify that we have the correct opcodes
|
||||
if (ISD::SHL != Op0Opc && ISD::SRL != Op0Opc && ISD::AND != Op0Opc)
|
||||
return false;
|
||||
if (ISD::SHL != Op1Opc && ISD::SRL != Op1Opc && ISD::AND != Op1Opc)
|
||||
return false;
|
||||
|
||||
// Generate Mask value for Target
|
||||
if (ConstantSDNode *CN =
|
||||
dyn_cast<ConstantSDNode>(OR.getOperand(0).getOperand(1).Val)) {
|
||||
switch(Op0Opc) {
|
||||
case ISD::SHL: TgtMask <<= (unsigned)CN->getValue(); break;
|
||||
case ISD::SRL: TgtMask >>= (unsigned)CN->getValue(); break;
|
||||
case ISD::AND: TgtMask &= (unsigned)CN->getValue(); break;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate Mask value for Insert
|
||||
if (ConstantSDNode *CN =
|
||||
dyn_cast<ConstantSDNode>(OR.getOperand(1).getOperand(1).Val)) {
|
||||
switch(Op1Opc) {
|
||||
case ISD::SHL:
|
||||
Amount = CN->getValue();
|
||||
InsMask <<= Amount;
|
||||
break;
|
||||
case ISD::SRL:
|
||||
Amount = CN->getValue();
|
||||
InsMask >>= Amount;
|
||||
Amount = 32-Amount;
|
||||
break;
|
||||
case ISD::AND:
|
||||
InsMask &= (unsigned)CN->getValue();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that the Target mask and Insert mask together form a full word mask
|
||||
// and that the Insert mask is a run of set bits (which implies both are runs
|
||||
// of set bits). Given that, Select the arguments and generate the rlwimi
|
||||
// instruction.
|
||||
unsigned MB, ME;
|
||||
if (((TgtMask ^ InsMask) == 0xFFFFFFFF) && IsRunOfOnes(InsMask, MB, ME)) {
|
||||
unsigned Tmp1, Tmp2;
|
||||
if (Op0Opc == ISD::AND)
|
||||
Tmp1 = SelectExpr(OR.getOperand(0).getOperand(0));
|
||||
else
|
||||
Tmp1 = SelectExpr(OR.getOperand(0));
|
||||
Tmp2 = SelectExpr(OR.getOperand(1).getOperand(0));
|
||||
BuildMI(BB, PPC::RLWIMI, 5, Result).addReg(Tmp1).addReg(Tmp2)
|
||||
.addImm(Amount).addImm(MB).addImm(ME);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned ISel::SelectSetCR0(SDOperand CC) {
|
||||
unsigned Opc, Tmp1, Tmp2;
|
||||
static const unsigned CompareOpcodes[] =
|
||||
@ -1476,31 +1604,40 @@ unsigned ISel::SelectExpr(SDOperand N) {
|
||||
return Result;
|
||||
|
||||
case ISD::AND:
|
||||
Tmp1 = SelectExpr(N.getOperand(0));
|
||||
// FIXME: should add check in getImmediateForOpcode to return a value
|
||||
// indicating the immediate is a run of set bits so we can emit a bitfield
|
||||
// clear with RLWINM instead.
|
||||
switch(getImmediateForOpcode(N.getOperand(1), opcode, Tmp2)) {
|
||||
default: assert(0 && "unhandled result code");
|
||||
case 0: // No immediate
|
||||
Tmp2 = SelectExpr(N.getOperand(1));
|
||||
BuildMI(BB, PPC::AND, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
||||
break;
|
||||
case 1: // Low immediate
|
||||
BuildMI(BB, PPC::ANDIo, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
||||
break;
|
||||
case 2: // Shifted immediate
|
||||
BuildMI(BB, PPC::ANDISo, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
||||
break;
|
||||
}
|
||||
return Result;
|
||||
|
||||
case ISD::OR:
|
||||
if (SelectBitfieldInsert(N, Result))
|
||||
return Result;
|
||||
Tmp1 = SelectExpr(N.getOperand(0));
|
||||
switch(getImmediateForOpcode(N.getOperand(1), opcode, Tmp2)) {
|
||||
default: assert(0 && "unhandled result code");
|
||||
case 0: // No immediate
|
||||
Tmp2 = SelectExpr(N.getOperand(1));
|
||||
switch (opcode) {
|
||||
case ISD::AND: Opc = PPC::AND; break;
|
||||
case ISD::OR: Opc = PPC::OR; break;
|
||||
}
|
||||
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
||||
BuildMI(BB, PPC::OR, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
||||
break;
|
||||
case 1: // Low immediate
|
||||
switch (opcode) {
|
||||
case ISD::AND: Opc = PPC::ANDIo; break;
|
||||
case ISD::OR: Opc = PPC::ORI; break;
|
||||
}
|
||||
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
||||
BuildMI(BB, PPC::ORI, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
||||
break;
|
||||
case 2: // Shifted immediate
|
||||
switch (opcode) {
|
||||
case ISD::AND: Opc = PPC::ANDISo; break;
|
||||
case ISD::OR: Opc = PPC::ORIS; break;
|
||||
}
|
||||
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
||||
BuildMI(BB, PPC::ORIS, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
||||
break;
|
||||
}
|
||||
return Result;
|
||||
|
Loading…
Reference in New Issue
Block a user