Index: lib/Target/NDS32/AsmParser/NDS32AsmParser.cpp =================================================================== --- lib/Target/NDS32/AsmParser/NDS32AsmParser.cpp +++ lib/Target/NDS32/AsmParser/NDS32AsmParser.cpp @@ -103,6 +103,9 @@ bool parseMemory(OperandVector &Operands); + bool isMultipleLoadStore(StringRef Mnemonic); + bool parseRegisterList(OperandVector &Operands); + bool parseOperand(OperandVector &Operands, StringRef Mnemonic); int matchCPURegisterName(StringRef Symbol); @@ -336,6 +339,9 @@ } void addRegListOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + for (auto RegNo : getRegList()) + Inst.addOperand(MCOperand::createReg(RegNo)); } bool isReg() const override { @@ -560,6 +566,13 @@ static std::unique_ptr CreateRegList(SmallVectorImpl &Regs, SMLoc StartLoc, SMLoc EndLoc, NDS32AsmParser &Parser) { + assert (Regs.size() > 0 && "Empty list not allowed"); + + auto Op = make_unique(k_RegList, Parser); + Op->RegList.List = new SmallVector(Regs.begin(), Regs.end()); + Op->StartLoc = StartLoc; + Op->EndLoc = EndLoc; + return Op; } bool isGPRAsmReg() const { @@ -940,6 +953,157 @@ return false; } +bool NDS32AsmParser::isMultipleLoadStore(StringRef Mnemonic) { + if (Mnemonic.compare ("smw.ad") == 0) + return true; + if (Mnemonic.compare ("smw.adm") == 0) + return true; + if (Mnemonic.compare ("smw.ai") == 0) + return true; + if (Mnemonic.compare ("smw.bd") == 0) + return true; + if (Mnemonic.compare ("smw.bi") == 0) + return true; + if (Mnemonic.compare ("smw.bim") == 0) + return true; + if (Mnemonic.compare ("lmw.ad") == 0) + return true; + if (Mnemonic.compare ("lmw.adm") == 0) + return true; + if (Mnemonic.compare ("lmw.ai") == 0) + return true; + if (Mnemonic.compare ("lmw.bd") == 0) + return true; + if (Mnemonic.compare ("lmw.bi") == 0) + return true; + if (Mnemonic.compare ("lmw.bim") == 0) + return true; + + return false; +} + +/// Parse a register list. +bool NDS32AsmParser::parseRegisterList(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + SMLoc S, E; + int BaseRegNum = -1; + int RegListBeginRegNum = -1; + int RegListEndRegNum = -1; + int64_t Enable4Encode = 0; + int Reg = 0; + SmallVector Registers; + + DEBUG(dbgs() << "ParseRegisterList\n"); + + if (Parser.getTok().is(AsmToken::Dollar)) { + Parser.Lex(); // Eat the Dollar. + DEBUG(dbgs() << "Eat $ \n"); + S = Parser.getTok().getLoc(); + + const AsmToken &BeginRegTok = Parser.getTok(); + RegListBeginRegNum = tryParseRegister(); + if (RegListBeginRegNum == -1) + return Error(BeginRegTok.getLoc(), "register expected"); + + DEBUG(dbgs() << "RegListBeginRegNum = " << RegListBeginRegNum << "\n"); + } else + return Error(S, "Expact $"); + + // The next token must be a Comma + if (!Parser.getTok().is(AsmToken::Comma)) + return Error(Parser.getTok().getLoc(), "Expact ,"); + else + Parser.Lex(); // Eat the Comma. + + // The next token must be a LBrac + if (!Parser.getTok().is(AsmToken::LBrac)) + return Error(Parser.getTok().getLoc(), "Expact ["); + else + Parser.Lex(); // Eat the LBrac. + + if (Parser.getTok().is(AsmToken::Dollar)) { + Parser.Lex(); // Eat the Dollar. + DEBUG(dbgs() << "Eat $ \n"); + + const AsmToken &BaseRegTok = Parser.getTok(); + BaseRegNum = tryParseRegister(); + if (BaseRegNum == -1) + return Error(BaseRegTok.getLoc(), "register expected"); + + DEBUG(dbgs() << "BaseRegNum = " << BaseRegNum << "\n"); + // insert BaseRegNum to register list first + Registers.push_back(BaseRegNum); + } else + return Error(Parser.getTok().getLoc(), "Expact $"); + + // The next token must a RBrac + if (!Parser.getTok().is(AsmToken::RBrac)) + return Error(Parser.getTok().getLoc(), "Expact ]"); + else + Parser.Lex(); // Eat the RBrac. + + // The next token must a comma + if (!Parser.getTok().is(AsmToken::Comma)) + return Error(Parser.getTok().getLoc(), "Expact ,"); + else + Parser.Lex(); // Eat the Comma. + + if (Parser.getTok().is(AsmToken::Dollar)) { + Parser.Lex(); // Eat the Dollar. + DEBUG(dbgs() << "Eat $ \n"); + + const AsmToken &EndRegTok = Parser.getTok(); + RegListEndRegNum = tryParseRegister(); + if (RegListEndRegNum == -1) + return Error(EndRegTok.getLoc(), "register expected"); + + DEBUG(dbgs() << "RegListEndRegNum = " << RegListEndRegNum << "\n"); + } else + return Error(Parser.getTok().getLoc(), "Expact $"); + + // The next token must a comma + if (!Parser.getTok().is(AsmToken::Comma)) + return Error(Parser.getTok().getLoc(), "Expact ,"); + else + Parser.Lex(); // Eat the Comma. + + // parsing Enable4 + if (Parser.getTok().is(AsmToken::Integer)) { + E = Parser.getTok().getLoc(); + + const MCExpr *Enable4; + if (getParser().parseExpression(Enable4)) + return true; + + const MCConstantExpr *CE = dyn_cast(Enable4); + if (!CE) + return Error (E, "constant expression expected"); + + Enable4Encode = CE->getValue(); + DEBUG(dbgs() << "Enable4 = " << Enable4Encode << "\n"); + } + + // Add all the registers in the range to the register list. + // There is no R0~R27 register in register if Rb == SP. + if (RegListBeginRegNum != NDS32::SP) + for (Reg = RegListBeginRegNum; Reg <= RegListEndRegNum; Reg++) + Registers.push_back(Reg); + + if (Enable4Encode & 1) + Registers.push_back(NDS32::SP); + if (Enable4Encode & 2) + Registers.push_back(NDS32::LP); + if (Enable4Encode & 4) + Registers.push_back(NDS32::GP); + if (Enable4Encode & 8) + Registers.push_back(NDS32::FP); + + // Push the register list operand. + Operands.push_back(NDS32Operand::CreateRegList(Registers, S, E, *this)); + + return false; +} + bool NDS32AsmParser:: ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { @@ -1048,6 +1212,11 @@ if (ResTy == MatchOperand_ParseFail) return true; + if (isMultipleLoadStore (Mnemonic)) { + parseRegisterList (Operands); + return false; + } + switch (getLexer().getKind()) { default: Error(Parser.getTok().getLoc(), "unexpected token in operand"); Index: lib/Target/NDS32/Disassembler/NDS32Disassembler.cpp =================================================================== --- lib/Target/NDS32/Disassembler/NDS32Disassembler.cpp +++ lib/Target/NDS32/Disassembler/NDS32Disassembler.cpp @@ -444,11 +444,45 @@ return MCDisassembler::Success; } +static void addEnable4Regs(MCInst &Inst, + int32_t Enable4, + const void *Decoder) { + if (Enable4 & 1) + Inst.addOperand(MCOperand::createReg(NDS32::SP)); + if (Enable4 & 2) + Inst.addOperand(MCOperand::createReg(NDS32::LP)); + if (Enable4 & 4) + Inst.addOperand(MCOperand::createReg(NDS32::GP)); + if (Enable4 & 8) + Inst.addOperand(MCOperand::createReg(NDS32::FP)); +} + static DecodeStatus DecodeRegisterList(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) { - return MCDisassembler::Success; + DecodeStatus S = MCDisassembler::Success; + int32_t Enable4 = fieldFromInstruction(Insn, 0, 4); + int32_t ReEnc = fieldFromInstruction(Insn, 4, 5); + int32_t RaEnc = fieldFromInstruction(Insn, 9, 5); + int32_t RbEnc = fieldFromInstruction(Insn, 14, 5); + unsigned I, Re, Ra, Rb; + + Re = getReg(Decoder, NDS32::GPRRegClassID, ReEnc); + Ra = getReg(Decoder, NDS32::GPRRegClassID, RaEnc); + Rb = getReg(Decoder, NDS32::GPRRegClassID, RbEnc); + + // Insert base register first + Inst.addOperand(MCOperand::createReg(Ra)); + + if (Rb != Re) { + for (I = Rb; I <= Re; I++) + Inst.addOperand(MCOperand::createReg(I)); + } + + addEnable4Regs(Inst, Enable4, Decoder); + + return S; } // Decode mulitple load/store with base modification instructions @@ -456,7 +490,29 @@ unsigned Insn, uint64_t Address, const void *Decoder) { - return MCDisassembler::Success; + DecodeStatus S = MCDisassembler::Success; + int32_t Enable4 = fieldFromInstruction(Insn, 6, 4); + int32_t ReEnc = fieldFromInstruction(Insn, 10, 5); + int32_t RaEnc = fieldFromInstruction(Insn, 15, 5); + int32_t RbEnc = fieldFromInstruction(Insn, 20, 5); + unsigned I, Re, Ra, Rb; + + Re = getReg(Decoder, NDS32::GPRRegClassID, ReEnc); + Ra = getReg(Decoder, NDS32::GPRRegClassID, RaEnc); + Rb = getReg(Decoder, NDS32::GPRRegClassID, RbEnc); + + // Insert wb, Ra register first + Inst.addOperand(MCOperand::createReg(Ra)); + Inst.addOperand(MCOperand::createReg(Ra)); + + if (Rb != Re) { + for (I = Rb; I <= Re; I++) + Inst.addOperand(MCOperand::createReg(I)); + } + + addEnable4Regs(Inst, Enable4, Decoder); + + return S; } namespace llvm { Index: lib/Target/NDS32/MCTargetDesc/NDS32MCCodeEmitter.cpp =================================================================== --- lib/Target/NDS32/MCTargetDesc/NDS32MCCodeEmitter.cpp +++ lib/Target/NDS32/MCTargetDesc/NDS32MCCodeEmitter.cpp @@ -422,7 +422,35 @@ getRegisterListEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - return 0; + unsigned SPEncode = Ctx.getRegisterInfo()->getEncodingValue(NDS32::SP); + unsigned Enable4 = 0; + unsigned Rb = SPEncode; + unsigned Re = SPEncode; + unsigned Ra = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + + for (unsigned i = OpNo + 1, e = MI.getNumOperands(); i != e; ++i) { + unsigned Reg = MI.getOperand(i).getReg(); + switch (Reg) { + case NDS32::SP: + Enable4 += 1; + break; + case NDS32::LP: + Enable4 += 2; + break; + case NDS32::GP: + Enable4 += 4; + break; + case NDS32::FP: + Enable4 += 8; + break; + default: + if (Rb == SPEncode) + Rb = getMachineOpValue(MI, MI.getOperand(i), Fixups, STI); + Re = getMachineOpValue(MI, MI.getOperand(i), Fixups, STI); + } + } + + return Rb << 14 | Ra << 9 | Re << 4 | Enable4; } #include "NDS32GenMCCodeEmitter.inc" Index: lib/Target/NDS32/NDS32Predicate.td =================================================================== --- lib/Target/NDS32/NDS32Predicate.td +++ lib/Target/NDS32/NDS32Predicate.td @@ -271,6 +271,8 @@ def reglist : Operand { let MIOperandInfo = (ops GPR:$base, variable_ops); let PrintMethod = "printRegisterList"; + let EncoderMethod = "getRegisterListEncoding"; + let DecoderMethod = "DecodeRegisterList"; let ParserMatchClass = RegListAsmOperand; } Index: test/MC/NDS32/multiple-load-store.s =================================================================== --- /dev/null +++ test/MC/NDS32/multiple-load-store.s @@ -0,0 +1,28 @@ +! RUN: llvm-mc -triple nds32 -filetype=obj -o %t %s +! RUN: llvm-objdump -d -r -triple nds32 %t | FileCheck %s +foo: + smw.adm $sp, [$sp], $sp, 2 + smw.adm $r6, [$sp], $r8, 2 + smw.ai $r6, [$sp], $r6, 2 + smw.bi $r7, [$sp], $r9, 10 + smw.ad $r0, [$r12], $r11, 2 + smw.bd $r0, [$r13], $r12, 10 + lmw.bim $r6, [$sp], $r8, 2 + lmw.bim $sp, [$sp], $sp, 2 + lmw.ai $r6, [$sp], $r6, 2 + lmw.bi $r7, [$sp], $r9, 10 + lmw.ad $r2, [$r0], $r11, 2 + lmw.bd $r3, [$r1], $r12, 10 + +! CHECK: 3b ff fc bc smw.adm $sp, [$sp], $sp, 2 +! CHECK: 3a 6f a0 bc smw.adm $r6, [$sp], $r8, 2 +! CHECK: 3a 6f 98 b0 smw.ai $sp, [$sp], $sp, 2 +! CHECK: 3a 7f a6 a0 smw.bi $r7, [$sp], $r9, 10 +! CHECK: 3a 06 2c b8 smw.ad $r0, [$r12], $r11, 2 +! CHECK: 3a 06 b2 a8 smw.bd $r0, [$r13], $r12, 10 +! CHECK: 3a 6f a0 84 lmw.bim $r6, [$sp], $r8, 2 +! CHECK: 3b ff fc 84 lmw.bim $sp, [$sp], $sp, 2 +! CHECK: 3a 6f 98 90 lmw.ai $sp, [$sp], $sp, 2 +! CHECK: 3a 7f a6 80 lmw.bi $r7, [$sp], $r9, 10 +! CHECK: 3a 20 2c 98 lmw.ad $r2, [$r0], $r11, 2 +! CHECK: 3a 30 b2 88 lmw.bd $r3, [$r1], $r12, 10