+/// ParseOperation - Parse an operator. This returns null on error.
+///
+/// Operation ::= XOperator ['<' Type '>'] '(' Args ')'
+///
+Init *TGParser::ParseOperation(Record *CurRec) {
+ switch (Lex.getCode()) {
+ default:
+ TokError("unknown operation");
+ return 0;
+ break;
+ case tgtok::XHead:
+ case tgtok::XTail:
+ case tgtok::XEmpty:
+ case tgtok::XCast: { // Value ::= !unop '(' Value ')'
+ UnOpInit::UnaryOp Code;
+ RecTy *Type = 0;
+
+ switch (Lex.getCode()) {
+ default: assert(0 && "Unhandled code!");
+ case tgtok::XCast:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::CAST;
+
+ Type = ParseOperatorType();
+
+ if (Type == 0) {
+ TokError("did not get type for unary operator");
+ return 0;
+ }
+
+ break;
+ case tgtok::XHead:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::HEAD;
+ break;
+ case tgtok::XTail:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::TAIL;
+ break;
+ case tgtok::XEmpty:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::EMPTY;
+ Type = new IntRecTy;
+ break;
+ }
+ if (Lex.getCode() != tgtok::l_paren) {
+ TokError("expected '(' after unary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the '('
+
+ Init *LHS = ParseValue(CurRec);
+ if (LHS == 0) return 0;
+
+ if (Code == UnOpInit::HEAD
+ || Code == UnOpInit::TAIL
+ || Code == UnOpInit::EMPTY) {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
+ TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS);
+ if (LHSl == 0 && LHSs == 0 && LHSt == 0) {
+ TokError("expected list or string type argument in unary operator");
+ return 0;
+ }
+ if (LHSt) {
+ ListRecTy *LType = dynamic_cast<ListRecTy*>(LHSt->getType());
+ StringRecTy *SType = dynamic_cast<StringRecTy*>(LHSt->getType());
+ if (LType == 0 && SType == 0) {
+ TokError("expected list or string type argumnet in unary operator");
+ return 0;
+ }
+ }
+
+ if (Code == UnOpInit::HEAD
+ || Code == UnOpInit::TAIL) {
+ if (LHSl == 0 && LHSt == 0) {
+ TokError("expected list type argumnet in unary operator");
+ return 0;
+ }
+
+ if (LHSl && LHSl->getSize() == 0) {
+ TokError("empty list argument in unary operator");
+ return 0;
+ }
+ if (LHSl) {
+ Init *Item = LHSl->getElement(0);
+ TypedInit *Itemt = dynamic_cast<TypedInit*>(Item);
+ if (Itemt == 0) {
+ TokError("untyped list element in unary operator");
+ return 0;
+ }
+ if (Code == UnOpInit::HEAD) {
+ Type = Itemt->getType();
+ } else {
+ Type = new ListRecTy(Itemt->getType());
+ }
+ } else {
+ assert(LHSt && "expected list type argument in unary operator");
+ ListRecTy *LType = dynamic_cast<ListRecTy*>(LHSt->getType());
+ if (LType == 0) {
+ TokError("expected list type argumnet in unary operator");
+ return 0;
+ }
+ if (Code == UnOpInit::HEAD) {
+ Type = LType->getElementType();
+ } else {
+ Type = LType;
+ }
+ }
+ }
+ }
+
+ if (Lex.getCode() != tgtok::r_paren) {
+ TokError("expected ')' in unary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ')'
+ return (new UnOpInit(Code, LHS, Type))->Fold(CurRec, CurMultiClass);
+ }
+
+ case tgtok::XConcat:
+ case tgtok::XSRA:
+ case tgtok::XSRL:
+ case tgtok::XSHL:
+ case tgtok::XEq:
+ case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')'
+ tgtok::TokKind OpTok = Lex.getCode();
+ SMLoc OpLoc = Lex.getLoc();
+ Lex.Lex(); // eat the operation
+
+ BinOpInit::BinaryOp Code;
+ RecTy *Type = 0;
+
+ switch (OpTok) {
+ default: assert(0 && "Unhandled code!");
+ case tgtok::XConcat: Code = BinOpInit::CONCAT; Type = new DagRecTy(); break;
+ case tgtok::XSRA: Code = BinOpInit::SRA; Type = new IntRecTy(); break;
+ case tgtok::XSRL: Code = BinOpInit::SRL; Type = new IntRecTy(); break;
+ case tgtok::XSHL: Code = BinOpInit::SHL; Type = new IntRecTy(); break;
+ case tgtok::XEq: Code = BinOpInit::EQ; Type = new BitRecTy(); break;
+ case tgtok::XStrConcat:
+ Code = BinOpInit::STRCONCAT;
+ Type = new StringRecTy();
+ break;
+ }
+
+ if (Lex.getCode() != tgtok::l_paren) {
+ TokError("expected '(' after binary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the '('
+
+ SmallVector<Init*, 2> InitList;
+
+ InitList.push_back(ParseValue(CurRec));
+ if (InitList.back() == 0) return 0;
+
+ while (Lex.getCode() == tgtok::comma) {
+ Lex.Lex(); // eat the ','
+
+ InitList.push_back(ParseValue(CurRec));
+ if (InitList.back() == 0) return 0;
+ }
+
+ if (Lex.getCode() != tgtok::r_paren) {
+ TokError("expected ')' in operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ')'
+
+ // We allow multiple operands to associative operators like !strconcat as
+ // shorthand for nesting them.
+ if (Code == BinOpInit::STRCONCAT) {
+ while (InitList.size() > 2) {
+ Init *RHS = InitList.pop_back_val();
+ RHS = (new BinOpInit(Code, InitList.back(), RHS, Type))
+ ->Fold(CurRec, CurMultiClass);
+ InitList.back() = RHS;
+ }
+ }
+
+ if (InitList.size() == 2)
+ return (new BinOpInit(Code, InitList[0], InitList[1], Type))
+ ->Fold(CurRec, CurMultiClass);
+
+ Error(OpLoc, "expected two operands to operator");
+ return 0;
+ }
+
+ case tgtok::XIf:
+ case tgtok::XForEach:
+ case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
+ TernOpInit::TernaryOp Code;
+ RecTy *Type = 0;
+
+ tgtok::TokKind LexCode = Lex.getCode();
+ Lex.Lex(); // eat the operation
+ switch (LexCode) {
+ default: assert(0 && "Unhandled code!");
+ case tgtok::XIf:
+ Code = TernOpInit::IF;
+ break;
+ case tgtok::XForEach:
+ Code = TernOpInit::FOREACH;
+ break;
+ case tgtok::XSubst:
+ Code = TernOpInit::SUBST;
+ break;
+ }
+ if (Lex.getCode() != tgtok::l_paren) {
+ TokError("expected '(' after ternary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the '('
+
+ Init *LHS = ParseValue(CurRec);
+ if (LHS == 0) return 0;
+
+ if (Lex.getCode() != tgtok::comma) {
+ TokError("expected ',' in ternary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ','
+
+ Init *MHS = ParseValue(CurRec);
+ if (MHS == 0) return 0;
+
+ if (Lex.getCode() != tgtok::comma) {
+ TokError("expected ',' in ternary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ','
+
+ Init *RHS = ParseValue(CurRec);
+ if (RHS == 0) return 0;
+
+ if (Lex.getCode() != tgtok::r_paren) {
+ TokError("expected ')' in binary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ')'
+
+ switch (LexCode) {
+ default: assert(0 && "Unhandled code!");
+ case tgtok::XIf: {
+ // FIXME: The `!if' operator doesn't handle non-TypedInit well at
+ // all. This can be made much more robust.
+ TypedInit *MHSt = dynamic_cast<TypedInit*>(MHS);
+ TypedInit *RHSt = dynamic_cast<TypedInit*>(RHS);
+
+ RecTy *MHSTy = 0;
+ RecTy *RHSTy = 0;
+
+ if (MHSt == 0 && RHSt == 0) {
+ BitsInit *MHSbits = dynamic_cast<BitsInit*>(MHS);
+ BitsInit *RHSbits = dynamic_cast<BitsInit*>(RHS);
+
+ if (MHSbits && RHSbits &&
+ MHSbits->getNumBits() == RHSbits->getNumBits()) {
+ Type = new BitRecTy();
+ break;
+ } else {
+ BitInit *MHSbit = dynamic_cast<BitInit*>(MHS);
+ BitInit *RHSbit = dynamic_cast<BitInit*>(RHS);
+
+ if (MHSbit && RHSbit) {
+ Type = new BitRecTy();
+ break;
+ }
+ }
+ } else if (MHSt != 0 && RHSt != 0) {
+ MHSTy = MHSt->getType();
+ RHSTy = RHSt->getType();
+ }
+
+ if (!MHSTy || !RHSTy) {
+ TokError("could not get type for !if");
+ return 0;
+ }
+
+ if (MHSTy->typeIsConvertibleTo(RHSTy)) {
+ Type = RHSTy;
+ } else if (RHSTy->typeIsConvertibleTo(MHSTy)) {
+ Type = MHSTy;
+ } else {
+ TokError("inconsistent types for !if");
+ return 0;
+ }
+ break;
+ }
+ case tgtok::XForEach: {
+ TypedInit *MHSt = dynamic_cast<TypedInit *>(MHS);
+ if (MHSt == 0) {
+ TokError("could not get type for !foreach");
+ return 0;
+ }
+ Type = MHSt->getType();
+ break;
+ }
+ case tgtok::XSubst: {
+ TypedInit *RHSt = dynamic_cast<TypedInit *>(RHS);
+ if (RHSt == 0) {
+ TokError("could not get type for !subst");
+ return 0;
+ }
+ Type = RHSt->getType();
+ break;
+ }
+ }
+ return (new TernOpInit(Code, LHS, MHS, RHS, Type))->Fold(CurRec,
+ CurMultiClass);
+ }
+ }
+ TokError("could not parse operation");
+ return 0;
+}
+
+/// ParseOperatorType - Parse a type for an operator. This returns
+/// null on error.
+///
+/// OperatorType ::= '<' Type '>'
+///
+RecTy *TGParser::ParseOperatorType() {
+ RecTy *Type = 0;
+
+ if (Lex.getCode() != tgtok::less) {
+ TokError("expected type name for operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the <
+
+ Type = ParseType();
+
+ if (Type == 0) {
+ TokError("expected type name for operator");
+ return 0;
+ }
+
+ if (Lex.getCode() != tgtok::greater) {
+ TokError("expected type name for operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the >
+
+ return Type;
+}
+
+