llvm.org GIT mirror llvm / beb31a5
Implement a !foreach operator analogous to GNU make's $(foreach). Use it on dags and lists like this: class decls { string name; } def Decls : decls; class B<list<string> names> : A<!foreach(Decls.name, names, !strconcat(Decls.name, ", Sr."))>; git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@71803 91177308-0d34-0410-b5e6-96231b3b80d8 David Greene 10 years ago
8 changed file(s) with 374 addition(s) and 188 deletion(s). Raw diff Collapse all Expand all
406406
!subst(a, b, c)
407407
If 'a' and 'b' are of string type or are symbol references, substitute
408408 'b' for 'a' in 'c.' This operation is analogous to $(subst) in GNU make.
409
!foreach(a, b, c)
410
For each member 'b' of dag or list 'a' apply operator 'c.' 'b' is a
411 dummy variable that should be declared as a member variable of an instantiated
412 class. This operation is analogous to $(foreach) in GNU make.
409413
410414
411415

Note that all of the values have rules specifying how they convert to values

0 // RUN: tblgen %s | grep {[(set VR128:$dst, (int_x86_sse2_add_pd VR128:$src1, VR128:$src2))]} | count 1
1 // RUN: tblgen %s | grep {[(set VR128:$dst, (int_x86_sse2_add_ps VR128:$src1, VR128:$src2))]} | count 2
2
3 class ValueType {
4 int Size = size;
5 int Value = value;
6 }
7
8 def v2i64 : ValueType<128, 22>; // 2 x i64 vector value
9 def v2f64 : ValueType<128, 28>; // 2 x f64 vector value
10
11 class Intrinsic {
12 string Name = name;
13 }
14
15 class Inst opcode, dag oopnds, dag iopnds, string asmstr,
16 list pattern> {
17 bits<8> Opcode = opcode;
18 dag OutOperands = oopnds;
19 dag InOperands = iopnds;
20 string AssemblyString = asmstr;
21 list Pattern = pattern;
22 }
23
24 def ops;
25 def outs;
26 def ins;
27
28 def set;
29
30 // Define registers
31 class Register {
32 string Name = n;
33 }
34
35 class RegisterClass regTypes, list regList> {
36 list RegTypes = regTypes;
37 list MemberList = regList;
38 }
39
40 def XMM0: Register<"xmm0">;
41 def XMM1: Register<"xmm1">;
42 def XMM2: Register<"xmm2">;
43 def XMM3: Register<"xmm3">;
44 def XMM4: Register<"xmm4">;
45 def XMM5: Register<"xmm5">;
46 def XMM6: Register<"xmm6">;
47 def XMM7: Register<"xmm7">;
48 def XMM8: Register<"xmm8">;
49 def XMM9: Register<"xmm9">;
50 def XMM10: Register<"xmm10">;
51 def XMM11: Register<"xmm11">;
52 def XMM12: Register<"xmm12">;
53 def XMM13: Register<"xmm13">;
54 def XMM14: Register<"xmm14">;
55 def XMM15: Register<"xmm15">;
56
57 def VR128 : RegisterClass<[v2i64, v2f64],
58 [XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
59 XMM8, XMM9, XMM10, XMM11,
60 XMM12, XMM13, XMM14, XMM15]>;
61
62 // Dummy for subst
63 def REGCLASS : RegisterClass<[], []>;
64
65 class decls {
66 // Dummy for foreach
67 dag pattern;
68 int operand;
69 }
70
71 def Decls : decls;
72
73 // Define intrinsics
74 def int_x86_sse2_add_ps : Intrinsic<"addps">;
75 def int_x86_sse2_add_pd : Intrinsic<"addpd">;
76 def INTRINSIC : Intrinsic<"Dummy">;
77
78 multiclass arith opcode, string asmstr, string intr, list patterns> {
79 def PS : Inst
80 !strconcat(asmstr, "\t$dst, $src1, $src2"),
81 !foreach(Decls.pattern, patterns,
82 !foreach(Decls.operand, Decls.pattern,
83 !subst(INTRINSIC, !cast(!subst("SUFFIX", "_ps", intr)),
84 !subst(REGCLASS, VR128, Decls.operand))))>;
85
86 def PD : Inst
87 !strconcat(asmstr, "\t$dst, $src1, $src2"),
88 !foreach(Decls.pattern, patterns,
89 !foreach(Decls.operand, Decls.pattern,
90 !subst(INTRINSIC, !cast(!subst("SUFFIX", "_pd", intr)),
91 !subst(REGCLASS, VR128, Decls.operand))))>;
92 }
93
94 defm ADD : arith<0x58, "add", "int_x86_sse2_addSUFFIX",
95 [(set REGCLASS:$dst, (INTRINSIC REGCLASS:$src1, REGCLASS:$src2))]>;
96
0 // RUN: tblgen %s | grep {Jr} | count 2
1 // RUN: tblgen %s | grep {Sr} | count 2
2 // RUN: tblgen %s | not grep {NAME}
3
4 // Variables for foreach
5 class decls {
6 string name;
7 }
8
9 def Decls : decls;
10
11 class A names> {
12 list Names = names;
13 }
14
15 class B names> : A;
16
17 class C names> : A;
18
19 class D names> : A;
20
21 class Names {
22 list values = ["Ken Griffey", "Seymour Cray"];
23 }
24
25 def People : Names;
26
27 def Seniors : B;
28 def Juniors : C;
29 def Smiths : D<["NAME", "Jane Smith"]>;
30 def Unprocessed : D;
677677 return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";
678678 }
679679
680 static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type,
681 Record *CurRec, MultiClass *CurMultiClass);
682
683 static Init *EvaluateOperation(OpInit *RHSo, Init *LHS, Init *Arg,
684 RecTy *Type, Record *CurRec,
685 MultiClass *CurMultiClass) {
686 std::vector NewOperands;
687
688 TypedInit *TArg = dynamic_cast(Arg);
689
690 // If this is a dag, recurse
691 if (TArg && TArg->getType()->getAsString() == "dag") {
692 Init *Result = ForeachHelper(LHS, Arg, RHSo, Type,
693 CurRec, CurMultiClass);
694 if (Result != 0) {
695 return Result;
696 }
697 else {
698 return 0;
699 }
700 }
701
702 for (int i = 0; i < RHSo->getNumOperands(); ++i) {
703 OpInit *RHSoo = dynamic_cast(RHSo->getOperand(i));
704
705 if (RHSoo) {
706 Init *Result = EvaluateOperation(RHSoo, LHS, Arg,
707 Type, CurRec, CurMultiClass);
708 if (Result != 0) {
709 NewOperands.push_back(Result);
710 }
711 else {
712 NewOperands.push_back(Arg);
713 }
714 }
715 else if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
716 NewOperands.push_back(Arg);
717 }
718 else {
719 NewOperands.push_back(RHSo->getOperand(i));
720 }
721 }
722
723 // Now run the operator and use its result as the new leaf
724 OpInit *NewOp = RHSo->clone(NewOperands);
725 Init *NewVal = NewOp->Fold(CurRec, CurMultiClass);
726 if (NewVal != NewOp) {
727 delete NewOp;
728 return NewVal;
729 }
730 return 0;
731 }
732
733 static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type,
734 Record *CurRec, MultiClass *CurMultiClass) {
735 DagInit *MHSd = dynamic_cast(MHS);
736 ListInit *MHSl = dynamic_cast(MHS);
737
738 DagRecTy *DagType = dynamic_cast(Type);
739 ListRecTy *ListType = dynamic_cast(Type);
740
741 OpInit *RHSo = dynamic_cast(RHS);
742
743 if (!RHSo) {
744 cerr << "!foreach requires an operator\n";
745 assert(0 && "No operator for !foreach");
746 }
747
748 TypedInit *LHSt = dynamic_cast(LHS);
749
750 if (!LHSt) {
751 cerr << "!foreach requires typed variable\n";
752 assert(0 && "No typed variable for !foreach");
753 }
754
755 if (MHSd && DagType || MHSl && ListType) {
756 if (MHSd) {
757 Init *Val = MHSd->getOperator();
758 Init *Result = EvaluateOperation(RHSo, LHS, Val,
759 Type, CurRec, CurMultiClass);
760 if (Result != 0) {
761 Val = Result;
762 }
763
764 std::vector > args;
765 for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) {
766 Init *Arg;
767 std::string ArgName;
768 Arg = MHSd->getArg(i);
769 ArgName = MHSd->getArgName(i);
770
771 // Process args
772 Init *Result = EvaluateOperation(RHSo, LHS, Arg, Type,
773 CurRec, CurMultiClass);
774 if (Result != 0) {
775 Arg = Result;
776 }
777
778 // TODO: Process arg names
779 args.push_back(std::make_pair(Arg, ArgName));
780 }
781
782 return new DagInit(Val, "", args);
783 }
784 if (MHSl) {
785 std::vector NewOperands;
786 std::vector NewList(MHSl->begin(), MHSl->end());
787
788 for (ListInit::iterator li = NewList.begin(),
789 liend = NewList.end();
790 li != liend;
791 ++li) {
792 Init *Item = *li;
793 NewOperands.clear();
794 for(int i = 0; i < RHSo->getNumOperands(); ++i) {
795 // First, replace the foreach variable with the list item
796 if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
797 NewOperands.push_back(Item);
798 }
799 else {
800 NewOperands.push_back(RHSo->getOperand(i));
801 }
802 }
803
804 // Now run the operator and use its result as the new list item
805 OpInit *NewOp = RHSo->clone(NewOperands);
806 Init *NewItem = NewOp->Fold(CurRec, CurMultiClass);
807 if (NewItem != NewOp) {
808 *li = NewItem;
809 delete NewOp;
810 }
811 }
812 return new ListInit(NewList);
813 }
814 }
815 return 0;
816 }
817
680818 Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
681819 switch (getOpcode()) {
682820 default: assert(0 && "Unknown binop");
728866 }
729867
730868 case FOREACH: {
731 DagInit *MHSd = dynamic_cast(MHS);
732 ListInit *MHSl = dynamic_cast(MHS);
733
734 DagRecTy *DagType = dynamic_cast(getType());
735 ListRecTy *ListType = dynamic_cast(getType());
736
737 OpInit *RHSo = dynamic_cast(RHS);
738
739 if (!RHSo) {
740 cerr << "!foreach requires an operator\n";
741 assert(0 && "No operator for !foreach");
742 }
743
744 TypedInit *LHSt = dynamic_cast(LHS);
745
746 if (!LHSt) {
747 cerr << "!foreach requires typed variable\n";
748 assert(0 && "No typed variable for !foreach");
749 }
750
751 if (MHSd && DagType || MHSl && ListType) {
752 std::vector NewOperands;
753 if (MHSd) {
754 Init *Val = MHSd->getOperator();
755 TypedInit *TVal = dynamic_cast(Val);
756
757 if (TVal && TVal->getType()->typeIsConvertibleTo(LHSt->getType())) {
758
759 // First, replace the foreach variable with the DAG leaf
760 for (int i = 0; i < RHSo->getNumOperands(); ++i) {
761 if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
762 NewOperands.push_back(Val);
763 }
764 else {
765 NewOperands.push_back(RHSo->getOperand(i));
766 }
767 }
768
769 // Now run the operator and use its result as the new leaf
770 OpInit *NewOp = RHSo->clone(NewOperands);
771 Val = NewOp->Fold(CurRec, CurMultiClass);
772 if (Val != NewOp) {
773 delete NewOp;
774 }
775 }
776
777 std::vector > args;
778 for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) {
779 Init *Arg;
780 std::string ArgName;
781 Arg = MHSd->getArg(i);
782 ArgName = MHSd->getArgName(i);
783
784 TypedInit *TArg = dynamic_cast(Arg);
785
786 if (TArg && TArg->getType()->typeIsConvertibleTo(LHSt->getType())) {
787 NewOperands.clear();
788
789 // First, replace the foreach variable with the DAG leaf
790 for (int i = 0; i < RHSo->getNumOperands(); ++i) {
791 if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
792 NewOperands.push_back(Arg);
793 }
794 else {
795 NewOperands.push_back(RHSo->getOperand(i));
796 }
797 }
798
799 // Now run the operator and use its result as the new leaf
800 OpInit *NewOp = RHSo->clone(NewOperands);
801 Arg = NewOp->Fold(CurRec, CurMultiClass);
802 if (Arg != NewOp) {
803 delete NewOp;
804 }
805 }
806
807 if (LHSt->getType()->getAsString() == "string") {
808 NewOperands.clear();
809
810 // First, replace the foreach variable with the DAG leaf
811 for (int i = 0; i < RHSo->getNumOperands(); ++i) {
812 if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
813 NewOperands.push_back(new StringInit(ArgName));
814 }
815 else {
816 NewOperands.push_back(RHSo->getOperand(i));
817 }
818 }
819
820 // Now run the operator and use its result as the new leaf
821 OpInit *NewOp = RHSo->clone(NewOperands);
822 Init *ArgNameInit = NewOp->Fold(CurRec, CurMultiClass);
823 StringInit *SArgNameInit = dynamic_cast(ArgNameInit);
824 if (SArgNameInit) {
825 ArgName = SArgNameInit->getValue();
826 }
827 if (ArgNameInit != NewOp) {
828 delete NewOp;
829 }
830 delete ArgNameInit;
831 }
832
833 args.push_back(std::make_pair(Arg, ArgName));
834 }
835
836 return new DagInit(Val, "", args);
837 }
838 if (MHSl) {
839 std::vector NewList(MHSl->begin(), MHSl->end());
840
841 for (ListInit::iterator li = NewList.begin(),
842 liend = NewList.end();
843 li != liend;
844 ++li) {
845 Init *Item = *li;
846 TypedInit *TItem = dynamic_cast(Item);
847 if (TItem && TItem->getType()->typeIsConvertibleTo(LHSt->getType())) {
848 // First, replace the foreach variable with the list item
849 for (int i = 0; i < RHSo->getNumOperands(); ++i) {
850 if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
851 NewOperands.push_back(Item);
852 }
853 else {
854 NewOperands.push_back(RHSo->getOperand(i));
855 }
856 }
857
858 // Now run the operator and use its result as the new list item
859 OpInit *NewOp = RHSo->clone(NewOperands);
860 *li = NewOp->Fold(CurRec, CurMultiClass);
861 if (*li != NewOp) {
862 delete NewOp;
863 }
864 }
865 }
866
867 return new ListInit(NewList);
868 }
869 Init *Result = ForeachHelper(LHS, MHS, RHS, getType(),
870 CurRec, CurMultiClass);
871 if (Result != 0) {
872 return Result;
869873 }
870874 break;
871875 }
516516 I.print(OS); return OS;
517517 }
518518
519 /// TypedInit - This is the common super-class of types that have a specific,
520 /// explicit, type.
521 ///
522 class TypedInit : public Init {
523 RecTy *Ty;
524 public:
525 explicit TypedInit(RecTy *T) : Ty(T) {}
526
527 RecTy *getType() const { return Ty; }
528
529 virtual Init *convertInitializerBitRange(const std::vector &Bits);
530 virtual Init *convertInitListSlice(const std::vector &Elements);
531
532 /// resolveBitReference - This method is used to implement
533 /// VarBitInit::resolveReferences. If the bit is able to be resolved, we
534 /// simply return the resolved value, otherwise we return null.
535 ///
536 virtual Init *resolveBitReference(Record &R, const RecordVal *RV,
537 unsigned Bit) = 0;
538
539 /// resolveListElementReference - This method is used to implement
540 /// VarListElementInit::resolveReferences. If the list element is resolvable
541 /// now, we return the resolved value, otherwise we return null.
542 virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
543 unsigned Elt) = 0;
544 };
545
519546
520547 /// UnsetInit - ? - Represents an uninitialized value
521548 ///
608635
609636 /// StringInit - "foo" - Represent an initialization by a string value.
610637 ///
611 class StringInit : public Init {
638 class StringInit : public TypedInit {
612639 std::string Value;
613640 public:
614 explicit StringInit(const std::string &V) : Value(V) {}
641 explicit StringInit(const std::string &V) : TypedInit(new StringRecTy), Value(V) {}
615642
616643 const std::string &getValue() const { return Value; }
617644
620647 }
621648
622649 virtual std::string getAsString() const { return "\"" + Value + "\""; }
650
651 /// resolveBitReference - This method is used to implement
652 /// VarBitInit::resolveReferences. If the bit is able to be resolved, we
653 /// simply return the resolved value, otherwise we return null.
654 ///
655 virtual Init *resolveBitReference(Record &R, const RecordVal *RV,
656 unsigned Bit) {
657 assert(0 && "Illegal bit reference off string");
658 return 0;
659 }
660
661 /// resolveListElementReference - This method is used to implement
662 /// VarListElementInit::resolveReferences. If the list element is resolvable
663 /// now, we return the resolved value, otherwise we return null.
664 virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
665 unsigned Elt) {
666 assert(0 && "Illegal element reference off string");
667 return 0;
668 }
623669 };
624670
625671 /// CodeInit - "[{...}]" - Represent a code fragment.
682728 inline bool empty() const { return Values.empty(); }
683729 };
684730
685
686 /// TypedInit - This is the common super-class of types that have a specific,
687 /// explicit, type.
688 ///
689 class TypedInit : public Init {
690 RecTy *Ty;
691 public:
692 explicit TypedInit(RecTy *T) : Ty(T) {}
693
694 RecTy *getType() const { return Ty; }
695
696 virtual Init *convertInitializerBitRange(const std::vector &Bits);
697 virtual Init *convertInitListSlice(const std::vector &Elements);
698
699 /// resolveBitReference - This method is used to implement
700 /// VarBitInit::resolveReferences. If the bit is able to be resolved, we
701 /// simply return the resolved value, otherwise we return null.
702 ///
703 virtual Init *resolveBitReference(Record &R, const RecordVal *RV,
704 unsigned Bit) = 0;
705
706 /// resolveListElementReference - This method is used to implement
707 /// VarListElementInit::resolveReferences. If the list element is resolvable
708 /// now, we return the resolved value, otherwise we return null.
709 virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
710 unsigned Elt) = 0;
711 };
712731
713732 /// OpInit - Base class for operators
714733 ///
956975
957976 /// DefInit - AL - Represent a reference to a 'def' in the description
958977 ///
959 class DefInit : public Init {
978 class DefInit : public TypedInit {
960979 Record *Def;
961980 public:
962 explicit DefInit(Record *D) : Def(D) {}
981 explicit DefInit(Record *D) : TypedInit(new RecordRecTy(D)), Def(D) {}
963982
964983 virtual Init *convertInitializerTo(RecTy *Ty) {
965984 return Ty->convertValue(this);
973992 virtual Init *getFieldInit(Record &R, const std::string &FieldName) const;
974993
975994 virtual std::string getAsString() const;
995
996 /// resolveBitReference - This method is used to implement
997 /// VarBitInit::resolveReferences. If the bit is able to be resolved, we
998 /// simply return the resolved value, otherwise we return null.
999 ///
1000 virtual Init *resolveBitReference(Record &R, const RecordVal *RV,
1001 unsigned Bit) {
1002 assert(0 && "Illegal bit reference off def");
1003 return 0;
1004 }
1005
1006 /// resolveListElementReference - This method is used to implement
1007 /// VarListElementInit::resolveReferences. If the list element is resolvable
1008 /// now, we return the resolved value, otherwise we return null.
1009 virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
1010 unsigned Elt) {
1011 assert(0 && "Illegal element reference off def");
1012 return 0;
1013 }
9761014 };
9771015
9781016
10071045 /// to have at least one value then a (possibly empty) list of arguments. Each
10081046 /// argument can have a name associated with it.
10091047 ///
1010 class DagInit : public Init {
1048 class DagInit : public TypedInit {
10111049 Init *Val;
10121050 std::string ValName;
10131051 std::vector Args;
10151053 public:
10161054 DagInit(Init *V, std::string VN,
10171055 const std::vector > &args)
1018 : Val(V), ValName(VN) {
1056 : TypedInit(new DagRecTy), Val(V), ValName(VN) {
10191057 Args.reserve(args.size());
10201058 ArgNames.reserve(args.size());
10211059 for (unsigned i = 0, e = args.size(); i != e; ++i) {
10251063 }
10261064 DagInit(Init *V, std::string VN, const std::vector &args,
10271065 const std::vector &argNames)
1028 : Val(V), ValName(VN), Args(args), ArgNames(argNames) {
1066 : TypedInit(new DagRecTy), Val(V), ValName(VN), Args(args), ArgNames(argNames) {
10291067 }
10301068
10311069 virtual Init *convertInitializerTo(RecTy *Ty) {
10761114 inline size_t name_size () const { return ArgNames.size(); }
10771115 inline bool name_empty() const { return ArgNames.empty(); }
10781116
1117 virtual Init *resolveBitReference(Record &R, const RecordVal *RV,
1118 unsigned Bit) {
1119 assert(0 && "Illegal bit reference off dag");
1120 return 0;
1121 }
1122
1123 virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
1124 unsigned Elt) {
1125 assert(0 && "Illegal element reference off dag");
1126 return 0;
1127 }
1128
10791129 };
10801130
10811131 //===----------------------------------------------------------------------===//
447447 if (Len == 9 && !memcmp(Start, "strconcat", 9)) return tgtok::XStrConcat;
448448 if (Len == 10 && !memcmp(Start, "nameconcat", 10)) return tgtok::XNameConcat;
449449 if (Len == 5 && !memcmp(Start, "subst", 5)) return tgtok::XSubst;
450 // if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach;
450 if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach;
451451 if (Len == 4 && !memcmp(Start, "cast", 4)) return tgtok::XCast;
452452
453453 return ReturnError(Start-1, "Unknown operator");
4545
4646 // !keywords.
4747 XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst,
48 //XForEach,
48 XForEach,
4949
5050 // Integer value.
5151 IntVal,
791791 return (new BinOpInit(Code, LHS, RHS, Type))->Fold(CurRec, CurMultiClass);
792792 }
793793
794 // case tgtok::XForEach:
794 case tgtok::XForEach:
795795 case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
796796 TernOpInit::TernaryOp Code;
797797 RecTy *Type = 0;
801801 Lex.Lex(); // eat the operation
802802 switch (LexCode) {
803803 default: assert(0 && "Unhandled code!");
804 //case tgtok::XForEach:
805 //Code = TernOpInit::FOREACH;
806 //break;
804 case tgtok::XForEach:
805 Code = TernOpInit::FOREACH;
806 break;
807807 case tgtok::XSubst:
808808 Code = TernOpInit::SUBST;
809809 break;
843843
844844 switch (LexCode) {
845845 default: assert(0 && "Unhandled code!");
846 //case tgtok::XForEach: {
847 //TypedInit *MHSt = dynamic_cast(MHS);
848 //if (MHSt == 0) {
849 // TokError("could not get type for !foreach");
850 // return 0;
851 //}
852 //Type = MHSt->getType();
853 //break;
854 //}
846 case tgtok::XForEach: {
847 TypedInit *MHSt = dynamic_cast(MHS);
848 if (MHSt == 0) {
849 TokError("could not get type for !foreach");
850 return 0;
851 }
852 Type = MHSt->getType();
853 break;
854 }
855855 case tgtok::XSubst: {
856856 TypedInit *RHSt = dynamic_cast(RHS);
857857 if (RHSt == 0) {
10781078 case tgtok::XSHL:
10791079 case tgtok::XStrConcat:
10801080 case tgtok::XNameConcat: // Value ::= !binop '(' Value ',' Value ')'
1081 // case tgtok::XForEach:
1081 case tgtok::XForEach:
10821082 case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
10831083 return ParseOperation(CurRec);
10841084 break;