diff options
Diffstat (limited to 'llvm/lib/Target/AVR/AVRRegisterInfo.cpp')
| -rw-r--r-- | llvm/lib/Target/AVR/AVRRegisterInfo.cpp | 54 |
1 files changed, 37 insertions, 17 deletions
diff --git a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp index 87e6558c12c2..d345c50488a2 100644 --- a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp +++ b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp @@ -140,7 +140,7 @@ static void foldFrameOffset(MachineBasicBlock::iterator &II, int &Offset, MI.eraseFromParent(); } -void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, +bool AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected SPAdj value"); @@ -166,18 +166,28 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, // instruction. We have only two-address instructions, thus we need to // expand it into move + add. if (MI.getOpcode() == AVR::FRMIDX) { - MI.setDesc(TII.get(AVR::MOVWRdRr)); - MI.getOperand(FIOperandNum).ChangeToRegister(AVR::R29R28, false); - MI.removeOperand(2); + Register DstReg = MI.getOperand(0).getReg(); + assert(DstReg != AVR::R29R28 && "Dest reg cannot be the frame pointer"); + + // Copy the frame pointer. + if (STI.hasMOVW()) { + BuildMI(MBB, MI, dl, TII.get(AVR::MOVWRdRr), DstReg) + .addReg(AVR::R29R28); + } else { + Register DstLoReg, DstHiReg; + splitReg(DstReg, DstLoReg, DstHiReg); + BuildMI(MBB, MI, dl, TII.get(AVR::MOVRdRr), DstLoReg) + .addReg(AVR::R28); + BuildMI(MBB, MI, dl, TII.get(AVR::MOVRdRr), DstHiReg) + .addReg(AVR::R29); + } assert(Offset > 0 && "Invalid offset"); // We need to materialize the offset via an add instruction. unsigned Opcode; - Register DstReg = MI.getOperand(0).getReg(); - assert(DstReg != AVR::R29R28 && "Dest reg cannot be the frame pointer"); - II++; // Skip over the FRMIDX (and now MOVW) instruction. + II++; // Skip over the FRMIDX instruction. // Generally, to load a frame address two add instructions are emitted that // could get folded into a single one: @@ -195,11 +205,11 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, case AVR::R25R24: case AVR::R27R26: case AVR::R31R30: { - if (isUInt<6>(Offset)) { + if (isUInt<6>(Offset) && STI.hasADDSUBIW()) { Opcode = AVR::ADIWRdK; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; } default: { // This opcode will get expanded into a pair of subi/sbci. @@ -214,19 +224,28 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, .addImm(Offset); New->getOperand(3).setIsDead(); - return; + MI.eraseFromParent(); // remove FRMIDX + + return false; } + // On most AVRs, we can use an offset up to 62 for load/store with + // displacement (63 for byte values, 62 for word values). However, the + // "reduced tiny" cores don't support load/store with displacement. So for + // them, we force an offset of 0 meaning that any positive offset will require + // adjusting the frame pointer. + int MaxOffset = STI.hasTinyEncoding() ? 0 : 62; + // If the offset is too big we have to adjust and restore the frame pointer // to materialize a valid load/store with displacement. //: TODO: consider using only one adiw/sbiw chain for more than one frame //: index - if (Offset > 62) { + if (Offset > MaxOffset) { unsigned AddOpc = AVR::ADIWRdK, SubOpc = AVR::SBIWRdK; - int AddOffset = Offset - 63 + 1; + int AddOffset = Offset - MaxOffset; // For huge offsets where adiw/sbiw cannot be used use a pair of subi/sbci. - if ((Offset - 63 + 1) > 63) { + if ((Offset - MaxOffset) > 63 || !STI.hasADDSUBIW()) { AddOpc = AVR::SUBIWRdK; SubOpc = AVR::SUBIWRdK; AddOffset = -AddOffset; @@ -236,7 +255,7 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, // a compare and branch, invalidating the contents of SREG set by the // compare instruction because of the add/sub pairs. Conservatively save and // restore SREG before and after each add/sub pair. - BuildMI(MBB, II, dl, TII.get(AVR::INRdA), AVR::R0) + BuildMI(MBB, II, dl, TII.get(AVR::INRdA), STI.getTmpRegister()) .addImm(STI.getIORegSREG()); MachineInstr *New = BuildMI(MBB, II, dl, TII.get(AddOpc), AVR::R29R28) @@ -247,20 +266,21 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, // Restore SREG. BuildMI(MBB, std::next(II), dl, TII.get(AVR::OUTARr)) .addImm(STI.getIORegSREG()) - .addReg(AVR::R0, RegState::Kill); + .addReg(STI.getTmpRegister(), RegState::Kill); // No need to set SREG as dead here otherwise if the next instruction is a // cond branch it will be using a dead register. BuildMI(MBB, std::next(II), dl, TII.get(SubOpc), AVR::R29R28) .addReg(AVR::R29R28, RegState::Kill) - .addImm(Offset - 63 + 1); + .addImm(Offset - MaxOffset); - Offset = 62; + Offset = MaxOffset; } MI.getOperand(FIOperandNum).ChangeToRegister(AVR::R29R28, false); assert(isUInt<6>(Offset) && "Offset is out of range"); MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + return false; } Register AVRRegisterInfo::getFrameRegister(const MachineFunction &MF) const { |
