[llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp
Nate Begeman
natebegeman at mac.com
Wed Apr 6 16:51:51 PDT 2005
Changes in directory llvm/lib/Target/PowerPC:
PPC32ISelPattern.cpp updated: 1.49 -> 1.50
---
Log message:
Pattern match bitfield insert, which helps shift long by immediate, among
other things.
---
Diffs of the changes: (+152 -15)
PPC32ISelPattern.cpp | 167 ++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 152 insertions(+), 15 deletions(-)
Index: llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp
diff -u llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp:1.49 llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp:1.50
--- llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp:1.49 Wed Apr 6 01:44:57 2005
+++ llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp Wed Apr 6 18:51:40 2005
@@ -489,6 +489,7 @@
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 @@
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 @@
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 @@
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;
More information about the llvm-commits
mailing list