mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
[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:
parent
ca72befdb5
commit
d67cd80220
@ -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 =
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
}
|
||||||
|
@ -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>;
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user