Fix frame index elimination to correctly handle thumb-2 addressing modes that don...
authorDavid Goodwin <david_goodwin@apple.com>
Thu, 23 Jul 2009 17:06:46 +0000 (17:06 +0000)
committerDavid Goodwin <david_goodwin@apple.com>
Thu, 23 Jul 2009 17:06:46 +0000 (17:06 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76883 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMBaseInstrInfo.h
lib/Target/ARM/ARMBaseRegisterInfo.cpp
lib/Target/ARM/ARMBaseRegisterInfo.h
lib/Target/ARM/ARMInstrInfo.cpp
lib/Target/ARM/ARMInstrInfo.h
lib/Target/ARM/ARMInstrThumb2.td
lib/Target/ARM/Thumb1InstrInfo.cpp
lib/Target/ARM/Thumb1InstrInfo.h
lib/Target/ARM/Thumb2InstrInfo.cpp
lib/Target/ARM/Thumb2InstrInfo.h

index 63e08da9b6efcef2f230fcdbf988403f523d401e..be952d8b8c43ed86b77fffd26da25598f5120fac 100644 (file)
@@ -215,6 +215,13 @@ public:
   // Return the opcode that implements 'Op', or 0 if no opcode
   virtual unsigned getOpcode(ARMII::Op Op) const =0;
 
+  // If 'opcode' is an instruction with an unsigned offset that also
+  // has a version with a signed offset, return the opcode for the
+  // version with the signed offset. In 'NumBits' return the number of
+  // bits for the signed offset.
+  virtual unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
+                                                unsigned *NumBits) const = 0;
+
   // Return true if the block does not fall through.
   virtual bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const =0;
 
index 9e21f3cf7192dd3da3718d557660c14d2ccb001a..ec5e89f045b0a5ebc9dcede5d30030ad2acf476e 100644 (file)
@@ -142,6 +142,11 @@ getOpcode(int Op) const {
   return TII.getOpcode((ARMII::Op)Op);
 }
 
+unsigned ARMBaseRegisterInfo::
+unsignedOffsetOpcodeToSigned(unsigned opcode, unsigned *NumBits) const {
+  return TII.unsignedOffsetOpcodeToSigned(opcode, NumBits);
+}
+
 const unsigned*
 ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
   static const unsigned CalleeSavedRegs[] = {
@@ -1109,6 +1114,8 @@ eliminateFrameIndex(MachineBasicBlock::iterator II,
     int InstrOffs = 0;
     unsigned NumBits = 0;
     unsigned Scale = 1;
+    bool encodedOffset = true;
+    bool HandlesNeg = true;
     switch (AddrMode) {
     case ARMII::AddrMode2: {
       ImmIdx = i+2;
@@ -1139,17 +1146,21 @@ eliminateFrameIndex(MachineBasicBlock::iterator II,
       ImmIdx = i+1;
       InstrOffs = MI.getOperand(ImmIdx).getImm();
       NumBits = 12;
+      encodedOffset = false;
+      HandlesNeg = false;
       break;
     }
     case ARMII::AddrModeT2_i8: {
       ImmIdx = i+1;
       InstrOffs = MI.getOperand(ImmIdx).getImm();
       NumBits = 8;
+      encodedOffset = false;
       break;
     }
     case ARMII::AddrModeT2_so: {
       ImmIdx = i+2;
       InstrOffs = MI.getOperand(ImmIdx).getImm();
+      encodedOffset = false;
       break;
     }
     default:
@@ -1160,29 +1171,55 @@ eliminateFrameIndex(MachineBasicBlock::iterator II,
     Offset += InstrOffs * Scale;
     assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
     if (Offset < 0) {
+      // For addrmodes that cannot handle negative offsets, convert to
+      // an opcode that can, or set NumBits == 0 to avoid folding
+      // address computation
+      if (!HandlesNeg) {
+        unsigned usop = unsignedOffsetOpcodeToSigned(Opcode, &NumBits);
+        if (usop != 0) {
+          MI.setDesc(TII.get(usop));
+          HandlesNeg = true;
+          Opcode = usop;
+        }
+        else {
+          NumBits = 0;
+        }
+      }
+
       Offset = -Offset;
       isSub = true;
     }
 
-    // Common case: small offset, fits into instruction.
-    MachineOperand &ImmOp = MI.getOperand(ImmIdx);
-    int ImmedOffset = Offset / Scale;
-    unsigned Mask = (1 << NumBits) - 1;
-    if ((unsigned)Offset <= Mask * Scale) {
-      // Replace the FrameIndex with sp
-      MI.getOperand(i).ChangeToRegister(FrameReg, false);
-      if (isSub)
-        ImmedOffset |= 1 << NumBits;
+    // Attempt to fold address comp. if opcode has offset bits
+    if (NumBits > 0) {
+      // Common case: small offset, fits into instruction.
+      MachineOperand &ImmOp = MI.getOperand(ImmIdx);
+      int ImmedOffset = Offset / Scale;
+      unsigned Mask = (1 << NumBits) - 1;
+      if ((unsigned)Offset <= Mask * Scale) {
+        // Replace the FrameIndex with sp
+        MI.getOperand(i).ChangeToRegister(FrameReg, false);
+        if (isSub) {
+          if (encodedOffset)
+            ImmedOffset |= 1 << NumBits;
+          else
+            ImmedOffset = -ImmedOffset;
+        }
+        ImmOp.ChangeToImmediate(ImmedOffset);
+        return;
+      }
+      
+      // Otherwise, it didn't fit. Pull in what we can to simplify the immed.
+      ImmedOffset = ImmedOffset & Mask;
+      if (isSub) {
+          if (encodedOffset)
+            ImmedOffset |= 1 << NumBits;
+          else
+            ImmedOffset = -ImmedOffset;
+      }
       ImmOp.ChangeToImmediate(ImmedOffset);
-      return;
+      Offset &= ~(Mask*Scale);
     }
-
-    // Otherwise, it didn't fit. Pull in what we can to simplify the immed.
-    ImmedOffset = ImmedOffset & Mask;
-    if (isSub)
-      ImmedOffset |= 1 << NumBits;
-    ImmOp.ChangeToImmediate(ImmedOffset);
-    Offset &= ~(Mask*Scale);
   }
 
   // If we get here, the immediate doesn't fit into the instruction.  We folded
index 9165bbc883e97bc119b4a45ad3a6475350a3cfae..ac5e6b67338ce56f9c0a46da48b0e93be1f3f241 100644 (file)
@@ -59,6 +59,13 @@ protected:
   // Return the opcode that implements 'Op', or 0 if no opcode
   unsigned getOpcode(int Op) const;
 
+  // If 'opcode' is an instruction with an unsigned offset that also
+  // has a version with a signed offset, return the opcode for the
+  // version with the signed offset. In 'NumBits' return the number of
+  // bits for the signed offset.
+  unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
+                                        unsigned *NumBits) const;
+
 public:
   /// getRegisterNumbering - Given the enum value for some register, e.g.
   /// ARM::LR, return the number that it corresponds to (e.g. 14). It
index 688dc31c1393047791085bc6fbccb78be3154f15..45b77c83bee113b880c72a4a8bdd12686792054b 100644 (file)
@@ -29,6 +29,11 @@ ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI)
   : ARMBaseInstrInfo(STI), RI(*this, STI) {
 }
 
+unsigned ARMInstrInfo::
+unsignedOffsetOpcodeToSigned(unsigned opcode, unsigned *NumBits) const {
+  return 0;
+}
+
 unsigned ARMInstrInfo::
 getUnindexedOpcode(unsigned Opc) const {
   switch (Opc) {
index 3e9f0204fe01d83301aefe974995dd6abb5e32cf..8ff09123da96bf6fa910e8a398be96087a6af38f 100644 (file)
@@ -35,6 +35,13 @@ public:
   // Return the opcode that implements 'Op', or 0 if no opcode
   unsigned getOpcode(ARMII::Op Op) const;
 
+  // If 'opcode' is an instruction with an unsigned offset that also
+  // has a version with a signed offset, return the opcode for the
+  // version with the signed offset. In 'NumBits' return the number of
+  // bits for the signed offset.
+  unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
+                                        unsigned *NumBits) const;
+
   // Return true if the block does not fall through.
   bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const;
 
index 5361bb59cfefa320783320e6a212bf1d2649d593..80b0d68aa29cf28c0502ff2dbc11f28d0eca2c33 100644 (file)
@@ -109,7 +109,7 @@ def t2addrmode_imm12 : Operand<i32>,
   let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
 }
 
-// t2addrmode_imm8  := reg - imm8
+// t2addrmode_imm8  := reg +/- imm8
 def t2addrmode_imm8 : Operand<i32>,
                       ComplexPattern<i32, 2, "SelectT2AddrModeImm8", []> {
   let PrintMethod = "printT2AddrModeImm8Operand";
index ddc6e0d154af633cf0355d66bea053d518f4e275..7bec736503e580e9db680de432190149889eb664 100644 (file)
@@ -30,6 +30,12 @@ unsigned Thumb1InstrInfo::getUnindexedOpcode(unsigned Opc) const {
   return 0;
 }
 
+unsigned
+Thumb1InstrInfo::unsignedOffsetOpcodeToSigned(unsigned opcode,
+                                              unsigned *NumBits) const {
+  return 0;
+}
+
 unsigned Thumb1InstrInfo::getOpcode(ARMII::Op Op) const {
   switch (Op) {
   case ARMII::ADDri: return ARM::tADDi8;
index 67b78fbedfa1bb3df3890250204860cfd9425ccb..a1c9f04ef74c91ce3707a951438ff97a42bce699 100644 (file)
@@ -34,6 +34,13 @@ public:
   // Return the opcode that implements 'Op', or 0 if no opcode
   unsigned getOpcode(ARMII::Op Op) const;
 
+  // If 'opcode' is an instruction with an unsigned offset that also
+  // has a version with a signed offset, return the opcode for the
+  // version with the signed offset. In 'NumBits' return the number of
+  // bits for the signed offset.
+  unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
+                                        unsigned *NumBits) const;
+
   // Return true if the block does not fall through.
   bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const;
 
index 081cf4f550341d09fbf166c773d30ab30a921625..d92856cf0c313e4f5d36e4423f91bd9ad67944ab 100644 (file)
@@ -88,6 +88,29 @@ Thumb2InstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
   return false;
 }
 
+unsigned
+Thumb2InstrInfo::unsignedOffsetOpcodeToSigned(unsigned opcode,
+                                              unsigned *NumBits) const
+{
+  if (NumBits != NULL)
+    *NumBits = 8;
+
+  switch (opcode) {
+  case ARM::t2LDRi12:   return ARM::t2LDRi8;
+  case ARM::t2LDRHi12:  return ARM::t2LDRHi8;
+  case ARM::t2LDRBi12:  return ARM::t2LDRBi8;
+  case ARM::t2LDRSHi12: return ARM::t2LDRSHi8;
+  case ARM::t2LDRSBi12: return ARM::t2LDRSBi8;
+  case ARM::t2STRi12:   return ARM::t2STRi8;
+  case ARM::t2STRBi12:  return ARM::t2STRBi8;
+  case ARM::t2STRHi12:  return ARM::t2STRHi8;
+  default:
+    break;
+  }
+
+  return 0;
+}
+
 bool
 Thumb2InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
                               MachineBasicBlock::iterator I,
index ac31707ab781b89d2f96f59aaa68ba08b7112e74..43ea56e7925b8cbd11e5fa9a132526e6fef3c58a 100644 (file)
@@ -34,6 +34,13 @@ public:
   // Return the opcode that implements 'Op', or 0 if no opcode
   unsigned getOpcode(ARMII::Op Op) const;
 
+  // If 'opcode' is an instruction with an unsigned offset that also
+  // has a version with a signed offset, return the opcode for the
+  // version with the signed offset. In 'NumBits' return the number of
+  // bits for the signed offset.
+  unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
+                                        unsigned *NumBits) const;
+
   // Return true if the block does not fall through.
   bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const;