llvm.org GIT mirror llvm / a93c9e0
[ARM] Add MVE 64-bit GPR <-> vector move instructions. These instructions let you load half a vector register at once from two general-purpose registers, or vice versa. The assembly syntax for these instructions mentions the vector register name twice. For the move _into_ a vector register, the MC operand list also has to mention the register name twice (once as the output, and once as an input to represent where the unchanged half of the output register comes from). So we can conveniently assign one of the two asm operands to be the output $Qd, and the other $QdSrc, which avoids confusing the auto-generated AsmMatcher too much. For the move _from_ a vector register, there's no way to get round the fact that both instances of that register name have to be inputs, so we need a custom AsmMatchConverter to avoid generating two separate output MC operands. (And even that wouldn't have worked if it hadn't been for D60695.) Reviewers: dmgreen, samparker, SjoerdMeijer, t.p.northover Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62679 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@364041 91177308-0d34-0410-b5e6-96231b3b80d8 Simon Tatham 1 year, 1 month ago
7 changed file(s) with 261 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
472472 let EncoderMethod = "getPowerTwoOpValue";
473473 let DecoderMethod = "DecodePowerTwoOperand<0,3>";
474474 let ParserMatchClass = MVE_VIDUP_imm_asmoperand;
475 }
476
477 // Pair vector indexing
478 class MVEPairVectorIndexOperand : AsmOperandClass {
479 let Name = "MVEPairVectorIndex"#start;
480 let RenderMethod = "addMVEPairVectorIndexOperands";
481 let PredicateMethod = "isMVEPairVectorIndex<"#start#", "#end#">";
482 }
483
484 class MVEPairVectorIndex : Operand {
485 let PrintMethod = "printVectorIndex";
486 let EncoderMethod = "getMVEPairVectorIndexOpValue<"#opval#">";
487 let DecoderMethod = "DecodeMVEPairVectorIndexOperand<"#opval#">";
488 let MIOperandInfo = (ops i32imm);
489 }
490
491 def MVEPairVectorIndex0 : MVEPairVectorIndex<"0"> {
492 let ParserMatchClass = MVEPairVectorIndexOperand<"0", "1">;
493 }
494
495 def MVEPairVectorIndex2 : MVEPairVectorIndex<"2"> {
496 let ParserMatchClass = MVEPairVectorIndexOperand<"2", "3">;
475497 }
476498
477499 // Vector indexing
30453045
30463046 // end of mve_qDest_rSrc
30473047
3048 // start of coproc mov
3049
3050 class MVE_VMOV_64bit
3051 : MVE_VMOV_lane_base
3052 MVEPairVectorIndex0:$idx2)),
3053 NoItinerary, "vmov", "", ops, cstr, []> {
3054 bits<5> Rt;
3055 bits<5> Rt2;
3056 bits<4> Qd;
3057 bit idx;
3058 bit idx2;
3059
3060 let Inst{31-23} = 0b111011000;
3061 let Inst{22} = Qd{3};
3062 let Inst{21} = 0b0;
3063 let Inst{20} = to_qreg;
3064 let Inst{19-16} = Rt2{3-0};
3065 let Inst{15-13} = Qd{2-0};
3066 let Inst{12-5} = 0b01111000;
3067 let Inst{4} = idx2;
3068 let Inst{3-0} = Rt{3-0};
3069 }
3070
3071 // The assembly syntax for these instructions mentions the vector
3072 // register name twice, e.g.
3073 //
3074 // vmov q2[2], q2[0], r0, r1
3075 // vmov r0, r1, q2[2], q2[0]
3076 //
3077 // which needs a bit of juggling with MC operand handling.
3078 //
3079 // For the move _into_ a vector register, the MC operand list also has
3080 // to mention the register name twice: once as the output, and once as
3081 // an extra input to represent where the unchanged half of the output
3082 // register comes from (when this instruction is used in code
3083 // generation). So we arrange that the first mention of the vector reg
3084 // in the instruction is considered by the AsmMatcher to be the output
3085 // ($Qd), and the second one is the input ($QdSrc). Binding them
3086 // together with the existing 'tie' constraint is enough to enforce at
3087 // register allocation time that they have to be the same register.
3088 //
3089 // For the move _from_ a vector register, there's no way to get round
3090 // the fact that both instances of that register name have to be
3091 // inputs. They have to be the same register again, but this time, we
3092 // can't use a tie constraint, because that has to be between an
3093 // output and an input operand. So this time, we have to arrange that
3094 // the q-reg appears just once in the MC operand list, in spite of
3095 // being mentioned twice in the asm syntax - which needs a custom
3096 // AsmMatchConverter.
3097
3098 def MVE_VMOV_q_rr : MVE_VMOV_64bit<(outs MQPR:$Qd),
3099 (ins MQPR:$QdSrc, rGPR:$Rt, rGPR:$Rt2),
3100 0b1, "$Qd$idx, $QdSrc$idx2, $Rt, $Rt2",
3101 "$Qd = $QdSrc"> {
3102 let DecoderMethod = "DecodeMVEVMOVDRegtoQ";
3103 }
3104
3105 def MVE_VMOV_rr_q : MVE_VMOV_64bit<(outs rGPR:$Rt, rGPR:$Rt2), (ins MQPR:$Qd),
3106 0b0, "$Rt, $Rt2, $Qd$idx, $Qd$idx2", ""> {
3107 let DecoderMethod = "DecodeMVEVMOVQtoDReg";
3108 let AsmMatchConverter = "cvtMVEVMOVQtoDReg";
3109 }
3110
3111 // end of coproc mov
3112
30483113 class MVE_VPT size, dag iops, string asm, list pattern=[]>
30493114 : MVE_MI<(outs ), iops, NoItinerary, !strconcat("vpt", "${Mk}", ".", suffix), asm, "", pattern> {
30503115 bits<3> fc;
576576 // Asm Match Converter Methods
577577 void cvtThumbMultiply(MCInst &Inst, const OperandVector &);
578578 void cvtThumbBranches(MCInst &Inst, const OperandVector &);
579 void cvtMVEVMOVQtoDReg(MCInst &Inst, const OperandVector &);
579580
580581 bool validateInstruction(MCInst &Inst, const OperandVector &Ops);
581582 bool processInstruction(MCInst &Inst, const OperandVector &Ops, MCStreamer &Out);
19451946 bool isVectorIndex32() const { return isVectorIndexInRange<2>(); }
19461947 bool isVectorIndex64() const { return isVectorIndexInRange<1>(); }
19471948
1949 template
1950 bool isMVEPairVectorIndex() const {
1951 if (Kind != k_VectorIndex) return false;
1952 return VectorIndex.Val == PermittedValue ||
1953 VectorIndex.Val == OtherPermittedValue;
1954 }
1955
19481956 bool isNEONi8splat() const {
19491957 if (!isImm()) return false;
19501958 const MCConstantExpr *CE = dyn_cast(getImm());
29912999 }
29923000
29933001 void addMVEVectorIndexOperands(MCInst &Inst, unsigned N) const {
3002 assert(N == 1 && "Invalid number of operands!");
3003 Inst.addOperand(MCOperand::createImm(getVectorIndex()));
3004 }
3005
3006 void addMVEPairVectorIndexOperands(MCInst &Inst, unsigned N) const {
29943007 assert(N == 1 && "Invalid number of operands!");
29953008 Inst.addOperand(MCOperand::createImm(getVectorIndex()));
29963009 }
53605373 ((ARMOperand &)*Operands[CondOp]).addCondCodeOperands(Inst, 2);
53615374 }
53625375
5376 void ARMAsmParser::cvtMVEVMOVQtoDReg(
5377 MCInst &Inst, const OperandVector &Operands) {
5378
5379 // mnemonic, condition code, Rt, Rt2, Qd, idx, Qd again, idx2
5380 assert(Operands.size() == 8);
5381
5382 ((ARMOperand &)*Operands[2]).addRegOperands(Inst, 1); // Rt
5383 ((ARMOperand &)*Operands[3]).addRegOperands(Inst, 1); // Rt2
5384 ((ARMOperand &)*Operands[4]).addRegOperands(Inst, 1); // Qd
5385 ((ARMOperand &)*Operands[5]).addMVEPairVectorIndexOperands(Inst, 1); // idx
5386 // skip second copy of Qd in Operands[6]
5387 ((ARMOperand &)*Operands[7]).addMVEPairVectorIndexOperands(Inst, 1); // idx2
5388 ((ARMOperand &)*Operands[1]).addCondCodeOperands(Inst, 2); // condition code
5389 }
5390
53635391 /// Parse an ARM memory expression, return false if successful else return true
53645392 /// or an error. The first token must be a '[' when called.
53655393 bool ARMAsmParser::parseMemory(OperandVector &Operands) {
75927620 return Error (Operands[3]->getStartLoc(),
75937621 "Qd register and Qm register can't be identical");
75947622 }
7623 break;
7624 }
7625 case ARM::MVE_VMOV_rr_q: {
7626 if (Operands[4]->getReg() != Operands[6]->getReg())
7627 return Error (Operands[4]->getStartLoc(), "Q-registers must be the same");
7628 if (static_cast(*Operands[5]).getVectorIndex() !=
7629 static_cast(*Operands[7]).getVectorIndex() + 2)
7630 return Error (Operands[5]->getStartLoc(), "Q-register indexes must be 2 and 0 or 3 and 1");
7631 break;
7632 }
7633 case ARM::MVE_VMOV_q_rr: {
7634 if (Operands[2]->getReg() != Operands[4]->getReg())
7635 return Error (Operands[2]->getStartLoc(), "Q-registers must be the same");
7636 if (static_cast(*Operands[3]).getVectorIndex() !=
7637 static_cast(*Operands[5]).getVectorIndex() + 2)
7638 return Error (Operands[3]->getStartLoc(), "Q-register indexes must be 2 and 0 or 3 and 1");
75957639 break;
75967640 }
75977641 }
512512 static DecodeStatus DecodeExpandedImmOperand(MCInst &Inst, unsigned Val,
513513 uint64_t Address,
514514 const void *Decoder);
515 template
516 static DecodeStatus DecodeMVEPairVectorIndexOperand(MCInst &Inst, unsigned Val,
517 uint64_t Address,
518 const void *Decoder);
519 static DecodeStatus DecodeMVEVMOVQtoDReg(MCInst &Inst, unsigned Insn,
520 uint64_t Address,
521 const void *Decoder);
522 static DecodeStatus DecodeMVEVMOVDRegtoQ(MCInst &Inst, unsigned Insn,
523 uint64_t Address,
524 const void *Decoder);
515525 static DecodeStatus DecodeMVEVCVTt1fp(MCInst &Inst, unsigned Insn,
516526 uint64_t Address, const void *Decoder);
517527 typedef DecodeStatus OperandDecoder(MCInst &Inst, unsigned Val,
61516161 return MCDisassembler::Success;
61526162 }
61536163
6164 template
6165 static DecodeStatus DecodeMVEPairVectorIndexOperand(MCInst &Inst, unsigned Val,
6166 uint64_t Address,
6167 const void *Decoder) {
6168 DecodeStatus S = MCDisassembler::Success;
6169
6170 Inst.addOperand(MCOperand::createImm(start + Val));
6171
6172 return S;
6173 }
6174
6175 static DecodeStatus DecodeMVEVMOVQtoDReg(MCInst &Inst, unsigned Insn,
6176 uint64_t Address, const void *Decoder) {
6177 DecodeStatus S = MCDisassembler::Success;
6178 unsigned Rt = fieldFromInstruction(Insn, 0, 4);
6179 unsigned Rt2 = fieldFromInstruction(Insn, 16, 4);
6180 unsigned Qd = ((fieldFromInstruction(Insn, 22, 1) << 3) |
6181 fieldFromInstruction(Insn, 13, 3));
6182 unsigned index = fieldFromInstruction(Insn, 4, 1);
6183
6184 if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder)))
6185 return MCDisassembler::Fail;
6186 if (!Check(S, DecodeGPRRegisterClass(Inst, Rt2, Address, Decoder)))
6187 return MCDisassembler::Fail;
6188 if (!Check(S, DecodeMQPRRegisterClass(Inst, Qd, Address, Decoder)))
6189 return MCDisassembler::Fail;
6190 if (!Check(S, DecodeMVEPairVectorIndexOperand<2>(Inst, index, Address, Decoder)))
6191 return MCDisassembler::Fail;
6192 if (!Check(S, DecodeMVEPairVectorIndexOperand<0>(Inst, index, Address, Decoder)))
6193 return MCDisassembler::Fail;
6194
6195 return S;
6196 }
6197
6198 static DecodeStatus DecodeMVEVMOVDRegtoQ(MCInst &Inst, unsigned Insn,
6199 uint64_t Address, const void *Decoder) {
6200 DecodeStatus S = MCDisassembler::Success;
6201 unsigned Rt = fieldFromInstruction(Insn, 0, 4);
6202 unsigned Rt2 = fieldFromInstruction(Insn, 16, 4);
6203 unsigned Qd = ((fieldFromInstruction(Insn, 22, 1) << 3) |
6204 fieldFromInstruction(Insn, 13, 3));
6205 unsigned index = fieldFromInstruction(Insn, 4, 1);
6206
6207 if (!Check(S, DecodeMQPRRegisterClass(Inst, Qd, Address, Decoder)))
6208 return MCDisassembler::Fail;
6209 if (!Check(S, DecodeMQPRRegisterClass(Inst, Qd, Address, Decoder)))
6210 return MCDisassembler::Fail;
6211 if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder)))
6212 return MCDisassembler::Fail;
6213 if (!Check(S, DecodeGPRRegisterClass(Inst, Rt2, Address, Decoder)))
6214 return MCDisassembler::Fail;
6215 if (!Check(S, DecodeMVEPairVectorIndexOperand<2>(Inst, index, Address, Decoder)))
6216 return MCDisassembler::Fail;
6217 if (!Check(S, DecodeMVEPairVectorIndexOperand<0>(Inst, index, Address, Decoder)))
6218 return MCDisassembler::Fail;
6219
6220 return S;
6221 }
6222
61546223 static DecodeStatus DecodeMVEOverlappingLongShift(
61556224 MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) {
61566225 DecodeStatus S = MCDisassembler::Success;
458458 uint32_t getRestrictedCondCodeOpValue(const MCInst &MI, unsigned OpIdx,
459459 SmallVectorImpl &Fixups,
460460 const MCSubtargetInfo &STI) const;
461 template
462 uint32_t getMVEPairVectorIndexOpValue(const MCInst &MI, unsigned OpIdx,
463 SmallVectorImpl &Fixups,
464 const MCSubtargetInfo &STI) const;
461465 };
462466
463467 } // end anonymous namespace
19251929 return countTrailingZeros((uint64_t)MO.getImm());
19261930 }
19271931
1932 template
1933 uint32_t ARMMCCodeEmitter::
1934 getMVEPairVectorIndexOpValue(const MCInst &MI, unsigned OpIdx,
1935 SmallVectorImpl &Fixups,
1936 const MCSubtargetInfo &STI) const {
1937 const MCOperand MO = MI.getOperand(OpIdx);
1938 assert(MO.isImm() && "Unexpected operand type!");
1939
1940 int Value = MO.getImm();
1941 return Value - start;
1942 }
1943
19281944 #include "ARMGenMCCodeEmitter.inc"
19291945
19301946 MCCodeEmitter *llvm::createARMLEMCCodeEmitter(const MCInstrInfo &MCII,
0 # RUN: not llvm-mc -triple=thumbv8.1m.main-none-eabi -mattr=+mve -show-encoding < %s \
1 # RUN: | FileCheck --check-prefix=CHECK-NOFP %s
2 # RUN: not llvm-mc -triple=thumbv8.1m.main-none-eabi -mattr=+mve.fp,+fp64 -show-encoding < %s 2>%t \
3 # RUN: | FileCheck --check-prefix=CHECK %s
4 # RUN: FileCheck --check-prefix=ERROR < %t %s
5
6 # CHECK: vmov lr, r7, q4[2], q4[0] @ encoding: [0x07,0xec,0x0e,0x8f]
7 # CHECK-NOFP: vmov lr, r7, q4[2], q4[0] @ encoding: [0x07,0xec,0x0e,0x8f]
8 vmov lr, r7, q4[2], q4[0]
9
10 # ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: Q-registers must be the same
11 vmov lr, r7, q5[2], q4[0]
12
13 # ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: Q-register indexes must be 2 and 0 or 3 and 1
14 vmov lr, r7, q4[2], q4[1]
15
16 # CHECK: vmov q3[3], q3[1], r4, r1 @ encoding: [0x11,0xec,0x14,0x6f]
17 # CHECK-NOFP: vmov q3[3], q3[1], r4, r1 @ encoding: [0x11,0xec,0x14,0x6f]
18 vmov q3[3], q3[1], r4, r1
19
20 # ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: Q-registers must be the same
21 vmov q4[3], q3[1], r4, r1
22
23 # ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: Q-register indexes must be 2 and 0 or 3 and 1
24 vmov q3[2], q3[1], r4, r1
0 # RUN: not llvm-mc -disassemble -triple=thumbv8.1m.main-none-eabi -mattr=+mve.fp,+fp64 -show-encoding %s 2> %t | FileCheck %s
1 # RUN: FileCheck --check-prefix=ERROR < %t %s
2 # RUN: not llvm-mc -disassemble -triple=thumbv8.1m.main-none-eabi -show-encoding %s &> %t
3 # RUN: FileCheck --check-prefix=CHECK-NOMVE < %t %s
4 # RUN: not llvm-mc -disassemble -triple=thumbv8.1m.main-none-eabi -mattr=+mve.fp,+fp64 -show-encoding %s 2> %t | FileCheck %s
5 # RUN: FileCheck --check-prefix=ERROR < %t %s
6
7 # CHECK: vmov lr, r7, q4[2], q4[0] @ encoding: [0x07,0xec,0x0e,0x8f]
8 # CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding
9 [0x07,0xec,0x0e,0x8f]
10
11 # CHECK: vmov q3[3], q3[1], r4, r1 @ encoding: [0x11,0xec,0x14,0x6f]
12 # CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding
13 [0x11,0xec,0x14,0x6f]
14
15 # ERROR: [[@LINE+1]]:2: warning: invalid instruction encoding
16 [0x40,0xec,0x00,0x0f]
17
18 # ERROR: [[@LINE+1]]:2: warning: invalid instruction encoding
19 [0x50,0xec,0x00,0x0f]