[mips] [IAS] Add support for the B{L,G}{T,E}(U) branch pseudo-instructions.

Summary:
This does not include support for the immediate variants of these pseudo-instructions.
Fixes llvm.org/PR20968.

Reviewers: dsanders

Reviewed By: dsanders

Subscribers: seanbruno, emaste, llvm-commits

Differential Revision: http://reviews.llvm.org/D8537

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239905 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Toma Tabacu
2015-06-17 13:20:24 +00:00
parent 87f93f5387
commit 279a212ca2
5 changed files with 556 additions and 0 deletions

View File

@@ -211,6 +211,9 @@ class MipsAsmParser : public MCTargetAsmParser {
bool expandBranchImm(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
bool expandCondBranches(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
void createNop(bool hasShortDelaySlot, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
@@ -1624,6 +1627,14 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) {
case Mips::JalTwoReg:
case Mips::BneImm:
case Mips::BeqImm:
case Mips::BLT:
case Mips::BLE:
case Mips::BGE:
case Mips::BGT:
case Mips::BLTU:
case Mips::BLEU:
case Mips::BGEU:
case Mips::BGTU:
return true;
default:
return false;
@@ -1653,6 +1664,15 @@ bool MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc,
case Mips::BneImm:
case Mips::BeqImm:
return expandBranchImm(Inst, IDLoc, Instructions);
case Mips::BLT:
case Mips::BLE:
case Mips::BGE:
case Mips::BGT:
case Mips::BLTU:
case Mips::BLEU:
case Mips::BGEU:
case Mips::BGTU:
return expandCondBranches(Inst, IDLoc, Instructions);
}
}
@@ -2222,6 +2242,206 @@ MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc,
return false;
}
bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
unsigned PseudoOpcode = Inst.getOpcode();
unsigned SrcReg = Inst.getOperand(0).getReg();
unsigned TrgReg = Inst.getOperand(1).getReg();
const MCExpr *OffsetExpr = Inst.getOperand(2).getExpr();
unsigned ZeroSrcOpcode, ZeroTrgOpcode;
bool ReverseOrderSLT, IsUnsigned, AcceptsEquality;
switch (PseudoOpcode) {
case Mips::BLT:
case Mips::BLTU:
AcceptsEquality = false;
ReverseOrderSLT = false;
IsUnsigned = (PseudoOpcode == Mips::BLTU);
ZeroSrcOpcode = Mips::BGTZ;
ZeroTrgOpcode = Mips::BLTZ;
break;
case Mips::BLE:
case Mips::BLEU:
AcceptsEquality = true;
ReverseOrderSLT = true;
IsUnsigned = (PseudoOpcode == Mips::BLEU);
ZeroSrcOpcode = Mips::BGEZ;
ZeroTrgOpcode = Mips::BLEZ;
break;
case Mips::BGE:
case Mips::BGEU:
AcceptsEquality = true;
ReverseOrderSLT = false;
IsUnsigned = (PseudoOpcode == Mips::BGEU);
ZeroSrcOpcode = Mips::BLEZ;
ZeroTrgOpcode = Mips::BGEZ;
break;
case Mips::BGT:
case Mips::BGTU:
AcceptsEquality = false;
ReverseOrderSLT = true;
IsUnsigned = (PseudoOpcode == Mips::BGTU);
ZeroSrcOpcode = Mips::BLTZ;
ZeroTrgOpcode = Mips::BGTZ;
break;
default:
llvm_unreachable("unknown opcode for branch pseudo-instruction");
}
MCInst BranchInst;
bool IsTrgRegZero = (TrgReg == Mips::ZERO);
bool IsSrcRegZero = (SrcReg == Mips::ZERO);
if (IsSrcRegZero && IsTrgRegZero) {
// FIXME: All of these Opcode-specific if's are needed for compatibility
// with GAS' behaviour. However, they may not generate the most efficient
// code in some circumstances.
if (PseudoOpcode == Mips::BLT) {
BranchInst.setOpcode(Mips::BLTZ);
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
return false;
}
if (PseudoOpcode == Mips::BLE) {
BranchInst.setOpcode(Mips::BLEZ);
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
Warning(IDLoc, "branch is always taken");
return false;
}
if (PseudoOpcode == Mips::BGE) {
BranchInst.setOpcode(Mips::BGEZ);
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
Warning(IDLoc, "branch is always taken");
return false;
}
if (PseudoOpcode == Mips::BGT) {
BranchInst.setOpcode(Mips::BGTZ);
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
return false;
}
if (PseudoOpcode == Mips::BGTU) {
BranchInst.setOpcode(Mips::BNE);
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
return false;
}
if (AcceptsEquality) {
// If both registers are $0 and the pseudo-branch accepts equality, it
// will always be taken, so we emit an unconditional branch.
BranchInst.setOpcode(Mips::BEQ);
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
Warning(IDLoc, "branch is always taken");
return false;
}
// If both registers are $0 and the pseudo-branch does not accept
// equality, it will never be taken, so we don't have to emit anything.
return false;
}
if (IsSrcRegZero || IsTrgRegZero) {
if ((IsSrcRegZero && PseudoOpcode == Mips::BGTU) ||
(IsTrgRegZero && PseudoOpcode == Mips::BLTU)) {
// If the $rs is $0 and the pseudo-branch is BGTU (0 > x) or
// if the $rt is $0 and the pseudo-branch is BLTU (x < 0),
// the pseudo-branch will never be taken, so we don't emit anything.
// This only applies to unsigned pseudo-branches.
return false;
}
if ((IsSrcRegZero && PseudoOpcode == Mips::BLEU) ||
(IsTrgRegZero && PseudoOpcode == Mips::BGEU)) {
// If the $rs is $0 and the pseudo-branch is BLEU (0 <= x) or
// if the $rt is $0 and the pseudo-branch is BGEU (x >= 0),
// the pseudo-branch will always be taken, so we emit an unconditional
// branch.
// This only applies to unsigned pseudo-branches.
BranchInst.setOpcode(Mips::BEQ);
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
Warning(IDLoc, "branch is always taken");
return false;
}
if (IsUnsigned) {
// If the $rs is $0 and the pseudo-branch is BLTU (0 < x) or
// if the $rt is $0 and the pseudo-branch is BGTU (x > 0),
// the pseudo-branch will be taken only when the non-zero register is
// different from 0, so we emit a BNEZ.
//
// If the $rs is $0 and the pseudo-branch is BGEU (0 >= x) or
// if the $rt is $0 and the pseudo-branch is BLEU (x <= 0),
// the pseudo-branch will be taken only when the non-zero register is
// equal to 0, so we emit a BEQZ.
//
// Because only BLEU and BGEU branch on equality, we can use the
// AcceptsEquality variable to decide when to emit the BEQZ.
BranchInst.setOpcode(AcceptsEquality ? Mips::BEQ : Mips::BNE);
BranchInst.addOperand(
MCOperand::createReg(IsSrcRegZero ? TrgReg : SrcReg));
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
return false;
}
// If we have a signed pseudo-branch and one of the registers is $0,
// we can use an appropriate compare-to-zero branch. We select which one
// to use in the switch statement above.
BranchInst.setOpcode(IsSrcRegZero ? ZeroSrcOpcode : ZeroTrgOpcode);
BranchInst.addOperand(MCOperand::createReg(IsSrcRegZero ? TrgReg : SrcReg));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
return false;
}
// If neither the SrcReg nor the TrgReg are $0, we need AT to perform the
// expansions. If it is not available, we return.
unsigned ATRegNum = getATReg(IDLoc);
if (!ATRegNum)
return true;
warnIfNoMacro(IDLoc);
// SLT fits well with 2 of our 4 pseudo-branches:
// BLT, where $rs < $rt, translates into "slt $at, $rs, $rt" and
// BGT, where $rs > $rt, translates into "slt $at, $rt, $rs".
// If the result of the SLT is 1, we branch, and if it's 0, we don't.
// This is accomplished by using a BNEZ with the result of the SLT.
//
// The other 2 pseudo-branches are opposites of the above 2 (BGE with BLT
// and BLE with BGT), so we change the BNEZ into a a BEQZ.
// Because only BGE and BLE branch on equality, we can use the
// AcceptsEquality variable to decide when to emit the BEQZ.
// Note that the order of the SLT arguments doesn't change between
// opposites.
//
// The same applies to the unsigned variants, except that SLTu is used
// instead of SLT.
MCInst SetInst;
SetInst.setOpcode(IsUnsigned ? Mips::SLTu : Mips::SLT);
SetInst.addOperand(MCOperand::createReg(ATRegNum));
SetInst.addOperand(MCOperand::createReg(ReverseOrderSLT ? TrgReg : SrcReg));
SetInst.addOperand(MCOperand::createReg(ReverseOrderSLT ? SrcReg : TrgReg));
Instructions.push_back(SetInst);
BranchInst.setOpcode(AcceptsEquality ? Mips::BEQ : Mips::BNE);
BranchInst.addOperand(MCOperand::createReg(ATRegNum));
BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
Instructions.push_back(BranchInst);
return false;
}
void MipsAsmParser::createNop(bool hasShortDelaySlot, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
MCInst NopInst;