[mips][micromips] Implement SWM32 and LWM32 instructions

Differential Revision: http://reviews.llvm.org/D5519


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222367 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Zoran Jovanovic 2014-11-19 16:44:02 +00:00
parent ca72befdb5
commit d67cd80220
14 changed files with 355 additions and 30 deletions

View File

@ -146,6 +146,9 @@ class MipsAsmParser : public MCTargetAsmParser {
MipsAsmParser::OperandMatchResultTy parseLSAImm(OperandVector &Operands); MipsAsmParser::OperandMatchResultTy parseLSAImm(OperandVector &Operands);
MipsAsmParser::OperandMatchResultTy
parseRegisterList (OperandVector &Operands);
bool searchSymbolAlias(OperandVector &Operands); bool searchSymbolAlias(OperandVector &Operands);
bool parseOperand(OperandVector &, StringRef Mnemonic); bool parseOperand(OperandVector &, StringRef Mnemonic);
@ -424,7 +427,8 @@ private:
k_Memory, /// Base + Offset Memory Address k_Memory, /// Base + Offset Memory Address
k_PhysRegister, /// A physical register from the Mips namespace k_PhysRegister, /// A physical register from the Mips namespace
k_RegisterIndex, /// A register index in one or more RegKind. 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; } Kind;
public: public:
@ -459,12 +463,17 @@ private:
const MCExpr *Off; const MCExpr *Off;
}; };
struct RegListOp {
SmallVector<unsigned, 10> *List;
};
union { union {
struct Token Tok; struct Token Tok;
struct PhysRegOp PhysReg; struct PhysRegOp PhysReg;
struct RegIdxOp RegIdx; struct RegIdxOp RegIdx;
struct ImmOp Imm; struct ImmOp Imm;
struct MemOp Mem; struct MemOp Mem;
struct RegListOp RegList;
}; };
SMLoc StartLoc, EndLoc; SMLoc StartLoc, EndLoc;
@ -751,6 +760,13 @@ public:
addExpr(Inst, Expr); 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 { bool isReg() const override {
// As a special case until we sort out the definition of div/divu, pretend // 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. // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly.
@ -783,6 +799,7 @@ public:
int64_t Val = getConstantImm(); int64_t Val = getConstantImm();
return 1 <= Val && Val <= 4; return 1 <= Val && Val <= 4;
} }
bool isRegList() const { return Kind == k_RegList; }
StringRef getToken() const { StringRef getToken() const {
assert(Kind == k_Token && "Invalid access!"); assert(Kind == k_Token && "Invalid access!");
@ -824,6 +841,11 @@ public:
return static_cast<const MCConstantExpr *>(getMemOff())->getValue(); return static_cast<const MCConstantExpr *>(getMemOff())->getValue();
} }
const SmallVectorImpl<unsigned> &getRegList() const {
assert((Kind == k_RegList) && "Invalid access!");
return *(RegList.List);
}
static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S, static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S,
MipsAsmParser &Parser) { MipsAsmParser &Parser) {
auto Op = make_unique<MipsOperand>(k_Token, Parser); auto Op = make_unique<MipsOperand>(k_Token, Parser);
@ -919,6 +941,20 @@ public:
return Op; return Op;
} }
static std::unique_ptr<MipsOperand>
CreateRegList(SmallVectorImpl<unsigned> &Regs, SMLoc StartLoc, SMLoc EndLoc,
MipsAsmParser &Parser) {
assert (Regs.size() > 0 && "Empty list not allowed");
auto Op = make_unique<MipsOperand>(k_RegList, Parser);
Op->RegList.List = new SmallVector<unsigned, 10>();
for (auto Reg : Regs)
Op->RegList.List->push_back(Reg);
Op->StartLoc = StartLoc;
Op->EndLoc = EndLoc;
return Op;
}
bool isGPRAsmReg() const { bool isGPRAsmReg() const {
return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31;
} }
@ -973,6 +1009,8 @@ public:
case k_Memory: case k_Memory:
delete Mem.Base; delete Mem.Base;
break; break;
case k_RegList:
delete RegList.List;
case k_PhysRegister: case k_PhysRegister:
case k_RegisterIndex: case k_RegisterIndex:
case k_Token: case k_Token:
@ -1003,6 +1041,12 @@ public:
case k_Token: case k_Token:
OS << Tok.Data; OS << Tok.Data;
break; break;
case k_RegList:
OS << "RegList< ";
for (auto Reg : (*RegList.List))
OS << Reg << " ";
OS << ">";
break;
} }
} }
}; // class MipsOperand }; // class MipsOperand
@ -2522,6 +2566,82 @@ MipsAsmParser::parseLSAImm(OperandVector &Operands) {
return MatchOperand_Success; return MatchOperand_Success;
} }
MipsAsmParser::OperandMatchResultTy
MipsAsmParser::parseRegisterList(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SmallVector<unsigned, 10> Regs;
unsigned RegNo;
unsigned PrevReg = Mips::NoRegister;
bool RegRange = false;
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 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<MipsOperand &>(*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 MipsAsmParser::getVariantKind(StringRef Symbol) {
MCSymbolRefExpr::VariantKind VK = MCSymbolRefExpr::VariantKind VK =

View File

@ -341,6 +341,10 @@ static DecodeStatus
DecodeBlezGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, DecodeBlezGroupBranch(MCInst &MI, InsnType insn, uint64_t Address,
const void *Decoder); const void *Decoder);
static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Insn,
uint64_t Address,
const void *Decoder);
namespace llvm { namespace llvm {
extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, extern Target TheMipselTarget, TheMipsTarget, TheMips64Target,
TheMips64elTarget; TheMips64elTarget;
@ -1034,12 +1038,23 @@ static DecodeStatus DecodeMemMMImm12(MCInst &Inst,
Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg);
Base = getReg(Decoder, Mips::GPR32RegClassID, Base); 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));
// fallthrough
Inst.addOperand(MCOperand::CreateReg(Reg)); default:
Inst.addOperand(MCOperand::CreateReg(Base)); Inst.addOperand(MCOperand::CreateReg(Reg));
Inst.addOperand(MCOperand::CreateImm(Offset)); Inst.addOperand(MCOperand::CreateReg(Base));
Inst.addOperand(MCOperand::CreateImm(Offset));
}
return MCDisassembler::Success; return MCDisassembler::Success;
} }
@ -1375,3 +1390,26 @@ static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn,
Inst.addOperand(MCOperand::CreateImm(SignExtend32<18>(Insn) * 8)); Inst.addOperand(MCOperand::CreateImm(SignExtend32<18>(Insn) * 8));
return MCDisassembler::Success; 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;
}

View File

@ -225,6 +225,18 @@ printMemOperand(const MCInst *MI, int opNum, raw_ostream &O) {
// Load/Store memory operands -- imm($reg) // Load/Store memory operands -- imm($reg)
// If PIC target the target is loaded as the // If PIC target the target is loaded as the
// pattern lw $25,%call16($28) // 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); printOperand(MI, opNum+1, O);
O << "("; O << "(";
printOperand(MI, opNum, 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());
}
}

View File

@ -107,6 +107,7 @@ private:
unsigned OpNo1, raw_ostream &OS); unsigned OpNo1, raw_ostream &OS);
bool printAlias(const MCInst &MI, raw_ostream &OS); bool printAlias(const MCInst &MI, raw_ostream &OS);
void printSaveRestore(const MCInst *MI, raw_ostream &O); void printSaveRestore(const MCInst *MI, raw_ostream &O);
void printRegisterList(const MCInst *MI, int opNum, raw_ostream &O);
}; };
} // end namespace llvm } // end namespace llvm

View File

@ -638,6 +638,17 @@ unsigned MipsMCCodeEmitter::
getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const { 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. // Base register is encoded in bits 20-16, offset is encoded in bits 11-0.
assert(MI.getOperand(OpNo).isReg()); assert(MI.getOperand(OpNo).isReg());
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI) << 16; 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"); llvm_unreachable("Unexpected value");
} }
unsigned
MipsMCCodeEmitter::getRegisterListOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &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" #include "MipsGenMCCodeEmitter.inc"

View File

@ -175,6 +175,9 @@ public:
unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups, unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const; const MCSubtargetInfo &STI) const;
unsigned getRegisterListOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
}; // class MipsMCCodeEmitter }; // class MipsMCCodeEmitter
} // namespace llvm. } // namespace llvm.

View File

@ -804,3 +804,16 @@ class LWXS_FM_MM<bits<10> funct> {
let Inst{10} = 0; let Inst{10} = 0;
let Inst{9-0} = funct; let Inst{9-0} = funct;
} }
class LWM_FM_MM<bits<4> 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};
}

View File

@ -271,6 +271,35 @@ class LoadWordIndexedScaledMM<string opstr, RegisterOperand RO,
InstSE<(outs RO:$rd), (ins PtrRC:$base, PtrRC:$index), InstSE<(outs RO:$rd), (ins PtrRC:$base, PtrRC:$index),
!strconcat(opstr, "\t$rd, ${index}(${base})"), [], Itin, FrmFI>; !strconcat(opstr, "\t$rd, ${index}(${base})"), [], Itin, FrmFI>;
/// A list of registers used by load/store multiple instructions.
def RegListAsmOperand : AsmOperandClass {
let Name = "RegList";
let ParserMethod = "parseRegisterList";
}
def reglist : Operand<i32> {
let EncoderMethod = "getRegisterListOpValue";
let ParserMatchClass = RegListAsmOperand;
let PrintMethod = "printRegisterList";
let DecoderMethod = "DecodeRegListOperand";
}
class StoreMultMM<string opstr,
InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> :
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<string opstr,
InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> :
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>, def ADDU16_MM : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>,
ARITH_FM_MM16<0>; ARITH_FM_MM16<0>;
def SUBU16_MM : ArithRMM16<"subu16", GPRMM16Opnd, 0, II_SUBU, sub>, 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>, def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12>,
LWL_FM_MM<0x9>; 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 /// Move Conditional
def MOVZ_I_MM : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, def MOVZ_I_MM : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd,
NoItinerary>, ADD_FM_MM<0, 0x58>; NoItinerary>, ADD_FM_MM<0, 0x58>;

View File

@ -645,6 +645,18 @@ printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) {
// Load/Store memory operands -- imm($reg) // Load/Store memory operands -- imm($reg)
// If PIC target the target is loaded as the // If PIC target the target is loaded as the
// pattern lw $25,%call16($28) // 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); printOperand(MI, opNum+1, O);
O << "("; O << "(";
printOperand(MI, opNum, 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()); 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) { void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
bool IsABICalls = Subtarget->isABICalls(); bool IsABICalls = Subtarget->isABICalls();
if (IsABICalls) { if (IsABICalls) {

View File

@ -134,6 +134,7 @@ public:
void printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O); void printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O);
void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
const char *Modifier = nullptr); const char *Modifier = nullptr);
void printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O);
void EmitStartOfAsmFile(Module &M) override; void EmitStartOfAsmFile(Module &M) override;
void EmitEndOfAsmFile(Module &M) override; void EmitEndOfAsmFile(Module &M) override;
void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);

View File

@ -315,3 +315,9 @@
# CHECK: jalrs $ra, $6 # CHECK: jalrs $ra, $6
0x03 0xe6 0x4f 0x3c 0x03 0xe6 0x4f 0x3c
# CHECK: lwm32 $16, $17, 8($4)
0x20 0x44 0x50 0x08
# CHECK: swm32 $16, $17, 8($4)
0x20 0x44 0xd0 0x08

View File

@ -315,3 +315,9 @@
# CHECK: jalrs $ra, $6 # CHECK: jalrs $ra, $6
0xe6 0x03 0x3c 0x4f 0xe6 0x03 0x3c 0x4f
# CHECK: lwm32 $16, $17, 8($4)
0x44 0x20 0x08 0x50
# CHECK: swm32 $16, $17, 8($4)
0x44 0x20 0x08 0xd0

View File

@ -22,3 +22,10 @@
li16 $4, -2 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range 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 $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 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

View File

@ -9,33 +9,49 @@
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# Little endian # Little endian
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# CHECK-EL: lb $5, 8($4) # encoding: [0xa4,0x1c,0x08,0x00] # CHECK-EL: lb $5, 8($4) # encoding: [0xa4,0x1c,0x08,0x00]
# CHECK-EL: lbu $6, 8($4) # encoding: [0xc4,0x14,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: lh $2, 8($4) # encoding: [0x44,0x3c,0x08,0x00]
# CHECK-EL: lhu $4, 8($2) # encoding: [0x82,0x34,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: lw $6, 4($5) # encoding: [0xc5,0xfc,0x04,0x00]
# CHECK-EL: sb $5, 8($4) # encoding: [0xa4,0x18,0x08,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: sh $2, 8($4) # encoding: [0x44,0x38,0x08,0x00]
# CHECK-EL: sw $5, 4($6) # encoding: [0xa6,0xf8,0x04,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: ll $2, 8($4) # encoding: [0x44,0x60,0x08,0x30]
# CHECK-EL: sc $2, 8($4) # encoding: [0x44,0x60,0x08,0xb0] # CHECK-EL: sc $2, 8($4) # encoding: [0x44,0x60,0x08,0xb0]
# CHECK-EL: lwu $2, 8($4) # encoding: [0x44,0x60,0x08,0xe0] # CHECK-EL: lwu $2, 8($4) # encoding: [0x44,0x60,0x08,0xe0]
# CHECK-EL: lwxs $2, $3($4) # encoding: [0x64,0x00,0x18,0x11] # 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 # Big endian
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# CHECK-EB: lb $5, 8($4) # encoding: [0x1c,0xa4,0x00,0x08] # CHECK-EB: lb $5, 8($4) # encoding: [0x1c,0xa4,0x00,0x08]
# CHECK-EB: lbu $6, 8($4) # encoding: [0x14,0xc4,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: lh $2, 8($4) # encoding: [0x3c,0x44,0x00,0x08]
# CHECK-EB: lhu $4, 8($2) # encoding: [0x34,0x82,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: lw $6, 4($5) # encoding: [0xfc,0xc5,0x00,0x04]
# CHECK-EB: sb $5, 8($4) # encoding: [0x18,0xa4,0x00,0x08] # CHECK-EB: sb $5, 8($4) # encoding: [0x18,0xa4,0x00,0x08]
# CHECK-EB: sh $2, 8($4) # encoding: [0x38,0x44,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: sw $5, 4($6) # encoding: [0xf8,0xa6,0x00,0x04]
# CHECK-EB: ll $2, 8($4) # encoding: [0x60,0x44,0x30,0x08] # CHECK-EB: ll $2, 8($4) # encoding: [0x60,0x44,0x30,0x08]
# CHECK-EB: sc $2, 8($4) # encoding: [0x60,0x44,0xb0,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: lwu $2, 8($4) # encoding: [0x60,0x44,0xe0,0x08]
# CHECK-EB: lwxs $2, $3($4) # encoding: [0x00,0x64,0x11,0x18] # 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) lb $5, 8($4)
lbu $6, 8($4) lbu $6, 8($4)
lh $2, 8($4) lh $2, 8($4)
@ -48,3 +64,11 @@
sc $2, 8($4) sc $2, 8($4)
lwu $2, 8($4) lwu $2, 8($4)
lwxs $2, $3($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)