let ParserMatchClass = VecListTwoQAsmOperand;
}
+// Register list of one D register, with "all lanes" subscripting.
+def VecListOneDAllLanesAsmOperand : AsmOperandClass {
+ let Name = "VecListOneDAllLanes";
+ let ParserMethod = "parseVectorList";
+ let RenderMethod = "addVecListOperands";
+}
+def VecListOneDAllLanes : RegisterOperand<DPR, "printVectorListOneAllLanes"> {
+ let ParserMatchClass = VecListOneDAllLanesAsmOperand;
+}
+
//===----------------------------------------------------------------------===//
// NEON-specific DAG Nodes.
//===----------------------------------------------------------------------===//
// VLD1DUP : Vector Load (single element to all lanes)
class VLD1DUP<bits<4> op7_4, string Dt, ValueType Ty, PatFrag LoadOp>
- : NLdSt<1, 0b10, 0b1100, op7_4, (outs DPR:$Vd), (ins addrmode6dup:$Rn),
- IIC_VLD1dup, "vld1", Dt, "\\{$Vd[]\\}, $Rn", "",
- [(set DPR:$Vd, (Ty (NEONvdup (i32 (LoadOp addrmode6dup:$Rn)))))]> {
+ : NLdSt<1, 0b10, 0b1100, op7_4, (outs VecListOneDAllLanes:$Vd),
+ (ins addrmode6dup:$Rn),
+ IIC_VLD1dup, "vld1", Dt, "$Vd, $Rn", "",
+ [(set VecListOneDAllLanes:$Vd,
+ (Ty (NEONvdup (i32 (LoadOp addrmode6dup:$Rn)))))]> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
let DecoderMethod = "DecodeVLD1DupInstruction";
class ARMOperand;
+enum VectorLaneTy { NoLanes, AllLanes };
+
class ARMAsmParser : public MCTargetAsmParser {
MCSubtargetInfo &STI;
MCAsmParser &Parser;
OperandMatchResultTy parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseFPImm(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseVectorList(SmallVectorImpl<MCParsedAsmOperand*>&);
+ OperandMatchResultTy parseVectorLane(VectorLaneTy &LaneKind);
// Asm Match Converter Methods
bool cvtT2LdrdPre(MCInst &Inst, unsigned Opcode,
k_DPRRegisterList,
k_SPRRegisterList,
k_VectorList,
+ k_VectorListAllLanes,
k_ShiftedRegister,
k_ShiftedImmediate,
k_ShifterImmediate,
Registers = o.Registers;
break;
case k_VectorList:
+ case k_VectorListAllLanes:
VectorList = o.VectorList;
break;
case k_CoprocNum:
return VectorList.Count == 2 && false;
}
+ bool isVecListOneDAllLanes() const {
+ if (Kind != k_VectorListAllLanes) return false;
+ return VectorList.Count == 1;
+ }
+
bool isVectorIndex8() const {
if (Kind != k_VectorIndex) return false;
return VectorIndex.Val < 8;
return Op;
}
+ static ARMOperand *CreateVectorListAllLanes(unsigned RegNum, unsigned Count,
+ SMLoc S, SMLoc E) {
+ ARMOperand *Op = new ARMOperand(k_VectorListAllLanes);
+ Op->VectorList.RegNum = RegNum;
+ Op->VectorList.Count = Count;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
static ARMOperand *CreateVectorIndex(unsigned Idx, SMLoc S, SMLoc E,
MCContext &Ctx) {
ARMOperand *Op = new ARMOperand(k_VectorIndex);
OS << "<vector_list " << VectorList.Count << " * "
<< VectorList.RegNum << ">";
break;
+ case k_VectorListAllLanes:
+ OS << "<vector_list(all lanes) " << VectorList.Count << " * "
+ << VectorList.RegNum << ">";
+ break;
case k_Token:
OS << "'" << getToken() << "'";
break;
return false;
}
+// Helper function to parse the lane index for vector lists.
+ARMAsmParser::OperandMatchResultTy ARMAsmParser::
+parseVectorLane(VectorLaneTy &LaneKind) {
+ if (Parser.getTok().is(AsmToken::LBrac)) {
+ Parser.Lex(); // Eat the '['.
+ if (Parser.getTok().is(AsmToken::RBrac)) {
+ // "Dn[]" is the 'all lanes' syntax.
+ LaneKind = AllLanes;
+ Parser.Lex(); // Eat the ']'.
+ return MatchOperand_Success;
+ }
+ // FIXME: Other lane kinds as we add them.
+ Error(Parser.getTok().getLoc(), "FIXME: Unexpected lane kind.");
+ return MatchOperand_ParseFail;
+ }
+ LaneKind = NoLanes;
+ return MatchOperand_Success;
+}
+
// parse a vector register list
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseVectorList(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+ VectorLaneTy LaneKind;
SMLoc S = Parser.getTok().getLoc();
// As an extension (to match gas), support a plain D register or Q register
// (without encosing curly braces) as a single or double entry list,
return MatchOperand_NoMatch;
SMLoc E = Parser.getTok().getLoc();
if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg)) {
- Operands.push_back(ARMOperand::CreateVectorList(Reg, 1, S, E));
+ OperandMatchResultTy Res = parseVectorLane(LaneKind);
+ if (Res != MatchOperand_Success)
+ return Res;
+ switch (LaneKind) {
+ default:
+ assert(0 && "unexpected lane kind!");
+ case NoLanes:
+ E = Parser.getTok().getLoc();
+ Operands.push_back(ARMOperand::CreateVectorList(Reg, 1, S, E));
+ break;
+ case AllLanes:
+ E = Parser.getTok().getLoc();
+ Operands.push_back(ARMOperand::CreateVectorListAllLanes(Reg, 1, S, E));
+ break;
+ }
return MatchOperand_Success;
}
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {
Reg = getDRegFromQReg(Reg);
- Operands.push_back(ARMOperand::CreateVectorList(Reg, 2, S, E));
+ OperandMatchResultTy Res = parseVectorLane(LaneKind);
+ if (Res != MatchOperand_Success)
+ return Res;
+ switch (LaneKind) {
+ default:
+ assert(0 && "unexpected lane kind!");
+ case NoLanes:
+ E = Parser.getTok().getLoc();
+ Operands.push_back(ARMOperand::CreateVectorList(Reg, 2, S, E));
+ break;
+ case AllLanes:
+ E = Parser.getTok().getLoc();
+ Operands.push_back(ARMOperand::CreateVectorListAllLanes(Reg, 2, S, E));
+ break;
+ }
return MatchOperand_Success;
}
Error(S, "vector register expected");
++Reg;
++Count;
}
+ if (parseVectorLane(LaneKind) != MatchOperand_Success)
+ return MatchOperand_ParseFail;
while (Parser.getTok().is(AsmToken::Comma) ||
Parser.getTok().is(AsmToken::Minus)) {
Error(EndLoc, "bad range in register list");
return MatchOperand_ParseFail;
}
+ // Parse the lane specifier if present.
+ VectorLaneTy NextLaneKind;
+ if (parseVectorLane(NextLaneKind) != MatchOperand_Success)
+ return MatchOperand_ParseFail;
+ if (NextLaneKind != LaneKind) {
+ Error(EndLoc, "mismatched lane index in register list");
+ return MatchOperand_ParseFail;
+ }
+ EndLoc = Parser.getTok().getLoc();
// Add all the registers in the range to the register list.
Count += EndReg - Reg;
}
++Reg;
Count += 2;
+ // Parse the lane specifier if present.
+ VectorLaneTy NextLaneKind;
+ SMLoc EndLoc = Parser.getTok().getLoc();
+ if (parseVectorLane(NextLaneKind) != MatchOperand_Success)
+ return MatchOperand_ParseFail;
+ if (NextLaneKind != LaneKind) {
+ Error(EndLoc, "mismatched lane index in register list");
+ return MatchOperand_ParseFail;
+ }
continue;
}
// Normal D register. Just check that it's contiguous and keep going.
return MatchOperand_ParseFail;
}
++Count;
+ // Parse the lane specifier if present.
+ VectorLaneTy NextLaneKind;
+ SMLoc EndLoc = Parser.getTok().getLoc();
+ if (parseVectorLane(NextLaneKind) != MatchOperand_Success)
+ return MatchOperand_ParseFail;
+ if (NextLaneKind != LaneKind) {
+ Error(EndLoc, "mismatched lane index in register list");
+ return MatchOperand_ParseFail;
+ }
}
SMLoc E = Parser.getTok().getLoc();
}
Parser.Lex(); // Eat '}' token.
- Operands.push_back(ARMOperand::CreateVectorList(FirstReg, Count, S, E));
+ switch (LaneKind) {
+ default:
+ assert(0 && "unexpected lane kind in register list.");
+ case NoLanes:
+ Operands.push_back(ARMOperand::CreateVectorList(FirstReg, Count, S, E));
+ break;
+ case AllLanes:
+ Operands.push_back(ARMOperand::CreateVectorListAllLanes(FirstReg, Count,
+ S, E));
+ break;
+ }
return MatchOperand_Success;
}