+ emitRX(Mips::LUi, TmpRegNum,
+ isImmOpnd ? MCOperand::createImm(HiOffset)
+ : MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "hi")),
+ IDLoc, Instructions);
+ // Add temp register to base.
+ if (BaseRegNum != Mips::ZERO)
+ emitRRR(Mips::ADDu, TmpRegNum, TmpRegNum, BaseRegNum, IDLoc, Instructions);
+ // And finally, create original instruction with low part
+ // of offset and new base.
+ emitRRX(Inst.getOpcode(), RegOpNum, TmpRegNum,
+ isImmOpnd
+ ? MCOperand::createImm(LoOffset)
+ : MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "lo")),
+ IDLoc, Instructions);
+}
+
+bool
+MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions) {
+ unsigned OpNum = Inst.getNumOperands();
+ unsigned Opcode = Inst.getOpcode();
+ unsigned NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM32_MM : Mips::LWM32_MM;
+
+ assert (Inst.getOperand(OpNum - 1).isImm() &&
+ Inst.getOperand(OpNum - 2).isReg() &&
+ Inst.getOperand(OpNum - 3).isReg() && "Invalid instruction operand.");
+
+ if (OpNum < 8 && Inst.getOperand(OpNum - 1).getImm() <= 60 &&
+ Inst.getOperand(OpNum - 1).getImm() >= 0 &&
+ Inst.getOperand(OpNum - 2).getReg() == Mips::SP &&
+ Inst.getOperand(OpNum - 3).getReg() == Mips::RA)
+ // It can be implemented as SWM16 or LWM16 instruction.
+ NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM16_MM : Mips::LWM16_MM;
+
+ Inst.setOpcode(NewOpcode);
+ Instructions.push_back(Inst);
+ return false;
+}
+
+bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions) {
+ bool EmittedNoMacroWarning = false;
+ unsigned PseudoOpcode = Inst.getOpcode();
+ unsigned SrcReg = Inst.getOperand(0).getReg();
+ const MCOperand &TrgOp = Inst.getOperand(1);
+ const MCExpr *OffsetExpr = Inst.getOperand(2).getExpr();
+
+ unsigned ZeroSrcOpcode, ZeroTrgOpcode;
+ bool ReverseOrderSLT, IsUnsigned, IsLikely, AcceptsEquality;
+
+ unsigned TrgReg;
+ if (TrgOp.isReg())
+ TrgReg = TrgOp.getReg();
+ else if (TrgOp.isImm()) {
+ warnIfNoMacro(IDLoc);
+ EmittedNoMacroWarning = true;
+
+ TrgReg = getATReg(IDLoc);
+ if (!TrgReg)
+ return true;
+
+ switch(PseudoOpcode) {
+ default:
+ llvm_unreachable("unknown opcode for branch pseudo-instruction");
+ case Mips::BLTImmMacro:
+ PseudoOpcode = Mips::BLT;
+ break;
+ case Mips::BLEImmMacro:
+ PseudoOpcode = Mips::BLE;
+ break;
+ case Mips::BGEImmMacro:
+ PseudoOpcode = Mips::BGE;
+ break;
+ case Mips::BGTImmMacro:
+ PseudoOpcode = Mips::BGT;
+ break;
+ case Mips::BLTUImmMacro:
+ PseudoOpcode = Mips::BLTU;
+ break;
+ case Mips::BLEUImmMacro:
+ PseudoOpcode = Mips::BLEU;
+ break;
+ case Mips::BGEUImmMacro:
+ PseudoOpcode = Mips::BGEU;
+ break;
+ case Mips::BGTUImmMacro:
+ PseudoOpcode = Mips::BGTU;
+ break;
+ case Mips::BLTLImmMacro:
+ PseudoOpcode = Mips::BLTL;
+ break;
+ case Mips::BLELImmMacro:
+ PseudoOpcode = Mips::BLEL;
+ break;
+ case Mips::BGELImmMacro:
+ PseudoOpcode = Mips::BGEL;
+ break;
+ case Mips::BGTLImmMacro:
+ PseudoOpcode = Mips::BGTL;
+ break;
+ case Mips::BLTULImmMacro:
+ PseudoOpcode = Mips::BLTUL;
+ break;
+ case Mips::BLEULImmMacro:
+ PseudoOpcode = Mips::BLEUL;
+ break;
+ case Mips::BGEULImmMacro:
+ PseudoOpcode = Mips::BGEUL;
+ break;
+ case Mips::BGTULImmMacro:
+ PseudoOpcode = Mips::BGTUL;
+ break;
+ }
+
+ if (loadImmediate(TrgOp.getImm(), TrgReg, Mips::NoRegister, !isGP64bit(),
+ false, IDLoc, Instructions))
+ return true;
+ }
+
+ switch (PseudoOpcode) {
+ case Mips::BLT:
+ case Mips::BLTU:
+ case Mips::BLTL:
+ case Mips::BLTUL:
+ AcceptsEquality = false;
+ ReverseOrderSLT = false;
+ IsUnsigned = ((PseudoOpcode == Mips::BLTU) || (PseudoOpcode == Mips::BLTUL));
+ IsLikely = ((PseudoOpcode == Mips::BLTL) || (PseudoOpcode == Mips::BLTUL));
+ ZeroSrcOpcode = Mips::BGTZ;
+ ZeroTrgOpcode = Mips::BLTZ;
+ break;
+ case Mips::BLE:
+ case Mips::BLEU:
+ case Mips::BLEL:
+ case Mips::BLEUL:
+ AcceptsEquality = true;
+ ReverseOrderSLT = true;
+ IsUnsigned = ((PseudoOpcode == Mips::BLEU) || (PseudoOpcode == Mips::BLEUL));
+ IsLikely = ((PseudoOpcode == Mips::BLEL) || (PseudoOpcode == Mips::BLEUL));
+ ZeroSrcOpcode = Mips::BGEZ;
+ ZeroTrgOpcode = Mips::BLEZ;
+ break;
+ case Mips::BGE:
+ case Mips::BGEU:
+ case Mips::BGEL:
+ case Mips::BGEUL:
+ AcceptsEquality = true;
+ ReverseOrderSLT = false;
+ IsUnsigned = ((PseudoOpcode == Mips::BGEU) || (PseudoOpcode == Mips::BGEUL));
+ IsLikely = ((PseudoOpcode == Mips::BGEL) || (PseudoOpcode == Mips::BGEUL));
+ ZeroSrcOpcode = Mips::BLEZ;
+ ZeroTrgOpcode = Mips::BGEZ;
+ break;
+ case Mips::BGT:
+ case Mips::BGTU:
+ case Mips::BGTL:
+ case Mips::BGTUL:
+ AcceptsEquality = false;
+ ReverseOrderSLT = true;
+ IsUnsigned = ((PseudoOpcode == Mips::BGTU) || (PseudoOpcode == Mips::BGTUL));
+ IsLikely = ((PseudoOpcode == Mips::BGTL) || (PseudoOpcode == Mips::BGTUL));
+ ZeroSrcOpcode = Mips::BLTZ;
+ ZeroTrgOpcode = Mips::BGTZ;
+ break;
+ default:
+ llvm_unreachable("unknown opcode for branch pseudo-instruction");
+ }
+
+ 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) {
+ emitRX(Mips::BLTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc,
+ Instructions);
+ return false;
+ }
+ if (PseudoOpcode == Mips::BLE) {
+ emitRX(Mips::BLEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc,
+ Instructions);
+ Warning(IDLoc, "branch is always taken");
+ return false;
+ }
+ if (PseudoOpcode == Mips::BGE) {
+ emitRX(Mips::BGEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc,
+ Instructions);
+ Warning(IDLoc, "branch is always taken");
+ return false;
+ }
+ if (PseudoOpcode == Mips::BGT) {
+ emitRX(Mips::BGTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc,
+ Instructions);
+ return false;
+ }
+ if (PseudoOpcode == Mips::BGTU) {
+ emitRRX(Mips::BNE, Mips::ZERO, Mips::ZERO,
+ MCOperand::createExpr(OffsetExpr), IDLoc, Instructions);
+ 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.
+ emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO,
+ MCOperand::createExpr(OffsetExpr), IDLoc, Instructions);
+ 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.
+ emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO,
+ MCOperand::createExpr(OffsetExpr), IDLoc, Instructions);
+ 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.
+ emitRRX(AcceptsEquality ? Mips::BEQ : Mips::BNE,
+ IsSrcRegZero ? TrgReg : SrcReg, Mips::ZERO,
+ MCOperand::createExpr(OffsetExpr), IDLoc, Instructions);
+ 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.
+ emitRX(IsSrcRegZero ? ZeroSrcOpcode : ZeroTrgOpcode,
+ IsSrcRegZero ? TrgReg : SrcReg, MCOperand::createExpr(OffsetExpr),
+ IDLoc, Instructions);
+ 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;
+
+ if (!EmittedNoMacroWarning)
+ 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.
+ emitRRR(IsUnsigned ? Mips::SLTu : Mips::SLT, ATRegNum,
+ ReverseOrderSLT ? TrgReg : SrcReg, ReverseOrderSLT ? SrcReg : TrgReg,
+ IDLoc, Instructions);
+
+ emitRRX(IsLikely ? (AcceptsEquality ? Mips::BEQL : Mips::BNEL)
+ : (AcceptsEquality ? Mips::BEQ : Mips::BNE),
+ ATRegNum, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc,
+ Instructions);
+ return false;
+}
+
+bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions,
+ const bool IsMips64, const bool Signed) {
+ if (hasMips32r6()) {
+ Error(IDLoc, "instruction not supported on mips32r6 or mips64r6");
+ return false;
+ }
+
+ warnIfNoMacro(IDLoc);
+
+ const MCOperand &RsRegOp = Inst.getOperand(0);
+ assert(RsRegOp.isReg() && "expected register operand kind");
+ unsigned RsReg = RsRegOp.getReg();
+
+ const MCOperand &RtRegOp = Inst.getOperand(1);
+ assert(RtRegOp.isReg() && "expected register operand kind");
+ unsigned RtReg = RtRegOp.getReg();
+ unsigned DivOp;
+ unsigned ZeroReg;
+
+ if (IsMips64) {
+ DivOp = Signed ? Mips::DSDIV : Mips::DUDIV;
+ ZeroReg = Mips::ZERO_64;
+ } else {
+ DivOp = Signed ? Mips::SDIV : Mips::UDIV;
+ ZeroReg = Mips::ZERO;
+ }
+
+ bool UseTraps = useTraps();
+
+ if (RsReg == Mips::ZERO || RsReg == Mips::ZERO_64) {
+ if (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64)
+ Warning(IDLoc, "dividing zero by zero");
+ if (IsMips64) {
+ if (Signed && (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64)) {
+ if (UseTraps) {
+ emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, Instructions);
+ return false;
+ }
+
+ emitII(Mips::BREAK, 0x7, 0, IDLoc, Instructions);
+ return false;
+ }