[llvm] r258527 - [Hexagon] Use general purpose registers to spill pred/mod registers into
Krzysztof Parzyszek via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 22 11:15:58 PST 2016
Author: kparzysz
Date: Fri Jan 22 13:15:58 2016
New Revision: 258527
URL: http://llvm.org/viewvc/llvm-project?rev=258527&view=rev
Log:
[Hexagon] Use general purpose registers to spill pred/mod registers into
Patch by Tobias Edler Von Koch.
Added:
llvm/trunk/test/CodeGen/Hexagon/avoid-predspill.ll
Modified:
llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp
llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h
llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.cpp
llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.td
Modified: llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp?rev=258527&r1=258526&r2=258527&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp Fri Jan 22 13:15:58 2016
@@ -19,6 +19,7 @@
#include "HexagonTargetMachine.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SCCIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -1072,80 +1073,65 @@ static bool needToReserveScavengingSpill
}
-/// Replaces the predicate spill code pseudo instructions by valid instructions.
-bool HexagonFrameLowering::replacePredRegPseudoSpillCode(MachineFunction &MF)
- const {
- auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
- auto &HII = *HST.getInstrInfo();
- MachineRegisterInfo &MRI = MF.getRegInfo();
- bool HasReplacedPseudoInst = false;
- // Replace predicate spill pseudo instructions by real code.
- // Loop over all of the basic blocks.
- for (MachineFunction::iterator MBBb = MF.begin(), MBBe = MF.end();
- MBBb != MBBe; ++MBBb) {
- MachineBasicBlock *MBB = &*MBBb;
- // Traverse the basic block.
- MachineBasicBlock::iterator NextII;
- for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end();
- MII = NextII) {
- MachineInstr *MI = MII;
- NextII = std::next(MII);
- int Opc = MI->getOpcode();
- if (Opc == Hexagon::STriw_pred) {
- HasReplacedPseudoInst = true;
- // STriw_pred FI, 0, SrcReg;
- unsigned VirtReg = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
- unsigned SrcReg = MI->getOperand(2).getReg();
- bool IsOrigSrcRegKilled = MI->getOperand(2).isKill();
-
- assert(MI->getOperand(0).isFI() && "Expect a frame index");
- assert(Hexagon::PredRegsRegClass.contains(SrcReg) &&
- "Not a predicate register");
-
- // Insert transfer to general purpose register.
- // VirtReg = C2_tfrpr SrcPredReg
- BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::C2_tfrpr),
- VirtReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled));
-
- // Change instruction to S2_storeri_io.
- // S2_storeri_io FI, 0, VirtReg
- MI->setDesc(HII.get(Hexagon::S2_storeri_io));
- MI->getOperand(2).setReg(VirtReg);
- MI->getOperand(2).setIsKill();
-
- } else if (Opc == Hexagon::LDriw_pred) {
- // DstReg = LDriw_pred FI, 0
- MachineOperand &M0 = MI->getOperand(0);
- if (M0.isDead()) {
- MBB->erase(MII);
- continue;
- }
+/// Find a GPR register that's available in the range from It to any use of
+/// the 'spill' in FI.
+static bool findAvailableReg(int FI, MachineBasicBlock::iterator It,
+ MachineBasicBlock::iterator End,
+ unsigned *AvailReg,
+ unsigned *NumUses,
+ const TargetRegisterInfo *TRI,
+ RegScavenger *Scavenger) {
+ assert(Scavenger->getCurrentPosition() == It &&
+ "Unexpected scavenger position!");
- unsigned VirtReg = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
- unsigned DestReg = MI->getOperand(0).getReg();
+ BitVector Avail(Scavenger->getRegsAvailable(&Hexagon::IntRegsRegClass));
+ if (Avail.none())
+ return false;
- assert(MI->getOperand(1).isFI() && "Expect a frame index");
- assert(Hexagon::PredRegsRegClass.contains(DestReg) &&
- "Not a predicate register");
-
- // Change instruction to L2_loadri_io.
- // VirtReg = L2_loadri_io FI, 0
- MI->setDesc(HII.get(Hexagon::L2_loadri_io));
- MI->getOperand(0).setReg(VirtReg);
-
- // Insert transfer to general purpose register.
- // DestReg = C2_tfrrp VirtReg
- const MCInstrDesc &D = HII.get(Hexagon::C2_tfrrp);
- BuildMI(*MBB, std::next(MII), MI->getDebugLoc(), D, DestReg)
- .addReg(VirtReg, getKillRegState(true));
- HasReplacedPseudoInst = true;
- }
+ BitVector AvailByLastLoad(Avail.size());
+
+ while (++It != End) {
+ MachineInstr *MI = It;
+ if (MI->isDebugValue())
+ continue;
+
+ // Remove all registers modified by this inst from Avail
+ int Reg = Avail.find_first();
+ while (Reg != -1) {
+ if (MI->modifiesRegister(Reg, TRI))
+ Avail[Reg] = false;
+ else
+ assert(!MI->readsRegister(Reg, TRI) && "Inst reads undefined register");
+
+ Reg = Avail.find_next(Reg);
+ }
+
+ int Opc = MI->getOpcode();
+ // Stop if we find a store that overwrites the current spill in FI
+ if ((Opc == Hexagon::STriw_pred || Opc == Hexagon::STriw_mod) &&
+ MI->getOperand(0).getIndex() == FI)
+ break;
+
+ if ((Opc == Hexagon::LDriw_pred || Opc == Hexagon::LDriw_mod) &&
+ MI->getOperand(1).getIndex() == FI && !MI->getOperand(0).isDead()) {
+ AvailByLastLoad = Avail;
+ ++(*NumUses);
}
+
+ // Give up early if there are no registers available
+ if (AvailByLastLoad.none() && Avail.none())
+ break;
}
- return HasReplacedPseudoInst;
+
+ if (AvailByLastLoad.none())
+ return false;
+
+ *AvailReg = (unsigned) AvailByLastLoad.find_first();
+ return true;
}
+
void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
@@ -1167,13 +1153,13 @@ void HexagonFrameLowering::determineCall
const TargetRegisterClass &RC = Hexagon::IntRegsRegClass;
// Replace predicate register pseudo spill code.
- bool HasReplacedPseudoInst = replacePredRegPseudoSpillCode(MF);
+ bool HasReplacedPseudoInst = replacePseudoRegTransferCode(MF);
// We need to reserve a a spill slot if scavenging could potentially require
// spilling a scavenged register.
if (HasReplacedPseudoInst && needToReserveScavengingSpillSlots(MF, HRI)) {
MachineFrameInfo *MFI = MF.getFrameInfo();
- for (int i=0; i < NumberScavengerSlots; i++)
+ for (int i = 0; i < NumberScavengerSlots; i++)
RS->addScavengingFrameIndex(
MFI->CreateSpillStackObject(RC.getSize(), RC.getAlignment()));
}
@@ -1327,6 +1313,231 @@ bool HexagonFrameLowering::assignCalleeS
}
+/// Expands pseudo instructions that copy/spill/restore registers that cannot
+/// have these operations done directly. For spills/restores, it will attempt
+/// to spill into a general-purpose register, instead of spilling to memory.
+bool HexagonFrameLowering::replacePseudoRegTransferCode(MachineFunction &MF)
+ const {
+ auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
+ auto &HII = *HST.getInstrInfo();
+ auto &HRI = *HST.getRegisterInfo();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ bool HasReplacedPseudoInst = false;
+
+ // We use the register scavenger purely for tracking of available registers
+ // here, but do the 'scavenging' on our own.
+ RegScavenger Scavenger;
+
+ // Map from PredReg spill FIs to GPRs and remaining number of uses
+ DenseMap<int,std::pair<unsigned, unsigned>> FItoRegUses;
+
+ // PredReg FIs that cannot be 'spilled' into GPRs because they are live
+ // across BB boundaries.
+ SmallSet<int, 8> AlwaysSpill;
+
+ // Pred Reg FIs that have been spilled in a block due to shortage of GPRs
+ SmallSet<int, 8> LocallySpilled;
+
+ // Do an SCC traversal of the MachineFunction. This is to make sure we detect
+ // cases where a PredReg *must* be spilled to memory because it is live across
+ // BasicBlock boundaries: we see the reload before the spill and can mark the
+ // PredReg's FI in AlwaysSpill.
+ for (auto It = scc_begin(&MF); !It.isAtEnd(); ++It) {
+ const std::vector<MachineBasicBlock *> &Scc = *It;
+ for (MachineBasicBlock *MBB : Scc) {
+ if (MBB->empty())
+ continue;
+
+ Scavenger.enterBasicBlock(MBB);
+ Scavenger.forward();
+
+ LocallySpilled.clear();
+
+ // Traverse the basic block.
+ MachineBasicBlock::iterator NextII;
+ for (auto MII = MBB->begin(); MII != MBB->end(); MII = NextII) {
+ MachineInstr *MI = MII;
+ NextII = std::next(MII);
+
+ assert(Scavenger.getCurrentPosition() == MII &&
+ "Unexpected scavenger position");
+
+ unsigned Opc = MI->getOpcode();
+ DebugLoc DL = MI->getDebugLoc();
+
+ if (Opc == TargetOpcode::COPY) {
+ unsigned DestReg = MI->getOperand(0).getReg();
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ MachineInstr *EraseMI = nullptr;
+ if (Hexagon::ModRegsRegClass.contains(DestReg) &&
+ Hexagon::ModRegsRegClass.contains(SrcReg)) {
+ unsigned T = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
+ BuildMI(*MBB, MII, DL, HII.get(TargetOpcode::COPY), T)
+ .addOperand(MI->getOperand(1));
+ BuildMI(*MBB, MII, DL, HII.get(TargetOpcode::COPY), DestReg)
+ .addReg(T, RegState::Kill);
+ EraseMI = &*MII;
+ HasReplacedPseudoInst = true;
+ }
+ if (NextII != MBB->end())
+ Scavenger.forward(); // Move to next instruction
+ if (EraseMI)
+ MBB->erase(EraseMI);
+ } else if (Opc == Hexagon::STriw_pred || Opc == Hexagon::STriw_mod) {
+ // STriw_pred FI, 0, SrcReg
+ unsigned SrcReg = MI->getOperand(2).getReg();
+ bool IsOrigSrcRegKilled = MI->getOperand(2).isKill();
+
+ assert(MI->getOperand(0).isFI() && "Expect a frame index");
+ assert((Hexagon::PredRegsRegClass.contains(SrcReg) ||
+ Hexagon::ModRegsRegClass.contains(SrcReg)) &&
+ "Not a predicate or modifier register");
+ int FI = MI->getOperand(0).getIndex();
+
+ assert(!FItoRegUses.count(FI) &&
+ "Still expecting a load of this spilled predicate register!");
+
+ // Check whether we have an available GPR here and all the way to the
+ // reload(s) of this spill
+ unsigned AvailReg, NumUses = 0;
+ if (!AlwaysSpill.count(FI) && findAvailableReg(FI, MII, MBB->end(),
+ &AvailReg, &NumUses, &HRI, &Scavenger)) {
+ // Found a register we can move this into instead of spilling
+ if (Opc == Hexagon::STriw_pred)
+ BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::C2_tfrpr),
+ AvailReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled));
+ else
+ BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::A2_tfrcrr),
+ AvailReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled));
+
+ // Mark the register as used in the function (important for callee
+ // saved registers).
+ BitVector UsedPhysRegsMask = MRI.getUsedPhysRegsMask();
+ UsedPhysRegsMask.set(AvailReg);
+ MRI.setUsedPhysRegMask(UsedPhysRegsMask);
+
+ Scavenger.setRegUsed(AvailReg);
+ if (NextII != MBB->end())
+ Scavenger.forward();
+
+ FItoRegUses[FI] = std::make_pair(AvailReg, NumUses);
+ LocallySpilled.erase(FI);
+
+ MBB->erase(MII);
+ } else {
+ // No register available. Insert actual spill.
+ // VirtReg = C2_tfrpr SrcPredReg
+ unsigned VirtReg =
+ MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
+ if (Opc == Hexagon::STriw_pred)
+ BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::C2_tfrpr),
+ VirtReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled));
+ else
+ BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::A2_tfrcrr),
+ VirtReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled));
+
+ // Change instruction to S2_storeri_io.
+ // S2_storeri_io FI, 0, VirtReg
+ MI->setDesc(HII.get(Hexagon::S2_storeri_io));
+ MI->getOperand(2).setReg(VirtReg);
+ MI->getOperand(2).setIsKill();
+
+ HasReplacedPseudoInst = true;
+
+ if (NextII != MBB->end())
+ Scavenger.forward();
+
+ if (!AlwaysSpill.count(FI))
+ LocallySpilled.insert(FI);
+ }
+ } else if (Opc == Hexagon::LDriw_pred || Opc == Hexagon::LDriw_mod) {
+ // DstReg = LDriw_pred FI, 0
+ unsigned DestReg = MI->getOperand(0).getReg();
+ assert(MI->getOperand(1).isFI() && "Expect a frame index");
+ assert((Hexagon::PredRegsRegClass.contains(DestReg) ||
+ Hexagon::ModRegsRegClass.contains(DestReg)) &&
+ "Not a predicate or modifier register");
+
+ int FI = MI->getOperand(1).getIndex();
+
+ MachineOperand &M0 = MI->getOperand(0);
+ if (M0.isDead()) {
+ if (NextII != MBB->end())
+ Scavenger.forward();
+ MBB->erase(MII);
+ continue;
+ }
+
+ if (FItoRegUses.count(FI)) {
+ // Reload from GPR
+ std::pair<unsigned,unsigned> &SpillInfo = FItoRegUses[FI];
+
+ --SpillInfo.second;
+ bool IsKill = SpillInfo.second == 0;
+ if (Opc == Hexagon::LDriw_pred)
+ BuildMI(*MBB, std::next(MII), MI->getDebugLoc(),
+ HII.get(Hexagon::C2_tfrrp), DestReg).addReg(SpillInfo.first,
+ getKillRegState(IsKill));
+ else
+ BuildMI(*MBB, std::next(MII), MI->getDebugLoc(),
+ HII.get(Hexagon::A2_tfrrcr), DestReg).addReg(SpillInfo.first,
+ getKillRegState(IsKill));
+
+ if (IsKill)
+ FItoRegUses.erase(FI);
+
+ Scavenger.forward(); // Process the newly inserted instruction
+ if (NextII != MBB->end())
+ Scavenger.forward(); // Move to next instruction
+
+ MBB->erase(MII);
+ } else {
+ // Reload from memory
+
+ // If this wasn't spilled previously in this block, the PredReg in
+ // this FI is live across blocks. Make sure it never ends up in a
+ // register.
+ if (!LocallySpilled.count(FI))
+ AlwaysSpill.insert(FI);
+
+ unsigned VirtReg =
+ MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
+
+ // Change instruction to L2_loadri_io.
+ // VirtReg = L2_loadri_io FI, 0
+ MI->setDesc(HII.get(Hexagon::L2_loadri_io));
+ MI->getOperand(0).setReg(VirtReg);
+
+ // Insert transfer to general purpose register.
+ // DestReg = C2_tfrrp VirtReg
+ if (Opc == Hexagon::LDriw_pred)
+ BuildMI(*MBB, std::next(MII), MI->getDebugLoc(),
+ HII.get(Hexagon::C2_tfrrp), DestReg).addReg(VirtReg,
+ getKillRegState(true));
+ else
+ BuildMI(*MBB, std::next(MII), MI->getDebugLoc(),
+ HII.get(Hexagon::A2_tfrrcr), DestReg).addReg(VirtReg,
+ getKillRegState(true));
+
+ Scavenger.forward(); // Process newly inserted instruction
+ if (NextII != MBB->end())
+ Scavenger.forward(); // Move to next instruction
+
+ HasReplacedPseudoInst = true;
+ }
+ } else if (NextII != MBB->end())
+ Scavenger.forward();
+ }
+
+ assert(FItoRegUses.empty() && "PredRegs in GPRs outlast this block!");
+ }
+ }
+
+ return HasReplacedPseudoInst;
+}
+
+
+
void HexagonFrameLowering::expandAlloca(MachineInstr *AI,
const HexagonInstrInfo &HII, unsigned SP, unsigned CF) const {
MachineBasicBlock &MB = *AI->getParent();
Modified: llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h?rev=258527&r1=258526&r2=258527&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h Fri Jan 22 13:15:58 2016
@@ -93,7 +93,7 @@ private:
MachineBasicBlock::iterator At) const;
void adjustForCalleeSavedRegsSpillCall(MachineFunction &MF) const;
- bool replacePredRegPseudoSpillCode(MachineFunction &MF) const;
+ bool replacePseudoRegTransferCode(MachineFunction &MF) const;
bool replaceVecPredRegPseudoSpillCode(MachineFunction &MF) const;
void findShrunkPrologEpilog(MachineFunction &MF, MachineBasicBlock *&PrologB,
Modified: llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.cpp?rev=258527&r1=258526&r2=258527&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.cpp Fri Jan 22 13:15:58 2016
@@ -728,8 +728,12 @@ void HexagonInstrInfo::storeRegToStackSl
.addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
} else if (Hexagon::PredRegsRegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Hexagon::STriw_pred))
- .addFrameIndex(FI).addImm(0)
- .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
+ .addFrameIndex(FI).addImm(0)
+ .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
+ } else if (Hexagon::ModRegsRegClass.hasSubClassEq(RC)) {
+ BuildMI(MBB, I, DL, get(Hexagon::STriw_mod))
+ .addFrameIndex(FI).addImm(0)
+ .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
} else {
llvm_unreachable("Unimplemented");
}
@@ -747,15 +751,18 @@ void HexagonInstrInfo::loadRegFromStackS
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
MFI.getObjectSize(FI), Align);
- if (RC == &Hexagon::IntRegsRegClass) {
+ if (Hexagon::IntRegsRegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Hexagon::L2_loadri_io), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
- } else if (RC == &Hexagon::DoubleRegsRegClass) {
+ } else if (Hexagon::DoubleRegsRegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Hexagon::L2_loadrd_io), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
- } else if (RC == &Hexagon::PredRegsRegClass) {
+ } else if (Hexagon::PredRegsRegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Hexagon::LDriw_pred), DestReg)
- .addFrameIndex(FI).addImm(0).addMemOperand(MMO);
+ .addFrameIndex(FI).addImm(0).addMemOperand(MMO);
+ } else if (Hexagon::ModRegsRegClass.hasSubClassEq(RC)) {
+ BuildMI(MBB, I, DL, get(Hexagon::LDriw_mod), DestReg)
+ .addFrameIndex(FI).addImm(0).addMemOperand(MMO);
} else {
llvm_unreachable("Can't store this register to stack slot");
}
@@ -2461,6 +2468,8 @@ bool HexagonInstrInfo::isValidOffset(uns
// any size. Later pass knows how to handle it.
case Hexagon::STriw_pred:
case Hexagon::LDriw_pred:
+ case Hexagon::STriw_mod:
+ case Hexagon::LDriw_mod:
return true;
case Hexagon::TFR_FI:
Modified: llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.td?rev=258527&r1=258526&r2=258527&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.td (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonInstrInfo.td Fri Jan 22 13:15:58 2016
@@ -2010,6 +2010,12 @@ let isExtendable = 1, opExtendable = 2,
def LDriw_pred : LDInst<(outs PredRegs:$dst),
(ins IntRegs:$addr, s11_2Ext:$off),
".error \"should not emit\"", []>;
+// Load modifier.
+let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 13,
+ isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in
+def LDriw_mod : LDInst<(outs ModRegs:$dst),
+ (ins IntRegs:$addr, s11_2Ext:$off),
+ ".error \"should not emit\"", []>;
let Defs = [R29, R30, R31], Uses = [R30], hasSideEffects = 0 in
def L2_deallocframe : LDInst<(outs), (ins),
@@ -3651,6 +3657,12 @@ let isExtendable = 1, opExtendable = 1,
def STriw_pred : STInst<(outs),
(ins IntRegs:$addr, s11_2Ext:$off, PredRegs:$src1),
".error \"should not emit\"", []>;
+// Store modifier.
+let isExtendable = 1, opExtendable = 1, isExtentSigned = 1, opExtentBits = 13,
+ isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in
+def STriw_mod : STInst<(outs),
+ (ins IntRegs:$addr, s11_2Ext:$off, ModRegs:$src1),
+ ".error \"should not emit\"", []>;
// S2_allocframe: Allocate stack frame.
let Defs = [R29, R30], Uses = [R29, R31, R30],
Added: llvm/trunk/test/CodeGen/Hexagon/avoid-predspill.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/avoid-predspill.ll?rev=258527&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Hexagon/avoid-predspill.ll (added)
+++ llvm/trunk/test/CodeGen/Hexagon/avoid-predspill.ll Fri Jan 22 13:15:58 2016
@@ -0,0 +1,42 @@
+; RUN: llc -march=hexagon -O2 < %s | FileCheck %s
+;
+; This checks that predicate registers are moved to GPRs instead of spilling
+; where possible.
+
+; CHECK: p0 =
+; CHECK-NOT: memw(r29
+
+define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
+entry:
+ %cmp = icmp eq i32 %a, 1
+ %cmp1 = icmp eq i32 %b, 2
+ %or.cond = and i1 %cmp, %cmp1
+ %cmp3 = icmp eq i32 %c, 3
+ %or.cond30 = and i1 %or.cond, %cmp3
+ %cmp5 = icmp eq i32 %d, 4
+ %or.cond31 = and i1 %or.cond30, %cmp5
+ %cmp7 = icmp eq i32 %e, 5
+ %or.cond32 = and i1 %or.cond31, %cmp7
+ %ret.0 = zext i1 %or.cond32 to i32
+ %cmp8 = icmp eq i32 %a, 3
+ %cmp10 = icmp eq i32 %b, 4
+ %or.cond33 = and i1 %cmp8, %cmp10
+ %cmp12 = icmp eq i32 %c, 5
+ %or.cond34 = and i1 %or.cond33, %cmp12
+ %cmp14 = icmp eq i32 %d, 6
+ %or.cond35 = and i1 %or.cond34, %cmp14
+ %cmp16 = icmp eq i32 %e, 7
+ %or.cond36 = and i1 %or.cond35, %cmp16
+ %ret.1 = select i1 %or.cond36, i32 2, i32 %ret.0
+ %cmp21 = icmp eq i32 %b, 8
+ %or.cond37 = and i1 %cmp, %cmp21
+ %cmp23 = icmp eq i32 %c, 2
+ %or.cond38 = and i1 %or.cond37, %cmp23
+ %cmp25 = icmp eq i32 %d, 1
+ %or.cond39 = and i1 %or.cond38, %cmp25
+ %cmp27 = icmp eq i32 %e, 3
+ %or.cond40 = and i1 %or.cond39, %cmp27
+ %ret.2 = select i1 %or.cond40, i32 3, i32 %ret.1
+ ret i32 %ret.2
+}
+
More information about the llvm-commits
mailing list