From a4c4b5fc0160fb1c3d550f17732690eeb96a3702 Mon Sep 17 00:00:00 2001 From: Zoran Jovanovic Date: Wed, 19 Nov 2014 16:44:02 +0000 Subject: [PATCH] [mips][micromips] Implement SWM32 and LWM32 instructions Differential Revision: http://reviews.llvm.org/D5519 llvm-svn: 222367 --- llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 122 ++++++++++++++++++++- .../Target/Mips/Disassembler/MipsDisassembler.cpp | 48 +++++++- .../Target/Mips/InstPrinter/MipsInstPrinter.cpp | 22 ++++ llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h | 1 + .../Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp | 31 ++++++ .../Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h | 3 + llvm/lib/Target/Mips/MicroMipsInstrFormats.td | 13 +++ llvm/lib/Target/Mips/MicroMipsInstrInfo.td | 33 ++++++ llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 20 ++++ llvm/lib/Target/Mips/MipsAsmPrinter.h | 1 + llvm/test/MC/Disassembler/Mips/micromips.txt | 6 + llvm/test/MC/Disassembler/Mips/micromips_le.txt | 6 + llvm/test/MC/Mips/micromips-invalid.s | 7 ++ .../MC/Mips/micromips-loadstore-instructions.s | 72 ++++++++---- 14 files changed, 355 insertions(+), 30 deletions(-) diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 1efbc05..0c5b41f 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -146,6 +146,9 @@ class MipsAsmParser : public MCTargetAsmParser { MipsAsmParser::OperandMatchResultTy parseLSAImm(OperandVector &Operands); + MipsAsmParser::OperandMatchResultTy + parseRegisterList (OperandVector &Operands); + bool searchSymbolAlias(OperandVector &Operands); bool parseOperand(OperandVector &, StringRef Mnemonic); @@ -424,7 +427,8 @@ private: k_Memory, /// Base + Offset Memory Address k_PhysRegister, /// A physical register from the Mips namespace k_RegisterIndex, /// A register index in one or more RegKind. - k_Token /// A simple token + k_Token, /// A simple token + k_RegList /// A physical register list } Kind; public: @@ -459,12 +463,17 @@ private: const MCExpr *Off; }; + struct RegListOp { + SmallVector *List; + }; + union { struct Token Tok; struct PhysRegOp PhysReg; struct RegIdxOp RegIdx; struct ImmOp Imm; struct MemOp Mem; + struct RegListOp RegList; }; SMLoc StartLoc, EndLoc; @@ -751,6 +760,13 @@ public: addExpr(Inst, Expr); } + void addRegListOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + + for (auto RegNo : getRegList()) + Inst.addOperand(MCOperand::CreateReg(RegNo)); + } + bool isReg() const override { // As a special case until we sort out the definition of div/divu, pretend // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. @@ -783,6 +799,7 @@ public: int64_t Val = getConstantImm(); return 1 <= Val && Val <= 4; } + bool isRegList() const { return Kind == k_RegList; } StringRef getToken() const { assert(Kind == k_Token && "Invalid access!"); @@ -824,6 +841,11 @@ public: return static_cast(getMemOff())->getValue(); } + const SmallVectorImpl &getRegList() const { + assert((Kind == k_RegList) && "Invalid access!"); + return *(RegList.List); + } + static std::unique_ptr CreateToken(StringRef Str, SMLoc S, MipsAsmParser &Parser) { auto Op = make_unique(k_Token, Parser); @@ -919,6 +941,20 @@ public: return Op; } + static std::unique_ptr + CreateRegList(SmallVectorImpl &Regs, SMLoc StartLoc, SMLoc EndLoc, + MipsAsmParser &Parser) { + assert (Regs.size() > 0 && "Empty list not allowed"); + + auto Op = make_unique(k_RegList, Parser); + Op->RegList.List = new SmallVector(); + for (auto Reg : Regs) + Op->RegList.List->push_back(Reg); + Op->StartLoc = StartLoc; + Op->EndLoc = EndLoc; + return Op; + } + bool isGPRAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; } @@ -973,6 +1009,8 @@ public: case k_Memory: delete Mem.Base; break; + case k_RegList: + delete RegList.List; case k_PhysRegister: case k_RegisterIndex: case k_Token: @@ -1003,6 +1041,12 @@ public: case k_Token: OS << Tok.Data; break; + case k_RegList: + OS << "RegList< "; + for (auto Reg : (*RegList.List)) + OS << Reg << " "; + OS << ">"; + break; } } }; // class MipsOperand @@ -2522,6 +2566,82 @@ MipsAsmParser::parseLSAImm(OperandVector &Operands) { return MatchOperand_Success; } +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseRegisterList(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + SmallVector Regs; + unsigned RegNo; + unsigned PrevReg = Mips::NoRegister; + bool RegRange = false; + SmallVector, 8> TmpOperands; + + if (Parser.getTok().isNot(AsmToken::Dollar)) + return MatchOperand_ParseFail; + + SMLoc S = Parser.getTok().getLoc(); + while (parseAnyRegister(TmpOperands) == MatchOperand_Success) { + SMLoc E = getLexer().getLoc(); + MipsOperand &Reg = static_cast(*TmpOperands.back()); + RegNo = isGP64bit() ? Reg.getGPR64Reg() : Reg.getGPR32Reg(); + if (RegRange) { + // Remove last register operand because registers from register range + // should be inserted first. + if (RegNo == Mips::RA) { + Regs.push_back(RegNo); + } else { + unsigned TmpReg = PrevReg + 1; + while (TmpReg <= RegNo) { + if ((TmpReg < Mips::S0) || (TmpReg > Mips::S7)) { + Error(E, "invalid register operand"); + return MatchOperand_ParseFail; + } + + PrevReg = TmpReg; + Regs.push_back(TmpReg++); + } + } + + RegRange = false; + } else { + if ((PrevReg == Mips::NoRegister) && (RegNo != Mips::S0) && + (RegNo != Mips::RA)) { + Error(E, "$16 or $31 expected"); + return MatchOperand_ParseFail; + } else if (((RegNo < Mips::S0) || (RegNo > Mips::S7)) && + (RegNo != Mips::FP) && (RegNo != Mips::RA)) { + Error(E, "invalid register operand"); + return MatchOperand_ParseFail; + } else if ((PrevReg != Mips::NoRegister) && (RegNo != PrevReg + 1) && + (RegNo != Mips::FP) && (RegNo != Mips::RA)) { + Error(E, "consecutive register numbers expected"); + return MatchOperand_ParseFail; + } + + Regs.push_back(RegNo); + } + + if (Parser.getTok().is(AsmToken::Minus)) + RegRange = true; + + if (!Parser.getTok().isNot(AsmToken::Minus) && + !Parser.getTok().isNot(AsmToken::Comma)) { + Error(E, "',' or '-' expected"); + return MatchOperand_ParseFail; + } + + Lex(); // Consume comma or minus + if (Parser.getTok().isNot(AsmToken::Dollar)) + break; + + PrevReg = RegNo; + } + + SMLoc E = Parser.getTok().getLoc(); + Operands.push_back(MipsOperand::CreateRegList(Regs, S, E, *this)); + parseMemOperand(Operands); + return MatchOperand_Success; +} + MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) { MCSymbolRefExpr::VariantKind VK = diff --git a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp index 5d594f1..48904ce 100644 --- a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -341,6 +341,10 @@ static DecodeStatus DecodeBlezGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + namespace llvm { extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, TheMips64elTarget; @@ -1034,12 +1038,23 @@ static DecodeStatus DecodeMemMMImm12(MCInst &Inst, Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); Base = getReg(Decoder, Mips::GPR32RegClassID, Base); - if (Inst.getOpcode() == Mips::SC_MM) + switch (Inst.getOpcode()) { + case Mips::SWM32_MM: + case Mips::LWM32_MM: + if (DecodeRegListOperand(Inst, Insn, Address, Decoder) + == MCDisassembler::Fail) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + break; + case Mips::SC_MM: Inst.addOperand(MCOperand::CreateReg(Reg)); - - Inst.addOperand(MCOperand::CreateReg(Reg)); - Inst.addOperand(MCOperand::CreateReg(Base)); - Inst.addOperand(MCOperand::CreateImm(Offset)); + // fallthrough + default: + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + } return MCDisassembler::Success; } @@ -1375,3 +1390,26 @@ static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, Inst.addOperand(MCOperand::CreateImm(SignExtend32<18>(Insn) * 8)); return MCDisassembler::Success; } + +static DecodeStatus DecodeRegListOperand(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Regs[] = {Mips::S0, Mips::S1, Mips::S2, Mips::S3, Mips::S4, Mips::S5, + Mips::S6, Mips::FP}; + unsigned RegNum; + + unsigned RegLst = fieldFromInstruction(Insn, 21, 5); + // Empty register lists are not allowed. + if (RegLst == 0) + return MCDisassembler::Fail; + + RegNum = RegLst & 0xf; + for (unsigned i = 0; i < RegNum; i++) + Inst.addOperand(MCOperand::CreateReg(Regs[i])); + + if (RegLst & 0x10) + Inst.addOperand(MCOperand::CreateReg(Mips::RA)); + + return MCDisassembler::Success; +} diff --git a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp index 8c79751..ab6b225 100644 --- a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp +++ b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -225,6 +225,18 @@ printMemOperand(const MCInst *MI, int opNum, raw_ostream &O) { // Load/Store memory operands -- imm($reg) // If PIC target the target is loaded as the // pattern lw $25,%call16($28) + + // opNum can be invalid if instruction had reglist as operand. + // MemOperand is always last operand of instruction (base + offset). + switch (MI->getOpcode()) { + default: + break; + case Mips::SWM32_MM: + case Mips::LWM32_MM: + opNum = MI->getNumOperands() - 2; + break; + } + printOperand(MI, opNum+1, O); O << "("; printOperand(MI, opNum, O); @@ -324,3 +336,13 @@ void MipsInstPrinter::printSaveRestore(const MCInst *MI, raw_ostream &O) { } } +void MipsInstPrinter:: +printRegisterList(const MCInst *MI, int opNum, raw_ostream &O) { + // - 2 because register List is always first operand of instruction and it is + // always followed by memory operand (base + offset). + for (int i = opNum, e = MI->getNumOperands() - 2; i != e; ++i) { + if (i != opNum) + O << ", "; + printRegName(O, MI->getOperand(i).getReg()); + } +} diff --git a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h index d4f3253..42df013 100644 --- a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h +++ b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h @@ -107,6 +107,7 @@ private: unsigned OpNo1, raw_ostream &OS); bool printAlias(const MCInst &MI, raw_ostream &OS); void printSaveRestore(const MCInst *MI, raw_ostream &O); + void printRegisterList(const MCInst *MI, int opNum, raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index 6fa56e8..d632c27 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -638,6 +638,17 @@ unsigned MipsMCCodeEmitter:: getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { + // opNum can be invalid if instruction had reglist as operand. + // MemOperand is always last operand of instruction (base + offset). + switch (MI.getOpcode()) { + default: + break; + case Mips::SWM32_MM: + case Mips::LWM32_MM: + OpNo = MI.getNumOperands() - 2; + break; + } + // Base register is encoded in bits 20-16, offset is encoded in bits 11-0. assert(MI.getOperand(OpNo).isReg()); unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI) << 16; @@ -757,4 +768,24 @@ MipsMCCodeEmitter::getUImm4AndValue(const MCInst &MI, unsigned OpNo, llvm_unreachable("Unexpected value"); } +unsigned +MipsMCCodeEmitter::getRegisterListOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + unsigned res = 0; + + // Register list operand is always first operand of instruction and it is + // placed before memory operand (register + imm). + + for (unsigned I = OpNo, E = MI.getNumOperands() - 2; I < E; ++I) { + unsigned Reg = MI.getOperand(I).getReg(); + unsigned RegNo = Ctx.getRegisterInfo()->getEncodingValue(Reg); + if (RegNo != 31) + res++; + else + res |= 0x10; + } + return res; +} + #include "MipsGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h index df64ed4..9016fcf 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -175,6 +175,9 @@ public: unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned getRegisterListOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; // class MipsMCCodeEmitter } // namespace llvm. diff --git a/llvm/lib/Target/Mips/MicroMipsInstrFormats.td b/llvm/lib/Target/Mips/MicroMipsInstrFormats.td index d1e02b8..59bf949 100644 --- a/llvm/lib/Target/Mips/MicroMipsInstrFormats.td +++ b/llvm/lib/Target/Mips/MicroMipsInstrFormats.td @@ -804,3 +804,16 @@ class LWXS_FM_MM funct> { let Inst{10} = 0; let Inst{9-0} = funct; } + +class LWM_FM_MM funct> : MMArch { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = 0x8; + let Inst{25-21} = rt; + let Inst{20-16} = addr{20-16}; + let Inst{15-12} = funct; + let Inst{11-0} = addr{11-0}; +} diff --git a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td index 4a4cca9..e854620 100644 --- a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td +++ b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td @@ -271,6 +271,35 @@ class LoadWordIndexedScaledMM; +/// A list of registers used by load/store multiple instructions. +def RegListAsmOperand : AsmOperandClass { + let Name = "RegList"; + let ParserMethod = "parseRegisterList"; +} + +def reglist : Operand { + let EncoderMethod = "getRegisterListOpValue"; + let ParserMatchClass = RegListAsmOperand; + let PrintMethod = "printRegisterList"; + let DecoderMethod = "DecodeRegListOperand"; +} + +class StoreMultMM : + InstSE<(outs), (ins reglist:$rt, mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMemMMImm12"; + let mayStore = 1; +} + +class LoadMultMM : + InstSE<(outs reglist:$rt), (ins mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMemMMImm12"; + let mayLoad = 1; +} + def ADDU16_MM : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>, ARITH_FM_MM16<0>; def SUBU16_MM : ArithRMM16<"subu16", GPRMM16Opnd, 0, II_SUBU, sub>, @@ -402,6 +431,10 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12>, LWL_FM_MM<0x9>; + /// Load and Store Instructions - multiple + def SWM32_MM : StoreMultMM<"swm32">, LWM_FM_MM<0xd>; + def LWM32_MM : LoadMultMM<"lwm32">, LWM_FM_MM<0x5>; + /// Move Conditional def MOVZ_I_MM : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, NoItinerary>, ADD_FM_MM<0, 0x58>; diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp index 1b4cb61..832fa05 100644 --- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp @@ -645,6 +645,18 @@ printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { // Load/Store memory operands -- imm($reg) // If PIC target the target is loaded as the // pattern lw $25,%call16($28) + + // opNum can be invalid if instruction has reglist as operand. + // MemOperand is always last operand of instruction (base + offset). + switch (MI->getOpcode()) { + default: + break; + case Mips::SWM32_MM: + case Mips::LWM32_MM: + opNum = MI->getNumOperands() - 2; + break; + } + printOperand(MI, opNum+1, O); O << "("; printOperand(MI, opNum, O); @@ -668,6 +680,14 @@ printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); } +void MipsAsmPrinter:: +printRegisterList(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::EmitStartOfAsmFile(Module &M) { bool IsABICalls = Subtarget->isABICalls(); if (IsABICalls) { diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.h b/llvm/lib/Target/Mips/MipsAsmPrinter.h index 7f358d7..0582e21 100644 --- a/llvm/lib/Target/Mips/MipsAsmPrinter.h +++ b/llvm/lib/Target/Mips/MipsAsmPrinter.h @@ -134,6 +134,7 @@ public: void printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O); void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, const char *Modifier = nullptr); + void printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O); void EmitStartOfAsmFile(Module &M) override; void EmitEndOfAsmFile(Module &M) override; void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); diff --git a/llvm/test/MC/Disassembler/Mips/micromips.txt b/llvm/test/MC/Disassembler/Mips/micromips.txt index 6419455..6464824 100644 --- a/llvm/test/MC/Disassembler/Mips/micromips.txt +++ b/llvm/test/MC/Disassembler/Mips/micromips.txt @@ -315,3 +315,9 @@ # CHECK: jalrs $ra, $6 0x03 0xe6 0x4f 0x3c + +# CHECK: lwm32 $16, $17, 8($4) +0x20 0x44 0x50 0x08 + +# CHECK: swm32 $16, $17, 8($4) +0x20 0x44 0xd0 0x08 diff --git a/llvm/test/MC/Disassembler/Mips/micromips_le.txt b/llvm/test/MC/Disassembler/Mips/micromips_le.txt index e9ca451..d4dbc46 100644 --- a/llvm/test/MC/Disassembler/Mips/micromips_le.txt +++ b/llvm/test/MC/Disassembler/Mips/micromips_le.txt @@ -315,3 +315,9 @@ # CHECK: jalrs $ra, $6 0xe6 0x03 0x3c 0x4f + +# CHECK: lwm32 $16, $17, 8($4) +0x44 0x20 0x08 0x50 + +# CHECK: swm32 $16, $17, 8($4) +0x44 0x20 0x08 0xd0 diff --git a/llvm/test/MC/Mips/micromips-invalid.s b/llvm/test/MC/Mips/micromips-invalid.s index fb0e9ac..779e66e0 100644 --- a/llvm/test/MC/Mips/micromips-invalid.s +++ b/llvm/test/MC/Mips/micromips-invalid.s @@ -22,3 +22,10 @@ li16 $4, -2 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range 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 + lwm32 $5, $6, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: $16 or $31 expected + lwm32 $16, $19, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: consecutive register numbers expected + lwm32 $16-$25, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid register operand + swm32 $5, $6, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: $16 or $31 expected + swm32 $16, $19, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: consecutive register numbers expected + swm32 $16-$25, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid register operand + lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $24, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid register operand diff --git a/llvm/test/MC/Mips/micromips-loadstore-instructions.s b/llvm/test/MC/Mips/micromips-loadstore-instructions.s index e5ce78a..62fa101 100644 --- a/llvm/test/MC/Mips/micromips-loadstore-instructions.s +++ b/llvm/test/MC/Mips/micromips-loadstore-instructions.s @@ -9,33 +9,49 @@ #------------------------------------------------------------------------------ # Little endian #------------------------------------------------------------------------------ -# CHECK-EL: lb $5, 8($4) # encoding: [0xa4,0x1c,0x08,0x00] -# CHECK-EL: lbu $6, 8($4) # encoding: [0xc4,0x14,0x08,0x00] -# CHECK-EL: lh $2, 8($4) # encoding: [0x44,0x3c,0x08,0x00] -# CHECK-EL: lhu $4, 8($2) # encoding: [0x82,0x34,0x08,0x00] -# CHECK-EL: lw $6, 4($5) # encoding: [0xc5,0xfc,0x04,0x00] -# CHECK-EL: sb $5, 8($4) # encoding: [0xa4,0x18,0x08,0x00] -# CHECK-EL: sh $2, 8($4) # encoding: [0x44,0x38,0x08,0x00] -# CHECK-EL: sw $5, 4($6) # encoding: [0xa6,0xf8,0x04,0x00] -# CHECK-EL: ll $2, 8($4) # encoding: [0x44,0x60,0x08,0x30] -# CHECK-EL: sc $2, 8($4) # encoding: [0x44,0x60,0x08,0xb0] -# CHECK-EL: lwu $2, 8($4) # encoding: [0x44,0x60,0x08,0xe0] -# CHECK-EL: lwxs $2, $3($4) # encoding: [0x64,0x00,0x18,0x11] +# CHECK-EL: lb $5, 8($4) # encoding: [0xa4,0x1c,0x08,0x00] +# CHECK-EL: lbu $6, 8($4) # encoding: [0xc4,0x14,0x08,0x00] +# CHECK-EL: lh $2, 8($4) # encoding: [0x44,0x3c,0x08,0x00] +# CHECK-EL: lhu $4, 8($2) # encoding: [0x82,0x34,0x08,0x00] +# CHECK-EL: lw $6, 4($5) # encoding: [0xc5,0xfc,0x04,0x00] +# CHECK-EL: sb $5, 8($4) # encoding: [0xa4,0x18,0x08,0x00] +# CHECK-EL: sh $2, 8($4) # encoding: [0x44,0x38,0x08,0x00] +# CHECK-EL: sw $5, 4($6) # encoding: [0xa6,0xf8,0x04,0x00] +# CHECK-EL: ll $2, 8($4) # encoding: [0x44,0x60,0x08,0x30] +# CHECK-EL: sc $2, 8($4) # encoding: [0x44,0x60,0x08,0xb0] +# CHECK-EL: lwu $2, 8($4) # encoding: [0x44,0x60,0x08,0xe0] +# CHECK-EL: lwxs $2, $3($4) # encoding: [0x64,0x00,0x18,0x11] +# CHECK-EL: lwm32 $16, $17, 8($4) # encoding: [0x44,0x20,0x08,0x50] +# CHECK-EL: lwm32 $16, $17, $18, $19, 8($4) # encoding: [0x84,0x20,0x08,0x50] +# CHECK-EL: lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $fp, 8($4) # encoding: [0x24,0x21,0x08,0x50] +# CHECK-EL: lwm32 $16, $17, $18, $19, $ra, 8($4) # encoding: [0x84,0x22,0x08,0x50] +# CHECK-EL: lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $fp, $ra, 8($4) # encoding: [0x24,0x23,0x08,0x50] +# CHECK-EL: lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $fp, $ra, 8($4) # encoding: [0x24,0x23,0x08,0x50] +# CHECK-EL: swm32 $16, $17, 8($4) # encoding: [0x44,0x20,0x08,0xd0] +# CHECK-EL: swm32 $16, $17, $18, $19, 8($4) # encoding: [0x84,0x20,0x08,0xd0] #------------------------------------------------------------------------------ # Big endian #------------------------------------------------------------------------------ -# CHECK-EB: lb $5, 8($4) # encoding: [0x1c,0xa4,0x00,0x08] -# CHECK-EB: lbu $6, 8($4) # encoding: [0x14,0xc4,0x00,0x08] -# CHECK-EB: lh $2, 8($4) # encoding: [0x3c,0x44,0x00,0x08] -# CHECK-EB: lhu $4, 8($2) # encoding: [0x34,0x82,0x00,0x08] -# CHECK-EB: lw $6, 4($5) # encoding: [0xfc,0xc5,0x00,0x04] -# CHECK-EB: sb $5, 8($4) # encoding: [0x18,0xa4,0x00,0x08] -# CHECK-EB: sh $2, 8($4) # encoding: [0x38,0x44,0x00,0x08] -# CHECK-EB: sw $5, 4($6) # encoding: [0xf8,0xa6,0x00,0x04] -# CHECK-EB: ll $2, 8($4) # encoding: [0x60,0x44,0x30,0x08] -# CHECK-EB: sc $2, 8($4) # encoding: [0x60,0x44,0xb0,0x08] -# CHECK-EB: lwu $2, 8($4) # encoding: [0x60,0x44,0xe0,0x08] -# CHECK-EB: lwxs $2, $3($4) # encoding: [0x00,0x64,0x11,0x18] +# CHECK-EB: lb $5, 8($4) # encoding: [0x1c,0xa4,0x00,0x08] +# CHECK-EB: lbu $6, 8($4) # encoding: [0x14,0xc4,0x00,0x08] +# CHECK-EB: lh $2, 8($4) # encoding: [0x3c,0x44,0x00,0x08] +# CHECK-EB: lhu $4, 8($2) # encoding: [0x34,0x82,0x00,0x08] +# CHECK-EB: lw $6, 4($5) # encoding: [0xfc,0xc5,0x00,0x04] +# CHECK-EB: sb $5, 8($4) # encoding: [0x18,0xa4,0x00,0x08] +# CHECK-EB: sh $2, 8($4) # encoding: [0x38,0x44,0x00,0x08] +# CHECK-EB: sw $5, 4($6) # encoding: [0xf8,0xa6,0x00,0x04] +# CHECK-EB: ll $2, 8($4) # encoding: [0x60,0x44,0x30,0x08] +# CHECK-EB: sc $2, 8($4) # encoding: [0x60,0x44,0xb0,0x08] +# CHECK-EB: lwu $2, 8($4) # encoding: [0x60,0x44,0xe0,0x08] +# CHECK-EB: lwxs $2, $3($4) # encoding: [0x00,0x64,0x11,0x18] +# CHECK-EB: lwm32 $16, $17, 8($4) # encoding: [0x20,0x44,0x50,0x08] +# CHECK-EB: lwm32 $16, $17, $18, $19, 8($4) # encoding: [0x20,0x84,0x50,0x08] +# CHECK-EB: lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $fp, 8($4) # encoding: [0x21,0x24,0x50,0x08] +# CHECK-EB: lwm32 $16, $17, $18, $19, $ra, 8($4) # encoding: [0x22,0x84,0x50,0x08] +# CHECK-EB: lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $fp, $ra, 8($4) # encoding: [0x23,0x24,0x50,0x08] +# CHECK-EB: lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $fp, $ra, 8($4) # encoding: [0x23,0x24,0x50,0x08] +# CHECK-EB: swm32 $16, $17, 8($4) # encoding: [0x20,0x44,0xd0,0x08] +# CHECK-EB: swm32 $16, $17, $18, $19, 8($4) # encoding: [0x20,0x84,0xd0,0x08] lb $5, 8($4) lbu $6, 8($4) lh $2, 8($4) @@ -48,3 +64,11 @@ sc $2, 8($4) lwu $2, 8($4) lwxs $2, $3($4) + lwm32 $16, $17, 8($4) + lwm32 $16 - $19, 8($4) + lwm32 $16-$23, $30, 8($4) + lwm32 $16-$19, $31, 8($4) + lwm32 $16-$23, $30, $31, 8($4) + lwm32 $16-$23, $30 - $31, 8($4) + swm32 $16, $17, 8($4) + swm32 $16 - $19, 8($4) -- 2.7.4