mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
[AVR] Optimize 16-bit int shift
Reviewed By: dylanmckay Differential Revision: https://reviews.llvm.org/D90092
This commit is contained in:
parent
9b80fe63e4
commit
d588dec200
@ -1402,6 +1402,135 @@ bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool AVRExpandPseudo::expand<AVR::LSLW4Rd>(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(2).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, getKillRegState(DstIsKill));
|
||||||
|
// 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, getKillRegState(DstIsKill));
|
||||||
|
if (ImpIsDead)
|
||||||
|
MI3->getOperand(3).setIsDead();
|
||||||
|
|
||||||
|
MI.eraseFromParent();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool AVRExpandPseudo::expand<AVR::LSLW8Rd>(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(2).isDead();
|
||||||
|
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
|
||||||
|
|
||||||
|
// mov Rh, Rl
|
||||||
|
buildMI(MBB, MBBI, AVR::MOVRdRr)
|
||||||
|
.addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
|
||||||
|
.addReg(DstLoReg, getKillRegState(DstIsKill));
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool AVRExpandPseudo::expand<AVR::LSLW12Rd>(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(2).isDead();
|
||||||
|
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
|
||||||
|
|
||||||
|
// mov Rh, Rl
|
||||||
|
buildMI(MBB, MBBI, AVR::MOVRdRr)
|
||||||
|
.addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
|
||||||
|
.addReg(DstLoReg, getKillRegState(DstIsKill));
|
||||||
|
|
||||||
|
// 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 <>
|
template <>
|
||||||
bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
|
bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
|
||||||
MachineInstr &MI = *MBBI;
|
MachineInstr &MI = *MBBI;
|
||||||
@ -1433,6 +1562,135 @@ bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool AVRExpandPseudo::expand<AVR::LSRW4Rd>(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(2).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, getKillRegState(DstIsKill));
|
||||||
|
// 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, getKillRegState(DstIsKill));
|
||||||
|
if (ImpIsDead)
|
||||||
|
MI3->getOperand(3).setIsDead();
|
||||||
|
|
||||||
|
MI.eraseFromParent();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool AVRExpandPseudo::expand<AVR::LSRW8Rd>(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(2).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;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool AVRExpandPseudo::expand<AVR::LSRW12Rd>(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(2).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 <>
|
template <>
|
||||||
bool AVRExpandPseudo::expand<AVR::RORWRd>(Block &MBB, BlockIt MBBI) {
|
bool AVRExpandPseudo::expand<AVR::RORWRd>(Block &MBB, BlockIt MBBI) {
|
||||||
llvm_unreachable("RORW unimplemented");
|
llvm_unreachable("RORW unimplemented");
|
||||||
@ -1476,6 +1734,39 @@ bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool AVRExpandPseudo::expand<AVR::ASRW8Rd>(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(2).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, getKillRegState(DstIsKill));
|
||||||
|
|
||||||
|
// Move the sign bit to the C flag.
|
||||||
|
buildMI(MBB, MBBI, AVR::ADDRdRr).addReg(DstHiReg)
|
||||||
|
.addReg(DstHiReg, RegState::Define | 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 <>
|
template <>
|
||||||
bool AVRExpandPseudo::expand<AVR::LSLB7Rd>(Block &MBB, BlockIt MBBI) {
|
bool AVRExpandPseudo::expand<AVR::LSLB7Rd>(Block &MBB, BlockIt MBBI) {
|
||||||
MachineInstr &MI = *MBBI;
|
MachineInstr &MI = *MBBI;
|
||||||
@ -1798,10 +2089,17 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
|
|||||||
EXPAND(AVR::ROLBRd);
|
EXPAND(AVR::ROLBRd);
|
||||||
EXPAND(AVR::RORBRd);
|
EXPAND(AVR::RORBRd);
|
||||||
EXPAND(AVR::LSLWRd);
|
EXPAND(AVR::LSLWRd);
|
||||||
|
EXPAND(AVR::LSLW4Rd);
|
||||||
|
EXPAND(AVR::LSLW8Rd);
|
||||||
|
EXPAND(AVR::LSLW12Rd);
|
||||||
EXPAND(AVR::LSRWRd);
|
EXPAND(AVR::LSRWRd);
|
||||||
|
EXPAND(AVR::LSRW4Rd);
|
||||||
|
EXPAND(AVR::LSRW8Rd);
|
||||||
|
EXPAND(AVR::LSRW12Rd);
|
||||||
EXPAND(AVR::RORWRd);
|
EXPAND(AVR::RORWRd);
|
||||||
EXPAND(AVR::ROLWRd);
|
EXPAND(AVR::ROLWRd);
|
||||||
EXPAND(AVR::ASRWRd);
|
EXPAND(AVR::ASRWRd);
|
||||||
|
EXPAND(AVR::ASRW8Rd);
|
||||||
EXPAND(AVR::LSLB7Rd);
|
EXPAND(AVR::LSLB7Rd);
|
||||||
EXPAND(AVR::LSRB7Rd);
|
EXPAND(AVR::LSRB7Rd);
|
||||||
EXPAND(AVR::ASRB7Rd);
|
EXPAND(AVR::ASRB7Rd);
|
||||||
|
@ -334,7 +334,7 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
|
|||||||
llvm_unreachable("Invalid shift opcode");
|
llvm_unreachable("Invalid shift opcode");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimize int8 shifts.
|
// Optimize int8/int16 shifts.
|
||||||
if (VT.getSizeInBits() == 8) {
|
if (VT.getSizeInBits() == 8) {
|
||||||
if (Op.getOpcode() == ISD::SHL && 4 <= ShiftAmount && ShiftAmount < 7) {
|
if (Op.getOpcode() == ISD::SHL && 4 <= ShiftAmount && ShiftAmount < 7) {
|
||||||
// Optimize LSL when 4 <= ShiftAmount <= 6.
|
// Optimize LSL when 4 <= ShiftAmount <= 6.
|
||||||
@ -362,6 +362,50 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
|
|||||||
Victim = DAG.getNode(AVRISD::ASR7, dl, VT, Victim);
|
Victim = DAG.getNode(AVRISD::ASR7, dl, VT, Victim);
|
||||||
ShiftAmount = 0;
|
ShiftAmount = 0;
|
||||||
}
|
}
|
||||||
|
} else if (VT.getSizeInBits() == 16) {
|
||||||
|
if (4 <= ShiftAmount && ShiftAmount < 8)
|
||||||
|
switch (Op.getOpcode()) {
|
||||||
|
case ISD::SHL:
|
||||||
|
Victim = DAG.getNode(AVRISD::LSL4, dl, VT, Victim);
|
||||||
|
ShiftAmount -= 4;
|
||||||
|
break;
|
||||||
|
case ISD::SRL:
|
||||||
|
Victim = DAG.getNode(AVRISD::LSR4, dl, VT, Victim);
|
||||||
|
ShiftAmount -= 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (8 <= ShiftAmount && ShiftAmount < 12)
|
||||||
|
switch (Op.getOpcode()) {
|
||||||
|
case ISD::SHL:
|
||||||
|
Victim = DAG.getNode(AVRISD::LSL8, dl, VT, Victim);
|
||||||
|
ShiftAmount -= 8;
|
||||||
|
break;
|
||||||
|
case ISD::SRL:
|
||||||
|
Victim = DAG.getNode(AVRISD::LSR8, dl, VT, Victim);
|
||||||
|
ShiftAmount -= 8;
|
||||||
|
break;
|
||||||
|
case ISD::SRA:
|
||||||
|
Victim = DAG.getNode(AVRISD::ASR8, dl, VT, Victim);
|
||||||
|
ShiftAmount -= 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (12 <= ShiftAmount)
|
||||||
|
switch (Op.getOpcode()) {
|
||||||
|
case ISD::SHL:
|
||||||
|
Victim = DAG.getNode(AVRISD::LSL12, dl, VT, Victim);
|
||||||
|
ShiftAmount -= 12;
|
||||||
|
break;
|
||||||
|
case ISD::SRL:
|
||||||
|
Victim = DAG.getNode(AVRISD::LSR12, dl, VT, Victim);
|
||||||
|
ShiftAmount -= 12;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ShiftAmount--) {
|
while (ShiftAmount--) {
|
||||||
|
@ -36,8 +36,15 @@ enum NodeType {
|
|||||||
/// TargetExternalSymbol, and TargetGlobalAddress.
|
/// TargetExternalSymbol, and TargetGlobalAddress.
|
||||||
WRAPPER,
|
WRAPPER,
|
||||||
LSL, ///< Logical shift left.
|
LSL, ///< Logical shift left.
|
||||||
|
LSL4, ///< Logical shift left 4 bits.
|
||||||
|
LSL8, ///< Logical shift left 8 bits.
|
||||||
|
LSL12, ///< Logical shift left 12 bits.
|
||||||
LSR, ///< Logical shift right.
|
LSR, ///< Logical shift right.
|
||||||
|
LSR4, ///< Logical shift right 4 bits.
|
||||||
|
LSR8, ///< Logical shift right 8 bits.
|
||||||
|
LSR12, ///< Logical shift right 12 bits.
|
||||||
ASR, ///< Arithmetic shift right.
|
ASR, ///< Arithmetic shift right.
|
||||||
|
ASR8, ///< Arithmetic shift right 8 bits.
|
||||||
LSL7, ///< Logical shift left 7 bits.
|
LSL7, ///< Logical shift left 7 bits.
|
||||||
LSR7, ///< Logical shift right 7 bits.
|
LSR7, ///< Logical shift right 7 bits.
|
||||||
ASR7, ///< Arithmetic shift right 7 bits.
|
ASR7, ///< Arithmetic shift right 7 bits.
|
||||||
|
@ -55,10 +55,17 @@ def AVRselectcc: SDNode<"AVRISD::SELECT_CC", SDT_AVRSelectCC, [SDNPInGlue]>;
|
|||||||
|
|
||||||
// Shift nodes.
|
// Shift nodes.
|
||||||
def AVRlsl : SDNode<"AVRISD::LSL", SDTIntUnaryOp>;
|
def AVRlsl : SDNode<"AVRISD::LSL", SDTIntUnaryOp>;
|
||||||
|
def AVRlsl4 : SDNode<"AVRISD::LSL4", SDTIntUnaryOp>;
|
||||||
|
def AVRlsl8 : SDNode<"AVRISD::LSL8", SDTIntUnaryOp>;
|
||||||
|
def AVRlsl12 : SDNode<"AVRISD::LSL12", SDTIntUnaryOp>;
|
||||||
def AVRlsr : SDNode<"AVRISD::LSR", SDTIntUnaryOp>;
|
def AVRlsr : SDNode<"AVRISD::LSR", SDTIntUnaryOp>;
|
||||||
|
def AVRlsr4 : SDNode<"AVRISD::LSR4", SDTIntUnaryOp>;
|
||||||
|
def AVRlsr8 : SDNode<"AVRISD::LSR8", SDTIntUnaryOp>;
|
||||||
|
def AVRlsr12 : SDNode<"AVRISD::LSR12", SDTIntUnaryOp>;
|
||||||
def AVRrol : SDNode<"AVRISD::ROL", SDTIntUnaryOp>;
|
def AVRrol : SDNode<"AVRISD::ROL", SDTIntUnaryOp>;
|
||||||
def AVRror : SDNode<"AVRISD::ROR", SDTIntUnaryOp>;
|
def AVRror : SDNode<"AVRISD::ROR", SDTIntUnaryOp>;
|
||||||
def AVRasr : SDNode<"AVRISD::ASR", SDTIntUnaryOp>;
|
def AVRasr : SDNode<"AVRISD::ASR", SDTIntUnaryOp>;
|
||||||
|
def AVRasr8 : SDNode<"AVRISD::ASR8", SDTIntUnaryOp>;
|
||||||
def AVRlsl7 : SDNode<"AVRISD::LSL7", SDTIntUnaryOp>;
|
def AVRlsl7 : SDNode<"AVRISD::LSL7", SDTIntUnaryOp>;
|
||||||
def AVRlsr7 : SDNode<"AVRISD::LSR7", SDTIntUnaryOp>;
|
def AVRlsr7 : SDNode<"AVRISD::LSR7", SDTIntUnaryOp>;
|
||||||
def AVRasr7 : SDNode<"AVRISD::ASR7", SDTIntUnaryOp>;
|
def AVRasr7 : SDNode<"AVRISD::ASR7", SDTIntUnaryOp>;
|
||||||
@ -1674,6 +1681,21 @@ Defs = [SREG] in
|
|||||||
"lslb7\t$rd",
|
"lslb7\t$rd",
|
||||||
[(set i8:$rd, (AVRlsl7 i8:$src)), (implicit SREG)]>;
|
[(set i8:$rd, (AVRlsl7 i8:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
|
def LSLW4Rd : Pseudo<(outs DREGS:$rd),
|
||||||
|
(ins DREGS:$src),
|
||||||
|
"lslw4\t$rd",
|
||||||
|
[(set i16:$rd, (AVRlsl4 i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
|
def LSLW8Rd : Pseudo<(outs DREGS:$rd),
|
||||||
|
(ins DREGS:$src),
|
||||||
|
"lslw8\t$rd",
|
||||||
|
[(set i16:$rd, (AVRlsl8 i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
|
def LSLW12Rd : Pseudo<(outs DREGS:$rd),
|
||||||
|
(ins DREGS:$src),
|
||||||
|
"lslw12\t$rd",
|
||||||
|
[(set i16:$rd, (AVRlsl12 i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
def LSRRd : FRd<0b1001,
|
def LSRRd : FRd<0b1001,
|
||||||
0b0100110,
|
0b0100110,
|
||||||
(outs GPR8:$rd),
|
(outs GPR8:$rd),
|
||||||
@ -1691,6 +1713,21 @@ Defs = [SREG] in
|
|||||||
"lsrw\t$rd",
|
"lsrw\t$rd",
|
||||||
[(set i16:$rd, (AVRlsr i16:$src)), (implicit SREG)]>;
|
[(set i16:$rd, (AVRlsr i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
|
def LSRW4Rd : Pseudo<(outs DREGS:$rd),
|
||||||
|
(ins DREGS:$src),
|
||||||
|
"lsrw4\t$rd",
|
||||||
|
[(set i16:$rd, (AVRlsr4 i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
|
def LSRW8Rd : Pseudo<(outs DREGS:$rd),
|
||||||
|
(ins DREGS:$src),
|
||||||
|
"lsrw8\t$rd",
|
||||||
|
[(set i16:$rd, (AVRlsr8 i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
|
def LSRW12Rd : Pseudo<(outs DREGS:$rd),
|
||||||
|
(ins DREGS:$src),
|
||||||
|
"lsrw12\t$rd",
|
||||||
|
[(set i16:$rd, (AVRlsr12 i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
def ASRRd : FRd<0b1001,
|
def ASRRd : FRd<0b1001,
|
||||||
0b0100101,
|
0b0100101,
|
||||||
(outs GPR8:$rd),
|
(outs GPR8:$rd),
|
||||||
@ -1708,6 +1745,11 @@ Defs = [SREG] in
|
|||||||
"asrw\t$rd",
|
"asrw\t$rd",
|
||||||
[(set i16:$rd, (AVRasr i16:$src)), (implicit SREG)]>;
|
[(set i16:$rd, (AVRasr i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
|
def ASRW8Rd : Pseudo<(outs DREGS:$rd),
|
||||||
|
(ins DREGS:$src),
|
||||||
|
"asrw8\t$rd",
|
||||||
|
[(set i16:$rd, (AVRasr8 i16:$src)), (implicit SREG)]>;
|
||||||
|
|
||||||
// Bit rotate operations.
|
// Bit rotate operations.
|
||||||
let Uses = [SREG] in
|
let Uses = [SREG] in
|
||||||
{
|
{
|
||||||
@ -2123,12 +2165,7 @@ def : Pat<(store i16:$src, (i16 (AVRWrapper tglobaladdr:$dst))),
|
|||||||
def : Pat<(i16 (AVRWrapper tblockaddress:$dst)),
|
def : Pat<(i16 (AVRWrapper tblockaddress:$dst)),
|
||||||
(LDIWRdK tblockaddress:$dst)>;
|
(LDIWRdK tblockaddress:$dst)>;
|
||||||
|
|
||||||
// hi-reg truncation : trunc(int16 >> 8)
|
def : Pat<(i8 (trunc (AVRlsr8 DREGS:$src))),
|
||||||
//: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)))))))))),
|
|
||||||
(EXTRACT_SUBREG DREGS:$src, sub_hi)>;
|
(EXTRACT_SUBREG DREGS:$src, sub_hi)>;
|
||||||
|
|
||||||
// :FIXME: DAGCombiner produces an shl node after legalization from these seq:
|
// :FIXME: DAGCombiner produces an shl node after legalization from these seq:
|
||||||
|
@ -178,3 +178,93 @@ define i8 @asr_i8_7(i8 %a) {
|
|||||||
%result = ashr i8 %a, 7
|
%result = ashr i8 %a, 7
|
||||||
ret i8 %result
|
ret i8 %result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define i16 @lsl_i16_5(i16 %a) {
|
||||||
|
; CHECK-LABEL: lsl_i16_5
|
||||||
|
; CHECK: swap r25
|
||||||
|
; CHECK-NEXT: swap r24
|
||||||
|
; CHECK-NEXT: andi r25, 240
|
||||||
|
; CHECK-NEXT: eor r25, r24
|
||||||
|
; CHECK-NEXT: andi r24, 240
|
||||||
|
; CHECK-NEXT: eor r25, r24
|
||||||
|
; CHECK-NEXT: lsl r24
|
||||||
|
; CHECK-NEXT: rol r25
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
%result = shl i16 %a, 5
|
||||||
|
ret i16 %result
|
||||||
|
}
|
||||||
|
|
||||||
|
define i16 @lsl_i16_9(i16 %a) {
|
||||||
|
; CHECK-LABEL: lsl_i16_9
|
||||||
|
; CHECK: mov r25, r24
|
||||||
|
; CHECK-NEXT: clr r24
|
||||||
|
; CHECK-NEXT: lsl r24
|
||||||
|
; CHECK-NEXT: rol r25
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
%result = shl i16 %a, 9
|
||||||
|
ret i16 %result
|
||||||
|
}
|
||||||
|
|
||||||
|
define i16 @lsl_i16_13(i16 %a) {
|
||||||
|
; CHECK-LABEL: lsl_i16_13
|
||||||
|
; CHECK: mov r25, r24
|
||||||
|
; CHECK-NEXT: swap r25
|
||||||
|
; CHECK-NEXT: andi r25, 240
|
||||||
|
; CHECK-NEXT: clr r24
|
||||||
|
; CHECK-NEXT: lsl r24
|
||||||
|
; CHECK-NEXT: rol r25
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
%result = shl i16 %a, 13
|
||||||
|
ret i16 %result
|
||||||
|
}
|
||||||
|
|
||||||
|
define i16 @lsr_i16_5(i16 %a) {
|
||||||
|
; CHECK-LABEL: lsr_i16_5
|
||||||
|
; CHECK: swap r25
|
||||||
|
; CHECK-NEXT: swap r24
|
||||||
|
; CHECK-NEXT: andi r24, 15
|
||||||
|
; CHECK-NEXT: eor r24, r25
|
||||||
|
; CHECK-NEXT: andi r25, 15
|
||||||
|
; CHECK-NEXT: eor r24, r25
|
||||||
|
; CHECK-NEXT: lsr r25
|
||||||
|
; CHECK-NEXT: ror r24
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
%result = lshr i16 %a, 5
|
||||||
|
ret i16 %result
|
||||||
|
}
|
||||||
|
|
||||||
|
define i16 @lsr_i16_9(i16 %a) {
|
||||||
|
; CHECK-LABEL: lsr_i16_9
|
||||||
|
; CHECK: mov r24, r25
|
||||||
|
; CHECK-NEXT: clr r25
|
||||||
|
; CHECK-NEXT: lsr r25
|
||||||
|
; CHECK-NEXT: ror r24
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
%result = lshr i16 %a, 9
|
||||||
|
ret i16 %result
|
||||||
|
}
|
||||||
|
|
||||||
|
define i16 @lsr_i16_13(i16 %a) {
|
||||||
|
; CHECK-LABEL: lsr_i16_13
|
||||||
|
; CHECK: mov r24, r25
|
||||||
|
; CHECK-NEXT: swap r24
|
||||||
|
; CHECK-NEXT: andi r24, 15
|
||||||
|
; CHECK-NEXT: clr r25
|
||||||
|
; CHECK-NEXT: lsr r25
|
||||||
|
; CHECK-NEXT: ror r24
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
%result = lshr i16 %a, 13
|
||||||
|
ret i16 %result
|
||||||
|
}
|
||||||
|
|
||||||
|
define i16 @asr_i16_9(i16 %a) {
|
||||||
|
; CHECK-LABEL: asr_i16_9
|
||||||
|
; CHECK: mov r24, r25
|
||||||
|
; CHECK-NEXT: lsl r25
|
||||||
|
; CHECK-NEXT: sbc r25, r25
|
||||||
|
; CHECK-NEXT: asr r25
|
||||||
|
; CHECK-NEXT: ror r24
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
%result = ashr i16 %a, 9
|
||||||
|
ret i16 %result
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user