aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/AVR
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/AVR')
-rw-r--r--llvm/lib/Target/AVR/AVR.h2
-rw-r--r--llvm/lib/Target/AVR/AVRAsmPrinter.cpp17
-rw-r--r--llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp488
-rw-r--r--llvm/lib/Target/AVR/AVRFrameLowering.cpp7
-rw-r--r--llvm/lib/Target/AVR/AVRISelLowering.cpp178
-rw-r--r--llvm/lib/Target/AVR/AVRISelLowering.h9
-rw-r--r--llvm/lib/Target/AVR/AVRInstrInfo.td106
-rw-r--r--llvm/lib/Target/AVR/AVRRegisterInfo.td27
-rw-r--r--llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp2
-rw-r--r--llvm/lib/Target/AVR/AVRShiftExpand.cpp147
-rw-r--r--llvm/lib/Target/AVR/AVRTargetMachine.cpp11
-rw-r--r--llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp2
-rw-r--r--llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp7
-rw-r--r--llvm/lib/Target/AVR/MCTargetDesc/AVRMCELFStreamer.cpp4
-rw-r--r--llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp6
-rw-r--r--llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h3
16 files changed, 838 insertions, 178 deletions
diff --git a/llvm/lib/Target/AVR/AVR.h b/llvm/lib/Target/AVR/AVR.h
index f0746d73c95f..7332307c07a3 100644
--- a/llvm/lib/Target/AVR/AVR.h
+++ b/llvm/lib/Target/AVR/AVR.h
@@ -22,6 +22,7 @@ namespace llvm {
class AVRTargetMachine;
class FunctionPass;
+Pass *createAVRShiftExpandPass();
FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createAVRExpandPseudoPass();
@@ -30,6 +31,7 @@ FunctionPass *createAVRRelaxMemPass();
FunctionPass *createAVRDynAllocaSRPass();
FunctionPass *createAVRBranchSelectionPass();
+void initializeAVRShiftExpandPass(PassRegistry &);
void initializeAVRExpandPseudoPass(PassRegistry&);
void initializeAVRRelaxMemPass(PassRegistry&);
diff --git a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
index 722eecdc16a1..e8a13c712210 100644
--- a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
+++ b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
@@ -15,6 +15,7 @@
#include "AVRMCInstLower.h"
#include "AVRSubtarget.h"
#include "MCTargetDesc/AVRInstPrinter.h"
+#include "MCTargetDesc/AVRMCExpr.h"
#include "TargetInfo/AVRTargetInfo.h"
#include "llvm/CodeGen/AsmPrinter.h"
@@ -53,6 +54,8 @@ public:
void emitInstruction(const MachineInstr *MI) override;
+ const MCExpr *lowerConstant(const Constant *CV) override;
+
private:
const MCRegisterInfo &MRI;
};
@@ -176,6 +179,20 @@ void AVRAsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, I);
}
+const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV) {
+ MCContext &Ctx = OutContext;
+
+ if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
+ bool IsProgMem = GV->getAddressSpace() == AVR::ProgramMemory;
+ if (IsProgMem) {
+ const MCExpr *Expr = MCSymbolRefExpr::create(getSymbol(GV), Ctx);
+ return AVRMCExpr::create(AVRMCExpr::VK_AVR_PM, Expr, false, Ctx);
+ }
+ }
+
+ return AsmPrinter::lowerConstant(CV);
+}
+
} // end of namespace llvm
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAVRAsmPrinter() {
diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
index a48d3d134bb5..f9f91f50c9d5 100644
--- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
@@ -90,6 +90,18 @@ private:
Block &MBB,
BlockIt MBBI);
+ /// Specific shift implementation.
+ bool expandLSLB7Rd(Block &MBB, BlockIt MBBI);
+ bool expandLSRB7Rd(Block &MBB, BlockIt MBBI);
+ bool expandASRB7Rd(Block &MBB, BlockIt MBBI);
+ bool expandLSLW4Rd(Block &MBB, BlockIt MBBI);
+ bool expandLSRW4Rd(Block &MBB, BlockIt MBBI);
+ bool expandLSLW8Rd(Block &MBB, BlockIt MBBI);
+ bool expandLSRW8Rd(Block &MBB, BlockIt MBBI);
+ bool expandASRW8Rd(Block &MBB, BlockIt MBBI);
+ bool expandLSLW12Rd(Block &MBB, BlockIt MBBI);
+ bool expandLSRW12Rd(Block &MBB, BlockIt MBBI);
+
/// Scavenges a free GPR8 register for use.
Register scavengeGPR8(MachineInstr &MI);
};
@@ -438,12 +450,12 @@ bool AVRExpandPseudo::expand<AVR::NEGWRd>(Block &MBB, BlockIt MBBI) {
.addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
.addReg(DstLoReg, getKillRegState(DstIsKill));
- // Do an extra SBCI.
+ // Do an extra SBC.
auto MISBCI =
- buildMI(MBB, MBBI, AVR::SBCIRdK)
+ buildMI(MBB, MBBI, AVR::SBCRdRr)
.addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
.addReg(DstHiReg, getKillRegState(DstIsKill))
- .addImm(0);
+ .addReg(ZERO_REGISTER);
if (ImpIsDead)
MISBCI->getOperand(3).setIsDead();
// SREG is always implicitly killed
@@ -650,10 +662,10 @@ bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {
if (TmpReg) {
// Move the high byte into the final destination.
- buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
+ buildMI(MBB, MBBI, AVR::MOVRdRr, DstHiReg).addReg(TmpReg);
// Move the low byte from the scratch space into the final destination.
- buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
+ buildMI(MBB, MBBI, AVR::POPRd, DstLoReg);
}
MIBLO.setMemRefs(MI.memoperands());
@@ -767,10 +779,10 @@ bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
if (TmpReg) {
// Move the high byte into the final destination.
- buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
+ buildMI(MBB, MBBI, AVR::MOVRdRr, DstHiReg).addReg(TmpReg);
// Move the low byte from the scratch space into the final destination.
- buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
+ buildMI(MBB, MBBI, AVR::POPRd, DstLoReg);
}
MIBLO.setMemRefs(MI.memoperands());
@@ -815,10 +827,10 @@ bool AVRExpandPseudo::expand<AVR::LPMWRdZ>(Block &MBB, BlockIt MBBI) {
if (TmpReg) {
// Move the high byte into the final destination.
- buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
+ buildMI(MBB, MBBI, AVR::MOVRdRr, DstHiReg).addReg(TmpReg);
// Move the low byte from the scratch space into the final destination.
- buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
+ buildMI(MBB, MBBI, AVR::POPRd, DstLoReg);
}
MIBLO.setMemRefs(MI.memoperands());
@@ -883,20 +895,24 @@ bool AVRExpandPseudo::expandAtomicArithmeticOp(unsigned Width,
Block &MBB,
BlockIt MBBI) {
return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
- auto Op1 = MI.getOperand(0);
- auto Op2 = MI.getOperand(1);
+ auto DstReg = MI.getOperand(0).getReg();
+ auto PtrOp = MI.getOperand(1);
+ auto SrcReg = MI.getOperand(2).getReg();
unsigned LoadOpcode = (Width == 8) ? AVR::LDRdPtr : AVR::LDWRdPtr;
unsigned StoreOpcode = (Width == 8) ? AVR::STPtrRr : AVR::STWPtrRr;
+ // FIXME: this returns the new value (after the operation), not the old
+ // value as the atomicrmw instruction is supposed to do!
+
// Create the load
- buildMI(MBB, MBBI, LoadOpcode).add(Op1).add(Op2);
+ buildMI(MBB, MBBI, LoadOpcode, DstReg).addReg(PtrOp.getReg());
// Create the arithmetic op
- buildMI(MBB, MBBI, ArithOpcode).add(Op1).add(Op1).add(Op2);
+ buildMI(MBB, MBBI, ArithOpcode, DstReg).addReg(DstReg).addReg(SrcReg);
// Create the store
- buildMI(MBB, MBBI, StoreOpcode).add(Op2).add(Op1);
+ buildMI(MBB, MBBI, StoreOpcode).add(PtrOp).addReg(DstReg);
});
}
@@ -1055,6 +1071,7 @@ bool AVRExpandPseudo::expand<AVR::STWPtrRr>(Block &MBB, BlockIt MBBI) {
Register SrcLoReg, SrcHiReg;
Register DstReg = MI.getOperand(0).getReg();
Register SrcReg = MI.getOperand(1).getReg();
+ bool DstIsUndef = MI.getOperand(0).isUndef();
bool SrcIsKill = MI.getOperand(1).isKill();
unsigned OpLo = AVR::STPtrRr;
unsigned OpHi = AVR::STDPtrQRr;
@@ -1062,11 +1079,11 @@ bool AVRExpandPseudo::expand<AVR::STWPtrRr>(Block &MBB, BlockIt MBBI) {
//:TODO: need to reverse this order like inw and stsw?
auto MIBLO = buildMI(MBB, MBBI, OpLo)
- .addReg(DstReg)
+ .addReg(DstReg, getUndefRegState(DstIsUndef))
.addReg(SrcLoReg, getKillRegState(SrcIsKill));
auto MIBHI = buildMI(MBB, MBBI, OpHi)
- .addReg(DstReg)
+ .addReg(DstReg, getUndefRegState(DstIsUndef))
.addImm(1)
.addReg(SrcHiReg, getKillRegState(SrcIsKill));
@@ -1328,42 +1345,20 @@ bool AVRExpandPseudo::expand<AVR::RORBRd>(Block &MBB, BlockIt MBBI) {
// to explicitly add the carry bit.
MachineInstr &MI = *MBBI;
- unsigned OpShiftOut, OpLoad, OpShiftIn, OpAdd;
Register DstReg = MI.getOperand(0).getReg();
- bool DstIsDead = MI.getOperand(0).isDead();
- OpShiftOut = AVR::LSRRd;
- OpLoad = AVR::LDIRdK;
- OpShiftIn = AVR::RORRd;
- OpAdd = AVR::ORRdRr;
-
- // lsr r16
- // ldi r0, 0
- // ror r0
- // or r16, r17
-
- // Shift out
- buildMI(MBB, MBBI, OpShiftOut)
- .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
- .addReg(DstReg);
- // Put 0 in temporary register
- buildMI(MBB, MBBI, OpLoad)
- .addReg(SCRATCH_REGISTER, RegState::Define | getDeadRegState(true))
- .addImm(0x00);
+ // bst r16, 0
+ // ror r16
+ // bld r16, 7
- // Shift in
- buildMI(MBB, MBBI, OpShiftIn)
- .addReg(SCRATCH_REGISTER, RegState::Define | getDeadRegState(true))
- .addReg(SCRATCH_REGISTER);
+ // Move the lowest bit from DstReg into the T bit
+ buildMI(MBB, MBBI, AVR::BST).addReg(DstReg).addImm(0);
- // Add the results together using an or-instruction
- auto MIB = buildMI(MBB, MBBI, OpAdd)
- .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
- .addReg(DstReg)
- .addReg(SCRATCH_REGISTER);
+ // Rotate to the right
+ buildMI(MBB, MBBI, AVR::RORRd, DstReg).addReg(DstReg);
- // SREG is always implicitly killed
- MIB->getOperand(2).setIsKill();
+ // Move the T bit into the highest bit of DstReg.
+ buildMI(MBB, MBBI, AVR::BLD, DstReg).addReg(DstReg).addImm(7);
MI.eraseFromParent();
return true;
@@ -1402,6 +1397,149 @@ bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
+bool AVRExpandPseudo::expandLSLW4Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // swap Rh
+ // swap Rl
+ buildMI(MBB, MBBI, AVR::SWAPRd)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+ buildMI(MBB, MBBI, AVR::SWAPRd)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ // andi Rh, 0xf0
+ auto MI0 =
+ buildMI(MBB, MBBI, AVR::ANDIRdK)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addImm(0xf0);
+ // SREG is implicitly dead.
+ MI0->getOperand(3).setIsDead();
+
+ // eor Rh, Rl
+ auto MI1 =
+ buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(DstLoReg);
+ // SREG is implicitly dead.
+ MI1->getOperand(3).setIsDead();
+
+ // andi Rl, 0xf0
+ auto MI2 =
+ buildMI(MBB, MBBI, AVR::ANDIRdK)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addImm(0xf0);
+ // SREG is implicitly dead.
+ MI2->getOperand(3).setIsDead();
+
+ // eor Rh, Rl
+ auto MI3 =
+ buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(DstLoReg);
+ if (ImpIsDead)
+ MI3->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::expandLSLW8Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // mov Rh, Rl
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg);
+
+ // clr Rl
+ auto MIBLO =
+ buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+ if (ImpIsDead)
+ MIBLO->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::expandLSLW12Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // mov Rh, Rl
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg);
+
+ // swap Rh
+ buildMI(MBB, MBBI, AVR::SWAPRd)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ // andi Rh, 0xf0
+ auto MI0 =
+ buildMI(MBB, MBBI, AVR::ANDIRdK)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addImm(0xf0);
+ // SREG is implicitly dead.
+ MI0->getOperand(3).setIsDead();
+
+ // clr Rl
+ auto MI1 =
+ buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+ if (ImpIsDead)
+ MI1->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSLWNRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned Imm = MI.getOperand(2).getImm();
+ switch (Imm) {
+ case 4:
+ return expandLSLW4Rd(MBB, MBBI);
+ case 8:
+ return expandLSLW8Rd(MBB, MBBI);
+ case 12:
+ return expandLSLW12Rd(MBB, MBBI);
+ default:
+ llvm_unreachable("unimplemented lslwn");
+ return false;
+ }
+}
+
template <>
bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
@@ -1433,6 +1571,149 @@ bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
+bool AVRExpandPseudo::expandLSRW4Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // swap Rh
+ // swap Rl
+ buildMI(MBB, MBBI, AVR::SWAPRd)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+ buildMI(MBB, MBBI, AVR::SWAPRd)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ // andi Rl, 0xf
+ auto MI0 =
+ buildMI(MBB, MBBI, AVR::ANDIRdK)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addImm(0xf);
+ // SREG is implicitly dead.
+ MI0->getOperand(3).setIsDead();
+
+ // eor Rl, Rh
+ auto MI1 =
+ buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(DstHiReg);
+ // SREG is implicitly dead.
+ MI1->getOperand(3).setIsDead();
+
+ // andi Rh, 0xf
+ auto MI2 =
+ buildMI(MBB, MBBI, AVR::ANDIRdK)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addImm(0xf);
+ // SREG is implicitly dead.
+ MI2->getOperand(3).setIsDead();
+
+ // eor Rl, Rh
+ auto MI3 =
+ buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(DstHiReg);
+ if (ImpIsDead)
+ MI3->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::expandLSRW8Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Move upper byte to lower byte.
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg);
+
+ // Clear upper byte.
+ auto MIBHI =
+ buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::expandLSRW12Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Move upper byte to lower byte.
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg);
+
+ // swap Rl
+ buildMI(MBB, MBBI, AVR::SWAPRd)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ // andi Rl, 0xf
+ auto MI0 =
+ buildMI(MBB, MBBI, AVR::ANDIRdK)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addImm(0xf);
+ // SREG is implicitly dead.
+ MI0->getOperand(3).setIsDead();
+
+ // Clear upper byte.
+ auto MIBHI =
+ buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSRWNRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned Imm = MI.getOperand(2).getImm();
+ switch (Imm) {
+ case 4:
+ return expandLSRW4Rd(MBB, MBBI);
+ case 8:
+ return expandLSRW8Rd(MBB, MBBI);
+ case 12:
+ return expandLSRW12Rd(MBB, MBBI);
+ default:
+ llvm_unreachable("unimplemented lsrwn");
+ return false;
+ }
+}
+
template <>
bool AVRExpandPseudo::expand<AVR::RORWRd>(Block &MBB, BlockIt MBBI) {
llvm_unreachable("RORW unimplemented");
@@ -1476,13 +1757,58 @@ bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
+bool AVRExpandPseudo::expandASRW8Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Move upper byte to lower byte.
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg);
+
+ // Move the sign bit to the C flag.
+ buildMI(MBB, MBBI, AVR::ADDRdRr)
+ .addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill) | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ // Set upper byte to 0 or -1.
+ auto MIBHI =
+ buildMI(MBB, MBBI, AVR::SBCRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
template <>
-bool AVRExpandPseudo::expand<AVR::LSLB7Rd>(Block &MBB, BlockIt MBBI) {
+bool AVRExpandPseudo::expand<AVR::ASRWNRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned Imm = MI.getOperand(2).getImm();
+ switch (Imm) {
+ case 8:
+ return expandASRW8Rd(MBB, MBBI);
+ default:
+ llvm_unreachable("unimplemented asrwn");
+ return false;
+ }
+}
+
+bool AVRExpandPseudo::expandLSLB7Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstReg = MI.getOperand(0).getReg();
bool DstIsDead = MI.getOperand(0).isDead();
bool DstIsKill = MI.getOperand(1).isKill();
- bool ImpIsDead = MI.getOperand(2).isDead();
+ bool ImpIsDead = MI.getOperand(3).isDead();
// ror r24
// clr r24
@@ -1490,7 +1816,8 @@ bool AVRExpandPseudo::expand<AVR::LSLB7Rd>(Block &MBB, BlockIt MBBI) {
buildMI(MBB, MBBI, AVR::RORRd)
.addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
- .addReg(DstReg, getKillRegState(DstIsKill));
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ ->getOperand(3).setIsUndef(true);
buildMI(MBB, MBBI, AVR::EORRdRr)
.addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
@@ -1513,12 +1840,24 @@ bool AVRExpandPseudo::expand<AVR::LSLB7Rd>(Block &MBB, BlockIt MBBI) {
}
template <>
-bool AVRExpandPseudo::expand<AVR::LSRB7Rd>(Block &MBB, BlockIt MBBI) {
+bool AVRExpandPseudo::expand<AVR::LSLBNRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned Imm = MI.getOperand(2).getImm();
+ switch (Imm) {
+ case 7:
+ return expandLSLB7Rd(MBB, MBBI);
+ default:
+ llvm_unreachable("unimplemented lslbn");
+ return false;
+ }
+}
+
+bool AVRExpandPseudo::expandLSRB7Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstReg = MI.getOperand(0).getReg();
bool DstIsDead = MI.getOperand(0).isDead();
bool DstIsKill = MI.getOperand(1).isKill();
- bool ImpIsDead = MI.getOperand(2).isDead();
+ bool ImpIsDead = MI.getOperand(3).isDead();
// rol r24
// clr r24
@@ -1527,7 +1866,8 @@ bool AVRExpandPseudo::expand<AVR::LSRB7Rd>(Block &MBB, BlockIt MBBI) {
buildMI(MBB, MBBI, AVR::ADCRdRr)
.addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
.addReg(DstReg, getKillRegState(DstIsKill))
- .addReg(DstReg, getKillRegState(DstIsKill));
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ ->getOperand(4).setIsUndef(true);
buildMI(MBB, MBBI, AVR::EORRdRr)
.addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
@@ -1551,12 +1891,24 @@ bool AVRExpandPseudo::expand<AVR::LSRB7Rd>(Block &MBB, BlockIt MBBI) {
}
template <>
-bool AVRExpandPseudo::expand<AVR::ASRB7Rd>(Block &MBB, BlockIt MBBI) {
+bool AVRExpandPseudo::expand<AVR::LSRBNRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned Imm = MI.getOperand(2).getImm();
+ switch (Imm) {
+ case 7:
+ return expandLSRB7Rd(MBB, MBBI);
+ default:
+ llvm_unreachable("unimplemented lsrbn");
+ return false;
+ }
+}
+
+bool AVRExpandPseudo::expandASRB7Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstReg = MI.getOperand(0).getReg();
bool DstIsDead = MI.getOperand(0).isDead();
bool DstIsKill = MI.getOperand(1).isKill();
- bool ImpIsDead = MI.getOperand(2).isDead();
+ bool ImpIsDead = MI.getOperand(3).isDead();
// lsl r24
// sbc r24, r24
@@ -1581,6 +1933,19 @@ bool AVRExpandPseudo::expand<AVR::ASRB7Rd>(Block &MBB, BlockIt MBBI) {
return true;
}
+template <>
+bool AVRExpandPseudo::expand<AVR::ASRBNRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned Imm = MI.getOperand(2).getImm();
+ switch (Imm) {
+ case 7:
+ return expandASRB7Rd(MBB, MBBI);
+ default:
+ llvm_unreachable("unimplemented asrbn");
+ return false;
+ }
+}
+
template <> bool AVRExpandPseudo::expand<AVR::SEXT>(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
@@ -1666,8 +2031,8 @@ template <> bool AVRExpandPseudo::expand<AVR::ZEXT>(Block &MBB, BlockIt MBBI) {
auto EOR = buildMI(MBB, MBBI, AVR::EORRdRr)
.addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
- .addReg(DstHiReg, RegState::Kill)
- .addReg(DstHiReg, RegState::Kill);
+ .addReg(DstHiReg, RegState::Kill | RegState::Undef)
+ .addReg(DstHiReg, RegState::Kill | RegState::Undef);
if (ImpIsDead)
EOR->getOperand(3).setIsDead();
@@ -1802,9 +2167,12 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
EXPAND(AVR::RORWRd);
EXPAND(AVR::ROLWRd);
EXPAND(AVR::ASRWRd);
- EXPAND(AVR::LSLB7Rd);
- EXPAND(AVR::LSRB7Rd);
- EXPAND(AVR::ASRB7Rd);
+ EXPAND(AVR::LSLWNRd);
+ EXPAND(AVR::LSRWNRd);
+ EXPAND(AVR::ASRWNRd);
+ EXPAND(AVR::LSLBNRd);
+ EXPAND(AVR::LSRBNRd);
+ EXPAND(AVR::ASRBNRd);
EXPAND(AVR::SEXT);
EXPAND(AVR::ZEXT);
EXPAND(AVR::SPREAD);
diff --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
index 757b41466c3f..89ed30e8bcdb 100644
--- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
@@ -83,6 +83,11 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
.addReg(AVR::R0, RegState::Kill)
.addReg(AVR::R0, RegState::Kill)
.setMIFlag(MachineInstr::FrameSetup);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::EORRdRr))
+ .addReg(AVR::R1, RegState::Define)
+ .addReg(AVR::R1, RegState::Kill)
+ .addReg(AVR::R1, RegState::Kill)
+ .setMIFlag(MachineInstr::FrameSetup);
}
// Early exit if the frame pointer is not needed in this function.
@@ -362,7 +367,7 @@ MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(
New->getOperand(3).setIsDead();
BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
- .addReg(AVR::R31R30, RegState::Kill);
+ .addReg(AVR::R31R30);
// Make sure the remaining stack stores are converted to real store
// instructions.
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp
index 3e7c2984655a..58a7aed91cdf 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -334,7 +334,7 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
llvm_unreachable("Invalid shift opcode");
}
- // Optimize int8 shifts.
+ // Optimize int8/int16 shifts.
if (VT.getSizeInBits() == 8) {
if (Op.getOpcode() == ISD::SHL && 4 <= ShiftAmount && ShiftAmount < 7) {
// Optimize LSL when 4 <= ShiftAmount <= 6.
@@ -351,17 +351,71 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
ShiftAmount -= 4;
} else if (Op.getOpcode() == ISD::SHL && ShiftAmount == 7) {
// Optimize LSL when ShiftAmount == 7.
- Victim = DAG.getNode(AVRISD::LSL7, dl, VT, Victim);
+ Victim = DAG.getNode(AVRISD::LSLBN, dl, VT, Victim,
+ DAG.getConstant(7, dl, VT));
ShiftAmount = 0;
} else if (Op.getOpcode() == ISD::SRL && ShiftAmount == 7) {
// Optimize LSR when ShiftAmount == 7.
- Victim = DAG.getNode(AVRISD::LSR7, dl, VT, Victim);
+ Victim = DAG.getNode(AVRISD::LSRBN, dl, VT, Victim,
+ DAG.getConstant(7, dl, VT));
ShiftAmount = 0;
} else if (Op.getOpcode() == ISD::SRA && ShiftAmount == 7) {
// Optimize ASR when ShiftAmount == 7.
- Victim = DAG.getNode(AVRISD::ASR7, dl, VT, Victim);
+ Victim = DAG.getNode(AVRISD::ASRBN, dl, VT, Victim,
+ DAG.getConstant(7, dl, VT));
ShiftAmount = 0;
}
+ } else if (VT.getSizeInBits() == 16) {
+ if (4 <= ShiftAmount && ShiftAmount < 8)
+ switch (Op.getOpcode()) {
+ case ISD::SHL:
+ Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
+ DAG.getConstant(4, dl, VT));
+ ShiftAmount -= 4;
+ break;
+ case ISD::SRL:
+ Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
+ DAG.getConstant(4, dl, VT));
+ ShiftAmount -= 4;
+ break;
+ default:
+ break;
+ }
+ else if (8 <= ShiftAmount && ShiftAmount < 12)
+ switch (Op.getOpcode()) {
+ case ISD::SHL:
+ Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
+ DAG.getConstant(8, dl, VT));
+ ShiftAmount -= 8;
+ break;
+ case ISD::SRL:
+ Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
+ DAG.getConstant(8, dl, VT));
+ ShiftAmount -= 8;
+ break;
+ case ISD::SRA:
+ Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
+ DAG.getConstant(8, dl, VT));
+ ShiftAmount -= 8;
+ break;
+ default:
+ break;
+ }
+ else if (12 <= ShiftAmount)
+ switch (Op.getOpcode()) {
+ case ISD::SHL:
+ Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
+ DAG.getConstant(12, dl, VT));
+ ShiftAmount -= 12;
+ break;
+ case ISD::SRL:
+ Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
+ DAG.getConstant(12, dl, VT));
+ ShiftAmount -= 12;
+ break;
+ default:
+ break;
+ }
}
while (ShiftAmount--) {
@@ -477,7 +531,7 @@ SDValue AVRTargetLowering::getAVRCmp(SDValue LHS, SDValue RHS,
SDValue Cmp;
- if (LHS.getSimpleValueType() == MVT::i16 && dyn_cast<ConstantSDNode>(RHS)) {
+ if (LHS.getSimpleValueType() == MVT::i16 && isa<ConstantSDNode>(RHS)) {
// Generate a CPI/CPC pair if RHS is a 16-bit constant.
SDValue LHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS,
DAG.getIntPtrConstant(0, DL));
@@ -1269,15 +1323,17 @@ SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
}
- // Second, stack arguments have to walked in reverse order by inserting
- // chained stores, this ensures their order is not changed by the scheduler
- // and that the push instruction sequence generated is correct, otherwise they
- // can be freely intermixed.
+ // Second, stack arguments have to walked.
+ // Previously this code created chained stores but those chained stores appear
+ // to be unchained in the legalization phase. Therefore, do not attempt to
+ // chain them here. In fact, chaining them here somehow causes the first and
+ // second store to be reversed which is the exact opposite of the intended
+ // effect.
if (HasStackArgs) {
- for (AE = AI, AI = ArgLocs.size(); AI != AE; --AI) {
- unsigned Loc = AI - 1;
- CCValAssign &VA = ArgLocs[Loc];
- SDValue Arg = OutVals[Loc];
+ SmallVector<SDValue, 8> MemOpChains;
+ for (; AI != AE; AI++) {
+ CCValAssign &VA = ArgLocs[AI];
+ SDValue Arg = OutVals[AI];
assert(VA.isMemLoc());
@@ -1287,10 +1343,13 @@ SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
DAG.getRegister(AVR::SP, getPointerTy(DAG.getDataLayout())),
DAG.getIntPtrConstant(VA.getLocMemOffset() + 1, DL));
- Chain =
+ MemOpChains.push_back(
DAG.getStore(Chain, DL, Arg, PtrOff,
- MachinePointerInfo::getStack(MF, VA.getLocMemOffset()));
+ MachinePointerInfo::getStack(MF, VA.getLocMemOffset())));
}
+
+ if (!MemOpChains.empty())
+ Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
}
// Build a sequence of copy-to-reg nodes chained together with token chain and
@@ -1871,44 +1930,65 @@ std::pair<unsigned, const TargetRegisterClass *>
AVRTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint,
MVT VT) const {
- // We only support i8 and i16.
- //
- //:FIXME: remove this assert for now since it gets sometimes executed
- // assert((VT == MVT::i16 || VT == MVT::i8) && "Wrong operand type.");
-
if (Constraint.size() == 1) {
switch (Constraint[0]) {
case 'a': // Simple upper registers r16..r23.
- return std::make_pair(0U, &AVR::LD8loRegClass);
+ if (VT == MVT::i8)
+ return std::make_pair(0U, &AVR::LD8loRegClass);
+ else if (VT == MVT::i16)
+ return std::make_pair(0U, &AVR::DREGSLD8loRegClass);
+ break;
case 'b': // Base pointer registers: y, z.
- return std::make_pair(0U, &AVR::PTRDISPREGSRegClass);
+ if (VT == MVT::i8 || VT == MVT::i16)
+ return std::make_pair(0U, &AVR::PTRDISPREGSRegClass);
+ break;
case 'd': // Upper registers r16..r31.
- return std::make_pair(0U, &AVR::LD8RegClass);
+ if (VT == MVT::i8)
+ return std::make_pair(0U, &AVR::LD8RegClass);
+ else if (VT == MVT::i16)
+ return std::make_pair(0U, &AVR::DLDREGSRegClass);
+ break;
case 'l': // Lower registers r0..r15.
- return std::make_pair(0U, &AVR::GPR8loRegClass);
+ if (VT == MVT::i8)
+ return std::make_pair(0U, &AVR::GPR8loRegClass);
+ else if (VT == MVT::i16)
+ return std::make_pair(0U, &AVR::DREGSloRegClass);
+ break;
case 'e': // Pointer register pairs: x, y, z.
- return std::make_pair(0U, &AVR::PTRREGSRegClass);
+ if (VT == MVT::i8 || VT == MVT::i16)
+ return std::make_pair(0U, &AVR::PTRREGSRegClass);
+ break;
case 'q': // Stack pointer register: SPH:SPL.
return std::make_pair(0U, &AVR::GPRSPRegClass);
case 'r': // Any register: r0..r31.
if (VT == MVT::i8)
return std::make_pair(0U, &AVR::GPR8RegClass);
-
- assert(VT == MVT::i16 && "inline asm constraint too large");
- return std::make_pair(0U, &AVR::DREGSRegClass);
+ else if (VT == MVT::i16)
+ return std::make_pair(0U, &AVR::DREGSRegClass);
+ break;
case 't': // Temporary register: r0.
- return std::make_pair(unsigned(AVR::R0), &AVR::GPR8RegClass);
+ if (VT == MVT::i8)
+ return std::make_pair(unsigned(AVR::R0), &AVR::GPR8RegClass);
+ break;
case 'w': // Special upper register pairs: r24, r26, r28, r30.
- return std::make_pair(0U, &AVR::IWREGSRegClass);
+ if (VT == MVT::i8 || VT == MVT::i16)
+ return std::make_pair(0U, &AVR::IWREGSRegClass);
+ break;
case 'x': // Pointer register pair X: r27:r26.
case 'X':
- return std::make_pair(unsigned(AVR::R27R26), &AVR::PTRREGSRegClass);
+ if (VT == MVT::i8 || VT == MVT::i16)
+ return std::make_pair(unsigned(AVR::R27R26), &AVR::PTRREGSRegClass);
+ break;
case 'y': // Pointer register pair Y: r29:r28.
case 'Y':
- return std::make_pair(unsigned(AVR::R29R28), &AVR::PTRREGSRegClass);
+ if (VT == MVT::i8 || VT == MVT::i16)
+ return std::make_pair(unsigned(AVR::R29R28), &AVR::PTRREGSRegClass);
+ break;
case 'z': // Pointer register pair Z: r31:r30.
case 'Z':
- return std::make_pair(unsigned(AVR::R31R30), &AVR::PTRREGSRegClass);
+ if (VT == MVT::i8 || VT == MVT::i16)
+ return std::make_pair(unsigned(AVR::R31R30), &AVR::PTRREGSRegClass);
+ break;
default:
break;
}
@@ -2031,37 +2111,21 @@ Register AVRTargetLowering::getRegisterByName(const char *RegName, LLT VT,
if (VT == LLT::scalar(8)) {
Reg = StringSwitch<unsigned>(RegName)
- .Case("r0", AVR::R0).Case("r1", AVR::R1).Case("r2", AVR::R2)
- .Case("r3", AVR::R3).Case("r4", AVR::R4).Case("r5", AVR::R5)
- .Case("r6", AVR::R6).Case("r7", AVR::R7).Case("r8", AVR::R8)
- .Case("r9", AVR::R9).Case("r10", AVR::R10).Case("r11", AVR::R11)
- .Case("r12", AVR::R12).Case("r13", AVR::R13).Case("r14", AVR::R14)
- .Case("r15", AVR::R15).Case("r16", AVR::R16).Case("r17", AVR::R17)
- .Case("r18", AVR::R18).Case("r19", AVR::R19).Case("r20", AVR::R20)
- .Case("r21", AVR::R21).Case("r22", AVR::R22).Case("r23", AVR::R23)
- .Case("r24", AVR::R24).Case("r25", AVR::R25).Case("r26", AVR::R26)
- .Case("r27", AVR::R27).Case("r28", AVR::R28).Case("r29", AVR::R29)
- .Case("r30", AVR::R30).Case("r31", AVR::R31)
- .Case("X", AVR::R27R26).Case("Y", AVR::R29R28).Case("Z", AVR::R31R30)
- .Default(0);
+ .Case("r0", AVR::R0)
+ .Case("r1", AVR::R1)
+ .Default(0);
} else {
Reg = StringSwitch<unsigned>(RegName)
- .Case("r0", AVR::R1R0).Case("r2", AVR::R3R2)
- .Case("r4", AVR::R5R4).Case("r6", AVR::R7R6)
- .Case("r8", AVR::R9R8).Case("r10", AVR::R11R10)
- .Case("r12", AVR::R13R12).Case("r14", AVR::R15R14)
- .Case("r16", AVR::R17R16).Case("r18", AVR::R19R18)
- .Case("r20", AVR::R21R20).Case("r22", AVR::R23R22)
- .Case("r24", AVR::R25R24).Case("r26", AVR::R27R26)
- .Case("r28", AVR::R29R28).Case("r30", AVR::R31R30)
- .Case("X", AVR::R27R26).Case("Y", AVR::R29R28).Case("Z", AVR::R31R30)
- .Default(0);
+ .Case("r0", AVR::R1R0)
+ .Case("sp", AVR::SP)
+ .Default(0);
}
if (Reg)
return Reg;
- report_fatal_error("Invalid register name global variable");
+ report_fatal_error(
+ Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
}
} // end of namespace llvm
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h
index 7aff4159211b..8130cf045fa8 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.h
+++ b/llvm/lib/Target/AVR/AVRISelLowering.h
@@ -36,11 +36,14 @@ enum NodeType {
/// TargetExternalSymbol, and TargetGlobalAddress.
WRAPPER,
LSL, ///< Logical shift left.
+ LSLBN, ///< Byte logical shift left N bits.
+ LSLWN, ///< Word logical shift left N bits.
LSR, ///< Logical shift right.
+ LSRBN, ///< Byte logical shift right N bits.
+ LSRWN, ///< Word logical shift right N bits.
ASR, ///< Arithmetic shift right.
- LSL7, ///< Logical shift left 7 bits.
- LSR7, ///< Logical shift right 7 bits.
- ASR7, ///< Arithmetic shift right 7 bits.
+ ASRBN, ///< Byte arithmetic shift right N bits.
+ ASRWN, ///< Word arithmetic shift right N bits.
ROR, ///< Bit rotate right.
ROL, ///< Bit rotate left.
LSLLOOP, ///< A loop of single logical shift left instructions.
diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td
index 9f7c16fc96d2..c7c9656d3bfb 100644
--- a/llvm/lib/Target/AVR/AVRInstrInfo.td
+++ b/llvm/lib/Target/AVR/AVRInstrInfo.td
@@ -59,9 +59,12 @@ def AVRlsr : SDNode<"AVRISD::LSR", SDTIntUnaryOp>;
def AVRrol : SDNode<"AVRISD::ROL", SDTIntUnaryOp>;
def AVRror : SDNode<"AVRISD::ROR", SDTIntUnaryOp>;
def AVRasr : SDNode<"AVRISD::ASR", SDTIntUnaryOp>;
-def AVRlsl7 : SDNode<"AVRISD::LSL7", SDTIntUnaryOp>;
-def AVRlsr7 : SDNode<"AVRISD::LSR7", SDTIntUnaryOp>;
-def AVRasr7 : SDNode<"AVRISD::ASR7", SDTIntUnaryOp>;
+def AVRlslbn : SDNode<"AVRISD::LSLBN", SDTIntBinOp>;
+def AVRlsrbn : SDNode<"AVRISD::LSRBN", SDTIntBinOp>;
+def AVRasrbn : SDNode<"AVRISD::ASRBN", SDTIntBinOp>;
+def AVRlslwn : SDNode<"AVRISD::LSLWN", SDTIntBinOp>;
+def AVRlsrwn : SDNode<"AVRISD::LSRWN", SDTIntBinOp>;
+def AVRasrwn : SDNode<"AVRISD::ASRWN", SDTIntBinOp>;
// Pseudo shift nodes for non-constant shift amounts.
def AVRlslLoop : SDNode<"AVRISD::LSLLOOP", SDTIntShiftOp>;
@@ -357,11 +360,13 @@ Uses = [SP] in
"#ADJCALLSTACKDOWN",
[(AVRcallseq_start timm:$amt, timm:$amt2)]>;
- // R31R30 is used to update SP, since it is a scratch reg and this instruction
- // is placed after the function call then R31R30 should be always free.
- //let Defs = [R31R30],
- //Uses = [R31R30] in
- //:TODO: if we enable this, the pseudo is killed because it looks dead
+ // R31R30 is used to update SP. It is normally free because it is a
+ // call-clobbered register but it is necessary to set it as a def as the
+ // register allocator might use it in rare cases (for rematerialization, it
+ // seems). hasSideEffects needs to be set to true so this instruction isn't
+ // considered dead.
+ let Defs = [R31R30],
+ hasSideEffects=1 in
def ADJCALLSTACKUP : Pseudo<(outs),
(ins i16imm:$amt1, i16imm:$amt2),
"#ADJCALLSTACKUP",
@@ -750,7 +755,7 @@ Defs = [SREG] in
// Expands to:
// neg Rd+1
// neg Rd
- // sbci Rd+1, 0
+ // sbc Rd+1, r1
def NEGWRd : Pseudo<(outs DREGS:$rd),
(ins DREGS:$src),
"negw\t$rd",
@@ -1292,6 +1297,7 @@ class AtomicStore<PatFrag Op, RegisterClass DRC,
Pseudo<(outs), (ins PTRRC:$rd, DRC:$rr), "atomic_op",
[(Op i16:$rd, DRC:$rr)]>;
+let Constraints = "@earlyclobber $rd" in
class AtomicLoadOp<PatFrag Op, RegisterClass DRC,
RegisterClass PTRRC> :
Pseudo<(outs DRC:$rd), (ins PTRRC:$rr, DRC:$operand),
@@ -1669,10 +1675,17 @@ Defs = [SREG] in
"lslw\t$rd",
[(set i16:$rd, (AVRlsl i16:$src)), (implicit SREG)]>;
- def LSLB7Rd : Pseudo<(outs GPR8:$rd),
- (ins GPR8:$src),
- "lslb7\t$rd",
- [(set i8:$rd, (AVRlsl7 i8:$src)), (implicit SREG)]>;
+ def LSLWNRd : Pseudo<(outs DLDREGS:$rd),
+ (ins DREGS:$src, imm16:$bits),
+ "lslwn\t$rd, $bits",
+ [(set i16:$rd, (AVRlslwn i16:$src, imm:$bits)),
+ (implicit SREG)]>;
+
+ def LSLBNRd : Pseudo<(outs LD8:$rd),
+ (ins GPR8:$src, imm_ldi8:$bits),
+ "lslbn\t$rd, $bits",
+ [(set i8:$rd, (AVRlslbn i8:$src, imm:$bits)),
+ (implicit SREG)]>;
def LSRRd : FRd<0b1001,
0b0100110,
@@ -1681,16 +1694,23 @@ Defs = [SREG] in
"lsr\t$rd",
[(set i8:$rd, (AVRlsr i8:$src)), (implicit SREG)]>;
- def LSRB7Rd : Pseudo<(outs GPR8:$rd),
- (ins GPR8:$src),
- "lsrb7\t$rd",
- [(set i8:$rd, (AVRlsr7 i8:$src)), (implicit SREG)]>;
-
def LSRWRd : Pseudo<(outs DREGS:$rd),
(ins DREGS:$src),
"lsrw\t$rd",
[(set i16:$rd, (AVRlsr i16:$src)), (implicit SREG)]>;
+ def LSRWNRd : Pseudo<(outs DLDREGS:$rd),
+ (ins DREGS:$src, imm16:$bits),
+ "lsrwn\t$rd, $bits",
+ [(set i16:$rd, (AVRlsrwn i16:$src, imm:$bits)),
+ (implicit SREG)]>;
+
+ def LSRBNRd : Pseudo<(outs LD8:$rd),
+ (ins GPR8:$src, imm_ldi8:$bits),
+ "lsrbn\t$rd, $bits",
+ [(set i8:$rd, (AVRlsrbn i8:$src, imm:$bits)),
+ (implicit SREG)]>;
+
def ASRRd : FRd<0b1001,
0b0100101,
(outs GPR8:$rd),
@@ -1698,30 +1718,36 @@ Defs = [SREG] in
"asr\t$rd",
[(set i8:$rd, (AVRasr i8:$src)), (implicit SREG)]>;
- def ASRB7Rd : Pseudo<(outs GPR8:$rd),
- (ins GPR8:$src),
- "asrb7\t$rd",
- [(set i8:$rd, (AVRasr7 i8:$src)), (implicit SREG)]>;
+ def ASRWNRd : Pseudo<(outs DLDREGS:$rd),
+ (ins DREGS:$src, imm16:$bits),
+ "asrwn\t$rd, $bits",
+ [(set i16:$rd, (AVRasrwn i16:$src, imm:$bits)),
+ (implicit SREG)]>;
+
+ def ASRBNRd : Pseudo<(outs LD8:$rd),
+ (ins GPR8:$src, imm_ldi8:$bits),
+ "asrbn\t$rd, $bits",
+ [(set i8:$rd, (AVRasrbn i8:$src, imm:$bits)),
+ (implicit SREG)]>;
def ASRWRd : Pseudo<(outs DREGS:$rd),
(ins DREGS:$src),
"asrw\t$rd",
[(set i16:$rd, (AVRasr i16:$src)), (implicit SREG)]>;
+ def ROLBRd : Pseudo<(outs GPR8:$rd),
+ (ins GPR8:$src),
+ "rolb\t$rd",
+ [(set i8:$rd, (AVRrol i8:$src)), (implicit SREG)]>;
+
+ def RORBRd : Pseudo<(outs GPR8:$rd),
+ (ins GPR8:$src),
+ "rorb\t$rd",
+ [(set i8:$rd, (AVRror i8:$src)), (implicit SREG)]>;
+
// Bit rotate operations.
let Uses = [SREG] in
{
- // 8-bit ROL is an alias of ADC Rd, Rd
-
- def ROLBRd : Pseudo<(outs GPR8:$rd),
- (ins GPR8:$src),
- "rolb\t$rd",
- [(set i8:$rd, (AVRrol i8:$src)), (implicit SREG)]>;
-
- def RORBRd : Pseudo<(outs GPR8:$rd),
- (ins GPR8:$src),
- "rorb\t$rd",
- [(set i8:$rd, (AVRror i8:$src)), (implicit SREG)]>;
def ROLWRd : Pseudo<(outs DREGS:$rd),
(ins DREGS:$src),
@@ -1777,10 +1803,11 @@ def BST : FRdB<0b01,
"bst\t$rd, $b",
[]>;
-let Uses = [SREG] in
+let Constraints = "$src = $rd",
+Uses = [SREG] in
def BLD : FRdB<0b00,
- (outs),
- (ins GPR8:$rd, i8imm:$b),
+ (outs GPR8:$rd),
+ (ins GPR8:$src, i8imm:$b),
"bld\t$rd, $b",
[]>;
@@ -2123,12 +2150,7 @@ def : Pat<(store i16:$src, (i16 (AVRWrapper tglobaladdr:$dst))),
def : Pat<(i16 (AVRWrapper tblockaddress:$dst)),
(LDIWRdK tblockaddress:$dst)>;
-// hi-reg truncation : trunc(int16 >> 8)
-//:FIXME: i think it's better to emit an extract subreg node in the DAG than
-// all this mess once we get optimal shift code
-// lol... I think so, too. [@agnat]
-def : Pat<(i8 (trunc (AVRlsr (AVRlsr (AVRlsr (AVRlsr (AVRlsr (AVRlsr (AVRlsr
- (AVRlsr DREGS:$src)))))))))),
+def : Pat<(i8 (trunc (AVRlsrwn DLDREGS:$src, (i16 8)))),
(EXTRACT_SUBREG DREGS:$src, sub_hi)>;
// :FIXME: DAGCombiner produces an shl node after legalization from these seq:
diff --git a/llvm/lib/Target/AVR/AVRRegisterInfo.td b/llvm/lib/Target/AVR/AVRRegisterInfo.td
index ab5d02356c9d..1948fcbaf75a 100644
--- a/llvm/lib/Target/AVR/AVRRegisterInfo.td
+++ b/llvm/lib/Target/AVR/AVRRegisterInfo.td
@@ -67,12 +67,12 @@ def R22 : AVRReg<22, "r22">, DwarfRegNum<[22]>;
def R23 : AVRReg<23, "r23">, DwarfRegNum<[23]>;
def R24 : AVRReg<24, "r24">, DwarfRegNum<[24]>;
def R25 : AVRReg<25, "r25">, DwarfRegNum<[25]>;
-def R26 : AVRReg<26, "r26">, DwarfRegNum<[26]>;
-def R27 : AVRReg<27, "r27">, DwarfRegNum<[27]>;
-def R28 : AVRReg<28, "r28">, DwarfRegNum<[28]>;
-def R29 : AVRReg<29, "r29">, DwarfRegNum<[29]>;
-def R30 : AVRReg<30, "r30">, DwarfRegNum<[30]>;
-def R31 : AVRReg<31, "r31">, DwarfRegNum<[31]>;
+def R26 : AVRReg<26, "r26", [], ["xl"]>, DwarfRegNum<[26]>;
+def R27 : AVRReg<27, "r27", [], ["xh"]>, DwarfRegNum<[27]>;
+def R28 : AVRReg<28, "r28", [], ["yl"]>, DwarfRegNum<[28]>;
+def R29 : AVRReg<29, "r29", [], ["yh"]>, DwarfRegNum<[29]>;
+def R30 : AVRReg<30, "r30", [], ["zl"]>, DwarfRegNum<[30]>;
+def R31 : AVRReg<31, "r31", [], ["zh"]>, DwarfRegNum<[31]>;
def SPL : AVRReg<32, "SPL">, DwarfRegNum<[32]>;
def SPH : AVRReg<33, "SPH">, DwarfRegNum<[33]>;
@@ -171,6 +171,21 @@ def DREGS : RegisterClass<"AVR", [i16], 8,
R14R13, R12R11, R10R9
)>;
+// Lower 16-bit pair registers in R0..R15, only used in inline assembly.
+def DREGSlo : RegisterClass<"AVR", [i16], 8,
+ (
+ add R15R14, R13R12, R11R10, R9R8, R7R6, R5R4, R3R2, R1R0
+ )>;
+
+// Lower 16-bit pair registers in r16..r23, only used in inline assembly.
+def DREGSLD8lo : RegisterClass<"AVR", [i16], 8,
+ (
+ // Return value and arguments.
+ add R19R18, R21R20, R23R22,
+ // Callee saved registers.
+ R17R16
+ )>;
+
// 16-bit pair register class for movw
def DREGSMOVW : RegisterClass<"AVR", [i16], 8,
(
diff --git a/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp b/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp
index 6be901743e82..7d2d19de7578 100644
--- a/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp
+++ b/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp
@@ -113,7 +113,7 @@ bool AVRRelaxMem::relax<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
// Pop the original state of the pointer register.
buildMI(MBB, MBBI, AVR::POPWRd)
- .addReg(Ptr.getReg(), getKillRegState(Ptr.isKill()));
+ .addDef(Ptr.getReg(), getKillRegState(Ptr.isKill()));
MI.removeFromParent();
}
diff --git a/llvm/lib/Target/AVR/AVRShiftExpand.cpp b/llvm/lib/Target/AVR/AVRShiftExpand.cpp
new file mode 100644
index 000000000000..b7dcd860467d
--- /dev/null
+++ b/llvm/lib/Target/AVR/AVRShiftExpand.cpp
@@ -0,0 +1,147 @@
+//===- AVRShift.cpp - Shift Expansion Pass --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Expand 32-bit shift instructions (shl, lshr, ashr) to inline loops, just
+/// like avr-gcc. This must be done in IR because otherwise the type legalizer
+/// will turn 32-bit shifts into (non-existing) library calls such as __ashlsi3.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
+
+using namespace llvm;
+
+namespace {
+
+class AVRShiftExpand : public FunctionPass {
+public:
+ static char ID;
+
+ AVRShiftExpand() : FunctionPass(ID) {}
+
+ bool runOnFunction(Function &F) override;
+
+ StringRef getPassName() const override { return "AVR Shift Expansion"; }
+
+private:
+ void expand(BinaryOperator *BI);
+};
+
+} // end of anonymous namespace
+
+char AVRShiftExpand::ID = 0;
+
+INITIALIZE_PASS(AVRShiftExpand, "avr-shift-expand", "AVR Shift Expansion",
+ false, false)
+
+Pass *llvm::createAVRShiftExpandPass() { return new AVRShiftExpand(); }
+
+bool AVRShiftExpand::runOnFunction(Function &F) {
+ SmallVector<BinaryOperator *, 1> ShiftInsts;
+ auto &Ctx = F.getContext();
+ for (Instruction &I : instructions(F)) {
+ if (!I.isShift())
+ // Only expand shift instructions (shl, lshr, ashr).
+ continue;
+ if (I.getType() != Type::getInt32Ty(Ctx))
+ // Only expand plain i32 types.
+ continue;
+ if (isa<ConstantInt>(I.getOperand(1)))
+ // Only expand when the shift amount is not known.
+ // Known shift amounts are (currently) better expanded inline.
+ continue;
+ ShiftInsts.push_back(cast<BinaryOperator>(&I));
+ }
+
+ // The expanding itself needs to be done separately as expand() will remove
+ // these instructions. Removing instructions while iterating over a basic
+ // block is not a great idea.
+ for (auto *I : ShiftInsts) {
+ expand(I);
+ }
+
+ // Return whether this function expanded any shift instructions.
+ return ShiftInsts.size() > 0;
+}
+
+void AVRShiftExpand::expand(BinaryOperator *BI) {
+ auto &Ctx = BI->getContext();
+ IRBuilder<> Builder(BI);
+ Type *Int32Ty = Type::getInt32Ty(Ctx);
+ Type *Int8Ty = Type::getInt8Ty(Ctx);
+ Value *Int8Zero = ConstantInt::get(Int8Ty, 0);
+
+ // Split the current basic block at the point of the existing shift
+ // instruction and insert a new basic block for the loop.
+ BasicBlock *BB = BI->getParent();
+ Function *F = BB->getParent();
+ BasicBlock *EndBB = BB->splitBasicBlock(BI, "shift.done");
+ BasicBlock *LoopBB = BasicBlock::Create(Ctx, "shift.loop", F, EndBB);
+
+ // Truncate the shift amount to i8, which is trivially lowered to a single
+ // AVR register.
+ Builder.SetInsertPoint(&BB->back());
+ Value *ShiftAmount = Builder.CreateTrunc(BI->getOperand(1), Int8Ty);
+
+ // Replace the unconditional branch that splitBasicBlock created with a
+ // conditional branch.
+ Value *Cmp1 = Builder.CreateICmpEQ(ShiftAmount, Int8Zero);
+ Builder.CreateCondBr(Cmp1, EndBB, LoopBB);
+ BB->back().eraseFromParent();
+
+ // Create the loop body starting with PHI nodes.
+ Builder.SetInsertPoint(LoopBB);
+ PHINode *ShiftAmountPHI = Builder.CreatePHI(Int8Ty, 2);
+ ShiftAmountPHI->addIncoming(ShiftAmount, BB);
+ PHINode *ValuePHI = Builder.CreatePHI(Int32Ty, 2);
+ ValuePHI->addIncoming(BI->getOperand(0), BB);
+
+ // Subtract the shift amount by one, as we're shifting one this loop
+ // iteration.
+ Value *ShiftAmountSub =
+ Builder.CreateSub(ShiftAmountPHI, ConstantInt::get(Int8Ty, 1));
+ ShiftAmountPHI->addIncoming(ShiftAmountSub, LoopBB);
+
+ // Emit the actual shift instruction. The difference is that this shift
+ // instruction has a constant shift amount, which can be emitted inline
+ // without a library call.
+ Value *ValueShifted;
+ switch (BI->getOpcode()) {
+ case Instruction::Shl:
+ ValueShifted = Builder.CreateShl(ValuePHI, ConstantInt::get(Int32Ty, 1));
+ break;
+ case Instruction::LShr:
+ ValueShifted = Builder.CreateLShr(ValuePHI, ConstantInt::get(Int32Ty, 1));
+ break;
+ case Instruction::AShr:
+ ValueShifted = Builder.CreateAShr(ValuePHI, ConstantInt::get(Int32Ty, 1));
+ break;
+ default:
+ llvm_unreachable("asked to expand an instruction that is not a shift");
+ }
+ ValuePHI->addIncoming(ValueShifted, LoopBB);
+
+ // Branch to either the loop again (if there is more to shift) or to the
+ // basic block after the loop (if all bits are shifted).
+ Value *Cmp2 = Builder.CreateICmpEQ(ShiftAmountSub, Int8Zero);
+ Builder.CreateCondBr(Cmp2, EndBB, LoopBB);
+
+ // Collect the resulting value. This is necessary in the IR but won't produce
+ // any actual instructions.
+ Builder.SetInsertPoint(BI);
+ PHINode *Result = Builder.CreatePHI(Int32Ty, 2);
+ Result->addIncoming(BI->getOperand(0), BB);
+ Result->addIncoming(ValueShifted, LoopBB);
+
+ // Replace the original shift instruction.
+ BI->replaceAllUsesWith(Result);
+ BI->eraseFromParent();
+}
diff --git a/llvm/lib/Target/AVR/AVRTargetMachine.cpp b/llvm/lib/Target/AVR/AVRTargetMachine.cpp
index 0fa8623e2fb7..5be4260ce035 100644
--- a/llvm/lib/Target/AVR/AVRTargetMachine.cpp
+++ b/llvm/lib/Target/AVR/AVRTargetMachine.cpp
@@ -65,6 +65,7 @@ public:
return getTM<AVRTargetMachine>();
}
+ void addIRPasses() override;
bool addInstSelector() override;
void addPreSched2() override;
void addPreEmitPass() override;
@@ -76,6 +77,15 @@ TargetPassConfig *AVRTargetMachine::createPassConfig(PassManagerBase &PM) {
return new AVRPassConfig(*this, PM);
}
+void AVRPassConfig::addIRPasses() {
+ // Expand instructions like
+ // %result = shl i32 %n, %amount
+ // to a loop so that library calls are avoided.
+ addPass(createAVRShiftExpandPass());
+
+ TargetPassConfig::addIRPasses();
+}
+
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAVRTarget() {
// Register the target.
RegisterTargetMachine<AVRTargetMachine> X(getTheAVRTarget());
@@ -83,6 +93,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAVRTarget() {
auto &PR = *PassRegistry::getPassRegistry();
initializeAVRExpandPseudoPass(PR);
initializeAVRRelaxMemPass(PR);
+ initializeAVRShiftExpandPass(PR);
}
const AVRSubtarget *AVRTargetMachine::getSubtargetImpl() const {
diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp
index 1c69fea5962d..bedf68db08ca 100644
--- a/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp
+++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/AVRFixupKinds.h"
+#include "MCTargetDesc/AVRMCExpr.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"
#include "llvm/MC/MCAssembler.h"
@@ -72,6 +73,7 @@ unsigned AVRELFObjectWriter::getRelocType(MCContext &Ctx,
case MCSymbolRefExpr::VK_None:
return ELF::R_AVR_16;
case MCSymbolRefExpr::VK_AVR_NONE:
+ case MCSymbolRefExpr::VK_AVR_PM:
return ELF::R_AVR_16_PM;
case MCSymbolRefExpr::VK_AVR_DIFF16:
return ELF::R_AVR_DIFF16;
diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
index db995e247562..50872d6d7a92 100644
--- a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
+++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
@@ -254,11 +254,8 @@ unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI,
if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
if (MO.isImm()) return static_cast<unsigned>(MO.getImm());
- if (MO.isFPImm())
- return static_cast<unsigned>(APFloat(MO.getFPImm())
- .bitcastToAPInt()
- .getHiBits(32)
- .getLimitedValue());
+ if (MO.isDFPImm())
+ return static_cast<unsigned>(bit_cast<double>(MO.getDFPImm()));
// MO must be an Expr.
assert(MO.isExpr());
diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCELFStreamer.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCELFStreamer.cpp
index 77b49931843b..0743344bc1ed 100644
--- a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCELFStreamer.cpp
+++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCELFStreamer.cpp
@@ -10,14 +10,14 @@
// instructions on to the real streamer.
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "avrmcelfstreamer"
-
#include "MCTargetDesc/AVRMCELFStreamer.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCObjectWriter.h"
+#define DEBUG_TYPE "avrmcelfstreamer"
+
using namespace llvm;
void AVRMCELFStreamer::emitValueForModiferKind(
diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp
index 9eff554a082b..a4f8787e5667 100644
--- a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp
+++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp
@@ -26,6 +26,7 @@ const struct ModifierEntry {
{"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8
{"hlo8", AVRMCExpr::VK_AVR_HH8}, {"hhi8", AVRMCExpr::VK_AVR_HHI8},
+ {"pm", AVRMCExpr::VK_AVR_PM},
{"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8},
{"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8},
@@ -87,6 +88,9 @@ bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result,
MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
if (Modifier != MCSymbolRefExpr::VK_None)
return false;
+ if (Kind == VK_AVR_PM) {
+ Modifier = MCSymbolRefExpr::VK_AVR_PM;
+ }
Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
@@ -131,6 +135,7 @@ int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const {
Value &= 0xff0000;
Value >>= 16;
break;
+ case AVRMCExpr::VK_AVR_PM:
case AVRMCExpr::VK_AVR_GS:
Value >>= 1; // Program memory addresses must always be shifted by one.
break;
@@ -167,6 +172,7 @@ AVR::Fixups AVRMCExpr::getFixupKind() const {
case VK_AVR_PM_HH8:
Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm;
break;
+ case VK_AVR_PM:
case VK_AVR_GS:
Kind = AVR::fixup_16_pm;
break;
diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h
index 3b696bab1715..e35385ebd90a 100644
--- a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h
+++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h
@@ -20,13 +20,14 @@ class AVRMCExpr : public MCTargetExpr {
public:
/// Specifies the type of an expression.
enum VariantKind {
- VK_AVR_None,
+ VK_AVR_None = 0,
VK_AVR_HI8, ///< Corresponds to `hi8()`.
VK_AVR_LO8, ///< Corresponds to `lo8()`.
VK_AVR_HH8, ///< Corresponds to `hlo8() and hh8()`.
VK_AVR_HHI8, ///< Corresponds to `hhi8()`.
+ VK_AVR_PM, ///< Corresponds to `pm()`, reference to program memory.
VK_AVR_PM_LO8, ///< Corresponds to `pm_lo8()`.
VK_AVR_PM_HI8, ///< Corresponds to `pm_hi8()`.
VK_AVR_PM_HH8, ///< Corresponds to `pm_hh8()`.