diff options
author | Simon Tatham <simon.tatham@arm.com> | 2019-06-25 11:24:33 +0000 |
---|---|---|
committer | Simon Tatham <simon.tatham@arm.com> | 2019-06-25 11:24:33 +0000 |
commit | 86b7a1e660b55d0082a671282523fa30cc9bff6a (patch) | |
tree | 10381f792f5d4784c436ea499e24ed3a3fb0df3c /llvm/lib | |
parent | e6824160dd6f1edbeac8744a960ef7d3d2ae472a (diff) | |
download | bcm5719-llvm-86b7a1e660b55d0082a671282523fa30cc9bff6a.tar.gz bcm5719-llvm-86b7a1e660b55d0082a671282523fa30cc9bff6a.zip |
[ARM] Add remaining miscellaneous MVE instructions.
This final batch includes the tail-predicated versions of the
low-overhead loop instructions (LETP); the VPSEL instruction to select
between two vector registers based on the predicate mask without
having to open a VPT block; and VPNOT which complements the predicate
mask in place.
Reviewers: dmgreen, samparker, SjoerdMeijer, t.p.northover
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62681
llvm-svn: 364292
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Target/ARM/ARMInstrMVE.td | 103 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMInstrThumb2.td | 23 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 37 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp | 23 |
4 files changed, 164 insertions, 22 deletions
diff --git a/llvm/lib/Target/ARM/ARMInstrMVE.td b/llvm/lib/Target/ARM/ARMInstrMVE.td index e76e999ee52..2d37255bba8 100644 --- a/llvm/lib/Target/ARM/ARMInstrMVE.td +++ b/llvm/lib/Target/ARM/ARMInstrMVE.td @@ -3895,3 +3895,106 @@ def MVE_VPST : MVE_MI<(outs ), (ins vpt_mask:$Mk), NoItinerary, let Defs = [P0]; } + +def MVE_VPSEL : MVE_p<(outs MQPR:$Qd), (ins MQPR:$Qn, MQPR:$Qm), NoItinerary, + "vpsel", "", "$Qd, $Qn, $Qm", vpred_n, "", []> { + bits<4> Qn; + bits<4> Qd; + bits<4> Qm; + + let Inst{28} = 0b1; + let Inst{25-23} = 0b100; + let Inst{22} = Qd{3}; + let Inst{21-20} = 0b11; + let Inst{19-17} = Qn{2-0}; + let Inst{16} = 0b1; + let Inst{15-13} = Qd{2-0}; + let Inst{12-9} = 0b0111; + let Inst{8} = 0b1; + let Inst{7} = Qn{3}; + let Inst{6} = 0b0; + let Inst{5} = Qm{3}; + let Inst{4} = 0b0; + let Inst{3-1} = Qm{2-0}; + let Inst{0} = 0b1; +} + +foreach suffix = ["s8", "s16", "s32", "u8", "u16", "u32", + "i8", "i16", "i32", "f16", "f32"] in +def : MVEInstAlias<"vpsel${vp}." # suffix # "\t$Qd, $Qn, $Qm", + (MVE_VPSEL MQPR:$Qd, MQPR:$Qn, MQPR:$Qm, vpred_n:$vp)>; + +def MVE_VPNOT : MVE_p<(outs), (ins), NoItinerary, + "vpnot", "", "", vpred_n, "", []> { + let Inst{31-0} = 0b11111110001100010000111101001101; + let Unpredictable{19-17} = 0b111; + let Unpredictable{12} = 0b1; + let Unpredictable{7} = 0b1; + let Unpredictable{5} = 0b1; + let Defs = [P0]; + let Uses = [P0]; + + let Constraints = ""; +} + +class MVE_loltp_start<dag iops, string asm, string ops, bits<2> size> + : t2LOL<(outs GPRlr:$LR), iops, asm, ops> { + bits<4> Rn; + let Predicates = [HasMVEInt]; + let Inst{22} = 0b0; + let Inst{21-20} = size; + let Inst{19-16} = Rn{3-0}; + let Inst{12} = 0b0; +} + +class MVE_DLSTP<string asm, bits<2> size> + : MVE_loltp_start<(ins rGPR:$Rn), asm, "$LR, $Rn", size> { + let Inst{13} = 0b1; + let Inst{11-1} = 0b00000000000; + let Unpredictable{10-1} = 0b1111111111; +} + +class MVE_WLSTP<string asm, bits<2> size> + : MVE_loltp_start<(ins rGPR:$Rn, wlslabel_u11:$label), + asm, "$LR, $Rn, $label", size> { + bits<11> label; + let Inst{13} = 0b0; + let Inst{11} = label{0}; + let Inst{10-1} = label{10-1}; +} + +def MVE_DLSTP_8 : MVE_DLSTP<"dlstp.8", 0b00>; +def MVE_DLSTP_16 : MVE_DLSTP<"dlstp.16", 0b01>; +def MVE_DLSTP_32 : MVE_DLSTP<"dlstp.32", 0b10>; +def MVE_DLSTP_64 : MVE_DLSTP<"dlstp.64", 0b11>; + +def MVE_WLSTP_8 : MVE_WLSTP<"wlstp.8", 0b00>; +def MVE_WLSTP_16 : MVE_WLSTP<"wlstp.16", 0b01>; +def MVE_WLSTP_32 : MVE_WLSTP<"wlstp.32", 0b10>; +def MVE_WLSTP_64 : MVE_WLSTP<"wlstp.64", 0b11>; + +class MVE_loltp_end<dag oops, dag iops, string asm, string ops> + : t2LOL<oops, iops, asm, ops> { + let Predicates = [HasMVEInt]; + let Inst{22-21} = 0b00; + let Inst{19-16} = 0b1111; + let Inst{12} = 0b0; +} + +def MVE_LETP : MVE_loltp_end<(outs GPRlr:$LRout), + (ins GPRlr:$LRin, lelabel_u11:$label), + "letp", "$LRin, $label"> { + bits<11> label; + let Inst{20} = 0b1; + let Inst{13} = 0b0; + let Inst{11} = label{0}; + let Inst{10-1} = label{10-1}; +} + +def MVE_LCTP : MVE_loltp_end<(outs), (ins pred:$p), "lctp${p}", ""> { + let Inst{20} = 0b0; + let Inst{13} = 0b1; + let Inst{11-1} = 0b00000000000; + let Unpredictable{21-20} = 0b11; + let Unpredictable{11-1} = 0b11111111111; +} diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td index 594d2ab6b32..fa7d6913d42 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb2.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td @@ -372,8 +372,27 @@ def bflabel_u4 : BFLabelOp<"false", "false", "4", "ARM::fixup_bf_branch">; def bflabel_s12 : BFLabelOp<"true", "false", "12", "ARM::fixup_bfc_target">; def bflabel_s16 : BFLabelOp<"true", "false", "16", "ARM::fixup_bf_target">; def bflabel_s18 : BFLabelOp<"true", "false", "18", "ARM::fixup_bfl_target">; -def wlslabel_u11 : BFLabelOp<"false", "false", "11", "ARM::fixup_wls">; -def lelabel_u11 : BFLabelOp<"false", "true", "11", "ARM::fixup_le">; + +def wlslabel_u11_asmoperand : AsmOperandClass { + let Name = "WLSLabel"; + let RenderMethod = "addImmOperands"; + let PredicateMethod = "isUnsignedOffset<11, 1>"; + let DiagnosticString = + "loop end is out of range or not a positive multiple of 2"; +} +def wlslabel_u11 : BFLabelOp<"false", "false", "11", "ARM::fixup_wls"> { + let ParserMatchClass = wlslabel_u11_asmoperand; +} +def lelabel_u11_asmoperand : AsmOperandClass { + let Name = "LELabel"; + let RenderMethod = "addImmOperands"; + let PredicateMethod = "isLEOffset"; + let DiagnosticString = + "loop start is out of range or not a negative multiple of 2"; +} +def lelabel_u11 : BFLabelOp<"false", "true", "11", "ARM::fixup_le"> { + let ParserMatchClass = lelabel_u11_asmoperand; +} def bfafter_target : Operand<OtherVT> { let EncoderMethod = "getBFAfterTargetOpValue"; diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 40ed67b44bd..76734a6b13e 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -1013,6 +1013,18 @@ public: return false; } + // checks whether this operand is an offset suitable for the LE / + // LETP instructions in Arm v8.1M + bool isLEOffset() const { + if (!isImm()) return false; + if (isa<MCSymbolRefExpr>(Imm.Val)) return true; + if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) { + int64_t Val = CE->getValue(); + return Val < 0 && Val >= -4094 && (Val & 1) == 0; + } + return false; + } + // checks whether this operand is a memory operand computed as an offset // applied to PC. the offset may have 8 bits of magnitude and is represented // with two bits of shift. textually it may be either [pc, #imm], #imm or @@ -6213,6 +6225,7 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic, Mnemonic == "vmule" || Mnemonic == "vmult" || Mnemonic == "vrintne" || Mnemonic == "vcmult" || Mnemonic == "vcmule" || + Mnemonic == "vpsele" || Mnemonic == "vpselt" || Mnemonic.startswith("vq")))) { unsigned CC = ARMCondCodeFromString(Mnemonic.substr(Mnemonic.size()-2)); if (CC != ~0U) { @@ -6261,7 +6274,7 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic, Mnemonic != "vqrshrnt" && Mnemonic != "vqshrnt" && Mnemonic != "vmullt" && Mnemonic != "vqmovnt" && Mnemonic != "vqmovunt" && Mnemonic != "vqmovnt" && Mnemonic != "vmovnt" && Mnemonic != "vqdmullt" && - Mnemonic != "vcvtt" && Mnemonic != "vcvt") { + Mnemonic != "vpnot" && Mnemonic != "vcvtt" && Mnemonic != "vcvt") { unsigned CC = ARMVectorCondCodeFromString(Mnemonic.substr(Mnemonic.size()-1)); if (CC != ~0U) { Mnemonic = Mnemonic.slice(0, Mnemonic.size()-1); @@ -6337,7 +6350,9 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic, Mnemonic.startswith("vpt") || Mnemonic.startswith("vpst") || (hasMVE() && (Mnemonic.startswith("vst2") || Mnemonic.startswith("vld2") || - Mnemonic.startswith("vst4") || Mnemonic.startswith("vld4")))) { + Mnemonic.startswith("vst4") || Mnemonic.startswith("vld4") || + Mnemonic.startswith("wlstp") || Mnemonic.startswith("dlstp") || + Mnemonic.startswith("letp")))) { // These mnemonics are never predicable CanAcceptPredicationCode = false; } else if (!isThumb()) { @@ -6599,7 +6614,7 @@ bool ARMAsmParser::shouldOmitVectorPredicateOperand(StringRef Mnemonic, Mnemonic.startswith("vst2") || Mnemonic.startswith("vst4")) return true; - if (Mnemonic.startswith("vctp")) + if (Mnemonic.startswith("vctp") || Mnemonic.startswith("vpnot")) return false; if (Mnemonic.startswith("vmov") && @@ -7742,22 +7757,6 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, "code specified"); break; } - case ARM::t2WLS: { - int idx = Opcode == ARM::t2WLS ? 3 : 4; - if (!static_cast<ARMOperand &>(*Operands[idx]).isUnsignedOffset<11, 1>()) - return Error(Operands[idx]->getStartLoc(), - "loop end is out of range or not a positive multiple of 2"); - break; - } - case ARM::t2LEUpdate: { - if (Inst.getOperand(2).isImm() && - !(Inst.getOperand(2).getImm() < 0 && - Inst.getOperand(2).getImm() >= -4094 && - (Inst.getOperand(2).getImm() & 1) == 0)) - return Error(Operands[2]->getStartLoc(), - "loop start is out of range or not a negative multiple of 2"); - break; - } case ARM::t2BFi: case ARM::t2BFr: case ARM::t2BFLi: diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index dc5dedf9ae3..9e0a63da7df 100644 --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -5948,10 +5948,14 @@ static DecodeStatus DecodeLOLoop(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) { DecodeStatus S = MCDisassembler::Success; + if (Inst.getOpcode() == ARM::MVE_LCTP) + return S; + unsigned Imm = fieldFromInstruction(Insn, 11, 1) | fieldFromInstruction(Insn, 1, 10) << 1; switch (Inst.getOpcode()) { case ARM::t2LEUpdate: + case ARM::MVE_LETP: Inst.addOperand(MCOperand::createReg(ARM::LR)); Inst.addOperand(MCOperand::createReg(ARM::LR)); LLVM_FALLTHROUGH; @@ -5961,6 +5965,10 @@ static DecodeStatus DecodeLOLoop(MCInst &Inst, unsigned Insn, uint64_t Address, return MCDisassembler::Fail; break; case ARM::t2WLS: + case ARM::MVE_WLSTP_8: + case ARM::MVE_WLSTP_16: + case ARM::MVE_WLSTP_32: + case ARM::MVE_WLSTP_64: Inst.addOperand(MCOperand::createReg(ARM::LR)); if (!Check(S, DecoderGPRRegisterClass(Inst, fieldFromInstruction(Insn, 16, 4), @@ -5970,9 +5978,22 @@ static DecodeStatus DecodeLOLoop(MCInst &Inst, unsigned Insn, uint64_t Address, return MCDisassembler::Fail; break; case ARM::t2DLS: + case ARM::MVE_DLSTP_8: + case ARM::MVE_DLSTP_16: + case ARM::MVE_DLSTP_32: + case ARM::MVE_DLSTP_64: unsigned Rn = fieldFromInstruction(Insn, 16, 4); if (Rn == 0xF) { - return MCDisassembler::Fail; + // Enforce all the rest of the instruction bits in LCTP, which + // won't have been reliably checked based on LCTP's own tablegen + // record, because we came to this decode by a roundabout route. + uint32_t CanonicalLCTP = 0xF00FE001, SBZMask = 0x00300FFE; + if ((Insn & ~SBZMask) != CanonicalLCTP) + return MCDisassembler::Fail; // a mandatory bit is wrong: hard fail + if (Insn != CanonicalLCTP) + Check(S, MCDisassembler::SoftFail); // an SBZ bit is wrong: soft fail + + Inst.setOpcode(ARM::MVE_LCTP); } else { Inst.addOperand(MCOperand::createReg(ARM::LR)); if (!Check(S, DecoderGPRRegisterClass(Inst, |