[llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp

Nate Begeman natebegeman at mac.com
Sun Oct 24 03:33:40 PDT 2004



Changes in directory llvm/lib/Target/PowerPC:

PPC32ISelSimple.cpp updated: 1.97 -> 1.98
---
Log message:

Implement more complete and correct codegen for bitfield inserts, as tested
by the recently committed rlwimi.ll test file.  Also commit initial code
for bitfield extract, although it is turned off until fully debugged.


---
Diffs of the changes:  (+236 -89)

Index: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp
diff -u llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.97 llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.98
--- llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.97	Fri Oct 22 19:50:23 2004
+++ llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp	Sun Oct 24 05:33:30 2004
@@ -32,8 +32,6 @@
 using namespace llvm;
 
 namespace {
-  Statistic<> Bitfields("ppc-codegen", "Number of bitfield inserts");
-
   /// TypeClass - Used by the PowerPC backend to group LLVM types by their basic
   /// PPC Representation.
   ///
@@ -99,19 +97,18 @@
       FoldedGEP(unsigned b, unsigned i, ConstantSInt *o) : 
         base(b), index(i), offset(o) {}
     };
-
-    /// RlwimiRec - This struct is for recording the necessary information to
-    /// emit a PowerPC rlwimi instruction for a bitfield insert rather than
-    /// a sequence of shifts and ands, followed by an or.
-    struct RlwimiRec {
-      unsigned Shift;
-      unsigned MB, ME;
-      Value *Op0, *Op1;
-      RlwimiRec() : Shift(0), MB(0), ME(0), Op0(0), Op1(0) {}
-      RlwimiRec(unsigned s, unsigned b, unsigned e, Value *y, Value *z) :
-        Shift(s), MB(b), ME(e), Op0(y), Op1(z) {}
+    
+    /// RlwimiRec - This struct is for recording the arguments to a PowerPC 
+    /// rlwimi instruction to be output for a particular Instruction::Or when
+    /// we recognize the pattern for rlwimi, starting with a shift or and.
+    struct RlwimiRec { 
+      Value *Target, *Insert;
+      unsigned Shift, MB, ME;
+      RlwimiRec() : Target(0), Insert(0), Shift(0), MB(0), ME(0) {}
+      RlwimiRec(Value *tgt, Value *ins, unsigned s, unsigned b, unsigned e) :
+        Target(tgt), Insert(ins), Shift(s), MB(b), ME(e) {}
     };
-
+    
     // External functions used in the Module
     Function *fmodfFn, *fmodFn, *__cmpdi2Fn, *__moddi3Fn, *__divdi3Fn, 
       *__umoddi3Fn,  *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__fixunssfdiFn,
@@ -132,7 +129,11 @@
     
     // RlwimiMap  - Mapping between BinaryOperand (Or) instructions and info
     // needed to properly emit a rlwimi instruction in its place.
-    std::map<BinaryOperator *, RlwimiRec> RlwimiMap;
+    std::map<Instruction *, RlwimiRec> InsertMap;
+
+    // A rlwimi instruction is the combination of at least three instructions.
+    // Keep a vector of instructions to skip around so that we do not try to
+    // emit instructions that were folded into a rlwimi.
     std::vector<Instruction *> SkipList;
 
     // A Reg to hold the base address used for global loads and stores, and a
@@ -215,8 +216,8 @@
       GEPMap.clear();
       RegMap.clear();
       MBBMap.clear();
+      InsertMap.clear();
       AllocaMap.clear();
-      RlwimiMap.clear();
       SkipList.clear();
       F = 0;
       // We always build a machine code representation for the function
@@ -339,10 +340,18 @@
 
 
     /// emitBitfieldInsert - return true if we were able to fold the sequence of
-    /// instructions starting with AndI into a bitfield insert.
-    bool PPC32ISel::emitBitfieldInsert(BinaryOperator *AndI, 
-                                       unsigned ShlAmount,
-                                       Value *InsertOp);
+    /// instructions into a bitfield insert (rlwimi).
+    bool emitBitfieldInsert(MachineBasicBlock *MBB, 
+                            MachineBasicBlock::iterator IP,
+                            User *OpUser, unsigned DestReg);
+                                  
+    /// emitBitfieldExtract - return true if we were able to fold the sequence
+    /// of instructions into a bitfield extract (rlwinm).
+    bool emitBitfieldExtract(MachineBasicBlock *MBB, 
+                             MachineBasicBlock::iterator IP,
+                             BinaryOperator *AndI, Value *Op,
+                             unsigned Amount, bool isLeftShift, 
+                             unsigned DestReg);
 
     /// emitBinaryConstOperation - Used by several functions to emit simple
     /// arithmetic and logical operations with constants on a register rather
@@ -359,8 +368,7 @@
     ///
     void emitSimpleBinaryOperation(MachineBasicBlock *BB,
                                    MachineBasicBlock::iterator IP,
-                                   BinaryOperator *BO,
-                                   Value *Op0, Value *Op1,
+                                   BinaryOperator *BO, Value *Op0, Value *Op1,
                                    unsigned OperatorClass, unsigned TargetReg);
 
     /// emitBinaryFPOperation - This method handles emission of floating point
@@ -2021,23 +2029,23 @@
 /// Xor.
 ///
 void PPC32ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) {
+  if (std::find(SkipList.begin(), SkipList.end(), &B) != SkipList.end())
+    return;
+
   unsigned DestReg = getReg(B);
   MachineBasicBlock::iterator MI = BB->end();
-  Value *Op0 = B.getOperand(0), *Op1 = B.getOperand(1);
-  unsigned Class = getClassB(B.getType());
-
-  if (std::find(SkipList.begin(), SkipList.end(), &B) != SkipList.end())
+  RlwimiRec RR = InsertMap[&B];
+  if (RR.Target != 0) {
+    unsigned TargetReg = getReg(RR.Target, BB, MI);
+    unsigned InsertReg = getReg(RR.Insert, BB, MI);
+    BuildMI(*BB, MI, PPC::RLWIMI, 5, DestReg).addReg(TargetReg)
+      .addReg(InsertReg).addImm(RR.Shift).addImm(RR.MB).addImm(RR.ME);
     return;
-  
-  RlwimiRec r = RlwimiMap[&B];
-  if (0 != r.Op0) {
-    unsigned Op0Reg = getReg(r.Op0, BB, MI);
-    unsigned Op1Reg = getReg(r.Op1, BB, MI);
-    BuildMI(*BB, MI, PPC::RLWIMI, 5, DestReg).addReg(Op1Reg)
-            .addReg(Op0Reg).addImm(r.Shift).addImm(r.MB).addImm(r.ME);
-  } else {
-    emitSimpleBinaryOperation(BB, MI, &B, Op0, Op1, OperatorClass, DestReg);
   }
+    
+  unsigned Class = getClassB(B.getType());
+  Value *Op0 = B.getOperand(0), *Op1 = B.getOperand(1);
+  emitSimpleBinaryOperation(BB, MI, &B, Op0, Op1, OperatorClass, DestReg);
 }
 
 /// emitBinaryFPOperation - This method handles emission of floating point
@@ -2134,52 +2142,189 @@
   return false;
 }
 
-/// emitBitfieldInsert - return true if we were able to fold the sequence of
-/// instructions starting with AndI into a bitfield insert.
-bool PPC32ISel::emitBitfieldInsert(BinaryOperator *AndI, unsigned ShlAmount, 
-                                   Value *InsertOp) {
-  if (AndI->hasOneUse()) {
-    ConstantInt *CI_1 = dyn_cast<ConstantInt>(AndI->getOperand(1));
-    BinaryOperator *OrI = dyn_cast<BinaryOperator>(*(AndI->use_begin()));
-    if (CI_1 && OrI && OrI->getOpcode() == Instruction::Or) {
-      Value *Op0 = OrI->getOperand(0);
-      Value *Op1 = OrI->getOperand(1);
-      BinaryOperator *AndI_2 = 0;
-      // Whichever operand our initial And instruction is to the Or instruction,
-      // Look at the other operand to determine if it is also an And instruction
-      if (AndI == Op0) { 
-        AndI_2 = dyn_cast<BinaryOperator>(Op1);
-      }  else if (AndI == Op1) {
-        AndI_2 = dyn_cast<BinaryOperator>(Op0);
-        std::swap(Op0, Op1);
-      } else {
-        assert(0 && "And instruction not used in Or!");
-      }
-      // Verify that the second operand to the Or is an And with one use
-      if (AndI_2 && AndI_2->hasOneUse() 
-                 && AndI_2->getOpcode() == Instruction::And) {
-        // Check to see if this And instruction also has a constant int operand.
-        // If it does, then we can replace this sequence of instructions with an
-        // insert if the sum of the two ConstantInts has all bits set, and
-        // one is a run of ones (which implies the other is as well).
-        ConstantInt *CI_2 = dyn_cast<ConstantInt>(AndI_2->getOperand(1));
-        if (CI_2) { 
-          unsigned Imm1 = CI_1->getRawValue();
-          unsigned Imm2 = CI_2->getRawValue();
-          if (Imm1 + Imm2 == 0xFFFFFFFF) {
-            unsigned MB, ME;
-            if (isRunOfOnes(Imm1, MB, ME)) {
-              ++Bitfields;
-              SkipList.push_back(AndI);
-              SkipList.push_back(AndI_2);
-              RlwimiMap[OrI] = RlwimiRec(ShlAmount, MB, ME, 
-                InsertOp, AndI_2->getOperand(0));
-              return true;
+/// isInsertAndHalf - Helper function for emitBitfieldInsert.  Returns true if
+/// OpUser has one use, is used by an or instruction, and is itself an and whose
+/// second operand is a constant int.  Optionally, set OrI to the Or instruction
+/// that is the sole user of OpUser, and Op1User to the other operand of the Or
+/// instruction.
+static bool isInsertAndHalf(User *OpUser, Instruction **Op1User, 
+                            Instruction **OrI, unsigned &Mask) {
+  // If this instruction doesn't have one use, then return false.
+  if (!OpUser->hasOneUse())
+    return false;
+  
+  Mask = 0xFFFFFFFF;
+  if (BinaryOperator *BO = dyn_cast<BinaryOperator>(OpUser))
+    if (BO->getOpcode() == Instruction::And) {
+      Value *AndUse = *(OpUser->use_begin());
+      if (BinaryOperator *Or = dyn_cast<BinaryOperator>(AndUse)) {
+        if (Or->getOpcode() == Instruction::Or) {
+          if (ConstantInt *CI = dyn_cast<ConstantInt>(OpUser->getOperand(1))) {
+            if (OrI) *OrI = Or;
+            if (Op1User) {
+              if (Or->getOperand(0) == OpUser)
+                *Op1User = dyn_cast<Instruction>(Or->getOperand(1));
+              else
+                *Op1User = dyn_cast<Instruction>(Or->getOperand(0));
             }
+            Mask &= CI->getRawValue();
+            return true;
           }
         }
       }
     }
+  return false;
+}
+
+/// isInsertShiftHalf - Helper function for emitBitfieldInsert.  Returns true if
+/// OpUser has one use, is used by an or instruction, and is itself a shift
+/// instruction that is either used directly by the or instruction, or is used
+/// by an and instruction whose second operand is a constant int, and which is
+/// used by the or instruction.
+static bool isInsertShiftHalf(User *OpUser, Instruction **Op1User, 
+                              Instruction **OrI, Instruction **OptAndI, 
+                              unsigned &Shift, unsigned &Mask) {
+  // If this instruction doesn't have one use, then return false.
+  if (!OpUser->hasOneUse())
+    return false;
+  
+  Mask = 0xFFFFFFFF;
+  if (ShiftInst *SI = dyn_cast<ShiftInst>(OpUser)) {
+    if (ConstantInt *CI = dyn_cast<ConstantInt>(SI->getOperand(1))) {
+      Shift = CI->getRawValue();
+      if (SI->getOpcode() == Instruction::Shl)
+        Mask <<= Shift;
+      else if (!SI->getOperand(0)->getType()->isSigned()) {
+        Mask >>= Shift;
+        Shift = 32 - Shift;
+      }
+
+      // Now check to see if the shift instruction is used by an or.
+      Value *ShiftUse = *(OpUser->use_begin());
+      Value *OptAndICopy = 0;
+      if (BinaryOperator *BO = dyn_cast<BinaryOperator>(ShiftUse)) {
+        if (BO->getOpcode() == Instruction::And && BO->hasOneUse()) {
+          if (ConstantInt *ACI = dyn_cast<ConstantInt>(BO->getOperand(1))) {
+            if (OptAndI) *OptAndI = BO;
+            OptAndICopy = BO;
+            Mask &= ACI->getRawValue();
+            BO = dyn_cast<BinaryOperator>(*(BO->use_begin()));
+          }
+        }
+        if (BO && BO->getOpcode() == Instruction::Or) {
+          if (OrI) *OrI = BO;
+          if (Op1User) {
+            if (BO->getOperand(0) == OpUser || BO->getOperand(0) == OptAndICopy)
+              *Op1User = dyn_cast<Instruction>(BO->getOperand(1));
+            else
+              *Op1User = dyn_cast<Instruction>(BO->getOperand(0));
+          }
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+/// emitBitfieldInsert - turn a shift used only by an and with immediate into 
+/// the rotate left word immediate then mask insert (rlwimi) instruction.
+/// Patterns matched:
+/// 1. or shl, and   5. or (shl-and), and   9. or and, and
+/// 2. or and, shl   6. or and, (shl-and)
+/// 3. or shr, and   7. or (shr-and), and
+/// 4. or and, shr   8. or and, (shr-and)
+bool PPC32ISel::emitBitfieldInsert(MachineBasicBlock *MBB, 
+                                   MachineBasicBlock::iterator IP,
+                                   User *OpUser, unsigned DestReg) {
+  // Instructions to skip if we match any of the patterns
+  Instruction *Op0User, *Op1User = 0, *OptAndI = 0, *OrI = 0;
+  unsigned TgtMask, InsMask, Amount = 0;
+  bool matched = false;
+
+  // We require OpUser to be an instruction to continue
+  Op0User = dyn_cast<Instruction>(OpUser);
+  if (0 == Op0User)
+    return false;
+
+  // Look for cases 2, 4, 6, 8, and 9
+  if (isInsertAndHalf(Op0User, &Op1User, &OrI, TgtMask))
+    if (Op1User)
+      if (isInsertAndHalf(Op1User, 0, 0, InsMask))
+        matched = true;
+      else if (isInsertShiftHalf(Op1User, 0, 0, &OptAndI, Amount, InsMask))
+        matched = true;
+  
+  // Look for cases 1, 3, 5, and 7.  Force the shift argument to be the one
+  // inserted into the target, since rlwimi can only rotate the value inserted,
+  // not the value being inserted into.
+  if (matched == false)
+    if (isInsertShiftHalf(Op0User, &Op1User, &OrI, &OptAndI, Amount, InsMask))
+      if (Op1User && isInsertAndHalf(Op1User, 0, 0, TgtMask)) {
+        std::swap(Op0User, Op1User);
+        matched = true;
+      }
+  
+  // We didn't succeed in matching one of the patterns, so return false
+  if (matched == false)
+    return false;
+  
+  // If the masks xor to -1, and the insert mask is a run of ones, then we have
+  // succeeded in matching one of the cases for generating rlwimi.  Update the
+  // skip lists and users of the Instruction::Or.
+  unsigned MB, ME;
+  if (((TgtMask ^ InsMask) == 0xFFFFFFFF) && isRunOfOnes(InsMask, MB, ME)) {
+    SkipList.push_back(Op0User);
+    SkipList.push_back(Op1User);
+    SkipList.push_back(OptAndI);
+    InsertMap[OrI] = RlwimiRec(Op0User->getOperand(0), Op1User->getOperand(0), 
+                               Amount, MB, ME);
+    return true;
+  }
+  return false;
+}
+
+/// emitBitfieldExtract - turn a shift used only by an and with immediate into the
+/// rotate left word immediate then and with mask (rlwinm) instruction.
+bool PPC32ISel::emitBitfieldExtract(MachineBasicBlock *MBB, 
+                                    MachineBasicBlock::iterator IP,
+                                    BinaryOperator *BO, Value *Op,
+                                    unsigned Amount, bool isLeftShift,
+                                    unsigned DestReg) {
+  return false;
+  if (BO && BO->getOpcode() == Instruction::And) {
+    // Since the powerpc shift instructions are really rotate left, subtract 32
+    // to simulate a right shift.
+    unsigned Rotate = (isLeftShift) ? Amount : 32 - Amount;
+
+    if (ConstantInt *CI = dyn_cast<ConstantInt>(BO->getOperand(1))) {
+      unsigned Imm = CI->getRawValue(), MB, ME;
+      // In the case of a left shift or unsigned right shift, be sure to clear
+      // any bits that would have been zeroes shifted in from the left or right.
+      // Usually instcombine will do this for us, but there's no guarantee the 
+      // optimization has been performed already.
+      // 
+      // Also, take this opportunity to check for the algebraic right shift case
+      // where the mask would overlap sign bits shifted in from the left.  We do
+      // not want to perform the optimization in that case since we could clear
+      // bits that should be set. Think of int (x >> 17) & 0x0000FFFF;
+      unsigned mask = 0xFFFFFFFF;
+      if (isLeftShift)
+        Imm &= (mask << Amount);
+      else if (!isLeftShift && !Op->getType()->isSigned())
+        Imm &= (mask >> Amount);
+      else if (((mask << Rotate) & Imm) != 0)
+        return false;
+        
+      if (isRunOfOnes(Imm, MB, ME)) {
+        unsigned SrcReg = getReg(Op, MBB, IP);
+        BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg)
+          .addImm(Rotate).addImm(MB).addImm(ME);
+        BO->replaceAllUsesWith(Op->use_back());
+        SkipList.push_back(BO);
+        return true;
+      }
+    }
   }
   return false;
 }
@@ -2322,9 +2467,9 @@
   // Special case: op Reg, <const int>
   if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1))
     if (Class != cLong) {
-      if (OperatorClass == 2 && emitBitfieldInsert(BO, 0, Op0))
+      if (emitBitfieldInsert(MBB, IP, BO, DestReg))
         return;
-
+      
       unsigned Op0r = getReg(Op0, MBB, IP);
       emitBinaryConstOperation(MBB, IP, Op0r, CI, OperatorClass, DestReg);
       return;
@@ -2619,6 +2764,9 @@
 /// because the shift amount has to be in CL, not just any old register.
 ///
 void PPC32ISel::visitShiftInst(ShiftInst &I) {
+  if (std::find(SkipList.begin(), SkipList.end(), &I) != SkipList.end())
+    return;
+
   MachineBasicBlock::iterator IP = BB->end();
   emitShiftOperation(BB, IP, I.getOperand(0), I.getOperand(1),
                      I.getOpcode() == Instruction::Shl, I.getType(),
@@ -2776,17 +2924,16 @@
     assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?");
     unsigned Amount = CUI->getValue();
     
-    // If this is a left shift with one use, and that use is an And instruction,
-    // then attempt to emit a bitfield insert.
-    if (isLeftShift) {
-      User *U = Op->use_back();
-      if (U->hasOneUse()) {
-        Value *V = *(U->use_begin());
-        BinaryOperator *BO = dyn_cast<BinaryOperator>(V);
-        if (BO && BO->getOpcode() == Instruction::And) {
-          if (emitBitfieldInsert(BO, Amount, Op))
-            return;
-        }
+    // If this is a shift with one use, and that use is an And instruction,
+    // then attempt to emit a bitfield operation.
+    User *U = Op->use_back();
+    if (U->hasOneUse()) {
+      BinaryOperator *BO = dyn_cast<BinaryOperator>(*(U->use_begin()));
+      if (BO) {
+        if (emitBitfieldInsert(MBB, IP, U, DestReg))
+          return;
+        if (emitBitfieldExtract(MBB, IP, BO, Op, Amount, isLeftShift, DestReg))
+          return;
       }
     }
     






More information about the llvm-commits mailing list