mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[SystemZ] Add support for the .insn directive
Summary: Add support for the .insn directive. .insn is an s390 specific directive that allows encoding of an instruction instead of using a mnemonic. The motivating case is some code in node.js that requires support for the .insn directive. Reviewers: koriakin, uweigand Subscribers: koriakin, llvm-commits Differential Revision: https://reviews.llvm.org/D21809 llvm-svn: 278012
This commit is contained in:
parent
6aa81f4185
commit
d6608e9acc
@ -12,6 +12,7 @@
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstBuilder.h"
|
||||
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
||||
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
@ -322,6 +323,7 @@ public:
|
||||
bool isVR64() const { return isReg(VR64Reg); }
|
||||
bool isVF128() const { return false; }
|
||||
bool isVR128() const { return isReg(VR128Reg); }
|
||||
bool isAnyReg() const { return (isReg() || isImm(0, 15)); }
|
||||
bool isBDAddr32Disp12() const { return isMemDisp12(BDMem, ADDR32Reg); }
|
||||
bool isBDAddr32Disp20() const { return isMemDisp20(BDMem, ADDR32Reg); }
|
||||
bool isBDAddr64Disp12() const { return isMemDisp12(BDMem, ADDR64Reg); }
|
||||
@ -342,6 +344,7 @@ public:
|
||||
bool isS16Imm() const { return isImm(-32768, 32767); }
|
||||
bool isU32Imm() const { return isImm(0, (1LL << 32) - 1); }
|
||||
bool isS32Imm() const { return isImm(-(1LL << 31), (1LL << 31) - 1); }
|
||||
bool isU48Imm() const { return isImm(0, (1LL << 48) - 1); }
|
||||
};
|
||||
|
||||
class SystemZAsmParser : public MCTargetAsmParser {
|
||||
@ -371,10 +374,14 @@ private:
|
||||
RegisterGroup Group, const unsigned *Regs,
|
||||
RegisterKind Kind);
|
||||
|
||||
OperandMatchResultTy parseAnyRegister(OperandVector &Operands);
|
||||
|
||||
bool parseAddress(unsigned &Base, const MCExpr *&Disp,
|
||||
unsigned &Index, bool &IsVector, const MCExpr *&Length,
|
||||
const unsigned *Regs, RegisterKind RegKind);
|
||||
|
||||
bool ParseDirectiveInsn(SMLoc L);
|
||||
|
||||
OperandMatchResultTy parseAddress(OperandVector &Operands,
|
||||
MemoryKind MemKind, const unsigned *Regs,
|
||||
RegisterKind RegKind);
|
||||
@ -454,6 +461,9 @@ public:
|
||||
OperandMatchResultTy parseVR128(OperandVector &Operands) {
|
||||
return parseRegister(Operands, RegV, SystemZMC::VR128Regs, VR128Reg);
|
||||
}
|
||||
OperandMatchResultTy parseAnyReg(OperandVector &Operands) {
|
||||
return parseAnyRegister(Operands);
|
||||
}
|
||||
OperandMatchResultTy parseBDAddr32(OperandVector &Operands) {
|
||||
return parseAddress(Operands, BDMem, SystemZMC::GR32Regs, ADDR32Reg);
|
||||
}
|
||||
@ -490,6 +500,80 @@ public:
|
||||
#define GET_MATCHER_IMPLEMENTATION
|
||||
#include "SystemZGenAsmMatcher.inc"
|
||||
|
||||
// Used for the .insn directives; contains information needed to parse the
|
||||
// operands in the directive.
|
||||
struct InsnMatchEntry {
|
||||
StringRef Format;
|
||||
uint64_t Opcode;
|
||||
int32_t NumOperands;
|
||||
MatchClassKind OperandKinds[5];
|
||||
};
|
||||
|
||||
// For equal_range comparison.
|
||||
struct CompareInsn {
|
||||
bool operator() (const InsnMatchEntry &LHS, StringRef RHS) {
|
||||
return LHS.Format < RHS;
|
||||
}
|
||||
bool operator() (StringRef LHS, const InsnMatchEntry &RHS) {
|
||||
return LHS < RHS.Format;
|
||||
}
|
||||
};
|
||||
|
||||
// Table initializing information for parsing the .insn directive.
|
||||
static struct InsnMatchEntry InsnMatchTable[] = {
|
||||
/* Format, Opcode, NumOperands, OperandKinds */
|
||||
{ "e", SystemZ::InsnE, 1,
|
||||
{ MCK_U16Imm } },
|
||||
{ "ri", SystemZ::InsnRI, 3,
|
||||
{ MCK_U32Imm, MCK_AnyReg, MCK_S16Imm } },
|
||||
{ "rie", SystemZ::InsnRIE, 4,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_PCRel16 } },
|
||||
{ "ril", SystemZ::InsnRIL, 3,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_PCRel32 } },
|
||||
{ "rilu", SystemZ::InsnRILU, 3,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_U32Imm } },
|
||||
{ "ris", SystemZ::InsnRIS, 5,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_S8Imm, MCK_U4Imm, MCK_BDAddr64Disp12 } },
|
||||
{ "rr", SystemZ::InsnRR, 3,
|
||||
{ MCK_U16Imm, MCK_AnyReg, MCK_AnyReg } },
|
||||
{ "rre", SystemZ::InsnRRE, 3,
|
||||
{ MCK_U32Imm, MCK_AnyReg, MCK_AnyReg } },
|
||||
{ "rrf", SystemZ::InsnRRF, 5,
|
||||
{ MCK_U32Imm, MCK_AnyReg, MCK_AnyReg, MCK_AnyReg, MCK_U4Imm } },
|
||||
{ "rrs", SystemZ::InsnRRS, 5,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_U4Imm, MCK_BDAddr64Disp12 } },
|
||||
{ "rs", SystemZ::InsnRS, 4,
|
||||
{ MCK_U32Imm, MCK_AnyReg, MCK_AnyReg, MCK_BDAddr64Disp12 } },
|
||||
{ "rse", SystemZ::InsnRSE, 4,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_BDAddr64Disp12 } },
|
||||
{ "rsi", SystemZ::InsnRSI, 4,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_PCRel16 } },
|
||||
{ "rsy", SystemZ::InsnRSY, 4,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_BDAddr64Disp20 } },
|
||||
{ "rx", SystemZ::InsnRX, 3,
|
||||
{ MCK_U32Imm, MCK_AnyReg, MCK_BDXAddr64Disp12 } },
|
||||
{ "rxe", SystemZ::InsnRXE, 3,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_BDXAddr64Disp12 } },
|
||||
{ "rxf", SystemZ::InsnRXF, 4,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_BDXAddr64Disp12 } },
|
||||
{ "rxy", SystemZ::InsnRXY, 3,
|
||||
{ MCK_U48Imm, MCK_AnyReg, MCK_BDXAddr64Disp20 } },
|
||||
{ "s", SystemZ::InsnS, 2,
|
||||
{ MCK_U32Imm, MCK_BDAddr64Disp12 } },
|
||||
{ "si", SystemZ::InsnSI, 3,
|
||||
{ MCK_U32Imm, MCK_BDAddr64Disp12, MCK_S8Imm } },
|
||||
{ "sil", SystemZ::InsnSIL, 3,
|
||||
{ MCK_U48Imm, MCK_BDAddr64Disp12, MCK_U16Imm } },
|
||||
{ "siy", SystemZ::InsnSIY, 3,
|
||||
{ MCK_U48Imm, MCK_BDAddr64Disp20, MCK_U8Imm } },
|
||||
{ "ss", SystemZ::InsnSS, 4,
|
||||
{ MCK_U48Imm, MCK_BDXAddr64Disp12, MCK_BDAddr64Disp12, MCK_AnyReg } },
|
||||
{ "sse", SystemZ::InsnSSE, 3,
|
||||
{ MCK_U48Imm, MCK_BDAddr64Disp12, MCK_BDAddr64Disp12 } },
|
||||
{ "ssf", SystemZ::InsnSSF, 4,
|
||||
{ MCK_U48Imm, MCK_BDAddr64Disp12, MCK_BDAddr64Disp12, MCK_AnyReg } }
|
||||
};
|
||||
|
||||
void SystemZOperand::print(raw_ostream &OS) const {
|
||||
llvm_unreachable("Not implemented");
|
||||
}
|
||||
@ -572,6 +656,59 @@ SystemZAsmParser::parseRegister(OperandVector &Operands, RegisterGroup Group,
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
// Parse any type of register (including integers) and add it to Operands.
|
||||
SystemZAsmParser::OperandMatchResultTy
|
||||
SystemZAsmParser::parseAnyRegister(OperandVector &Operands) {
|
||||
// Handle integer values.
|
||||
if (Parser.getTok().is(AsmToken::Integer)) {
|
||||
const MCExpr *Register;
|
||||
SMLoc StartLoc = Parser.getTok().getLoc();
|
||||
if (Parser.parseExpression(Register))
|
||||
return MatchOperand_ParseFail;
|
||||
|
||||
if (auto *CE = dyn_cast<MCConstantExpr>(Register)) {
|
||||
int64_t Value = CE->getValue();
|
||||
if (Value < 0 || Value > 15) {
|
||||
Error(StartLoc, "invalid register");
|
||||
return MatchOperand_ParseFail;
|
||||
}
|
||||
}
|
||||
|
||||
SMLoc EndLoc =
|
||||
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
||||
|
||||
Operands.push_back(SystemZOperand::createImm(Register, StartLoc, EndLoc));
|
||||
}
|
||||
else {
|
||||
Register Reg;
|
||||
if (parseRegister(Reg))
|
||||
return MatchOperand_ParseFail;
|
||||
|
||||
// Map to the correct register kind.
|
||||
RegisterKind Kind;
|
||||
unsigned RegNo;
|
||||
if (Reg.Group == RegGR) {
|
||||
Kind = GR64Reg;
|
||||
RegNo = SystemZMC::GR64Regs[Reg.Num];
|
||||
}
|
||||
else if (Reg.Group == RegFP) {
|
||||
Kind = FP64Reg;
|
||||
RegNo = SystemZMC::FP64Regs[Reg.Num];
|
||||
}
|
||||
else if (Reg.Group == RegV) {
|
||||
Kind = VR128Reg;
|
||||
RegNo = SystemZMC::VR128Regs[Reg.Num];
|
||||
}
|
||||
else {
|
||||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
Operands.push_back(SystemZOperand::createReg(Kind, RegNo,
|
||||
Reg.StartLoc, Reg.EndLoc));
|
||||
}
|
||||
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).
|
||||
@ -681,9 +818,116 @@ SystemZAsmParser::parseAddress(OperandVector &Operands, MemoryKind MemKind,
|
||||
}
|
||||
|
||||
bool SystemZAsmParser::ParseDirective(AsmToken DirectiveID) {
|
||||
StringRef IDVal = DirectiveID.getIdentifier();
|
||||
|
||||
if (IDVal == ".insn")
|
||||
return ParseDirectiveInsn(DirectiveID.getLoc());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// ParseDirectiveInsn
|
||||
/// ::= .insn [ format, encoding, (operands (, operands)*) ]
|
||||
bool SystemZAsmParser::ParseDirectiveInsn(SMLoc L) {
|
||||
MCAsmParser &Parser = getParser();
|
||||
|
||||
// Expect instruction format as identifier.
|
||||
StringRef Format;
|
||||
SMLoc ErrorLoc = Parser.getTok().getLoc();
|
||||
if (Parser.parseIdentifier(Format))
|
||||
return Error(ErrorLoc, "expected instruction format");
|
||||
|
||||
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> Operands;
|
||||
|
||||
// Find entry for this format in InsnMatchTable.
|
||||
auto EntryRange =
|
||||
std::equal_range(std::begin(InsnMatchTable), std::end(InsnMatchTable),
|
||||
Format, CompareInsn());
|
||||
|
||||
// If first == second, couldn't find a match in the table.
|
||||
if (EntryRange.first == EntryRange.second)
|
||||
return Error(ErrorLoc, "unrecognized format");
|
||||
|
||||
struct InsnMatchEntry *Entry = EntryRange.first;
|
||||
|
||||
// Format should match from equal_range.
|
||||
assert(Entry->Format == Format);
|
||||
|
||||
// Parse the following operands using the table's information.
|
||||
for (int i = 0; i < Entry->NumOperands; i++) {
|
||||
MatchClassKind Kind = Entry->OperandKinds[i];
|
||||
|
||||
SMLoc StartLoc = Parser.getTok().getLoc();
|
||||
|
||||
// Always expect commas as separators for operands.
|
||||
if (getLexer().isNot(AsmToken::Comma))
|
||||
return Error(StartLoc, "unexpected token in directive");
|
||||
Lex();
|
||||
|
||||
// Parse operands.
|
||||
OperandMatchResultTy ResTy;
|
||||
if (Kind == MCK_AnyReg)
|
||||
ResTy = parseAnyReg(Operands);
|
||||
else if (Kind == MCK_BDXAddr64Disp12 || Kind == MCK_BDXAddr64Disp20)
|
||||
ResTy = parseBDXAddr64(Operands);
|
||||
else if (Kind == MCK_BDAddr64Disp12 || Kind == MCK_BDAddr64Disp20)
|
||||
ResTy = parseBDAddr64(Operands);
|
||||
else if (Kind == MCK_PCRel32)
|
||||
ResTy = parsePCRel32(Operands);
|
||||
else if (Kind == MCK_PCRel16)
|
||||
ResTy = parsePCRel16(Operands);
|
||||
else {
|
||||
// Only remaining operand kind is an immediate.
|
||||
const MCExpr *Expr;
|
||||
SMLoc StartLoc = Parser.getTok().getLoc();
|
||||
|
||||
// Expect immediate expression.
|
||||
if (Parser.parseExpression(Expr))
|
||||
return Error(StartLoc, "unexpected token in directive");
|
||||
|
||||
SMLoc EndLoc =
|
||||
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
||||
|
||||
Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc));
|
||||
ResTy = MatchOperand_Success;
|
||||
}
|
||||
|
||||
if (ResTy != MatchOperand_Success)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build the instruction with the parsed operands.
|
||||
MCInst Inst = MCInstBuilder(Entry->Opcode);
|
||||
|
||||
for (size_t i = 0; i < Operands.size(); i++) {
|
||||
MCParsedAsmOperand &Operand = *Operands[i];
|
||||
MatchClassKind Kind = Entry->OperandKinds[i];
|
||||
|
||||
// Verify operand.
|
||||
unsigned Res = validateOperandClass(Operand, Kind);
|
||||
if (Res != Match_Success)
|
||||
return Error(Operand.getStartLoc(), "unexpected operand type");
|
||||
|
||||
// Add operands to instruction.
|
||||
SystemZOperand &ZOperand = static_cast<SystemZOperand &>(Operand);
|
||||
if (ZOperand.isReg())
|
||||
ZOperand.addRegOperands(Inst, 1);
|
||||
else if (ZOperand.isMem(BDMem))
|
||||
ZOperand.addBDAddrOperands(Inst, 2);
|
||||
else if (ZOperand.isMem(BDXMem))
|
||||
ZOperand.addBDXAddrOperands(Inst, 3);
|
||||
else if (ZOperand.isImm())
|
||||
ZOperand.addImmOperands(Inst, 1);
|
||||
else
|
||||
llvm_unreachable("unexpected operand type");
|
||||
}
|
||||
|
||||
// Emit as a regular instruction.
|
||||
Parser.getStreamer().EmitInstruction(Inst, getSTI());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SystemZAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
|
||||
SMLoc &EndLoc) {
|
||||
Register Reg;
|
||||
|
@ -134,6 +134,11 @@ void SystemZInstPrinter::printU32ImmOperand(const MCInst *MI, int OpNum,
|
||||
printUImmOperand<32>(MI, OpNum, O);
|
||||
}
|
||||
|
||||
void SystemZInstPrinter::printU48ImmOperand(const MCInst *MI, int OpNum,
|
||||
raw_ostream &O) {
|
||||
printUImmOperand<48>(MI, OpNum, O);
|
||||
}
|
||||
|
||||
void SystemZInstPrinter::printAccessRegOperand(const MCInst *MI, int OpNum,
|
||||
raw_ostream &O) {
|
||||
uint64_t Value = MI->getOperand(OpNum).getImm();
|
||||
|
@ -61,6 +61,7 @@ private:
|
||||
void printU16ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printS32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printU32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printU48ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printPCRelOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printPCRelTLSOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printAccessRegOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
|
@ -1015,6 +1015,196 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
let Inst{7-0} = op{7-0};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction classes for .insn directives
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class DirectiveInsnE<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstE<0, outs, ins, asmstr, pattern> {
|
||||
bits<16> enc;
|
||||
|
||||
let Inst = enc;
|
||||
}
|
||||
|
||||
class DirectiveInsnRI<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRI<0, outs, ins, asmstr, pattern> {
|
||||
bits<32> enc;
|
||||
|
||||
let Inst{31-24} = enc{31-24};
|
||||
let Inst{19-16} = enc{19-16};
|
||||
}
|
||||
|
||||
class DirectiveInsnRIE<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRIEd<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnRIL<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRIL<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
string type;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{35-32} = enc{35-32};
|
||||
}
|
||||
|
||||
class DirectiveInsnRIS<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRIS<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnRR<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRR<0, outs, ins, asmstr, pattern> {
|
||||
bits<16> enc;
|
||||
|
||||
let Inst{15-8} = enc{15-8};
|
||||
}
|
||||
|
||||
class DirectiveInsnRRE<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRRE<0, outs, ins, asmstr, pattern> {
|
||||
bits<32> enc;
|
||||
|
||||
let Inst{31-16} = enc{31-16};
|
||||
}
|
||||
|
||||
class DirectiveInsnRRF<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRRF<0, outs, ins, asmstr, pattern> {
|
||||
bits<32> enc;
|
||||
|
||||
let Inst{31-16} = enc{31-16};
|
||||
}
|
||||
|
||||
class DirectiveInsnRRS<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRRS<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnRS<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRS<0, outs, ins, asmstr, pattern> {
|
||||
bits<32> enc;
|
||||
|
||||
let Inst{31-24} = enc{31-24};
|
||||
}
|
||||
|
||||
// RSE is like RSY except with a 12 bit displacement (instead of 20).
|
||||
class DirectiveInsnRSE<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRSY<6, outs, ins, asmstr, pattern> {
|
||||
bits <48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{31-16} = BD2{15-0};
|
||||
let Inst{15-8} = 0;
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnRSI<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRSI<0, outs, ins, asmstr, pattern> {
|
||||
bits<32> enc;
|
||||
|
||||
let Inst{31-24} = enc{31-24};
|
||||
}
|
||||
|
||||
class DirectiveInsnRSY<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRSY<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnRX<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRX<0, outs, ins, asmstr, pattern> {
|
||||
bits<32> enc;
|
||||
|
||||
let Inst{31-24} = enc{31-24};
|
||||
}
|
||||
|
||||
class DirectiveInsnRXE<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRXE<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let M3 = 0;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnRXF<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRXF<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnRXY<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstRXY<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnS<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstS<0, outs, ins, asmstr, pattern> {
|
||||
bits<32> enc;
|
||||
|
||||
let Inst{31-16} = enc{31-16};
|
||||
}
|
||||
|
||||
class DirectiveInsnSI<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstSI<0, outs, ins, asmstr, pattern> {
|
||||
bits<32> enc;
|
||||
|
||||
let Inst{31-24} = enc{31-24};
|
||||
}
|
||||
|
||||
class DirectiveInsnSIY<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstSIY<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{7-0} = enc{7-0};
|
||||
}
|
||||
|
||||
class DirectiveInsnSIL<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstSIL<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-32} = enc{47-32};
|
||||
}
|
||||
|
||||
class DirectiveInsnSS<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstSSd<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
}
|
||||
|
||||
class DirectiveInsnSSE<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstSSE<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-32} = enc{47-32};
|
||||
}
|
||||
|
||||
class DirectiveInsnSSF<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstSSF<0, outs, ins, asmstr, pattern> {
|
||||
bits<48> enc;
|
||||
|
||||
let Inst{47-40} = enc{47-40};
|
||||
let Inst{35-32} = enc{35-32};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction definitions with semantics
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1703,6 +1703,102 @@ let Defs = [R0D, R1D], mayLoad = 1 in
|
||||
(ins bdaddr12only:$BD1, bdaddr12only:$BD2, GR64:$R3),
|
||||
"ectg\t$BD1, $BD2, $R3", []>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// .insn directive instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
let isCodeGenOnly = 1 in {
|
||||
def InsnE : DirectiveInsnE<(outs), (ins imm64zx16:$enc), ".insn e,$enc", []>;
|
||||
def InsnRI : DirectiveInsnRI<(outs), (ins imm64zx32:$enc, AnyReg:$R1,
|
||||
imm32sx16:$I2),
|
||||
".insn ri,$enc,$R1,$I2", []>;
|
||||
def InsnRIE : DirectiveInsnRIE<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
|
||||
AnyReg:$R3, brtarget16:$I2),
|
||||
".insn rie,$enc,$R1,$R3,$I2", []>;
|
||||
def InsnRIL : DirectiveInsnRIL<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
|
||||
brtarget32:$I2),
|
||||
".insn ril,$enc,$R1,$I2", []>;
|
||||
def InsnRILU : DirectiveInsnRIL<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
|
||||
uimm32:$I2),
|
||||
".insn rilu,$enc,$R1,$I2", []>;
|
||||
def InsnRIS : DirectiveInsnRIS<(outs),
|
||||
(ins imm64zx48:$enc, AnyReg:$R1,
|
||||
imm32sx8:$I2, imm32zx4:$M3,
|
||||
bdaddr12only:$BD4),
|
||||
".insn ris,$enc,$R1,$I2,$M3,$BD4", []>;
|
||||
def InsnRR : DirectiveInsnRR<(outs),
|
||||
(ins imm64zx16:$enc, AnyReg:$R1, AnyReg:$R2),
|
||||
".insn rr,$enc,$R1,$R2", []>;
|
||||
def InsnRRE : DirectiveInsnRRE<(outs), (ins imm64zx32:$enc,
|
||||
AnyReg:$R1, AnyReg:$R2),
|
||||
".insn rre,$enc,$R1,$R2", []>;
|
||||
def InsnRRF : DirectiveInsnRRF<(outs),
|
||||
(ins imm64zx32:$enc, AnyReg:$R1, AnyReg:$R2,
|
||||
AnyReg:$R3, imm32zx4:$R4),
|
||||
".insn rrf,$enc,$R1,$R2,$R3,$R4", []>;
|
||||
def InsnRRS : DirectiveInsnRRS<(outs),
|
||||
(ins imm64zx48:$enc, AnyReg:$R1,
|
||||
AnyReg:$R2, imm32zx4:$M3,
|
||||
bdaddr12only:$BD4),
|
||||
".insn rrs,$enc,$R1,$R2,$M3,$BD4", []>;
|
||||
def InsnRS : DirectiveInsnRS<(outs),
|
||||
(ins imm64zx32:$enc, AnyReg:$R1,
|
||||
AnyReg:$R3, bdaddr12only:$BD2),
|
||||
".insn rs,$enc,$R1,$R3,$BD2", []>;
|
||||
def InsnRSE : DirectiveInsnRSE<(outs),
|
||||
(ins imm64zx48:$enc, AnyReg:$R1,
|
||||
AnyReg:$R3, bdaddr12only:$BD2),
|
||||
".insn rse,$enc,$R1,$R3,$BD2", []>;
|
||||
def InsnRSI : DirectiveInsnRSI<(outs),
|
||||
(ins imm64zx48:$enc, AnyReg:$R1,
|
||||
AnyReg:$R3, brtarget16:$RI2),
|
||||
".insn rsi,$enc,$R1,$R3,$RI2", []>;
|
||||
def InsnRSY : DirectiveInsnRSY<(outs),
|
||||
(ins imm64zx48:$enc, AnyReg:$R1,
|
||||
AnyReg:$R3, bdaddr20only:$BD2),
|
||||
".insn rsy,$enc,$R1,$R3,$BD2", []>;
|
||||
def InsnRX : DirectiveInsnRX<(outs), (ins imm64zx32:$enc, AnyReg:$R1,
|
||||
bdxaddr12only:$XBD2),
|
||||
".insn rx,$enc,$R1,$XBD2", []>;
|
||||
def InsnRXE : DirectiveInsnRXE<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
|
||||
bdxaddr12only:$XBD2),
|
||||
".insn rxe,$enc,$R1,$XBD2", []>;
|
||||
def InsnRXF : DirectiveInsnRXF<(outs),
|
||||
(ins imm64zx48:$enc, AnyReg:$R1,
|
||||
AnyReg:$R3, bdxaddr12only:$XBD2),
|
||||
".insn rxf,$enc,$R1,$R3,$XBD2", []>;
|
||||
def InsnRXY : DirectiveInsnRXY<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
|
||||
bdxaddr20only:$XBD2),
|
||||
".insn rxy,$enc,$R1,$XBD2", []>;
|
||||
def InsnS : DirectiveInsnS<(outs),
|
||||
(ins imm64zx32:$enc, bdaddr12only:$BD2),
|
||||
".insn s,$enc,$BD2", []>;
|
||||
def InsnSI : DirectiveInsnSI<(outs),
|
||||
(ins imm64zx32:$enc, bdaddr12only:$BD1,
|
||||
imm32sx8:$I2),
|
||||
".insn si,$enc,$BD1,$I2", []>;
|
||||
def InsnSIY : DirectiveInsnSIY<(outs),
|
||||
(ins imm64zx48:$enc,
|
||||
bdaddr20only:$BD1, imm32zx8:$I2),
|
||||
".insn siy,$enc,$BD1,$I2", []>;
|
||||
def InsnSIL : DirectiveInsnSIL<(outs),
|
||||
(ins imm64zx48:$enc, bdaddr12only:$BD1,
|
||||
imm32zx16:$I2),
|
||||
".insn sil,$enc,$BD1,$I2", []>;
|
||||
def InsnSS : DirectiveInsnSS<(outs),
|
||||
(ins imm64zx48:$enc, bdxaddr12only:$XBD1,
|
||||
bdaddr12only:$BD2, AnyReg:$R3),
|
||||
".insn ss,$enc,$XBD1,$BD2,$R3", []>;
|
||||
def InsnSSE : DirectiveInsnSSE<(outs),
|
||||
(ins imm64zx48:$enc,
|
||||
bdaddr12only:$BD1,bdaddr12only:$BD2),
|
||||
".insn sse,$enc,$BD1,$BD2", []>;
|
||||
def InsnSSF : DirectiveInsnSSF<(outs),
|
||||
(ins imm64zx48:$enc, bdaddr12only:$BD1,
|
||||
bdaddr12only:$BD2, AnyReg:$R3),
|
||||
".insn ssf,$enc,$BD1,$BD2,$R3", []>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Peepholes.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -230,6 +230,12 @@ def UIMM32 : SDNodeXForm<imm, [{
|
||||
MVT::i64);
|
||||
}]>;
|
||||
|
||||
// Truncate an immediate to a 48-bit unsigned quantity.
|
||||
def UIMM48 : SDNodeXForm<imm, [{
|
||||
return CurDAG->getTargetConstant(uint64_t(N->getZExtValue()) & 0xffffffffffff,
|
||||
SDLoc(N), MVT::i64);
|
||||
}]>;
|
||||
|
||||
// Negate and then truncate an immediate to a 32-bit unsigned quantity.
|
||||
def NEGIMM32 : SDNodeXForm<imm, [{
|
||||
return CurDAG->getTargetConstant(uint32_t(-N->getZExtValue()), SDLoc(N),
|
||||
@ -252,6 +258,7 @@ def S16Imm : ImmediateAsmOperand<"S16Imm">;
|
||||
def U16Imm : ImmediateAsmOperand<"U16Imm">;
|
||||
def S32Imm : ImmediateAsmOperand<"S32Imm">;
|
||||
def U32Imm : ImmediateAsmOperand<"U32Imm">;
|
||||
def U48Imm : ImmediateAsmOperand<"U48Imm">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// i32 immediates
|
||||
@ -425,6 +432,10 @@ def imm64zx32n : Immediate<i64, [{
|
||||
return isUInt<32>(-N->getSExtValue());
|
||||
}], NEGIMM32, "U32Imm">;
|
||||
|
||||
def imm64zx48 : Immediate<i64, [{
|
||||
return isUInt<64>(N->getZExtValue());
|
||||
}], UIMM48, "U48Imm">;
|
||||
|
||||
def imm64 : ImmLeaf<i64, [{}]>, Operand<i64>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -121,6 +121,14 @@ defm ADDR64 : SystemZRegClass<"ADDR64", [i64], 64, (sub GR64Bit, R0D)>;
|
||||
// of a GR128.
|
||||
defm ADDR128 : SystemZRegClass<"ADDR128", [untyped], 128, (sub GR128Bit, R0Q)>;
|
||||
|
||||
// Any type register. Used for .insn directives when we don't know what the
|
||||
// register types could be.
|
||||
defm AnyReg : SystemZRegClass<"AnyReg",
|
||||
[i64, f64, v8i8, v4i16, v2i32, v2f32], 64,
|
||||
(add (sequence "R%uD", 0, 15),
|
||||
(sequence "F%uD", 0, 15),
|
||||
(sequence "V%u", 0, 15))>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating-point registers
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
102
test/MC/SystemZ/directive-insn.s
Normal file
102
test/MC/SystemZ/directive-insn.s
Normal file
@ -0,0 +1,102 @@
|
||||
# RUN: llvm-mc -triple s390x-linux-gnu -filetype=obj %s | \
|
||||
# RUN: llvm-objdump -mcpu=zEC12 -disassemble - | FileCheck %s
|
||||
|
||||
# Test the .insn directive which provides a way of encoding an instruction
|
||||
# directly. It takes a format, encoding, and operands based on the format.
|
||||
|
||||
#CHECK: 01 01 pr
|
||||
.insn e,0x0101
|
||||
|
||||
#CHECK: a7 18 12 34 lhi %r1, 4660
|
||||
.insn ri,0xa7080000,%r1,0x1234
|
||||
|
||||
# GAS considers this instruction's immediate operand to be PC relative.
|
||||
#CHECK: ec 12 00 06 00 76 crj %r1, %r2, 0, 0x12
|
||||
.insn rie,0xec0000000076,%r1,%r2,12
|
||||
#CHECK: ec 12 00 03 00 64 cgrj %r1, %r2, 0, 0x12
|
||||
.insn rie,0xec0000000064,%r1,%r2,label.rie
|
||||
#CHECK: label.rie:
|
||||
label.rie:
|
||||
|
||||
# GAS considers this instruction's immediate operand to be PC relative.
|
||||
#CHECK: c6 1d 00 00 00 06 crl %r1, 0x1e
|
||||
.insn ril,0xc60d00000000,%r1,12
|
||||
#CHECK: c6 18 00 00 00 03 cgrl %r1, 0x1e
|
||||
.insn ril,0xc60800000000,%r1,label.ril
|
||||
#CHECK: label.ril:
|
||||
label.ril:
|
||||
|
||||
#CHECK: c2 2b 80 00 00 00 alfi %r2, 2147483648
|
||||
.insn rilu,0xc20b00000000,%r2,0x80000000
|
||||
|
||||
#CHECK: ec 1c f0 a0 34 fc cgible %r1, 52, 160(%r15)
|
||||
.insn ris,0xec00000000fc,%r1,0x34,0xc,160(%r15)
|
||||
|
||||
# Test using an integer in place of a register.
|
||||
#CHECK: 18 23 lr %r2, %r3
|
||||
.insn rr,0x1800,2,3
|
||||
|
||||
#CHECK: b9 14 00 45 lgfr %r4, %r5
|
||||
.insn rre,0xb9140000,%r4,%r5
|
||||
|
||||
# Test FP and GR registers in a single directive.
|
||||
#CHECK: b3 c1 00 fe ldgr %f15, %r14
|
||||
.insn rre,0xb3c10000,%f15,%r14
|
||||
|
||||
# Test using an integer in place of a register.
|
||||
#CHECK: b3 44 34 12 ledbra %f1, 3, %f2, 4
|
||||
.insn rrf,0xb3440000,%f1,2,%f3,4
|
||||
|
||||
#CHECK: ec 34 f0 b4 a0 e4 cgrbhe %r3, %r4, 180(%r15)
|
||||
.insn rrs,0xec00000000e4,%r3,%r4,0xa,180(%r15)
|
||||
|
||||
#CHECK: ba 01 f0 a0 cs %r0, %r1, 160(%r15)
|
||||
.insn rs,0xba000000,%r0,%r1,160(%r15)
|
||||
|
||||
# GAS considers this instruction's immediate operand to be PC relative.
|
||||
#CHECK: 84 13 00 04 brxh %r1, %r3, 0x4a
|
||||
.insn rsi,0x84000000,%r1,%r3,8
|
||||
#CHECK: 84 13 00 02 brxh %r1, %r3, 0x4a
|
||||
.insn rsi,0x84000000,%r1,%r3,label.rsi
|
||||
#CHECK: label.rsi:
|
||||
label.rsi:
|
||||
|
||||
# RSE formats are short displacement versions of the RSY formats.
|
||||
#CHECK: eb 12 f0 a0 00 f8 laa %r1, %r2, 160(%r15)
|
||||
.insn rse,0xeb00000000f8,%r1,%r2,160(%r15)
|
||||
|
||||
#CHECK: eb 12 f3 45 12 30 csg %r1, %r2, 74565(%r15)
|
||||
.insn rsy,0xeb0000000030,%r1,%r2,74565(%r15)
|
||||
|
||||
#CHECK: 59 13 f0 a0 c %r1, 160(%r3,%r15)
|
||||
.insn rx,0x59000000,%r1,160(%r3,%r15)
|
||||
|
||||
#CHECK: ed 13 f0 a0 00 19 cdb %f1, 160(%r3,%r15)
|
||||
.insn rxe,0xed0000000019,%f1,160(%r3,%r15)
|
||||
|
||||
#CHECK: ed 23 f0 a0 10 1e madb %f1, %f2, 160(%r3,%r15)
|
||||
.insn rxf,0xed000000001e,%f1,%f2,160(%r3,%r15)
|
||||
|
||||
#CHECK: ed 12 f1 23 90 65 ldy %f1, -458461(%r2,%r15)
|
||||
.insn rxy,0xed0000000065,%f1,-458461(%r2,%r15)
|
||||
|
||||
#CHECK: b2 fc f0 a0 tabort 160(%r15)
|
||||
.insn s,0xb2fc0000,160(%r15)
|
||||
|
||||
#CHECK: 91 34 f0 a0 tm 160(%r15), 52
|
||||
.insn si,0x91000000,160(%r15),52
|
||||
|
||||
#CHECK: eb f0 fc de ab 51 tmy -344866(%r15), 240
|
||||
.insn siy,0xeb0000000051,-344866(%r15),240
|
||||
|
||||
#CHECK: e5 60 f0 a0 12 34 tbegin 160(%r15), 4660
|
||||
.insn sil,0xe56000000000,160(%r15),0x1234
|
||||
|
||||
#CHECK: d9 13 f1 23 e4 56 mvck 291(%r1,%r15), 1110(%r14), %r3
|
||||
.insn ss,0xd90000000000,291(%r1,%r15),1110(%r14),%r3
|
||||
|
||||
#CHECK: e5 02 10 a0 21 23 strag 160(%r1), 291(%r2)
|
||||
.insn sse,0xe50200000000,160(%r1),291(%r2)
|
||||
|
||||
#CHECK: c8 31 f0 a0 e2 34 ectg 160(%r15), 564(%r14), %r3
|
||||
.insn ssf,0xc80100000000,160(%r15),564(%r14),%r3
|
Loading…
x
Reference in New Issue
Block a user