forked from OSchip/llvm-project
[SystemZ] Fix encoding of MVCK and .insn ss
LLVM currently treats the first operand of MVCK as if it were a regular base+index+displacement address. However, it is in fact a base+displacement combined with a length register field. While the two might look syntactically similar, there are two semantic differences: - %r0 is a valid length register, even though it cannot be used as an index register. - In an expression with just a single register like 0(%rX), the register is treated as base with normal addresses, while it is treated as the length register (with an empty base) for MVCK. Fixed by adding a new operand parser class BDRAddr and reworking the assembler parser to distinguish between address + length register operands and regular addresses. llvm-svn: 285574
This commit is contained in:
parent
15604b996f
commit
ec5d779eb8
|
@ -50,6 +50,7 @@ enum MemoryKind {
|
||||||
BDMem,
|
BDMem,
|
||||||
BDXMem,
|
BDXMem,
|
||||||
BDLMem,
|
BDLMem,
|
||||||
|
BDRMem,
|
||||||
BDVMem
|
BDVMem
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,7 +100,10 @@ private:
|
||||||
unsigned MemKind : 4;
|
unsigned MemKind : 4;
|
||||||
unsigned RegKind : 4;
|
unsigned RegKind : 4;
|
||||||
const MCExpr *Disp;
|
const MCExpr *Disp;
|
||||||
const MCExpr *Length;
|
union {
|
||||||
|
const MCExpr *Imm;
|
||||||
|
unsigned Reg;
|
||||||
|
} Length;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Imm is an immediate operand, and Sym is an optional TLS symbol
|
// Imm is an immediate operand, and Sym is an optional TLS symbol
|
||||||
|
@ -164,15 +168,18 @@ public:
|
||||||
}
|
}
|
||||||
static std::unique_ptr<SystemZOperand>
|
static std::unique_ptr<SystemZOperand>
|
||||||
createMem(MemoryKind MemKind, RegisterKind RegKind, unsigned Base,
|
createMem(MemoryKind MemKind, RegisterKind RegKind, unsigned Base,
|
||||||
const MCExpr *Disp, unsigned Index, const MCExpr *Length,
|
const MCExpr *Disp, unsigned Index, const MCExpr *LengthImm,
|
||||||
SMLoc StartLoc, SMLoc EndLoc) {
|
unsigned LengthReg, SMLoc StartLoc, SMLoc EndLoc) {
|
||||||
auto Op = make_unique<SystemZOperand>(KindMem, StartLoc, EndLoc);
|
auto Op = make_unique<SystemZOperand>(KindMem, StartLoc, EndLoc);
|
||||||
Op->Mem.MemKind = MemKind;
|
Op->Mem.MemKind = MemKind;
|
||||||
Op->Mem.RegKind = RegKind;
|
Op->Mem.RegKind = RegKind;
|
||||||
Op->Mem.Base = Base;
|
Op->Mem.Base = Base;
|
||||||
Op->Mem.Index = Index;
|
Op->Mem.Index = Index;
|
||||||
Op->Mem.Disp = Disp;
|
Op->Mem.Disp = Disp;
|
||||||
Op->Mem.Length = Length;
|
if (MemKind == BDLMem)
|
||||||
|
Op->Mem.Length.Imm = LengthImm;
|
||||||
|
if (MemKind == BDRMem)
|
||||||
|
Op->Mem.Length.Reg = LengthReg;
|
||||||
return Op;
|
return Op;
|
||||||
}
|
}
|
||||||
static std::unique_ptr<SystemZOperand>
|
static std::unique_ptr<SystemZOperand>
|
||||||
|
@ -249,14 +256,7 @@ public:
|
||||||
return isMem(MemKind, RegKind) && inRange(Mem.Disp, -524288, 524287);
|
return isMem(MemKind, RegKind) && inRange(Mem.Disp, -524288, 524287);
|
||||||
}
|
}
|
||||||
bool isMemDisp12Len8(RegisterKind RegKind) const {
|
bool isMemDisp12Len8(RegisterKind RegKind) const {
|
||||||
return isMemDisp12(BDLMem, RegKind) && inRange(Mem.Length, 1, 0x100);
|
return isMemDisp12(BDLMem, RegKind) && inRange(Mem.Length.Imm, 1, 0x100);
|
||||||
}
|
|
||||||
void addBDVAddrOperands(MCInst &Inst, unsigned N) const {
|
|
||||||
assert(N == 3 && "Invalid number of operands");
|
|
||||||
assert(isMem(BDVMem) && "Invalid operand type");
|
|
||||||
Inst.addOperand(MCOperand::createReg(Mem.Base));
|
|
||||||
addExpr(Inst, Mem.Disp);
|
|
||||||
Inst.addOperand(MCOperand::createReg(Mem.Index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override MCParsedAsmOperand.
|
// Override MCParsedAsmOperand.
|
||||||
|
@ -297,7 +297,21 @@ public:
|
||||||
assert(isMem(BDLMem) && "Invalid operand type");
|
assert(isMem(BDLMem) && "Invalid operand type");
|
||||||
Inst.addOperand(MCOperand::createReg(Mem.Base));
|
Inst.addOperand(MCOperand::createReg(Mem.Base));
|
||||||
addExpr(Inst, Mem.Disp);
|
addExpr(Inst, Mem.Disp);
|
||||||
addExpr(Inst, Mem.Length);
|
addExpr(Inst, Mem.Length.Imm);
|
||||||
|
}
|
||||||
|
void addBDRAddrOperands(MCInst &Inst, unsigned N) const {
|
||||||
|
assert(N == 3 && "Invalid number of operands");
|
||||||
|
assert(isMem(BDRMem) && "Invalid operand type");
|
||||||
|
Inst.addOperand(MCOperand::createReg(Mem.Base));
|
||||||
|
addExpr(Inst, Mem.Disp);
|
||||||
|
Inst.addOperand(MCOperand::createReg(Mem.Length.Reg));
|
||||||
|
}
|
||||||
|
void addBDVAddrOperands(MCInst &Inst, unsigned N) const {
|
||||||
|
assert(N == 3 && "Invalid number of operands");
|
||||||
|
assert(isMem(BDVMem) && "Invalid operand type");
|
||||||
|
Inst.addOperand(MCOperand::createReg(Mem.Base));
|
||||||
|
addExpr(Inst, Mem.Disp);
|
||||||
|
Inst.addOperand(MCOperand::createReg(Mem.Index));
|
||||||
}
|
}
|
||||||
void addImmTLSOperands(MCInst &Inst, unsigned N) const {
|
void addImmTLSOperands(MCInst &Inst, unsigned N) const {
|
||||||
assert(N == 2 && "Invalid number of operands");
|
assert(N == 2 && "Invalid number of operands");
|
||||||
|
@ -331,6 +345,7 @@ public:
|
||||||
bool isBDXAddr64Disp12() const { return isMemDisp12(BDXMem, ADDR64Reg); }
|
bool isBDXAddr64Disp12() const { return isMemDisp12(BDXMem, ADDR64Reg); }
|
||||||
bool isBDXAddr64Disp20() const { return isMemDisp20(BDXMem, ADDR64Reg); }
|
bool isBDXAddr64Disp20() const { return isMemDisp20(BDXMem, ADDR64Reg); }
|
||||||
bool isBDLAddr64Disp12Len8() const { return isMemDisp12Len8(ADDR64Reg); }
|
bool isBDLAddr64Disp12Len8() const { return isMemDisp12Len8(ADDR64Reg); }
|
||||||
|
bool isBDRAddr64Disp12() const { return isMemDisp12(BDRMem, ADDR64Reg); }
|
||||||
bool isBDVAddr64Disp12() const { return isMemDisp12(BDVMem, ADDR64Reg); }
|
bool isBDVAddr64Disp12() const { return isMemDisp12(BDVMem, ADDR64Reg); }
|
||||||
bool isU1Imm() const { return isImm(0, 1); }
|
bool isU1Imm() const { return isImm(0, 1); }
|
||||||
bool isU2Imm() const { return isImm(0, 3); }
|
bool isU2Imm() const { return isImm(0, 3); }
|
||||||
|
@ -376,9 +391,10 @@ private:
|
||||||
|
|
||||||
OperandMatchResultTy parseAnyRegister(OperandVector &Operands);
|
OperandMatchResultTy parseAnyRegister(OperandVector &Operands);
|
||||||
|
|
||||||
bool parseAddress(unsigned &Base, const MCExpr *&Disp,
|
bool parseAddress(bool &HaveReg1, Register &Reg1,
|
||||||
unsigned &Index, bool &IsVector, const MCExpr *&Length,
|
bool &HaveReg2, Register &Reg2,
|
||||||
const unsigned *Regs, RegisterKind RegKind);
|
const MCExpr *&Disp, const MCExpr *&Length);
|
||||||
|
bool parseAddressRegister(Register &Reg);
|
||||||
|
|
||||||
bool ParseDirectiveInsn(SMLoc L);
|
bool ParseDirectiveInsn(SMLoc L);
|
||||||
|
|
||||||
|
@ -476,6 +492,9 @@ public:
|
||||||
OperandMatchResultTy parseBDLAddr64(OperandVector &Operands) {
|
OperandMatchResultTy parseBDLAddr64(OperandVector &Operands) {
|
||||||
return parseAddress(Operands, BDLMem, SystemZMC::GR64Regs, ADDR64Reg);
|
return parseAddress(Operands, BDLMem, SystemZMC::GR64Regs, ADDR64Reg);
|
||||||
}
|
}
|
||||||
|
OperandMatchResultTy parseBDRAddr64(OperandVector &Operands) {
|
||||||
|
return parseAddress(Operands, BDRMem, SystemZMC::GR64Regs, ADDR64Reg);
|
||||||
|
}
|
||||||
OperandMatchResultTy parseBDVAddr64(OperandVector &Operands) {
|
OperandMatchResultTy parseBDVAddr64(OperandVector &Operands) {
|
||||||
return parseAddress(Operands, BDVMem, SystemZMC::GR64Regs, ADDR64Reg);
|
return parseAddress(Operands, BDVMem, SystemZMC::GR64Regs, ADDR64Reg);
|
||||||
}
|
}
|
||||||
|
@ -712,58 +731,39 @@ SystemZAsmParser::parseAnyRegister(OperandVector &Operands) {
|
||||||
return MatchOperand_Success;
|
return MatchOperand_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a memory operand into Base, Disp, Index and Length.
|
// Parse a memory operand into Reg1, Reg2, Disp, and Length.
|
||||||
// Regs maps asm register numbers to LLVM register numbers and RegKind
|
bool SystemZAsmParser::parseAddress(bool &HaveReg1, Register &Reg1,
|
||||||
// says what kind of address register we're using (ADDR32Reg or ADDR64Reg).
|
bool &HaveReg2, Register &Reg2,
|
||||||
bool SystemZAsmParser::parseAddress(unsigned &Base, const MCExpr *&Disp,
|
const MCExpr *&Disp,
|
||||||
unsigned &Index, bool &IsVector,
|
const MCExpr *&Length) {
|
||||||
const MCExpr *&Length, const unsigned *Regs,
|
|
||||||
RegisterKind RegKind) {
|
|
||||||
// Parse the displacement, which must always be present.
|
// Parse the displacement, which must always be present.
|
||||||
if (getParser().parseExpression(Disp))
|
if (getParser().parseExpression(Disp))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Parse the optional base and index.
|
// Parse the optional base and index.
|
||||||
Index = 0;
|
HaveReg1 = false;
|
||||||
Base = 0;
|
HaveReg2 = false;
|
||||||
IsVector = false;
|
|
||||||
Length = nullptr;
|
Length = nullptr;
|
||||||
if (getLexer().is(AsmToken::LParen)) {
|
if (getLexer().is(AsmToken::LParen)) {
|
||||||
Parser.Lex();
|
Parser.Lex();
|
||||||
|
|
||||||
if (getLexer().is(AsmToken::Percent)) {
|
if (getLexer().is(AsmToken::Percent)) {
|
||||||
// Parse the first register and decide whether it's a base or an index.
|
// Parse the first register.
|
||||||
Register Reg;
|
HaveReg1 = true;
|
||||||
if (parseRegister(Reg))
|
if (parseRegister(Reg1))
|
||||||
return true;
|
return true;
|
||||||
if (Reg.Group == RegV) {
|
|
||||||
// A vector index register. The base register is optional.
|
|
||||||
IsVector = true;
|
|
||||||
Index = SystemZMC::VR128Regs[Reg.Num];
|
|
||||||
} else if (Reg.Group == RegGR) {
|
|
||||||
if (Reg.Num == 0)
|
|
||||||
return Error(Reg.StartLoc, "%r0 used in an address");
|
|
||||||
// If the are two registers, the first one is the index and the
|
|
||||||
// second is the base.
|
|
||||||
if (getLexer().is(AsmToken::Comma))
|
|
||||||
Index = Regs[Reg.Num];
|
|
||||||
else
|
|
||||||
Base = Regs[Reg.Num];
|
|
||||||
} else
|
|
||||||
return Error(Reg.StartLoc, "invalid address register");
|
|
||||||
} else {
|
} else {
|
||||||
// Parse the length.
|
// Parse the length.
|
||||||
if (getParser().parseExpression(Length))
|
if (getParser().parseExpression(Length))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether there's a second register. It's the base if so.
|
// Check whether there's a second register.
|
||||||
if (getLexer().is(AsmToken::Comma)) {
|
if (getLexer().is(AsmToken::Comma)) {
|
||||||
Parser.Lex();
|
Parser.Lex();
|
||||||
Register Reg;
|
HaveReg2 = true;
|
||||||
if (parseRegister(Reg, RegGR, Regs, RegKind))
|
if (parseRegister(Reg2))
|
||||||
return true;
|
return true;
|
||||||
Base = Reg.Num;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume the closing bracket.
|
// Consume the closing bracket.
|
||||||
|
@ -774,49 +774,141 @@ bool SystemZAsmParser::parseAddress(unsigned &Base, const MCExpr *&Disp,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that Reg is a valid address register (base or index).
|
||||||
|
bool
|
||||||
|
SystemZAsmParser::parseAddressRegister(Register &Reg) {
|
||||||
|
if (Reg.Group == RegV) {
|
||||||
|
Error(Reg.StartLoc, "invalid use of vector addressing");
|
||||||
|
return true;
|
||||||
|
} else if (Reg.Group != RegGR) {
|
||||||
|
Error(Reg.StartLoc, "invalid address register");
|
||||||
|
return true;
|
||||||
|
} else if (Reg.Num == 0) {
|
||||||
|
Error(Reg.StartLoc, "%r0 used in an address");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Parse a memory operand and add it to Operands. The other arguments
|
// Parse a memory operand and add it to Operands. The other arguments
|
||||||
// are as above.
|
// are as above.
|
||||||
SystemZAsmParser::OperandMatchResultTy
|
SystemZAsmParser::OperandMatchResultTy
|
||||||
SystemZAsmParser::parseAddress(OperandVector &Operands, MemoryKind MemKind,
|
SystemZAsmParser::parseAddress(OperandVector &Operands, MemoryKind MemKind,
|
||||||
const unsigned *Regs, RegisterKind RegKind) {
|
const unsigned *Regs, RegisterKind RegKind) {
|
||||||
SMLoc StartLoc = Parser.getTok().getLoc();
|
SMLoc StartLoc = Parser.getTok().getLoc();
|
||||||
unsigned Base, Index;
|
unsigned Base = 0, Index = 0, LengthReg = 0;
|
||||||
bool IsVector;
|
Register Reg1, Reg2;
|
||||||
|
bool HaveReg1, HaveReg2;
|
||||||
const MCExpr *Disp;
|
const MCExpr *Disp;
|
||||||
const MCExpr *Length;
|
const MCExpr *Length;
|
||||||
if (parseAddress(Base, Disp, Index, IsVector, Length, Regs, RegKind))
|
if (parseAddress(HaveReg1, Reg1, HaveReg2, Reg2, Disp, Length))
|
||||||
return MatchOperand_ParseFail;
|
return MatchOperand_ParseFail;
|
||||||
|
|
||||||
if (IsVector && MemKind != BDVMem) {
|
switch (MemKind) {
|
||||||
Error(StartLoc, "invalid use of vector addressing");
|
case BDMem:
|
||||||
return MatchOperand_ParseFail;
|
// If we have Reg1, it must be an address register.
|
||||||
}
|
if (HaveReg1) {
|
||||||
|
if (parseAddressRegister(Reg1))
|
||||||
if (!IsVector && MemKind == BDVMem) {
|
return MatchOperand_ParseFail;
|
||||||
Error(StartLoc, "vector index required in address");
|
Base = Regs[Reg1.Num];
|
||||||
return MatchOperand_ParseFail;
|
}
|
||||||
}
|
// There must be no Reg2 or length.
|
||||||
|
if (Length) {
|
||||||
if (Index && MemKind != BDXMem && MemKind != BDVMem) {
|
Error(StartLoc, "invalid use of length addressing");
|
||||||
Error(StartLoc, "invalid use of indexed addressing");
|
return MatchOperand_ParseFail;
|
||||||
return MatchOperand_ParseFail;
|
}
|
||||||
}
|
if (HaveReg2) {
|
||||||
|
Error(StartLoc, "invalid use of indexed addressing");
|
||||||
if (Length && MemKind != BDLMem) {
|
return MatchOperand_ParseFail;
|
||||||
Error(StartLoc, "invalid use of length addressing");
|
}
|
||||||
return MatchOperand_ParseFail;
|
break;
|
||||||
}
|
case BDXMem:
|
||||||
|
// If we have Reg1, it must be an address register.
|
||||||
if (!Length && MemKind == BDLMem) {
|
if (HaveReg1) {
|
||||||
Error(StartLoc, "missing length in address");
|
if (parseAddressRegister(Reg1))
|
||||||
return MatchOperand_ParseFail;
|
return MatchOperand_ParseFail;
|
||||||
|
// If the are two registers, the first one is the index and the
|
||||||
|
// second is the base.
|
||||||
|
if (HaveReg2)
|
||||||
|
Index = Regs[Reg1.Num];
|
||||||
|
else
|
||||||
|
Base = Regs[Reg1.Num];
|
||||||
|
}
|
||||||
|
// If we have Reg2, it must be an address register.
|
||||||
|
if (HaveReg2) {
|
||||||
|
if (parseAddressRegister(Reg2))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
Base = Regs[Reg2.Num];
|
||||||
|
}
|
||||||
|
// There must be no length.
|
||||||
|
if (Length) {
|
||||||
|
Error(StartLoc, "invalid use of length addressing");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BDLMem:
|
||||||
|
// If we have Reg2, it must be an address register.
|
||||||
|
if (HaveReg2) {
|
||||||
|
if (parseAddressRegister(Reg2))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
Base = Regs[Reg2.Num];
|
||||||
|
}
|
||||||
|
// We cannot support base+index addressing.
|
||||||
|
if (HaveReg1 && HaveReg2) {
|
||||||
|
Error(StartLoc, "invalid use of indexed addressing");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
// We must have a length.
|
||||||
|
if (!Length) {
|
||||||
|
Error(StartLoc, "missing length in address");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BDRMem:
|
||||||
|
// We must have Reg1, and it must be a GPR.
|
||||||
|
if (!HaveReg1 || Reg1.Group != RegGR) {
|
||||||
|
Error(StartLoc, "invalid operand for instruction");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
LengthReg = SystemZMC::GR64Regs[Reg1.Num];
|
||||||
|
// If we have Reg2, it must be an address register.
|
||||||
|
if (HaveReg2) {
|
||||||
|
if (parseAddressRegister(Reg2))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
Base = Regs[Reg2.Num];
|
||||||
|
}
|
||||||
|
// There must be no length.
|
||||||
|
if (Length) {
|
||||||
|
Error(StartLoc, "invalid use of length addressing");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BDVMem:
|
||||||
|
// We must have Reg1, and it must be a vector register.
|
||||||
|
if (!HaveReg1 || Reg1.Group != RegV) {
|
||||||
|
Error(StartLoc, "vector index required in address");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
Index = SystemZMC::VR128Regs[Reg1.Num];
|
||||||
|
// If we have Reg2, it must be an address register.
|
||||||
|
if (HaveReg2) {
|
||||||
|
if (parseAddressRegister(Reg2))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
Base = Regs[Reg2.Num];
|
||||||
|
}
|
||||||
|
// There must be no length.
|
||||||
|
if (Length) {
|
||||||
|
Error(StartLoc, "invalid use of length addressing");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMLoc EndLoc =
|
SMLoc EndLoc =
|
||||||
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
||||||
Operands.push_back(SystemZOperand::createMem(MemKind, RegKind, Base, Disp,
|
Operands.push_back(SystemZOperand::createMem(MemKind, RegKind, Base, Disp,
|
||||||
Index, Length, StartLoc,
|
Index, Length, LengthReg,
|
||||||
EndLoc));
|
StartLoc, EndLoc));
|
||||||
return MatchOperand_Success;
|
return MatchOperand_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1010,16 +1102,23 @@ bool SystemZAsmParser::parseOperand(OperandVector &Operands,
|
||||||
// real address operands should have used a context-dependent parse routine,
|
// real address operands should have used a context-dependent parse routine,
|
||||||
// so we treat any plain expression as an immediate.
|
// so we treat any plain expression as an immediate.
|
||||||
SMLoc StartLoc = Parser.getTok().getLoc();
|
SMLoc StartLoc = Parser.getTok().getLoc();
|
||||||
unsigned Base, Index;
|
Register Reg1, Reg2;
|
||||||
bool IsVector;
|
bool HaveReg1, HaveReg2;
|
||||||
const MCExpr *Expr, *Length;
|
const MCExpr *Expr;
|
||||||
if (parseAddress(Base, Expr, Index, IsVector, Length, SystemZMC::GR64Regs,
|
const MCExpr *Length;
|
||||||
ADDR64Reg))
|
if (parseAddress(HaveReg1, Reg1, HaveReg2, Reg2, Expr, Length))
|
||||||
return true;
|
return MatchOperand_ParseFail;
|
||||||
|
// If the register combination is not valid for any instruction, reject it.
|
||||||
|
// Otherwise, fall back to reporting an unrecognized instruction.
|
||||||
|
if (HaveReg1 && Reg1.Group != RegGR && Reg1.Group != RegV
|
||||||
|
&& parseAddressRegister(Reg1))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
if (HaveReg2 && parseAddressRegister(Reg2))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
|
||||||
SMLoc EndLoc =
|
SMLoc EndLoc =
|
||||||
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
||||||
if (Base || Index || Length)
|
if (HaveReg1 || HaveReg2 || Length)
|
||||||
Operands.push_back(SystemZOperand::createInvalid(StartLoc, EndLoc));
|
Operands.push_back(SystemZOperand::createInvalid(StartLoc, EndLoc));
|
||||||
else
|
else
|
||||||
Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc));
|
Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc));
|
||||||
|
|
|
@ -321,6 +321,18 @@ static DecodeStatus decodeBDLAddr12Len8Operand(MCInst &Inst, uint64_t Field,
|
||||||
return MCDisassembler::Success;
|
return MCDisassembler::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DecodeStatus decodeBDRAddr12Operand(MCInst &Inst, uint64_t Field,
|
||||||
|
const unsigned *Regs) {
|
||||||
|
uint64_t Length = Field >> 16;
|
||||||
|
uint64_t Base = (Field >> 12) & 0xf;
|
||||||
|
uint64_t Disp = Field & 0xfff;
|
||||||
|
assert(Length < 16 && "Invalid BDRAddr12");
|
||||||
|
Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
|
||||||
|
Inst.addOperand(MCOperand::createImm(Disp));
|
||||||
|
Inst.addOperand(MCOperand::createReg(Regs[Length]));
|
||||||
|
return MCDisassembler::Success;
|
||||||
|
}
|
||||||
|
|
||||||
static DecodeStatus decodeBDVAddr12Operand(MCInst &Inst, uint64_t Field,
|
static DecodeStatus decodeBDVAddr12Operand(MCInst &Inst, uint64_t Field,
|
||||||
const unsigned *Regs) {
|
const unsigned *Regs) {
|
||||||
uint64_t Index = Field >> 16;
|
uint64_t Index = Field >> 16;
|
||||||
|
@ -376,6 +388,13 @@ static DecodeStatus decodeBDLAddr64Disp12Len8Operand(MCInst &Inst,
|
||||||
return decodeBDLAddr12Len8Operand(Inst, Field, SystemZMC::GR64Regs);
|
return decodeBDLAddr12Len8Operand(Inst, Field, SystemZMC::GR64Regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DecodeStatus decodeBDRAddr64Disp12Operand(MCInst &Inst,
|
||||||
|
uint64_t Field,
|
||||||
|
uint64_t Address,
|
||||||
|
const void *Decoder) {
|
||||||
|
return decodeBDRAddr12Operand(Inst, Field, SystemZMC::GR64Regs);
|
||||||
|
}
|
||||||
|
|
||||||
static DecodeStatus decodeBDVAddr64Disp12Operand(MCInst &Inst, uint64_t Field,
|
static DecodeStatus decodeBDVAddr64Disp12Operand(MCInst &Inst, uint64_t Field,
|
||||||
uint64_t Address,
|
uint64_t Address,
|
||||||
const void *Decoder) {
|
const void *Decoder) {
|
||||||
|
|
|
@ -208,6 +208,17 @@ void SystemZInstPrinter::printBDLAddrOperand(const MCInst *MI, int OpNum,
|
||||||
O << ')';
|
O << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SystemZInstPrinter::printBDRAddrOperand(const MCInst *MI, int OpNum,
|
||||||
|
raw_ostream &O) {
|
||||||
|
unsigned Base = MI->getOperand(OpNum).getReg();
|
||||||
|
uint64_t Disp = MI->getOperand(OpNum + 1).getImm();
|
||||||
|
unsigned Length = MI->getOperand(OpNum + 2).getReg();
|
||||||
|
O << Disp << "(%" << getRegisterName(Length);
|
||||||
|
if (Base)
|
||||||
|
O << ",%" << getRegisterName(Base);
|
||||||
|
O << ')';
|
||||||
|
}
|
||||||
|
|
||||||
void SystemZInstPrinter::printBDVAddrOperand(const MCInst *MI, int OpNum,
|
void SystemZInstPrinter::printBDVAddrOperand(const MCInst *MI, int OpNum,
|
||||||
raw_ostream &O) {
|
raw_ostream &O) {
|
||||||
printAddress(MI->getOperand(OpNum).getReg(),
|
printAddress(MI->getOperand(OpNum).getReg(),
|
||||||
|
|
|
@ -48,6 +48,7 @@ private:
|
||||||
void printBDAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
void printBDAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||||
void printBDXAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
void printBDXAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||||
void printBDLAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
void printBDLAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||||
|
void printBDRAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||||
void printBDVAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
void printBDVAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||||
void printU1ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
void printU1ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||||
void printU2ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
void printU2ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||||
|
|
|
@ -72,6 +72,9 @@ private:
|
||||||
uint64_t getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
|
uint64_t getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
|
||||||
SmallVectorImpl<MCFixup> &Fixups,
|
SmallVectorImpl<MCFixup> &Fixups,
|
||||||
const MCSubtargetInfo &STI) const;
|
const MCSubtargetInfo &STI) const;
|
||||||
|
uint64_t getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum,
|
||||||
|
SmallVectorImpl<MCFixup> &Fixups,
|
||||||
|
const MCSubtargetInfo &STI) const;
|
||||||
uint64_t getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
|
uint64_t getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
|
||||||
SmallVectorImpl<MCFixup> &Fixups,
|
SmallVectorImpl<MCFixup> &Fixups,
|
||||||
const MCSubtargetInfo &STI) const;
|
const MCSubtargetInfo &STI) const;
|
||||||
|
@ -198,6 +201,17 @@ getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
|
||||||
return (Len << 16) | (Base << 12) | Disp;
|
return (Len << 16) | (Base << 12) | Disp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t SystemZMCCodeEmitter::
|
||||||
|
getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum,
|
||||||
|
SmallVectorImpl<MCFixup> &Fixups,
|
||||||
|
const MCSubtargetInfo &STI) const {
|
||||||
|
uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
|
||||||
|
uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
|
||||||
|
uint64_t Len = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
|
||||||
|
assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<4>(Len));
|
||||||
|
return (Len << 16) | (Base << 12) | Disp;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t SystemZMCCodeEmitter::
|
uint64_t SystemZMCCodeEmitter::
|
||||||
getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
|
getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
|
||||||
SmallVectorImpl<MCFixup> &Fixups,
|
SmallVectorImpl<MCFixup> &Fixups,
|
||||||
|
|
|
@ -588,14 +588,14 @@ class InstSSd<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||||
field bits<48> Inst;
|
field bits<48> Inst;
|
||||||
field bits<48> SoftFail = 0;
|
field bits<48> SoftFail = 0;
|
||||||
|
|
||||||
bits<20> XBD1;
|
bits<20> RBD1;
|
||||||
bits<16> BD2;
|
bits<16> BD2;
|
||||||
bits<4> R3;
|
bits<4> R3;
|
||||||
|
|
||||||
let Inst{47-40} = op;
|
let Inst{47-40} = op;
|
||||||
let Inst{39-36} = XBD1{19-16};
|
let Inst{39-36} = RBD1{19-16};
|
||||||
let Inst{35-32} = R3;
|
let Inst{35-32} = R3;
|
||||||
let Inst{31-16} = XBD1{15-0};
|
let Inst{31-16} = RBD1{15-0};
|
||||||
let Inst{15-0} = BD2;
|
let Inst{15-0} = BD2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1692,9 +1692,9 @@ let Defs = [CC] in {
|
||||||
|
|
||||||
let mayLoad = 1, mayStore = 1 in
|
let mayLoad = 1, mayStore = 1 in
|
||||||
def MVCK : InstSSd<0xD9, (outs),
|
def MVCK : InstSSd<0xD9, (outs),
|
||||||
(ins bdxaddr12only:$XBD1, bdaddr12only:$BD2,
|
(ins bdraddr12only:$RBD1, bdaddr12only:$BD2,
|
||||||
GR64:$R3),
|
GR64:$R3),
|
||||||
"mvck\t$XBD1, $BD2, $R3", []>;
|
"mvck\t$RBD1, $BD2, $R3", []>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mayStore = 1 in
|
let mayStore = 1 in
|
||||||
|
@ -1789,9 +1789,9 @@ let isCodeGenOnly = 1 in {
|
||||||
imm32zx16:$I2),
|
imm32zx16:$I2),
|
||||||
".insn sil,$enc,$BD1,$I2", []>;
|
".insn sil,$enc,$BD1,$I2", []>;
|
||||||
def InsnSS : DirectiveInsnSS<(outs),
|
def InsnSS : DirectiveInsnSS<(outs),
|
||||||
(ins imm64zx48:$enc, bdxaddr12only:$XBD1,
|
(ins imm64zx48:$enc, bdraddr12only:$RBD1,
|
||||||
bdaddr12only:$BD2, AnyReg:$R3),
|
bdaddr12only:$BD2, AnyReg:$R3),
|
||||||
".insn ss,$enc,$XBD1,$BD2,$R3", []>;
|
".insn ss,$enc,$RBD1,$BD2,$R3", []>;
|
||||||
def InsnSSE : DirectiveInsnSSE<(outs),
|
def InsnSSE : DirectiveInsnSSE<(outs),
|
||||||
(ins imm64zx48:$enc,
|
(ins imm64zx48:$enc,
|
||||||
bdaddr12only:$BD1,bdaddr12only:$BD2),
|
bdaddr12only:$BD1,bdaddr12only:$BD2),
|
||||||
|
|
|
@ -133,6 +133,13 @@ class BDLMode<string type, string bitsize, string dispsize, string suffix,
|
||||||
!cast<Immediate>("disp"##dispsize##"imm"##bitsize),
|
!cast<Immediate>("disp"##dispsize##"imm"##bitsize),
|
||||||
!cast<Immediate>("imm"##bitsize))>;
|
!cast<Immediate>("imm"##bitsize))>;
|
||||||
|
|
||||||
|
// A BDMode paired with a register length operand.
|
||||||
|
class BDRMode<string type, string bitsize, string dispsize, string suffix>
|
||||||
|
: AddressingMode<type, bitsize, dispsize, suffix, "", 3, "BDRAddr",
|
||||||
|
(ops !cast<RegisterOperand>("ADDR"##bitsize),
|
||||||
|
!cast<Immediate>("disp"##dispsize##"imm"##bitsize),
|
||||||
|
!cast<RegisterOperand>("GR"##bitsize))>;
|
||||||
|
|
||||||
// An addressing mode with a base, displacement and a vector index.
|
// An addressing mode with a base, displacement and a vector index.
|
||||||
class BDVMode<string bitsize, string dispsize>
|
class BDVMode<string bitsize, string dispsize>
|
||||||
: AddressOperand<bitsize, dispsize, "", "BDVAddr",
|
: AddressOperand<bitsize, dispsize, "", "BDVAddr",
|
||||||
|
@ -509,6 +516,7 @@ def BDAddr64Disp20 : AddressAsmOperand<"BDAddr", "64", "20">;
|
||||||
def BDXAddr64Disp12 : AddressAsmOperand<"BDXAddr", "64", "12">;
|
def BDXAddr64Disp12 : AddressAsmOperand<"BDXAddr", "64", "12">;
|
||||||
def BDXAddr64Disp20 : AddressAsmOperand<"BDXAddr", "64", "20">;
|
def BDXAddr64Disp20 : AddressAsmOperand<"BDXAddr", "64", "20">;
|
||||||
def BDLAddr64Disp12Len8 : AddressAsmOperand<"BDLAddr", "64", "12", "Len8">;
|
def BDLAddr64Disp12Len8 : AddressAsmOperand<"BDLAddr", "64", "12", "Len8">;
|
||||||
|
def BDRAddr64Disp12 : AddressAsmOperand<"BDRAddr", "64", "12">;
|
||||||
def BDVAddr64Disp12 : AddressAsmOperand<"BDVAddr", "64", "12">;
|
def BDVAddr64Disp12 : AddressAsmOperand<"BDVAddr", "64", "12">;
|
||||||
|
|
||||||
// DAG patterns and operands for addressing modes. Each mode has
|
// DAG patterns and operands for addressing modes. Each mode has
|
||||||
|
@ -555,6 +563,7 @@ def dynalloc12only : BDXMode<"DynAlloc", "64", "12", "Only">;
|
||||||
def laaddr12pair : BDXMode<"LAAddr", "64", "12", "Pair">;
|
def laaddr12pair : BDXMode<"LAAddr", "64", "12", "Pair">;
|
||||||
def laaddr20pair : BDXMode<"LAAddr", "64", "20", "Pair">;
|
def laaddr20pair : BDXMode<"LAAddr", "64", "20", "Pair">;
|
||||||
def bdladdr12onlylen8 : BDLMode<"BDLAddr", "64", "12", "Only", "8">;
|
def bdladdr12onlylen8 : BDLMode<"BDLAddr", "64", "12", "Only", "8">;
|
||||||
|
def bdraddr12only : BDRMode<"BDRAddr", "64", "12", "Only">;
|
||||||
def bdvaddr12only : BDVMode< "64", "12">;
|
def bdvaddr12only : BDVMode< "64", "12">;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -6523,22 +6523,22 @@
|
||||||
# CHECK: mvc 0(256,%r15), 0
|
# CHECK: mvc 0(256,%r15), 0
|
||||||
0xd2 0xff 0xf0 0x00 0x00 0x00
|
0xd2 0xff 0xf0 0x00 0x00 0x00
|
||||||
|
|
||||||
# CHECK: mvck 0, 0, %r0
|
# CHECK: mvck 0(%r0), 0, %r0
|
||||||
0xd9 0x00 0x00 0x00 0x00 0x00
|
0xd9 0x00 0x00 0x00 0x00 0x00
|
||||||
|
|
||||||
# CHECK: mvck 0, 4095, %r2
|
# CHECK: mvck 0(%r0), 4095, %r2
|
||||||
0xd9 0x02 0x00 0x00 0x0f 0xff
|
0xd9 0x02 0x00 0x00 0x0f 0xff
|
||||||
|
|
||||||
# CHECK: mvck 0, 0(%r1), %r2
|
# CHECK: mvck 0(%r0), 0(%r1), %r2
|
||||||
0xd9 0x02 0x00 0x00 0x10 0x00
|
0xd9 0x02 0x00 0x00 0x10 0x00
|
||||||
|
|
||||||
# CHECK: mvck 0, 0(%r15), %r2
|
# CHECK: mvck 0(%r0), 0(%r15), %r2
|
||||||
0xd9 0x02 0x00 0x00 0xf0 0x00
|
0xd9 0x02 0x00 0x00 0xf0 0x00
|
||||||
|
|
||||||
# CHECK: mvck 0(%r1), 4095(%r15), %r2
|
# CHECK: mvck 0(%r0,%r1), 4095(%r15), %r2
|
||||||
0xd9 0x02 0x10 0x00 0xff 0xff
|
0xd9 0x02 0x10 0x00 0xff 0xff
|
||||||
|
|
||||||
# CHECK: mvck 0(%r1), 0(%r15), %r2
|
# CHECK: mvck 0(%r0,%r1), 0(%r15), %r2
|
||||||
0xd9 0x02 0x10 0x00 0xf0 0x00
|
0xd9 0x02 0x10 0x00 0xf0 0x00
|
||||||
|
|
||||||
# CHECK: mvck 4095(%r15,%r1), 0(%r15), %r2
|
# CHECK: mvck 4095(%r15,%r1), 0(%r15), %r2
|
||||||
|
|
|
@ -2418,8 +2418,6 @@
|
||||||
|
|
||||||
#CHECK: error: invalid use of length addressing
|
#CHECK: error: invalid use of length addressing
|
||||||
#CHECK: mvck 0(%r1,%r1), 0(2,%r1), %r3
|
#CHECK: mvck 0(%r1,%r1), 0(2,%r1), %r3
|
||||||
#CHECK: error: %r0 used in an address
|
|
||||||
#CHECK: mvck 0(%r0,%r1), 0(%r1), %r3
|
|
||||||
#CHECK: error: invalid operand
|
#CHECK: error: invalid operand
|
||||||
#CHECK: mvck -1(%r1,%r1), 0(%r1), %r3
|
#CHECK: mvck -1(%r1,%r1), 0(%r1), %r3
|
||||||
#CHECK: error: invalid operand
|
#CHECK: error: invalid operand
|
||||||
|
@ -2438,7 +2436,6 @@
|
||||||
#CHECK: mvck 0(-), 0, %r3
|
#CHECK: mvck 0(-), 0, %r3
|
||||||
|
|
||||||
mvck 0(%r1,%r1), 0(2,%r1), %r3
|
mvck 0(%r1,%r1), 0(2,%r1), %r3
|
||||||
mvck 0(%r0,%r1), 0(%r1), %r3
|
|
||||||
mvck -1(%r1,%r1), 0(%r1), %r3
|
mvck -1(%r1,%r1), 0(%r1), %r3
|
||||||
mvck 4096(%r1,%r1), 0(%r1), %r3
|
mvck 4096(%r1,%r1), 0(%r1), %r3
|
||||||
mvck 0(%r1,%r1), -1(%r1), %r3
|
mvck 0(%r1,%r1), -1(%r1), %r3
|
||||||
|
|
|
@ -7752,12 +7752,13 @@
|
||||||
mvc 0(256,%r1), 0
|
mvc 0(256,%r1), 0
|
||||||
mvc 0(256,%r15), 0
|
mvc 0(256,%r15), 0
|
||||||
|
|
||||||
#CHECK: mvck 0(%r1), 0, %r3 # encoding: [0xd9,0x03,0x10,0x00,0x00,0x00]
|
#CHECK: mvck 0(%r0), 0, %r3 # encoding: [0xd9,0x03,0x00,0x00,0x00,0x00]
|
||||||
#CHECK: mvck 0(%r1), 0(%r1), %r3 # encoding: [0xd9,0x03,0x10,0x00,0x10,0x00]
|
#CHECK: mvck 0(%r1), 0, %r3 # encoding: [0xd9,0x13,0x00,0x00,0x00,0x00]
|
||||||
#CHECK: mvck 0(%r1), 0(%r15), %r3 # encoding: [0xd9,0x03,0x10,0x00,0xf0,0x00]
|
#CHECK: mvck 0(%r1), 0(%r1), %r3 # encoding: [0xd9,0x13,0x00,0x00,0x10,0x00]
|
||||||
#CHECK: mvck 0(%r1), 4095, %r3 # encoding: [0xd9,0x03,0x10,0x00,0x0f,0xff]
|
#CHECK: mvck 0(%r1), 0(%r15), %r3 # encoding: [0xd9,0x13,0x00,0x00,0xf0,0x00]
|
||||||
#CHECK: mvck 0(%r1), 4095(%r1), %r3 # encoding: [0xd9,0x03,0x10,0x00,0x1f,0xff]
|
#CHECK: mvck 0(%r1), 4095, %r3 # encoding: [0xd9,0x13,0x00,0x00,0x0f,0xff]
|
||||||
#CHECK: mvck 0(%r1), 4095(%r15), %r3 # encoding: [0xd9,0x03,0x10,0x00,0xff,0xff]
|
#CHECK: mvck 0(%r1), 4095(%r1), %r3 # encoding: [0xd9,0x13,0x00,0x00,0x1f,0xff]
|
||||||
|
#CHECK: mvck 0(%r1), 4095(%r15), %r3 # encoding: [0xd9,0x13,0x00,0x00,0xff,0xff]
|
||||||
#CHECK: mvck 0(%r2,%r1), 0, %r3 # encoding: [0xd9,0x23,0x10,0x00,0x00,0x00]
|
#CHECK: mvck 0(%r2,%r1), 0, %r3 # encoding: [0xd9,0x23,0x10,0x00,0x00,0x00]
|
||||||
#CHECK: mvck 0(%r2,%r15), 0, %r3 # encoding: [0xd9,0x23,0xf0,0x00,0x00,0x00]
|
#CHECK: mvck 0(%r2,%r15), 0, %r3 # encoding: [0xd9,0x23,0xf0,0x00,0x00,0x00]
|
||||||
#CHECK: mvck 4095(%r2,%r1), 0, %r3 # encoding: [0xd9,0x23,0x1f,0xff,0x00,0x00]
|
#CHECK: mvck 4095(%r2,%r1), 0, %r3 # encoding: [0xd9,0x23,0x1f,0xff,0x00,0x00]
|
||||||
|
@ -7765,6 +7766,7 @@
|
||||||
#CHECK: mvck 0(%r2,%r1), 0, %r3 # encoding: [0xd9,0x23,0x10,0x00,0x00,0x00]
|
#CHECK: mvck 0(%r2,%r1), 0, %r3 # encoding: [0xd9,0x23,0x10,0x00,0x00,0x00]
|
||||||
#CHECK: mvck 0(%r2,%r15), 0, %r3 # encoding: [0xd9,0x23,0xf0,0x00,0x00,0x00]
|
#CHECK: mvck 0(%r2,%r15), 0, %r3 # encoding: [0xd9,0x23,0xf0,0x00,0x00,0x00]
|
||||||
|
|
||||||
|
mvck 0(%r0), 0, %r3
|
||||||
mvck 0(%r1), 0, %r3
|
mvck 0(%r1), 0, %r3
|
||||||
mvck 0(%r1), 0(%r1), %r3
|
mvck 0(%r1), 0(%r1), %r3
|
||||||
mvck 0(%r1), 0(%r15), %r3
|
mvck 0(%r1), 0(%r15), %r3
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#CHECK: foo 100(200,%r1), 300
|
#CHECK: foo 100(200,%r1), 300
|
||||||
#CHECK: error: invalid address register
|
#CHECK: error: invalid address register
|
||||||
#CHECK: foo 100(%a0), 200
|
#CHECK: foo 100(%a0), 200
|
||||||
#CHECK: error: %r0 used in an address
|
#CHECK: error: invalid instruction
|
||||||
#CHECK: foo 100(%r0), 200
|
#CHECK: foo 100(%r0), 200
|
||||||
#CHECK: error: %r0 used in an address
|
#CHECK: error: %r0 used in an address
|
||||||
#CHECK: foo 100(%v1,%r0), 200
|
#CHECK: foo 100(%v1,%r0), 200
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
#CHECK: foo 100(%v0,%r1), 200
|
#CHECK: foo 100(%v0,%r1), 200
|
||||||
#CHECK: error: invalid instruction
|
#CHECK: error: invalid instruction
|
||||||
#CHECK: foo 100(%v31), 200
|
#CHECK: foo 100(%v31), 200
|
||||||
#CHECK: error: invalid operand
|
#CHECK: error: invalid address register
|
||||||
#CHECK: foo 100(%r1,%a0), 200
|
#CHECK: foo 100(%r1,%a0), 200
|
||||||
#CHECK: error: %r0 used in an address
|
#CHECK: error: %r0 used in an address
|
||||||
#CHECK: foo 100(%r1,%r0), 200
|
#CHECK: foo 100(%r1,%r0), 200
|
||||||
|
|
Loading…
Reference in New Issue