diff options
-rw-r--r-- | lib/Target/ARM/ARMBaseInstrInfo.h | 7 | ||||
-rw-r--r-- | lib/Target/ARM/ARMBaseRegisterInfo.cpp | 71 | ||||
-rw-r--r-- | lib/Target/ARM/ARMBaseRegisterInfo.h | 7 | ||||
-rw-r--r-- | lib/Target/ARM/ARMInstrInfo.cpp | 5 | ||||
-rw-r--r-- | lib/Target/ARM/ARMInstrInfo.h | 7 | ||||
-rw-r--r-- | lib/Target/ARM/ARMInstrThumb2.td | 2 | ||||
-rw-r--r-- | lib/Target/ARM/Thumb1InstrInfo.cpp | 6 | ||||
-rw-r--r-- | lib/Target/ARM/Thumb1InstrInfo.h | 7 | ||||
-rw-r--r-- | lib/Target/ARM/Thumb2InstrInfo.cpp | 23 | ||||
-rw-r--r-- | lib/Target/ARM/Thumb2InstrInfo.h | 7 |
10 files changed, 124 insertions, 18 deletions
diff --git a/lib/Target/ARM/ARMBaseInstrInfo.h b/lib/Target/ARM/ARMBaseInstrInfo.h index 63e08da..be952d8 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.h +++ b/lib/Target/ARM/ARMBaseInstrInfo.h @@ -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; diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp index 9e21f3c..ec5e89f 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -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 diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h index 9165bbc..ac5e6b6 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.h +++ b/lib/Target/ARM/ARMBaseRegisterInfo.h @@ -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 diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp index 688dc31..45b77c8 100644 --- a/lib/Target/ARM/ARMInstrInfo.cpp +++ b/lib/Target/ARM/ARMInstrInfo.cpp @@ -30,6 +30,11 @@ ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI) } unsigned ARMInstrInfo:: +unsignedOffsetOpcodeToSigned(unsigned opcode, unsigned *NumBits) const { + return 0; +} + +unsigned ARMInstrInfo:: getUnindexedOpcode(unsigned Opc) const { switch (Opc) { default: break; diff --git a/lib/Target/ARM/ARMInstrInfo.h b/lib/Target/ARM/ARMInstrInfo.h index 3e9f020..8ff0912 100644 --- a/lib/Target/ARM/ARMInstrInfo.h +++ b/lib/Target/ARM/ARMInstrInfo.h @@ -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; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 5361bb5..80b0d68 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -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"; diff --git a/lib/Target/ARM/Thumb1InstrInfo.cpp b/lib/Target/ARM/Thumb1InstrInfo.cpp index ddc6e0d..7bec736 100644 --- a/lib/Target/ARM/Thumb1InstrInfo.cpp +++ b/lib/Target/ARM/Thumb1InstrInfo.cpp @@ -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; diff --git a/lib/Target/ARM/Thumb1InstrInfo.h b/lib/Target/ARM/Thumb1InstrInfo.h index 67b78fb..a1c9f04 100644 --- a/lib/Target/ARM/Thumb1InstrInfo.h +++ b/lib/Target/ARM/Thumb1InstrInfo.h @@ -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; diff --git a/lib/Target/ARM/Thumb2InstrInfo.cpp b/lib/Target/ARM/Thumb2InstrInfo.cpp index 081cf4f..d92856c 100644 --- a/lib/Target/ARM/Thumb2InstrInfo.cpp +++ b/lib/Target/ARM/Thumb2InstrInfo.cpp @@ -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, diff --git a/lib/Target/ARM/Thumb2InstrInfo.h b/lib/Target/ARM/Thumb2InstrInfo.h index ac31707..43ea56e 100644 --- a/lib/Target/ARM/Thumb2InstrInfo.h +++ b/lib/Target/ARM/Thumb2InstrInfo.h @@ -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; |