in llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp [1871:2369]
bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out,
const MCSubtargetInfo *STI) {
MipsTargetStreamer &TOut = getTargetStreamer();
const unsigned Opcode = Inst.getOpcode();
const MCInstrDesc &MCID = getInstDesc(Opcode);
bool ExpandedJalSym = false;
Inst.setLoc(IDLoc);
if (MCID.isBranch() || MCID.isCall()) {
MCOperand Offset;
switch (Opcode) {
default:
break;
case Mips::BBIT0:
case Mips::BBIT032:
case Mips::BBIT1:
case Mips::BBIT132:
assert(hasCnMips() && "instruction only valid for octeon cpus");
LLVM_FALLTHROUGH;
case Mips::BEQ:
case Mips::BNE:
case Mips::BEQ_MM:
case Mips::BNE_MM:
assert(MCID.getNumOperands() == 3 && "unexpected number of operands");
Offset = Inst.getOperand(2);
if (!Offset.isImm())
break; // We'll deal with this situation later on when applying fixups.
if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm()))
return Error(IDLoc, "branch target out of range");
if (offsetToAlignment(Offset.getImm(),
(inMicroMipsMode() ? Align(2) : Align(4))))
return Error(IDLoc, "branch to misaligned address");
break;
case Mips::BGEZ:
case Mips::BGTZ:
case Mips::BLEZ:
case Mips::BLTZ:
case Mips::BGEZAL:
case Mips::BLTZAL:
case Mips::BC1F:
case Mips::BC1T:
case Mips::BGEZ_MM:
case Mips::BGTZ_MM:
case Mips::BLEZ_MM:
case Mips::BLTZ_MM:
case Mips::BGEZAL_MM:
case Mips::BLTZAL_MM:
case Mips::BC1F_MM:
case Mips::BC1T_MM:
case Mips::BC1EQZC_MMR6:
case Mips::BC1NEZC_MMR6:
case Mips::BC2EQZC_MMR6:
case Mips::BC2NEZC_MMR6:
assert(MCID.getNumOperands() == 2 && "unexpected number of operands");
Offset = Inst.getOperand(1);
if (!Offset.isImm())
break; // We'll deal with this situation later on when applying fixups.
if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm()))
return Error(IDLoc, "branch target out of range");
if (offsetToAlignment(Offset.getImm(),
(inMicroMipsMode() ? Align(2) : Align(4))))
return Error(IDLoc, "branch to misaligned address");
break;
case Mips::BGEC: case Mips::BGEC_MMR6:
case Mips::BLTC: case Mips::BLTC_MMR6:
case Mips::BGEUC: case Mips::BGEUC_MMR6:
case Mips::BLTUC: case Mips::BLTUC_MMR6:
case Mips::BEQC: case Mips::BEQC_MMR6:
case Mips::BNEC: case Mips::BNEC_MMR6:
assert(MCID.getNumOperands() == 3 && "unexpected number of operands");
Offset = Inst.getOperand(2);
if (!Offset.isImm())
break; // We'll deal with this situation later on when applying fixups.
if (!isIntN(18, Offset.getImm()))
return Error(IDLoc, "branch target out of range");
if (offsetToAlignment(Offset.getImm(), Align(4)))
return Error(IDLoc, "branch to misaligned address");
break;
case Mips::BLEZC: case Mips::BLEZC_MMR6:
case Mips::BGEZC: case Mips::BGEZC_MMR6:
case Mips::BGTZC: case Mips::BGTZC_MMR6:
case Mips::BLTZC: case Mips::BLTZC_MMR6:
assert(MCID.getNumOperands() == 2 && "unexpected number of operands");
Offset = Inst.getOperand(1);
if (!Offset.isImm())
break; // We'll deal with this situation later on when applying fixups.
if (!isIntN(18, Offset.getImm()))
return Error(IDLoc, "branch target out of range");
if (offsetToAlignment(Offset.getImm(), Align(4)))
return Error(IDLoc, "branch to misaligned address");
break;
case Mips::BEQZC: case Mips::BEQZC_MMR6:
case Mips::BNEZC: case Mips::BNEZC_MMR6:
assert(MCID.getNumOperands() == 2 && "unexpected number of operands");
Offset = Inst.getOperand(1);
if (!Offset.isImm())
break; // We'll deal with this situation later on when applying fixups.
if (!isIntN(23, Offset.getImm()))
return Error(IDLoc, "branch target out of range");
if (offsetToAlignment(Offset.getImm(), Align(4)))
return Error(IDLoc, "branch to misaligned address");
break;
case Mips::BEQZ16_MM:
case Mips::BEQZC16_MMR6:
case Mips::BNEZ16_MM:
case Mips::BNEZC16_MMR6:
assert(MCID.getNumOperands() == 2 && "unexpected number of operands");
Offset = Inst.getOperand(1);
if (!Offset.isImm())
break; // We'll deal with this situation later on when applying fixups.
if (!isInt<8>(Offset.getImm()))
return Error(IDLoc, "branch target out of range");
if (offsetToAlignment(Offset.getImm(), Align(2)))
return Error(IDLoc, "branch to misaligned address");
break;
}
}
// SSNOP is deprecated on MIPS32r6/MIPS64r6
// We still accept it but it is a normal nop.
if (hasMips32r6() && Opcode == Mips::SSNOP) {
std::string ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6";
Warning(IDLoc, "ssnop is deprecated for " + ISA + " and is equivalent to a "
"nop instruction");
}
if (hasCnMips()) {
MCOperand Opnd;
int Imm;
switch (Opcode) {
default:
break;
case Mips::BBIT0:
case Mips::BBIT032:
case Mips::BBIT1:
case Mips::BBIT132:
assert(MCID.getNumOperands() == 3 && "unexpected number of operands");
// The offset is handled above
Opnd = Inst.getOperand(1);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < 0 || Imm > (Opcode == Mips::BBIT0 ||
Opcode == Mips::BBIT1 ? 63 : 31))
return Error(IDLoc, "immediate operand value out of range");
if (Imm > 31) {
Inst.setOpcode(Opcode == Mips::BBIT0 ? Mips::BBIT032
: Mips::BBIT132);
Inst.getOperand(1).setImm(Imm - 32);
}
break;
case Mips::SEQi:
case Mips::SNEi:
assert(MCID.getNumOperands() == 3 && "unexpected number of operands");
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (!isInt<10>(Imm))
return Error(IDLoc, "immediate operand value out of range");
break;
}
}
// Warn on division by zero. We're checking here as all instructions get
// processed here, not just the macros that need expansion.
//
// The MIPS backend models most of the divison instructions and macros as
// three operand instructions. The pre-R6 divide instructions however have
// two operands and explicitly define HI/LO as part of the instruction,
// not in the operands.
unsigned FirstOp = 1;
unsigned SecondOp = 2;
switch (Opcode) {
default:
break;
case Mips::SDivIMacro:
case Mips::UDivIMacro:
case Mips::DSDivIMacro:
case Mips::DUDivIMacro:
if (Inst.getOperand(2).getImm() == 0) {
if (Inst.getOperand(1).getReg() == Mips::ZERO ||
Inst.getOperand(1).getReg() == Mips::ZERO_64)
Warning(IDLoc, "dividing zero by zero");
else
Warning(IDLoc, "division by zero");
}
break;
case Mips::DSDIV:
case Mips::SDIV:
case Mips::UDIV:
case Mips::DUDIV:
case Mips::UDIV_MM:
case Mips::SDIV_MM:
FirstOp = 0;
SecondOp = 1;
LLVM_FALLTHROUGH;
case Mips::SDivMacro:
case Mips::DSDivMacro:
case Mips::UDivMacro:
case Mips::DUDivMacro:
case Mips::DIV:
case Mips::DIVU:
case Mips::DDIV:
case Mips::DDIVU:
case Mips::DIVU_MMR6:
case Mips::DIV_MMR6:
if (Inst.getOperand(SecondOp).getReg() == Mips::ZERO ||
Inst.getOperand(SecondOp).getReg() == Mips::ZERO_64) {
if (Inst.getOperand(FirstOp).getReg() == Mips::ZERO ||
Inst.getOperand(FirstOp).getReg() == Mips::ZERO_64)
Warning(IDLoc, "dividing zero by zero");
else
Warning(IDLoc, "division by zero");
}
break;
}
// For PIC code convert unconditional jump to unconditional branch.
if ((Opcode == Mips::J || Opcode == Mips::J_MM) && inPicMode()) {
MCInst BInst;
BInst.setOpcode(inMicroMipsMode() ? Mips::BEQ_MM : Mips::BEQ);
BInst.addOperand(MCOperand::createReg(Mips::ZERO));
BInst.addOperand(MCOperand::createReg(Mips::ZERO));
BInst.addOperand(Inst.getOperand(0));
Inst = BInst;
}
// This expansion is not in a function called by tryExpandInstruction()
// because the pseudo-instruction doesn't have a distinct opcode.
if ((Opcode == Mips::JAL || Opcode == Mips::JAL_MM) && inPicMode()) {
warnIfNoMacro(IDLoc);
const MCExpr *JalExpr = Inst.getOperand(0).getExpr();
// We can do this expansion if there's only 1 symbol in the argument
// expression.
if (countMCSymbolRefExpr(JalExpr) > 1)
return Error(IDLoc, "jal doesn't support multiple symbols in PIC mode");
// FIXME: This is checking the expression can be handled by the later stages
// of the assembler. We ought to leave it to those later stages.
const MCSymbol *JalSym = getSingleMCSymbol(JalExpr);
if (expandLoadAddress(Mips::T9, Mips::NoRegister, Inst.getOperand(0),
!isGP64bit(), IDLoc, Out, STI))
return true;
MCInst JalrInst;
if (inMicroMipsMode())
JalrInst.setOpcode(IsCpRestoreSet ? Mips::JALRS_MM : Mips::JALR_MM);
else
JalrInst.setOpcode(Mips::JALR);
JalrInst.addOperand(MCOperand::createReg(Mips::RA));
JalrInst.addOperand(MCOperand::createReg(Mips::T9));
if (isJalrRelocAvailable(JalExpr)) {
// As an optimization hint for the linker, before the JALR we add:
// .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol
// tmplabel:
MCSymbol *TmpLabel = getContext().createTempSymbol();
const MCExpr *TmpExpr = MCSymbolRefExpr::create(TmpLabel, getContext());
const MCExpr *RelocJalrExpr =
MCSymbolRefExpr::create(JalSym, MCSymbolRefExpr::VK_None,
getContext(), IDLoc);
TOut.getStreamer().emitRelocDirective(
*TmpExpr, inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
RelocJalrExpr, IDLoc, *STI);
TOut.getStreamer().emitLabel(TmpLabel);
}
Inst = JalrInst;
ExpandedJalSym = true;
}
if (MCID.mayLoad() || MCID.mayStore()) {
// Check the offset of memory operand, if it is a symbol
// reference or immediate we may have to expand instructions.
if (needsExpandMemInst(Inst)) {
const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
switch (MCID.OpInfo[MCID.getNumOperands() - 1].OperandType) {
case MipsII::OPERAND_MEM_SIMM9:
expandMem9Inst(Inst, IDLoc, Out, STI, MCID.mayLoad());
break;
default:
expandMem16Inst(Inst, IDLoc, Out, STI, MCID.mayLoad());
break;
}
return getParser().hasPendingError();
}
}
if (inMicroMipsMode()) {
if (MCID.mayLoad() && Opcode != Mips::LWP_MM) {
// Try to create 16-bit GP relative load instruction.
for (unsigned i = 0; i < MCID.getNumOperands(); i++) {
const MCOperandInfo &OpInfo = MCID.OpInfo[i];
if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) ||
(OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) {
MCOperand &Op = Inst.getOperand(i);
if (Op.isImm()) {
int MemOffset = Op.getImm();
MCOperand &DstReg = Inst.getOperand(0);
MCOperand &BaseReg = Inst.getOperand(1);
if (isInt<9>(MemOffset) && (MemOffset % 4 == 0) &&
getContext().getRegisterInfo()->getRegClass(
Mips::GPRMM16RegClassID).contains(DstReg.getReg()) &&
(BaseReg.getReg() == Mips::GP ||
BaseReg.getReg() == Mips::GP_64)) {
TOut.emitRRI(Mips::LWGP_MM, DstReg.getReg(), Mips::GP, MemOffset,
IDLoc, STI);
return false;
}
}
}
} // for
} // if load
// TODO: Handle this with the AsmOperandClass.PredicateMethod.
MCOperand Opnd;
int Imm;
switch (Opcode) {
default:
break;
case Mips::ADDIUSP_MM:
Opnd = Inst.getOperand(0);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < -1032 || Imm > 1028 || (Imm < 8 && Imm > -12) ||
Imm % 4 != 0)
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::SLL16_MM:
case Mips::SRL16_MM:
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < 1 || Imm > 8)
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::LI16_MM:
Opnd = Inst.getOperand(1);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < -1 || Imm > 126)
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::ADDIUR2_MM:
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (!(Imm == 1 || Imm == -1 ||
((Imm % 4 == 0) && Imm < 28 && Imm > 0)))
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::ANDI16_MM:
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (!(Imm == 128 || (Imm >= 1 && Imm <= 4) || Imm == 7 || Imm == 8 ||
Imm == 15 || Imm == 16 || Imm == 31 || Imm == 32 || Imm == 63 ||
Imm == 64 || Imm == 255 || Imm == 32768 || Imm == 65535))
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::LBU16_MM:
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < -1 || Imm > 14)
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::SB16_MM:
case Mips::SB16_MMR6:
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < 0 || Imm > 15)
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::LHU16_MM:
case Mips::SH16_MM:
case Mips::SH16_MMR6:
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < 0 || Imm > 30 || (Imm % 2 != 0))
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::LW16_MM:
case Mips::SW16_MM:
case Mips::SW16_MMR6:
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < 0 || Imm > 60 || (Imm % 4 != 0))
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::ADDIUPC_MM:
Opnd = Inst.getOperand(1);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if ((Imm % 4 != 0) || !isInt<25>(Imm))
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::LWP_MM:
case Mips::SWP_MM:
if (Inst.getOperand(0).getReg() == Mips::RA)
return Error(IDLoc, "invalid operand for instruction");
break;
case Mips::MOVEP_MM:
case Mips::MOVEP_MMR6: {
unsigned R0 = Inst.getOperand(0).getReg();
unsigned R1 = Inst.getOperand(1).getReg();
bool RegPair = ((R0 == Mips::A1 && R1 == Mips::A2) ||
(R0 == Mips::A1 && R1 == Mips::A3) ||
(R0 == Mips::A2 && R1 == Mips::A3) ||
(R0 == Mips::A0 && R1 == Mips::S5) ||
(R0 == Mips::A0 && R1 == Mips::S6) ||
(R0 == Mips::A0 && R1 == Mips::A1) ||
(R0 == Mips::A0 && R1 == Mips::A2) ||
(R0 == Mips::A0 && R1 == Mips::A3));
if (!RegPair)
return Error(IDLoc, "invalid operand for instruction");
break;
}
}
}
bool FillDelaySlot =
MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder();
if (FillDelaySlot)
TOut.emitDirectiveSetNoReorder();
MacroExpanderResultTy ExpandResult =
tryExpandInstruction(Inst, IDLoc, Out, STI);
switch (ExpandResult) {
case MER_NotAMacro:
Out.emitInstruction(Inst, *STI);
break;
case MER_Success:
break;
case MER_Fail:
return true;
}
// We know we emitted an instruction on the MER_NotAMacro or MER_Success path.
// If we're in microMIPS mode then we must also set EF_MIPS_MICROMIPS.
if (inMicroMipsMode()) {
TOut.setUsesMicroMips();
TOut.updateABIInfo(*this);
}
// If this instruction has a delay slot and .set reorder is active,
// emit a NOP after it.
if (FillDelaySlot) {
TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc, STI);
TOut.emitDirectiveSetReorder();
}
if ((Opcode == Mips::JalOneReg || Opcode == Mips::JalTwoReg ||
ExpandedJalSym) &&
isPicAndNotNxxAbi()) {
if (IsCpRestoreSet) {
// We need a NOP between the JALR and the LW:
// If .set reorder has been used, we've already emitted a NOP.
// If .set noreorder has been used, we need to emit a NOP at this point.
if (!AssemblerOptions.back()->isReorder())
TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc,
STI);
// Load the $gp from the stack.
TOut.emitGPRestore(CpRestoreOffset, IDLoc, STI);
} else
Warning(IDLoc, "no .cprestore used in PIC mode");
}
return false;
}