[llvm] [MIPS]Initial support for MIPS16 assembly. (PR #108681)
Jesse D via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 13 21:29:37 PDT 2024
https://github.com/jdeguire created https://github.com/llvm/llvm-project/pull/108681
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.
>From 1b98d634aca5a27299876a4e3125d701348e704e Mon Sep 17 00:00:00 2001
From: Jesse DeGuire <jesse.a.deguire at gmail.com>
Date: Mon, 27 May 2024 14:59:55 -0500
Subject: [PATCH] [MIPS]Initial support for MIPS16 assembly.
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, instructions aliases for things like large immediate values
and loading from or storing to labels (like "lw $rx, FOO").
---
.../Target/Mips/AsmParser/MipsAsmParser.cpp | 447 ++++++-
.../Mips/Disassembler/MipsDisassembler.cpp | 403 +++++-
.../Mips/MCTargetDesc/MipsAsmBackend.cpp | 1 +
.../Mips/MCTargetDesc/MipsInstPrinter.cpp | 54 +-
.../Mips/MCTargetDesc/MipsInstPrinter.h | 8 +-
.../Mips/MCTargetDesc/MipsMCCodeEmitter.cpp | 218 ++-
.../Mips/MCTargetDesc/MipsMCCodeEmitter.h | 44 +-
.../Mips/MCTargetDesc/MipsTargetStreamer.cpp | 18 +-
.../lib/Target/Mips/MicroMips32r6InstrInfo.td | 5 +-
llvm/lib/Target/Mips/MicroMipsInstrInfo.td | 5 -
llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp | 6 +-
llvm/lib/Target/Mips/Mips16InstrFormats.td | 78 +-
llvm/lib/Target/Mips/Mips16InstrInfo.cpp | 9 +-
llvm/lib/Target/Mips/Mips16InstrInfo.td | 1181 +++++++++++++----
llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 34 +-
llvm/lib/Target/Mips/MipsAsmPrinter.h | 4 +
llvm/lib/Target/Mips/MipsBranchExpansion.cpp | 2 +-
.../Target/Mips/MipsConstantIslandPass.cpp | 7 +-
llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp | 3 +-
llvm/lib/Target/Mips/MipsInstrInfo.cpp | 21 +-
llvm/lib/Target/Mips/MipsInstrInfo.h | 1 -
llvm/lib/Target/Mips/MipsInstrInfo.td | 103 +-
llvm/lib/Target/Mips/MipsRegisterInfo.cpp | 2 +
llvm/lib/Target/Mips/MipsRegisterInfo.h | 2 +
llvm/lib/Target/Mips/MipsRegisterInfo.td | 30 +-
llvm/lib/Target/Mips/MipsScheduleGeneric.td | 57 +-
llvm/lib/Target/Mips/MipsTargetMachine.cpp | 3 +
llvm/test/CodeGen/Mips/addi.ll | 12 +-
llvm/test/CodeGen/Mips/adjust-callstack-sp.ll | 2 +-
llvm/test/CodeGen/Mips/align16.ll | 12 +-
llvm/test/CodeGen/Mips/alloca16.ll | 2 +-
llvm/test/CodeGen/Mips/beqzc.ll | 2 +-
llvm/test/CodeGen/Mips/beqzc1.ll | 2 +-
llvm/test/CodeGen/Mips/brsize3.ll | 23 +-
llvm/test/CodeGen/Mips/brsize3a.ll | 2 +-
llvm/test/CodeGen/Mips/const4a.ll | 2 +-
llvm/test/CodeGen/Mips/const6.ll | 6 +-
llvm/test/CodeGen/Mips/const6a.ll | 10 +-
llvm/test/CodeGen/Mips/dins.ll | 26 +-
llvm/test/CodeGen/Mips/div.ll | 4 +-
llvm/test/CodeGen/Mips/div_rem.ll | 6 +-
llvm/test/CodeGen/Mips/divu.ll | 4 +-
llvm/test/CodeGen/Mips/divu_remu.ll | 6 +-
llvm/test/CodeGen/Mips/ex2.ll | 2 +-
llvm/test/CodeGen/Mips/helloworld.ll | 10 +-
.../CodeGen/Mips/init-global-base-reg-16.ll | 37 +
llvm/test/CodeGen/Mips/lcb2.ll | 31 +-
llvm/test/CodeGen/Mips/lcb3c.ll | 6 +-
llvm/test/CodeGen/Mips/lcb4a.ll | 4 +-
llvm/test/CodeGen/Mips/lcb5.ll | 16 +-
llvm/test/CodeGen/Mips/rem.ll | 4 +-
llvm/test/CodeGen/Mips/remu.ll | 4 +-
llvm/test/CodeGen/Mips/sel1c.ll | 2 +-
llvm/test/CodeGen/Mips/sel2c.ll | 2 +-
llvm/test/CodeGen/Mips/seleqk.ll | 16 +-
llvm/test/CodeGen/Mips/selgek.ll | 16 +-
llvm/test/CodeGen/Mips/selltk.ll | 16 +-
llvm/test/CodeGen/Mips/selnek.ll | 16 +-
llvm/test/CodeGen/Mips/setultk.ll | 6 +-
llvm/test/CodeGen/Mips/simplebr.ll | 2 +-
llvm/test/CodeGen/Mips/sr1.ll | 22 +-
llvm/test/CodeGen/Mips/tailcall/tailcall.ll | 26 +-
llvm/test/CodeGen/Mips/trap1.ll | 2 +-
llvm/test/CodeGen/Mips/whitespace.ll | 4 +-
.../MC/Disassembler/Mips/mips16/valid.txt | 167 +++
llvm/test/MC/Mips/micromips-invalid.s | 4 +-
llvm/test/MC/Mips/mips16/invalid.s | 213 ++-
llvm/test/MC/Mips/mips16/valid.s | 172 ++-
68 files changed, 3013 insertions(+), 654 deletions(-)
create mode 100644 llvm/test/CodeGen/Mips/init-global-base-reg-16.ll
create mode 100644 llvm/test/MC/Disassembler/Mips/mips16/valid.txt
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
+ // not provide useful syntax info. This will use a syntax similar to GNU AS:
+ //
+ // save/restore {saved aregs and sregs}, frame size, {static aregs}
+ //
+ // where the saved and static regs are register lists and the frame size
+ // is a mulitple of 8 from 0 to 2040.
+
+ SMLoc TokStart;
+ SMLoc TokEnd;
+ while (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
+ TokStart = Parser.getTok().getLoc();
+ TokEnd = TokStart;
+
+ if (Parser.getTok().is(AsmToken::Dollar)) {
+ MCRegister Reg;
+ if (parseRegister(Reg, TokStart, TokEnd)) {
+ return Error(TokEnd, "expected register operand");
+ }
+
+ unsigned RegIndex = RegInfo->getEncodingValue(Reg);
+ if (RegIndex > 31) {
+ return Error(TokEnd, "invalid register operand");
+ }
+
+ if (IsRange) {
+ uint32_t width = AbsoluteDifference(RegIndex, PrevRegIndex) + 1;
+ uint32_t shift = (RegIndex > PrevRegIndex ? PrevRegIndex : RegIndex);
+
+ *RegMaskPtr |= (maskTrailingOnes<uint32_t>(width) << shift);
+ IsRange = false;
+ } else {
+ *RegMaskPtr |= (1 << RegIndex);
+
+ if (Parser.getTok().is(AsmToken::Minus)) {
+ IsRange = true;
+ Lex(); // eat minus
+ }
+ }
+
+ PrevRegIndex = RegIndex;
+ } else {
+ // If it's not a register, try parsing this as an expression for
+ // presumably the frame size. Any args after the frame size are
+ // static registers.
+ if (FramesizeSet) {
+ return Error(TokEnd, "expected static register");
+ }
+
+ const MCExpr *FramesizeExpr;
+ if (Parser.parseExpression(FramesizeExpr, TokEnd)) {
+ return Error(TokEnd, "expected frame size value");
+ }
+
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(FramesizeExpr);
+ if (nullptr == MCE) {
+ return Error(TokEnd, "frame size not an absolute expression");
+ }
+
+ int64_t FramesizeVal = MCE->getValue();
+ if (FramesizeVal > 2040 || FramesizeVal < 0 || FramesizeVal & 0x07) {
+ return Error(
+ TokEnd,
+ "frame size must be in range 0 .. 2040 and a multiple of 8");
+ }
+
+ RegMaskPtr = &StaticRegMask;
+ Framesize = (unsigned)FramesizeVal;
+ FramesizeSet = true;
+ }
+
+ if (!IsRange) {
+ if (Parser.getTok().isNot(AsmToken::EndOfStatement) &&
+ Parser.getTok().isNot(AsmToken::Comma)) {
+ return Error(Parser.getTok().getLoc(),
+ "unexpected token, expected comma");
+ }
+
+ if (Parser.getTok().is(AsmToken::Comma))
+ Lex(); // eat comma
+ } else if (Parser.getTok().isNot(AsmToken::Dollar)) {
+ return Error(Parser.getTok().getLoc(), "expected end of register range");
+ }
+ }
+
+ TokEnd = Parser.getTok().getLoc();
+
+ if (SavedRegMask & ~0xC0FF00F0) {
+ return Error(TokEnd,
+ "only registers $4-7, $16-23, $30, and $31 can be used");
+ }
+ if (StaticRegMask & ~0xF0) {
+ return Error(TokEnd,
+ "only registers $4-7 can be saved as static registers");
+ }
+ if (SavedRegMask & StaticRegMask) {
+ return Error(TokEnd, "registers cannot be both in saved and static lists");
+ }
+
+ Operands.push_back(MipsOperand::CreateSaveRestore(
+ SavedRegMask, StaticRegMask, Framesize, OperandsStart, TokEnd, *this));
+ return ParseStatus::Success;
+}
+
/// Sometimes (i.e. load/stores) the operand may be followed immediately by
/// either this.
/// ::= '(', register, ')'
diff --git a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
index cda288a25aed5a..2c659b24379549 100644
--- a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
+++ b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
@@ -38,12 +38,13 @@ using DecodeStatus = MCDisassembler::DecodeStatus;
namespace {
class MipsDisassembler : public MCDisassembler {
+ bool IsMips16;
bool IsMicroMips;
bool IsBigEndian;
public:
MipsDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool IsBigEndian)
- : MCDisassembler(STI, Ctx),
+ : MCDisassembler(STI, Ctx), IsMips16(STI.hasFeature(Mips::FeatureMips16)),
IsMicroMips(STI.hasFeature(Mips::FeatureMicroMips)),
IsBigEndian(IsBigEndian) {}
@@ -227,6 +228,30 @@ static DecodeStatus DecodeBranchTarget26MM(MCInst &Inst, unsigned Offset,
uint64_t Address,
const MCDisassembler *Decoder);
+// DecodeBranchTarget8Mips16 - Decode MIPS16 branch offset, which is
+// shifted left by 1 bit.
+static DecodeStatus DecodeBranchTarget8Mips16(MCInst &Inst, unsigned Offset,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+// DecodeBranchTarget11Mips16 - Decode MIPS16 branch offset, which is
+// shifted left by 1 bit.
+static DecodeStatus DecodeBranchTarget11Mips16(MCInst &Inst, unsigned Offset,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+// DecodeBranchTarget16Mips16 - Decode MIPS16 branch offset, which is
+// shifted left by 1 bit.
+static DecodeStatus DecodeBranchTarget16Mips16(MCInst &Inst, unsigned Offset,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+// DecodeJumpTargetMips16 - Decode MIPS16 jump target, which is
+// shifted left by 2 bits.
+static DecodeStatus DecodeJumpTargetMips16(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
// DecodeJumpTargetMM - Decode microMIPS jump target, which is
// shifted left by 1 bit.
static DecodeStatus DecodeJumpTargetMM(MCInst &Inst, unsigned Insn,
@@ -245,6 +270,21 @@ static DecodeStatus DecodeMem(MCInst &Inst, unsigned Insn, uint64_t Address,
static DecodeStatus DecodeMemEVA(MCInst &Inst, unsigned Insn, uint64_t Address,
const MCDisassembler *Decoder);
+template <int ShiftAmount>
+static DecodeStatus DecodeMemMips16(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+template <int ShiftAmount>
+static DecodeStatus DecodeMemSprelMips16(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+template <int ShiftAmount>
+static DecodeStatus DecodeMemPcrelMips16(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
static DecodeStatus DecodeLoadByte15(MCInst &Inst, unsigned Insn,
uint64_t Address,
const MCDisassembler *Decoder);
@@ -339,9 +379,9 @@ static DecodeStatus DecodeLi16Imm(MCInst &Inst, unsigned Value,
uint64_t Address,
const MCDisassembler *Decoder);
-static DecodeStatus DecodePOOL16BEncodedField(MCInst &Inst, unsigned Value,
- uint64_t Address,
- const MCDisassembler *Decoder);
+static DecodeStatus DecodeUImm3Shift(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
template <unsigned Bits, int Offset, int Scale>
static DecodeStatus DecodeUImmWithOffsetAndScale(MCInst &Inst, unsigned Value,
@@ -486,9 +526,33 @@ static DecodeStatus DecodeMovePOperands(MCInst &Inst, unsigned Insn,
uint64_t Address,
const MCDisassembler *Decoder);
-static DecodeStatus DecodeFIXMEInstruction(MCInst &Inst, unsigned Insn,
- uint64_t Address,
- const MCDisassembler *Decoder);
+static DecodeStatus DecodeSaveRestore(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+static DecodeStatus DecodeAddiuRxSpMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+static DecodeStatus DecodeAddiuRxPcMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+static DecodeStatus DecodeAddiuSpMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+static DecodeStatus DecodeJalrRaRxMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+static DecodeStatus DecodeJrRaMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+
+static DecodeStatus DecodeSwRaSpMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
static MCDisassembler *createMipsDisassembler(
const Target &T,
@@ -1123,10 +1187,11 @@ static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
}
/// Read four bytes from the ArrayRef and return 32 bit word sorted
-/// according to the given endianness.
+/// according to the given endianness and whether this is a compressed
+/// ISA (MIPS16 or microMIPS).
static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
uint64_t &Size, uint32_t &Insn,
- bool IsBigEndian, bool IsMicroMips) {
+ bool IsBigEndian, bool IsCompressed) {
// We want to read exactly 4 Bytes of data.
if (Bytes.size() < 4) {
Size = 0;
@@ -1135,9 +1200,10 @@ static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
// High 16 bits of a 32-bit microMIPS instruction (where the opcode is)
// always precede the low 16 bits in the instruction stream (that is, they
- // are placed at lower addresses in the instruction stream).
+ // are placed at lower addresses in the instruction stream). MIPS16 is
+ // similar in that the EXTEND portion is always first in 32-bit instructions.
//
- // microMIPS byte ordering:
+ // microMIPS/MIPS16 byte ordering:
// Big-endian: 0 | 1 | 2 | 3
// Little-endian: 1 | 0 | 3 | 2
@@ -1146,7 +1212,7 @@ static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
Insn =
(Bytes[3] << 0) | (Bytes[2] << 8) | (Bytes[1] << 16) | (Bytes[0] << 24);
} else {
- if (IsMicroMips) {
+ if (IsCompressed) {
Insn = (Bytes[2] << 0) | (Bytes[3] << 8) | (Bytes[0] << 16) |
(Bytes[1] << 24);
} else {
@@ -1166,6 +1232,44 @@ DecodeStatus MipsDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
DecodeStatus Result;
Size = 0;
+ if (IsMips16) {
+ Result = readInstruction16(Bytes, Address, Size, Insn, IsBigEndian);
+ if (Result == MCDisassembler::Fail)
+ return MCDisassembler::Fail;
+
+ LLVM_DEBUG(dbgs() << "Trying Mips16 table (16-bit instructions):\n");
+ // Calling the auto-generated decoder function for MIPS16 16-bit
+ // instructions.
+ Result = decodeInstruction(DecoderTableMips1616, Instr, Insn, Address, this,
+ STI);
+ if (Result != MCDisassembler::Fail) {
+ Size = 2;
+ return Result;
+ }
+
+ Result = readInstruction32(Bytes, Address, Size, Insn, IsBigEndian, true);
+ if (Result == MCDisassembler::Fail)
+ return MCDisassembler::Fail;
+
+ LLVM_DEBUG(dbgs() << "Trying Mips16 table (32-bit instructions):\n");
+ // Calling the auto-generated decoder function for MIPS16 extended
+ // instructions.
+ Result = decodeInstruction(DecoderTableMips1632, Instr, Insn, Address, this,
+ STI);
+ if (Result != MCDisassembler::Fail) {
+ Size = 4;
+ return Result;
+ }
+
+ // This is an invalid instruction. Claim that the Size is 2 bytes. Since
+ // MIPS16 instructions have a minimum alignment of 2, the next 2 bytes
+ // could form a valid instruction. The two bytes we rejected as an
+ // instruction could have actually beeen an inline constant pool that is
+ // unconditionally branched over.
+ Size = 2;
+ return MCDisassembler::Fail;
+ }
+
if (IsMicroMips) {
Result = readInstruction16(Bytes, Address, Size, Insn, IsBigEndian);
if (Result == MCDisassembler::Fail)
@@ -1337,7 +1441,11 @@ DecodeStatus MipsDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
static DecodeStatus
DecodeCPU16RegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
const MCDisassembler *Decoder) {
- return MCDisassembler::Fail;
+ if (RegNo > 7)
+ return MCDisassembler::Fail;
+ unsigned Reg = getReg(Decoder, Mips::CPU16RegsRegClassID, RegNo);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
}
static DecodeStatus DecodeGPR64RegisterClass(MCInst &Inst, unsigned RegNo,
@@ -1498,6 +1606,43 @@ static DecodeStatus DecodeMemEVA(MCInst &Inst, unsigned Insn, uint64_t Address,
return MCDisassembler::Success;
}
+template <int ShiftAmount>
+static DecodeStatus DecodeMemMips16(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ // Value is encoded as ((reg << 16) | offset).
+ // See MipsMCCodeEmitter::getMemEncoding().
+ unsigned Reg =
+ getReg(Decoder, Mips::CPU16RegsRegClassID, (Value >> 16) & 0x07);
+ int Offset = SignExtend32<16>((Value & 0xFFFF) << ShiftAmount);
+
+ Inst.addOperand(MCOperand::createReg(Reg));
+ Inst.addOperand(MCOperand::createImm(Offset));
+ return MCDisassembler::Success;
+}
+
+template <int ShiftAmount>
+static DecodeStatus DecodeMemSprelMips16(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ int Offset = SignExtend32<16>((Value & 0xFFFF) << ShiftAmount);
+
+ Inst.addOperand(MCOperand::createReg(Mips::SP));
+ Inst.addOperand(MCOperand::createImm(Offset));
+ return MCDisassembler::Success;
+}
+
+template <int ShiftAmount>
+static DecodeStatus DecodeMemPcrelMips16(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ int Offset = SignExtend32<16>((Value & 0xFFFF) << ShiftAmount);
+
+ Inst.addOperand(MCOperand::createReg(Mips::PC));
+ Inst.addOperand(MCOperand::createImm(Offset));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus DecodeLoadByte15(MCInst &Inst, unsigned Insn,
uint64_t Address,
const MCDisassembler *Decoder) {
@@ -2184,6 +2329,38 @@ static DecodeStatus DecodeBranchTarget26MM(MCInst &Inst, unsigned Offset,
return MCDisassembler::Success;
}
+static DecodeStatus DecodeBranchTarget8Mips16(MCInst &Inst, unsigned Offset,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ int32_t BranchOffset = SignExtend32<9>(Offset << 1);
+ Inst.addOperand(MCOperand::createImm(BranchOffset));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeBranchTarget11Mips16(MCInst &Inst, unsigned Offset,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ int32_t BranchOffset = SignExtend32<12>(Offset << 1);
+ Inst.addOperand(MCOperand::createImm(BranchOffset));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeBranchTarget16Mips16(MCInst &Inst, unsigned Offset,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ int32_t BranchOffset = SignExtend32<17>(Offset << 1);
+ Inst.addOperand(MCOperand::createImm(BranchOffset));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeJumpTargetMips16(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ unsigned JumpOffset = Value << 2;
+ Inst.addOperand(MCOperand::createImm(JumpOffset));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus DecodeJumpTargetMM(MCInst &Inst, unsigned Insn,
uint64_t Address,
const MCDisassembler *Decoder) {
@@ -2222,9 +2399,9 @@ static DecodeStatus DecodeLi16Imm(MCInst &Inst, unsigned Value,
return MCDisassembler::Success;
}
-static DecodeStatus DecodePOOL16BEncodedField(MCInst &Inst, unsigned Value,
- uint64_t Address,
- const MCDisassembler *Decoder) {
+static DecodeStatus DecodeUImm3Shift(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
Inst.addOperand(MCOperand::createImm(Value == 0x0 ? 8 : Value));
return MCDisassembler::Success;
}
@@ -2518,11 +2695,191 @@ static DecodeStatus DecodeBlezGroupBranchMMR6(MCInst &MI, InsnType insn,
return MCDisassembler::Success;
}
-// This instruction does not have a working decoder, and needs to be
-// fixed. This "fixme" function was introduced to keep the backend compiling,
-// while making changes to tablegen code.
-static DecodeStatus DecodeFIXMEInstruction(MCInst &Inst, unsigned Insn,
- uint64_t Address,
- const MCDisassembler *Decoder) {
- return MCDisassembler::Fail;
+static DecodeStatus DecodeSaveRestore(MCInst &Inst, unsigned Value,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ // This is for the MIPS16 SAVE and RESTORE instructions, which are weird.
+ // See MipsMCCodeEmitter::getSaveRestoreEncoding() for how this was derived.
+ union {
+ struct {
+ unsigned framesize : 8;
+ unsigned s1 : 1;
+ unsigned s0 : 1;
+ unsigned ra : 1;
+ unsigned aregs : 4;
+ unsigned xsregs : 3;
+ } bits;
+ unsigned val;
+ } Encoding;
+
+ Encoding.val = Value;
+
+ if (Encoding.bits.aregs == 15) {
+ // This is undefined.
+ return MCDisassembler::SoftFail;
+ }
+
+ unsigned SavedRegs = 0;
+ unsigned StaticRegs = 0;
+ unsigned FrameSize = Encoding.bits.framesize << 3;
+
+ if (Encoding.bits.s0) // Is $16 saved?
+ SavedRegs |= (1 << 16);
+ if (Encoding.bits.s1) // Is $17 saved?
+ SavedRegs |= (1 << 17);
+ if (Encoding.bits.ra) // Is $31 saved?
+ SavedRegs |= (1 << 31);
+
+ if (Inst.getOpcode() == Mips::SaveX16 ||
+ Inst.getOpcode() == Mips::RestoreX16) {
+ // 'xsregs' indicates which regs in [$18-$23, $30] are saved.
+ unsigned XsregsMask[8] = {0x00000000, 0x00040000, 0x000C0000, 0x001C0000,
+ 0x003C0000, 0x007C0000, 0x00FC0000, 0x40FC0000};
+ SavedRegs |= XsregsMask[Encoding.bits.xsregs];
+
+ // 'aregs' indicates which argument registers are saved and, if so,
+ // if they're caller- or callee-saved (static regs).
+ unsigned AregsStaticsMask[16] = {0x00, 0x80, 0xC0, 0xE0, 0x00, 0x80,
+ 0xC0, 0xE0, 0x00, 0x80, 0xC0, 0xF0,
+ 0x00, 0x80, 0x00, 0x00};
+ StaticRegs = AregsStaticsMask[Encoding.bits.aregs];
+
+ if (Inst.getOpcode() == Mips::SaveX16) {
+ // This applies only to SAVE because RESTORE does not restore these.
+ unsigned AregsSavedMask[16] = {0x00, 0x00, 0x00, 0x00, 0x10, 0x10,
+ 0x10, 0x10, 0x30, 0x30, 0x30, 0x00,
+ 0x70, 0x70, 0xF0, 0x00};
+ SavedRegs |= AregsSavedMask[Encoding.bits.aregs];
+ }
+
+ } else {
+ // The 16-bit versions interpret an encoded frame size of 0 as 128 bytes.
+ if (FrameSize == 0)
+ FrameSize = 128;
+ }
+
+ while (SavedRegs) {
+ unsigned RegNo = llvm::countr_zero(SavedRegs);
+ unsigned Reg = getReg(Decoder, Mips::GPR32RegClassID, RegNo);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ SavedRegs &= (SavedRegs - 1);
+ }
+
+ Inst.addOperand(MCOperand::createImm(FrameSize));
+
+ while (StaticRegs) {
+ unsigned RegNo = llvm::countr_zero(StaticRegs);
+ unsigned Reg = getReg(Decoder, Mips::GPR32RegClassID, RegNo);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ StaticRegs &= (StaticRegs - 1);
+ }
+
+ return MCDisassembler::Success;
+}
+
+static bool InstructionIsMips16Extended(unsigned Insn) {
+ return (Insn & 0xF8000000) == 0xF0000000;
+}
+
+static DecodeStatus DecodeAddiuRxSpMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ unsigned RegNo = fieldFromInstruction(Insn, 8, 3);
+ unsigned Reg = getReg(Decoder, Mips::CPU16RegsRegClassID, RegNo);
+ unsigned Imm;
+
+ Inst.addOperand(MCOperand::createReg(Reg));
+ Inst.addOperand(MCOperand::createReg(Mips::SP));
+
+ if (InstructionIsMips16Extended(Insn)) {
+ Imm = fieldFromInstruction(Insn, 0, 5);
+ Imm |= fieldFromInstruction(Insn, 21, 6) << 5;
+ Imm |= fieldFromInstruction(Insn, 16, 5) << 11;
+ Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Imm)));
+ } else {
+ Imm = fieldFromInstruction(Insn, 0, 8) << 2;
+ Inst.addOperand(MCOperand::createImm(Imm));
+ }
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeAddiuRxPcMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ unsigned RegNo = fieldFromInstruction(Insn, 8, 3);
+ unsigned Reg = getReg(Decoder, Mips::CPU16RegsRegClassID, RegNo);
+ unsigned Imm;
+
+ Inst.addOperand(MCOperand::createReg(Reg));
+ Inst.addOperand(MCOperand::createReg(Mips::PC));
+
+ if (InstructionIsMips16Extended(Insn)) {
+ Imm = fieldFromInstruction(Insn, 0, 5);
+ Imm |= fieldFromInstruction(Insn, 21, 6) << 5;
+ Imm |= fieldFromInstruction(Insn, 16, 5) << 11;
+ Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Imm)));
+ } else {
+ Imm = fieldFromInstruction(Insn, 0, 8) << 2;
+ Inst.addOperand(MCOperand::createImm(Imm));
+ }
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeAddiuSpMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ unsigned Imm;
+
+ Inst.addOperand(MCOperand::createReg(Mips::SP));
+
+ if (InstructionIsMips16Extended(Insn)) {
+ Imm = fieldFromInstruction(Insn, 0, 5);
+ Imm |= fieldFromInstruction(Insn, 21, 6) << 5;
+ Imm |= fieldFromInstruction(Insn, 16, 5) << 11;
+ Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Imm)));
+ } else {
+ Imm = fieldFromInstruction(Insn, 0, 8) << 3;
+ Inst.addOperand(MCOperand::createImm(SignExtend32<11>(Imm)));
+ }
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeJalrRaRxMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ unsigned RegNo = fieldFromInstruction(Insn, 8, 3);
+ unsigned Reg = getReg(Decoder, Mips::CPU16RegsRegClassID, RegNo);
+
+ Inst.addOperand(MCOperand::createReg(Mips::RA));
+ Inst.addOperand(MCOperand::createReg(Reg));
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeJrRaMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ Inst.addOperand(MCOperand::createReg(Mips::RA));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeSwRaSpMips16(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ int Offset;
+
+ Inst.addOperand(MCOperand::createReg(Mips::RA));
+
+ if (InstructionIsMips16Extended(Insn)) {
+ Offset = fieldFromInstruction(Insn, 0, 5);
+ Offset |= fieldFromInstruction(Insn, 21, 6) << 5;
+ Offset |= fieldFromInstruction(Insn, 16, 5) << 11;
+ return DecodeMemSprelMips16<0>(Inst, Offset, Address, Decoder);
+ } else {
+ Offset = fieldFromInstruction(Insn, 0, 8);
+ return DecodeMemSprelMips16<2>(Inst, Offset, Address, Decoder);
+ }
}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index f8172e576ce4c1..816be33f33ccbd 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -589,6 +589,7 @@ bool MipsAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
}
}
+// FIXME: Is something similar needed for MIPS16?
bool MipsAsmBackend::isMicroMips(const MCSymbol *Sym) const {
if (const auto *ElfSym = dyn_cast<const MCSymbolELF>(Sym)) {
if (ElfSym->getOther() & ELF::STO_MIPS_MICROMIPS)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp
index 1518a539782efb..afbf0e457b0bb0 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp
@@ -88,26 +88,6 @@ void MipsInstPrinter::printInst(const MCInst *MI, uint64_t Address,
O << "\t.set\tpush\n";
O << "\t.set\tmips32r2\n";
break;
- case Mips::Save16:
- O << "\tsave\t";
- printSaveRestore(MI, STI, O);
- O << " # 16 bit inst\n";
- return;
- case Mips::SaveX16:
- O << "\tsave\t";
- printSaveRestore(MI, STI, O);
- O << "\n";
- return;
- case Mips::Restore16:
- O << "\trestore\t";
- printSaveRestore(MI, STI, O);
- O << " # 16 bit inst\n";
- return;
- case Mips::RestoreX16:
- O << "\trestore\t";
- printSaveRestore(MI, STI, O);
- O << "\n";
- return;
}
// Try to print any aliases first.
@@ -230,6 +210,27 @@ void MipsInstPrinter::printMemOperandEA(const MCInst *MI, int opNum,
printOperand(MI, opNum + 1, STI, O);
}
+void MipsInstPrinter::printPCPseudoReg(const MCInst *MI, int opNum,
+ const MCSubtargetInfo & /* STI */,
+ raw_ostream &O) {
+ // Not a real operand; instead indicates a PC-realtive MIPS16 instruction.
+ O << "$pc";
+}
+
+void MipsInstPrinter::printSPPseudoReg(const MCInst *MI, int opNum,
+ const MCSubtargetInfo & /* STI */,
+ raw_ostream &O) {
+ // Not a real operand; instead indicates an SP-realtive MIPS16 instruction.
+ O << "$sp";
+}
+
+void MipsInstPrinter::printRAPseudoReg(const MCInst *MI, int opNum,
+ const MCSubtargetInfo & /* STI */,
+ raw_ostream &O) {
+ // Not a real operand; instead indicates the MIPS16 instruction accesses RA.
+ O << "$ra";
+}
+
void MipsInstPrinter::printFCCOperand(const MCInst *MI, int opNum,
const MCSubtargetInfo & /* STI */,
raw_ostream &O) {
@@ -338,15 +339,14 @@ bool MipsInstPrinter::printAlias(const MCInst &MI, uint64_t Address,
}
}
-void MipsInstPrinter::printSaveRestore(const MCInst *MI,
+void MipsInstPrinter::printSaveRestore(const MCInst *MI, int opNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- if (i != 0) O << ", ";
- if (MI->getOperand(i).isReg())
- printRegName(O, MI->getOperand(i).getReg());
- else
- printUImm<16>(MI, i, STI, O);
+ for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {
+ if (i != opNum)
+ O << ", ";
+
+ printOperand(MI, i, STI, O);
}
}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.h
index 0652b237509fe3..48580927ab1171 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.h
@@ -108,6 +108,12 @@ class MipsInstPrinter : public MCInstPrinter {
raw_ostream &O);
void printMemOperandEA(const MCInst *MI, int opNum,
const MCSubtargetInfo &STI, raw_ostream &O);
+ void printPCPseudoReg(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printSPPseudoReg(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printRAPseudoReg(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
+ raw_ostream &O);
void printFCCOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
raw_ostream &O);
void printSHFMask(const MCInst *MI, int opNum, raw_ostream &O);
@@ -120,7 +126,7 @@ class MipsInstPrinter : public MCInstPrinter {
raw_ostream &OS, bool IsBranch = false);
bool printAlias(const MCInst &MI, uint64_t Address,
const MCSubtargetInfo &STI, raw_ostream &OS);
- void printSaveRestore(const MCInst *MI, const MCSubtargetInfo &STI,
+ void printSaveRestore(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
raw_ostream &O);
void printRegisterList(const MCInst *MI, int opNum,
const MCSubtargetInfo &STI, raw_ostream &O);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
index 73ee44eec22cdd..f72333bc29e091 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
@@ -116,6 +116,10 @@ void MipsMCCodeEmitter::LowerCompactBranch(MCInst& Inst) const {
Inst.getOperand(1).setReg(RegOp0);
}
+bool MipsMCCodeEmitter::isMips16(const MCSubtargetInfo &STI) const {
+ return STI.hasFeature(Mips::FeatureMips16);
+}
+
bool MipsMCCodeEmitter::isMicroMips(const MCSubtargetInfo &STI) const {
return STI.hasFeature(Mips::FeatureMicroMips);
}
@@ -210,7 +214,7 @@ void MipsMCCodeEmitter::encodeInstruction(const MCInst &MI,
IsLittleEndian ? llvm::endianness::little : llvm::endianness::big;
if (Size == 2) {
support::endian::write<uint16_t>(CB, Binary, Endian);
- } else if (IsLittleEndian && isMicroMips(STI)) {
+ } else if (IsLittleEndian && (isMips16(STI) || isMicroMips(STI))) {
support::endian::write<uint16_t>(CB, Binary >> 16, Endian);
support::endian::write<uint16_t>(CB, Binary & 0xffff, Endian);
} else {
@@ -372,6 +376,42 @@ getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo,
return 0;
}
+/// getBranchTargetOpValueMips16 - Return binary encoding of the MIPS16
+/// branch target operand. This is for the 16-bit instructions, which
+/// do not support relocations.
+unsigned MipsMCCodeEmitter::getBranchTargetOpValueMips16(
+ const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+
+ // If the destination is an immediate, divide by 2.
+ if (MO.isImm())
+ return MO.getImm() >> 1;
+
+ assert(false &&
+ "getBranchTargetOpValueMips16 expects only constant immediates");
+
+ return 0;
+}
+
+/// getBranchTarget16OpValueMips16 - Return binary encoding of the MIPS16
+/// branch target operand. If the machine operand requires relocation,
+/// record the relocation and return zero.
+unsigned MipsMCCodeEmitter::getBranchTarget16OpValueMips16(
+ const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+
+ // If the destination is an immediate, divide by 2.
+ if (MO.isImm())
+ return MO.getImm() >> 1;
+ // FIXME: This should output a fixup, but MIPS16 fixups are not yet supported.
+ assert(false &&
+ "getBranchTarget16OpValueMips16 expects only constant immediates");
+
+ return 0;
+}
+
/// getBranchTarget21OpValue - Return binary encoding of the branch
/// target operand. If the machine operand requires relocation,
/// record the relocation and return zero.
@@ -518,6 +558,21 @@ getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo,
return 0;
}
+unsigned MipsMCCodeEmitter::getJumpTargetOpValueMips16(
+ const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ // If the destination is an immediate, divide by 4.
+ if (MO.isImm())
+ return MO.getImm() >> 2;
+
+ // FIXME: This should output a fixup, but MIPS16 fixups are not yet supported.
+ assert(false &&
+ "getJumpTargetOpValueMips16 expects only constant immediates");
+
+ return 0;
+}
+
unsigned MipsMCCodeEmitter::
getUImm5Lsl2Encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
@@ -562,6 +617,58 @@ getUImm6Lsl2Encoding(const MCInst &MI, unsigned OpNo,
return 0;
}
+unsigned
+MipsMCCodeEmitter::getUImm8Lsl2Encoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isImm()) {
+ unsigned Value = MO.getImm();
+ return Value >> 2;
+ }
+
+ return 0;
+}
+
+unsigned
+MipsMCCodeEmitter::getSImm8Lsl3Encoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isImm()) {
+ unsigned Value = MO.getImm();
+ return Value >> 3;
+ }
+
+ return 0;
+}
+
+unsigned
+MipsMCCodeEmitter::getSImm11Lsl1Encoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isImm()) {
+ unsigned Value = MO.getImm();
+ return Value >> 1;
+ }
+
+ return 0;
+}
+
+unsigned
+MipsMCCodeEmitter::getSImm16Lsl1Encoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isImm()) {
+ unsigned Value = MO.getImm();
+ return Value >> 1;
+ }
+
+ return 0;
+}
+
unsigned MipsMCCodeEmitter::
getSImm9AddiuspValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
@@ -598,6 +705,7 @@ getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
if (Kind == MCExpr::Target) {
const MipsMCExpr *MipsExpr = cast<MipsMCExpr>(Expr);
+ // FIXME: Need to add MIPS16 fixups to these cases once support is added.
Mips::Fixups FixupKind = Mips::Fixups(0);
switch (MipsExpr->getKind()) {
case MipsMCExpr::MEK_None:
@@ -737,6 +845,114 @@ getMachineOpValue(const MCInst &MI, const MCOperand &MO,
return getExprOpValue(MO.getExpr(),Fixups, STI);
}
+/// Return binary encoding of MIPS16 save and restore operands.
+unsigned
+MipsMCCodeEmitter::getSaveRestoreEncoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ union {
+ struct {
+ unsigned framesize : 8;
+ unsigned s1 : 1;
+ unsigned s0 : 1;
+ unsigned ra : 1;
+ unsigned aregs : 4;
+ unsigned xsregs : 3;
+ } bits;
+ unsigned val;
+ } Encoding;
+
+ Encoding.val = 0;
+
+ // The number of caller-saved regs for 'aregs' and saved 'xsregs' is
+ // determined by the largest register number in the list. That is [$4-7] for
+ // 'aregs' and [$18-23, $30] for 'xsregs'. All other regs below those are
+ // implicitly handled. For example, reg $6 would also handle regs $4 and $5
+ // even if they were not called out in the assembly code.
+ // This is similar for the static registers in 'aregs', but the count is
+ // determined by the smallest register number. For example, if only reg $4
+ // were specified, then the other three argument regs would be handled.
+ unsigned NumAregArgs = 0;
+ unsigned NumAregStatics = 0;
+ unsigned NumXsRegs = 0;
+
+ // Get saved "$s_" regs (xsregs) and caller-saved argument regs.
+ while (OpNo < MI.getNumOperands() && MI.getOperand(OpNo).isReg()) {
+ switch (MI.getOperand(OpNo).getReg()) {
+ default: {
+ unsigned RegIdx = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI);
+ if (NumXsRegs < (RegIdx - 17))
+ NumXsRegs = RegIdx - 17;
+ break;
+ }
+ case Mips::A0:
+ case Mips::A0_64:
+ if (NumAregArgs < 1)
+ NumAregArgs = 1;
+ break;
+ case Mips::A1:
+ case Mips::A1_64:
+ if (NumAregArgs < 2)
+ NumAregArgs = 2;
+ break;
+ case Mips::A2:
+ case Mips::A2_64:
+ if (NumAregArgs < 3)
+ NumAregArgs = 3;
+ break;
+ case Mips::A3:
+ case Mips::A3_64:
+ NumAregArgs = 4;
+ break;
+ case Mips::S0:
+ case Mips::S0_64:
+ Encoding.bits.s0 = 1;
+ break;
+ case Mips::S1:
+ case Mips::S1_64:
+ Encoding.bits.s1 = 1;
+ break;
+ case Mips::FP:
+ case Mips::FP_64:
+ NumXsRegs = 7;
+ break;
+ case Mips::RA:
+ case Mips::RA_64:
+ Encoding.bits.ra = 1;
+ break;
+ }
+
+ ++OpNo;
+ }
+
+ // Instruction multiplies framesize value by 8.
+ Encoding.bits.framesize = MI.getOperand(OpNo).getImm() >> 3;
+ ++OpNo;
+
+ // Get static argument regs (ones saved at the end of the callee stack).
+ while (OpNo < MI.getNumOperands() && MI.getOperand(OpNo).isReg()) {
+ unsigned RegIdx = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI);
+ if (NumAregStatics < (8 - RegIdx))
+ NumAregStatics = 8 - RegIdx;
+
+ ++OpNo;
+ }
+
+ // Determine 'aregs' encoding. There are two special cases for when all
+ // four argument regs are used.
+ if (NumAregStatics == 4) {
+ Encoding.bits.aregs = 0b1011;
+ } else if (NumAregArgs == 4) {
+ Encoding.bits.aregs = 0b1110;
+ } else {
+ Encoding.bits.aregs = (NumAregArgs << 2) | NumAregStatics;
+ }
+
+ Encoding.bits.xsregs = NumXsRegs;
+
+ return Encoding.val;
+}
+
/// Return binary encoding of memory related operand.
/// If the offset operand requires relocation, record the relocation.
template <unsigned ShiftAmount>
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
index 871afd9eb9584b..9485895ce31c81 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
@@ -32,6 +32,7 @@ class MipsMCCodeEmitter : public MCCodeEmitter {
MCContext &Ctx;
bool IsLittleEndian;
+ bool isMips16(const MCSubtargetInfo &STI) const;
bool isMicroMips(const MCSubtargetInfo &STI) const;
bool isMips32r6(const MCSubtargetInfo &STI) const;
@@ -61,13 +62,20 @@ class MipsMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
- // getBranchJumpOpValueMM - Return binary encoding of the microMIPS jump
+ // getJumpTargetOpValueMM - Return binary encoding of the microMIPS jump
// target operand. If the machine operand requires relocation,
// record the relocation and return zero.
unsigned getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ // getJumpTargetOpValueMips16 - Return binary encoding of the MIPS16 jump
+ // target operand. If the machine operand requires relocation,
+ // record the relocation and return zero.
+ unsigned getJumpTargetOpValueMips16(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
// getUImm5Lsl2Encoding - Return binary encoding of the microMIPS jump
// target operand.
unsigned getUImm5Lsl2Encoding(const MCInst &MI, unsigned OpNo,
@@ -82,6 +90,22 @@ class MipsMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ unsigned getUImm8Lsl2Encoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ unsigned getSImm8Lsl3Encoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ unsigned getSImm11Lsl1Encoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ unsigned getSImm16Lsl1Encoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
// getSImm9AddiuspValue - Return binary encoding of the microMIPS addiusp
// instruction immediate operand.
unsigned getSImm9AddiuspValue(const MCInst &MI, unsigned OpNo,
@@ -137,6 +161,20 @@ class MipsMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ // getBranchTargetOpValueMips16 - Return binary encoding of the MIPS16
+ // branch target operand. The 16-bit instruction does not support
+ // relocations.
+ unsigned getBranchTargetOpValueMips16(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ // getBranchTarget16OpValueMips16 - Return binary encoding of the MIPS16
+ // branch target operand. If the machine operand requires relocation,
+ // record the relocation and return zero.
+ unsigned getBranchTarget16OpValueMips16(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
// getBranchTarget21OpValue - Return binary encoding of the branch
// offset operand. If the machine operand requires relocation,
// record the relocation and return zero.
@@ -182,6 +220,10 @@ class MipsMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ unsigned getSaveRestoreEncoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
template <unsigned ShiftAmount = 0>
unsigned getMemEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
index cca4a9cc805662..7dcd0e7855177a 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -37,6 +37,10 @@ static cl::opt<bool> RoundSectionSizes(
cl::desc("Round section sizes up to the section alignment"), cl::Hidden);
} // end anonymous namespace
+static bool isMips16(const MCSubtargetInfo *STI) {
+ return STI->hasFeature(Mips::FeatureMips16);
+}
+
static bool isMicroMips(const MCSubtargetInfo *STI) {
return STI->hasFeature(Mips::FeatureMicroMips);
}
@@ -286,6 +290,13 @@ void MipsTargetStreamer::emitEmptyDelaySlot(bool hasShortDelaySlot, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
// The default case of `nop` is `sll $zero, $zero, 0`.
unsigned Opc = Mips::SLL;
+
+ if (isMips16(STI)) {
+ assert(hasShortDelaySlot && "Expected short delay slot with MIPS16");
+ emitRR(Mips::Move32R16, Mips::ZERO, Mips::S0, IDLoc, STI);
+ return;
+ }
+
if (isMicroMips(STI) && hasShortDelaySlot) {
Opc = isMips32r6(STI) ? Mips::MOVE16_MMR6 : Mips::MOVE16_MM;
emitRR(Opc, Mips::ZERO, Mips::ZERO, IDLoc, STI);
@@ -299,7 +310,9 @@ void MipsTargetStreamer::emitEmptyDelaySlot(bool hasShortDelaySlot, SMLoc IDLoc,
}
void MipsTargetStreamer::emitNop(SMLoc IDLoc, const MCSubtargetInfo *STI) {
- if (isMicroMips(STI))
+ if (isMips16(STI))
+ emitRR(Mips::Move32R16, Mips::ZERO, Mips::S0, IDLoc, STI);
+ else if (isMicroMips(STI))
emitRR(Mips::MOVE16_MM, Mips::ZERO, Mips::ZERO, IDLoc, STI);
else
emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, STI);
@@ -887,6 +900,7 @@ void MipsTargetELFStreamer::emitLabel(MCSymbol *S) {
if (isMicroMipsEnabled())
Symbol->setOther(ELF::STO_MIPS_MICROMIPS);
+ // FIXME: Does this need to do something similar for MIPS16?
}
void MipsTargetELFStreamer::finish() {
@@ -997,6 +1011,8 @@ void MipsTargetELFStreamer::setUsesMicroMips() {
W.setELFHeaderEFlags(Flags);
}
+// FIXME: Should this be split into emitDirectiveSet(No)MipS16() and
+// setUsesMips16() like with microMIPS above?
void MipsTargetELFStreamer::emitDirectiveSetMips16() {
ELFObjectWriter &W = getStreamer().getWriter();
unsigned Flags = W.getELFHeaderEFlags();
diff --git a/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td b/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
index 197cd8ac5579b3..719328ba04d149 100644
--- a/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
+++ b/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
@@ -1652,8 +1652,9 @@ def BLTZALC_MMR6 : R6MMR6Rel, BLTZALC_MMR6_ENC, BLTZALC_MMR6_DESC,
def : MipsInstAlias<"ei", (EI_MMR6 ZERO), 1>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"di", (DI_MMR6 ZERO), 1>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"nop", (SLL_MMR6 ZERO, ZERO, 0), 1>, ISA_MICROMIPS32R6;
-def B_MMR6_Pseudo : MipsAsmPseudoInst<(outs), (ins brtarget_mm:$offset),
- !strconcat("b", "\t$offset")> {
+def B_MMR6_Pseudo :
+ MipsAsmPseudoInst<(outs), (ins brtarget_mm:$offset),
+ !strconcat("b", "\t$offset")>, ISA_MICROMIPS32R6 {
string DecoderNamespace = "MicroMipsR6";
}
def : MipsInstAlias<"sync", (SYNC_MMR6 0), 1>, ISA_MICROMIPS32R6;
diff --git a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
index 43b8eb7faf0ecd..1b29c2eb771ae1 100644
--- a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
@@ -20,11 +20,6 @@ def simm9_addiusp : Operand<i32> {
let DecoderMethod = "DecodeSimm9SP";
}
-def uimm3_shift : Operand<i32> {
- let EncoderMethod = "getUImm3Mod8Encoding";
- let DecoderMethod = "DecodePOOL16BEncodedField";
-}
-
def simm3_lsa2 : Operand<i32> {
let EncoderMethod = "getSImm3Lsa2Value";
let DecoderMethod = "DecodeAddiur2Simm7";
diff --git a/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp b/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp
index b8e6dcefe622a5..99f67aafd05859 100644
--- a/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp
@@ -79,10 +79,14 @@ void Mips16DAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) {
V1 = RegInfo.createVirtualRegister(RC);
V2 = RegInfo.createVirtualRegister(RC);
-
+ // FIXME: This seems like it should not use a PC-relative ADD with MO_ABS_LO.
+ // Should AddiuRxImmX16 be used instead?
+ // The program counter is always live.
+ MBB.addLiveIn(Mips::PC);
BuildMI(MBB, I, DL, TII.get(Mips::LiRxImmX16), V0)
.addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI);
BuildMI(MBB, I, DL, TII.get(Mips::AddiuRxPcImmX16), V1)
+ .addReg(Mips::PC)
.addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO);
BuildMI(MBB, I, DL, TII.get(Mips::SllX16), V2).addReg(V0).addImm(16);
diff --git a/llvm/lib/Target/Mips/Mips16InstrFormats.td b/llvm/lib/Target/Mips/Mips16InstrFormats.td
index b180e53855bc44..2ce8281637858f 100644
--- a/llvm/lib/Target/Mips/Mips16InstrFormats.td
+++ b/llvm/lib/Target/Mips/Mips16InstrFormats.td
@@ -37,6 +37,7 @@ class MipsInst16_Base<dag outs, dag ins, string asmstr, list<dag> pattern,
{
let Namespace = "Mips";
+ let DecoderNamespace = "Mips16";
let OutOperandList = outs;
let InOperandList = ins;
@@ -336,16 +337,14 @@ class FI8_MOVR3216<dag outs, dag ins, string asmstr,
list<dag> pattern, InstrItinClass itin>:
MipsInst16<outs, ins, asmstr, pattern, itin>
{
- // FIXME: this seems wrong? 'ry' should be 3 bits, and 'r32' 5?
- bits<4> ry;
- bits<4> r32;
+ bits<5> r32;
+ bits<3> ry;
let Opcode = 0b01100;
let Inst{10-8} = 0b111;
- let Inst{7-4} = ry;
- let Inst{3-0} = r32;
-
+ let Inst{7-5} = ry;
+ let Inst{4-0} = r32;
}
@@ -358,19 +357,16 @@ class FI8_MOV32R16<dag outs, dag ins, string asmstr,
list<dag> pattern, InstrItinClass itin>:
MipsInst16<outs, ins, asmstr, pattern, itin>
{
-
bits<3> func;
bits<5> r32;
bits<3> rz;
-
let Opcode = 0b01100;
let Inst{10-8} = 0b101;
let Inst{7-5} = r32{2-0};
let Inst{4-3} = r32{4-3};
let Inst{2-0} = rz;
-
}
//===----------------------------------------------------------------------===//
@@ -382,11 +378,16 @@ class FI8_SVRS16<bits<1> _s, dag outs, dag ins, string asmstr,
list<dag> pattern, InstrItinClass itin>:
MipsInst16<outs, ins, asmstr, pattern, itin>
{
+ // This is produced by getSaveRestoreEncoding().
+ // This instruction uses 4 bits of the framesize and the ra, s0, and s1 bits.
+ // This instruction interprets a framesize value of 0 as 128 (16 * 8).
+ bits<32> svrs_ops;
+
bits<1> s;
- bits<1> ra = 0;
- bits<1> s0 = 0;
- bits<1> s1 = 0;
- bits<4> framesize = 0;
+ bits<1> ra = svrs_ops{10};
+ bits<1> s0 = svrs_ops{9};
+ bits<1> s1 = svrs_ops{8};
+ bits<4> framesize = svrs_ops{3-0};
let s =_s;
let Opcode = 0b01100;
@@ -402,7 +403,7 @@ class FI8_SVRS16<bits<1> _s, dag outs, dag ins, string asmstr,
//===----------------------------------------------------------------------===//
// Format JAL instruction class in Mips16 :
-// <|opcode|svrs|s|ra|s0|s1|framesize>
+// <|opcode|X|target20:16|target25:21|target15:10>
//===----------------------------------------------------------------------===//
class FJAL16<bits<1> _X, dag outs, dag ins, string asmstr,
@@ -455,21 +456,21 @@ class FASMACRO16<dag outs, dag ins, string asmstr,
MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin>
{
bits<3> select;
- bits<3> p4;
- bits<5> p3;
+ bits<3> _p4;
+ bits<5> _p3;
bits<5> RRR = 0b11100;
- bits<3> p2;
- bits<3> p1;
- bits<5> p0;
+ bits<3> _p2;
+ bits<3> _p1;
+ bits<5> _p0;
let Inst{26-24} = select;
- let Inst{23-21} = p4;
- let Inst{20-16} = p3;
+ let Inst{23-21} = _p4;
+ let Inst{20-16} = _p3;
let Inst{15-11} = RRR;
- let Inst{10-8} = p2;
- let Inst{7-5} = p1;
- let Inst{4-0} = p0;
+ let Inst{10-8} = _p2;
+ let Inst{7-5} = _p1;
+ let Inst{4-0} = _p0;
}
@@ -551,23 +552,22 @@ class FEXT_RRI_A16<bits<1> _f, dag outs, dag ins, string asmstr,
//===----------------------------------------------------------------------===//
// Format EXT-SHIFT instruction class in Mips16 :
-// <|EXTEND|sa 4:0|s5|0|SHIFT|rx|ry|0|f>
+// <|EXTEND|sa 4:0|0|SHIFT|rx|ry|0|f>
//===----------------------------------------------------------------------===//
class FEXT_SHIFT16<bits<2> _f, dag outs, dag ins, string asmstr,
list<dag> pattern, InstrItinClass itin>:
MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin>
{
- bits<6> sa6;
+ bits<6> sa;
bits<3> rx;
bits<3> ry;
bits<2> f;
let f = _f;
- let Inst{26-22} = sa6{4-0};
- let Inst{21} = sa6{5};
- let Inst{20-16} = 0;
+ let Inst{26-22} = sa{4-0};
+ let Inst{21-16} = 0;
let Inst{15-11} = 0b00110;
let Inst{10-8} = rx;
let Inst{7-5} = ry;
@@ -590,7 +590,7 @@ class FEXT_I816<bits<3> _funct, dag outs, dag ins, string asmstr,
bits<3> funct;
let funct = _funct;
- let I8 = 0b00110;
+ let I8 = 0b01100;
let Inst{26-21} = imm16{10-5};
let Inst{20-16} = imm16{15-11};
@@ -610,22 +610,24 @@ class FEXT_I8_SVRS16<bits<1> s_, dag outs, dag ins, string asmstr,
list<dag> pattern, InstrItinClass itin>:
MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin>
{
- bits<3> xsregs =0;
- bits<8> framesize =0;
- bits<3> aregs =0;
+ // This is produced by getSaveRestoreEncoding().
+ bits<32> svrs_ops;
+
+ bits<3> xsregs = svrs_ops{17-15};
+ bits<8> framesize = svrs_ops{7-0};
+ bits<4> aregs = svrs_ops{14-11};
bits<5> I8 = 0b01100;
bits<3> SVRS = 0b100;
bits<1> s;
- bits<1> ra = 0;
- bits<1> s0 = 0;
- bits<1> s1 = 0;
+ bits<1> ra = svrs_ops{10};
+ bits<1> s0 = svrs_ops{9};
+ bits<1> s1 = svrs_ops{8};
let s= s_;
let Inst{26-24} = xsregs;
let Inst{23-20} = framesize{7-4};
- let Inst{19} = 0;
- let Inst{18-16} = aregs;
+ let Inst{19-16} = aregs;
let Inst{15-11} = I8;
let Inst{10-8} = SVRS;
let Inst{7} = s;
diff --git a/llvm/lib/Target/Mips/Mips16InstrInfo.cpp b/llvm/lib/Target/Mips/Mips16InstrInfo.cpp
index 1bc1ed7ab93e31..ff139c837e5b5d 100644
--- a/llvm/lib/Target/Mips/Mips16InstrInfo.cpp
+++ b/llvm/lib/Target/Mips/Mips16InstrInfo.cpp
@@ -418,8 +418,9 @@ unsigned Mips16InstrInfo::loadImmediate(unsigned FrameReg, int64_t Imm,
.addReg(Reg);
}
else
- BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16), Reg).addReg(FrameReg)
- .addReg(Reg, RegState::Kill);
+ BuildMI(MBB, II, DL, get(Mips::AdduRxRyRz16), Reg)
+ .addReg(FrameReg)
+ .addReg(Reg, RegState::Kill);
if (FirstRegSaved || SecondRegSaved) {
II = std::next(II);
if (FirstRegSaved)
@@ -448,7 +449,7 @@ unsigned Mips16InstrInfo::getAnalyzableBrOpc(unsigned Opc) const {
void Mips16InstrInfo::ExpandRetRA16(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned Opc) const {
- BuildMI(MBB, I, I->getDebugLoc(), get(Opc));
+ BuildMI(MBB, I, I->getDebugLoc(), get(Opc)).addReg(Mips::RA, RegState::Undef);
}
const MCInstrDesc &Mips16InstrInfo::AddiuSpImm(int64_t Imm) const {
@@ -461,7 +462,7 @@ const MCInstrDesc &Mips16InstrInfo::AddiuSpImm(int64_t Imm) const {
void Mips16InstrInfo::BuildAddiuSpImm
(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, int64_t Imm) const {
DebugLoc DL;
- BuildMI(MBB, I, DL, AddiuSpImm(Imm)).addImm(Imm);
+ BuildMI(MBB, I, DL, AddiuSpImm(Imm), Mips::SP).addImm(Imm);
}
const MipsInstrInfo *llvm::createMips16InstrInfo(const MipsSubtarget &STI) {
diff --git a/llvm/lib/Target/Mips/Mips16InstrInfo.td b/llvm/lib/Target/Mips/Mips16InstrInfo.td
index fb2a83dc90ea97..765769456c8d4e 100644
--- a/llvm/lib/Target/Mips/Mips16InstrInfo.td
+++ b/llvm/lib/Target/Mips/Mips16InstrInfo.td
@@ -16,101 +16,373 @@
def addr16 : ComplexPattern<iPTR, 2, "selectAddr16", [frameindex]>;
def addr16sp : ComplexPattern<iPTR, 2, "selectAddr16SP", [frameindex]>;
-//
-// Address operand
-def mem16 : Operand<i32> {
- let PrintMethod = "printMemOperand";
- let MIOperandInfo = (ops CPU16Regs, simm16);
- let EncoderMethod = "getMemEncoding";
+// The number matches the value in MipsRegisterInfo::MipsPtrClass.
+def ptr_cpu16_rc : PointerLikeRegClass<4>;
+
+def pcrel16 : Operand<i32>;
+
+// Some MIPS16 instructions, such as "addiu", have operands that look like
+// registers but are not encoded as normal operands. Instead, they determine
+// the opcode to use and so could be considered part of the mnemonic. These
+// define "pseudo register" operands to handle such instructions.
+def Mips16PCPseudoRegOperand : AsmOperandClass {
+ let Name = "Mips16PCPseudoReg";
+ let PredicateMethod = "isPCPseudoReg";
+ let RenderMethod = "addPCPseudoRegOperands";
+}
+def pc_pseudo_reg : Operand<i32> {
+ let PrintMethod = "printPCPseudoReg";
+ let ParserMatchClass = Mips16PCPseudoRegOperand;
}
-def mem16sp : Operand<i32> {
- let PrintMethod = "printMemOperand";
- // This should be CPUSPReg but the MIPS16 subtarget isn't good enough at
- // keeping the sp-relative load and the other varieties separate at the
- // moment. This lie fixes the problem sufficiently well to fix the errors
- // emitted by -verify-machineinstrs and the output ends up correct as long
- // as we use an external assembler (which is already a requirement for MIPS16
- // for several other reasons).
- let MIOperandInfo = (ops CPU16RegsPlusSP, simm16);
- let EncoderMethod = "getMemEncoding";
+def Mips16SPPseudoRegOperand : AsmOperandClass {
+ let Name = "Mips16SPPseudoReg";
+ let PredicateMethod = "isSPPseudoReg";
+ let RenderMethod = "addSPPseudoRegOperands";
+}
+def sp_pseudo_reg : Operand<i32> {
+ let PrintMethod = "printSPPseudoReg";
+ let ParserMatchClass = Mips16SPPseudoRegOperand;
+}
+
+def Mips16RAPseudoRegOperand : AsmOperandClass {
+ let Name = "Mips16RAPseudoReg";
+ let PredicateMethod = "isRAPseudoReg";
+ let RenderMethod = "addRAPseudoRegOperands";
+}
+def ra_pseudo_reg : Operand<i32> {
+ let PrintMethod = "printRAPseudoReg";
+ let ParserMatchClass = Mips16RAPseudoRegOperand;
+}
+
+
+// MIPS16 memory operands.
+// The "Ext" operands are for the 32-bit extended instructions. The non-"Ext"
+// operands are for the 16-bit instructions. They subclass the "Ext" versions
+// so that TableGen picks the 16-bit instructions that use these operands
+// before the extended instructions that use the superclass operands.
+class Mips16ExtMemAsmOperandBase : AsmOperandClass {
+ let Name = "Mips16ExtMemBase";
+ let ParserMethod = "parseMemOperand";
+ let RenderMethod = "addMips16MemOperands";
+}
+class Mips16MemAsmOperandBase : Mips16ExtMemAsmOperandBase {
+ let Name = "Mips16MemBase";
+}
+
+def Mips16ExtMemAsmOperand : Mips16ExtMemAsmOperandBase {
+ let Name = "Mips16ExtMem";
+ let PredicateMethod = "isMemWithExtCPU16Base";
+}
+// mem_generic is found in MipsInstrInfo.td.
+def mem16ext : mem_generic {
+ let ParserMatchClass = Mips16ExtMemAsmOperand;
+ let MIOperandInfo = (ops ptr_cpu16_rc, simm16);
+ let DecoderMethod = "DecodeMemMips16<0>";
+}
+
+def Mips16MemAsmOperandLsl0 : Mips16MemAsmOperandBase {
+ let SuperClasses = [Mips16ExtMemAsmOperand];
+ let Name = "Mips16MemLsl0";
+ let PredicateMethod = "isMemWithCPU16Base<0>";
+}
+def mem16_lsl0 : mem_generic {
+ let ParserMatchClass = Mips16MemAsmOperandLsl0;
+ let MIOperandInfo = (ops ptr_cpu16_rc, uimm5);
+ let DecoderMethod = "DecodeMemMips16<0>";
+}
+
+def Mips16MemAsmOperandLsl1 : Mips16MemAsmOperandBase {
+ let SuperClasses = [Mips16ExtMemAsmOperand];
+ let Name = "Mips16MemLsl1";
+ let PredicateMethod = "isMemWithCPU16Base<1>";
+}
+def mem16_lsl1 : mem_generic {
+ let ParserMatchClass = Mips16MemAsmOperandLsl1;
+ let MIOperandInfo = (ops ptr_cpu16_rc, uimm5);
+ let EncoderMethod = "getMemEncoding<1>";
+ let DecoderMethod = "DecodeMemMips16<1>";
+}
+
+def Mips16MemAsmOperandLsl2 : Mips16MemAsmOperandBase {
+ let SuperClasses = [Mips16ExtMemAsmOperand];
+ let Name = "Mips16MemLsl2";
+ let PredicateMethod = "isMemWithCPU16Base<2>";
+}
+def mem16_lsl2 : mem_generic {
+ let ParserMatchClass = Mips16MemAsmOperandLsl2;
+ let MIOperandInfo = (ops ptr_cpu16_rc, uimm5);
+ let EncoderMethod = "getMemEncoding<2>";
+ let DecoderMethod = "DecodeMemMips16<2>";
+}
+
+// These use the $pc pseudo-register as the implicit base register.
+def Mips16ExtPcRelMemAsmOperand : Mips16ExtMemAsmOperandBase {
+ let Name = "Mips16ExtPcRelMem";
+ let PredicateMethod = "isMemWithExtCPU16PCBase";
+}
+def mem16ext_pc : mem_generic {
+ let ParserMatchClass = Mips16ExtPcRelMemAsmOperand;
+ let MIOperandInfo = (ops pc_pseudo_reg, simm16);
+ let DecoderMethod = "DecodeMemPcrelMips16<0>";
+}
+
+def Mips16PcRelMemAsmOperand : Mips16MemAsmOperandBase {
+ let SuperClasses = [Mips16ExtPcRelMemAsmOperand];
+ let Name = "Mips16PcRelMem";
+ let PredicateMethod = "isMemWithCPU16PCBase";
+}
+def mem16_pc : mem_generic {
+ let ParserMatchClass = Mips16PcRelMemAsmOperand;
+ let MIOperandInfo = (ops pc_pseudo_reg, uimm8);
+ let EncoderMethod = "getMemEncoding<2>";
+ let DecoderMethod = "DecodeMemPcrelMips16<2>";
+}
+
+// These use the $sp pseudo-register as the implicit base register.
+def Mips16ExtSpRelMemAsmOperand : Mips16ExtMemAsmOperandBase {
+ let Name = "Mips16ExtSpRelMem";
+ let PredicateMethod = "isMemWithExtCPU16SPBase";
+}
+def mem16ext_sp : mem_generic {
+ let ParserMatchClass = Mips16ExtSpRelMemAsmOperand;
+ let MIOperandInfo = (ops sp_pseudo_reg, simm16);
+ let DecoderMethod = "DecodeMemSprelMips16<0>";
+}
+
+def Mips16SpRelMemAsmOperand : Mips16MemAsmOperandBase {
+ let SuperClasses = [Mips16ExtSpRelMemAsmOperand];
+ let Name = "Mips16SpRelMem";
+ let PredicateMethod = "isMemWithCPU16SPBase";
+}
+def mem16_sp : mem_generic {
+ let ParserMatchClass = Mips16SpRelMemAsmOperand;
+ let MIOperandInfo = (ops sp_pseudo_reg, uimm8);
+ let EncoderMethod = "getMemEncoding<2>";
+ let DecoderMethod = "DecodeMemSprelMips16<2>";
+}
+
+
+// Operands for the MIPS16 "save" and "restore" instructions.
+class SaveRestoreOperandsBase : AsmOperandClass {
+ let Name = "SaveRestoreBase";
+ let ParserMethod = "parseSaveRestoreOperands";
+ let RenderMethod = "addSaveRestoreOperands";
+}
+class svrsBase : Operand<i32> {
+ let PrintMethod = "printSaveRestore";
+ let EncoderMethod = "getSaveRestoreEncoding";
+ let DecoderMethod = "DecodeSaveRestore";
+}
+
+def SaveRestoreOperands : SaveRestoreOperandsBase {
+ let Name = "SaveRestore";
+ let PredicateMethod = "isSaveRestore";
+}
+def svrsExt : svrsBase {
+ let ParserMatchClass = SaveRestoreOperands;
}
+def SaveRestore16Operands : SaveRestoreOperandsBase {
+ let SuperClasses = [SaveRestoreOperands];
+ let Name = "SaveRestore16";
+ let PredicateMethod = "isSaveRestore16";
+}
+def svrs16 : svrsBase {
+ let ParserMatchClass = SaveRestore16Operands;
+}
+
+
def mem16_ea : Operand<i32> {
let PrintMethod = "printMemOperandEA";
- let MIOperandInfo = (ops CPU16RegsPlusSP, simm16);
+ let MIOperandInfo = (ops CPU16OpndPlusSP, simm15);
let EncoderMethod = "getMemEncoding";
}
-def pcrel16 : Operand<i32>;
+// Used for extended branches.
+def brtarget16_mips16 : Operand<OtherVT> {
+ let EncoderMethod = "getBranchTarget16OpValueMips16";
+ let OperandType = "OPERAND_PCREL";
+ let DecoderMethod = "DecodeBranchTarget16Mips16";
+ let ParserMatchClass = MipsJumpTargetAsmOperand;
+ let PrintMethod = "printBranchOperand";
+}
+
+// Used for JAL and JALX
+def calltarget_mips16 : Operand<iPTR> {
+ let EncoderMethod = "getJumpTargetOpValueMips16";
+ let DecoderMethod = "DecodeJumpTargetMips16";
+ let ParserMatchClass = MipsJumpTargetAsmOperand;
+ let PrintMethod = "printJumpOperand";
+}
+
+// These ensure that the compressed branch is tried first by being a subclass
+// of MipsJumpTargetAsmOperand. They also require a constant immediate because
+// there is no fixup available for the compressed branches.
+def Mips16JumpTarget11AsmOperand : AsmOperandClass {
+ let SuperClasses = [MipsJumpTargetAsmOperand];
+ let Name = "JumpTarget11Mips16";
+ let ParserMethod = "parseJumpTarget";
+ let PredicateMethod = "isConstantScaledSImm<11, 1>";
+ let RenderMethod = "addImmOperands";
+}
+def brtarget11_mips16 : Operand<OtherVT> {
+ let EncoderMethod = "getBranchTargetOpValueMips16";
+ let OperandType = "OPERAND_PCREL";
+ let DecoderMethod = "DecodeBranchTarget11Mips16";
+ let ParserMatchClass = Mips16JumpTarget11AsmOperand;
+ let PrintMethod = "printBranchOperand";
+}
+
+def Mips16JumpTarget8AsmOperand : AsmOperandClass {
+ let SuperClasses = [MipsJumpTargetAsmOperand];
+ let Name = "JumpTarget8Mips16";
+ let ParserMethod = "parseJumpTarget";
+ let PredicateMethod = "isConstantScaledSImm<8, 1>";
+ let RenderMethod = "addImmOperands";
+}
+def brtarget8_mips16 : Operand<OtherVT> {
+ let EncoderMethod = "getBranchTargetOpValueMips16";
+ let OperandType = "OPERAND_PCREL";
+ let DecoderMethod = "DecodeBranchTarget8Mips16";
+ let ParserMatchClass = Mips16JumpTarget8AsmOperand;
+ let PrintMethod = "printBranchOperand";
+}
//
// I-type instruction format
//
-// this is only used by bimm. the actual assembly value is a 12 bit signed
+// This is used only by Bimm16. The actual assembly value is a 12-bit signed
// number
//
-class FI16_ins<bits<5> op, string asmstr, InstrItinClass itin>:
- FI16<op, (outs), (ins brtarget:$imm11),
- !strconcat(asmstr, "\t$imm11 # 16 bit inst"), [], itin>;
+class FI16_B_ins<bits<5> op, string asmstr, InstrItinClass itin>:
+ FI16<op, (outs), (ins brtarget11_mips16:$imm11),
+ !strconcat(asmstr, "\t$imm11"), [], itin>;
//
//
// I8 instruction format
//
-class FI816_ins_base<bits<3> _func, string asmstr,
- string asmstr2, InstrItinClass itin>:
- FI816<_func, (outs), (ins simm16:$imm8), !strconcat(asmstr, asmstr2),
+class FI816_ins<bits<3> _func, string asmstr, InstrItinClass itin>:
+ FI816<_func, (outs), (ins simm16:$imm), !strconcat(asmstr, "\t$imm"),
[], itin>;
-class FI816_ins<bits<3> _func, string asmstr,
- InstrItinClass itin>:
- FI816_ins_base<_func, asmstr, "\t$imm8 # 16 bit inst", itin>;
+class FI816_B_ins<bits<3> _func, string asmstr, InstrItinClass itin>:
+ FI816<_func, (outs), (ins brtarget8_mips16:$imm8),
+ !strconcat(asmstr, "\t$imm8"), [], itin>;
+
+class FI816_SP_ins<bits<3> _func, string asmstr, InstrItinClass itin>:
+ FI816<_func, (outs), (ins sp_pseudo_reg:$pseudo, simm8_lsl3:$imm8),
+ !strconcat(asmstr, "\t$pseudo, $imm8"), [], itin>;
-class FI816_SP_ins<bits<3> _func, string asmstr,
+class FI816_RA_mem_ins<bits<3> _func, string asmstr, Operand MemOpnd,
InstrItinClass itin>:
- FI816_ins_base<_func, asmstr, "\t$$sp, $imm8 # 16 bit inst", itin>;
+ FI816<_func, (outs), (ins ra_pseudo_reg:$pseudo, MemOpnd:$addr),
+ !strconcat(asmstr, "\t$pseudo, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses only 8 bits of the offset.
+ bits<8> addr;
+ let imm8 = addr{7-0};
+}
//
// RI instruction format
//
-
-class FRI16_ins_base<bits<5> op, string asmstr, string asmstr2,
- InstrItinClass itin>:
- FRI16<op, (outs CPU16Regs:$rx), (ins simm16:$imm8),
- !strconcat(asmstr, asmstr2), [], itin>;
-
-class FRI16_ins<bits<5> op, string asmstr,
- InstrItinClass itin>:
- FRI16_ins_base<op, asmstr, "\t$rx, $imm8 \t# 16 bit inst", itin>;
+class FRI16_ins<bits<5> op, string asmstr, Operand ImmOpnd, InstrItinClass itin>:
+ FRI16<op, (outs CPU16Opnd:$rx), (ins ImmOpnd:$imm8),
+ !strconcat(asmstr, "\t$rx, $imm8"), [], itin>;
class FRI16_TCP_ins<bits<5> _op, string asmstr,
InstrItinClass itin>:
- FRI16<_op, (outs CPU16Regs:$rx), (ins pcrel16:$imm8, i32imm:$size),
- !strconcat(asmstr, "\t$rx, $imm8\t# 16 bit inst"), [], itin>;
+ FRI16<_op, (outs CPU16Opnd:$rx), (ins pcrel16:$imm8, i32imm:$size),
+ !strconcat(asmstr, "\t$rx, $imm8"), [], itin>;
-class FRI16R_ins_base<bits<5> op, string asmstr, string asmstr2,
- InstrItinClass itin>:
- FRI16<op, (outs), (ins CPU16Regs:$rx, simm16:$imm8),
- !strconcat(asmstr, asmstr2), [], itin>;
+class FRI16R_ins<bits<5> op, string asmstr, InstrItinClass itin>:
+ FRI16<op, (outs), (ins CPU16Opnd:$rx, uimm8:$imm8),
+ !strconcat(asmstr, "\t$rx, $imm8"), [], itin>;
-class FRI16R_ins<bits<5> op, string asmstr,
- InstrItinClass itin>:
- FRI16R_ins_base<op, asmstr, "\t$rx, $imm8 \t# 16 bit inst", itin>;
+class F2RI16_ins<bits<5> _op, string asmstr, InstrItinClass itin>:
+ FRI16<_op, (outs CPU16Opnd:$rx), (ins CPU16Opnd:$rx_, simm16:$imm),
+ !strconcat(asmstr, "\t$rx, $imm"), [], itin> {
+ bits<16> imm;
+ let imm8 = imm{7-0};
-class F2RI16_ins<bits<5> _op, string asmstr,
- InstrItinClass itin>:
- FRI16<_op, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_, simm16:$imm8),
- !strconcat(asmstr, "\t$rx, $imm8\t# 16 bit inst"), [], itin> {
let Constraints = "$rx_ = $rx";
}
-class FRI16_B_ins<bits<5> _op, string asmstr,
- InstrItinClass itin>:
- FRI16<_op, (outs), (ins CPU16Regs:$rx, brtarget:$imm8),
- !strconcat(asmstr, "\t$rx, $imm8 # 16 bit inst"), [], itin>;
+class FRI16_Pseudo_ins<bits<5> _op, string asmstr, Operand PseudoRegOpnd,
+ Operand ImmOpnd, InstrItinClass itin>:
+ FRI16<_op, (outs CPU16Opnd:$rx), (ins PseudoRegOpnd:$pseudo, ImmOpnd:$imm8),
+ !strconcat(asmstr, "\t$rx, $pseudo, $imm8"), [], itin>;
+
+class FRI16_B_ins<bits<5> _op, string asmstr, InstrItinClass itin>:
+ FRI16<_op, (outs), (ins CPU16Opnd:$rx, brtarget8_mips16:$imm8),
+ !strconcat(asmstr, "\t$rx, $imm8"), [], itin>;
+
+class FRI16_memload_ins<bits<5> op, string asmstr, Operand MemOpnd,
+ InstrItinClass itin>:
+ FRI16<op, (outs CPU16Opnd:$rx), (ins MemOpnd:$addr),
+ !strconcat(asmstr, "\t$rx, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses only 8 bits of the offset.
+ bits<8> addr;
+ let imm8 = addr{7-0};
+}
+
+class FRI16_memstore_ins<bits<5> op, string asmstr, Operand MemOpnd,
+ InstrItinClass itin>:
+ FRI16<op, (outs ), (ins CPU16Opnd:$rx, MemOpnd:$addr),
+ !strconcat(asmstr, "\t$rx, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses only 8 bits of the offset.
+ bits<8> addr;
+ let imm8 = addr{7-0};
+}
+
+//
+// RRI-A instruction format
+//
+
+class FRRI_A16_ins<bits<1> _f, string asmstr, InstrItinClass itin>:
+ FRRI_A16<_f, (outs CPU16Opnd:$ry), (ins CPU16Opnd:$rx, simm4: $imm4),
+ !strconcat(asmstr, "\t$ry, $rx, $imm4"), [], itin>;
+
+//
+// SHIFT instruction format
+//
+class FSHIFT16_ins<bits<2> _f, string asmstr, InstrItinClass itin>:
+ FSHIFT16<_f, (outs CPU16Opnd:$rx), (ins CPU16Opnd:$ry, uimm3_shift:$sa),
+ !strconcat(asmstr, "\t$rx, $ry, $sa"), [], itin>;
+
+//
+// RRI memory instruction formats
+//
+
+class FRRI16_memload_ins<bits<5> op, string asmstr, Operand MemOpnd,
+ InstrItinClass itin>:
+ FRRI16<op, (outs CPU16Opnd:$ry), (ins MemOpnd:$addr),
+ !strconcat(asmstr, "\t$ry, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses 3 bits of the reg and 5 bits of the offset.
+ bits<19> addr;
+ let rx = addr{18-16};
+ let imm5 = addr{4-0};
+}
+
+class FRRI16_memstore_ins<bits<5> op, string asmstr, Operand MemOpnd,
+ InstrItinClass itin>:
+ FRRI16<op, (outs ), (ins CPU16Opnd:$ry, MemOpnd:$addr),
+ !strconcat(asmstr, "\t$ry, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses 3 bits of the reg and 5 bits of the offset.
+ bits<19> addr;
+ let rx = addr{18-16};
+ let imm5 = addr{4-0};
+}
+
+
//
// Compare a register and immediate and place result in CC
// Implicit use of T8
@@ -118,7 +390,7 @@ class FRI16_B_ins<bits<5> _op, string asmstr,
// EXT-CCRR Instruction format
//
class FEXT_CCRXI16_ins<string asmstr>:
- MipsPseudo16<(outs CPU16Regs:$cc), (ins CPU16Regs:$rx, simm16:$imm),
+ MipsPseudo16<(outs CPU16Opnd:$cc), (ins CPU16Opnd:$rx, simm16:$imm),
!strconcat(asmstr, "\t$rx, $imm\n\tmove\t$cc, $$t8"), []> {
let isCodeGenOnly=1;
let usesCustomInserter = 1;
@@ -128,45 +400,38 @@ class FEXT_CCRXI16_ins<string asmstr>:
//
class FJAL16_ins<bits<1> _X, string asmstr,
InstrItinClass itin>:
- FJAL16<_X, (outs), (ins uimm26:$imm26),
- !strconcat(asmstr, "\t$imm26\n\tnop"),[],
- itin> {
- let isCodeGenOnly=1;
- let Size=6;
-}
-
-class FJALB16_ins<bits<1> _X, string asmstr,
- InstrItinClass itin>:
- FJAL16<_X, (outs), (ins uimm26:$imm26),
- !strconcat(asmstr, "\t$imm26\t# branch\n\tnop"),[],
- itin> {
- let isCodeGenOnly=1;
- let Size=6;
-}
+ FJAL16<_X, (outs), (ins calltarget_mips16:$imm26),
+ !strconcat(asmstr, "\t$imm26"),[], itin>;
//
// EXT-I instruction format
//
class FEXT_I16_ins<bits<5> eop, string asmstr, InstrItinClass itin> :
- FEXT_I16<eop, (outs), (ins brtarget:$imm16),
+ FEXT_I16<eop, (outs), (ins brtarget16_mips16:$imm16),
!strconcat(asmstr, "\t$imm16"),[], itin>;
//
// EXT-I8 instruction format
//
-class FEXT_I816_ins_base<bits<3> _func, string asmstr,
- string asmstr2, InstrItinClass itin>:
- FEXT_I816<_func, (outs), (ins simm16:$imm16), !strconcat(asmstr, asmstr2),
- [], itin>;
-
-class FEXT_I816_ins<bits<3> _func, string asmstr,
- InstrItinClass itin>:
- FEXT_I816_ins_base<_func, asmstr, "\t$imm16", itin>;
+class FEXT_I816_B_ins<bits<3> _func, string asmstr, InstrItinClass itin>:
+ FEXT_I816<_func, (outs), (ins brtarget16_mips16:$imm16),
+ !strconcat(asmstr, "\t$imm16"), [], itin>;
class FEXT_I816_SP_ins<bits<3> _func, string asmstr,
InstrItinClass itin>:
- FEXT_I816_ins_base<_func, asmstr, "\t$$sp, $imm16", itin>;
+ FEXT_I816<_func, (outs), (ins sp_pseudo_reg:$pseudo, simm16:$imm16),
+ !strconcat(asmstr, "\t$pseudo, $imm16"), [], itin>;
+
+class FEXT_I816_RA_mem_ins<bits<3> _func, string asmstr, Operand MemOpnd,
+ InstrItinClass itin>:
+ FEXT_I816<_func, (outs), (ins ra_pseudo_reg:$pseudo, MemOpnd:$addr),
+ !strconcat(asmstr, "\t$pseudo, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses only the 16-bit offset.
+ bits<16> addr;
+ let imm16 = addr{15-0};
+}
//
// Assembler formats in alphabetical order.
@@ -178,7 +443,7 @@ class FEXT_I816_SP_ins<bits<3> _func, string asmstr,
// CC-RR Instruction format
//
class FCCRR16_ins<string asmstr> :
- MipsPseudo16<(outs CPU16Regs:$cc), (ins CPU16Regs:$rx, CPU16Regs:$ry),
+ MipsPseudo16<(outs CPU16Opnd:$cc), (ins CPU16Opnd:$rx, CPU16Opnd:$ry),
!strconcat(asmstr, "\t$rx, $ry\n\tmove\t$cc, $$t8"), []> {
let isCodeGenOnly=1;
let usesCustomInserter = 1;
@@ -188,30 +453,31 @@ class FCCRR16_ins<string asmstr> :
// EXT-RI instruction format
//
-class FEXT_RI16_ins_base<bits<5> _op, string asmstr, string asmstr2,
- InstrItinClass itin>:
- FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins simm16:$imm16),
+class FEXT_RI16_ins_base<bits<5> _op, string asmstr, string asmstr2,
+ Operand ImmOpnd, InstrItinClass itin>:
+ FEXT_RI16<_op, (outs CPU16Opnd:$rx), (ins ImmOpnd:$imm16),
!strconcat(asmstr, asmstr2), [], itin>;
-class FEXT_RI16_ins<bits<5> _op, string asmstr,
+class FEXT_RI16_ins<bits<5> _op, string asmstr, Operand ImmOpnd,
InstrItinClass itin>:
- FEXT_RI16_ins_base<_op, asmstr, "\t$rx, $imm16", itin>;
+ FEXT_RI16_ins_base<_op, asmstr, "\t$rx, $imm16", ImmOpnd, itin>;
-class FEXT_RI16R_ins_base<bits<5> _op, string asmstr, string asmstr2,
- InstrItinClass itin>:
- FEXT_RI16<_op, (outs ), (ins CPU16Regs:$rx, simm16:$imm16),
- !strconcat(asmstr, asmstr2), [], itin>;
-
-class FEXT_RI16R_ins<bits<5> _op, string asmstr,
+class FEXT_RI16R_ins<bits<5> _op, string asmstr, Operand ImmOpnd,
InstrItinClass itin>:
- FEXT_RI16R_ins_base<_op, asmstr, "\t$rx, $imm16", itin>;
+ FEXT_RI16<_op, (outs ), (ins CPU16Opnd:$rx, ImmOpnd:$imm16),
+ !strconcat(asmstr, "\t$rx, $imm16"), [], itin>;
class FEXT_RI16_PC_ins<bits<5> _op, string asmstr, InstrItinClass itin>:
- FEXT_RI16_ins_base<_op, asmstr, "\t$rx, $$pc, $imm16", itin>;
+ FEXT_RI16<_op, (outs CPU16Opnd:$rx), (ins pc_pseudo_reg:$pseudo, simm16:$imm16),
+ !strconcat(asmstr, "\t$rx, $pseudo, $imm16"), [], itin>;
+
+class FEXT_RI16_SP_ins<bits<5> _op, string asmstr, InstrItinClass itin>:
+ FEXT_RI16<_op, (outs CPU16Opnd:$rx), (ins sp_pseudo_reg:$pseudo, simm16:$imm16),
+ !strconcat(asmstr, "\t$rx, $pseudo, $imm16"), [], itin>;
class FEXT_RI16_B_ins<bits<5> _op, string asmstr,
InstrItinClass itin>:
- FEXT_RI16<_op, (outs), (ins CPU16Regs:$rx, brtarget:$imm16),
+ FEXT_RI16<_op, (outs), (ins CPU16Opnd:$rx, brtarget16_mips16:$imm16),
!strconcat(asmstr, "\t$rx, $imm16"), [], itin>;
class FEXT_RI16_TCP_ins<bits<5> _op, string asmstr,
@@ -221,48 +487,93 @@ class FEXT_RI16_TCP_ins<bits<5> _op, string asmstr,
class FEXT_2RI16_ins<bits<5> _op, string asmstr,
InstrItinClass itin>:
- FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_, simm16:$imm16),
+ FEXT_RI16<_op, (outs CPU16Opnd:$rx), (ins CPU16Opnd:$rx_, simm16:$imm16),
!strconcat(asmstr, "\t$rx, $imm16"), [], itin> {
let Constraints = "$rx_ = $rx";
}
//
-// EXT-RRI instruction format
+// EXT-RI memory instruction formats
+//
+
+class FEXT_RI16_memload_ins<bits<5> op, string asmstr, Operand MemOpnd,
+ InstrItinClass itin>:
+ FEXT_RI16<op, (outs CPU16Opnd:$rx), (ins MemOpnd:$addr),
+ !strconcat(asmstr, "\t$rx, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses only the offset.
+ bits<16> addr;
+ let imm16 = addr;
+}
+
+class FEXT_RI16_memstore_ins<bits<5> op, string asmstr, Operand MemOpnd,
+ InstrItinClass itin>:
+ FEXT_RI16<op, (outs ), (ins CPU16Opnd:$rx, MemOpnd:$addr),
+ !strconcat(asmstr, "\t$rx, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses only the offset.
+ bits<16> addr;
+ let imm16 = addr;
+}
+
+//
+// EXT-RRI memory instruction formats
//
-class FEXT_RRI16_mem_ins<bits<5> op, string asmstr, Operand MemOpnd,
+class FEXT_RRI16_memload_ins<bits<5> op, string asmstr, Operand MemOpnd,
InstrItinClass itin>:
- FEXT_RRI16<op, (outs CPU16Regs:$ry), (ins (MemOpnd $rx, $imm16):$addr),
- !strconcat(asmstr, "\t$ry, $addr"), [], itin>;
+ FEXT_RRI16<op, (outs CPU16Opnd:$ry), (ins MemOpnd:$addr),
+ !strconcat(asmstr, "\t$ry, $addr"), [], itin>{
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses 3 bits of reg and the whole offset.
+ bits<19> addr;
+ let rx = addr{18-16};
+ let imm16 = addr{15-0};
+}
-class FEXT_RRI16_mem2_ins<bits<5> op, string asmstr, Operand MemOpnd,
+class FEXT_RRI16_memstore_ins<bits<5> op, string asmstr, Operand MemOpnd,
InstrItinClass itin>:
- FEXT_RRI16<op, (outs ), (ins CPU16Regs:$ry, (MemOpnd $rx, $imm16):$addr),
- !strconcat(asmstr, "\t$ry, $addr"), [], itin>;
+ FEXT_RRI16<op, (outs ), (ins CPU16Opnd:$ry, MemOpnd:$addr),
+ !strconcat(asmstr, "\t$ry, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ // This instruction type uses 3 bits of reg and the whole offset.
+ bits<19> addr;
+ let rx = addr{18-16};
+ let imm16 = addr{15-0};
+}
//
//
// EXT-RRI-A instruction format
//
+class FEXT_RRI_A16_ins<bits<1> op, string asmstr, InstrItinClass itin>:
+ FEXT_RRI_A16<op, (outs CPU16Opnd:$ry), (ins CPU16Opnd: $rx, simm15: $imm15),
+ !strconcat(asmstr, "\t$ry, $rx, $imm15"), [], itin>;
+
class FEXT_RRI_A16_mem_ins<bits<1> op, string asmstr, Operand MemOpnd,
InstrItinClass itin>:
- FEXT_RRI_A16<op, (outs CPU16Regs:$ry), (ins (MemOpnd $rx, $imm15):$addr),
- !strconcat(asmstr, "\t$ry, $addr"), [], itin>;
+ FEXT_RRI_A16<op, (outs CPU16Opnd:$ry), (ins MemOpnd:$addr),
+ !strconcat(asmstr, "\t$ry, $addr"), [], itin> {
+ // 'addr' is produced by getMemEncoding(), which outputs (reg << 16 | offset).
+ bits<19> addr;
+ let imm15 = addr{14-0};
+ let rx = addr{18-16};
+}
//
// EXT-SHIFT instruction format
//
class FEXT_SHIFT16_ins<bits<2> _f, string asmstr, InstrItinClass itin>:
- FEXT_SHIFT16<_f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry, uimm5:$sa6),
- !strconcat(asmstr, "\t$rx, $ry, $sa6"), [], itin>;
+ FEXT_SHIFT16<_f, (outs CPU16Opnd:$rx), (ins CPU16Opnd:$ry, uimm5:$sa),
+ !strconcat(asmstr, "\t$rx, $ry, $sa"), [], itin>;
//
// EXT-T8I8
//
class FEXT_T8I816_ins<string asmstr, string asmstr2>:
MipsPseudo16<(outs),
- (ins CPU16Regs:$rx, CPU16Regs:$ry, brtarget:$imm),
+ (ins CPU16Opnd:$rx, CPU16Opnd:$ry, brtarget:$imm),
!strconcat(asmstr2, !strconcat("\t$rx, $ry\n\t",
!strconcat(asmstr, "\t$imm"))),[]> {
let isCodeGenOnly=1;
@@ -274,7 +585,7 @@ class FEXT_T8I816_ins<string asmstr, string asmstr2>:
//
class FEXT_T8I8I16_ins<string asmstr, string asmstr2>:
MipsPseudo16<(outs),
- (ins CPU16Regs:$rx, simm16:$imm, brtarget:$targ),
+ (ins CPU16Opnd:$rx, simm16:$imm, brtarget:$targ),
!strconcat(asmstr2, !strconcat("\t$rx, $imm\n\t",
!strconcat(asmstr, "\t$targ"))), []> {
let isCodeGenOnly=1;
@@ -287,110 +598,108 @@ class FEXT_T8I8I16_ins<string asmstr, string asmstr2>:
// I8_MOVR32 instruction format (used only by the MOVR32 instructio
//
class FI8_MOVR3216_ins<string asmstr, InstrItinClass itin>:
- FI8_MOVR3216<(outs CPU16Regs:$ry), (ins GPR32:$r32),
- !strconcat(asmstr, "\t$ry, $r32"), [], itin>;
+ FI8_MOVR3216<(outs CPU16Opnd:$ry), (ins GPR32Opnd:$r32),
+ !strconcat(asmstr, "\t$ry, $r32"), [], itin>;
//
// I8_MOV32R instruction format (used only by MOV32R instruction)
//
class FI8_MOV32R16_ins<string asmstr, InstrItinClass itin>:
- FI8_MOV32R16<(outs GPR32:$r32), (ins CPU16Regs:$rz),
- !strconcat(asmstr, "\t$r32, $rz"), [], itin>;
+ FI8_MOV32R16<(outs GPR32Opnd:$r32), (ins CPU16Opnd:$rz),
+ !strconcat(asmstr, "\t$r32, $rz"), [], itin>;
-//
-// This are pseudo formats for multiply
-// This first one can be changed to non-pseudo now.
//
// MULT
//
-class FMULT16_ins<string asmstr> :
- MipsPseudo16<(outs), (ins CPU16Regs:$rx, CPU16Regs:$ry),
- !strconcat(asmstr, "\t$rx, $ry"), []>;
+class FMULT16_ins<bits<5> _funct, string asmstr, InstrItinClass itin> :
+ FRR16<_funct, (outs), (ins CPU16Opnd: $rx, CPU16Opnd: $ry),
+ !strconcat(asmstr, "\t$rx, $ry"), [], itin>;
-//
+// Pseudo format for multiply
// MULT-LO
//
class FMULT16_LO_ins<string asmstr> :
- MipsPseudo16<(outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry),
+ MipsPseudo16<(outs CPU16Opnd:$rz), (ins CPU16Opnd:$rx, CPU16Opnd:$ry),
!strconcat(asmstr, "\t$rx, $ry\n\tmflo\t$rz"), []> {
let isCodeGenOnly=1;
}
//
-// RR-type instruction format
+// Used for breakpoint instructions (break and sdbbp)
//
+class FC16_ins<bits<5> _funct, string asmstr, InstrItinClass itin> :
+ FC16<_funct, (outs), (ins uimm6:$_code), !strconcat(asmstr, "\t$_code"),
+ [], itin>;
-class FRR16_ins<bits<5> f, string asmstr, InstrItinClass itin> :
- FRR16<f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry),
- !strconcat(asmstr, "\t$rx, $ry"), [], itin> {
-}
-
-class FRRBreakNull16_ins<string asmstr, InstrItinClass itin> :
- FRRBreak16<(outs), (ins), asmstr, [], itin> {
- let Code=0;
-}
-
+//
+// RR-type instruction format
+//
class FRR16R_ins<bits<5> f, string asmstr, InstrItinClass itin> :
- FRR16<f, (outs), (ins CPU16Regs:$rx, CPU16Regs:$ry),
+ FRR16<f, (outs), (ins CPU16Opnd:$rx, CPU16Opnd:$ry),
!strconcat(asmstr, "\t$rx, $ry"), [], itin> {
}
class FRRTR16_ins<string asmstr> :
- MipsPseudo16<(outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry),
+ MipsPseudo16<(outs CPU16Opnd:$rz), (ins CPU16Opnd:$rx, CPU16Opnd:$ry),
!strconcat(asmstr, "\t$rx, $ry\n\tmove\t$rz, $$t8"), []> ;
//
// maybe refactor but need a $zero as a dummy first parameter
//
class FRR16_div_ins<bits<5> f, string asmstr, InstrItinClass itin> :
- FRR16<f, (outs ), (ins CPU16Regs:$rx, CPU16Regs:$ry),
+ FRR16<f, (outs ), (ins CPU16Opnd:$rx, CPU16Opnd:$ry),
!strconcat(asmstr, "\t$$zero, $rx, $ry"), [], itin> ;
class FUnaryRR16_ins<bits<5> f, string asmstr, InstrItinClass itin> :
- FRR16<f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry),
+ FRR16<f, (outs CPU16Opnd:$rx), (ins CPU16Opnd:$ry),
!strconcat(asmstr, "\t$rx, $ry"), [], itin> ;
class FRR16_M_ins<bits<5> f, string asmstr,
InstrItinClass itin> :
- FRR16<f, (outs CPU16Regs:$rx), (ins),
- !strconcat(asmstr, "\t$rx"), [], itin>;
+ FRR16<f, (outs CPU16Opnd:$rx), (ins),
+ !strconcat(asmstr, "\t$rx"), [], itin> {
+ let ry = 0;
+}
class FRxRxRy16_ins<bits<5> f, string asmstr,
InstrItinClass itin> :
- FRR16<f, (outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry),
+ FRR16<f, (outs CPU16Opnd:$rz), (ins CPU16Opnd:$rx, CPU16Opnd:$ry),
!strconcat(asmstr, "\t$rz, $ry"),
[], itin> {
let Constraints = "$rx = $rz";
}
-let rx=0 in
-class FRR16_JALRC_RA_only_ins<bits<1> nd_, bits<1> l_,
- string asmstr, InstrItinClass itin>:
- FRR16_JALRC<nd_, l_, 1, (outs), (ins), !strconcat(asmstr, "\t$$ra"),
- [], itin> ;
+class FRR16_JALRC_RaRx_ins<bits<1> nd_, string asmstr, InstrItinClass itin>:
+ FRR16_JALRC<nd_, 1, 0, (outs ra_pseudo_reg:$pseudo), (ins CPU16Opnd:$rx),
+ !strconcat(asmstr, "\t$pseudo, $rx"), [], itin> ;
+let rx=0 in
+class FRR16_JALRC_RA_only_ins<bits<1> nd_, string asmstr, InstrItinClass itin>:
+ FRR16_JALRC<nd_, 0, 1, (outs), (ins ra_pseudo_reg:$pseudo),
+ !strconcat(asmstr, "\t$pseudo"), [], itin> ;
-class FRR16_JALRC_ins<bits<1> nd, bits<1> l, bits<1> ra,
- string asmstr, InstrItinClass itin>:
- FRR16_JALRC<nd, l, ra, (outs), (ins CPU16Regs:$rs),
- !strconcat(asmstr, "\t$rs"), [], itin> ;
+class FRR16_JALRC_RX_only_ins<bits<1> nd_, string asmstr,
+ InstrItinClass itin>:
+ FRR16_JALRC<nd_, 0, 0, (outs), (ins CPU16Opnd:$rx),
+ !strconcat(asmstr, "\t$rx"), [], itin> ;
class FRR_SF16_ins
<bits<5> _funct, bits<3> _subfunc,
string asmstr, InstrItinClass itin>:
- FRR_SF16<_funct, _subfunc, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_),
+ FRR_SF16<_funct, _subfunc, (outs CPU16Opnd:$rx), (ins CPU16Opnd:$rx_),
!strconcat(asmstr, "\t $rx"),
[], itin> {
let Constraints = "$rx_ = $rx";
}
+
//
// RRR-type instruction format
//
class FRRR16_ins<bits<2> _f, string asmstr, InstrItinClass itin> :
- FRRR16<_f, (outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry),
+ FRRR16<_f, (outs CPU16Opnd:$rz), (ins CPU16Opnd:$rx, CPU16Opnd:$ry),
!strconcat(asmstr, "\t$rz, $rx, $ry"), [], itin>;
//
@@ -422,8 +731,8 @@ class FRRR16_ins<bits<2> _f, string asmstr, InstrItinClass itin> :
// So this pseudo class only has one operand, i.e. op
//
class Sel<string op>:
- MipsPseudo16<(outs CPU16Regs:$rd_), (ins CPU16Regs:$rd, CPU16Regs:$rs,
- CPU16Regs:$rt),
+ MipsPseudo16<(outs CPU16Opnd:$rd_), (ins CPU16Opnd:$rd, CPU16Opnd:$rs,
+ CPU16Opnd:$rt),
!strconcat(op, "\t$rt, .+4\n\t\n\tmove $rd, $rs"), []> {
//let isCodeGenOnly=1;
let Constraints = "$rd = $rd_";
@@ -446,8 +755,8 @@ class Sel<string op>:
//
//
class SeliT<string op1, string op2>:
- MipsPseudo16<(outs CPU16Regs:$rd_), (ins CPU16Regs:$rd, CPU16Regs:$rs,
- CPU16Regs:$rl, simm16:$imm),
+ MipsPseudo16<(outs CPU16Opnd:$rd_), (ins CPU16Opnd:$rd, CPU16Opnd:$rs,
+ CPU16Opnd:$rl, simm16:$imm),
!strconcat(op2,
!strconcat("\t$rl, $imm\n\t",
!strconcat(op1, "\t.+4\n\tmove $rd, $rs"))), []> {
@@ -469,9 +778,9 @@ class SeliT<string op1, string op2>:
//
//
class SelT<string op1, string op2>:
- MipsPseudo16<(outs CPU16Regs:$rd_),
- (ins CPU16Regs:$rd, CPU16Regs:$rs,
- CPU16Regs:$rl, CPU16Regs:$rr),
+ MipsPseudo16<(outs CPU16Opnd:$rd_),
+ (ins CPU16Opnd:$rd, CPU16Opnd:$rs,
+ CPU16Opnd:$rl, CPU16Opnd:$rr),
!strconcat(op2,
!strconcat("\t$rl, $rr\n\t",
!strconcat(op1, "\t.+4\n\tmove $rd, $rs"))), []> {
@@ -486,7 +795,7 @@ class SelT<string op1, string op2>:
def Constant32 : MipsPseudo16<(outs), (ins simm32:$imm), "\t.word $imm", []>;
def LwConstant32 :
- MipsPseudo16<(outs CPU16Regs:$rx), (ins simm32:$imm, simm32:$constid),
+ MipsPseudo16<(outs CPU16Opnd:$rx), (ins simm32:$imm, simm32:$constid),
"lw\t$rx, 1f\n\tb\t2f\n\t.align\t2\n1: \t.word\t$imm\n2:", []>;
//
@@ -521,50 +830,93 @@ class MayStore {
}
//
-
// Format: ADDIU rx, immediate MIPS16e
-// Purpose: Add Immediate Unsigned Word (2-Operand, Extended)
+// Purpose: Add Immediate Unsigned Word (2-Operand)
// To add a constant to a 32-bit integer.
//
-def AddiuRxImmX16: FEXT_RI16_ins<0b01001, "addiu", IIM16Alu>;
+def AddiuRxImm16:
+ FRI16_ins<0b01001, "addiu", simm8, IIM16Alu>, ArithLogic16Defs<0>;
+def AddiuRxImmX16:
+ FEXT_RI16_ins<0b01001, "addiu", simm16, IIM16Alu>, ArithLogic16Defs<0>;
+
+// These next two are used only in patterns.
def AddiuRxRxImm16: F2RI16_ins<0b01001, "addiu", IIM16Alu>,
ArithLogic16Defs<0> {
let AddedComplexity = 5;
+ let isCodeGenOnly = 1;
}
+
def AddiuRxRxImmX16: FEXT_2RI16_ins<0b01001, "addiu", IIM16Alu>,
ArithLogic16Defs<0> {
let isCodeGenOnly = 1;
}
-let DecoderMethod = "DecodeFIXMEInstruction" in
-def AddiuRxRyOffMemX16:
- FEXT_RRI_A16_mem_ins<0, "addiu", mem16_ea, IIM16Alu>;
+// Format: ADDIU ry, rx immediate MIPS16e
+// Purpose: Add Immediate Unsigned Word (3-Operand)
+// To add a constant to a 32-bit integer.
//
+def AddiuRyRxImm16:
+ FRRI_A16_ins<0, "addiu", IIM16Alu>, ArithLogic16Defs<0>;
+
+def AddiuRyRxImmX16:
+ FEXT_RRI_A16_ins<0, "addiu", IIM16Alu>, ArithLogic16Defs<0>;
+
+def AddiuRxRyOffMemX16:
+ FEXT_RRI_A16_mem_ins<0, "addiu", mem16_ea, IIM16Alu>, ArithLogic16Defs<0> {
+ let isCodeGenOnly = 1;
+}
+
// Format: ADDIU rx, pc, immediate MIPS16e
-// Purpose: Add Immediate Unsigned Word (3-Operand, PC-Relative, Extended)
+// Purpose: Add Immediate Unsigned Word (3-Operand, PC-Relative)
// To add a constant to the program counter.
//
-def AddiuRxPcImmX16: FEXT_RI16_PC_ins<0b00001, "addiu", IIM16Alu>;
+def AddiuRxPcImm16: FRI16_Pseudo_ins<0b00001, "addiu", pc_pseudo_reg,
+ uimm8_lsl2, IIM16Alu> {
+ let DecoderMethod = "DecodeAddiuRxPcMips16";
+}
+
+def AddiuRxPcImmX16: FEXT_RI16_PC_ins<0b00001, "addiu", IIM16Alu> {
+ let DecoderMethod = "DecodeAddiuRxPcMips16";
+}
+
+
+// Format: ADDIU rx, sp, immediate MIPS16e
+// Purpose: Add Immediate Unsigned Word (3-Operand, SP-Relative)
+// To add a constant to the stack pointer.
+//
+def AddiuRxSpImm16: FRI16_Pseudo_ins<0b00000, "addiu", sp_pseudo_reg,
+ uimm8_lsl2, IIM16Alu> {
+ let Defs = [SP];
+ let Uses = [SP];
+ let DecoderMethod = "DecodeAddiuRxSpMips16";
+}
+
+def AddiuRxSpImmX16: FEXT_RI16_SP_ins<0b00000, "addiu", IIM16Alu> {
+ let Defs = [SP];
+ let Uses = [SP];
+ let DecoderMethod = "DecodeAddiuRxSpMips16";
+}
+
//
// Format: ADDIU sp, immediate MIPS16e
// Purpose: Add Immediate Unsigned Word (2-Operand, SP-Relative, Extended)
// To add a constant to the stack pointer.
//
-def AddiuSpImm16
- : FI816_SP_ins<0b011, "addiu", IIM16Alu> {
+def AddiuSpImm16 : FI816_SP_ins<0b011, "addiu", IIM16Alu> {
let Defs = [SP];
let Uses = [SP];
let AddedComplexity = 5;
+ let DecoderMethod = "DecodeAddiuSpMips16";
}
-def AddiuSpImmX16
- : FEXT_I816_SP_ins<0b011, "addiu", IIM16Alu> {
+def AddiuSpImmX16 : FEXT_I816_SP_ins<0b011, "addiu", IIM16Alu> {
let Defs = [SP];
let Uses = [SP];
+ let DecoderMethod = "DecodeAddiuSpMips16";
}
//
@@ -584,33 +936,43 @@ def AndRxRxRy16: FRxRxRy16_ins<0b01100, "and", IIM16Alu>, ArithLogic16Defs<1>;
//
-// Format: BEQZ rx, offset MIPS16e
-// Purpose: Branch on Equal to Zero
-// To test a GPR then do a PC-relative conditional branch.
+// Format: ASMACRO select, p0, p1, p2, p3, p4
+// Purpose: Application-Specific Macro Instruction
+// To execute an implementation-definable macro instruction
//
-def BeqzRxImm16: FRI16_B_ins<0b00100, "beqz", IIM16Alu>, cbranch16;
+def Asmacro16: FASMACRO16<(outs),
+ (ins uimm3:$select, uimm5:$_p0, uimm3:$_p1, uimm3:$_p2,
+ uimm5:$_p3, uimm3:$_p4),
+ "asmacro\t$select, $_p0, $_p1, $_p2, $_p3, $_p4",
+ [], IIM16Alu>;
//
-// Format: BEQZ rx, offset MIPS16e
-// Purpose: Branch on Equal to Zero (Extended)
-// To test a GPR then do a PC-relative conditional branch.
+// Format: B offset MIPS16e
+// Purpose: Unconditional Branch
+// To do an unconditional PC-relative branch.
//
-def BeqzRxImmX16: FEXT_RI16_B_ins<0b00100, "beqz", IIM16Alu>, cbranch16;
+def Bimm16: FI16_B_ins<0b00010, "b", IIM16Alu>, branch16;
-//
// Format: B offset MIPS16e
// Purpose: Unconditional Branch (Extended)
// To do an unconditional PC-relative branch.
//
+def BimmX16: FEXT_I16_ins<0b00010, "b", IIM16Alu>, branch16;
-def Bimm16: FI16_ins<0b00010, "b", IIM16Alu>, branch16;
+//
+// Format: BEQZ rx, offset MIPS16e
+// Purpose: Branch on Equal to Zero
+// To test a GPR then do a PC-relative conditional branch.
+//
+def BeqzRxImm16: FRI16_B_ins<0b00100, "beqz", IIM16Alu>, cbranch16;
-// Format: B offset MIPS16e
-// Purpose: Unconditional Branch
-// To do an unconditional PC-relative branch.
//
-def BimmX16: FEXT_I16_ins<0b00010, "b", IIM16Alu>, branch16;
+// Format: BEQZ rx, offset MIPS16e
+// Purpose: Branch on Equal to Zero (Extended)
+// To test a GPR then do a PC-relative conditional branch.
+//
+def BeqzRxImmX16: FEXT_RI16_B_ins<0b00100, "beqz", IIM16Alu>, cbranch16;
//
// Format: BNEZ rx, offset MIPS16e
@@ -632,24 +994,24 @@ def BnezRxImmX16: FEXT_RI16_B_ins<0b00101, "bnez", IIM16Alu>, cbranch16;
// Purpose: Breakpoint
// To cause a Breakpoint exception.
-def Break16: FRRBreakNull16_ins<"break 0", IIM16Alu>;
+def Break16: FC16_ins<0b00101, "break", IIM16Alu>;
+
//
// Format: BTEQZ offset MIPS16e
// Purpose: Branch on T Equal to Zero (Extended)
// To test special register T then do a PC-relative conditional branch.
//
-def Bteqz16: FI816_ins<0b000, "bteqz", IIM16Alu>, cbranch16 {
+def Bteqz16: FI816_B_ins<0b000, "bteqz", IIM16Alu>, cbranch16 {
let Uses = [T8];
}
-def BteqzX16: FEXT_I816_ins<0b000, "bteqz", IIM16Alu>, cbranch16 {
+def BteqzX16: FEXT_I816_B_ins<0b000, "bteqz", IIM16Alu>, cbranch16 {
let Uses = [T8];
}
def BteqzT8CmpX16: FEXT_T8I816_ins<"bteqz", "cmp">, cbranch16;
-def BteqzT8CmpiX16: FEXT_T8I8I16_ins<"bteqz", "cmpi">,
- cbranch16;
+def BteqzT8CmpiX16: FEXT_T8I8I16_ins<"bteqz", "cmpi">, cbranch16;
def BteqzT8SltX16: FEXT_T8I816_ins<"bteqz", "slt">, cbranch16;
@@ -657,8 +1019,7 @@ def BteqzT8SltuX16: FEXT_T8I816_ins<"bteqz", "sltu">, cbranch16;
def BteqzT8SltiX16: FEXT_T8I8I16_ins<"bteqz", "slti">, cbranch16;
-def BteqzT8SltiuX16: FEXT_T8I8I16_ins<"bteqz", "sltiu">,
- cbranch16;
+def BteqzT8SltiuX16: FEXT_T8I8I16_ins<"bteqz", "sltiu">, cbranch16;
//
// Format: BTNEZ offset MIPS16e
@@ -666,11 +1027,11 @@ def BteqzT8SltiuX16: FEXT_T8I8I16_ins<"bteqz", "sltiu">,
// To test special register T then do a PC-relative conditional branch.
//
-def Btnez16: FI816_ins<0b001, "btnez", IIM16Alu>, cbranch16 {
+def Btnez16: FI816_B_ins<0b001, "btnez", IIM16Alu>, cbranch16 {
let Uses = [T8];
}
-def BtnezX16: FEXT_I816_ins<0b001, "btnez", IIM16Alu> ,cbranch16 {
+def BtnezX16: FEXT_I816_B_ins<0b001, "btnez", IIM16Alu> ,cbranch16 {
let Uses = [T8];
}
@@ -684,8 +1045,7 @@ def BtnezT8SltuX16: FEXT_T8I816_ins<"btnez", "sltu">, cbranch16;
def BtnezT8SltiX16: FEXT_T8I8I16_ins<"btnez", "slti">, cbranch16;
-def BtnezT8SltiuX16: FEXT_T8I8I16_ins<"btnez", "sltiu">,
- cbranch16;
+def BtnezT8SltiuX16: FEXT_T8I8I16_ins<"btnez", "sltiu">, cbranch16;
//
// Format: CMP rx, ry MIPS16e
@@ -710,7 +1070,7 @@ def CmpiRxImm16: FRI16R_ins<0b01110, "cmpi", IIM16Alu> {
// Purpose: Compare Immediate (Extended)
// To compare a constant with the contents of a GPR.
//
-def CmpiRxImmX16: FEXT_RI16R_ins<0b01110, "cmpi", IIM16Alu> {
+def CmpiRxImmX16: FEXT_RI16R_ins<0b01110, "cmpi", uimm16, IIM16Alu> {
let Defs = [T8];
}
@@ -732,64 +1092,136 @@ def DivRxRy16: FRR16_div_ins<0b11010, "div", IIM16Alu> {
def DivuRxRy16: FRR16_div_ins<0b11011, "divu", IIM16Alu> {
let Defs = [HI0, LO0];
}
+
//
// Format: JAL target MIPS16e
// Purpose: Jump and Link
// To execute a procedure call within the current 256 MB-aligned
// region and preserve the current ISA.
//
+def Jal16 : FJAL16_ins<0, "jal", IIM16Alu> {
+ let hasDelaySlot = 1;
+ let isCall = 1;
+ let Defs = [RA];
+}
-def Jal16 : FJAL16_ins<0b0, "jal", IIM16Alu> {
- let hasDelaySlot = 0; // not true, but we add the nop for now
- let isCall=1;
+// This is used only in MipsConstantIslandPass.cpp for MIPS16 to generate a
+// branch that can reach further than the "b" instructions. The code assumes
+// RA is always saved and so it does not matter this this overwrites it.
+def JalB16 : FJAL16_ins<0, "jal", IIM16Alu>, branch16 {
+ let hasDelaySlot = 1;
+ let isBranch = 1;
+ let isCodeGenOnly = 1;
let Defs = [RA];
}
-def JalB16 : FJALB16_ins<0b0, "jal", IIM16Alu>, branch16 {
- let hasDelaySlot = 0; // not true, but we add the nop for now
- let isBranch=1;
+//
+// Format: JALX target MIPS16e
+// Purpose: Jump and Link Exchange
+// To execute a procedure call within the current 256 MB-aligned
+// region and change the ISA Mode from MIPS16e to 32-bit MIPS.
+//
+def Jalx16 : FJAL16_ins<1, "jalx", IIM16Alu> {
+ let hasDelaySlot = 1;
+ let isCall = 1;
let Defs = [RA];
}
//
-// Format: JR ra MIPS16e
+// Format: JALR(C) ra, rx MIPS16e
+// Purpose: Jump and Link Register
+// To execute a procedure call to an instruction address in
+// a register.
+//
+def JalrRaRx16: FRR16_JALRC_RaRx_ins<0, "jalr", IIM16Alu> {
+ let isBranch = 0;
+ let isIndirectBranch = 0;
+ let hasDelaySlot = 1;
+ let isCall = 1;
+ let isTerminator = 0;
+ let isBarrier = 1;
+ let DecoderMethod = "DecodeJalrRaRxMips16";
+}
+
+def JalrcRaRx16: FRR16_JALRC_RaRx_ins<1, "jalrc", IIM16Alu> {
+ let isBranch = 0;
+ let isIndirectBranch = 0;
+ let hasDelaySlot = 0;
+ let isCall = 1;
+ let isTerminator = 0;
+ let isBarrier = 1;
+ let DecoderMethod = "DecodeJalrRaRxMips16";
+}
+
+//
+// Format: JR(C) ra MIPS16e
// Purpose: Jump Register Through Register ra
// To execute a branch to the instruction address in the return
// address register.
//
-
-def JrRa16: FRR16_JALRC_RA_only_ins<0, 0, "jr", IIM16Alu> {
- let isBranch = 1;
- let isIndirectBranch = 1;
+def JrRa16: FRR16_JALRC_RA_only_ins<0, "jr", IIM16Alu> {
+ let isBranch = 0;
+ let isIndirectBranch = 0;
let hasDelaySlot = 1;
- let isTerminator=1;
+ let isTerminator = 1;
+ let isBarrier = 1;
+ let isReturn = 1;
+ let DecoderMethod = "DecodeJrRaMips16";
+}
+
+def JrcRa16: FRR16_JALRC_RA_only_ins<1, "jrc", IIM16Alu> {
+ let isBranch = 0;
+ let isIndirectBranch = 0;
+ let hasDelaySlot = 0;
+ let isTerminator = 1;
let isBarrier=1;
let isReturn=1;
+ let DecoderMethod = "DecodeJrRaMips16";
}
-def JrcRa16: FRR16_JALRC_RA_only_ins<1, 1, "jrc", IIM16Alu> {
+//
+// Format: JR(C) rx MIPS16e
+// Purpose: Jump Register Through MIPS16e GPR
+// To execute a branch to an instruction address in a register.
+def JrRx16: FRR16_JALRC_RX_only_ins<0, "jr", IIM16Alu> {
let isBranch = 1;
let isIndirectBranch = 1;
- let isTerminator=1;
- let isBarrier=1;
- let isReturn=1;
+ let hasDelaySlot = 1;
+ let isTerminator = 1;
+ let isBarrier = 1;
}
-def JrcRx16: FRR16_JALRC_ins<1, 1, 0, "jrc", IIM16Alu> {
- let rx = 0b000;
+def JrcRx16: FRR16_JALRC_RX_only_ins<1, "jrc", IIM16Alu> {
let isBranch = 1;
let isIndirectBranch = 1;
- let isTerminator=1;
- let isBarrier=1;
+ let hasDelaySlot = 0;
+ let isTerminator = 1;
+ let isBarrier = 1;
}
+
+//
+// Format: LB ry, offset(rx) MIPS16e
+// Purpose: Load Byte
+// To load a byte from memory as a signed value.
+//
+def LbRxRyOffMem16:
+ FRRI16_memload_ins<0b10000, "lb", mem16_lsl0, II_LB>, MayLoad;
+
//
// Format: LB ry, offset(rx) MIPS16e
// Purpose: Load Byte (Extended)
// To load a byte from memory as a signed value.
//
-def LbRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lb", mem16, II_LB>, MayLoad{
- let isCodeGenOnly = 1;
-}
+def LbRxRyOffMemX16:
+ FEXT_RRI16_memload_ins<0b10000, "lb", mem16ext, II_LB>, MayLoad;
+
+//
+// Format: LBU ry, offset(rx) MIPS16e
+// Purpose: Load Byte Unsigned
+// To load a byte from memory as a unsigned value.
+//
+def LbuRxRyOffMem16:
+ FRRI16_memload_ins<0b10100, "lbu", mem16_lsl0, II_LBU>, MayLoad;
//
// Format: LBU ry, offset(rx) MIPS16e
@@ -797,18 +1229,31 @@ def LbRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lb", mem16, II_LB>, MayLoad{
// To load a byte from memory as a unsigned value.
//
def LbuRxRyOffMemX16:
- FEXT_RRI16_mem_ins<0b10100, "lbu", mem16, II_LBU>, MayLoad {
- let isCodeGenOnly = 1;
-}
+ FEXT_RRI16_memload_ins<0b10100, "lbu", mem16ext, II_LBU>, MayLoad;
+
+//
+// Format: LH ry, offset(rx) MIPS16e
+// Purpose: Load Halfword signed
+// To load a halfword from memory as a signed value.
+//
+def LhRxRyOffMem16:
+ FRRI16_memload_ins<0b10001, "lh", mem16_lsl1, II_LH>, MayLoad;
//
// Format: LH ry, offset(rx) MIPS16e
// Purpose: Load Halfword signed (Extended)
// To load a halfword from memory as a signed value.
//
-def LhRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10100, "lh", mem16, II_LH>, MayLoad{
- let isCodeGenOnly = 1;
-}
+def LhRxRyOffMemX16:
+ FEXT_RRI16_memload_ins<0b10001, "lh", mem16ext, II_LH>, MayLoad;
+
+//
+// Format: LHU ry, offset(rx) MIPS16e
+// Purpose: Load Halfword unsigned
+// To load a halfword from memory as an unsigned value.
+//
+def LhuRxRyOffMem16:
+ FRRI16_memload_ins<0b10101, "lhu", mem16_lsl1, II_LHU>, MayLoad;
//
// Format: LHU ry, offset(rx) MIPS16e
@@ -816,57 +1261,100 @@ def LhRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10100, "lh", mem16, II_LH>, MayLoad{
// To load a halfword from memory as an unsigned value.
//
def LhuRxRyOffMemX16:
- FEXT_RRI16_mem_ins<0b10100, "lhu", mem16, II_LHU>, MayLoad {
- let isCodeGenOnly = 1;
-}
+ FEXT_RRI16_memload_ins<0b10101, "lhu", mem16ext, II_LHU>, MayLoad;
//
// Format: LI rx, immediate MIPS16e
// Purpose: Load Immediate
// To load a constant into a GPR.
//
-def LiRxImm16: FRI16_ins<0b01101, "li", IIM16Alu>;
+def LiRxImm16: FRI16_ins<0b01101, "li", uimm8, IIM16Alu>;
//
// Format: LI rx, immediate MIPS16e
// Purpose: Load Immediate (Extended)
// To load a constant into a GPR.
//
-def LiRxImmX16: FEXT_RI16_ins<0b01101, "li", IIM16Alu>;
+def LiRxImmX16: FEXT_RI16_ins<0b01101, "li", uimm16, IIM16Alu>;
-def LiRxImmAlignX16: FEXT_RI16_ins<0b01101, ".align 2\n\tli", IIM16Alu> {
+def LiRxImmAlignX16: FEXT_RI16_ins<0b01101, ".align 2\n\tli", uimm16, IIM16Alu> {
let isCodeGenOnly = 1;
}
+//
+// Format: LW ry, offset(rx) MIPS16e
+// Purpose: Load Word
+// To load a word from memory as a signed value.
+//
+def LwRxRyOffMem16:
+ FRRI16_memload_ins<0b10011, "lw", mem16_lsl2, II_LW>, MayLoad;
+
//
// Format: LW ry, offset(rx) MIPS16e
// Purpose: Load Word (Extended)
// To load a word from memory as a signed value.
//
-def LwRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lw", mem16, II_LW>, MayLoad{
- let isCodeGenOnly = 1;
+def LwRxRyOffMemX16:
+ FEXT_RRI16_memload_ins<0b10011, "lw", mem16ext, II_LW>, MayLoad;
+
+//
+// Format: LW rx, offset(sp) MIPS16e
+// Purpose: Load Word (SP-Relative)
+// To load an SP-relative word from memory as a signed value.
+//
+def LwRxSpImm16: FRI16_memload_ins<0b10010, "lw", mem16_sp, II_LW>, MayLoad {
+ let Uses = [SP];
}
+//
// Format: LW rx, offset(sp) MIPS16e
// Purpose: Load Word (SP-Relative, Extended)
// To load an SP-relative word from memory as a signed value.
//
-let DecoderMethod = "DecodeFIXMEInstruction" in
-def LwRxSpImmX16: FEXT_RRI16_mem_ins<0b10010, "lw", mem16sp, II_LW>, MayLoad;
+def LwRxSpImmX16:
+ FEXT_RI16_memload_ins<0b10010, "lw", mem16ext_sp, II_LW>, MayLoad {
+ let Uses = [SP];
+}
-def LwRxPcTcp16: FRI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad;
+//
+// Format: LW rx, offset(pc) MIPS16e
+// Purpose: Load Word (PC-Relative)
+// To load a PC-relative word from memory as a signed value.
+//
+def LwRxPcImm16: FRI16_memload_ins<0b10110, "lw", mem16_pc, II_LW>, MayLoad;
+
+//
+// Format: LW rx, offset(pc) MIPS16e
+// Purpose: Load Word (PC-Relative, Extended)
+// To load a PC-relative word from memory as a signed value.
+//
+def LwRxPcImmX16:
+ FEXT_RI16_memload_ins<0b10110, "lw", mem16ext_pc, II_LW>, MayLoad;
+
+
+// These are used in MipsConstantIslandPass.cpp to create a PC-relative load
+// from a nearby constant island.
+// FIXME: Could these go away when support for MIPS16 relocations is added?
+// Would that let the above LwRxPcImm(X)16 versions handle this?
+def LwRxPcTcp16: FRI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad {
+ let isCodeGenOnly = 1;
+}
+def LwRxPcTcpX16: FEXT_RI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad {
+ let isCodeGenOnly = 1;
+}
-def LwRxPcTcpX16: FEXT_RI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad;
//
// Format: MOVE r32, rz MIPS16e
// Purpose: Move
// To move the contents of a GPR to a GPR.
//
-def Move32R16: FI8_MOV32R16_ins<"move", IIM16Alu>;
+def Move32R16: FI8_MOV32R16_ins<"move", IIM16Alu> {
+ let isMoveReg = 1;
+}
//
// Format: MOVE ry, r32 MIPS16e
-//Purpose: Move
+// Purpose: Move
// To move the contents of a GPR to a GPR.
//
def MoveR3216: FI8_MOVR3216_ins<"move", IIM16Alu> {
@@ -879,7 +1367,6 @@ def MoveR3216: FI8_MOVR3216_ins<"move", IIM16Alu> {
// To copy the special purpose HI register to a GPR.
//
def Mfhi16: FRR16_M_ins<0b10000, "mfhi", IIM16Alu> {
- let ry = 0b000; // no 'ry' field
let Uses = [HI0];
let hasSideEffects = 0;
let isMoveReg = 1;
@@ -891,31 +1378,35 @@ def Mfhi16: FRR16_M_ins<0b10000, "mfhi", IIM16Alu> {
// To copy the special purpose LO register to a GPR.
//
def Mflo16: FRR16_M_ins<0b10010, "mflo", IIM16Alu> {
- let ry = 0b000; // no 'ry' field
let Uses = [LO0];
let hasSideEffects = 0;
let isMoveReg = 0;
}
//
-// Pseudo Instruction for mult
+// Format: MULT rx, ry MIPS16e
+// Purpose: Multiply Word
+// To multiply 32-bit signed integers.
//
-def MultRxRy16: FMULT16_ins<"mult"> {
+def MultRxRy16: FMULT16_ins<0b11000, "mult", IIM16Alu> {
let isCommutable = 1;
let hasSideEffects = 0;
let Defs = [HI0, LO0];
}
-def MultuRxRy16: FMULT16_ins<"multu"> {
+//
+// Format: MULTU rx, ry MIPS16e
+// Purpose: Multiply Unsigned Word
+// To multiply 32-bit unsigned integers.
+//
+def MultuRxRy16: FMULT16_ins<0b11001, "multu", IIM16Alu> {
let isCommutable = 1;
let hasSideEffects = 0;
let Defs = [HI0, LO0];
}
//
-// Format: MULT rx, ry MIPS16e
-// Purpose: Multiply Word
-// To multiply 32-bit signed integers.
+// Pseudo Instruction for mult
//
def MultRxRyRz16: FMULT16_LO_ins<"mult"> {
let isCommutable = 1;
@@ -924,9 +1415,7 @@ def MultRxRyRz16: FMULT16_LO_ins<"mult"> {
}
//
-// Format: MULTU rx, ry MIPS16e
-// Purpose: Multiply Unsigned Word
-// To multiply 32-bit unsigned integers.
+// Pseudo Instruction for multu
//
def MultuRxRyRz16: FMULT16_LO_ins<"multu"> {
let isCommutable = 1;
@@ -939,7 +1428,7 @@ def MultuRxRyRz16: FMULT16_LO_ins<"multu"> {
// Purpose: Negate
// To negate an integer value.
//
-def NegRxRy16: FUnaryRR16_ins<0b11101, "neg", IIM16Alu>;
+def NegRxRy16: FUnaryRR16_ins<0b01011, "neg", IIM16Alu>;
//
// Format: NOT rx, ry MIPS16e
@@ -965,18 +1454,16 @@ def OrRxRxRy16: FRxRxRy16_ins<0b01101, "or", IIM16Alu>, ArithLogic16Defs<1>;
//
def Restore16:
- FI8_SVRS16<0b1, (outs), (ins variable_ops),
- "", [], II_RESTORE >, MayLoad {
- let isCodeGenOnly = 1;
+ FI8_SVRS16<0b0, (outs), (ins svrs16:$svrs_ops, variable_ops),
+ "restore\t$svrs_ops", [], II_RESTORE >, MayLoad {
let Defs = [SP];
let Uses = [SP];
}
def RestoreX16:
- FI8_SVRS16<0b1, (outs), (ins variable_ops),
- "", [], II_RESTORE >, MayLoad {
- let isCodeGenOnly = 1;
+ FEXT_I8_SVRS16<0b0, (outs), (ins svrsExt:$svrs_ops, variable_ops),
+ "restore\t$svrs_ops", [], II_RESTORE >, MayLoad {
let Defs = [SP];
let Uses = [SP];
}
@@ -989,28 +1476,40 @@ def RestoreX16:
// saving return address and static registers, and adjusting stack
//
def Save16:
- FI8_SVRS16<0b1, (outs), (ins variable_ops),
- "", [], II_SAVE >, MayStore {
- let isCodeGenOnly = 1;
+ FI8_SVRS16<0b1, (outs), (ins svrs16:$svrs_ops, variable_ops),
+ "save\t$svrs_ops", [], II_SAVE >, MayStore {
let Uses = [SP];
let Defs = [SP];
}
def SaveX16:
- FI8_SVRS16<0b1, (outs), (ins variable_ops),
- "", [], II_SAVE >, MayStore {
- let isCodeGenOnly = 1;
+ FEXT_I8_SVRS16<0b1, (outs), (ins svrsExt:$svrs_ops, variable_ops),
+ "save\t$svrs_ops", [], II_SAVE >, MayStore {
let Uses = [SP];
let Defs = [SP];
}
+
+//
+// Format: SB ry, offset(rx) MIPS16e
+// Purpose: Store Byte
+// To store a byte to memory.
+//
+def SbRxRyOffMem16:
+ FRRI16_memstore_ins<0b11000, "sb", mem16_lsl0, II_SB>, MayStore;
+
//
// Format: SB ry, offset(rx) MIPS16e
// Purpose: Store Byte (Extended)
// To store a byte to memory.
//
-let DecoderMethod = "DecodeFIXMEInstruction" in
def SbRxRyOffMemX16:
- FEXT_RRI16_mem2_ins<0b11000, "sb", mem16, II_SB>, MayStore;
+ FEXT_RRI16_memstore_ins<0b11000, "sb", mem16ext, II_SB>, MayStore;
+
+//
+// Format: SDBBP immediate
+// Purpose: Software Debug Breakpoint
+// To cause a debug breakpoint exception.
+def Sdbbp16: FC16_ins<0b00001, "sdbbp", IIM16Alu>;
//
// Format: SEB rx MIPS16e
@@ -1141,15 +1640,29 @@ def SelTBtneZSltu: SelT<"btnez", "sltu">;
// if b==0 then rd = rs
//
def SelTBtneZSltiu: SeliT<"btnez", "sltiu">;
+
+//
+// Format: SH ry, offset(rx) MIPS16e
+// Purpose: Store Halfword
+// To store a halfword to memory.
//
+def ShRxRyOffMem16:
+ FRRI16_memstore_ins<0b11001, "sh", mem16_lsl1, II_SH>, MayStore;
+
//
// Format: SH ry, offset(rx) MIPS16e
// Purpose: Store Halfword (Extended)
// To store a halfword to memory.
//
-let DecoderMethod = "DecodeFIXMEInstruction" in
def ShRxRyOffMemX16:
- FEXT_RRI16_mem2_ins<0b11001, "sh", mem16, II_SH>, MayStore;
+ FEXT_RRI16_memstore_ins<0b11001, "sh", mem16ext, II_SH>, MayStore;
+
+//
+// Format: SLL rx, ry, sa MIPS16e
+// Purpose: Shift Word Left Logical
+// To execute a left-shift of a word by a fixed number of bits-1 to 8 bits.
+//
+def Sll16: FSHIFT16_ins<0b00, "sll", IIM16Alu>;
//
// Format: SLL rx, ry, sa MIPS16e
@@ -1180,7 +1693,7 @@ def SltiRxImm16: FRI16R_ins<0b01010, "slti", IIM16Alu> {
// To record the result of a less-than comparison with a constant.
//
//
-def SltiRxImmX16: FEXT_RI16R_ins<0b01010, "slti", IIM16Alu> {
+def SltiRxImmX16: FEXT_RI16R_ins<0b01010, "slti", simm16, IIM16Alu> {
let Defs = [T8];
}
@@ -1200,8 +1713,10 @@ def SltiuRxImm16: FRI16R_ins<0b01011, "sltiu", IIM16Alu> {
// Purpose: Set on Less Than Immediate Unsigned (Extended)
// To record the result of a less-than comparison with a constant.
//
-//
-def SltiuRxImmX16: FEXT_RI16R_ins<0b01011, "sltiu", IIM16Alu> {
+// This sign-extends the immediate operand, but treats both operands
+// as unsigned for the comparison. Allow a "relaxed" operand since,
+// for example, -1 and 65535 would yield the same result.
+def SltiuRxImmX16: FEXT_RI16R_ins<0b01011, "sltiu", simm16_relaxed, IIM16Alu> {
let Defs = [T8];
}
//
@@ -1245,33 +1760,46 @@ def SltuCCRxRy16: FCCRR16_ins<"sltu">;
//
def SravRxRy16: FRxRxRy16_ins<0b00111, "srav", IIM16Alu>;
+//
+// Format: SRA rx, ry, sa MIPS16e
+// Purpose: Shift Word Right Arithmetic
+// To execute an arithmetic right-shift of a word by a fixed
+// number of bits-1 to 8 bits.
+//
+def Sra16: FSHIFT16_ins<0b11, "sra", IIM16Alu>;
//
// Format: SRA rx, ry, sa MIPS16e
// Purpose: Shift Word Right Arithmetic (Extended)
// To execute an arithmetic right-shift of a word by a fixed
-// number of bits-1 to 8 bits.
+// number of bits-0 to 31 bits.
//
def SraX16: FEXT_SHIFT16_ins<0b11, "sra", IIM16Alu>;
-
//
-// Format: SRLV ry, rx MIPS16e
-// Purpose: Shift Word Right Logical Variable
-// To execute a logical right-shift of a word by a variable
-// number of bits.
+// Format: SRL rx, ry, sa MIPS16e
+// Purpose: Shift Word Right Logical
+// To execute a logical right-shift of a word by a fixed
+// number of bits-1 to 8 bits.
//
-def SrlvRxRy16: FRxRxRy16_ins<0b00110, "srlv", IIM16Alu>;
-
+def Srl16: FSHIFT16_ins<0b10, "srl", IIM16Alu>;
//
// Format: SRL rx, ry, sa MIPS16e
// Purpose: Shift Word Right Logical (Extended)
// To execute a logical right-shift of a word by a fixed
-// number of bits-1 to 31 bits.
+// number of bits-0 to 31 bits.
//
def SrlX16: FEXT_SHIFT16_ins<0b10, "srl", IIM16Alu>;
+//
+// Format: SRLV ry, rx MIPS16e
+// Purpose: Shift Word Right Logical Variable
+// To execute a logical right-shift of a word by a variable
+// number of bits.
+//
+def SrlvRxRy16: FRxRxRy16_ins<0b00110, "srlv", IIM16Alu>;
+
//
// Format: SUBU rz, rx, ry MIPS16e
// Purpose: Subtract Unsigned Word
@@ -1279,21 +1807,61 @@ def SrlX16: FEXT_SHIFT16_ins<0b10, "srl", IIM16Alu>;
//
def SubuRxRyRz16: FRRR16_ins<0b11, "subu", IIM16Alu>, ArithLogic16Defs<0>;
+//
+// Format: SW ry, offset(rx) MIPS16e
+// Purpose: Store Word
+// To store a word to memory.
+//
+def SwRxRyOffMem16:
+ FRRI16_memstore_ins<0b11011, "sw", mem16_lsl2, II_SW>, MayStore;
+
//
// Format: SW ry, offset(rx) MIPS16e
// Purpose: Store Word (Extended)
// To store a word to memory.
//
-let DecoderMethod = "DecodeFIXMEInstruction" in
-def SwRxRyOffMemX16: FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, II_SW>, MayStore;
+def SwRxRyOffMemX16:
+ FEXT_RRI16_memstore_ins<0b11011, "sw", mem16ext, II_SW>, MayStore;
//
// Format: SW rx, offset(sp) MIPS16e
// Purpose: Store Word rx (SP-Relative)
// To store an SP-relative word to memory.
//
-let DecoderMethod = "DecodeFIXMEInstruction" in
-def SwRxSpImmX16: FEXT_RRI16_mem2_ins<0b11010, "sw", mem16sp, II_SW>, MayStore;
+def SwRxSpImm16: FRI16_memstore_ins<0b11010, "sw", mem16_sp, II_SW>, MayStore {
+ let Uses = [SP];
+}
+
+//
+// Format: SW rx, offset(sp) MIPS16e
+// Purpose: Store Word rx (SP-Relative, Extended)
+// To store an SP-relative word to memory.
+//
+def SwRxSpImmX16:
+ FEXT_RI16_memstore_ins<0b11010, "sw", mem16ext_sp, II_SW>, MayStore {
+ let Uses = [SP];
+}
+
+//
+// Format: SW ra, offset(sp) MIPS16e
+// Purpose: Store Word ra (SP-Relative)
+// To store register ra SP-relative to memory.
+//
+def SwRaSpImm16: FI816_RA_mem_ins<0b010, "sw", mem16_sp, II_SW>, MayStore {
+ let Uses = [RA, SP];
+ let DecoderMethod = "DecodeSwRaSpMips16";
+}
+
+//
+// Format: SW ra, offset(sp) MIPS16e
+// Purpose: Store Word ra (SP-Relative, Extended)
+// To store register ra SP-relative to memory.
+//
+def SwRaSpImmX16:
+ FEXT_I816_RA_mem_ins<0b010, "sw", mem16ext_sp, II_SW>, MayStore {
+ let Uses = [RA, SP];
+ let DecoderMethod = "DecodeSwRaSpMips16";
+}
//
//
@@ -1303,6 +1871,23 @@ def SwRxSpImmX16: FEXT_RRI16_mem2_ins<0b11010, "sw", mem16sp, II_SW>, MayStore;
//
def XorRxRxRy16: FRxRxRy16_ins<0b01110, "xor", IIM16Alu>, ArithLogic16Defs<1>;
+//
+// Format: ZEB rx MIPS16e
+// Purpose: Zero-Extend Byte
+// Zero-extend least significant byte in register rx.
+//
+def ZebRx16
+ : FRR_SF16_ins<0b10001, 0b000, "zeb", IIM16Alu>;
+
+//
+// Format: ZEH rx MIPS16e
+// Purpose: Zero-Extend Halfword
+// Zero-extend least significant word in register rx.
+//
+def ZehRx16
+ : FRR_SF16_ins<0b10001, 0b001, "zeh", IIM16Alu>;
+
+
class Mips16Pat<dag pattern, dag result> : Pat<pattern, result> {
let Predicates = [InMips16Mode];
}
@@ -1383,13 +1968,16 @@ def: Mips16Pat<(brind CPU16Regs:$rs), (JrcRx16 CPU16Regs:$rs)> {
}
// Jump and Link (Call)
-let isCall=1, hasDelaySlot=0 in
-def JumpLinkReg16:
- FRR16_JALRC<0, 0, 0, (outs), (ins CPU16Regs:$rx),
- "jalrc\t$rx", [(MipsJmpLink CPU16Regs:$rx)], II_JALRC> {
+def JumpLinkReg16 :
+ MipsPseudo16<(outs), (ins CPU16Opnd:$rx), "", [(MipsJmpLink CPU16Opnd:$rx)]>,
+ PseudoInstExpansion<(JalrcRaRx16 RA, CPU16Opnd:$rx)> {
+ let isCall = 1;
+ let hasDelaySlot = 0;
+ let isBarrier = 1;
let Defs = [RA];
}
+
// Mips16 pseudos
let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1,
hasExtraSrcRegAllocReq = 1 in
@@ -1544,6 +2132,8 @@ def: Mips16Pat
// (BtnezT8SltuX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16)
// >;
+// This is the 16-bit unconditional branch. It is expanded to BimmX16
+// if needed in MipsConstantIslandPass::fixupUnconditionalBr().
def: UncondBranch16_pat<br, Bimm16>;
// Small immediates
@@ -1884,7 +2474,7 @@ def : Mips16Pat<(i32 (extloadi8 addr16:$src)),
def : Mips16Pat<(i32 (extloadi16 addr16:$src)),
(LhuRxRyOffMemX16 addr16:$src)>;
-def: Mips16Pat<(trap), (Break16)>;
+def: Mips16Pat<(trap), (Break16 0)>;
def : Mips16Pat<(sext_inreg CPU16Regs:$val, i8),
(SebRx16 CPU16Regs:$val)>;
@@ -1915,5 +2505,12 @@ MipsPseudo16<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx,
// Instruction Aliases
-let EncodingPredicates = [InMips16Mode] in
-def : MipsInstAlias<"nop", (Move32R16 ZERO, S0)>;
+let EncodingPredicates = [InMips16Mode] in {
+ def : MipsInstAlias<"break", (Break16 0)>;
+ def : MipsInstAlias<"sdbbp", (Sdbbp16 0)>;
+ def : MipsInstAlias<"nop", (Move32R16 ZERO, S0)>;
+ def : MipsInstAlias<"div $rs, $rt",
+ (DivRxRy16 CPU16Opnd:$rs, CPU16Opnd:$rt)>;
+ def : MipsInstAlias<"divu $rs, $rt",
+ (DivuRxRy16 CPU16Opnd:$rs, CPU16Opnd:$rt)>;
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
index e267a6d0844c64..7e8c7d12dcaab9 100644
--- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -244,7 +244,11 @@ void MipsAsmPrinter::emitInstruction(const MachineInstr *MI) {
return;
}
- if (EmitJalrReloc &&
+ // FIXME: This is disabled for MIPS16 because otherwise some MIPS16 tests
+ // crash. Can this be made usable for MIPS16, maybe when MIPS16 relocations
+ // are supported? There is no "R_MIPS16_JALR" reloc, so maybe not.
+ // If this is updated, also update MipsAsmParser::isJalrRelocAvailable().
+ if (EmitJalrReloc && !Subtarget->inMips16Mode() &&
(MI->isReturn() || MI->isCall() || MI->isIndirectBranch())) {
emitDirectiveRelocJalr(*MI, OutContext, TM, *OutStreamer, *Subtarget);
}
@@ -718,6 +722,24 @@ printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) {
printOperand(MI, opNum+1, O);
}
+void MipsAsmPrinter::printPCPseudoReg(const MachineInstr *MI, int opNum,
+ raw_ostream &O) {
+ // Not a real operand; instead indicates a PC-realtive MIPS16 instruction.
+ O << "$pc";
+}
+
+void MipsAsmPrinter::printSPPseudoReg(const MachineInstr *MI, int opNum,
+ raw_ostream &O) {
+ // Not a real operand; instead indicates an SP-realtive MIPS16 instruction.
+ O << "$sp";
+}
+
+void MipsAsmPrinter::printRAPseudoReg(const MachineInstr *MI, int opNum,
+ raw_ostream &O) {
+ // Not a real operand; instead indicates the MIPS16 instruction accesses RA.
+ O << "$ra";
+}
+
void MipsAsmPrinter::
printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
const char *Modifier) {
@@ -725,6 +747,16 @@ printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
}
+void MipsAsmPrinter::printSaveRestore(const MachineInstr *MI, int opNum,
+ raw_ostream &O) {
+ for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {
+ if (i != opNum)
+ O << ", ";
+
+ printOperand(MI, i, O);
+ }
+}
+
void MipsAsmPrinter::
printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) {
for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.h b/llvm/lib/Target/Mips/MipsAsmPrinter.h
index d53a0f6a396675..bae57c62364244 100644
--- a/llvm/lib/Target/Mips/MipsAsmPrinter.h
+++ b/llvm/lib/Target/Mips/MipsAsmPrinter.h
@@ -148,8 +148,12 @@ class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter {
void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
void printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O);
+ void printPCPseudoReg(const MachineInstr *MI, int opNum, raw_ostream &O);
+ void printSPPseudoReg(const MachineInstr *MI, int opNum, raw_ostream &O);
+ void printRAPseudoReg(const MachineInstr *MI, int opNum, raw_ostream &O);
void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
const char *Modifier = nullptr);
+ void printSaveRestore(const MachineInstr *MI, int opNum, raw_ostream &O);
void printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O);
void emitStartOfAsmFile(Module &M) override;
void emitEndOfAsmFile(Module &M) override;
diff --git a/llvm/lib/Target/Mips/MipsBranchExpansion.cpp b/llvm/lib/Target/Mips/MipsBranchExpansion.cpp
index 721e525331c6ce..cdf68a1d187b56 100644
--- a/llvm/lib/Target/Mips/MipsBranchExpansion.cpp
+++ b/llvm/lib/Target/Mips/MipsBranchExpansion.cpp
@@ -881,7 +881,7 @@ bool MipsBranchExpansion::runOnMachineFunction(MachineFunction &MF) {
STI = &MF.getSubtarget<MipsSubtarget>();
TII = static_cast<const MipsInstrInfo *>(STI->getInstrInfo());
- if (IsPIC && ABI.IsO32() &&
+ if (!STI->inMips16Mode() && IsPIC && ABI.IsO32() &&
MF.getInfo<MipsFunctionInfo>()->globalBaseRegSet())
emitGPDisp(MF, TII);
diff --git a/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp b/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp
index 311b73710fb7a1..dcf2c4b16d31e2 100644
--- a/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp
+++ b/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp
@@ -1502,6 +1502,7 @@ MipsConstantIslands::fixupUnconditionalBr(ImmBranch &Br) {
if (isBBInRange(MI, DestBB, BimmX16MaxDisp)) {
Br.MaxDisp = BimmX16MaxDisp;
MI->setDesc(TII->get(Mips::BimmX16));
+ BBInfo[MBB->getNumber()].Size += 2;
}
else {
// need to give the math a more careful look here
@@ -1518,8 +1519,12 @@ MipsConstantIslands::fixupUnconditionalBr(ImmBranch &Br) {
DestBB->setAlignment(Align(4));
Br.MaxDisp = ((1<<24)-1) * 2;
MI->setDesc(TII->get(Mips::JalB16));
+ MachineInstr *DelaySlotNop =
+ BuildMI(MBB, DebugLoc(), TII->get(Mips::Move32R16), Mips::ZERO)
+ .addReg(Mips::S0);
+ DelaySlotNop->bundleWithPred();
+ BBInfo[MBB->getNumber()].Size += 4;
}
- BBInfo[MBB->getNumber()].Size += 2;
adjustBBOffsetsAfter(MBB);
HasFarJump = true;
++NumUBrFixed;
diff --git a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
index 4ec01ab7b45659..c75865777ad4e4 100644
--- a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
+++ b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
@@ -611,9 +611,10 @@ bool MipsDelaySlotFiller::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
continue;
// Delay slot filling is disabled at -O0, or in microMIPS32R6.
+ // FIXME: Add support for MIPS16. All delay slots in MIPS16 are 16-bit.
if (!DisableDelaySlotFiller &&
(TM->getOptLevel() != CodeGenOptLevel::None) &&
- !(InMicroMipsMode && STI.hasMips32r6())) {
+ !(InMicroMipsMode && STI.hasMips32r6()) && !STI.inMips16Mode()) {
bool Filled = false;
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.cpp b/llvm/lib/Target/Mips/MipsInstrInfo.cpp
index f4fba5e53132df..f9b9e1c15affc7 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.cpp
@@ -64,15 +64,18 @@ insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const
MachineInstrBuilder MipsInstrInfo::insertNop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
DebugLoc DL) const {
- assert(!Subtarget.inMips16Mode() &&
- "insertNop does not support MIPS16e mode at this time");
- const unsigned MMOpc =
- Subtarget.hasMips32r6() ? Mips::SLL_MMR6 : Mips::SLL_MM;
- const unsigned Opc =
- Subtarget.inMicroMipsMode() ? MMOpc : (unsigned)Mips::SLL;
- return BuildMI(MBB, MI, DL, get(Opc), Mips::ZERO)
- .addReg(Mips::ZERO)
- .addImm(0);
+ if (Subtarget.inMips16Mode()) {
+ return BuildMI(MBB, MI, DL, get(Mips::Move32R16), Mips::ZERO)
+ .addReg(Mips::S0);
+ } else {
+ const unsigned MMOpc =
+ Subtarget.hasMips32r6() ? Mips::SLL_MMR6 : Mips::SLL_MM;
+ const unsigned Opc =
+ Subtarget.inMicroMipsMode() ? MMOpc : (unsigned)Mips::SLL;
+ return BuildMI(MBB, MI, DL, get(Opc), Mips::ZERO)
+ .addReg(Mips::ZERO)
+ .addImm(0);
+ }
}
MachineMemOperand *
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.h b/llvm/lib/Target/Mips/MipsInstrInfo.h
index 4e039e0e32aba6..77735e29d688f9 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.h
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.h
@@ -114,7 +114,6 @@ class MipsInstrInfo : public MipsGenInstrInfo {
MachineBasicBlock::iterator MI) const override;
/// Insert an ISA appropriate `nop`.
- // FIXME: Add support for MIPS16e.
MachineInstrBuilder insertNop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
DebugLoc DL) const;
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td
index 85e3e78d2a4d8f..3c91da0722e16b 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.td
@@ -679,8 +679,15 @@ def ConstantSImm19Lsl2AsmOperandClass : AsmOperandClass {
let SuperClasses = [ConstantUImm20AsmOperandClass];
let DiagnosticType = "SImm19_Lsl2";
}
+def ConstantSImm16Lsl1AsmOperandClass : AsmOperandClass {
+ let Name = "SImm16Lsl1";
+ let RenderMethod = "addImmOperands";
+ let PredicateMethod = "isScaledSImm<16, 1>";
+ let SuperClasses = [ConstantSImm19Lsl2AsmOperandClass];
+ let DiagnosticType = "SImm16_Lsl1";
+}
def UImm16RelaxedAsmOperandClass
- : UImmAsmOperandClass<16, [ConstantUImm20AsmOperandClass]> {
+ : UImmAsmOperandClass<16, [ConstantSImm16Lsl1AsmOperandClass]> {
let Name = "UImm16_Relaxed";
let PredicateMethod = "isAnyImm<16>";
let DiagnosticType = "UImm16_Relaxed";
@@ -705,11 +712,13 @@ def SImm16RelaxedAsmOperandClass
}
def SImm16AsmOperandClass
: SImmAsmOperandClass<16, [SImm16RelaxedAsmOperandClass]>;
+def ConstantSImm15AsmOperandClass
+ : SImmAsmOperandClass<15, [SImm16AsmOperandClass]>;
def ConstantSImm10Lsl3AsmOperandClass : AsmOperandClass {
let Name = "SImm10Lsl3";
let RenderMethod = "addImmOperands";
let PredicateMethod = "isScaledSImm<10, 3>";
- let SuperClasses = [SImm16AsmOperandClass];
+ let SuperClasses = [ConstantSImm15AsmOperandClass];
let DiagnosticType = "SImm10_Lsl3";
}
def ConstantSImm10Lsl2AsmOperandClass : AsmOperandClass {
@@ -728,10 +737,24 @@ def ConstantSImm10Lsl1AsmOperandClass : AsmOperandClass {
let SuperClasses = [ConstantSImm11AsmOperandClass];
let DiagnosticType = "SImm10_Lsl1";
}
+def ConstantSImm8Lsl3AsmOperandClass : AsmOperandClass {
+ let Name = "SImm8Lsl3";
+ let RenderMethod = "addImmOperands";
+ let PredicateMethod = "isScaledSImm<8, 3>";
+ let SuperClasses = [ConstantSImm10Lsl1AsmOperandClass];
+ let DiagnosticType = "SImm8_Lsl3";
+}
def ConstantUImm10AsmOperandClass
- : ConstantUImmAsmOperandClass<10, [ConstantSImm10Lsl1AsmOperandClass]>;
+ : ConstantUImmAsmOperandClass<10, [ConstantSImm8Lsl3AsmOperandClass]>;
+def ConstantUImm8Lsl2AsmOperandClass : AsmOperandClass {
+ let Name = "UImm8Lsl2";
+ let RenderMethod = "addImmOperands";
+ let PredicateMethod = "isScaledUImm<8, 2>";
+ let SuperClasses = [ConstantUImm10AsmOperandClass];
+ let DiagnosticType = "UImm8_Lsl2";
+}
def ConstantSImm10AsmOperandClass
- : ConstantSImmAsmOperandClass<10, [ConstantUImm10AsmOperandClass]>;
+ : ConstantSImmAsmOperandClass<10, [ConstantUImm8Lsl2AsmOperandClass]>;
def ConstantSImm9AsmOperandClass
: ConstantSImmAsmOperandClass<9, [ConstantSImm10AsmOperandClass]>;
def ConstantSImm7Lsl2AsmOperandClass : AsmOperandClass {
@@ -743,8 +766,10 @@ def ConstantSImm7Lsl2AsmOperandClass : AsmOperandClass {
}
def ConstantUImm8AsmOperandClass
: ConstantUImmAsmOperandClass<8, [ConstantSImm7Lsl2AsmOperandClass]>;
+def ConstantSImm8AsmOperandClass
+ : ConstantSImmAsmOperandClass<8, [ConstantUImm8AsmOperandClass]>;
def ConstantUImm7Sub1AsmOperandClass
- : ConstantUImmAsmOperandClass<7, [ConstantUImm8AsmOperandClass], -1> {
+ : ConstantUImmAsmOperandClass<7, [ConstantSImm8AsmOperandClass], -1> {
// Specify the names since the -1 offset causes invalid identifiers otherwise.
let Name = "UImm7_N1";
let DiagnosticType = "UImm7_N1";
@@ -804,8 +829,10 @@ def ConstantUImm4AsmOperandClass
: ConstantUImmAsmOperandClass<4, [ConstantSImm5AsmOperandClass]>;
def ConstantSImm4AsmOperandClass
: ConstantSImmAsmOperandClass<4, [ConstantUImm4AsmOperandClass]>;
+def ConstantUImm3Plus1AsmOperandClass
+ : ConstantUImmAsmOperandClass<3, [ConstantSImm4AsmOperandClass], 1>;
def ConstantUImm3AsmOperandClass
- : ConstantUImmAsmOperandClass<3, [ConstantSImm4AsmOperandClass]>;
+ : ConstantUImmAsmOperandClass<3, [ConstantUImm3Plus1AsmOperandClass]>;
def ConstantUImm2Plus1AsmOperandClass
: ConstantUImmAsmOperandClass<2, [ConstantUImm3AsmOperandClass], 1>;
def ConstantUImm2AsmOperandClass
@@ -899,6 +926,14 @@ def uimm2_plus1 : Operand<i32> {
let ParserMatchClass = ConstantUImm2Plus1AsmOperandClass;
}
+// A 3-bit shift value for MIPS16 and MicroMIPS 16-bit instructions in which
+// a shift amount of 8 is encoded as 0.
+def uimm3_shift : Operand<i32> {
+ let EncoderMethod = "getUImm3Mod8Encoding";
+ let DecoderMethod = "DecodeUImm3Shift";
+ let ParserMatchClass = ConstantUImm3Plus1AsmOperandClass;
+}
+
def uimm5_plus1 : Operand<i32> {
let PrintMethod = "printUImm<5, 1>";
let EncoderMethod = "getUImmWithOffsetEncoding<5, 1>";
@@ -954,6 +989,12 @@ def uimm6_lsl2 : Operand<OtherVT> {
let ParserMatchClass = ConstantUImm6Lsl2AsmOperandClass;
}
+def uimm8_lsl2 : Operand<OtherVT> {
+ let EncoderMethod = "getUImm8Lsl2Encoding";
+ let DecoderMethod = "DecodeUImmWithOffsetAndScale<8, 0, 4>";
+ let ParserMatchClass = ConstantUImm8Lsl2AsmOperandClass;
+}
+
foreach I = {16} in
def uimm # I : Operand<i32> {
let PrintMethod = "printUImm<" # I # ">";
@@ -1020,7 +1061,7 @@ foreach I = {1, 2, 3, 4, 5, 6, 8} in
}
// Signed operands
-foreach I = {4, 5, 6, 9, 10, 11} in
+foreach I = {4, 5, 6, 8, 9, 10, 11, 15} in
def simm # I : Operand<i32> {
let DecoderMethod = "DecodeSImmWithOffsetAndScale<" # I # ">";
let ParserMatchClass =
@@ -1047,9 +1088,21 @@ foreach I = {5, 10} in
!cast<AsmOperandClass>("ConstantSImm" # I # "AsmOperandClass");
}
+def simm16_lsl1 : Operand<OtherVT> {
+ let EncoderMethod = "getSImm16Lsl1Encoding";
+ let DecoderMethod = "DecodeSImmWithOffsetAndScale<16, 0, 2>";
+ let ParserMatchClass = ConstantSImm16Lsl1AsmOperandClass;
+}
+
+def simm8_lsl3 : Operand<OtherVT> {
+ let EncoderMethod = "getSImm8Lsl3Encoding";
+ let DecoderMethod = "DecodeSImmWithOffsetAndScale<8, 0, 8>";
+ let ParserMatchClass = ConstantSImm8Lsl3AsmOperandClass;
+}
+
def simm7_lsl2 : Operand<OtherVT> {
let EncoderMethod = "getSImm7Lsl2Encoding";
- let DecoderMethod = "DecodeSImmWithOffsetAndScale<" # I # ", 0, 4>";
+ let DecoderMethod = "DecodeSImmWithOffsetAndScale<7, 0, 4>";
let ParserMatchClass = ConstantSImm7Lsl2AsmOperandClass;
}
@@ -2025,7 +2078,7 @@ def LONG_BRANCH_ADDiu2Op : PseudoSE<(outs GPR32Opnd:$dst),
//===----------------------------------------------------------------------===//
/// Arithmetic Instructions (ALU Immediate)
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode] in {
def ADDiu : MMRel, StdMMR6Rel, ArithLogicI<"addiu", simm16_relaxed, GPR32Opnd,
II_ADDIU, imm32SExt16, add>,
ADDI_FM<0x9>, IsAsCheapAsAMove, ISA_MIPS1;
@@ -2078,7 +2131,7 @@ let AdditionalPredicates = [NotInMicroMips] in {
ISA_MIPS1;
}
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode] in {
/// Shift Instructions
def SLL : MMRel, shift_rotate_imm<"sll", uimm5, GPR32Opnd, II_SLL, mshl_32,
immZExt5>, SRA_FM<0, 0>, ISA_MIPS1;
@@ -2103,7 +2156,7 @@ let AdditionalPredicates = [NotInMicroMips] in {
/// Load and Store Instructions
/// aligned
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode] in {
def LB : LoadMemory<"lb", GPR32Opnd, mem_simmptr, sextloadi8, II_LB>, MMRel,
LW_FM<0x20>, ISA_MIPS1;
def LBu : LoadMemory<"lbu", GPR32Opnd, mem_simmptr, zextloadi8, II_LBU,
@@ -2215,11 +2268,11 @@ def LL : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>, PTR_32, ISA_MIPS2_NOT_32R6_64R6;
def SC : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>, PTR_32, ISA_MIPS2_NOT_32R6_64R6;
}
/// Jump and Branch Instructions
-let AdditionalPredicates = [NotInMicroMips, RelocNotPIC] in
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode, RelocNotPIC] in
def J : MMRel, JumpFJ<jmptarget, "j", br, bb, "j">, FJ<2>,
IsBranch, ISA_MIPS1;
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode] in {
def JR : MMRel, IndirectBranch<"jr", GPR32Opnd>, MTLO_FM<8>,
ISA_MIPS1_NOT_32R6_64R6;
def BEQ : MMRel, CBranch<"beq", brtarget, seteq, GPR32Opnd>, BEQ_FM<4>,
@@ -2252,7 +2305,8 @@ def JAL : MMRel, JumpLink<"jal", calltarget>, FJ<3>, ISA_MIPS1;
}
-let AdditionalPredicates = [NotInMicroMips, NoIndirectJumpGuards] in {
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode,
+ NoIndirectJumpGuards] in {
def JALR : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM, ISA_MIPS1;
def JALRPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR, RA>, ISA_MIPS1;
}
@@ -2336,7 +2390,7 @@ let Uses = [V0, V1], isTerminator = 1, isReturn = 1,
}
/// Multiply and Divide Instructions.
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode] in {
def MULT : MMRel, Mult<"mult", II_MULT, GPR32Opnd, [HI0, LO0]>,
MULT_FM<0, 0x18>, ISA_MIPS1_NOT_32R6_64R6;
def MULTu : MMRel, Mult<"multu", II_MULTU, GPR32Opnd, [HI0, LO0]>,
@@ -2440,7 +2494,7 @@ let AdditionalPredicates = [NotInMicroMips] in {
class Barrier<string asmstr, InstrItinClass itin = NoItinerary> :
InstSE<(outs), (ins), asmstr, [], itin, FrmOther, asmstr>;
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode] in {
def SSNOP : MMRel, StdMMR6Rel, Barrier<"ssnop", II_SSNOP>, BARRIER_FM<1>,
ISA_MIPS1;
def EHB : MMRel, Barrier<"ehb", II_EHB>, BARRIER_FM<3>, ISA_MIPS1;
@@ -2875,12 +2929,14 @@ def : MipsInstAlias<"sub, $rd, $rs, $imm",
def : MipsInstAlias<"sub $rs, $imm",
(ADDi GPR32Opnd:$rs, GPR32Opnd:$rs, InvertedImOperand:$imm),
0>, ISA_MIPS1_NOT_32R6_64R6;
-def : MipsInstAlias<"subu, $rd, $rs, $imm",
- (ADDiu GPR32Opnd:$rd, GPR32Opnd:$rs,
- InvertedImOperand:$imm), 0>;
-def : MipsInstAlias<"subu $rs, $imm", (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rs,
- InvertedImOperand:$imm), 0>;
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMips16Mode] in {
+ def : MipsInstAlias<"subu, $rd, $rs, $imm",
+ (ADDiu GPR32Opnd:$rd, GPR32Opnd:$rs,
+ InvertedImOperand:$imm), 0>;
+ def : MipsInstAlias<"subu $rs, $imm", (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rs,
+ InvertedImOperand:$imm), 0>;
+}
+let AdditionalPredicates = [NotInMicroMips, NotInMips16Mode] in {
def : MipsInstAlias<"sll $rd, $rt, $rs",
(SLLV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
def : MipsInstAlias<"sra $rd, $rt, $rs",
@@ -2921,7 +2977,8 @@ let AdditionalPredicates = [NotInMicroMips] in
class LoadImmediate32<string instr_asm, Operand Od, RegisterOperand RO> :
MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32),
!strconcat(instr_asm, "\t$rt, $imm32")> ;
-def LoadImm32 : LoadImmediate32<"li", uimm32_coerced, GPR32Opnd>;
+let AdditionalPredicates = [NotInMips16Mode] in
+ def LoadImm32 : LoadImmediate32<"li", uimm32_coerced, GPR32Opnd>;
class LoadAddressFromReg32<string instr_asm, Operand MemOpnd,
RegisterOperand RO> :
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 3b12cb35b36731..c1cba7eb2ebaeb 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -58,6 +58,8 @@ MipsRegisterInfo::getPointerRegClass(const MachineFunction &MF,
return ABI.ArePtrs64bit() ? &Mips::SP64RegClass : &Mips::SP32RegClass;
case MipsPtrClass::GlobalPointer:
return ABI.ArePtrs64bit() ? &Mips::GP64RegClass : &Mips::GP32RegClass;
+ case MipsPtrClass::CPU16Regs:
+ return &Mips::CPU16RegsRegClass;
}
llvm_unreachable("Unknown pointer kind");
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.h b/llvm/lib/Target/Mips/MipsRegisterInfo.h
index b002f4cf3ae7a1..eddd1af33faea2 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.h
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.h
@@ -36,6 +36,8 @@ class MipsRegisterInfo : public MipsGenRegisterInfo {
StackPointer = 2,
/// The global pointer only.
GlobalPointer = 3,
+ /// The subset of registers permitted in most MIPS16 instructions
+ CPU16Regs = 4,
};
MipsRegisterInfo();
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.td b/llvm/lib/Target/Mips/MipsRegisterInfo.td
index 237ccdc5cc967f..c9309956820243 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.td
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.td
@@ -366,22 +366,24 @@ def GPR64 : RegisterClass<"Mips", [i64], 64, (add
K0_64, K1_64, GP_64, SP_64, FP_64, RA_64)>;
def CPU16Regs : RegisterClass<"Mips", [i32], 32, (add
- // Return Values and Arguments
- V0, V1, A0, A1, A2, A3,
// Callee save
- S0, S1)>;
+ S0, S1,
+ // Return Values and Arguments
+ V0, V1, A0, A1, A2, A3)>;
def CPU16RegsPlusSP : RegisterClass<"Mips", [i32], 32, (add
- // Return Values and Arguments
- V0, V1, A0, A1, A2, A3,
// Callee save
S0, S1,
+ // Return Values and Arguments
+ V0, V1, A0, A1, A2, A3,
SP)>;
def CPURAReg : RegisterClass<"Mips", [i32], 32, (add RA)>, Unallocatable;
def CPUSPReg : RegisterClass<"Mips", [i32], 32, (add SP)>, Unallocatable;
+def CPUPCReg : RegisterClass<"Mips", [i32], 32, (add PC)>, Unallocatable;
+
// 64bit fp:
// * FGR64 - 32 64-bit registers
// * AFGR64 - 16 32-bit even registers (32-bit FP Mode)
@@ -551,6 +553,16 @@ def GPRMM16AsmOperandMovePPairSecond : MipsAsmRegOperand {
let PredicateMethod = "isMM16AsmRegMovePPairSecond";
}
+def CPU16AsmOperand : MipsAsmRegOperand {
+ let Name = "CPU16AsmReg";
+ let PredicateMethod = "isCPU16AsmReg";
+}
+
+def CPU16AsmOperandPlusSP : MipsAsmRegOperand {
+ let Name = "CPU16AsmRegPlusSP";
+ let PredicateMethod = "isCPU16AsmRegPlusSP";
+}
+
def ACC64DSPAsmOperand : MipsAsmRegOperand {
let Name = "ACC64DSPAsmReg";
let PredicateMethod = "isACCAsmReg";
@@ -645,6 +657,14 @@ def GPRMM16OpndMovePPairSecond : RegisterOperand<GPRMM16MovePPairSecond> {
let ParserMatchClass = GPRMM16AsmOperandMovePPairSecond;
}
+def CPU16Opnd : RegisterOperand<CPU16Regs> {
+ let ParserMatchClass = CPU16AsmOperand;
+}
+
+def CPU16OpndPlusSP : RegisterOperand<CPU16RegsPlusSP> {
+ let ParserMatchClass = CPU16AsmOperandPlusSP;
+}
+
def GPR64Opnd : RegisterOperand<GPR64> {
let ParserMatchClass = GPR64AsmOperand;
}
diff --git a/llvm/lib/Target/Mips/MipsScheduleGeneric.td b/llvm/lib/Target/Mips/MipsScheduleGeneric.td
index 6771a897eea786..752956bb7ae2a4 100644
--- a/llvm/lib/Target/Mips/MipsScheduleGeneric.td
+++ b/llvm/lib/Target/Mips/MipsScheduleGeneric.td
@@ -63,21 +63,24 @@ def : InstRW<[GenericWriteALU], (instrs ADDIUPC, ALIGN, ALUIPC, AUI,
// MIPS16e
// =======
-def : InstRW<[GenericWriteALU], (instrs AddiuRxImmX16, AddiuRxRxImm16,
- AddiuRxRxImmX16, AddiuRxRyOffMemX16,
- AddiuRxPcImmX16, AddiuSpImm16, AddiuSpImmX16,
- AdduRxRyRz16, AndRxRxRy16, CmpRxRy16,
+def : InstRW<[GenericWriteALU], (instrs AddiuRxImm16, AddiuRxImmX16,
+ AddiuRxRxImm16, AddiuRxRxImmX16,
+ AddiuRxRyOffMemX16, AddiuRxPcImm16,
+ AddiuRxPcImmX16, AddiuRxSpImm16,
+ AddiuRxSpImmX16, AddiuSpImm16, AddiuSpImmX16,
+ AddiuRyRxImm16, AddiuRyRxImmX16, AdduRxRyRz16,
+ AndRxRxRy16, Asmacro16, CmpRxRy16,
CmpiRxImm16, CmpiRxImmX16, LiRxImm16,
LiRxImmX16, LiRxImmAlignX16, Move32R16,
MoveR3216, Mfhi16, Mflo16, NegRxRy16,
- NotRxRy16, OrRxRxRy16, SebRx16, SehRx16,
- SllX16, SllvRxRy16, SltiRxImm16,
- SltiRxImmX16, SltiCCRxImmX16,
- SltiuRxImm16, SltiuRxImmX16, SltiuCCRxImmX16,
- SltRxRy16, SltCCRxRy16, SltuRxRy16,
- SltuRxRyRz16, SltuCCRxRy16, SravRxRy16,
- SraX16, SrlvRxRy16, SrlX16, SubuRxRyRz16,
- XorRxRxRy16)>;
+ NotRxRy16, OrRxRxRy16, SebRx16, SehRx16,
+ Sll16, SllX16, SllvRxRy16, SltiRxImm16,
+ SltiRxImmX16, SltiCCRxImmX16, SltiuRxImm16,
+ SltiuRxImmX16, SltiuCCRxImmX16, SltRxRy16,
+ SltCCRxRy16, SltuRxRy16, SltuRxRyRz16,
+ SltuCCRxRy16, SravRxRy16, Sra16, SraX16,
+ SrlvRxRy16, Srl16, SrlX16, SubuRxRyRz16,
+ XorRxRxRy16, ZebRx16, ZehRx16)>;
def : InstRW<[GenericWriteALU], (instrs Constant32, LwConstant32,
GotPrologue16, CONSTPOOL_ENTRY)>;
@@ -337,11 +340,12 @@ def : InstRW<[GenericWriteJump], (instrs Bimm16, BimmX16, BeqzRxImm16,
BtnezT8CmpX16, BtnezT8CmpiX16,
BtnezT8SltX16, BtnezT8SltuX16,
BtnezT8SltiX16, BtnezT8SltiuX16, JrRa16,
- JrcRa16, JrcRx16, RetRA16)>;
+ JrcRa16, JrRx16, JrcRx16, RetRA16)>;
-def : InstRW<[GenericWriteJumpAndLink], (instrs Jal16, JalB16, JumpLinkReg16)>;
+def : InstRW<[GenericWriteJumpAndLink], (instrs Jal16, JalB16, JumpLinkReg16,
+ JalrRaRx16, JalrcRaRx16, Jalx16)>;
-def : InstRW<[GenericWriteTrap], (instrs Break16)>;
+def : InstRW<[GenericWriteTrap], (instrs Break16, Sdbbp16)>;
def : InstRW<[GenericWriteALULong], (instrs SelBeqZ, SelTBteqZCmp,
SelTBteqZCmpi, SelTBteqZSlt,
@@ -633,14 +637,21 @@ def : InstRW<[GenericWriteCache], (instrs CACHEE_MM)>;
// =======
def : InstRW<[GenericWriteLoad], (instrs Restore16, RestoreX16,
- LbRxRyOffMemX16,
- LbuRxRyOffMemX16, LhRxRyOffMemX16,
- LhuRxRyOffMemX16, LwRxRyOffMemX16,
- LwRxSpImmX16, LwRxPcTcp16, LwRxPcTcpX16)>;
-
-def : InstRW<[GenericWriteStore], (instrs Save16, SaveX16, SbRxRyOffMemX16,
- ShRxRyOffMemX16, SwRxRyOffMemX16,
- SwRxSpImmX16)>;
+ LbRxRyOffMem16, LbRxRyOffMemX16,
+ LbuRxRyOffMem16, LbuRxRyOffMemX16,
+ LhRxRyOffMem16, LhRxRyOffMemX16,
+ LhuRxRyOffMem16, LhuRxRyOffMemX16,
+ LwRxRyOffMem16, LwRxRyOffMemX16,
+ LwRxSpImm16, LwRxSpImmX16,
+ LwRxPcImm16, LwRxPcImmX16,
+ LwRxPcTcp16, LwRxPcTcpX16)>;
+
+def : InstRW<[GenericWriteStore], (instrs Save16, SaveX16,
+ SbRxRyOffMem16, SbRxRyOffMemX16,
+ ShRxRyOffMem16, ShRxRyOffMemX16,
+ SwRxRyOffMem16, SwRxRyOffMemX16,
+ SwRxSpImm16, SwRxSpImmX16,
+ SwRaSpImm16, SwRaSpImmX16)>;
// microMIPS
// =========
diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
index 7802767e31c2f6..3ad0466cc50dd1 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
@@ -329,6 +329,9 @@ void MipsPassConfig::addPreEmitPass() {
// Any new pass should go before this pass.
addPass(createMipsBranchExpansion());
+ // FIXME:
+ // This pass is for MIPS16 only and may replace branches with jumps that need
+ // their delay slots filled, so can this go before the delay slot filler?
addPass(createMipsConstantIslandPass());
}
diff --git a/llvm/test/CodeGen/Mips/addi.ll b/llvm/test/CodeGen/Mips/addi.ll
index 40a71698d5daf4..65824b7a5ca682 100644
--- a/llvm/test/CodeGen/Mips/addi.ll
+++ b/llvm/test/CodeGen/Mips/addi.ll
@@ -1,4 +1,6 @@
-; RUN: llc -mtriple=mipsel -mattr=mips16 -relocation-model=static < %s | FileCheck %s -check-prefix=16
+; RUN: llc -mtriple=mipsel -mattr=mips16 -relocation-model=static < %s \
+; RUN: | llvm-mc -arch=mipsel -mattr=+mips16 -show-inst \
+; RUN: | FileCheck %s -check-prefix=16
@i = global i32 6, align 4
@j = global i32 12, align 4
@@ -20,10 +22,10 @@ entry:
%3 = load i32, ptr @l, align 4
%sub2 = sub nsw i32 %3, 10000
store i32 %sub2, ptr @l, align 4
-; 16: addiu ${{[0-9]+}}, 5 # 16 bit inst
-; 16: addiu ${{[0-9]+}}, -5 # 16 bit inst
-; 16: addiu ${{[0-9]+}}, 10000
-; 16: addiu ${{[0-9]+}}, -10000
+; 16: addiu $[[#]], 5 # <MCInst #[[#]] AddiuRxImm16
+; 16: addiu $[[#]], -5 # <MCInst #[[#]] AddiuRxImm16
+; 16: addiu $[[#]], 10000 # <MCInst #[[#]] AddiuRxImmX16
+; 16: addiu $[[#]], -10000 # <MCInst #[[#]] AddiuRxImmX16
ret void
}
diff --git a/llvm/test/CodeGen/Mips/adjust-callstack-sp.ll b/llvm/test/CodeGen/Mips/adjust-callstack-sp.ll
index c583ff0fdd6cff..5e1923589363ee 100644
--- a/llvm/test/CodeGen/Mips/adjust-callstack-sp.ll
+++ b/llvm/test/CodeGen/Mips/adjust-callstack-sp.ll
@@ -11,7 +11,7 @@ declare void @bar(ptr)
define void @foo(i32 %sz) {
; ALL-LABEL: foo:
- ; M16-NOT: addiu $sp, 0 # 16 bit inst
+ ; M16-NOT: addiu $sp, 0
; GP32-NOT: addiu $sp, $sp, 0
; GP64-NOT: daddiu $sp, $sp, 0
%a = alloca i32, i32 %sz
diff --git a/llvm/test/CodeGen/Mips/align16.ll b/llvm/test/CodeGen/Mips/align16.ll
index a264272a6b818e..13374b0cc69696 100644
--- a/llvm/test/CodeGen/Mips/align16.ll
+++ b/llvm/test/CodeGen/Mips/align16.ll
@@ -1,4 +1,6 @@
-; RUN: llc -mtriple=mipsel -mattr=mips16 -relocation-model=static < %s | FileCheck %s -check-prefix=16
+; RUN: llc -mtriple=mipsel -mattr=mips16 -relocation-model=static < %s \
+; RUN: | llvm-mc -arch=mipsel -mattr=+mips16 -show-inst \
+; RUN: | FileCheck %s -check-prefix=16
@i = global i32 25, align 4
@.str = private unnamed_addr constant [5 x i8] c"%i \0A\00", align 1
@@ -25,7 +27,7 @@ entry:
call void @p(ptr %arrayidx1)
ret void
}
-; 16: save $ra, 2040
-; 16: addiu $sp, -40 # 16 bit inst
-; 16: addiu $sp, 40 # 16 bit inst
-; 16: restore $ra, 2040
+; 16: save $ra, 2040 # <MCInst #[[#]] SaveX16
+; 16: addiu $sp, -40 # <MCInst #[[#]] AddiuSpImm16
+; 16: addiu $sp, 40 # <MCInst #[[#]] AddiuSpImm16
+; 16: restore $ra, 2040 # <MCInst #[[#]] RestoreX16
diff --git a/llvm/test/CodeGen/Mips/alloca16.ll b/llvm/test/CodeGen/Mips/alloca16.ll
index b6921d59e94c95..b94452b8cc2874 100644
--- a/llvm/test/CodeGen/Mips/alloca16.ll
+++ b/llvm/test/CodeGen/Mips/alloca16.ll
@@ -20,7 +20,7 @@ entry:
define void @test() nounwind {
entry:
; 16: .frame $sp,8,$ra
-; 16: save 8 # 16 bit inst
+; 16: save 8
; 16: move $16, $sp
; 16: move ${{[0-9]+}}, $sp
; 16: subu $[[REGISTER:[0-9]+]], ${{[0-9]+}}, ${{[0-9]+}}
diff --git a/llvm/test/CodeGen/Mips/beqzc.ll b/llvm/test/CodeGen/Mips/beqzc.ll
index 11e009bcc79e2d..0630da298339b5 100644
--- a/llvm/test/CodeGen/Mips/beqzc.ll
+++ b/llvm/test/CodeGen/Mips/beqzc.ll
@@ -10,7 +10,7 @@ entry:
%cmp = icmp eq i32 %0, 0
%. = select i1 %cmp, i32 10, i32 55
store i32 %., ptr @j, align 4
-; cond-b-short: beqz ${{[0-9]+}}, $BB{{[0-9]+}}_{{[0-9]+}} # 16 bit inst
+; cond-b-short: beqz $[[#]], $BB[[#]]_[[#]]
ret i32 0
}
diff --git a/llvm/test/CodeGen/Mips/beqzc1.ll b/llvm/test/CodeGen/Mips/beqzc1.ll
index ad41ae271bb420..1364e05eed432d 100644
--- a/llvm/test/CodeGen/Mips/beqzc1.ll
+++ b/llvm/test/CodeGen/Mips/beqzc1.ll
@@ -10,7 +10,7 @@ entry:
%cmp = icmp eq i32 %0, 0
br i1 %cmp, label %if.then, label %if.end
-; cond-b-short: bnez ${{[0-9]+}}, $BB{{[0-9]+}}_{{[0-9]+}} # 16 bit inst
+; cond-b-short: bnez $[[#]], $BB[[#]]_[[#]]
if.then: ; preds = %entry
store i32 10, ptr @j, align 4
br label %if.end
diff --git a/llvm/test/CodeGen/Mips/brsize3.ll b/llvm/test/CodeGen/Mips/brsize3.ll
index a93de3269510cc..c93aac281cb280 100644
--- a/llvm/test/CodeGen/Mips/brsize3.ll
+++ b/llvm/test/CodeGen/Mips/brsize3.ll
@@ -1,12 +1,8 @@
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 \
; RUN: -mattr=+soft-float -mips16-hard-float -relocation-model=pic \
-; RUN: -mips16-constant-islands -verify-machineinstrs < %s | \
-; RUN: FileCheck %s -check-prefix=b-no-short
-
-; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 \
-; RUN: -mattr=+soft-float -mips16-hard-float -relocation-model=pic \
-; RUN: -mips16-constant-islands -verify-machineinstrs < %s | \
-; RUN: FileCheck %s -check-prefix=b-long
+; RUN: -mips16-constant-islands -verify-machineinstrs < %s \
+; RUN: | llvm-mc -arch=mipsel -mattr=+mips16 -show-inst \
+; RUN: | FileCheck %s
; ModuleID = 'brsize3.c'
target datalayout = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64"
@@ -20,16 +16,9 @@ entry:
x: ; preds = %x, %entry
tail call void asm sideeffect ".space 60000", ""() #1, !srcloc !1
br label %x
-; b-long: $BB0_1:
-; b-long: #APP
-; b-long: .space 60000
-; b-long: #NO_APP
-; b-long: b $BB0_1
-; b-no-short: $BB0_1:
-; b-no-short: #APP
-; b-no-short: .space 60000
-; b-no-short: #NO_APP
-; b-no-short-NOT: b $BB0_1 # 16 bit inst
+; CHECK: $BB0_1:
+; CHECK: .space 60000
+; CHECK: b $BB0_1 # <MCInst #[[#]] BimmX16
}
diff --git a/llvm/test/CodeGen/Mips/brsize3a.ll b/llvm/test/CodeGen/Mips/brsize3a.ll
index 87f96203047e21..0f8238db7f436d 100644
--- a/llvm/test/CodeGen/Mips/brsize3a.ll
+++ b/llvm/test/CodeGen/Mips/brsize3a.ll
@@ -16,7 +16,7 @@ x: ; preds = %x, %entry
; b-short: #APP
; b-short: .space 200
; b-short: #NO_APP
-; b-short: b $BB0_1 # 16 bit inst
+; b-short: b $BB0_1
}
diff --git a/llvm/test/CodeGen/Mips/const4a.ll b/llvm/test/CodeGen/Mips/const4a.ll
index 757629de5da351..7db6309f26ff39 100644
--- a/llvm/test/CodeGen/Mips/const4a.ll
+++ b/llvm/test/CodeGen/Mips/const4a.ll
@@ -15,7 +15,7 @@ define void @t() #0 {
entry:
store i32 -559023410, ptr @i, align 4
%0 = load i32, ptr @b, align 4
-; no-load-relax: lw ${{[0-9]+}}, $CPI0_1 # 16 bit inst
+; no-load-relax: lw $[[#]], $CPI0_1
%tobool = icmp ne i32 %0, 0
br i1 %tobool, label %if.then, label %if.else
; no-load-relax: beqz ${{[0-9]+}}, $BB0_3
diff --git a/llvm/test/CodeGen/Mips/const6.ll b/llvm/test/CodeGen/Mips/const6.ll
index 27e8eace4b1630..850f8f87424d07 100644
--- a/llvm/test/CodeGen/Mips/const6.ll
+++ b/llvm/test/CodeGen/Mips/const6.ll
@@ -16,15 +16,15 @@ target triple = "mips--linux-gnu"
define void @t() #0 {
entry:
store i32 -559023410, ptr @i, align 4
-; load-relax: lw ${{[0-9]+}}, $CPI0_0
+; load-relax: lw $[[#]], $CPI0_0
; load-relax: jrc $ra
; load-relax: .p2align 2
; load-relax: $CPI0_0:
; load-relax: .4byte 3735943886
; load-relax: .end t
-; no-load-relax: lw ${{[0-9]+}}, $CPI0_1 # 16 bit inst
-; no-load-relax: jalrc ${{[0-9]+}}
+; no-load-relax: lw $[[#]], $CPI0_1
+; no-load-relax: jalrc $ra, $[[#]]
; no-load-relax: b $BB0_2
; no-load-relax: .p2align 2
; no-load-relax: $CPI0_1:
diff --git a/llvm/test/CodeGen/Mips/const6a.ll b/llvm/test/CodeGen/Mips/const6a.ll
index 5a3f4a1f951ef7..9d674fdbe6f76c 100644
--- a/llvm/test/CodeGen/Mips/const6a.ll
+++ b/llvm/test/CodeGen/Mips/const6a.ll
@@ -1,6 +1,7 @@
-; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -mattr=+soft-float -mips16-hard-float -relocation-model=pic -mips16-constant-islands < %s | FileCheck %s -check-prefix=load-relax1
-
-; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -mattr=+soft-float -mips16-hard-float -relocation-model=pic -mips16-constant-islands < %s | FileCheck %s -check-prefix=load-relax
+; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 \
+; RUN: -mattr=+soft-float -mips16-hard-float -relocation-model=pic \
+; RUN: -mips16-constant-islands < %s \
+; RUN: | FileCheck %s -check-prefix=load-relax
; ModuleID = 'const6a.c'
target datalayout = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64"
@@ -12,8 +13,7 @@ target triple = "mips--linux-gnu"
define void @t() #0 {
entry:
store i32 -559023410, ptr @i, align 4
-; load-relax-NOT: lw ${{[0-9]+}}, $CPI0_0 # 16 bit inst
-; load-relax1: lw ${{[0-9]+}}, $CPI0_0
+; load-relax: lw $[[#]], $CPI0_0
; load-relax: jrc $ra
; load-relax: .p2align 2
; load-relax: $CPI0_0:
diff --git a/llvm/test/CodeGen/Mips/dins.ll b/llvm/test/CodeGen/Mips/dins.ll
index 4deb7455a80128..35bf4caf32aa74 100644
--- a/llvm/test/CodeGen/Mips/dins.ll
+++ b/llvm/test/CodeGen/Mips/dins.ll
@@ -107,16 +107,15 @@ define i64 @f123(i64 inreg %bufptr.coerce0, i64 inreg %bufptr.coerce1) local_unn
;
; MIPS16-LABEL: f123:
; MIPS16: # %bb.0: # %entry
-; MIPS16-NEXT: save 16 # 16 bit inst
-; MIPS16-EMPTY:
+; MIPS16-NEXT: save 16
; MIPS16-NEXT: .cfi_def_cfa_offset 16
; MIPS16-NEXT: lw $2, 8($sp)
; MIPS16-NEXT: lw $2, 12($sp)
; MIPS16-NEXT: li $3, 3
; MIPS16-NEXT: sw $3, 8($sp)
-; MIPS16-NEXT: lw $3, $CPI0_0 # 16 bit inst
+; MIPS16-NEXT: lw $3, $CPI0_0
; MIPS16-NEXT: and $3, $2
-; MIPS16-NEXT: lw $2, $CPI0_1 # 16 bit inst
+; MIPS16-NEXT: lw $2, $CPI0_1
; MIPS16-NEXT: or $2, $3
; MIPS16-NEXT: sw $2, 12($sp)
; MIPS16-NEXT: move $2, $zero
@@ -125,17 +124,17 @@ define i64 @f123(i64 inreg %bufptr.coerce0, i64 inreg %bufptr.coerce1) local_unn
; MIPS16-NEXT: and $3, $2
; MIPS16-NEXT: lw $2, 4($sp)
; MIPS16-NEXT: sw $3, 0($sp)
-; MIPS16-NEXT: lw $3, $CPI0_2 # 16 bit inst
+; MIPS16-NEXT: lw $3, $CPI0_2
; MIPS16-NEXT: and $3, $2
-; MIPS16-NEXT: lw $2, $CPI0_3 # 16 bit inst
+; MIPS16-NEXT: lw $2, $CPI0_3
; MIPS16-NEXT: or $2, $3
; MIPS16-NEXT: sw $2, 4($sp)
; MIPS16-NEXT: lw $2, 0($sp)
; MIPS16-NEXT: lw $3, 4($sp)
; MIPS16-NEXT: sw $3, 4($sp)
-; MIPS16-NEXT: lw $3, $CPI0_4 # 16 bit inst
+; MIPS16-NEXT: lw $3, $CPI0_4
; MIPS16-NEXT: and $3, $2
-; MIPS16-NEXT: lw $2, $CPI0_5 # 16 bit inst
+; MIPS16-NEXT: lw $2, $CPI0_5
; MIPS16-NEXT: or $2, $3
; MIPS16-NEXT: sw $2, 0($sp)
; MIPS16-NEXT: lw $2, 4($sp)
@@ -146,7 +145,7 @@ define i64 @f123(i64 inreg %bufptr.coerce0, i64 inreg %bufptr.coerce1) local_unn
; MIPS16-NEXT: srl $2, $2, 16
; MIPS16-NEXT: li $4, 65532
; MIPS16-NEXT: and $4, $2
-; MIPS16-NEXT: lw $2, $CPI0_6 # 16 bit inst
+; MIPS16-NEXT: lw $2, $CPI0_6
; MIPS16-NEXT: and $2, $3
; MIPS16-NEXT: or $2, $4
; MIPS16-NEXT: sw $2, 0($sp)
@@ -156,8 +155,7 @@ define i64 @f123(i64 inreg %bufptr.coerce0, i64 inreg %bufptr.coerce1) local_unn
; MIPS16-NEXT: sll $3, $4, 5
; MIPS16-NEXT: or $3, $2
; MIPS16-NEXT: srl $2, $4, 27
-; MIPS16-NEXT: restore 16 # 16 bit inst
-; MIPS16-EMPTY:
+; MIPS16-NEXT: restore 16
; MIPS16-NEXT: jrc $ra
; MIPS16-NEXT: .p2align 2
; MIPS16-NEXT: # %bb.1:
@@ -268,8 +266,7 @@ define i32 @foo(i32 signext %x) {
;
; MIPS16-LABEL: foo:
; MIPS16: # %bb.0: # %entry
-; MIPS16-NEXT: save 8 # 16 bit inst
-; MIPS16-EMPTY:
+; MIPS16-NEXT: save 8
; MIPS16-NEXT: .cfi_def_cfa_offset 8
; MIPS16-NEXT: sw $4, 4($sp)
; MIPS16-NEXT: move $3, $zero
@@ -279,8 +276,7 @@ define i32 @foo(i32 signext %x) {
; MIPS16-NEXT: li $3, 8
; MIPS16-NEXT: or $3, $2
; MIPS16-NEXT: sw $3, 4($sp)
-; MIPS16-NEXT: restore 8 # 16 bit inst
-; MIPS16-EMPTY:
+; MIPS16-NEXT: restore 8
; MIPS16-NEXT: jrc $ra
;
; MIPS64R2N32-LABEL: foo:
diff --git a/llvm/test/CodeGen/Mips/div.ll b/llvm/test/CodeGen/Mips/div.ll
index 839b2dee6d09ea..cded2e40df9fa0 100644
--- a/llvm/test/CodeGen/Mips/div.ll
+++ b/llvm/test/CodeGen/Mips/div.ll
@@ -9,8 +9,8 @@ entry:
%0 = load i32, ptr @iiii, align 4
%1 = load i32, ptr @jjjj, align 4
%div = sdiv i32 %0, %1
-; 16: div $zero, ${{[0-9]+}}, ${{[0-9]+}}
-; 16: mflo ${{[0-9]+}}
+; 16: div $[[#]], $[[#]]
+; 16: mflo $[[#]]
store i32 %div, ptr @kkkk, align 4
ret void
}
diff --git a/llvm/test/CodeGen/Mips/div_rem.ll b/llvm/test/CodeGen/Mips/div_rem.ll
index c8e22f262fb28a..da01a7241b361c 100644
--- a/llvm/test/CodeGen/Mips/div_rem.ll
+++ b/llvm/test/CodeGen/Mips/div_rem.ll
@@ -12,9 +12,9 @@ entry:
%div = sdiv i32 %0, %1
store i32 %div, ptr @kkkk, align 4
%rem = srem i32 %0, %1
-; 16: div $zero, ${{[0-9]+}}, ${{[0-9]+}}
-; 16: mflo ${{[0-9]+}}
-; 16: mfhi ${{[0-9]+}}
+; 16: div $[[#]], $[[#]]
+; 16: mflo $[[#]]
+; 16: mfhi $[[#]]
store i32 %rem, ptr @llll, align 4
ret void
}
diff --git a/llvm/test/CodeGen/Mips/divu.ll b/llvm/test/CodeGen/Mips/divu.ll
index caa49fd472b370..2b9d8f817e6e40 100644
--- a/llvm/test/CodeGen/Mips/divu.ll
+++ b/llvm/test/CodeGen/Mips/divu.ll
@@ -9,8 +9,8 @@ entry:
%0 = load i32, ptr @iiii, align 4
%1 = load i32, ptr @jjjj, align 4
%div = udiv i32 %0, %1
-; 16: divu $zero, ${{[0-9]+}}, ${{[0-9]+}}
-; 16: mflo ${{[0-9]+}}
+; 16: divu $[[#]], $[[#]]
+; 16: mflo $[[#]]
store i32 %div, ptr @kkkk, align 4
ret void
}
diff --git a/llvm/test/CodeGen/Mips/divu_remu.ll b/llvm/test/CodeGen/Mips/divu_remu.ll
index 820633be119bed..c6c0d3f3ec60fa 100644
--- a/llvm/test/CodeGen/Mips/divu_remu.ll
+++ b/llvm/test/CodeGen/Mips/divu_remu.ll
@@ -13,9 +13,9 @@ entry:
%div = udiv i32 %0, %1
store i32 %div, ptr @kkkk, align 4
%rem = urem i32 %0, %1
-; 16: divu $zero, ${{[0-9]+}}, ${{[0-9]+}}
-; 16: mflo ${{[0-9]+}}
-; 16: mfhi ${{[0-9]+}}
+; 16: divu $[[#]], $[[#]]
+; 16: mflo $[[#]]
+; 16: mfhi $[[#]]
store i32 %rem, ptr @llll, align 4
ret void
}
diff --git a/llvm/test/CodeGen/Mips/ex2.ll b/llvm/test/CodeGen/Mips/ex2.ll
index 79aabfcbbfc437..78660d4b95849b 100644
--- a/llvm/test/CodeGen/Mips/ex2.ll
+++ b/llvm/test/CodeGen/Mips/ex2.ll
@@ -6,7 +6,7 @@
define i32 @main() {
; 16-LABEL: main:
; 16: .cfi_startproc
-; 16: save $16, $17, $ra, 32 # 16 bit inst
+; 16: save $16, $17, $ra, 32
; 16: .cfi_def_cfa_offset 32
; 16: .cfi_offset 31, -4
; 16: .cfi_offset 17, -8
diff --git a/llvm/test/CodeGen/Mips/helloworld.ll b/llvm/test/CodeGen/Mips/helloworld.ll
index 152f8533fc36a6..76e6f8e6cacdf4 100644
--- a/llvm/test/CodeGen/Mips/helloworld.ll
+++ b/llvm/test/CodeGen/Mips/helloworld.ll
@@ -4,7 +4,9 @@
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -relocation-model=static -O3 < %s | FileCheck %s -check-prefix=ST1
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -relocation-model=static -O3 < %s | FileCheck %s -check-prefix=ST2
;
-; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=SR
+; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -relocation-model=pic -O3 < %s \
+; RUN: | llvm-mc -arch=mipsel -mattr=+mips16 -show-inst \
+; RUN: | FileCheck %s -check-prefix=SR
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips32 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=SR32
@@ -25,7 +27,7 @@ entry:
; SR32: .set noreorder
; SR32: .set nomacro
; SR32: .set noat
-; SR: save $ra, 24 # 16 bit inst
+; SR: save $ra, 24 # <MCInst #[[#]] Save16
; PE: .ent main
; PE: li $[[T1:[0-9]+]], %hi(_gp_disp)
; PE-NEXT: addiu $[[T2:[0-9]+]], $pc, %lo(_gp_disp)
@@ -35,8 +37,8 @@ entry:
; C1: addiu ${{[0-9]+}}, %lo($.str)
; C2: move $25, ${{[0-9]+}}
; C1: move $gp, ${{[0-9]+}}
-; C1: jalrc ${{[0-9]+}}
-; SR: restore $ra, 24 # 16 bit inst
+; C1: jalrc $ra, $[[#]]
+; SR: restore $ra, 24 # <MCInst #[[#]] Restore16
; PE: li $2, 0
; PE: jrc $ra
diff --git a/llvm/test/CodeGen/Mips/init-global-base-reg-16.ll b/llvm/test/CodeGen/Mips/init-global-base-reg-16.ll
new file mode 100644
index 00000000000000..9871c238468028
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/init-global-base-reg-16.ll
@@ -0,0 +1,37 @@
+; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=M16
+; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips32 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=M32
+
+;; When in MIPS16 mode, LLVM used to generate the global base register
+;; initialization code for both MIPS32 and MIPS16. The MIPS32 version
+;; uses the LUI instruction that is not supported in MIPS16. This checks
+;; that only the expected sequences are generated for MIPS32 vs MIPS16.
+
+ at .str = private unnamed_addr constant [13 x i8] c"hello world\0A\00", align 1
+
+define i32 @main() nounwind {
+entry:
+ %call = call i32 (ptr, ...) @printf(ptr @.str)
+ ret i32 0
+
+; M16: # %bb.0:
+; M16-NOT: lui ${{[0-9]+}}, %hi(_gp_disp)
+; M16-NOT: addiu ${{[0-9]+}}, ${{[0-9]+}}, %lo(_gp_disp)
+
+; M16: li $[[R1:[0-9]+]], %hi(_gp_disp)
+; M16: addiu $[[R2:[0-9]+]], $pc, %lo(_gp_disp)
+; M16: sll $[[R3:[0-9]+]], $[[R1]], 16
+; M16: addu ${{[0-9]+}}, $[[R2]], $[[R3]]
+
+
+; M32: # %bb.0:
+; M32: lui $[[R0:[0-9]+]], %hi(_gp_disp)
+; M32: addiu $[[R0]], $[[R0]], %lo(_gp_disp)
+
+; M32-NOT: li ${{[0-9]+}}, %hi(_gp_disp)
+; M32-NOT: addiu ${{[0-9]+}}, $pc, %lo(_gp_disp)
+; M32-NOT: sll ${{[0-9]+}}, ${{[0-9]+}}, 16
+; M32-NOT: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
+
+}
+
+declare i32 @printf(ptr, ...)
diff --git a/llvm/test/CodeGen/Mips/lcb2.ll b/llvm/test/CodeGen/Mips/lcb2.ll
index 7f9e71d5efecfd..7e6ddf756019c4 100644
--- a/llvm/test/CodeGen/Mips/lcb2.ll
+++ b/llvm/test/CodeGen/Mips/lcb2.ll
@@ -1,6 +1,8 @@
-; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -mattr=+soft-float -mips16-hard-float -relocation-model=static -mips16-constant-islands=true < %s | FileCheck %s -check-prefix=lcb
-
-; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -mattr=+soft-float -mips16-hard-float -relocation-model=static -mips16-constant-islands=true < %s | FileCheck %s -check-prefix=lcbn
+; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 \
+; RUN: -mattr=+soft-float -mips16-hard-float -relocation-model=static \
+; RUN: -mips16-constant-islands=true < %s \
+; RUN: | llvm-mc -arch=mipsel -mattr=+mips16 -show-inst \
+; RUN: | FileCheck %s -check-prefix=lcb
@i = global i32 0, align 4
@j = common global i32 0, align 4
@@ -22,11 +24,8 @@ if.end: ; preds = %if.then, %entry
ret i32 0
}
; lcb: .ent bnez
-; lcbn: .ent bnez
-; lcb: bnez ${{[0-9]+}}, $BB{{[0-9]+}}_{{[0-9]+}}
-; lcbn-NOT: bnez ${{[0-9]+}}, $BB{{[0-9]+}}_{{[0-9]+}} # 16 bit inst
+; lcb: bnez $[[#]], $BB[[#]]_[[#]] # <MCInst #[[#]] BnezRxImmX16
; lcb: .end bnez
-; lcbn: .end bnez
; Function Attrs: nounwind optsize
define i32 @beqz() #0 {
@@ -50,11 +49,8 @@ if.end: ; preds = %if.else, %if.then
}
; lcb: .ent beqz
-; lcbn: .ent beqz
-; lcb: beqz ${{[0-9]+}}, $BB{{[0-9]+}}_{{[0-9]+}}
-; lcbn-NOT: beqz ${{[0-9]+}}, $BB{{[0-9]+}}_{{[0-9]+}} # 16 bit inst
+; lcb: beqz $[[#]], $BB[[#]]_[[#]] # <MCInst #[[#]] BeqzRxImmX16
; lcb: .end beqz
-; lcbn: .end beqz
; Function Attrs: nounwind optsize
@@ -80,11 +76,8 @@ if.end: ; preds = %if.else, %if.then
}
; lcb: .ent bteqz
-; lcbn: .ent bteqz
-; lcb: btnez $BB{{[0-9]+}}_{{[0-9]+}}
-; lcbn-NOT: btnez $BB{{[0-9]+}}_{{[0-9]+}} # 16 bit inst
+; lcb: btnez $BB[[#]]_[[#]] # <MCInst #[[#]] BtnezX16
; lcb: .end bteqz
-; lcbn: .end bteqz
; Function Attrs: nounwind optsize
@@ -107,13 +100,9 @@ if.end: ; preds = %if.then, %entry
}
; lcb: .ent btz
-; lcbn: .ent btz
-; lcb: bteqz $BB{{[0-9]+}}_{{[0-9]+}}
-; lcbn-NOT: bteqz $BB{{[0-9]+}}_{{[0-9]+}} # 16 bit inst
-; lcb: btnez $BB{{[0-9]+}}_{{[0-9]+}}
-; lcbn-NOT: btnez $BB{{[0-9]+}}_{{[0-9]+}} # 16 bit inst
+; lcb: bteqz $BB[[#]]_[[#]] # <MCInst #[[#]] BteqzX16
+; lcb: btnez $BB[[#]]_[[#]] # <MCInst #[[#]] BtnezX16
; lcb: .end btz
-; lcbn: .end btz
attributes #0 = { nounwind optsize "less-precise-fpmad"="false" "frame-pointer"="none" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }
diff --git a/llvm/test/CodeGen/Mips/lcb3c.ll b/llvm/test/CodeGen/Mips/lcb3c.ll
index 386059f144ddf0..5c55899317bc5a 100644
--- a/llvm/test/CodeGen/Mips/lcb3c.ll
+++ b/llvm/test/CodeGen/Mips/lcb3c.ll
@@ -23,7 +23,7 @@ if.else: ; preds = %entry
if.end: ; preds = %if.else, %if.then
ret i32 0
; lcb: bnez $2, $BB0_2
-; lcb: b $BB0_1 # 16 bit inst
+; lcb: b $BB0_1
; lcb: $BB0_1: # %if.then
}
@@ -47,8 +47,8 @@ if.end: ; preds = %if.else, %if.then
ret i32 0
}
-; lcb: beqz $2, $BB1_1 # 16 bit inst
-; lcb: jal $BB1_2 # branch
+; lcb: beqz $2, $BB1_1
+; lcb: jal $BB1_2
; lcb: $BB1_1: # %if.then
attributes #0 = { nounwind "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
diff --git a/llvm/test/CodeGen/Mips/lcb4a.ll b/llvm/test/CodeGen/Mips/lcb4a.ll
index 87089a7795582e..1a8e2ea8a662f6 100644
--- a/llvm/test/CodeGen/Mips/lcb4a.ll
+++ b/llvm/test/CodeGen/Mips/lcb4a.ll
@@ -50,8 +50,8 @@ if.end: ; preds = %if.else, %if.then
ret i32 0
}
-; ci: bnez $3, $BB1_1 # 16 bit inst
-; ci: jal $BB1_2 # branch
+; ci: bnez $3, $BB1_1
+; ci: jal $BB1_2
; ci: nop
; ci: $BB1_1: # %if.else
diff --git a/llvm/test/CodeGen/Mips/lcb5.ll b/llvm/test/CodeGen/Mips/lcb5.ll
index f320f6fc5660ce..b34b1e07faae55 100644
--- a/llvm/test/CodeGen/Mips/lcb5.ll
+++ b/llvm/test/CodeGen/Mips/lcb5.ll
@@ -52,8 +52,8 @@ if.end: ; preds = %if.else, %if.then
}
; ci: .ent x1
-; ci: bnez $3, $BB1_1 # 16 bit inst
-; ci: jal $BB1_2 # branch
+; ci: bnez $3, $BB1_1
+; ci: jal $BB1_2
; ci: nop
; ci: $BB1_1:
; ci: .end x1
@@ -105,8 +105,8 @@ if.end: ; preds = %if.else, %if.then
}
; ci: .ent y1
-; ci: bnez $2, $BB3_1 # 16 bit inst
-; ci: jal $BB3_2 # branch
+; ci: bnez $2, $BB3_1
+; ci: jal $BB3_2
; ci: nop
; ci: $BB3_1:
; ci: .end y1
@@ -160,8 +160,8 @@ if.end: ; preds = %if.else, %if.then
}
; ci: .ent z1
-; ci: bteqz $BB5_1 # 16 bit inst
-; ci: jal $BB5_2 # branch
+; ci: bteqz $BB5_1
+; ci: jal $BB5_2
; ci: nop
; ci: $BB5_1:
; ci: .end z1
@@ -209,8 +209,8 @@ if.end: ; preds = %if.then, %entry
}
; ci: .ent z4
-; ci: btnez $BB7_1 # 16 bit inst
-; ci: jal $BB7_3 # branch
+; ci: btnez $BB7_1
+; ci: jal $BB7_3
; ci: nop
; ci: $BB7_1:
; ci: .p2align 2
diff --git a/llvm/test/CodeGen/Mips/rem.ll b/llvm/test/CodeGen/Mips/rem.ll
index 525ab633ca019e..30d7882faeedb2 100644
--- a/llvm/test/CodeGen/Mips/rem.ll
+++ b/llvm/test/CodeGen/Mips/rem.ll
@@ -10,8 +10,8 @@ entry:
%0 = load i32, ptr @iiii, align 4
%1 = load i32, ptr @jjjj, align 4
%rem = srem i32 %0, %1
-; 16: div $zero, ${{[0-9]+}}, ${{[0-9]+}}
-; 16: mfhi ${{[0-9]+}}
+; 16: div $[[#]], $[[#]]
+; 16: mfhi $[[#]]
store i32 %rem, ptr @kkkk, align 4
ret void
}
diff --git a/llvm/test/CodeGen/Mips/remu.ll b/llvm/test/CodeGen/Mips/remu.ll
index 3d5f5d7629d958..49476cd6ff8b5a 100644
--- a/llvm/test/CodeGen/Mips/remu.ll
+++ b/llvm/test/CodeGen/Mips/remu.ll
@@ -10,8 +10,8 @@ entry:
%0 = load i32, ptr @iiii, align 4
%1 = load i32, ptr @jjjj, align 4
%rem = urem i32 %0, %1
-; 16: divu $zero, ${{[0-9]+}}, ${{[0-9]+}}
-; 16: mfhi ${{[0-9]+}}
+; 16: divu $[[#]], $[[#]]
+; 16: mfhi $[[#]]
store i32 %rem, ptr @kkkk, align 4
ret void
}
diff --git a/llvm/test/CodeGen/Mips/sel1c.ll b/llvm/test/CodeGen/Mips/sel1c.ll
index b4cba37b78ec9e..1a28e2e929e4c6 100644
--- a/llvm/test/CodeGen/Mips/sel1c.ll
+++ b/llvm/test/CodeGen/Mips/sel1c.ll
@@ -13,7 +13,7 @@ entry:
%cond = select i1 %cmp, i32 1, i32 3
store i32 %cond, ptr @k, align 4
ret void
-; cond-b-short: bteqz $BB0_{{[0-9]+}} # 16 bit inst
+; cond-b-short: bteqz $BB0_[[#]]
}
attributes #0 = { nounwind optsize "less-precise-fpmad"="false" "frame-pointer"="none" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="true" }
diff --git a/llvm/test/CodeGen/Mips/sel2c.ll b/llvm/test/CodeGen/Mips/sel2c.ll
index 9cf8b20eecdd50..52a4365c5ea32a 100644
--- a/llvm/test/CodeGen/Mips/sel2c.ll
+++ b/llvm/test/CodeGen/Mips/sel2c.ll
@@ -12,7 +12,7 @@ entry:
%cmp = icmp ne i32 %0, %1
%cond = select i1 %cmp, i32 1, i32 3
store i32 %cond, ptr @k, align 4
-; cond-b-short: btnez $BB0_{{[0-9]+}} # 16 bit inst
+; cond-b-short: btnez $BB0_[[#]]
ret void
}
diff --git a/llvm/test/CodeGen/Mips/seleqk.ll b/llvm/test/CodeGen/Mips/seleqk.ll
index 911c6f1996b674..8df2f2dd2534ad 100644
--- a/llvm/test/CodeGen/Mips/seleqk.ll
+++ b/llvm/test/CodeGen/Mips/seleqk.ll
@@ -78,14 +78,14 @@ cond.end14: ; preds = %cond.false13, %cond
attributes #0 = { nounwind "target-cpu"="mips16" "target-features"="+mips16,+o32" }
attributes #1 = { "target-cpu"="mips16" "target-features"="+mips16,+o32" }
-; 16: cmpi ${{[0-9]+}}, 1 # 16 bit inst
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: cmpi $[[#]], 1
+; 16: btnez $BB[[#]]_[[#]]
-; 16: cmpi ${{[0-9]+}}, 1000
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: cmpi $[[#]], 1000
+; 16: btnez $BB[[#]]_[[#]]
-; 16: cmpi ${{[0-9]+}}, 3 # 16 bit inst
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: cmpi $[[#]], 3
+; 16: btnez $BB[[#]]_[[#]]
-; 16: cmpi ${{[0-9]+}}, 1000
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: cmpi $[[#]], 1000
+; 16: btnez $BB[[#]]_[[#]]
diff --git a/llvm/test/CodeGen/Mips/selgek.ll b/llvm/test/CodeGen/Mips/selgek.ll
index a909bb543538b7..ee93c99576b71a 100644
--- a/llvm/test/CodeGen/Mips/selgek.ll
+++ b/llvm/test/CodeGen/Mips/selgek.ll
@@ -79,16 +79,16 @@ cond.end14: ; preds = %cond.false13, %cond
attributes #0 = { nounwind "target-cpu"="mips16" "target-features"="+mips16,+o32" }
attributes #1 = { "target-cpu"="mips16" "target-features"="+mips16,+o32" }
-; 16: slti ${{[0-9]+}}, 1000
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: slti $[[#]], 1000
+; 16: btnez $BB[[#]]_[[#]]
-; 16: slti ${{[0-9]+}}, 1 # 16 bit inst
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: slti $[[#]], 1
+; 16: btnez $BB[[#]]_[[#]]
-; 16: slti ${{[0-9]+}}, 2 # 16 bit inst
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: slti $[[#]], 2
+; 16: btnez $BB[[#]]_[[#]]
-; 16: slti ${{[0-9]+}}, 2 # 16 bit inst
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: slti $[[#]], 2
+; 16: btnez $BB[[#]]_[[#]]
diff --git a/llvm/test/CodeGen/Mips/selltk.ll b/llvm/test/CodeGen/Mips/selltk.ll
index b070c301b01995..c59c675c0344a2 100644
--- a/llvm/test/CodeGen/Mips/selltk.ll
+++ b/llvm/test/CodeGen/Mips/selltk.ll
@@ -79,15 +79,15 @@ cond.end14: ; preds = %cond.false13, %cond
attributes #0 = { nounwind "target-cpu"="mips16" "target-features"="+mips16,+o32" }
attributes #1 = { "target-cpu"="mips16" "target-features"="+mips16,+o32" }
-; 16: slt ${{[0-9]+}}, ${{[0-9]+}}
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: slt $[[#]], $[[#]]
+; 16: btnez $BB[[#]]_[[#]]
-; 16: slt ${{[0-9]+}}, ${{[0-9]+}}
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: slt $[[#]], $[[#]]
+; 16: btnez $BB[[#]]_[[#]]
-; 16: slti ${{[0-9]+}}, 3 # 16 bit inst
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: slti $[[#]], 3
+; 16: btnez $BB[[#]]_[[#]]
-; 16: slti ${{[0-9]+}}, 3 # 16 bit inst
-; 16: btnez $BB{{[0-9]+}}_{{[0-9]}}
+; 16: slti $[[#]], 3
+; 16: btnez $BB[[#]]_[[#]]
diff --git a/llvm/test/CodeGen/Mips/selnek.ll b/llvm/test/CodeGen/Mips/selnek.ll
index f38ab246e60f47..cd5f204f2f7c7d 100644
--- a/llvm/test/CodeGen/Mips/selnek.ll
+++ b/llvm/test/CodeGen/Mips/selnek.ll
@@ -94,14 +94,14 @@ declare i32 @printf(ptr, ...) "target-cpu"="mips16" "target-features"="+mips16,+
attributes #0 = { nounwind "target-cpu"="mips16" "target-features"="+mips16,+o32" }
attributes #1 = { "target-cpu"="mips16" "target-features"="+mips16,+o32" }
-; 16: cmpi ${{[0-9]+}}, 1 # 16 bit inst
-; 16: bteqz $BB{{[0-9]+}}_{{[0-9]}}
+; 16: cmpi $[[#]], 1
+; 16: bteqz $BB[[#]]_[[#]]
-; 16: cmpi ${{[0-9]+}}, 1000
-; 16: bteqz $BB{{[0-9]+}}_{{[0-9]}}
+; 16: cmpi $[[#]], 1000
+; 16: bteqz $BB[[#]]_[[#]]
-; 16: cmpi ${{[0-9]+}}, 3 # 16 bit inst
-; 16: bteqz $BB{{[0-9]+}}_{{[0-9]}}
+; 16: cmpi $[[#]], 3
+; 16: bteqz $BB[[#]]_[[#]]
-; 16: cmpi ${{[0-9]+}}, 1000
-; 16: bteqz $BB{{[0-9]+}}_{{[0-9]}}
+; 16: cmpi $[[#]], 1000
+; 16: bteqz $BB[[#]]_[[#]]
diff --git a/llvm/test/CodeGen/Mips/setultk.ll b/llvm/test/CodeGen/Mips/setultk.ll
index 9801d388d22322..ba17a237105b96 100644
--- a/llvm/test/CodeGen/Mips/setultk.ll
+++ b/llvm/test/CodeGen/Mips/setultk.ll
@@ -15,8 +15,8 @@ entry:
%cmp = icmp ult i32 %0, 10
%conv = zext i1 %cmp to i32
store i32 %conv, ptr @r1, align 4
-; 16: sltiu ${{[0-9]+}}, 10 # 16 bit inst
-; MMR6: sltiu ${{[0-9]+}}, ${{[0-9]+}}, 1
-; 16: move ${{[0-9]+}}, $24
+; 16: sltiu $[[#]], 10
+; MMR6: sltiu $[[#]], $[[#]], 1
+; 16: move $[[#]], $24
ret void
}
diff --git a/llvm/test/CodeGen/Mips/simplebr.ll b/llvm/test/CodeGen/Mips/simplebr.ll
index ba97bdd89c1799..086c59206115a7 100644
--- a/llvm/test/CodeGen/Mips/simplebr.ll
+++ b/llvm/test/CodeGen/Mips/simplebr.ll
@@ -25,7 +25,7 @@ if.end: ; preds = %if.else, %if.then
ret void
}
-; CHECK-STATIC16: b $BB{{[0-9]+}}_{{[0-9]+}} # 16 bit inst
+; CHECK-STATIC16: b $BB[[#]]_[[#]]
declare void @goo(...) #1
diff --git a/llvm/test/CodeGen/Mips/sr1.ll b/llvm/test/CodeGen/Mips/sr1.ll
index 47948c488aab24..e5434da565815c 100644
--- a/llvm/test/CodeGen/Mips/sr1.ll
+++ b/llvm/test/CodeGen/Mips/sr1.ll
@@ -1,6 +1,6 @@
-; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -relocation-model=static < %s | FileCheck %s
-
-; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -relocation-model=static < %s | FileCheck %s -check-prefix=NEG
+; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mattr=mips16 -relocation-model=static < %s | \
+; RUN: llvm-mc -arch=mipsel -mattr=+mips16 -show-inst | \
+; RUN: FileCheck %s
@f = common global float 0.000000e+00, align 4
@@ -12,8 +12,8 @@ entry:
call void @x(ptr %c)
ret void
; CHECK: .ent foo1
-; CHECK: save $16, $17, $ra, [[FS:[0-9]+]] # 16 bit inst
-; CHECK: restore $16, $17, $ra, [[FS]] # 16 bit inst
+; CHECK: save $16, $17, $ra, [[FS:[0-9]+]] # <MCInst #[[#]] Save16
+; CHECK: restore $16, $17, $ra, [[FS]] # <MCInst #[[#]] Restore16
; CHECK: .end foo1
}
@@ -27,8 +27,8 @@ entry:
call void @x(ptr %c)
ret void
; CHECK: .ent foo2
-; CHECK: save $16, $17, $ra, [[FS:[0-9]+]]
-; CHECK: restore $16, $17, $ra, [[FS]]
+; CHECK: save $16, $17, $ra, [[FS:[0-9]+]] # <MCInst #[[#]] SaveX16
+; CHECK: restore $16, $17, $ra, [[FS]] # <MCInst #[[#]] RestoreX16
; CHECK: .end foo2
}
@@ -39,13 +39,9 @@ entry:
store float %call, ptr @f, align 4
ret void
; CHECK: .ent foo3
-; CHECK: save $16, $17, $ra, $18, [[FS:[0-9]+]]
-; CHECK: restore $16, $17, $ra, $18, [[FS]]
+; CHECK: save $16, $17, $18, $ra, [[FS:[0-9]+]] # <MCInst #[[#]] SaveX16
+; CHECK: restore $16, $17, $18, $ra, [[FS]] # <MCInst #[[#]] RestoreX16
; CHECK: .end foo3
-; NEG: .ent foo3
-; NEG-NOT: save $16, $17, $ra, $18, {{[0-9]+}} # 16 bit inst
-; NEG-NOT: restore $16, $17, $ra, $18, {{[0-9]+}} # 16 bit inst
-; NEG: .end foo3
}
declare float @xf() #1
diff --git a/llvm/test/CodeGen/Mips/tailcall/tailcall.ll b/llvm/test/CodeGen/Mips/tailcall/tailcall.ll
index 3b200780b9f593..0b10cbd3589b6c 100644
--- a/llvm/test/CodeGen/Mips/tailcall/tailcall.ll
+++ b/llvm/test/CodeGen/Mips/tailcall/tailcall.ll
@@ -50,7 +50,7 @@ entry:
; STATIC32MMR6: balc
; N64: jalr $25
; N64R6: jalr $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 @callee1(i32 1, i32 1, i32 1, i32 %a0) nounwind
ret i32 %call
@@ -68,7 +68,7 @@ entry:
; STATIC32MMR6: balc
; N64: jalr $25
; N64R6: jalr $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 @callee2(i32 1, i32 %a0, i32 %a1, i32 %a2, i32 %a3) nounwind
ret i32 %call
@@ -86,7 +86,7 @@ entry:
; STATIC32MMR6: balc
; N64: jalr $25
; N64R6: jalr $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 @callee3(i32 1, i32 1, i32 1, i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4) nounwind
ret i32 %call
@@ -105,7 +105,7 @@ entry:
; PIC64: jalr $25
; STATIC64: jal
; N64R6: jalr $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 @callee4(i32 1, i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, i32 %a6, i32 %a7) nounwind
ret i32 %call
@@ -123,7 +123,7 @@ entry:
; STATIC32MMR6: bc
; PIC64: jr $25
; STATIC64: j
-; PIC16: jalrc
+; PIC16: jalrc $ra
%0 = load i32, ptr @g0, align 4
%1 = load i32, ptr @g1, align 4
@@ -166,7 +166,7 @@ entry:
; PIC64: jr $25
; PIC64R6: jrc $25
; STATIC64: j
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call fastcc i32 @caller8_1()
ret i32 %call
@@ -182,7 +182,7 @@ entry:
; STATIC32MMR6: balc
; PIC64: jalr $25
; STATIC64: jal
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 (i32, ...) @callee8(i32 2, i32 1) nounwind
ret i32 %call
@@ -205,7 +205,7 @@ entry:
; PIC64: jr $25
; STATIC64: j
; PIC64R6: jrc $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call fastcc i32 @caller9_1()
ret i32 %call
}
@@ -221,7 +221,7 @@ entry:
; STATIC64: jal
; PIC64: jalr $25
; PIC64R6: jalrc $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 @callee9(ptr byval(%struct.S) @gs1) nounwind
ret i32 %call
@@ -240,7 +240,7 @@ entry:
; STATIC64: jal
; PIC64: jalr $25
; PIC64R6: jalr $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 @callee10(i32 %a8, i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, i32 %a6, i32 %a7) nounwind
ret i32 %call
@@ -259,7 +259,7 @@ entry:
; STATIC64: jal
; PIC64: jalr $25
; PIC64R6: jalrc $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 @callee11(ptr byval(%struct.S) @gs1) nounwind
ret i32 %call
@@ -280,7 +280,7 @@ entry:
; STATIC64: jal
; PIC64: jalr $25
; PIC64R6: jalrc $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
tail call void @llvm.memcpy.p0.p0.i32(ptr align 4 @gs1, ptr align 4 %a0, i32 8, i1 false)
%call = tail call i32 @callee12() nounwind
@@ -300,7 +300,7 @@ entry:
; STATIC64: jal
; PIC64R6: jalr $25
; PIC64: jalr $25
-; PIC16: jalrc
+; PIC16: jalrc $ra
%call = tail call i32 (i32, ...) @callee13(i32 1, i32 2) nounwind
ret i32 %call
diff --git a/llvm/test/CodeGen/Mips/trap1.ll b/llvm/test/CodeGen/Mips/trap1.ll
index 575574a0a3b1ab..1234ab360b3493 100644
--- a/llvm/test/CodeGen/Mips/trap1.ll
+++ b/llvm/test/CodeGen/Mips/trap1.ll
@@ -7,7 +7,7 @@ define i32 @main() {
entry:
call void @llvm.trap()
unreachable
-; pic: break 0
+; pic: break
ret i32 0
}
diff --git a/llvm/test/CodeGen/Mips/whitespace.ll b/llvm/test/CodeGen/Mips/whitespace.ll
index 6710b73acbf1c4..cf315688378e8a 100644
--- a/llvm/test/CodeGen/Mips/whitespace.ll
+++ b/llvm/test/CodeGen/Mips/whitespace.ll
@@ -11,8 +11,8 @@
define i32 @main() nounwind {
entry:
-; 16: jalrc ${{[0-9]+}}
-; 16: jrc ${{[0-9]+}}
+; 16: jalrc $ra, $[[#]]
+; 16: jrc $[[#]]
; 16: jrc $ra
%puts = tail call i32 @puts(ptr @str)
br label %L1
diff --git a/llvm/test/MC/Disassembler/Mips/mips16/valid.txt b/llvm/test/MC/Disassembler/Mips/mips16/valid.txt
new file mode 100644
index 00000000000000..b4fa5931293f89
--- /dev/null
+++ b/llvm/test/MC/Disassembler/Mips/mips16/valid.txt
@@ -0,0 +1,167 @@
+# REQUIRES: mips-registered-target
+# RUN: llvm-mc --disassemble -arch=mipsel -mcpu=mips32r2 -mattr=+mips16 %s \
+# RUN: | FileCheck %s
+
+0xf1 0x4f # CHECK: addiu $7, -15
+0x3d 0x4a # CHECK: addiu $2, 61
+0x70 0xf6 0x1d 0x4d # CHECK: addiu $5, -31107
+0x0d 0xf0 0x01 0x48 # CHECK: addiu $16, 26625
+0x4e 0x40 # CHECK: addiu $2, $16, -2
+0xc7 0x45 # CHECK: addiu $6, $5, 7
+0x0f 0xf5 0x29 0x41 # CHECK: addiu $17, $17, -759
+0x33 0xf5 0x41 0x41 # CHECK: addiu $2, $17, 7473
+0x02 0x0a # CHECK: addiu $2, $pc, 8
+0x40 0xf0 0x12 0x0f # CHECK: addiu $7, $pc, 82
+0xd6 0xf5 0x19 0x0e # CHECK: addiu $6, $pc, -18983
+0xca 0xf6 0x0e 0x0c # CHECK: addiu $4, $pc, 22222
+0xb4 0x63 # CHECK: addiu $sp, -608
+0x4a 0x63 # CHECK: addiu $sp, 592
+0x3f 0xf6 0x04 0x63 # CHECK: addiu $sp, -476
+0x9f 0xf1 0x1d 0x63 # CHECK: addiu $sp, -1635
+0x40 0xf1 0x11 0x63 # CHECK: addiu $sp, 337
+0x4d 0xf3 0x0b 0x63 # CHECK: addiu $sp, 27467
+0x49 0x00 # CHECK: addiu $16, $sp, 292
+0xc0 0xf2 0x17 0x05 # CHECK: addiu $5, $sp, 727
+0xbc 0xf2 0x1b 0x03 # CHECK: addiu $3, $sp, -7493
+0x68 0xf3 0x05 0x07 # CHECK: addiu $7, $sp, 17253
+0x5d 0xe0 # CHECK: addu $7, $16, $2
+0x8c 0xed # CHECK: and $5, $4
+0x75 0xf4 0xcf 0xe7 # CHECK: asmacro 4, 15, 6, 7, 21, 3
+0xd3 0x17 # CHECK: b -90
+0x6a 0x11 # CHECK: b 724
+0x71 0xf1 0x10 0x10 # CHECK: b -60704
+0x8e 0xf7 0x03 0x10 # CHECK: b 61190
+0xd3 0x23 # CHECK: beqz $3, -90
+0x41 0x22 # CHECK: beqz $2, 130
+0x98 0xf3 0x0e 0x24 # CHECK: beqz $4, -30948
+0x6c 0xf4 0x1c 0x22 # CHECK: beqz $2, 51448
+0x99 0x2c # CHECK: bnez $4, -206
+0x34 0x2d # CHECK: bnez $5, 104
+0x7f 0xf1 0x09 0x2b # CHECK: bnez $3, -3374
+0xee 0xf0 0x02 0x28 # CHECK: bnez $16, 57796
+0x05 0xe8 # CHECK: break
+0xad 0x60 # CHECK: bteqz -166
+0x08 0x60 # CHECK: bteqz 16
+0xf7 0xf2 0x06 0x60 # CHECK: bteqz -35380
+0x87 0xf0 0x0f 0x60 # CHECK: bteqz 28958
+0x88 0x61 # CHECK: btnez -240
+0x2f 0x61 # CHECK: btnez 94
+0x77 0xf4 0x18 0x61 # CHECK: btnez -34576
+0x89 0xf5 0x16 0x61 # CHECK: btnez 39724
+0xaa 0xe9 # CHECK: cmp $17, $5
+0x7e 0x74 # CHECK: cmpi $4, 126
+0x27 0xf5 0x1f 0x75 # CHECK: cmpi $5, 15679
+0x1a 0xef # CHECK: div $7, $16
+0x1b 0xea # CHECK: divu $2, $16
+0x28 0x1a 0x5e 0xcf # CHECK: jal 71777656
+0x40 0xed # CHECK: jalr $ra, $5
+0xc0 0xee # CHECK: jalrc $ra, $6
+0xd3 0x1e 0xec 0x91 # CHECK: jalx 165300144
+0x20 0xe8 # CHECK: jr $ra
+0x00 0xed # CHECK: jr $5
+0xa0 0xe8 # CHECK: jrc $ra
+0x80 0xed # CHECK: jrc $5
+0x9c 0x87 # CHECK: lb $4, 28($7)
+0x34 0xf1 0x87 0x82 # CHECK: lb $4, -24281($2)
+0xeb 0xf0 0x76 0x84 # CHECK: lb $3, 22774($4)
+0x71 0xa6 # CHECK: lbu $3, 17($6)
+0xf2 0xf6 0x8c 0xa0 # CHECK: lbu $4, -26900($16)
+0xe4 0xf7 0x89 0xa1 # CHECK: lbu $4, 10217($17)
+0xd1 0x8b # CHECK: lh $6, 34($3)
+0x79 0xf1 0xc2 0x8d # CHECK: lh $6, -13982($5)
+0xa5 0xf5 0xf3 0x8c # CHECK: lh $7, 11699($4)
+0xaa 0xaa # CHECK: lhu $5, 20($2)
+0x5f 0xf5 0x3e 0xaa # CHECK: lhu $17, -674($2)
+0xab 0xf4 0x19 0xaa # CHECK: lhu $16, 23737($2)
+0xf3 0x6f # CHECK: li $7, 243
+0xa1 0xf4 0x19 0x68 # CHECK: li $16, 3257
+0x2f 0x9c # CHECK: lw $17, 60($4)
+0x36 0xf5 0x9f 0x9a # CHECK: lw $4, -19137($2)
+0x24 0xf3 0x83 0x9f # CHECK: lw $4, 8995($7)
+0x6d 0xb1 # CHECK: lw $17, 436($pc)
+0x74 0xf2 0x17 0xb6 # CHECK: lw $6, -23945($pc)
+0x46 0xf0 0x1e 0xb2 # CHECK: lw $2, 12382($pc)
+0x54 0x96 # CHECK: lw $6, 336($sp)
+0x5d 0xf5 0x1c 0x91 # CHECK: lw $17, -4772($sp)
+0xeb 0xf1 0x1d 0x91 # CHECK: lw $17, 23037($sp)
+0x10 0xef # CHECK: mfhi $7
+0x12 0xed # CHECK: mflo $5
+0xfb 0x65 # CHECK: move $ra, $3
+0xef 0x67 # CHECK: move $7, $15
+0x58 0xe9 # CHECK: mult $17, $2
+0xd9 0xe9 # CHECK: multu $17, $6
+0x8b 0xef # CHECK: neg $7, $4
+0x00 0x65 # CHECK: nop
+0x8f 0xee # CHECK: not $6, $4
+0x0d 0xee # CHECK: or $6, $16
+0x08 0x64 # CHECK: restore 64
+0x19 0x64 # CHECK: restore $17, 72
+0x20 0x64 # CHECK: restore $16, 128
+0x35 0x64 # CHECK: restore $16, $17, 40
+0x40 0x64 # CHECK: restore $ra, 128
+0x50 0x64 # CHECK: restore $17, $ra, 128
+0x6c 0x64 # CHECK: restore $16, $ra, 96
+0x71 0x64 # CHECK: restore $16, $17, $ra, 8
+0x60 0xf4 0x0e 0x64 # CHECK: restore $18, $19, $20, $21, 880
+0x80 0xf7 0x18 0x64 # CHECK: restore $17, $18, $19, $20, $21, $22, $23, $fp, 1088
+0x90 0xf4 0x2c 0x64 # CHECK: restore $16, $18, $19, $20, $21, 1248
+0x63 0xf3 0x35 0x64 # CHECK: restore $16, $17, $18, $19, $20, 808, $5, $6, $7
+0xf1 0xf6 0x4c 0x64 # CHECK: restore $18, $19, $20, $21, $22, $23, $ra, 2016, $7
+0x31 0xf0 0x5f 0x64 # CHECK: restore $17, $ra, 504, $7
+0xb3 0xf0 0x61 0x64 # CHECK: restore $16, $ra, 1416, $5, $6, $7
+0x92 0xf7 0x76 0x64 # CHECK: restore $16, $17, $18, $19, $20, $21, $22, $23, $fp, $ra, 1200, $6, $7
+0x88 0x64 # CHECK: save 64
+0x93 0x64 # CHECK: save $17, 24
+0xa6 0x64 # CHECK: save $16, 48
+0xb9 0x64 # CHECK: save $16, $17, 72
+0xc1 0x64 # CHECK: save $ra, 8
+0xdd 0x64 # CHECK: save $17, $ra, 104
+0xe0 0x64 # CHECK: save $16, $ra, 128
+0xf8 0x64 # CHECK: save $16, $17, $ra, 64
+0xa9 0xf2 0x86 0x64 # CHECK: save $4, $5, $18, $19, 1328, $7
+0x90 0xf6 0x95 0x64 # CHECK: save $17, $18, $19, $20, $21, $22, $23, 1192
+0x12 0xf0 0xac 0x64 # CHECK: save $16, 224, $6, $7
+0x36 0xf3 0xb5 0x64 # CHECK: save $4, $16, $17, $18, $19, $20, 424, $6, $7
+0x6c 0xf4 0xc7 0x64 # CHECK: save $4, $5, $6, $18, $19, $20, $21, $ra, 824
+0xe5 0xf5 0xd0 0x64 # CHECK: save $4, $17, $18, $19, $20, $21, $22, $ra, 1792, $7
+0x6d 0xf3 0xef 0x64 # CHECK: save $4, $5, $6, $16, $18, $19, $20, $ra, 888, $7
+0xf9 0xf5 0xfb 0x64 # CHECK: save $4, $5, $16, $17, $18, $19, $20, $21, $22, $ra, 2008, $7
+0x12 0xc1 # CHECK: sb $16, 18($17)
+0xf3 0xf3 0x97 0xc7 # CHECK: sb $4, -25609($7)
+0x40 0xf6 0x0a 0xc2 # CHECK: sb $16, 1610($2)
+0x01 0xe8 # CHECK: sdbbp
+0x91 0xee # CHECK: seb $6
+0xb1 0xef # CHECK: seh $7
+0xc5 0xcd # CHECK: sh $6, 10($5)
+0x1a 0xf1 0x1a 0xc9 # CHECK: sh $16, -12006($17)
+0xea 0xf1 0xbe 0xca # CHECK: sh $5, 20990($2)
+0xf4 0x33 # CHECK: sll $3, $7, 5
+0xc0 0xf3 0x40 0x30 # CHECK: sll $16, $2, 15
+0xa4 0xe9 # CHECK: sllv $17, $5
+0xc2 0xe8 # CHECK: slt $16, $6
+0x62 0x56 # CHECK: slti $6, 98
+0xf7 0xf0 0x07 0x55 # CHECK: slti $5, -18201
+0xc2 0xf2 0x0e 0x50 # CHECK: slti $16, 4814
+0xe4 0x58 # CHECK: sltiu $16, 228
+0x55 0xf6 0x04 0x5d # CHECK: sltiu $5, -20924
+0x49 0xf4 0x13 0x5d # CHECK: sltiu $5, 19539
+0x83 0xeb # CHECK: sltu $3, $4
+0x8b 0x31 # CHECK: sra $17, $4, 2
+0xc0 0xf2 0xc3 0x30 # CHECK: sra $16, $6, 11
+0xe7 0xec # CHECK: srav $4, $7
+0x4a 0x34 # CHECK: srl $4, $2, 2
+0x40 0xf5 0x22 0x32 # CHECK: srl $2, $17, 21
+0x66 0xef # CHECK: srlv $7, $3
+0xa7 0xe4 # CHECK: subu $17, $4, $5
+0x9a 0xdf # CHECK: sw $4, 104($7)
+0xdb 0xf0 0x12 0xd8 # CHECK: sw $16, -10030($16)
+0x41 0xf3 0xed 0xdf # CHECK: sw $7, 2893($7)
+0x76 0xd1 # CHECK: sw $17, 472($sp)
+0xb6 0xf0 0x1a 0xd1 # CHECK: sw $17, -20294($sp)
+0x86 0xf3 0x14 0xd1 # CHECK: sw $17, 13204($sp)
+0x5b 0x62 # CHECK: sw $ra, 364($sp)
+0xb8 0xf5 0x17 0x62 # CHECK: sw $ra, -14921($sp)
+0x69 0xf5 0x0d 0x62 # CHECK: sw $ra, 19821($sp)
+0xce 0xeb # CHECK: xor $3, $6
+0x11 0xe9 # CHECK: zeb $17
+0x31 0xed # CHECK: zeh $5
diff --git a/llvm/test/MC/Mips/micromips-invalid.s b/llvm/test/MC/Mips/micromips-invalid.s
index d7fe09a22e2063..6b3ae0b9a35851 100644
--- a/llvm/test/MC/Mips/micromips-invalid.s
+++ b/llvm/test/MC/Mips/micromips-invalid.s
@@ -15,8 +15,8 @@
xor16 $15, $5 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction
sll16 $1, $16, 5 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction
srl16 $4, $9, 6 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction
- sll16 $3, $16, 9 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range
- srl16 $4, $5, 15 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range
+ sll16 $3, $16, 9 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: expected immediate in range 1 ... 8
+ srl16 $4, $5, 15 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: expected immediate in range 1 ... 8
addiur2 $9, $7, -1 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction
addiur2 $6, $7, 10 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range
lwm16 $5, $6, $ra, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: $16 or $31 expected
diff --git a/llvm/test/MC/Mips/mips16/invalid.s b/llvm/test/MC/Mips/mips16/invalid.s
index ad28e40f7677fb..4c000aaf0d8463 100644
--- a/llvm/test/MC/Mips/mips16/invalid.s
+++ b/llvm/test/MC/Mips/mips16/invalid.s
@@ -1,10 +1,213 @@
-# RUN: not llvm-mc -triple=mips -mcpu=mips32r2 -mattr=+mips16 < %s 2> %t
+# REQUIRES: mips-registered-target
+# RUN: not llvm-mc -arch=mipsel -mcpu=mips32r2 -mattr=+mips16 %s 2> %t
# RUN: FileCheck %s < %t
-# Instructions which are invalid.
+# Use NOP to check instructions that do not take arguments.
$label:
- nop 4 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
- nop $4 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
- nop $label # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
+ nop 4 # CHECK: :[[#@LINE]]:[[#]]: error: invalid operand for instruction
+ nop $4 # CHECK: :[[#@LINE]]:[[#]]: error: invalid operand for instruction
+ nop $label # CHECK: :[[#@LINE]]:[[#]]: error: invalid operand for instruction
+# These are MIPS instructions, but are not usable in MIPS16 mode.
+
+and $s1,$v0,$12 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+andi $2, $3, 4 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+cache 1, 16($5) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+clz $sp,$s0 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+di # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+ehb # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+ei # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+eret # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lwl $s1,120($v1) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lwr $16,68($17) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+mfc0 $3,$15,1 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+mtc0 $4,$15,1 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+pref 1, 8($5) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+ssnop # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sync # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sync 1 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+syscall # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+syscall 256 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+teq $zero, $3 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+teq $5, $7, 620 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+tlbp # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+tlbr # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+tlbwi # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+tlbwr # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+
+# These instructions are valid in MIPS16, but use registers not
+# avaialble in MIPS16 mode.
+
+addiu $23, $17, -759 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+addiu $17, $23, -759 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+addu $7, $0, $2 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+addu $7, $16, $zero # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+addu $s5, $16, $2 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+div $7, $s6 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+div $t0, $s0 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+divu $2, $fp # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+divu $t8, $16 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+jr $k0 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lb $v1, 22774($t5) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lb $k1, 22774($a0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lbu $3, 17($22) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lbu $20, 17($6) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lh $7, 11699($28) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lh $29, 11699($4) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lhu $5, 20($8) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lhu $t1, 20($v0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+li $15, 3257 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $s1, 60($zero) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $s2, 60($a0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $sp, 23037($a0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+mfhi $13 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+mflo $10 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sb $s0, 1610($11) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sb $12, 1610($v0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sh $5, 20990($at) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sh $t2, 20990($2) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sll $k1, $a3, 5 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sll $v1, $k0, 5 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sra $18, $6, 11 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sra $s0, $19, 11 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+srl $4, $21, 2 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+srl $27, $2, 2 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+subu $17, $4, $0 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+subu $17, $sp, $a1 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+subu $fp, $4, $a1 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sw $sp, 104($7) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sw $4, 104($t6) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+
+# These instructions are valid in MIPS16 and use MIPS16 registers,
+# but the immediates are accepted in MIPS32 mode only.
+# FIXME: Add large immediate support to MIPS16.
+# See MipsAsmParser::ExpandMem16Instruction() and expandAliasImmediate().
+addiu $v0, $s0, -16385 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+addiu $a2, $a1, 16384 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+addiu $v0, 32768 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+addiu $sp, 32768 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+addiu $5, $sp, 32768 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lb $a0, -32769($2) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lb $v1, 32768($a0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lbu $4, -32769($16) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lbu $4, 32768($17) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lh $a2, -32769($a1) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lh $7, 32768($4) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lhu $s1, -32769($v0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lhu $s0, 32769($2) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+li $16, 65536 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $a0, -32769($v0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $4, 32768($7) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $6, -32769($pc) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $2, 32768($pc) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $17, -32769($sp) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+lw $s1, 32768($sp) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sb $a0, -32769($7) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sb $s0, 32768($v0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sh $16, -32769($s1) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sh $5, 32768($2) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sw $s0, -32769($s0) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sw $a3, 32768($7) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sw $17, -32769($sp) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sw $s1, 32768($sp) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sw $ra, -32769($sp) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+sw $ra, 32768($sp) # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+li $a3, -1 # CHECK: :[[#@LINE]]:[[#]]: error: instruction requires a CPU feature not currently enabled
+
+# These instructions are valid in MIPS16 and use MIPS16 registers,
+# but have out of range immediate values.
+
+addiu $a3, -32769 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+addiu $a2, $pc, -32769 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+addiu $4, $pc, 32768 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+addiu $sp, -32769 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+addiu $16, $sp, -32769 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+addiu $v0, $s0, -65537 # CHECK: :[[#@LINE]]:[[#]]: error: expected 15-bit signed immediate
+addiu $a2, $a1, 65536 # CHECK: :[[#@LINE]]:[[#]]: error: expected 15-bit signed immediate
+addiu $v0, 65536 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+addiu $sp, 65536 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+addiu $5, $sp, 65536 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+asmacro 8, 15, 6, 7, 21, 3 # CHECK: :[[#@LINE]]:[[#]]: error: expected 3-bit unsigned immediate
+asmacro 4, 32, 6, 7, 21, 3 # CHECK: :[[#@LINE]]:[[#]]: error: expected 5-bit unsigned immediate
+asmacro 4, 15, 8, 7, 21, 3 # CHECK: :[[#@LINE]]:[[#]]: error: expected 3-bit unsigned immediate
+asmacro 4, 15, 6, 8, 21, 3 # CHECK: :[[#@LINE]]:[[#]]: error: expected 3-bit unsigned immediate
+asmacro 4, 15, 6, 7, 32, 3 # CHECK: :[[#@LINE]]:[[#]]: error: expected 5-bit unsigned immediate
+asmacro 4, 15, 6, 7, 21, 8 # CHECK: :[[#@LINE]]:[[#]]: error: expected 3-bit unsigned immediate
+b -131074 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+b 131072 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+beqz $a0, -131074 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+beqz $a0, 131072 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+bnez $v1, -131074 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+bnez $v1, 131072 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+bteqz -131074 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+bteqz 131072 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+btnez -131074 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+btnez 131072 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+cmpi $a0, -1 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit unsigned immediate
+cmpi $5, 65536 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit unsigned immediate
+jal -256 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+jal 268435456 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+jalx -256 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+jalx 268435456 # CHECK: :[[#@LINE]]:[[#]]: error: branch target out of range
+sll $s0, $2, 32 # CHECK: :[[#@LINE]]:[[#]]: error: expected 5-bit unsigned immediate
+slti $a1, -32769 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+slti $16, 32768 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+sltiu $5, -32769 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+sltiu $5, 65536 # CHECK: :[[#@LINE]]:[[#]]: error: expected 16-bit signed immediate
+sra $s0, $6, 32 # CHECK: :[[#@LINE]]:[[#]]: error: expected 5-bit unsigned immediate
+srl $v0, $17, 32 # CHECK: :[[#@LINE]]:[[#]]: error: expected 5-bit unsigned immediate
+
+# Unalingned branches and jumps
+
+b -851 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+b 71 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+b -24193 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+b 30343 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+beqz $17, -211 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+beqz $v1, 207 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+beqz $s1, -39467 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+beqz $a0, 26545 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+bnez $6, -169 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+bnez $a3, 139 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+bnez $3, -10353 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+bnez $s1, 61261 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+bteqz -169 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+bteqz 47 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+bteqz -18163 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+bteqz 61095 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+btnez -161 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+btnez 71 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+btnez -29969 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+btnez 44113 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+jal 254 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+jalx 254 # CHECK: :[[#@LINE]]:[[#]]: error: branch to misaligned address
+
+# Try malformed versions of SAVE and RESTORE.
+
+restore -8 # CHECK: :[[#@LINE]]:[[#]]: error: frame size must be in range 0 .. 2040 and a multiple of 8
+restore 2048 # CHECK: :[[#@LINE]]:[[#]]: error: frame size must be in range 0 .. 2040 and a multiple of 8
+restore $24, 72 # CHECK: :[[#@LINE]]:[[#]]: error: only registers $4-7, $16-23, $30, and $31 can be used
+restore 72, $27 # CHECK: :[[#@LINE]]:[[#]]: error: only registers $4-7 can be saved as static registers
+restore 80, $28 # CHECK: :[[#@LINE]]:[[#]]: error: only registers $4-7 can be saved as static registers
+restore $17, 160, $17 # CHECK: :[[#@LINE]]:[[#]]: error: only registers $4-7 can be saved as static registers
+restore $16, $17, 720, 800 # CHECK: :[[#@LINE]]:[[#]]: error: expected static register
+restore 800, $4, $5, 720 # CHECK: :[[#@LINE]]:[[#]]: error: expected static register
+restore $4, $5, 120, $4, $5 # CHECK: :[[#@LINE]]:[[#]]: error: registers cannot be both in saved and static lists
+restore $18-$21-, 880 # CHECK: :[[#@LINE]]:[[#]]: error: unexpected token, expected comma
+restore $18-$21-$23, 960 # CHECK: :[[#@LINE]]:[[#]]: error: unexpected token, expected comma
+restore $18-400 # CHECK: :[[#@LINE]]:[[#]]: error: expected end of register range
+restore 240($18) # CHECK: :[[#@LINE]]:[[#]]: error: unexpected token, expected comma
+save -8 # CHECK: :[[#@LINE]]:[[#]]: error: frame size must be in range 0 .. 2040 and a multiple of 8
+save 2048 # CHECK: :[[#@LINE]]:[[#]]: error: frame size must be in range 0 .. 2040 and a multiple of 8
+save $24, 72 # CHECK: :[[#@LINE]]:[[#]]: error: only registers $4-7, $16-23, $30, and $31 can be used
+save 72, $27 # CHECK: :[[#@LINE]]:[[#]]: error: only registers $4-7 can be saved as static registers
+save 80, $28 # CHECK: :[[#@LINE]]:[[#]]: error: only registers $4-7 can be saved as static registers
+save $17, 160, $17 # CHECK: :[[#@LINE]]:[[#]]: error: only registers $4-7 can be saved as static registers
+save $16, $17, 720, 800 # CHECK: :[[#@LINE]]:[[#]]: error: expected static register
+save 800, $4, $5, 720 # CHECK: :[[#@LINE]]:[[#]]: error: expected static register
+save $4, $5, 120, $4, $5 # CHECK: :[[#@LINE]]:[[#]]: error: registers cannot be both in saved and static lists
+save $18-$21-, 880 # CHECK: :[[#@LINE]]:[[#]]: error: unexpected token, expected comma
+save $18-$21-$23, 960 # CHECK: :[[#@LINE]]:[[#]]: error: unexpected token, expected comma
+save $18-400 # CHECK: :[[#@LINE]]:[[#]]: error: expected end of register range
+save 240($18) # CHECK: :[[#@LINE]]:[[#]]: error: unexpected token, expected comma
diff --git a/llvm/test/MC/Mips/mips16/valid.s b/llvm/test/MC/Mips/mips16/valid.s
index 942bfd1a00faba..1030688106295b 100644
--- a/llvm/test/MC/Mips/mips16/valid.s
+++ b/llvm/test/MC/Mips/mips16/valid.s
@@ -1,3 +1,171 @@
-# RUN: llvm-mc -triple=mips -mcpu=mips32r2 -mattr=+mips16 -show-encoding -show-inst < %s
+# REQUIRES: mips-registered-target
+# RUN: llvm-mc -arch=mipsel -mcpu=mips32r2 -mattr=+mips16 -show-encoding -show-inst %s | FileCheck %s
- nop
+addiu $16, -16 # CHECK: addiu $16, -16 # encoding: [0xf0,0x48]
+addiu $6, 59 # CHECK: addiu $6, 59 # encoding: [0x3b,0x4e]
+addiu $a3, -30745 # CHECK: addiu $7, -30745 # encoding: [0xf0,0xf7,0x07,0x4f]
+addiu $v0, 30757 # CHECK: addiu $2, 30757 # encoding: [0x2f,0xf0,0x05,0x4a]
+addiu $6, $6, -7 # CHECK: addiu $6, $6, -7 # encoding: [0xc9,0x46]
+addiu $3, $a3, 3 # CHECK: addiu $3, $7, 3 # encoding: [0x63,0x47]
+addiu $5, $16, -5377 # CHECK: addiu $5, $16, -5377 # encoding: [0xfd,0xf2,0xaf,0x40]
+addiu $4, $16, 339 # CHECK: addiu $4, $16, 339 # encoding: [0x50,0xf1,0x83,0x40]
+addiu $a1, $pc, 208 # CHECK: addiu $5, $pc, 208 # encoding: [0x34,0x0d]
+addiu $17, $pc, 50 # CHECK: addiu $17, $pc, 50 # encoding: [0x20,0xf0,0x12,0x09]
+addiu $a1, $pc, -20868 # CHECK: addiu $5, $pc, -20868 # encoding: [0x75,0xf6,0x1c,0x0d]
+addiu $s0, $pc, 24513 # CHECK: addiu $16, $pc, 24513 # encoding: [0xcb,0xf7,0x01,0x08]
+addiu $sp, -48 # CHECK: addiu $sp, -48 # encoding: [0xfa,0x63]
+addiu $sp, 664 # CHECK: addiu $sp, 664 # encoding: [0x53,0x63]
+addiu $sp, -20 # CHECK: addiu $sp, -20 # encoding: [0xff,0xf7,0x0c,0x63]
+addiu $sp, -16747 # CHECK: addiu $sp, -16747 # encoding: [0x97,0xf6,0x15,0x63]
+addiu $sp, 687 # CHECK: addiu $sp, 687 # encoding: [0xa0,0xf2,0x0f,0x63]
+addiu $sp, 21923 # CHECK: addiu $sp, 21923 # encoding: [0xaa,0xf5,0x03,0x63]
+addiu $16, $sp, 892 # CHECK: addiu $16, $sp, 892 # encoding: [0xdf,0x00]
+addiu $s0, $sp, 814 # CHECK: addiu $16, $sp, 814 # encoding: [0x20,0xf3,0x0e,0x00]
+addiu $a0, $sp, -24228 # CHECK: addiu $4, $sp, -24228 # encoding: [0x54,0xf1,0x1c,0x04]
+addiu $v1, $sp, 3450 # CHECK: addiu $3, $sp, 3450 # encoding: [0x61,0xf5,0x1a,0x03]
+addu $5, $v1, $5 # CHECK: addu $5, $3, $5 # encoding: [0xb5,0xe3]
+and $v0, $a0 # CHECK: and $2, $4 # encoding: [0x8c,0xea]
+asmacro 4, 15, 6, 7, 21, 3 # CHECK: asmacro 4, 15, 6, 7, 21, 3 # encoding: [0x75,0xf4,0xcf,0xe7]
+b -852 # CHECK: b -852 # encoding: [0x56,0x16]
+b 76 # CHECK: b 76 # encoding: [0x26,0x10]
+b -24194 # CHECK: b -24194 # encoding: [0xba,0xf0,0x1f,0x10]
+b 30344 # CHECK: b 30344 # encoding: [0x47,0xf3,0x04,0x10]
+beqz $17, -212 # CHECK: beqz $17, -212 # encoding: [0x96,0x21]
+beqz $v1, 208 # CHECK: beqz $3, 208 # encoding: [0x68,0x23]
+beqz $s1, -39468 # CHECK: beqz $17, -39468 # encoding: [0xf6,0xf2,0x0a,0x21]
+beqz $a0, 26544 # CHECK: beqz $4, 26544 # encoding: [0xc6,0xf3,0x18,0x24]
+bnez $6, -168 # CHECK: bnez $6, -168 # encoding: [0xac,0x2e]
+bnez $a3, 138 # CHECK: bnez $7, 138 # encoding: [0x45,0x2f]
+bnez $3, -10354 # CHECK: bnez $3, -10354 # encoding: [0xdd,0xf3,0x07,0x2b]
+bnez $s1, 61262 # CHECK: bnez $17, 61262 # encoding: [0xae,0xf7,0x07,0x29]
+break # CHECK: break # encoding: [0x05,0xe8]
+bteqz -160 # CHECK: bteqz -160 # encoding: [0xb0,0x60]
+bteqz 48 # CHECK: bteqz 48 # encoding: [0x18,0x60]
+bteqz -18162 # CHECK: bteqz -18162 # encoding: [0x9b,0xf4,0x07,0x60]
+bteqz 61094 # CHECK: bteqz 61094 # encoding: [0x4e,0xf7,0x13,0x60]
+btnez -160 # CHECK: btnez -160 # encoding: [0xb0,0x61]
+btnez 72 # CHECK: btnez 72 # encoding: [0x24,0x61]
+btnez -29970 # CHECK: btnez -29970 # encoding: [0x78,0xf5,0x17,0x61]
+btnez 44114 # CHECK: btnez 44114 # encoding: [0x2a,0xf6,0x09,0x61]
+cmp $a1, $a2 # CHECK: cmp $5, $6 # encoding: [0xca,0xed]
+cmpi $17, 237 # CHECK: cmpi $17, 237 # encoding: [0xed,0x71]
+cmpi $16, 11085 # CHECK: cmpi $16, 11085 # encoding: [0x45,0xf3,0x0d,0x70]
+div $a3, $3 # CHECK: div $7, $3 # encoding: [0x7a,0xef]
+divu $2, $16 # CHECK: divu $2, $16 # encoding: [0x1b,0xea]
+jal 23115704 # CHECK: jal 23115704 # encoding: [0x02,0x1b,0xee,0x2d]
+# Delay slot nop # CHECK: nop # encoding: [0x00,0x65]
+jalr $ra, $a1 # CHECK: jalr $ra, $5 # encoding: [0x40,0xed]
+# Delay slot nop # CHECK: nop # encoding: [0x00,0x65]
+jalrc $ra, $5 # CHECK: jalrc $ra, $5 # encoding: [0xc0,0xed]
+jalx 220161744 # CHECK: jalx 220161744 # encoding: [0xfa,0x1c,0xb4,0xd9]
+# Delay slot nop # CHECK: nop # encoding: [0x00,0x65]
+jr $ra # CHECK: jr $ra # encoding: [0x20,0xe8]
+# Delay slot nop # CHECK: nop # encoding: [0x00,0x65]
+jr $s1 # CHECK: jr $17 # encoding: [0x00,0xe9]
+# Delay slot nop # CHECK: nop # encoding: [0x00,0x65]
+jrc $ra # CHECK: jrc $ra # encoding: [0xa0,0xe8]
+jrc $a1 # CHECK: jrc $5 # encoding: [0x80,0xed]
+lb $a3, 1($a0) # CHECK: lb $7, 1($4) # encoding: [0xe1,0x84]
+lb $s0, -29535($s1) # CHECK: lb $16, -29535($17) # encoding: [0xb1,0xf4,0x01,0x81]
+lb $5, 1619($s1) # CHECK: lb $5, 1619($17) # encoding: [0x40,0xf6,0xb3,0x81]
+lbu $v0, 16($3) # CHECK: lbu $2, 16($3) # encoding: [0x50,0xa3]
+lbu $3, -6232($a1) # CHECK: lbu $3, -6232($5) # encoding: [0xbc,0xf7,0x68,0xa5]
+lbu $6, 22916($5) # CHECK: lbu $6, 22916($5) # encoding: [0x8b,0xf1,0xc4,0xa5]
+lh $a1, 18($3) # CHECK: lh $5, 18($3) # encoding: [0xa9,0x8b]
+lh $a2, -29659($17) # CHECK: lh $6, -29659($17) # encoding: [0x31,0xf4,0xc5,0x89]
+lh $v0, 25362($17) # CHECK: lh $2, 25362($17) # encoding: [0x0c,0xf3,0x52,0x89]
+lhu $2, 4($a2) # CHECK: lhu $2, 4($6) # encoding: [0x42,0xae]
+lhu $7, -20406($s0) # CHECK: lhu $7, -20406($16) # encoding: [0x56,0xf0,0xea,0xa8]
+lhu $4, 7925($7) # CHECK: lhu $4, 7925($7) # encoding: [0xe3,0xf6,0x95,0xaf]
+li $4, 84 # CHECK: li $4, 84 # encoding: [0x54,0x6c]
+li $v1, 3743 # CHECK: li $3, 3743 # encoding: [0x81,0xf6,0x1f,0x6b]
+lw $a0, 64($a2) # CHECK: lw $4, 64($6) # encoding: [0x90,0x9e]
+lw $a1, -8056($s0) # CHECK: lw $5, -8056($16) # encoding: [0x9c,0xf0,0xa8,0x98]
+lw $6, 21317($17) # CHECK: lw $6, 21317($17) # encoding: [0x4a,0xf3,0xc5,0x99]
+lw $4, 688($pc) # CHECK: lw $4, 688($pc) # encoding: [0xac,0xb4]
+lw $5, -29893($pc) # CHECK: lw $5, -29893($pc) # encoding: [0x31,0xf3,0x1b,0xb5]
+lw $s1, 30422($pc) # CHECK: lw $17, 30422($pc) # encoding: [0xce,0xf6,0x16,0xb1]
+lw $6, 236($sp) # CHECK: lw $6, 236($sp) # encoding: [0x3b,0x96]
+lw $v0, -16035($sp) # CHECK: lw $2, -16035($sp) # encoding: [0x58,0xf1,0x1d,0x92]
+lw $4, 23397($sp) # CHECK: lw $4, 23397($sp) # encoding: [0x6b,0xf3,0x05,0x94]
+mfhi $2 # CHECK: mfhi $2 # encoding: [0x10,0xea]
+mflo $s1 # CHECK: mflo $17 # encoding: [0x12,0xe9]
+move $t7, $a1 # CHECK: move $15, $5 # encoding: [0xed,0x65]
+move $3, $k0 # CHECK: move $3, $26 # encoding: [0x7a,0x67]
+mult $s0, $6 # CHECK: mult $16, $6 # encoding: [0xd8,0xe8]
+multu $5, $4 # CHECK: multu $5, $4 # encoding: [0x99,0xed]
+neg $a1, $2 # CHECK: neg $5, $2 # encoding: [0x4b,0xed]
+nop # CHECK: nop # encoding: [0x00,0x65]
+not $7, $16 # CHECK: not $7, $16 # encoding: [0x0f,0xef]
+or $5, $2 # CHECK: or $5, $2 # encoding: [0x4d,0xed]
+restore 88 # CHECK: restore 88 # encoding: [0x0b,0x64]
+restore $17, 96 # CHECK: restore $17, 96 # encoding: [0x1c,0x64]
+restore $16, 80 # CHECK: restore $16, 80 # encoding: [0x2a,0x64]
+restore $16, $17, 8 # CHECK: restore $16, $17, 8 # encoding: [0x31,0x64]
+restore $31, 112 # CHECK: restore $ra, 112 # encoding: [0x4e,0x64]
+restore $31, $17, 88 # CHECK: restore $17, $ra, 88 # encoding: [0x5b,0x64]
+restore $31, $16, 120 # CHECK: restore $16, $ra, 120 # encoding: [0x6f,0x64]
+restore $31, $16, $17, 64 # CHECK: restore $16, $17, $ra, 64 # encoding: [0x78,0x64]
+restore $18-$22, 944 # CHECK: restore $18, $19, $20, $21, $22, 944 # encoding: [0x70,0xf5,0x06,0x64]
+restore $18-$19, $17, 936 # CHECK: restore $17, $18, $19, 936 # encoding: [0x70,0xf2,0x15,0x64]
+restore $18-$22, $16, 728 # CHECK: restore $16, $18, $19, $20, $21, $22, 728 # encoding: [0x50,0xf5,0x2b,0x64]
+restore $18, $16, $17, 2024, $5-$7 # CHECK: restore $16, $17, $18, 2024, $5, $6, $7 # encoding: [0xf3,0xf1,0x3d,0x64]
+restore $18, $31, 176 # CHECK: restore $18, $ra, 176 # encoding: [0x10,0xf1,0x46,0x64]
+restore $18, $31, $17, 944, $5-$7 # CHECK: restore $17, $18, $ra, 944, $5, $6, $7 # encoding: [0x73,0xf1,0x56,0x64]
+restore $18-$23, $30, $31, $16, 1064, $5-$7 # CHECK: restore $16, $18, $19, $20, $21, $22, $23, $fp, $ra, 1064, $5, $6, $7 # encoding: [0x83,0xf7,0x65,0x64]
+restore $18-$21, $31, $16, $17, 960, $6, $7 # CHECK: restore $16, $17, $18, $19, $20, $21, $ra, 960, $6, $7 # encoding: [0x72,0xf4,0x78,0x64]
+save 8 # CHECK: save 8 # encoding: [0x81,0x64]
+save $17, 16 # CHECK: save $17, 16 # encoding: [0x92,0x64]
+save $16, 96 # CHECK: save $16, 96 # encoding: [0xac,0x64]
+save $16, $17, 48 # CHECK: save $16, $17, 48 # encoding: [0xb6,0x64]
+save $31, 32 # CHECK: save $ra, 32 # encoding: [0xc4,0x64]
+save $31, $17, 128 # CHECK: save $17, $ra, 128 # encoding: [0xd0,0x64]
+save $31, $16, 128 # CHECK: save $16, $ra, 128 # encoding: [0xe0,0x64]
+save $31, $16, $17, 32 # CHECK: save $16, $17, $ra, 32 # encoding: [0xf4,0x64]
+save $18, $4, $5, 1648 # CHECK: save $4, $5, $18, 1648 # encoding: [0xc8,0xf1,0x8e,0x64]
+save $18-$21, $17, $4, 560, $7 # CHECK: save $4, $17, $18, $19, $20, $21, 560, $7 # encoding: [0x45,0xf4,0x96,0x64]
+save $18, $16, $4-$6, 1312, $7 # CHECK: save $4, $5, $6, $16, $18, 1312, $7 # encoding: [0xad,0xf1,0xa4,0x64]
+save $18-$23, $16, $17, $4, $5, 648 # CHECK: save $4, $5, $16, $17, $18, $19, $20, $21, $22, $23, 648 # encoding: [0x58,0xf6,0xb1,0x64]
+save $18-$21, $31, $4, $5, 216, $7 # CHECK: save $4, $5, $18, $19, $20, $21, $ra, 216, $7 # encoding: [0x19,0xf4,0xcb,0x64]
+save $18-$22, $31, $17, $4, $5, 520, $6, $7 # CHECK: save $4, $5, $17, $18, $19, $20, $21, $22, $ra, 520, $6, $7 # encoding: [0x4a,0xf5,0xd1,0x64]
+save $18-$21, $31, $16, $4, $5, 168, $6, $7 # CHECK: save $4, $5, $16, $18, $19, $20, $21, $ra, 168, $6, $7 # encoding: [0x1a,0xf4,0xe5,0x64]
+save $18-$23, $31, $16, $17, $4-$6, 1504 # CHECK: save $4, $5, $6, $16, $17, $18, $19, $20, $21, $22, $23, $ra, 1504 # encoding: [0xbc,0xf6,0xfc,0x64]
+sb $5, 26($a1) # CHECK: sb $5, 26($5) # encoding: [0xba,0xc5]
+sb $5, -24918($s0) # CHECK: sb $5, -24918($16) # encoding: [0xb3,0xf6,0xaa,0xc0]
+sb $16, 31788($3) # CHECK: sb $16, 31788($3) # encoding: [0x2f,0xf4,0x0c,0xc3]
+sdbbp # CHECK: sdbbp # encoding: [0x01,0xe8]
+seb $a3 # CHECK: seb $7 # encoding: [0x91,0xef]
+seh $4 # CHECK: seh $4 # encoding: [0xb1,0xec]
+sh $v0, 56($3) # CHECK: sh $2, 56($3) # encoding: [0x5c,0xcb]
+sh $a0, -26496($3) # CHECK: sh $4, -26496($3) # encoding: [0x93,0xf0,0x80,0xcb]
+sh $16, 3792($17) # CHECK: sh $16, 3792($17) # encoding: [0xc1,0xf6,0x10,0xc9]
+sll $a1, $5, 1 # CHECK: sll $5, $5, 1 # encoding: [0xa4,0x35]
+sll $17, $7, 24 # CHECK: sll $17, $7, 24 # encoding: [0x00,0xf6,0xe0,0x31]
+sllv $s0, $a2 # CHECK: sllv $16, $6 # encoding: [0xc4,0xe8]
+slt $a3, $2 # CHECK: slt $7, $2 # encoding: [0x42,0xef]
+slti $17, 88 # CHECK: slti $17, 88 # encoding: [0x58,0x51]
+slti $v0, -21090 # CHECK: slti $2, -21090 # encoding: [0x95,0xf5,0x1e,0x52]
+slti $2, 13698 # CHECK: slti $2, 13698 # encoding: [0x86,0xf5,0x02,0x52]
+sltiu $a2, 61 # CHECK: sltiu $6, 61 # encoding: [0x3d,0x5e]
+sltiu $s1, -12072 # CHECK: sltiu $17, -12072 # encoding: [0xda,0xf0,0x18,0x59]
+sltiu $6, 24469 # CHECK: sltiu $6, 24469 # encoding: [0x8b,0xf7,0x15,0x5e]
+sltu $17, $v0 # CHECK: sltu $17, $2 # encoding: [0x43,0xe9]
+sra $s1, $v0, 4 # CHECK: sra $17, $2, 4 # encoding: [0x53,0x31]
+sra $3, $s1, 28 # CHECK: sra $3, $17, 28 # encoding: [0x00,0xf7,0x23,0x33]
+srav $v1, $a0 # CHECK: srav $3, $4 # encoding: [0x87,0xeb]
+srl $s0, $5, 5 # CHECK: srl $16, $5, 5 # encoding: [0xb6,0x30]
+srl $2, $16, 27 # CHECK: srl $2, $16, 27 # encoding: [0xc0,0xf6,0x02,0x32]
+srlv $7, $3 # CHECK: srlv $7, $3 # encoding: [0x66,0xef]
+subu $3, $a0, $7 # CHECK: subu $3, $4, $7 # encoding: [0xef,0xe4]
+sw $v0, 88($16) # CHECK: sw $2, 88($16) # encoding: [0x56,0xd8]
+sw $v0, -7498($6) # CHECK: sw $2, -7498($6) # encoding: [0xbc,0xf2,0x56,0xde]
+sw $17, 31729($16) # CHECK: sw $17, 31729($16) # encoding: [0xef,0xf3,0x31,0xd8]
+sw $a3, 444($sp) # CHECK: sw $7, 444($sp) # encoding: [0x6f,0xd7]
+sw $17, -2308($sp) # CHECK: sw $17, -2308($sp) # encoding: [0xfe,0xf6,0x1c,0xd1]
+sw $a3, 1103($sp) # CHECK: sw $7, 1103($sp) # encoding: [0x40,0xf4,0x0f,0xd7]
+sw $ra, 364($sp) # CHECK: sw $ra, 364($sp) # encoding: [0x5b,0x62]
+sw $ra, -22762($sp) # CHECK: sw $ra, -22762($sp) # encoding: [0x14,0xf7,0x16,0x62]
+sw $ra, 32512($sp) # CHECK: sw $ra, 32512($sp) # encoding: [0x0f,0xf7,0x00,0x62]
+xor $5, $a0 # CHECK: xor $5, $4 # encoding: [0x8e,0xed]
+zeb $s0 # CHECK: zeb $16 # encoding: [0x11,0xe8]
+zeh $v1 # CHECK: zeh $3 # encoding: [0x31,0xeb]
More information about the llvm-commits
mailing list