Skip to content

Commit

Permalink
[SystemZ] Fix encoding of MVCK and .insn ss
Browse files Browse the repository at this point in the history
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
  • Loading branch information
uweigand committed Oct 31, 2016
1 parent 3aa3118 commit b12a0a5
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 107 deletions.
265 changes: 182 additions & 83 deletions lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ enum MemoryKind {
BDMem,
BDXMem,
BDLMem,
BDRMem,
BDVMem
};

Expand Down Expand Up @@ -99,7 +100,10 @@ class SystemZOperand : public MCParsedAsmOperand {
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
Expand Down Expand Up @@ -164,15 +168,18 @@ class SystemZOperand : public MCParsedAsmOperand {
}
static std::unique_ptr<SystemZOperand>
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<SystemZOperand>(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<SystemZOperand>
Expand Down Expand Up @@ -249,14 +256,7 @@ class SystemZOperand : public MCParsedAsmOperand {
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.
Expand Down Expand Up @@ -297,7 +297,21 @@ class SystemZOperand : public MCParsedAsmOperand {
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");
Expand Down Expand Up @@ -331,6 +345,7 @@ class SystemZOperand : public MCParsedAsmOperand {
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); }
Expand Down Expand Up @@ -376,9 +391,10 @@ class SystemZAsmParser : public MCTargetAsmParser {

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);

Expand Down Expand Up @@ -476,6 +492,9 @@ class SystemZAsmParser : public MCTargetAsmParser {
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);
}
Expand Down Expand Up @@ -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.
Expand All @@ -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;
}

Expand Down Expand Up @@ -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));
Expand Down
Loading

0 comments on commit b12a0a5

Please sign in to comment.