From b12a0a51d5887b7f0ed716d3c86b4e9dd154b8df Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Mon, 31 Oct 2016 14:21:36 +0000 Subject: [PATCH] [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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285574 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../SystemZ/AsmParser/SystemZAsmParser.cpp | 265 ++++++++++++------ .../Disassembler/SystemZDisassembler.cpp | 19 ++ .../InstPrinter/SystemZInstPrinter.cpp | 11 + .../SystemZ/InstPrinter/SystemZInstPrinter.h | 1 + .../MCTargetDesc/SystemZMCCodeEmitter.cpp | 14 + lib/Target/SystemZ/SystemZInstrFormats.td | 6 +- lib/Target/SystemZ/SystemZInstrInfo.td | 8 +- lib/Target/SystemZ/SystemZOperands.td | 9 + test/MC/Disassembler/SystemZ/insns.txt | 12 +- test/MC/SystemZ/insn-bad.s | 3 - test/MC/SystemZ/insn-good.s | 14 +- test/MC/SystemZ/tokens.s | 4 +- 12 files changed, 259 insertions(+), 107 deletions(-) diff --git a/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp index 5acb81d054e..457f76f3416 100644 --- a/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ b/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -50,6 +50,7 @@ enum MemoryKind { BDMem, BDXMem, BDLMem, + BDRMem, BDVMem }; @@ -99,7 +100,10 @@ private: unsigned MemKind : 4; unsigned RegKind : 4; 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 @@ -164,15 +168,18 @@ public: } static std::unique_ptr createMem(MemoryKind MemKind, RegisterKind RegKind, unsigned Base, - const MCExpr *Disp, unsigned Index, const MCExpr *Length, - SMLoc StartLoc, SMLoc EndLoc) { + const MCExpr *Disp, unsigned Index, const MCExpr *LengthImm, + unsigned LengthReg, SMLoc StartLoc, SMLoc EndLoc) { auto Op = make_unique(KindMem, StartLoc, EndLoc); Op->Mem.MemKind = MemKind; Op->Mem.RegKind = RegKind; Op->Mem.Base = Base; Op->Mem.Index = Index; 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; } static std::unique_ptr @@ -249,14 +256,7 @@ public: return isMem(MemKind, RegKind) && inRange(Mem.Disp, -524288, 524287); } bool isMemDisp12Len8(RegisterKind RegKind) const { - return isMemDisp12(BDLMem, RegKind) && inRange(Mem.Length, 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)); + return isMemDisp12(BDLMem, RegKind) && inRange(Mem.Length.Imm, 1, 0x100); } // Override MCParsedAsmOperand. @@ -297,7 +297,21 @@ public: assert(isMem(BDLMem) && "Invalid operand type"); Inst.addOperand(MCOperand::createReg(Mem.Base)); 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 { assert(N == 2 && "Invalid number of operands"); @@ -331,6 +345,7 @@ public: bool isBDXAddr64Disp12() const { return isMemDisp12(BDXMem, ADDR64Reg); } bool isBDXAddr64Disp20() const { return isMemDisp20(BDXMem, ADDR64Reg); } bool isBDLAddr64Disp12Len8() const { return isMemDisp12Len8(ADDR64Reg); } + bool isBDRAddr64Disp12() const { return isMemDisp12(BDRMem, ADDR64Reg); } bool isBDVAddr64Disp12() const { return isMemDisp12(BDVMem, ADDR64Reg); } bool isU1Imm() const { return isImm(0, 1); } bool isU2Imm() const { return isImm(0, 3); } @@ -376,9 +391,10 @@ private: OperandMatchResultTy parseAnyRegister(OperandVector &Operands); - bool parseAddress(unsigned &Base, const MCExpr *&Disp, - unsigned &Index, bool &IsVector, const MCExpr *&Length, - const unsigned *Regs, RegisterKind RegKind); + bool parseAddress(bool &HaveReg1, Register &Reg1, + bool &HaveReg2, Register &Reg2, + const MCExpr *&Disp, const MCExpr *&Length); + bool parseAddressRegister(Register &Reg); bool ParseDirectiveInsn(SMLoc L); @@ -476,6 +492,9 @@ public: OperandMatchResultTy parseBDLAddr64(OperandVector &Operands) { return parseAddress(Operands, BDLMem, SystemZMC::GR64Regs, ADDR64Reg); } + OperandMatchResultTy parseBDRAddr64(OperandVector &Operands) { + return parseAddress(Operands, BDRMem, SystemZMC::GR64Regs, ADDR64Reg); + } OperandMatchResultTy parseBDVAddr64(OperandVector &Operands) { return parseAddress(Operands, BDVMem, SystemZMC::GR64Regs, ADDR64Reg); } @@ -712,58 +731,39 @@ SystemZAsmParser::parseAnyRegister(OperandVector &Operands) { return MatchOperand_Success; } -// Parse a memory operand into Base, Disp, Index and Length. -// Regs maps asm register numbers to LLVM register numbers and RegKind -// says what kind of address register we're using (ADDR32Reg or ADDR64Reg). -bool SystemZAsmParser::parseAddress(unsigned &Base, const MCExpr *&Disp, - unsigned &Index, bool &IsVector, - const MCExpr *&Length, const unsigned *Regs, - RegisterKind RegKind) { +// Parse a memory operand into Reg1, Reg2, Disp, and Length. +bool SystemZAsmParser::parseAddress(bool &HaveReg1, Register &Reg1, + bool &HaveReg2, Register &Reg2, + const MCExpr *&Disp, + const MCExpr *&Length) { // Parse the displacement, which must always be present. if (getParser().parseExpression(Disp)) return true; // Parse the optional base and index. - Index = 0; - Base = 0; - IsVector = false; + HaveReg1 = false; + HaveReg2 = false; Length = nullptr; if (getLexer().is(AsmToken::LParen)) { Parser.Lex(); if (getLexer().is(AsmToken::Percent)) { - // Parse the first register and decide whether it's a base or an index. - Register Reg; - if (parseRegister(Reg)) + // Parse the first register. + HaveReg1 = true; + if (parseRegister(Reg1)) 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 { // Parse the length. if (getParser().parseExpression(Length)) 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)) { Parser.Lex(); - Register Reg; - if (parseRegister(Reg, RegGR, Regs, RegKind)) + HaveReg2 = true; + if (parseRegister(Reg2)) return true; - Base = Reg.Num; } // Consume the closing bracket. @@ -774,49 +774,141 @@ bool SystemZAsmParser::parseAddress(unsigned &Base, const MCExpr *&Disp, 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 // are as above. SystemZAsmParser::OperandMatchResultTy SystemZAsmParser::parseAddress(OperandVector &Operands, MemoryKind MemKind, const unsigned *Regs, RegisterKind RegKind) { SMLoc StartLoc = Parser.getTok().getLoc(); - unsigned Base, Index; - bool IsVector; + unsigned Base = 0, Index = 0, LengthReg = 0; + Register Reg1, Reg2; + bool HaveReg1, HaveReg2; const MCExpr *Disp; const MCExpr *Length; - if (parseAddress(Base, Disp, Index, IsVector, Length, Regs, RegKind)) + if (parseAddress(HaveReg1, Reg1, HaveReg2, Reg2, Disp, Length)) return MatchOperand_ParseFail; - if (IsVector && MemKind != BDVMem) { - Error(StartLoc, "invalid use of vector addressing"); - return MatchOperand_ParseFail; - } - - if (!IsVector && MemKind == BDVMem) { - Error(StartLoc, "vector index required in address"); - return MatchOperand_ParseFail; - } - - if (Index && MemKind != BDXMem && MemKind != BDVMem) { - Error(StartLoc, "invalid use of indexed addressing"); - return MatchOperand_ParseFail; - } - - if (Length && MemKind != BDLMem) { - Error(StartLoc, "invalid use of length addressing"); - return MatchOperand_ParseFail; - } - - if (!Length && MemKind == BDLMem) { - Error(StartLoc, "missing length in address"); - return MatchOperand_ParseFail; + switch (MemKind) { + case BDMem: + // If we have Reg1, it must be an address register. + if (HaveReg1) { + if (parseAddressRegister(Reg1)) + return MatchOperand_ParseFail; + Base = Regs[Reg1.Num]; + } + // There must be no Reg2 or length. + if (Length) { + Error(StartLoc, "invalid use of length addressing"); + return MatchOperand_ParseFail; + } + if (HaveReg2) { + Error(StartLoc, "invalid use of indexed addressing"); + return MatchOperand_ParseFail; + } + break; + case BDXMem: + // If we have Reg1, it must be an address register. + if (HaveReg1) { + if (parseAddressRegister(Reg1)) + 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::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(SystemZOperand::createMem(MemKind, RegKind, Base, Disp, - Index, Length, StartLoc, - EndLoc)); + Index, Length, LengthReg, + StartLoc, EndLoc)); return MatchOperand_Success; } @@ -1010,16 +1102,23 @@ bool SystemZAsmParser::parseOperand(OperandVector &Operands, // real address operands should have used a context-dependent parse routine, // so we treat any plain expression as an immediate. SMLoc StartLoc = Parser.getTok().getLoc(); - unsigned Base, Index; - bool IsVector; - const MCExpr *Expr, *Length; - if (parseAddress(Base, Expr, Index, IsVector, Length, SystemZMC::GR64Regs, - ADDR64Reg)) - return true; + Register Reg1, Reg2; + bool HaveReg1, HaveReg2; + const MCExpr *Expr; + const MCExpr *Length; + if (parseAddress(HaveReg1, Reg1, HaveReg2, Reg2, Expr, Length)) + 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::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - if (Base || Index || Length) + if (HaveReg1 || HaveReg2 || Length) Operands.push_back(SystemZOperand::createInvalid(StartLoc, EndLoc)); else Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc)); diff --git a/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp b/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp index c82302dbcb5..71b81cd26d7 100644 --- a/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp +++ b/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp @@ -321,6 +321,18 @@ static DecodeStatus decodeBDLAddr12Len8Operand(MCInst &Inst, uint64_t Field, 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, const unsigned *Regs) { uint64_t Index = Field >> 16; @@ -376,6 +388,13 @@ static DecodeStatus decodeBDLAddr64Disp12Len8Operand(MCInst &Inst, 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, uint64_t Address, const void *Decoder) { diff --git a/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp b/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp index 9cd5bda9e92..60ea7472159 100644 --- a/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp +++ b/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp @@ -208,6 +208,17 @@ void SystemZInstPrinter::printBDLAddrOperand(const MCInst *MI, int OpNum, 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, raw_ostream &O) { printAddress(MI->getOperand(OpNum).getReg(), diff --git a/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h b/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h index 05be5abc880..6c699093a08 100644 --- a/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h +++ b/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h @@ -48,6 +48,7 @@ private: void printBDAddrOperand(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 printBDRAddrOperand(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 printU2ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp index fd52a2ebf2f..936cfc6bce3 100644 --- a/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp @@ -72,6 +72,9 @@ private: uint64_t getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint64_t getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; uint64_t getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -198,6 +201,17 @@ getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum, return (Len << 16) | (Base << 12) | Disp; } +uint64_t SystemZMCCodeEmitter:: +getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &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:: getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, diff --git a/lib/Target/SystemZ/SystemZInstrFormats.td b/lib/Target/SystemZ/SystemZInstrFormats.td index 8d283a07b15..ad7a7cf7d94 100644 --- a/lib/Target/SystemZ/SystemZInstrFormats.td +++ b/lib/Target/SystemZ/SystemZInstrFormats.td @@ -588,14 +588,14 @@ class InstSSd op, dag outs, dag ins, string asmstr, list pattern> field bits<48> Inst; field bits<48> SoftFail = 0; - bits<20> XBD1; + bits<20> RBD1; bits<16> BD2; bits<4> R3; 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{31-16} = XBD1{15-0}; + let Inst{31-16} = RBD1{15-0}; let Inst{15-0} = BD2; } diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index e438013c7f2..7a966bad623 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -1692,9 +1692,9 @@ let Defs = [CC] in { let mayLoad = 1, mayStore = 1 in def MVCK : InstSSd<0xD9, (outs), - (ins bdxaddr12only:$XBD1, bdaddr12only:$BD2, + (ins bdraddr12only:$RBD1, bdaddr12only:$BD2, GR64:$R3), - "mvck\t$XBD1, $BD2, $R3", []>; + "mvck\t$RBD1, $BD2, $R3", []>; } let mayStore = 1 in @@ -1789,9 +1789,9 @@ let isCodeGenOnly = 1 in { imm32zx16:$I2), ".insn sil,$enc,$BD1,$I2", []>; def InsnSS : DirectiveInsnSS<(outs), - (ins imm64zx48:$enc, bdxaddr12only:$XBD1, + (ins imm64zx48:$enc, bdraddr12only:$RBD1, bdaddr12only:$BD2, AnyReg:$R3), - ".insn ss,$enc,$XBD1,$BD2,$R3", []>; + ".insn ss,$enc,$RBD1,$BD2,$R3", []>; def InsnSSE : DirectiveInsnSSE<(outs), (ins imm64zx48:$enc, bdaddr12only:$BD1,bdaddr12only:$BD2), diff --git a/lib/Target/SystemZ/SystemZOperands.td b/lib/Target/SystemZ/SystemZOperands.td index b3eccdc3385..442fbd6065a 100644 --- a/lib/Target/SystemZ/SystemZOperands.td +++ b/lib/Target/SystemZ/SystemZOperands.td @@ -133,6 +133,13 @@ class BDLMode("disp"##dispsize##"imm"##bitsize), !cast("imm"##bitsize))>; +// A BDMode paired with a register length operand. +class BDRMode + : AddressingMode("ADDR"##bitsize), + !cast("disp"##dispsize##"imm"##bitsize), + !cast("GR"##bitsize))>; + // An addressing mode with a base, displacement and a vector index. class BDVMode : AddressOperand; def BDXAddr64Disp12 : AddressAsmOperand<"BDXAddr", "64", "12">; def BDXAddr64Disp20 : AddressAsmOperand<"BDXAddr", "64", "20">; def BDLAddr64Disp12Len8 : AddressAsmOperand<"BDLAddr", "64", "12", "Len8">; +def BDRAddr64Disp12 : AddressAsmOperand<"BDRAddr", "64", "12">; def BDVAddr64Disp12 : AddressAsmOperand<"BDVAddr", "64", "12">; // 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 laaddr20pair : BDXMode<"LAAddr", "64", "20", "Pair">; def bdladdr12onlylen8 : BDLMode<"BDLAddr", "64", "12", "Only", "8">; +def bdraddr12only : BDRMode<"BDRAddr", "64", "12", "Only">; def bdvaddr12only : BDVMode< "64", "12">; //===----------------------------------------------------------------------===// diff --git a/test/MC/Disassembler/SystemZ/insns.txt b/test/MC/Disassembler/SystemZ/insns.txt index 20bf52a455b..6c6ac7bbd79 100644 --- a/test/MC/Disassembler/SystemZ/insns.txt +++ b/test/MC/Disassembler/SystemZ/insns.txt @@ -6523,22 +6523,22 @@ # CHECK: mvc 0(256,%r15), 0 0xd2 0xff 0xf0 0x00 0x00 0x00 -# CHECK: mvck 0, 0, %r0 +# CHECK: mvck 0(%r0), 0, %r0 0xd9 0x00 0x00 0x00 0x00 0x00 -# CHECK: mvck 0, 4095, %r2 +# CHECK: mvck 0(%r0), 4095, %r2 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 -# CHECK: mvck 0, 0(%r15), %r2 +# CHECK: mvck 0(%r0), 0(%r15), %r2 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 -# CHECK: mvck 0(%r1), 0(%r15), %r2 +# CHECK: mvck 0(%r0,%r1), 0(%r15), %r2 0xd9 0x02 0x10 0x00 0xf0 0x00 # CHECK: mvck 4095(%r15,%r1), 0(%r15), %r2 diff --git a/test/MC/SystemZ/insn-bad.s b/test/MC/SystemZ/insn-bad.s index ea6a47b0d5e..34c954a0a0c 100644 --- a/test/MC/SystemZ/insn-bad.s +++ b/test/MC/SystemZ/insn-bad.s @@ -2418,8 +2418,6 @@ #CHECK: error: invalid use of length addressing #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: mvck -1(%r1,%r1), 0(%r1), %r3 #CHECK: error: invalid operand @@ -2438,7 +2436,6 @@ #CHECK: mvck 0(-), 0, %r3 mvck 0(%r1,%r1), 0(2,%r1), %r3 - mvck 0(%r0,%r1), 0(%r1), %r3 mvck -1(%r1,%r1), 0(%r1), %r3 mvck 4096(%r1,%r1), 0(%r1), %r3 mvck 0(%r1,%r1), -1(%r1), %r3 diff --git a/test/MC/SystemZ/insn-good.s b/test/MC/SystemZ/insn-good.s index c0f3f8511dc..d747571ef1a 100644 --- a/test/MC/SystemZ/insn-good.s +++ b/test/MC/SystemZ/insn-good.s @@ -7752,12 +7752,13 @@ mvc 0(256,%r1), 0 mvc 0(256,%r15), 0 -#CHECK: mvck 0(%r1), 0, %r3 # encoding: [0xd9,0x03,0x10,0x00,0x00,0x00] -#CHECK: mvck 0(%r1), 0(%r1), %r3 # encoding: [0xd9,0x03,0x10,0x00,0x10,0x00] -#CHECK: mvck 0(%r1), 0(%r15), %r3 # encoding: [0xd9,0x03,0x10,0x00,0xf0,0x00] -#CHECK: mvck 0(%r1), 4095, %r3 # encoding: [0xd9,0x03,0x10,0x00,0x0f,0xff] -#CHECK: mvck 0(%r1), 4095(%r1), %r3 # encoding: [0xd9,0x03,0x10,0x00,0x1f,0xff] -#CHECK: mvck 0(%r1), 4095(%r15), %r3 # encoding: [0xd9,0x03,0x10,0x00,0xff,0xff] +#CHECK: mvck 0(%r0), 0, %r3 # encoding: [0xd9,0x03,0x00,0x00,0x00,0x00] +#CHECK: mvck 0(%r1), 0, %r3 # encoding: [0xd9,0x13,0x00,0x00,0x00,0x00] +#CHECK: mvck 0(%r1), 0(%r1), %r3 # encoding: [0xd9,0x13,0x00,0x00,0x10,0x00] +#CHECK: mvck 0(%r1), 0(%r15), %r3 # encoding: [0xd9,0x13,0x00,0x00,0xf0,0x00] +#CHECK: mvck 0(%r1), 4095, %r3 # encoding: [0xd9,0x13,0x00,0x00,0x0f,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,%r15), 0, %r3 # encoding: [0xd9,0x23,0xf0,0x00,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,%r15), 0, %r3 # encoding: [0xd9,0x23,0xf0,0x00,0x00,0x00] + mvck 0(%r0), 0, %r3 mvck 0(%r1), 0, %r3 mvck 0(%r1), 0(%r1), %r3 mvck 0(%r1), 0(%r15), %r3 diff --git a/test/MC/SystemZ/tokens.s b/test/MC/SystemZ/tokens.s index ceadcdb4b1d..7cea21a1e5c 100644 --- a/test/MC/SystemZ/tokens.s +++ b/test/MC/SystemZ/tokens.s @@ -15,7 +15,7 @@ #CHECK: foo 100(200,%r1), 300 #CHECK: error: invalid address register #CHECK: foo 100(%a0), 200 -#CHECK: error: %r0 used in an address +#CHECK: error: invalid instruction #CHECK: foo 100(%r0), 200 #CHECK: error: %r0 used in an address #CHECK: foo 100(%v1,%r0), 200 @@ -23,7 +23,7 @@ #CHECK: foo 100(%v0,%r1), 200 #CHECK: error: invalid instruction #CHECK: foo 100(%v31), 200 -#CHECK: error: invalid operand +#CHECK: error: invalid address register #CHECK: foo 100(%r1,%a0), 200 #CHECK: error: %r0 used in an address #CHECK: foo 100(%r1,%r0), 200