diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp --- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -645,30 +645,42 @@ template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; - Register DstLoReg, DstHiReg; Register DstReg = MI.getOperand(0).getReg(); Register SrcReg = MI.getOperand(1).getReg(); + bool DstIsKill = MI.getOperand(0).isKill(); bool SrcIsKill = MI.getOperand(1).isKill(); - unsigned OpLo = AVR::LDRdPtr; - unsigned OpHi = AVR::LDDRdPtrQ; - TRI->splitReg(DstReg, DstLoReg, DstHiReg); + const AVRSubtarget &STI = MBB.getParent()->getSubtarget(); // DstReg has an earlyclobber so the register allocator will allocate them in // separate registers. assert(DstReg != SrcReg && "Dst and Src registers are the same!"); - // Load low byte. - buildMI(MBB, MBBI, OpLo) - .addReg(DstLoReg, RegState::Define) - .addReg(SrcReg) - .setMemRefs(MI.memoperands()); - - // Load high byte. - buildMI(MBB, MBBI, OpHi) - .addReg(DstHiReg, RegState::Define) - .addReg(SrcReg, getKillRegState(SrcIsKill)) - .addImm(1) - .setMemRefs(MI.memoperands()); + if (STI.hasTinyEncoding()) { + // Handle this case in the expansion of LDDWRdPtrQ because it is very + // similar. + buildMI(MBB, MBBI, AVR::LDDWRdPtrQ) + .addDef(DstReg, getKillRegState(DstIsKill)) + .addReg(SrcReg, getKillRegState(SrcIsKill)) + .addImm(0) + .setMemRefs(MI.memoperands()); + + } else { + Register DstLoReg, DstHiReg; + TRI->splitReg(DstReg, DstLoReg, DstHiReg); + + // Load low byte. + buildMI(MBB, MBBI, AVR::LDRdPtr) + .addReg(DstLoReg, RegState::Define) + .addReg(SrcReg) + .setMemRefs(MI.memoperands()); + + // Load high byte. + buildMI(MBB, MBBI, AVR::LDDRdPtrQ) + .addReg(DstHiReg, RegState::Define) + .addReg(SrcReg, getKillRegState(SrcIsKill)) + .addImm(1) + .setMemRefs(MI.memoperands()); + } MI.eraseFromParent(); return true; @@ -743,14 +755,12 @@ template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; - Register DstLoReg, DstHiReg; Register DstReg = MI.getOperand(0).getReg(); Register SrcReg = MI.getOperand(1).getReg(); unsigned Imm = MI.getOperand(2).getImm(); + bool DstIsKill = MI.getOperand(0).isKill(); bool SrcIsKill = MI.getOperand(1).isKill(); - unsigned OpLo = AVR::LDDRdPtrQ; - unsigned OpHi = AVR::LDDRdPtrQ; - TRI->splitReg(DstReg, DstLoReg, DstHiReg); + const AVRSubtarget &STI = MBB.getParent()->getSubtarget(); // Since we add 1 to the Imm value for the high byte below, and 63 is the // highest Imm value allowed for the instruction, 62 is the limit here. @@ -760,19 +770,51 @@ // separate registers. assert(DstReg != SrcReg && "Dst and Src registers are the same!"); - // Load low byte. - buildMI(MBB, MBBI, OpLo) - .addReg(DstLoReg, RegState::Define) - .addReg(SrcReg) - .addImm(Imm) - .setMemRefs(MI.memoperands()); + if (STI.hasTinyEncoding()) { + // Reduced tiny cores don't support load/store with displacement. However, + // they do support postincrement. So we'll simply adjust the pointer before + // and after and use postincrement to load multiple registers. + + // Add offset. The offset can be 0 when expanding this instruction from the + // more specific LDWRdPtr instruction. + if (Imm != 0) { + buildMI(MBB, MBBI, AVR::SUBIWRdK, SrcReg) + .addReg(SrcReg) + .addImm(0x10000 - Imm); + } - // Load high byte. - buildMI(MBB, MBBI, OpHi) - .addReg(DstHiReg, RegState::Define) - .addReg(SrcReg, getKillRegState(SrcIsKill)) - .addImm(Imm + 1) - .setMemRefs(MI.memoperands()); + // Do a word load with postincrement. This will be lowered to a two byte + // load. + buildMI(MBB, MBBI, AVR::LDWRdPtrPi) + .addDef(DstReg, getKillRegState(DstIsKill)) + .addReg(SrcReg, getKillRegState(SrcIsKill)) + .addImm(0) + .setMemRefs(MI.memoperands()); + + // If the pointer is used after the store instruction, subtract the new + // offset (with 2 added after the postincrement instructions) so it is the + // same as before. + if (!SrcIsKill) { + buildMI(MBB, MBBI, AVR::SUBIWRdK, SrcReg).addReg(SrcReg).addImm(Imm + 2); + } + } else { + Register DstLoReg, DstHiReg; + TRI->splitReg(DstReg, DstLoReg, DstHiReg); + + // Load low byte. + buildMI(MBB, MBBI, AVR::LDDRdPtrQ) + .addReg(DstLoReg, RegState::Define) + .addReg(SrcReg) + .addImm(Imm) + .setMemRefs(MI.memoperands()); + + // Load high byte. + buildMI(MBB, MBBI, AVR::LDDRdPtrQ) + .addReg(DstHiReg, RegState::Define) + .addReg(SrcReg, getKillRegState(SrcIsKill)) + .addImm(Imm + 1) + .setMemRefs(MI.memoperands()); + } MI.eraseFromParent(); return true; @@ -1097,27 +1139,39 @@ template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; - Register SrcLoReg, SrcHiReg; Register DstReg = MI.getOperand(0).getReg(); Register SrcReg = MI.getOperand(1).getReg(); + bool DstIsKill = MI.getOperand(0).isKill(); bool DstIsUndef = MI.getOperand(0).isUndef(); bool SrcIsKill = MI.getOperand(1).isKill(); - unsigned OpLo = AVR::STPtrRr; - unsigned OpHi = AVR::STDPtrQRr; - TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); + const AVRSubtarget &STI = MBB.getParent()->getSubtarget(); //: TODO: need to reverse this order like inw and stsw? - auto MIBLO = buildMI(MBB, MBBI, OpLo) - .addReg(DstReg, getUndefRegState(DstIsUndef)) - .addReg(SrcLoReg, getKillRegState(SrcIsKill)); - auto MIBHI = buildMI(MBB, MBBI, OpHi) - .addReg(DstReg, getUndefRegState(DstIsUndef)) - .addImm(1) - .addReg(SrcHiReg, getKillRegState(SrcIsKill)); - - MIBLO.setMemRefs(MI.memoperands()); - MIBHI.setMemRefs(MI.memoperands()); + if (STI.hasTinyEncoding()) { + // Handle this case in the expansion of STDWPtrQRr because it is very + // similar. + buildMI(MBB, MBBI, AVR::STDWPtrQRr) + .addReg(DstReg, + getKillRegState(DstIsKill) | getUndefRegState(DstIsUndef)) + .addImm(0) + .addReg(SrcReg, getKillRegState(SrcIsKill)) + .setMemRefs(MI.memoperands()); + + } else { + Register SrcLoReg, SrcHiReg; + TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); + buildMI(MBB, MBBI, AVR::STPtrRr) + .addReg(DstReg, getUndefRegState(DstIsUndef)) + .addReg(SrcLoReg, getKillRegState(SrcIsKill)) + .setMemRefs(MI.memoperands()); + + buildMI(MBB, MBBI, AVR::STDPtrQRr) + .addReg(DstReg, getUndefRegState(DstIsUndef)) + .addImm(1) + .addReg(SrcHiReg, getKillRegState(SrcIsKill)) + .setMemRefs(MI.memoperands()); + } MI.eraseFromParent(); return true; @@ -1196,32 +1250,59 @@ template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; - Register SrcLoReg, SrcHiReg; Register DstReg = MI.getOperand(0).getReg(); Register SrcReg = MI.getOperand(2).getReg(); unsigned Imm = MI.getOperand(1).getImm(); bool DstIsKill = MI.getOperand(0).isKill(); bool SrcIsKill = MI.getOperand(2).isKill(); - unsigned OpLo = AVR::STDPtrQRr; - unsigned OpHi = AVR::STDPtrQRr; - TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); + const AVRSubtarget &STI = MBB.getParent()->getSubtarget(); // Since we add 1 to the Imm value for the high byte below, and 63 is the // highest Imm value allowed for the instruction, 62 is the limit here. assert(Imm <= 62 && "Offset is out of range"); - auto MIBLO = buildMI(MBB, MBBI, OpLo) - .addReg(DstReg) - .addImm(Imm) - .addReg(SrcLoReg, getKillRegState(SrcIsKill)); - - auto MIBHI = buildMI(MBB, MBBI, OpHi) - .addReg(DstReg, getKillRegState(DstIsKill)) - .addImm(Imm + 1) - .addReg(SrcHiReg, getKillRegState(SrcIsKill)); + if (STI.hasTinyEncoding()) { + // Reduced tiny cores don't support load/store with displacement. However, + // they do support postincrement. So we'll simply adjust the pointer before + // and after and use postincrement to store multiple registers. + + // Add offset. The offset can be 0 when expanding this instruction from the + // more specific STWPtrRr instruction. + if (Imm != 0) { + buildMI(MBB, MBBI, AVR::SUBIWRdK, DstReg) + .addReg(DstReg) + .addImm(0x10000 - Imm); + } - MIBLO.setMemRefs(MI.memoperands()); - MIBHI.setMemRefs(MI.memoperands()); + // Do the store. This is a word store, that will be expanded further. + buildMI(MBB, MBBI, AVR::STWPtrPiRr, DstReg) + .addReg(DstReg, getKillRegState(DstIsKill)) + .addReg(SrcReg, getKillRegState(SrcIsKill)) + .addImm(0) + .setMemRefs(MI.memoperands()); + + // If the pointer is used after the store instruction, subtract the new + // offset (with 2 added after the postincrement instructions) so it is the + // same as before. + if (!DstIsKill) { + buildMI(MBB, MBBI, AVR::SUBIWRdK, DstReg).addReg(DstReg).addImm(Imm + 2); + } + } else { + Register SrcLoReg, SrcHiReg; + TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); + + buildMI(MBB, MBBI, AVR::STDPtrQRr) + .addReg(DstReg) + .addImm(Imm) + .addReg(SrcLoReg, getKillRegState(SrcIsKill)) + .setMemRefs(MI.memoperands()); + + buildMI(MBB, MBBI, AVR::STDPtrQRr) + .addReg(DstReg, getKillRegState(DstIsKill)) + .addImm(Imm + 1) + .addReg(SrcHiReg, getKillRegState(SrcIsKill)) + .setMemRefs(MI.memoperands()); + } MI.eraseFromParent(); return true; diff --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp --- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp +++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp @@ -115,7 +115,8 @@ } // Reserve the necessary frame memory by doing FP -= . - unsigned Opcode = (isUInt<6>(FrameSize)) ? AVR::SBIWRdK : AVR::SUBIWRdK; + unsigned Opcode = (isUInt<6>(FrameSize) && STI.hasADDSUBIW()) ? AVR::SBIWRdK + : AVR::SUBIWRdK; MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28) .addReg(AVR::R29R28, RegState::Kill) @@ -192,7 +193,7 @@ unsigned Opcode; // Select the optimal opcode depending on how big it is. - if (isUInt<6>(FrameSize)) { + if (isUInt<6>(FrameSize) && STI.hasADDSUBIW()) { Opcode = AVR::ADIWRdK; } else { Opcode = AVR::SUBIWRdK; @@ -376,7 +377,7 @@ // Select the best opcode to adjust SP based on the offset size. unsigned addOpcode; - if (isUInt<6>(Amount)) { + if (isUInt<6>(Amount) && STI.hasADDSUBIW()) { addOpcode = AVR::ADIWRdK; } else { addOpcode = AVR::SUBIWRdK; diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td --- a/llvm/lib/Target/AVR/AVRInstrInfo.td +++ b/llvm/lib/Target/AVR/AVRInstrInfo.td @@ -311,6 +311,9 @@ def HasTinyEncoding : Predicate<"Subtarget->hasTinyEncoding()">, AssemblerPredicate<(all_of FeatureTinyEncoding)>; +def HasNonTinyEncoding : Predicate<"!Subtarget->hasTinyEncoding()">, + AssemblerPredicate<(all_of (not FeatureTinyEncoding))>; + // AVR specific condition code. These correspond to AVR_*_COND in // AVRInstrInfo.td. They must be kept in synch. def AVR_COND_EQ : PatLeaf<(i8 0)>; @@ -1283,7 +1286,7 @@ "lds\t$rd, $k", [(set i8 : $rd, (load imm : $k))]>, - Requires<[HasSRAM]>; + Requires<[HasSRAM, HasNonTinyEncoding]>; // LDSW Rd+1:Rd, K+1:K // @@ -1297,7 +1300,7 @@ "ldsw\t$dst, $src", [(set i16 : $dst, (load imm : $src))]>, - Requires<[HasSRAM]>; + Requires<[HasSRAM, HasNonTinyEncoding]>; } // Indirect loads. @@ -1315,8 +1318,12 @@ // LDW Rd+1:Rd, P // // Expands to: - // ld Rd, P - // ldd Rd+1, P+1 + // ld Rd, P + // ldd Rd+1, P+1 + // On reduced tiny cores, this instruction expands to: + // ld Rd, P+ + // ld Rd+1, P+ + // subiw P, 2 let Constraints = "@earlyclobber $reg" in def LDWRdPtr : Pseudo<(outs DREGS : $reg), @@ -1386,13 +1393,18 @@ "ldd\t$reg, $memri", [(set i8 : $reg, (load addr : $memri))]>, - Requires<[HasSRAM]>; + Requires<[HasSRAM, HasNonTinyEncoding]>; // LDDW Rd+1:Rd, P+q // // Expands to: - // ldd Rd, P+q - // ldd Rd+1, P+q+1 + // ldd Rd, P+q + // ldd Rd+1, P+q+1 + // On reduced tiny cores, this instruction expands to: + // subiw P, -q + // ld Rd, P+ + // ld Rd+1, P+ + // subiw P, q+2 let Constraints = "@earlyclobber $dst" in def LDDWRdPtrQ : Pseudo<(outs DREGS : $dst), @@ -1503,7 +1515,7 @@ "sts\t$k, $rd", [(store i8 : $rd, imm : $k)]>, - Requires<[HasSRAM]>; + Requires<[HasSRAM, HasNonTinyEncoding]>; // STSW K+1:K, Rr+1:Rr // @@ -1517,7 +1529,7 @@ "stsw\t$dst, $src", [(store i16 : $src, imm : $dst)]>, - Requires<[HasSRAM]>; + Requires<[HasSRAM, HasNonTinyEncoding]>; // Indirect stores. // ST P, Rr @@ -1535,8 +1547,12 @@ // Stores the value of Rr into the location addressed by pointer P. // // Expands to: -// st P, Rr -// std P+1, Rr+1 +// st P, Rr +// std P+1, Rr+1 +// On reduced tiny cores, this instruction expands to: +// st P+, Rr +// st P+, Rr+1 +// subiw P, q+2 def STWPtrRr : Pseudo<(outs), (ins PTRDISPREGS : $ptrreg, DREGS @@ -1635,15 +1651,20 @@ "std\t$memri, $reg", [(store i8 : $reg, addr : $memri)]>, - Requires<[HasSRAM]>; + Requires<[HasSRAM, HasNonTinyEncoding]>; // STDW P+q, Rr+1:Rr // Stores the value of Rr into the location addressed by pointer P with a // displacement of q. Does not modify P. // // Expands to: -// std P+q, Rr -// std P+q+1, Rr+1 +// std P+q, Rr +// std P+q+1, Rr+1 +// On reduced tiny cores, this instruction expands to: +// subiw P, -q +// st P+, Rr +// st P+, Rr+1 +// subiw P, q+2 def STDWPtrQRr : Pseudo<(outs), (ins memri : $memri, DREGS @@ -2423,7 +2444,8 @@ : $src2), (SBIWRdK i16 : $src1, (imm0_63_neg - : $src2))>; + : $src2))>, + Requires<[HasADDSUBIW]>; def : Pat<(add i16 : $src1, imm : $src2), @@ -2483,26 +2505,18 @@ (SUBIWRdK i16 : $src, tglobaladdr : $src2)>; -def : Pat<(i8(load(AVRWrapper tglobaladdr - : $dst))), - (LDSRdK tglobaladdr - : $dst)>; -def : Pat<(i16(load(AVRWrapper tglobaladdr - : $dst))), - (LDSWRdK tglobaladdr - : $dst)>; -def : Pat<(store i8 - : $src, (i16(AVRWrapper tglobaladdr - : $dst))), - (STSKRr tglobaladdr - : $dst, i8 - : $src)>; -def : Pat<(store i16 - : $src, (i16(AVRWrapper tglobaladdr - : $dst))), - (STSWKRr tglobaladdr - : $dst, i16 - : $src)>; +def : Pat<(i8(load(AVRWrapper tglobaladdr:$dst))), + (LDSRdK tglobaladdr:$dst)>, + Requires<[HasSRAM, HasNonTinyEncoding]>; +def : Pat<(i16(load(AVRWrapper tglobaladdr:$dst))), + (LDSWRdK tglobaladdr:$dst)>, + Requires<[HasSRAM, HasNonTinyEncoding]>; +def : Pat<(store i8:$src, (i16(AVRWrapper tglobaladdr:$dst))), + (STSKRr tglobaladdr:$dst, i8:$src)>, + Requires<[HasSRAM, HasNonTinyEncoding]>; +def : Pat<(store i16:$src, (i16(AVRWrapper tglobaladdr:$dst))), + (STSWKRr tglobaladdr:$dst, i16:$src)>, + Requires<[HasSRAM, HasNonTinyEncoding]>; // BlockAddress def : Pat<(i16(AVRWrapper tblockaddress diff --git a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp --- a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp +++ b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp @@ -137,6 +137,7 @@ const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo(); const MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetFrameLowering *TFI = TM.getSubtargetImpl()->getFrameLowering(); + const AVRSubtarget &STI = MF.getSubtarget(); int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); int Offset = MFI.getObjectOffset(FrameIndex); @@ -178,7 +179,7 @@ case AVR::R25R24: case AVR::R27R26: case AVR::R31R30: { - if (isUInt<6>(Offset)) { + if (isUInt<6>(Offset) && STI.hasADDSUBIW()) { Opcode = AVR::ADIWRdK; break; } @@ -200,16 +201,26 @@ return; } + // 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 = 62; + if (STI.hasTinyEncoding()) { + MaxOffset = 0; + } + // 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; @@ -235,9 +246,9 @@ // 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); diff --git a/llvm/test/CodeGen/AVR/directmem.ll b/llvm/test/CodeGen/AVR/directmem.ll --- a/llvm/test/CodeGen/AVR/directmem.ll +++ b/llvm/test/CodeGen/AVR/directmem.ll @@ -1,4 +1,5 @@ ; RUN: llc -mattr=sram,addsubiw < %s -march=avr | FileCheck %s +; RUN: llc -mattr=sram,avrtiny < %s -march=avr | FileCheck %s --check-prefix=CHECK-TINY @char = common global i8 0 @char.array = common global [3 x i8] zeroinitializer @@ -20,6 +21,11 @@ ; CHECK-LABEL: global8_store: ; CHECK: ldi [[REG:r[0-9]+]], 6 ; CHECK: sts char, [[REG]] +; CHECK-TINY-LABEL: global8_store: +; CHECK-TINY: ldi [[REG1:r[0-9]+]], 6 +; CHECK-TINY: ldi [[REG2:r[0-9]+]], lo8(char) +; CHECK-TINY: ldi [[REG3:r[0-9]+]], hi8(char) +; CHECK-TINY: st [[REG4:[X-Z]]], [[REG1]] store i8 6, i8* @char ret void } @@ -27,6 +33,10 @@ define i8 @global8_load() { ; CHECK-LABEL: global8_load: ; CHECK: lds r24, char +; CHECK-TINY-LABEL: global8_load: +; CHECK-TINY: ldi [[REG1:r[0-9]+]], lo8(char) +; CHECK-TINY: ldi [[REG2:r[0-9]+]], hi8(char) +; CHECK-TINY: ld [[REG3:r[0-9]+]], [[REG4:[X-Z]]] %result = load i8, i8* @char ret i8 %result } @@ -39,6 +49,7 @@ ; CHECK: ldi [[REG2:r[0-9]+]], 2 ; CHECK: sts char.array+1, [[REG2]] ; CHECK: sts char.array, [[REG3]] +; CHECK-TINY-LABEL: array8_store: store i8 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 0) store i8 2, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 1) store i8 3, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 2) diff --git a/llvm/test/CodeGen/AVR/pseudo/LDDWRdPtrQ.mir b/llvm/test/CodeGen/AVR/pseudo/LDDWRdPtrQ.mir --- a/llvm/test/CodeGen/AVR/pseudo/LDDWRdPtrQ.mir +++ b/llvm/test/CodeGen/AVR/pseudo/LDDWRdPtrQ.mir @@ -1,4 +1,5 @@ -# RUN: llc -O0 %s -o - -march=avr | FileCheck %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mattr=avrtiny %s -o - | FileCheck %s --check-prefix=CHECK-TINY # This test checks the expansion of the 16-bit 'LDDWRdPtrQ' pseudo instruction. @@ -19,8 +20,15 @@ ; CHECK-LABEL: test_lddwrdptrq - ; CHECK: ldd r24, Z+10 - ; CHECK-NEXT: ldd r25, Z+11 + ; CHECK: $r24 = LDDRdPtrQ $r31r30, 10 + ; CHECK-NEXT: $r25 = LDDRdPtrQ $r31r30, 11 + + ; CHECK-TINY: $r30 = SUBIRdK $r30, 246, implicit-def $sreg + ; CHECK-TINY-NEXT: $r31 = SBCIRdK $r31, 255, implicit-def $sreg, implicit killed $sreg + ; CHECK-TINY-NEXT: $r24, $r31r30 = LDRdPtrPi killed $r31r30 + ; CHECK-TINY-NEXT: $r25, $r31r30 = LDRdPtrPi killed $r31r30 + ; CHECK-TINY-NEXT: $r30 = SUBIRdK $r30, 12, implicit-def $sreg + ; CHECK-TINY-NEXT: $r31 = SBCIRdK $r31, 0, implicit-def $sreg, implicit killed $sreg early-clobber $r25r24 = LDDWRdPtrQ undef $r31r30, 10 ... diff --git a/llvm/test/CodeGen/AVR/pseudo/LDWRdPtr.mir b/llvm/test/CodeGen/AVR/pseudo/LDWRdPtr.mir --- a/llvm/test/CodeGen/AVR/pseudo/LDWRdPtr.mir +++ b/llvm/test/CodeGen/AVR/pseudo/LDWRdPtr.mir @@ -1,4 +1,5 @@ # RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mattr=avrtiny %s -o - | FileCheck %s --check-prefix=CHECK-TINY # This test checks the expansion of the 16-bit LDWRdPtr pseudo instruction. @@ -21,5 +22,10 @@ ; CHECK: $r0 = LDRdPtr $r31r30 ; CHECK-NEXT: $r1 = LDDRdPtrQ $r31r30, 1 + ; CHECK-TINY: $r0, $r31r30 = LDRdPtrPi killed $r31r30 + ; CHECK-TINY-NEXT: $r1, $r31r30 = LDRdPtrPi killed $r31r30 + ; CHECK-TINY-NEXT: $r30 = SUBIRdK $r30, 2, implicit-def $sreg + ; CHECK-TINY-NEXT: $r31 = SBCIRdK $r31, 0, implicit-def $sreg, implicit killed $sreg + $r1r0 = LDWRdPtr $r31r30 ... diff --git a/llvm/test/CodeGen/AVR/pseudo/STDWPtrQRr.mir b/llvm/test/CodeGen/AVR/pseudo/STDWPtrQRr.mir --- a/llvm/test/CodeGen/AVR/pseudo/STDWPtrQRr.mir +++ b/llvm/test/CodeGen/AVR/pseudo/STDWPtrQRr.mir @@ -1,4 +1,5 @@ # RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mattr=avrtiny %s -o - | FileCheck %s --check-prefix=CHECK-TINY --- | target triple = "avr--" @@ -12,11 +13,19 @@ name: test body: | bb.0.entry: + liveins: $r17r16 ; CHECK-LABEL: test - ; CHECK: STDPtrQRr $r29r28, 10, $r0 - ; CHECK-NEXT: STDPtrQRr $r29r28, 11, $r1 + ; CHECK: STDPtrQRr $r29r28, 10, $r16 + ; CHECK-NEXT: STDPtrQRr $r29r28, 11, $r17 - STDWPtrQRr $r29r28, 10, $r1r0 + ; CHECK-TINY: $r28 = SUBIRdK $r28, 246, implicit-def $sreg + ; CHECK-TINY-NEXT: $r29 = SBCIRdK $r29, 255, implicit-def $sreg, implicit killed $sreg + ; CHECK-TINY-NEXT: $r29r28 = STPtrPiRr killed $r29r28, $r16, 0 + ; CHECK-TINY-NEXT: $r29r28 = STPtrPiRr killed $r29r28, $r17, 0 + ; CHECK-TINY-NEXT: $r28 = SUBIRdK $r28, 12, implicit-def $sreg + ; CHECK-TINY-NEXT: $r29 = SBCIRdK $r29, 0, implicit-def $sreg, implicit killed $sreg + + STDWPtrQRr $r29r28, 10, $r17r16 ... diff --git a/llvm/test/CodeGen/AVR/pseudo/STWPtrRr.mir b/llvm/test/CodeGen/AVR/pseudo/STWPtrRr.mir --- a/llvm/test/CodeGen/AVR/pseudo/STWPtrRr.mir +++ b/llvm/test/CodeGen/AVR/pseudo/STWPtrRr.mir @@ -1,4 +1,5 @@ # RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mattr=avrtiny %s -o - | FileCheck %s --check-prefix=CHECK-TINY # This test checks the expansion of the 16-bit STSWRdK pseudo instruction. @@ -21,5 +22,10 @@ ; CHECK: STPtrRr $r31r30, $r16 ; CHECK-NEXT: STDPtrQRr $r31r30, 1, $r17 + ; CHECK-TINY: $r31r30 = STPtrPiRr killed $r31r30, $r16, 0 + ; CHECK-TINY-NEXT: $r31r30 = STPtrPiRr killed $r31r30, $r17, 0 + ; CHECK-TINY-NEXT: $r30 = SUBIRdK $r30, 2, implicit-def $sreg + ; CHECK-TINY-NEXT: $r31 = SBCIRdK $r31, 0, implicit-def $sreg, implicit killed $sreg + STWPtrRr $r31r30, $r17r16 ...