summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp')
-rw-r--r--llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp103
1 files changed, 103 insertions, 0 deletions
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 53a94a0c946..26ea086aa36 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -277,6 +277,109 @@ SystemZInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
return Count;
}
+bool SystemZInstrInfo::analyzeCompare(const MachineInstr *MI,
+ unsigned &SrcReg, unsigned &SrcReg2,
+ int &Mask, int &Value) const {
+ assert(MI->isCompare() && "Caller should check that this is a compare");
+
+ // Ignore comparisons involving memory for now.
+ if (MI->getNumExplicitOperands() != 2)
+ return false;
+
+ SrcReg = MI->getOperand(0).getReg();
+ if (MI->getOperand(1).isReg()) {
+ SrcReg2 = MI->getOperand(1).getReg();
+ Value = 0;
+ Mask = ~0;
+ return true;
+ } else if (MI->getOperand(1).isImm()) {
+ SrcReg2 = 0;
+ Value = MI->getOperand(1).getImm();
+ Mask = ~0;
+ return true;
+ }
+ return false;
+}
+
+// Return true if CC is live after MBBI. We can't rely on kill information
+// because of the way InsertBranch is used.
+static bool isCCLiveAfter(MachineBasicBlock::iterator MBBI,
+ const TargetRegisterInfo *TRI) {
+ if (MBBI->killsRegister(SystemZ::CC, TRI))
+ return false;
+
+ MachineBasicBlock *MBB = MBBI->getParent();
+ MachineBasicBlock::iterator MBBE = MBB->end();
+ for (++MBBI; MBBI != MBBE; ++MBBI)
+ if (MBBI->readsRegister(SystemZ::CC, TRI))
+ return true;
+
+ for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
+ SE = MBB->succ_end(); SI != SE; ++SI)
+ if ((*SI)->isLiveIn(SystemZ::CC))
+ return true;
+
+ return false;
+}
+
+bool
+SystemZInstrInfo::optimizeCompareInstr(MachineInstr *Compare,
+ unsigned SrcReg, unsigned SrcReg2,
+ int Mask, int Value,
+ const MachineRegisterInfo *MRI) const {
+ MachineBasicBlock *MBB = Compare->getParent();
+ const TargetRegisterInfo *TRI = &getRegisterInfo();
+
+ // Try to fold a comparison into a following branch, if it is only used once.
+ if (unsigned FusedOpcode = getCompareAndBranch(Compare->getOpcode(),
+ Compare)) {
+ MachineBasicBlock::iterator MBBI = Compare, MBBE = MBB->end();
+ for (++MBBI; MBBI != MBBE; ++MBBI) {
+ if (MBBI->getOpcode() == SystemZ::BRC && !isCCLiveAfter(MBBI, TRI)) {
+ // Read the branch mask and target.
+ MachineOperand CCMask(MBBI->getOperand(0));
+ MachineOperand Target(MBBI->getOperand(1));
+
+ // Clear out all current operands.
+ int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI);
+ assert(CCUse >= 0 && "BRC must use CC");
+ MBBI->RemoveOperand(CCUse);
+ MBBI->RemoveOperand(1);
+ MBBI->RemoveOperand(0);
+
+ // Rebuild MBBI as a fused compare and branch.
+ MBBI->setDesc(get(FusedOpcode));
+ MachineInstrBuilder(*MBB->getParent(), MBBI)
+ .addOperand(Compare->getOperand(0))
+ .addOperand(Compare->getOperand(1))
+ .addOperand(CCMask)
+ .addOperand(Target);
+
+ // Clear any intervening kills of SrcReg and SrcReg2.
+ MBBI = Compare;
+ for (++MBBI; MBBI != MBBE; ++MBBI) {
+ MBBI->clearRegisterKills(SrcReg, TRI);
+ if (SrcReg2)
+ MBBI->clearRegisterKills(SrcReg2, TRI);
+ }
+ Compare->removeFromParent();
+ return true;
+ }
+
+ // Stop if we find another reference to CC before a branch.
+ if (MBBI->readsRegister(SystemZ::CC, TRI) ||
+ MBBI->modifiesRegister(SystemZ::CC, TRI))
+ break;
+
+ // Stop if we find another assignment to the registers before the branch.
+ if (MBBI->modifiesRegister(SrcReg, TRI) ||
+ (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI)))
+ break;
+ }
+ }
+ return false;
+}
+
// If Opcode is a move that has a conditional variant, return that variant,
// otherwise return 0.
static unsigned getConditionalMove(unsigned Opcode) {
OpenPOWER on IntegriCloud