[llvm] [MIPS]Initial support for MIPS16 assembly. (PR #108681)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 13 21:30:08 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mc
Author: Jesse D (jdeguire)
<details>
<summary>Changes</summary>
Provide support for basic encoding and decoding of MIPS16 instructions without requiring an external assembler. All instructions are supported, including ones with "pseudo register" operands like "addiu $rx, $pc, imm". There are features, however, that still need to be added before MIPS16 is suitable for everyday use. These include delay slot filling, MIPS16 relocations, instruction aliases for things like large immediate values and loading from or storing to labels (like "lw $rx, FOO"), and probably others.
---
Patch is 248.73 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/108681.diff
68 Files Affected:
- (modified) llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp (+439-8)
- (modified) llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp (+380-23)
- (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp (+1)
- (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp (+27-27)
- (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.h (+7-1)
- (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp (+217-1)
- (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h (+43-1)
- (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp (+17-1)
- (modified) llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td (+3-2)
- (modified) llvm/lib/Target/Mips/MicroMipsInstrInfo.td (-5)
- (modified) llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp (+5-1)
- (modified) llvm/lib/Target/Mips/Mips16InstrFormats.td (+40-38)
- (modified) llvm/lib/Target/Mips/Mips16InstrInfo.cpp (+5-4)
- (modified) llvm/lib/Target/Mips/Mips16InstrInfo.td (+889-292)
- (modified) llvm/lib/Target/Mips/MipsAsmPrinter.cpp (+33-1)
- (modified) llvm/lib/Target/Mips/MipsAsmPrinter.h (+4)
- (modified) llvm/lib/Target/Mips/MipsBranchExpansion.cpp (+1-1)
- (modified) llvm/lib/Target/Mips/MipsConstantIslandPass.cpp (+6-1)
- (modified) llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp (+2-1)
- (modified) llvm/lib/Target/Mips/MipsInstrInfo.cpp (+12-9)
- (modified) llvm/lib/Target/Mips/MipsInstrInfo.h (-1)
- (modified) llvm/lib/Target/Mips/MipsInstrInfo.td (+80-23)
- (modified) llvm/lib/Target/Mips/MipsRegisterInfo.cpp (+2)
- (modified) llvm/lib/Target/Mips/MipsRegisterInfo.h (+2)
- (modified) llvm/lib/Target/Mips/MipsRegisterInfo.td (+25-5)
- (modified) llvm/lib/Target/Mips/MipsScheduleGeneric.td (+34-23)
- (modified) llvm/lib/Target/Mips/MipsTargetMachine.cpp (+3)
- (modified) llvm/test/CodeGen/Mips/addi.ll (+7-5)
- (modified) llvm/test/CodeGen/Mips/adjust-callstack-sp.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/align16.ll (+7-5)
- (modified) llvm/test/CodeGen/Mips/alloca16.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/beqzc.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/beqzc1.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/brsize3.ll (+6-17)
- (modified) llvm/test/CodeGen/Mips/brsize3a.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/const4a.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/const6.ll (+3-3)
- (modified) llvm/test/CodeGen/Mips/const6a.ll (+5-5)
- (modified) llvm/test/CodeGen/Mips/dins.ll (+11-15)
- (modified) llvm/test/CodeGen/Mips/div.ll (+2-2)
- (modified) llvm/test/CodeGen/Mips/div_rem.ll (+3-3)
- (modified) llvm/test/CodeGen/Mips/divu.ll (+2-2)
- (modified) llvm/test/CodeGen/Mips/divu_remu.ll (+3-3)
- (modified) llvm/test/CodeGen/Mips/ex2.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/helloworld.ll (+6-4)
- (added) llvm/test/CodeGen/Mips/init-global-base-reg-16.ll (+37)
- (modified) llvm/test/CodeGen/Mips/lcb2.ll (+10-21)
- (modified) llvm/test/CodeGen/Mips/lcb3c.ll (+3-3)
- (modified) llvm/test/CodeGen/Mips/lcb4a.ll (+2-2)
- (modified) llvm/test/CodeGen/Mips/lcb5.ll (+8-8)
- (modified) llvm/test/CodeGen/Mips/rem.ll (+2-2)
- (modified) llvm/test/CodeGen/Mips/remu.ll (+2-2)
- (modified) llvm/test/CodeGen/Mips/sel1c.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/sel2c.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/seleqk.ll (+8-8)
- (modified) llvm/test/CodeGen/Mips/selgek.ll (+8-8)
- (modified) llvm/test/CodeGen/Mips/selltk.ll (+8-8)
- (modified) llvm/test/CodeGen/Mips/selnek.ll (+8-8)
- (modified) llvm/test/CodeGen/Mips/setultk.ll (+3-3)
- (modified) llvm/test/CodeGen/Mips/simplebr.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/sr1.ll (+9-13)
- (modified) llvm/test/CodeGen/Mips/tailcall/tailcall.ll (+13-13)
- (modified) llvm/test/CodeGen/Mips/trap1.ll (+1-1)
- (modified) llvm/test/CodeGen/Mips/whitespace.ll (+2-2)
- (added) llvm/test/MC/Disassembler/Mips/mips16/valid.txt (+167)
- (modified) llvm/test/MC/Mips/micromips-invalid.s (+2-2)
- (modified) llvm/test/MC/Mips/mips16/invalid.s (+208-5)
- (modified) llvm/test/MC/Mips/mips16/valid.s (+170-2)
``````````diff
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 8ab435c6c6fd18..2a443747ec4228 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -206,6 +206,7 @@ class MipsAsmParser : public MCTargetAsmParser {
ParseStatus parseJumpTarget(OperandVector &Operands);
ParseStatus parseInvNum(OperandVector &Operands);
ParseStatus parseRegisterList(OperandVector &Operands);
+ ParseStatus parseSaveRestoreOperands(OperandVector &Operands);
bool searchSymbolAlias(OperandVector &Operands);
@@ -429,6 +430,8 @@ class MipsAsmParser : public MCTargetAsmParser {
int matchMSA128CtrlRegisterName(StringRef Name);
+ int matchPCRegisterName(StringRef Name);
+
unsigned getReg(int RC, int RegNo);
/// Returns the internal register number for the current AT. Also checks if
@@ -582,7 +585,11 @@ class MipsAsmParser : public MCTargetAsmParser {
}
bool isJalrRelocAvailable(const MCExpr *JalExpr) {
- if (!EmitJalrReloc)
+ // FIXME: A similar check was disabled for MIPS16 in
+ // MipsAsmPrinter::emitInstruction(), so disable it here
+ // as well for now to be safe. If this is updated, also
+ // update that FIXME in MipsAsmPrinter.
+ if (!EmitJalrReloc || inMips16Mode())
return false;
MCValue Res;
if (!JalExpr->evaluateAsRelocatable(Res, nullptr, nullptr))
@@ -825,9 +832,14 @@ class MipsOperand : public MCParsedAsmOperand {
RegKind_COP3 = 512, /// COP3
RegKind_COP0 = 1024, /// COP0
/// Potentially any (e.g. $1)
+ // This purposefully does not include RegKind_PC because it is not a real
+ // register and has no number.
RegKind_Numeric = RegKind_GPR | RegKind_FGR | RegKind_FCC | RegKind_MSA128 |
RegKind_MSACtrl | RegKind_COP2 | RegKind_ACC |
- RegKind_CCR | RegKind_HWRegs | RegKind_COP3 | RegKind_COP0
+ RegKind_CCR | RegKind_HWRegs | RegKind_COP3 |
+ RegKind_COP0,
+ RegKind_PC = 2048 /// Program counter (not a real register; used in
+ /// some MIPS16 instructions).
};
private:
@@ -837,6 +849,7 @@ class MipsOperand : public MCParsedAsmOperand {
k_RegisterIndex, /// A register index in one or more RegKind.
k_Token, /// A simple token
k_RegList, /// A physical register list
+ k_SaveRestore, /// Operands used in MIPS16 save/restore instructions
} Kind;
public:
@@ -853,6 +866,7 @@ class MipsOperand : public MCParsedAsmOperand {
case k_Immediate:
case k_RegisterIndex:
case k_Token:
+ case k_SaveRestore:
break;
}
}
@@ -886,12 +900,19 @@ class MipsOperand : public MCParsedAsmOperand {
SmallVector<unsigned, 10> *List;
};
+ struct SaveRestoreOp {
+ unsigned SavedRegsMask;
+ unsigned StaticRegsMask;
+ unsigned Framesize;
+ };
+
union {
struct Token Tok;
struct RegIdxOp RegIdx;
struct ImmOp Imm;
struct MemOp Mem;
struct RegListOp RegList;
+ struct SaveRestoreOp SaveRestore;
};
SMLoc StartLoc, EndLoc;
@@ -931,6 +952,14 @@ class MipsOperand : public MCParsedAsmOperand {
return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index);
}
+ /// Coerce the register to GPR32 and return the real register for the current
+ /// target.
+ unsigned getCPU16Reg() const {
+ assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!");
+ unsigned ClassID = Mips::GPR32RegClassID;
+ return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index);
+ }
+
/// Coerce the register to GPR64 and return the real register for the current
/// target.
unsigned getGPR64Reg() const {
@@ -1115,6 +1144,31 @@ class MipsOperand : public MCParsedAsmOperand {
Inst.addOperand(MCOperand::createReg(getGPRMM16Reg()));
}
+ void addCPU16AsmRegOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getCPU16Reg()));
+ }
+
+ void addCPU16AsmRegPlusSPOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getCPU16Reg()));
+ }
+
+ void addPCPseudoRegOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(Mips::PC));
+ }
+
+ void addSPPseudoRegOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(Mips::SP));
+ }
+
+ void addRAPseudoRegOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(Mips::RA));
+ }
+
/// Render the operand to an MCInst as a GPR64
/// Asserts if the wrong number of operands are requested, or the operand
/// is not a k_RegisterIndex compatible with RegKind_GPR
@@ -1282,6 +1336,20 @@ class MipsOperand : public MCParsedAsmOperand {
addExpr(Inst, Expr);
}
+ void addMips16MemOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+
+ MipsOperand *BaseOp = getMemBase();
+
+ if (BaseOp->isPCPseudoReg())
+ Inst.addOperand(MCOperand::createReg(Mips::PC));
+ else
+ Inst.addOperand(MCOperand::createReg(BaseOp->getCPU16Reg()));
+
+ const MCExpr *Expr = getMemOff();
+ addExpr(Inst, Expr);
+ }
+
void addRegListOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
@@ -1289,6 +1357,30 @@ class MipsOperand : public MCParsedAsmOperand {
Inst.addOperand(MCOperand::createReg(RegNo));
}
+ void addSaveRestoreOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ int RC =
+ (AsmParser.isGP64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID);
+ auto &RegClass = AsmParser.getContext().getRegisterInfo()->getRegClass(RC);
+
+ auto Mask = getSaveRestoreSavedRegs();
+ while (Mask) {
+ unsigned RegNo = RegClass.getRegister(llvm::countr_zero(Mask));
+ Inst.addOperand(MCOperand::createReg(RegNo));
+ Mask &= (Mask - 1);
+ }
+
+ Inst.addOperand(MCOperand::createImm(getSaveRestoreFramesize()));
+
+ Mask = getSaveRestoreStaticRegs();
+ while (Mask) {
+ unsigned RegNo = RegClass.getRegister(llvm::countr_zero(Mask));
+ Inst.addOperand(MCOperand::createReg(RegNo));
+ Mask &= (Mask - 1);
+ }
+ }
+
bool isReg() const override {
// As a special case until we sort out the definition of div/divu, accept
// $0/$zero here so that MCK_ZERO works correctly.
@@ -1397,16 +1489,75 @@ class MipsOperand : public MCParsedAsmOperand {
&& (getMemBase()->getGPR32Reg() == Mips::GP);
}
+ template <unsigned ShiftAmount = 0> bool isMemWithCPU16Base() const {
+ return isMem() && getMemBase()->isCPU16AsmReg() && isConstantMemOff() &&
+ isShiftedUInt<5, ShiftAmount>(getConstantMemOff());
+ }
+
+ bool isMemWithCPU16PCBase() const {
+ return isMem() && getMemBase()->isPCPseudoReg() && isConstantMemOff() &&
+ isShiftedUInt<8, 2>(getConstantMemOff());
+ }
+
+ bool isMemWithCPU16SPBase() const {
+ return isMem() && getMemBase()->isSPPseudoReg() && isConstantMemOff() &&
+ isShiftedUInt<8, 2>(getConstantMemOff());
+ }
+
+ bool isMemWithExtCPU16Base() const {
+ if (!isMem())
+ return false;
+ if (!getMemBase()->isCPU16AsmReg())
+ return false;
+ if (isa<MCTargetExpr>(getMemOff()) ||
+ (isConstantMemOff() && isInt<16>(getConstantMemOff())))
+ return true;
+ MCValue Res;
+ bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, nullptr);
+ return IsReloc && isInt<16>(Res.getConstant());
+ }
+
+ bool isMemWithExtCPU16PCBase() const {
+ if (!isMem())
+ return false;
+ if (!getMemBase()->isPCPseudoReg())
+ return false;
+ if (isa<MCTargetExpr>(getMemOff()) ||
+ (isConstantMemOff() && isInt<16>(getConstantMemOff())))
+ return true;
+ MCValue Res;
+ bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, nullptr);
+ return IsReloc && isInt<16>(Res.getConstant());
+ }
+
+ bool isMemWithExtCPU16SPBase() const {
+ if (!isMem())
+ return false;
+ if (!getMemBase()->isSPPseudoReg())
+ return false;
+ if (isa<MCTargetExpr>(getMemOff()) ||
+ (isConstantMemOff() && isInt<16>(getConstantMemOff())))
+ return true;
+ MCValue Res;
+ bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, nullptr);
+ return IsReloc && isInt<16>(Res.getConstant());
+ }
+
template <unsigned Bits, unsigned ShiftLeftAmount>
bool isScaledUImm() const {
return isConstantImm() &&
isShiftedUInt<Bits, ShiftLeftAmount>(getConstantImm());
}
+ template <unsigned Bits, unsigned ShiftLeftAmount>
+ bool isConstantScaledSImm() const {
+ return isConstantImm() &&
+ isShiftedInt<Bits, ShiftLeftAmount>(getConstantImm());
+ }
+
template <unsigned Bits, unsigned ShiftLeftAmount>
bool isScaledSImm() const {
- if (isConstantImm() &&
- isShiftedInt<Bits, ShiftLeftAmount>(getConstantImm()))
+ if (isConstantScaledSImm<Bits, ShiftLeftAmount>())
return true;
// Operand can also be a symbol or symbol plus
// offset in case of relocations.
@@ -1442,6 +1593,23 @@ class MipsOperand : public MCParsedAsmOperand {
return true;
}
+ bool isSaveRestore16() const {
+ if (!isSaveRestore())
+ return false;
+
+ if (SaveRestore.Framesize == 0 || SaveRestore.Framesize > 128)
+ return false;
+
+ if (SaveRestore.StaticRegsMask != 0)
+ return false;
+
+ // The 16-bit instruction can save only regs $16, $17, and $31.
+ if (SaveRestore.SavedRegsMask & ~0x80030000)
+ return false;
+
+ return true;
+ }
+
bool isInvNum() const { return Kind == k_Immediate; }
bool isLSAImm() const {
@@ -1453,6 +1621,8 @@ class MipsOperand : public MCParsedAsmOperand {
bool isRegList() const { return Kind == k_RegList; }
+ bool isSaveRestore() const { return Kind == k_SaveRestore; }
+
StringRef getToken() const {
assert(Kind == k_Token && "Invalid access!");
return StringRef(Tok.Data, Tok.Length);
@@ -1500,6 +1670,21 @@ class MipsOperand : public MCParsedAsmOperand {
return *(RegList.List);
}
+ unsigned getSaveRestoreSavedRegs() const {
+ assert((Kind == k_SaveRestore) && "Invalid access!");
+ return SaveRestore.SavedRegsMask;
+ }
+
+ unsigned getSaveRestoreStaticRegs() const {
+ assert((Kind == k_SaveRestore) && "Invalid access!");
+ return SaveRestore.StaticRegsMask;
+ }
+
+ unsigned getSaveRestoreFramesize() const {
+ assert((Kind == k_SaveRestore) && "Invalid access!");
+ return SaveRestore.Framesize;
+ }
+
static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S,
MipsAsmParser &Parser) {
auto Op = std::make_unique<MipsOperand>(k_Token, Parser);
@@ -1607,13 +1792,32 @@ class MipsOperand : public MCParsedAsmOperand {
return Op;
}
- bool isGPRZeroAsmReg() const {
+ static std::unique_ptr<MipsOperand>
+ CreateSaveRestore(unsigned SavedRegsMask, unsigned StaticRegsMask,
+ unsigned Framesize, SMLoc StartLoc, SMLoc EndLoc,
+ MipsAsmParser &Parser) {
+ auto Op = std::make_unique<MipsOperand>(k_SaveRestore, Parser);
+ Op->SaveRestore.SavedRegsMask = SavedRegsMask;
+ Op->SaveRestore.StaticRegsMask = StaticRegsMask;
+ Op->SaveRestore.Framesize = Framesize;
+ Op->StartLoc = StartLoc;
+ Op->EndLoc = EndLoc;
+ return Op;
+ }
+
+ static std::unique_ptr<MipsOperand> createPCReg(const MCRegisterInfo *RegInfo,
+ SMLoc S, SMLoc E,
+ MipsAsmParser &Parser) {
+ return CreateReg(0, "pc", RegKind_PC, RegInfo, S, E, Parser);
+ }
+
+ bool isGPRZeroAsmReg() const {
return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index == 0;
}
- bool isGPRNonZeroAsmReg() const {
- return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index > 0 &&
- RegIdx.Index <= 31;
+ bool isGPRNonZeroAsmReg() const {
+ return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index > 0 &&
+ RegIdx.Index <= 31;
}
bool isGPRAsmReg() const {
@@ -1655,6 +1859,41 @@ class MipsOperand : public MCParsedAsmOperand {
(RegIdx.Index >= 5 && RegIdx.Index <= 7));
}
+ bool isCPU16AsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return ((RegIdx.Index >= 2 && RegIdx.Index <= 7) || RegIdx.Index == 16 ||
+ RegIdx.Index == 17);
+ }
+
+ bool isCPU16AsmRegPlusSP() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return ((RegIdx.Index >= 2 && RegIdx.Index <= 7) || RegIdx.Index == 16 ||
+ RegIdx.Index == 17 || RegIdx.Index == 29);
+ }
+
+ // These next three are used in MIPS16 mode to find instructions that perform
+ // operations involving the program counter, SP, or RA. They are "pseudo
+ // registers" because they determine the opcode instead of being encoded as
+ // an operand. In this way, they are part of the instruction mnemonic.
+ bool isPCPseudoReg() const {
+ // "pc" is not a real register and has no number
+ return isRegIdx() && RegIdx.Kind == RegKind_PC;
+ }
+
+ bool isSPPseudoReg() const {
+ // Purposefully do not allow numeric registers; that is, require "$sp"
+ // instead of "$29"
+ return isRegIdx() && RegIdx.Kind == RegKind_GPR && RegIdx.Index == 29;
+ }
+
+ bool isRAPseudoReg() const {
+ // Purposefully do not allow numeric registers; that is, require "$ra"
+ // instead of "$31"
+ return isRegIdx() && RegIdx.Kind == RegKind_GPR && RegIdx.Index == 31;
+ }
+
bool isFGRAsmReg() const {
// AFGR64 is $0-$15 but we handle this in getAFGR64()
return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31;
@@ -1735,6 +1974,13 @@ class MipsOperand : public MCParsedAsmOperand {
OS << Reg << " ";
OS << ">";
break;
+ case k_SaveRestore:
+ OS << "SaveRestore<CallerSaved 0x";
+ OS.write_hex(SaveRestore.SavedRegsMask);
+ OS << ", Framesize " << SaveRestore.Framesize << ", CalleeSaved 0x";
+ OS.write_hex(SaveRestore.StaticRegsMask);
+ OS << ">";
+ break;
}
}
@@ -1771,6 +2017,11 @@ static bool hasShortDelaySlot(MCInst &Inst) {
case Mips::JALRS16_MM:
case Mips::BGEZALS_MM:
case Mips::BLTZALS_MM:
+ case Mips::Jal16:
+ case Mips::Jalx16:
+ case Mips::JrRa16:
+ case Mips::JrRx16:
+ case Mips::JalrRaRx16:
return true;
case Mips::J_MM:
return !Inst.getOperand(0).isReg();
@@ -1988,6 +2239,44 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
if (offsetToAlignment(Offset.getImm(), Align(2)))
return Error(IDLoc, "branch to misaligned address");
break;
+ // MIPS16 extended branches/jumps.
+ // The 16-bit variants do not need handling here because their predicate
+ // methods require a scaled 8-bit constant immediate. The instruction
+ // matcher will fall back to these extended variants as needed.
+ case Mips::BimmX16:
+ case Mips::BteqzX16:
+ case Mips::BtnezX16:
+ assert(MCID.getNumOperands() == 1 && "unexpected number of operands");
+ Offset = Inst.getOperand(0);
+ if (!Offset.isImm())
+ break; // We'll deal with this situation later on when applying fixups.
+ if (!isInt<17>(Offset.getImm()))
+ return Error(IDLoc, "branch target out of range");
+ if (offsetToAlignment(Offset.getImm(), Align(2)))
+ return Error(IDLoc, "branch to misaligned address");
+ break;
+ case Mips::BeqzRxImmX16:
+ case Mips::BnezRxImmX16:
+ 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<17>(Offset.getImm()))
+ return Error(IDLoc, "branch target out of range");
+ if (offsetToAlignment(Offset.getImm(), Align(2)))
+ return Error(IDLoc, "branch to misaligned address");
+ break;
+ case Mips::Jal16:
+ case Mips::Jalx16:
+ assert(MCID.getNumOperands() == 1 && "unexpected number of operands");
+ Offset = Inst.getOperand(0);
+ if (!Offset.isImm())
+ break; // We'll deal with this situation later on when applying fixups.
+ if (!isUInt<28>(Offset.getImm()))
+ return Error(IDLoc, "branch target out of range");
+ if (offsetToAlignment(Offset.getImm(), Align(4)))
+ return Error(IDLoc, "branch to misaligned address");
+ break;
}
}
@@ -2385,6 +2674,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
TOut.setUsesMicroMips();
TOut.updateABIInfo(*this);
}
+ // FIXME: Do something similar for MIPS16?
// If this instruction has a delay slot and .set reorder is active,
// emit a NOP after it.
@@ -6057,6 +6347,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_UImm3_0:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 3-bit unsigned immediate");
+ case Match_UImm3_1:
+ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+ "expected immediate in range 1 ... 8");
case Match_UImm4_0:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 4-bit unsigned immediate");
@@ -6110,6 +6403,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_UImm8_0:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 8-bit unsigned immediate");
+ case Match_SImm8_Lsl3:
+ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+ "expected both 11-bit signed immediate and multiple of 8");
case Match_UImm10_0:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 10-bit unsigned immediate");
@@ -6124,6 +6420,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_UImm16_AltRelaxed:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 16-bit unsigned immediate");
+ case Match_SImm15:
+ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+ "expected 15-bit signed immediate");
case Match_SImm16:
case Match_SImm16_Relaxed:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
@@ -6384,6 +6683,15 @@ int MipsAsmParser::matchMSA128CtrlRegisterName(StringRef Name) {
return CC;
}
+int MipsAsmParser::matchPCRegisterName(StringRef Name) {
+ // Used only in MIPS16; check in case someone was using "pc" as a symbol name
+ // in other MIPS modes.
+ if (inMips16Mode() && Name == "pc")
+ return 0;
+
+ return -1;
+}
+
bool MipsAsmParser::canUseATReg() {
return AssemblerOptions.back()->getATRegIndex() != 0;
}
@@ -6740,6 +7048,13 @@ ParseStatus MipsAsmParser::matchAnyRegisterNameWithoutDollar(
return ParseStatus::Success;
}
+ Index = matchPCRegisterName(Identifier);
+ if (Index != -1) {
+ Operands.push_back(MipsOperand::createPCReg(getContext().getRegisterInfo(),
+ S, getLexer().getLoc(), *this));
+ return ParseStatus::Success;
+ }
+
return ParseStatus::NoMatch;
}
@@ -6927,6 +7242,122 @@ ParseStatus MipsAsmParser::parseRegisterList(OperandVector &Operands) {
return ParseStatus::Success;
}
+ParseStatus MipsAsmParser::parseSaveRestoreOperands(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc OperandsStart = Parser.getTok().getLoc();
+ uint32_t SavedRegMask = 0;
+ uint32_t StaticRegMask = 0;
+ uint32_t *RegMaskPtr = &SavedRegMask;
+ unsigned PrevRegIndex = 0;
+ unsigned Framesize = 0;
+ bool FramesizeSet = false;
+ bool IsRange = false;
+ const llvm::MCRegisterInfo *RegInfo = getContext().getRegisterInfo();
+
+ // MIPS16 Save and Restore instructions are weird and the MIPS16 docs do
+ // ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/108681
More information about the llvm-commits
mailing list