Index: llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp =================================================================== --- llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -1207,6 +1207,34 @@ return true; } +template <> +bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { + MachineInstr &MI = *MBBI; + const MachineFunction &MF = *MBB.getParent(); + const AVRSubtarget &STI = MF.getSubtarget(); + + assert(MI.getOperand(0).getReg() == AVR::SP && "Unexpected register"); + + MI.setDesc(TII->get(AVR::STDPtrQRr)); + MI.getOperand(0).setReg(STI.getFrameLowering()->hasReservedCallFrame(MF) ? AVR::R29R28 : AVR::R31R30); + + return true; +} + +template <> +bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { + MachineInstr &MI = *MBBI; + const MachineFunction &MF = *MBB.getParent(); + const AVRSubtarget &STI = MF.getSubtarget(); + + assert(MI.getOperand(0).getReg() == AVR::SP && "Unexpected register"); + + MI.setDesc(TII->get(AVR::STDWPtrQRr)); + MI.getOperand(0).setReg(STI.getFrameLowering()->hasReservedCallFrame(MF) ? AVR::R29R28 : AVR::R31R30); + + return true; +} + template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; @@ -2178,6 +2206,8 @@ EXPAND(AVR::STWPtrPiRr); EXPAND(AVR::STWPtrPdRr); EXPAND(AVR::STDWPtrQRr); + EXPAND(AVR::STDSPQRr); + EXPAND(AVR::STDWSPQRr); EXPAND(AVR::INWRdA); EXPAND(AVR::OUTWARr); EXPAND(AVR::PUSHWRr); Index: llvm/lib/Target/AVR/AVRFrameLowering.cpp =================================================================== --- llvm/lib/Target/AVR/AVRFrameLowering.cpp +++ llvm/lib/Target/AVR/AVRFrameLowering.cpp @@ -297,47 +297,13 @@ return true; } -/// Replace pseudo store instructions that pass arguments through the stack with -/// real instructions. -static void fixStackStores(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - const TargetInstrInfo &TII, Register FP) { - // Iterate through the BB until we hit a call instruction or we reach the end. - for (MachineInstr &MI : - llvm::make_early_inc_range(llvm::make_range(MI, MBB.end()))) { - if (MI.isCall()) - break; - - unsigned Opcode = MI.getOpcode(); - - // Only care of pseudo store instructions where SP is the base pointer. - if (Opcode != AVR::STDSPQRr && Opcode != AVR::STDWSPQRr) - continue; - - assert(MI.getOperand(0).getReg() == AVR::SP && - "Invalid register, should be SP!"); - - // Replace this instruction with a regular store. Use Y as the base - // pointer since it is guaranteed to contain a copy of SP. - unsigned STOpc = - (Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr; - - MI.setDesc(TII.get(STOpc)); - MI.getOperand(0).setReg(FP); - } -} - MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const { const AVRSubtarget &STI = MF.getSubtarget(); const AVRInstrInfo &TII = *STI.getInstrInfo(); - // There is nothing to insert when the call frame memory is allocated during - // function entry. Delete the call frame pseudo and replace all pseudo stores - // with real store instructions. if (hasReservedCallFrame(MF)) { - fixStackStores(MBB, MI, TII, AVR::R29R28); return MBB.erase(MI); } @@ -345,57 +311,53 @@ unsigned int Opcode = MI->getOpcode(); int Amount = TII.getFrameSize(*MI); - // ADJCALLSTACKUP and ADJCALLSTACKDOWN are converted to adiw/subi - // instructions to read and write the stack pointer in I/O space. - if (Amount != 0) { - assert(getStackAlign() == Align(1) && "Unsupported stack alignment"); - - if (Opcode == TII.getCallFrameSetupOpcode()) { - // Update the stack pointer. - // In many cases this can be done far more efficiently by pushing the - // relevant values directly to the stack. However, doing that correctly - // (in the right order, possibly skipping some empty space for undef - // values, etc) is tricky and thus left to be optimized in the future. - BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP); - - MachineInstr *New = - BuildMI(MBB, MI, DL, TII.get(AVR::SUBIWRdK), AVR::R31R30) - .addReg(AVR::R31R30, RegState::Kill) - .addImm(Amount); - New->getOperand(3).setIsDead(); - - BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP).addReg(AVR::R31R30); - - // Make sure the remaining stack stores are converted to real store - // instructions. - fixStackStores(MBB, MI, TII, AVR::R31R30); - } else { - assert(Opcode == TII.getCallFrameDestroyOpcode()); - - // Note that small stack changes could be implemented more efficiently - // with a few pop instructions instead of the 8-9 instructions now - // required. - - // Select the best opcode to adjust SP based on the offset size. - unsigned addOpcode; - if (isUInt<6>(Amount)) { - addOpcode = AVR::ADIWRdK; - } else { - addOpcode = AVR::SUBIWRdK; - Amount = -Amount; - } + if (Amount == 0) { + return MBB.erase(MI); + } + + assert(getStackAlign() == Align(1) && "Unsupported stack alignment"); - // Build the instruction sequence. - BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP); + if (Opcode == TII.getCallFrameSetupOpcode()) { + // Update the stack pointer. + // In many cases this can be done far more efficiently by pushing the + // relevant values directly to the stack. However, doing that correctly + // (in the right order, possibly skipping some empty space for undef + // values, etc) is tricky and thus left to be optimized in the future. + BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP); + + MachineInstr *New = + BuildMI(MBB, MI, DL, TII.get(AVR::SUBIWRdK), AVR::R31R30) + .addReg(AVR::R31R30, RegState::Kill) + .addImm(Amount); + New->getOperand(3).setIsDead(); + + BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP).addReg(AVR::R31R30); + } else { + assert(Opcode == TII.getCallFrameDestroyOpcode()); - MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(addOpcode), AVR::R31R30) - .addReg(AVR::R31R30, RegState::Kill) - .addImm(Amount); - New->getOperand(3).setIsDead(); + // Note that small stack changes could be implemented more efficiently + // with a few pop instructions instead of the 8-9 instructions now + // required. - BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP) - .addReg(AVR::R31R30, RegState::Kill); + // Select the best opcode to adjust SP based on the offset size. + unsigned addOpcode; + if (isUInt<6>(Amount)) { + addOpcode = AVR::ADIWRdK; + } else { + addOpcode = AVR::SUBIWRdK; + Amount = -Amount; } + + // Build the instruction sequence. + BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP); + + MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(addOpcode), AVR::R31R30) + .addReg(AVR::R31R30, RegState::Kill) + .addImm(Amount); + New->getOperand(3).setIsDead(); + + BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP) + .addReg(AVR::R31R30, RegState::Kill); } return MBB.erase(MI); @@ -412,6 +374,7 @@ SavedRegs.set(AVR::R28); } } + /// The frame analyzer pass. /// /// Scans the function for allocas and used arguments @@ -422,7 +385,7 @@ bool runOnMachineFunction(MachineFunction &MF) override { const MachineFrameInfo &MFI = MF.getFrameInfo(); - AVRMachineFunctionInfo *FuncInfo = MF.getInfo(); + AVRMachineFunctionInfo *AFI = MF.getInfo(); // If there are no fixed frame indexes during this stage it means there // are allocas present in the function. @@ -433,7 +396,7 @@ for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) { // Variable sized objects have size 0. if (MFI.getObjectSize(i)) { - FuncInfo->setHasAllocas(true); + AFI->setHasAllocas(true); break; } } @@ -462,7 +425,7 @@ } if (MFI.isFixedObjectIndex(MO.getIndex())) { - FuncInfo->setHasStackArgs(true); + AFI->setHasStackArgs(true); return false; } } @@ -477,7 +440,6 @@ char AVRFrameAnalyzer::ID = 0; -/// Creates instance of the frame analyzer pass. FunctionPass *createAVRFrameAnalyzerPass() { return new AVRFrameAnalyzer(); } /// Create the Dynalloca Stack Pointer Save/Restore pass. @@ -528,8 +490,6 @@ char AVRDynAllocaSR::ID = 0; -/// createAVRDynAllocaSRPass - returns an instance of the dynalloca stack -/// pointer save/restore pass. FunctionPass *createAVRDynAllocaSRPass() { return new AVRDynAllocaSR(); } } // end of namespace llvm Index: llvm/lib/Target/AVR/AVRRegisterInfo.cpp =================================================================== --- llvm/lib/Target/AVR/AVRRegisterInfo.cpp +++ llvm/lib/Target/AVR/AVRRegisterInfo.cpp @@ -64,7 +64,7 @@ Reserved.set(AVR::SPH); Reserved.set(AVR::SP); - // We tenatively reserve the frame pointer register r29:r28 because the + // We tentatively reserve the frame pointer register r29:r28 because the // function may require one, but we cannot tell until register allocation // is complete, which can be too late. // Index: llvm/lib/Target/AVR/AVRSubtarget.h =================================================================== --- llvm/lib/Target/AVR/AVRSubtarget.h +++ llvm/lib/Target/AVR/AVRSubtarget.h @@ -87,7 +87,7 @@ /// of an ELF object file. unsigned getELFArch() const { assert(ELFArch != 0 && - "every device must have an associate ELF architecture"); + "every device must have an associated ELF architecture"); return ELFArch; } Index: llvm/test/CodeGen/AVR/pseudo/STDSPQRr.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AVR/pseudo/STDSPQRr.mir @@ -0,0 +1,19 @@ +# RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s + +--- | + target triple = "avr--" + define void @test() { + entry: + ret void + } +... + +--- +name: test +body: | + bb.0.entry: + + ; CHECK: STDPtrQRr $r31r30, 10, $r1, implicit-def $sp + + STDSPQRr $sp, 10, $r1, implicit-def $sp +... Index: llvm/test/CodeGen/AVR/pseudo/STDWSPQRr.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AVR/pseudo/STDWSPQRr.mir @@ -0,0 +1,20 @@ +# RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s + +--- | + target triple = "avr--" + define void @test() { + entry: + ret void + } +... + +--- +name: test +body: | + bb.0.entry: + + ; CHECK: STDPtrQRr $r31r30, 10, $r9 + ; CHECK-NEXT: STDPtrQRr $r31r30, 11, $r10 + + STDWSPQRr $sp, 10, $r10r9, implicit-def $sp +... Index: llvm/test/CodeGen/AVR/regression/D114611.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AVR/regression/D114611.ll @@ -0,0 +1,16 @@ +; RUN: llc < %s -march=avr | FileCheck %s + +declare { } @foo(i128, i128) addrspace(1) + +define i128 @bar(i128 %a, i128 %b) addrspace(1) { + call void asm "nop", "" () +; CHECK: nop +; CHECK-NEXT: ;NO_APP +; CHECK-NEXT: Y+15, r20 +; CHECK-NEXT: Y+16, r21 + %b_neg = icmp slt i128 %b, 0 + %divisor = select i1 %b_neg, i128 0, i128 %b + %result = tail call fastcc addrspace(1) { } @foo(i128 undef, i128 %divisor) + + ret i128 0 +} Index: llvm/utils/UpdateTestChecks/asm.py =================================================================== --- llvm/utils/UpdateTestChecks/asm.py +++ llvm/utils/UpdateTestChecks/asm.py @@ -357,6 +357,7 @@ def get_triple_from_march(march): triples = { 'amdgcn': 'amdgcn', + 'avr': 'avr', 'r600': 'r600', 'mips': 'mips', 'sparc': 'sparc',