Index: lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp =================================================================== --- lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -16,6 +16,7 @@ #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; @@ -30,6 +31,43 @@ } namespace { + +// Used for .insn directives +enum InstrFormat { + InsnE, + InsnRI, + InsnRIE, + InsnRIL, + InsnRILU, + InsnRIS, + InsnRR, + InsnRRE, + InsnRRF, + InsnRRS, + InsnRS, + InsnRSE, + InsnRSI, + InsnRSY, + InsnRX, + InsnRXE, + InsnRXF, + InsnRXY, + InsnS, + InsnSI, + InsnSIY, + InsnSIL, + InsnSS, + InsnSSE, + InsnSSF, + InsnInvalid +}; + +enum OperandKind { + RegisterOperand, + ImmOperand, + AddrOperand +}; + enum RegisterKind { GR32Reg, GRH32Reg, @@ -375,6 +413,9 @@ unsigned &Index, bool &IsVector, const MCExpr *&Length, const unsigned *Regs, RegisterKind RegKind); + bool ParseDirectiveInsn(SMLoc L); + bool ParseDirectiveWord(unsigned Size, SMLoc L); + OperandMatchResultTy parseAddress(OperandVector &Operands, MemoryKind MemKind, const unsigned *Regs, RegisterKind RegKind); @@ -487,6 +528,180 @@ #define GET_MATCHER_IMPLEMENTATION #include "SystemZGenAsmMatcher.inc" +// Used for .insn asm directives. +// Contains information of this instruction format like expected operands, +// shift for the various operands, sizes, etc. +struct InstrInfoEntry { + InstrFormat Format; + unsigned NumOperands; + unsigned Size; + uint64_t Shift[5]; + OperandKind Operands[5]; +}; + +// Table defining values for each instruction format, including number and +// types of each expected operand, shift amounts, etc. +static const InstrInfoEntry InstrInfoTable[] = { + /* { InstrFormat, NumClasses, Size, Shift, Classes } */ + { InsnE, 0, 2, {}, {} }, + { InsnRI, 2, 4, { 20, 0 }, + { RegisterOperand, ImmOperand } }, + { InsnRIE, 3, 6, { 36, 32, 16 }, + { RegisterOperand, RegisterOperand, ImmOperand } }, + { InsnRIL, 2, 6, { 36, 0 }, + { RegisterOperand, ImmOperand } }, + { InsnRILU, 2, 6, { 36, 0 }, + { RegisterOperand, ImmOperand } }, + { InsnRIS, 4, 6, { 36, 8, 32 }, + { RegisterOperand, ImmOperand, ImmOperand, AddrOperand } }, + { InsnRR, 2, 2, { 4, 0 }, + { RegisterOperand, RegisterOperand } }, + { InsnRRE, 2, 4, { 4, 0 }, + { RegisterOperand, RegisterOperand } }, + { InsnRRF, 4, 4, { 4, 0, 12, 8 }, + { RegisterOperand, RegisterOperand, RegisterOperand, ImmOperand } }, + { InsnRRS, 4, 6, { 36, 32, 12, 0 }, + { RegisterOperand, RegisterOperand, ImmOperand, AddrOperand } }, + { InsnRS, 3, 4, { 20, 16, 0 }, + { RegisterOperand, RegisterOperand, AddrOperand } }, + { InsnRSE, 3, 6, { 36, 32, 0 }, + { RegisterOperand, RegisterOperand, AddrOperand } }, + { InsnRSI, 3, 6, { 36, 32, 0 }, + { RegisterOperand, RegisterOperand, ImmOperand } }, + { InsnRSY, 3, 6, { 36, 32, 0 }, + { RegisterOperand, RegisterOperand, AddrOperand } }, + { InsnRX, 2, 4, { 20, 0 }, + { RegisterOperand, AddrOperand } }, + { InsnRXE, 2, 6, { 36, 0 }, + { RegisterOperand, AddrOperand } }, + { InsnRXF, 3, 6, { 12, 36, 0 }, + { RegisterOperand, RegisterOperand, AddrOperand } }, + { InsnRXY, 2, 6, { 36, 0 }, + { RegisterOperand, AddrOperand } }, + { InsnS, 1, 4, { }, + { AddrOperand } }, + { InsnSI, 2, 4, { 0, 16 }, + { AddrOperand, ImmOperand } }, + { InsnSIY, 2, 6, { 0, 32 }, + { AddrOperand, ImmOperand } }, + { InsnSIL, 2, 6, { 0, 0 }, + { AddrOperand, ImmOperand } }, + { InsnSS, 3, 6, { 0, 0, 32 }, + { AddrOperand, RegisterOperand } }, + { InsnSSE, 2, 6, { 0, 0 }, + { AddrOperand } }, + { InsnSSF, 3, 6, { 0, 0, 36 }, + { AddrOperand, RegisterOperand } } +}; + +static InstrFormat getFormatFromType(StringRef Type) { + return StringSwitch(Type.lower()) + .Case("e", InsnE) + .Case("ri", InsnRI) + .Case("rie", InsnRIE) + .Case("ril", InsnRIL) + .Case("rilu", InsnRIL) + .Case("ris", InsnRIS) + .Case("rr", InsnRR) + .Case("rre", InsnRRE) + .Case("rrf", InsnRRF) + .Case("rrs", InsnRRS) + .Case("rs", InsnRS) + .Case("rse", InsnRSE) + .Case("rsi", InsnRSI) + .Case("rsy", InsnRSY) + .Case("rx", InsnRX) + .Case("rxe", InsnRXE) + .Case("rxf", InsnRXF) + .Case("rxy", InsnRXY) + .Case("s", InsnS) + .Case("si", InsnSI) + .Case("siy", InsnSIY) + .Case("sil", InsnSIL) + .Case("ss", InsnSS) + .Case("sse", InsnSSE) + .Case("ssf", InsnSSF) + .Default(InsnInvalid); +} + +// Used to encode the operands for .insn asm directives. +static bool encodeAddress(MCContext &Ctx, int64_t &Encoding, InstrFormat Format, + unsigned Base, unsigned Index, const MCExpr *Expr, + unsigned Operand) { + int64_t BaseReg = Ctx.getRegisterInfo()->getEncodingValue(Base); + int64_t IndexReg = Ctx.getRegisterInfo()->getEncodingValue(Index); + const auto *DispValue = dyn_cast(Expr); + int64_t Disp = DispValue->getValue(); + + switch (Format) { + case InsnRIS: + case InsnRRS: + case InsnRSE: + case InsnSIL: + Encoding |= (BaseReg << 28); + Encoding |= (Disp << 16); + break; + case InsnRS: + case InsnS: + case InsnSI: + Encoding |= (BaseReg << 12); + Encoding |= Disp; + break; + case InsnRSY: + case InsnSIY: + Encoding |= (BaseReg << 28); + Encoding |= ((Disp & 0xfff) << 16); + Encoding |= ((Disp & 0xff000) >> 4); + break; + case InsnRX: + Encoding |= (IndexReg << 16); + Encoding |= (BaseReg << 12); + Encoding |= Disp; + break; + case InsnRXE: + case InsnRXF: + Encoding |= (IndexReg << 32); + Encoding |= (BaseReg << 28); + Encoding |= (Disp << 16); + break; + case InsnRXY: + Encoding |= (IndexReg << 32); + Encoding |= (BaseReg << 28); + Encoding |= ((Disp & 0xfff) << 16); + Encoding |= ((Disp & 0xff000) >> 4); + break; + case InsnSS: + if (Operand == 0) { + Encoding |= (IndexReg << 36); + Encoding |= (BaseReg << 28); + Encoding |= (Disp << 16); + } + else if (Operand == 1) { + Encoding |= (BaseReg << 12); + Encoding |= Disp; + } + break; + case InsnSSE: + case InsnSSF: + if (Operand == 0) { + Encoding |= (BaseReg << 28); + Encoding |= (Disp << 16); + } + else if (Operand == 1) { + Encoding |= (BaseReg << 12); + Encoding |= Disp; + } + break; + default: + // The other formats don't have address operands. + assert(false && "Invalid address operand"); + return true; + break; + } + + return false; +} + void SystemZOperand::print(raw_ostream &OS) const { llvm_unreachable("Not implemented"); } @@ -678,9 +893,116 @@ } bool SystemZAsmParser::ParseDirective(AsmToken DirectiveID) { + StringRef IDVal = DirectiveID.getIdentifier(); + + if (IDVal == ".insn") + return ParseDirectiveInsn(DirectiveID.getLoc()); + else if (IDVal == ".short" || IDVal == ".word") + return ParseDirectiveWord(2, DirectiveID.getLoc()); + else if (IDVal == ".long") + return ParseDirectiveWord(4, DirectiveID.getLoc()); + else if (IDVal == ".quad") + return ParseDirectiveWord(8, DirectiveID.getLoc()); + return true; } +/// ParseDirectiveWord +/// ::= .word [ expression (, expression)* ] +bool SystemZAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { + MCAsmParser &Parser = getParser(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + const MCExpr *Value; + if (Parser.parseExpression(Value)) + return true; + + Parser.getStreamer().EmitValue(Value, Size, L); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().is(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Parser.Lex(); + } + } + return false; +} + +/// ParseDirectiveInsn +/// ::= .insn [ insn-type, encoding (, operands)* ] +bool SystemZAsmParser::ParseDirectiveInsn(SMLoc L) { + MCAsmParser &Parser = getParser(); + + // Expect instruction type as identifier. + StringRef Type; + if (Parser.parseIdentifier(Type)) + return TokError("expected instruction format in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + // Expect the encoding as the next operand. + int64_t Encoding; + if (Parser.parseAbsoluteExpression(Encoding)) + return true; + + // Get the instruction format and the entry in the table. + // This is used to understand how to parse and encode the following + // operands in the directive. + InstrFormat Format = getFormatFromType(Type); + struct InstrInfoEntry Entry = InstrInfoTable[Format]; + + // Parse the operands, based on the expected operand types in this + // instruction format. + for (uint32_t i = 0; i < Entry.NumOperands; i++) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + OperandKind Kind = Entry.Operands[i]; + int64_t Shift = Entry.Shift[i]; + + if (Kind == RegisterOperand) { + unsigned int Reg; + SMLoc StartLoc, EndLoc; + if (ParseRegister(Reg, StartLoc, EndLoc)) + return Error(L, "error parsing register"); + + // Encode the register. + int64_t RegNum = getContext().getRegisterInfo()->getEncodingValue(Reg); + Encoding |= (RegNum << Shift); + } + else if (Kind == AddrOperand) { + unsigned Base, Index; + bool IsVector; + const MCExpr *Expr, *Length; + if (parseAddress(Base, Expr, Index, IsVector, Length, + SystemZMC::GR64Regs, ADDR64Reg)) + return Error(L, "error parsing address"); + + // Call helper routine to encode this address. + encodeAddress(getContext(), Encoding, Format, Base, Index, Expr, i); + } + else if (Kind == ImmOperand) { + int64_t Imm; + if (Parser.parseAbsoluteExpression(Imm)) + return Error(L, "error parsing immediate"); + + // Encode the immediate value. + Encoding |= (Imm << Shift); + } + } + + // Emit the encoded value as an integer. + Parser.getStreamer().EmitIntValue(Encoding, Entry.Size); + + return false; +} + bool SystemZAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { Register Reg; Index: test/MC/SystemZ/directive-insn.s =================================================================== --- /dev/null +++ test/MC/SystemZ/directive-insn.s @@ -0,0 +1,56 @@ +# RUN: llvm-mc -triple s390x-linux-gnu -filetype=obj %s | \ +# RUN: llvm-objdump -mcpu=zEC12 -disassemble - | FileCheck %s + +# TODO: No recognized E, RIE, RRF, SS, SSE, SSF, RSE, RSI instructions. + +#CHECK: a7 18 12 34 lhi %r1, 4660 + .insn ri,0xa7080000,%r1,0x1234 + +#CHECK: c2 19 ab cd ef 01 afi %r1, -1412567295 + .insn ril,0xc20900000000,%r1,0xabcdef01 + +#CHECK: c2 2b ab cd ef 01 alfi %r2, 2882400001 + .insn rilu,0xc20b00000000,%r2,0xabcdef01 + +#CHECK: ec 1c f0 a0 34 fc cgible %r1, 52, 160(%r15) + .insn ris,0xec00000000fc,%r1,0x34,0xc,160(%r15) + +#CHECK: 18 23 lr %r2, %r3 + .insn rr,0x1800,%r2,%r3 + +#CHECK: b9 14 00 45 lgfr %r4, %r5 + .insn rre,0xb9140000,%r4,%r5 + +#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) + +#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 ac f0 a0 tm 160(%r15), 172 + .insn si,0x91000000,160(%r15),172 + +#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 + Index: test/MC/SystemZ/directive-word.s =================================================================== --- /dev/null +++ test/MC/SystemZ/directive-word.s @@ -0,0 +1,90 @@ +# RUN: llvm-mc -triple s390x-linux-gnu -filetype=obj %s | \ +# RUN: llvm-readobj -s -sd | FileCheck %s + +.section word, "aw" +.word 0xabcd + +# CHECK: Section { +# CHECK: Name: word +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 2 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: ABCD +# CHECK-NEXT: ) +# CHECK-NEXT: } + +.section short, "aw" +.short 0xef01 + +# CHECK: Section { +# CHECK: Name: short +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 2 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: EF01 +# CHECK-NEXT: ) +# CHECK-NEXT: } + +.section long, "aw" +.long 0xdeadbeef + +# CHECK: Section { +# CHECK: Name: long +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 4 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: DEADBEEF +# CHECK-NEXT: ) +# CHECK-NEXT: } + +.section quad, "aw" +.quad 0x1234567890abcdef + +# CHECK: Section { +# CHECK: Name: quad +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 12345678 90ABCDEF +# CHECK-NEXT: ) +# CHECK-NEXT: }