Skip to content

Commit 1b98d63

Browse files
committed
[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").
1 parent 00f239e commit 1b98d63

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+3013
-654
lines changed

llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp

Lines changed: 439 additions & 8 deletions
Large diffs are not rendered by default.

llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp

Lines changed: 380 additions & 23 deletions
Large diffs are not rendered by default.

llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ bool MipsAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
589589
}
590590
}
591591

592+
// FIXME: Is something similar needed for MIPS16?
592593
bool MipsAsmBackend::isMicroMips(const MCSymbol *Sym) const {
593594
if (const auto *ElfSym = dyn_cast<const MCSymbolELF>(Sym)) {
594595
if (ElfSym->getOther() & ELF::STO_MIPS_MICROMIPS)

llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -88,26 +88,6 @@ void MipsInstPrinter::printInst(const MCInst *MI, uint64_t Address,
8888
O << "\t.set\tpush\n";
8989
O << "\t.set\tmips32r2\n";
9090
break;
91-
case Mips::Save16:
92-
O << "\tsave\t";
93-
printSaveRestore(MI, STI, O);
94-
O << " # 16 bit inst\n";
95-
return;
96-
case Mips::SaveX16:
97-
O << "\tsave\t";
98-
printSaveRestore(MI, STI, O);
99-
O << "\n";
100-
return;
101-
case Mips::Restore16:
102-
O << "\trestore\t";
103-
printSaveRestore(MI, STI, O);
104-
O << " # 16 bit inst\n";
105-
return;
106-
case Mips::RestoreX16:
107-
O << "\trestore\t";
108-
printSaveRestore(MI, STI, O);
109-
O << "\n";
110-
return;
11191
}
11292

11393
// Try to print any aliases first.
@@ -230,6 +210,27 @@ void MipsInstPrinter::printMemOperandEA(const MCInst *MI, int opNum,
230210
printOperand(MI, opNum + 1, STI, O);
231211
}
232212

213+
void MipsInstPrinter::printPCPseudoReg(const MCInst *MI, int opNum,
214+
const MCSubtargetInfo & /* STI */,
215+
raw_ostream &O) {
216+
// Not a real operand; instead indicates a PC-realtive MIPS16 instruction.
217+
O << "$pc";
218+
}
219+
220+
void MipsInstPrinter::printSPPseudoReg(const MCInst *MI, int opNum,
221+
const MCSubtargetInfo & /* STI */,
222+
raw_ostream &O) {
223+
// Not a real operand; instead indicates an SP-realtive MIPS16 instruction.
224+
O << "$sp";
225+
}
226+
227+
void MipsInstPrinter::printRAPseudoReg(const MCInst *MI, int opNum,
228+
const MCSubtargetInfo & /* STI */,
229+
raw_ostream &O) {
230+
// Not a real operand; instead indicates the MIPS16 instruction accesses RA.
231+
O << "$ra";
232+
}
233+
233234
void MipsInstPrinter::printFCCOperand(const MCInst *MI, int opNum,
234235
const MCSubtargetInfo & /* STI */,
235236
raw_ostream &O) {
@@ -338,15 +339,14 @@ bool MipsInstPrinter::printAlias(const MCInst &MI, uint64_t Address,
338339
}
339340
}
340341

341-
void MipsInstPrinter::printSaveRestore(const MCInst *MI,
342+
void MipsInstPrinter::printSaveRestore(const MCInst *MI, int opNum,
342343
const MCSubtargetInfo &STI,
343344
raw_ostream &O) {
344-
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
345-
if (i != 0) O << ", ";
346-
if (MI->getOperand(i).isReg())
347-
printRegName(O, MI->getOperand(i).getReg());
348-
else
349-
printUImm<16>(MI, i, STI, O);
345+
for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {
346+
if (i != opNum)
347+
O << ", ";
348+
349+
printOperand(MI, i, STI, O);
350350
}
351351
}
352352

llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ class MipsInstPrinter : public MCInstPrinter {
108108
raw_ostream &O);
109109
void printMemOperandEA(const MCInst *MI, int opNum,
110110
const MCSubtargetInfo &STI, raw_ostream &O);
111+
void printPCPseudoReg(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
112+
raw_ostream &O);
113+
void printSPPseudoReg(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
114+
raw_ostream &O);
115+
void printRAPseudoReg(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
116+
raw_ostream &O);
111117
void printFCCOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
112118
raw_ostream &O);
113119
void printSHFMask(const MCInst *MI, int opNum, raw_ostream &O);
@@ -120,7 +126,7 @@ class MipsInstPrinter : public MCInstPrinter {
120126
raw_ostream &OS, bool IsBranch = false);
121127
bool printAlias(const MCInst &MI, uint64_t Address,
122128
const MCSubtargetInfo &STI, raw_ostream &OS);
123-
void printSaveRestore(const MCInst *MI, const MCSubtargetInfo &STI,
129+
void printSaveRestore(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
124130
raw_ostream &O);
125131
void printRegisterList(const MCInst *MI, int opNum,
126132
const MCSubtargetInfo &STI, raw_ostream &O);

llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp

Lines changed: 217 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ void MipsMCCodeEmitter::LowerCompactBranch(MCInst& Inst) const {
116116
Inst.getOperand(1).setReg(RegOp0);
117117
}
118118

119+
bool MipsMCCodeEmitter::isMips16(const MCSubtargetInfo &STI) const {
120+
return STI.hasFeature(Mips::FeatureMips16);
121+
}
122+
119123
bool MipsMCCodeEmitter::isMicroMips(const MCSubtargetInfo &STI) const {
120124
return STI.hasFeature(Mips::FeatureMicroMips);
121125
}
@@ -210,7 +214,7 @@ void MipsMCCodeEmitter::encodeInstruction(const MCInst &MI,
210214
IsLittleEndian ? llvm::endianness::little : llvm::endianness::big;
211215
if (Size == 2) {
212216
support::endian::write<uint16_t>(CB, Binary, Endian);
213-
} else if (IsLittleEndian && isMicroMips(STI)) {
217+
} else if (IsLittleEndian && (isMips16(STI) || isMicroMips(STI))) {
214218
support::endian::write<uint16_t>(CB, Binary >> 16, Endian);
215219
support::endian::write<uint16_t>(CB, Binary & 0xffff, Endian);
216220
} else {
@@ -372,6 +376,42 @@ getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo,
372376
return 0;
373377
}
374378

379+
/// getBranchTargetOpValueMips16 - Return binary encoding of the MIPS16
380+
/// branch target operand. This is for the 16-bit instructions, which
381+
/// do not support relocations.
382+
unsigned MipsMCCodeEmitter::getBranchTargetOpValueMips16(
383+
const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
384+
const MCSubtargetInfo &STI) const {
385+
const MCOperand &MO = MI.getOperand(OpNo);
386+
387+
// If the destination is an immediate, divide by 2.
388+
if (MO.isImm())
389+
return MO.getImm() >> 1;
390+
391+
assert(false &&
392+
"getBranchTargetOpValueMips16 expects only constant immediates");
393+
394+
return 0;
395+
}
396+
397+
/// getBranchTarget16OpValueMips16 - Return binary encoding of the MIPS16
398+
/// branch target operand. If the machine operand requires relocation,
399+
/// record the relocation and return zero.
400+
unsigned MipsMCCodeEmitter::getBranchTarget16OpValueMips16(
401+
const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
402+
const MCSubtargetInfo &STI) const {
403+
const MCOperand &MO = MI.getOperand(OpNo);
404+
405+
// If the destination is an immediate, divide by 2.
406+
if (MO.isImm())
407+
return MO.getImm() >> 1;
408+
// FIXME: This should output a fixup, but MIPS16 fixups are not yet supported.
409+
assert(false &&
410+
"getBranchTarget16OpValueMips16 expects only constant immediates");
411+
412+
return 0;
413+
}
414+
375415
/// getBranchTarget21OpValue - Return binary encoding of the branch
376416
/// target operand. If the machine operand requires relocation,
377417
/// record the relocation and return zero.
@@ -518,6 +558,21 @@ getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo,
518558
return 0;
519559
}
520560

561+
unsigned MipsMCCodeEmitter::getJumpTargetOpValueMips16(
562+
const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
563+
const MCSubtargetInfo &STI) const {
564+
const MCOperand &MO = MI.getOperand(OpNo);
565+
// If the destination is an immediate, divide by 4.
566+
if (MO.isImm())
567+
return MO.getImm() >> 2;
568+
569+
// FIXME: This should output a fixup, but MIPS16 fixups are not yet supported.
570+
assert(false &&
571+
"getJumpTargetOpValueMips16 expects only constant immediates");
572+
573+
return 0;
574+
}
575+
521576
unsigned MipsMCCodeEmitter::
522577
getUImm5Lsl2Encoding(const MCInst &MI, unsigned OpNo,
523578
SmallVectorImpl<MCFixup> &Fixups,
@@ -562,6 +617,58 @@ getUImm6Lsl2Encoding(const MCInst &MI, unsigned OpNo,
562617
return 0;
563618
}
564619

620+
unsigned
621+
MipsMCCodeEmitter::getUImm8Lsl2Encoding(const MCInst &MI, unsigned OpNo,
622+
SmallVectorImpl<MCFixup> &Fixups,
623+
const MCSubtargetInfo &STI) const {
624+
const MCOperand &MO = MI.getOperand(OpNo);
625+
if (MO.isImm()) {
626+
unsigned Value = MO.getImm();
627+
return Value >> 2;
628+
}
629+
630+
return 0;
631+
}
632+
633+
unsigned
634+
MipsMCCodeEmitter::getSImm8Lsl3Encoding(const MCInst &MI, unsigned OpNo,
635+
SmallVectorImpl<MCFixup> &Fixups,
636+
const MCSubtargetInfo &STI) const {
637+
const MCOperand &MO = MI.getOperand(OpNo);
638+
if (MO.isImm()) {
639+
unsigned Value = MO.getImm();
640+
return Value >> 3;
641+
}
642+
643+
return 0;
644+
}
645+
646+
unsigned
647+
MipsMCCodeEmitter::getSImm11Lsl1Encoding(const MCInst &MI, unsigned OpNo,
648+
SmallVectorImpl<MCFixup> &Fixups,
649+
const MCSubtargetInfo &STI) const {
650+
const MCOperand &MO = MI.getOperand(OpNo);
651+
if (MO.isImm()) {
652+
unsigned Value = MO.getImm();
653+
return Value >> 1;
654+
}
655+
656+
return 0;
657+
}
658+
659+
unsigned
660+
MipsMCCodeEmitter::getSImm16Lsl1Encoding(const MCInst &MI, unsigned OpNo,
661+
SmallVectorImpl<MCFixup> &Fixups,
662+
const MCSubtargetInfo &STI) const {
663+
const MCOperand &MO = MI.getOperand(OpNo);
664+
if (MO.isImm()) {
665+
unsigned Value = MO.getImm();
666+
return Value >> 1;
667+
}
668+
669+
return 0;
670+
}
671+
565672
unsigned MipsMCCodeEmitter::
566673
getSImm9AddiuspValue(const MCInst &MI, unsigned OpNo,
567674
SmallVectorImpl<MCFixup> &Fixups,
@@ -598,6 +705,7 @@ getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
598705
if (Kind == MCExpr::Target) {
599706
const MipsMCExpr *MipsExpr = cast<MipsMCExpr>(Expr);
600707

708+
// FIXME: Need to add MIPS16 fixups to these cases once support is added.
601709
Mips::Fixups FixupKind = Mips::Fixups(0);
602710
switch (MipsExpr->getKind()) {
603711
case MipsMCExpr::MEK_None:
@@ -737,6 +845,114 @@ getMachineOpValue(const MCInst &MI, const MCOperand &MO,
737845
return getExprOpValue(MO.getExpr(),Fixups, STI);
738846
}
739847

848+
/// Return binary encoding of MIPS16 save and restore operands.
849+
unsigned
850+
MipsMCCodeEmitter::getSaveRestoreEncoding(const MCInst &MI, unsigned OpNo,
851+
SmallVectorImpl<MCFixup> &Fixups,
852+
const MCSubtargetInfo &STI) const {
853+
union {
854+
struct {
855+
unsigned framesize : 8;
856+
unsigned s1 : 1;
857+
unsigned s0 : 1;
858+
unsigned ra : 1;
859+
unsigned aregs : 4;
860+
unsigned xsregs : 3;
861+
} bits;
862+
unsigned val;
863+
} Encoding;
864+
865+
Encoding.val = 0;
866+
867+
// The number of caller-saved regs for 'aregs' and saved 'xsregs' is
868+
// determined by the largest register number in the list. That is [$4-7] for
869+
// 'aregs' and [$18-23, $30] for 'xsregs'. All other regs below those are
870+
// implicitly handled. For example, reg $6 would also handle regs $4 and $5
871+
// even if they were not called out in the assembly code.
872+
// This is similar for the static registers in 'aregs', but the count is
873+
// determined by the smallest register number. For example, if only reg $4
874+
// were specified, then the other three argument regs would be handled.
875+
unsigned NumAregArgs = 0;
876+
unsigned NumAregStatics = 0;
877+
unsigned NumXsRegs = 0;
878+
879+
// Get saved "$s_" regs (xsregs) and caller-saved argument regs.
880+
while (OpNo < MI.getNumOperands() && MI.getOperand(OpNo).isReg()) {
881+
switch (MI.getOperand(OpNo).getReg()) {
882+
default: {
883+
unsigned RegIdx = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI);
884+
if (NumXsRegs < (RegIdx - 17))
885+
NumXsRegs = RegIdx - 17;
886+
break;
887+
}
888+
case Mips::A0:
889+
case Mips::A0_64:
890+
if (NumAregArgs < 1)
891+
NumAregArgs = 1;
892+
break;
893+
case Mips::A1:
894+
case Mips::A1_64:
895+
if (NumAregArgs < 2)
896+
NumAregArgs = 2;
897+
break;
898+
case Mips::A2:
899+
case Mips::A2_64:
900+
if (NumAregArgs < 3)
901+
NumAregArgs = 3;
902+
break;
903+
case Mips::A3:
904+
case Mips::A3_64:
905+
NumAregArgs = 4;
906+
break;
907+
case Mips::S0:
908+
case Mips::S0_64:
909+
Encoding.bits.s0 = 1;
910+
break;
911+
case Mips::S1:
912+
case Mips::S1_64:
913+
Encoding.bits.s1 = 1;
914+
break;
915+
case Mips::FP:
916+
case Mips::FP_64:
917+
NumXsRegs = 7;
918+
break;
919+
case Mips::RA:
920+
case Mips::RA_64:
921+
Encoding.bits.ra = 1;
922+
break;
923+
}
924+
925+
++OpNo;
926+
}
927+
928+
// Instruction multiplies framesize value by 8.
929+
Encoding.bits.framesize = MI.getOperand(OpNo).getImm() >> 3;
930+
++OpNo;
931+
932+
// Get static argument regs (ones saved at the end of the callee stack).
933+
while (OpNo < MI.getNumOperands() && MI.getOperand(OpNo).isReg()) {
934+
unsigned RegIdx = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI);
935+
if (NumAregStatics < (8 - RegIdx))
936+
NumAregStatics = 8 - RegIdx;
937+
938+
++OpNo;
939+
}
940+
941+
// Determine 'aregs' encoding. There are two special cases for when all
942+
// four argument regs are used.
943+
if (NumAregStatics == 4) {
944+
Encoding.bits.aregs = 0b1011;
945+
} else if (NumAregArgs == 4) {
946+
Encoding.bits.aregs = 0b1110;
947+
} else {
948+
Encoding.bits.aregs = (NumAregArgs << 2) | NumAregStatics;
949+
}
950+
951+
Encoding.bits.xsregs = NumXsRegs;
952+
953+
return Encoding.val;
954+
}
955+
740956
/// Return binary encoding of memory related operand.
741957
/// If the offset operand requires relocation, record the relocation.
742958
template <unsigned ShiftAmount>

0 commit comments

Comments
 (0)