diff options
-rw-r--r-- | docs/TableGenFundamentals.html | 4 | ||||
-rw-r--r-- | test/TableGen/TargetInstrSpec.td | 97 | ||||
-rw-r--r-- | test/TableGen/foreach.td | 31 | ||||
-rw-r--r-- | utils/TableGen/Record.cpp | 280 | ||||
-rw-r--r-- | utils/TableGen/Record.h | 118 | ||||
-rw-r--r-- | utils/TableGen/TGLexer.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/TGLexer.h | 2 | ||||
-rw-r--r-- | utils/TableGen/TGParser.cpp | 28 |
8 files changed, 374 insertions, 188 deletions
diff --git a/docs/TableGenFundamentals.html b/docs/TableGenFundamentals.html index 0186453f36..9607f9ea9e 100644 --- a/docs/TableGenFundamentals.html +++ b/docs/TableGenFundamentals.html @@ -407,6 +407,10 @@ aborts with an error. </dd> <dt><tt>!subst(a, b, c)</tt></dt> <dd>If 'a' and 'b' are of string type or are symbol references, substitute 'b' for 'a' in 'c.' This operation is analogous to $(subst) in GNU make.</dd> +<dt><tt>!foreach(a, b, c)</tt></dt> + <dd>For each member 'b' of dag or list 'a' apply operator 'c.' 'b' is a +dummy variable that should be declared as a member variable of an instantiated +class. This operation is analogous to $(foreach) in GNU make.</dd> </dl> <p>Note that all of the values have rules specifying how they convert to values diff --git a/test/TableGen/TargetInstrSpec.td b/test/TableGen/TargetInstrSpec.td new file mode 100644 index 0000000000..852551d1fe --- /dev/null +++ b/test/TableGen/TargetInstrSpec.td @@ -0,0 +1,97 @@ +// RUN: tblgen %s | grep {[(set VR128:$dst, (int_x86_sse2_add_pd VR128:$src1, VR128:$src2))]} | count 1 +// RUN: tblgen %s | grep {[(set VR128:$dst, (int_x86_sse2_add_ps VR128:$src1, VR128:$src2))]} | count 2 + +class ValueType<int size, int value> { + int Size = size; + int Value = value; +} + +def v2i64 : ValueType<128, 22>; // 2 x i64 vector value +def v2f64 : ValueType<128, 28>; // 2 x f64 vector value + +class Intrinsic<string name> { + string Name = name; +} + +class Inst<bits<8> opcode, dag oopnds, dag iopnds, string asmstr, + list<dag> pattern> { + bits<8> Opcode = opcode; + dag OutOperands = oopnds; + dag InOperands = iopnds; + string AssemblyString = asmstr; + list<dag> Pattern = pattern; +} + +def ops; +def outs; +def ins; + +def set; + +// Define registers +class Register<string n> { + string Name = n; +} + +class RegisterClass<list<ValueType> regTypes, list<Register> regList> { + list<ValueType> RegTypes = regTypes; + list<Register> MemberList = regList; +} + +def XMM0: Register<"xmm0">; +def XMM1: Register<"xmm1">; +def XMM2: Register<"xmm2">; +def XMM3: Register<"xmm3">; +def XMM4: Register<"xmm4">; +def XMM5: Register<"xmm5">; +def XMM6: Register<"xmm6">; +def XMM7: Register<"xmm7">; +def XMM8: Register<"xmm8">; +def XMM9: Register<"xmm9">; +def XMM10: Register<"xmm10">; +def XMM11: Register<"xmm11">; +def XMM12: Register<"xmm12">; +def XMM13: Register<"xmm13">; +def XMM14: Register<"xmm14">; +def XMM15: Register<"xmm15">; + +def VR128 : RegisterClass<[v2i64, v2f64], + [XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, + XMM12, XMM13, XMM14, XMM15]>; + +// Dummy for subst +def REGCLASS : RegisterClass<[], []>; + +class decls { + // Dummy for foreach + dag pattern; + int operand; +} + +def Decls : decls; + +// Define intrinsics +def int_x86_sse2_add_ps : Intrinsic<"addps">; +def int_x86_sse2_add_pd : Intrinsic<"addpd">; +def INTRINSIC : Intrinsic<"Dummy">; + +multiclass arith<bits<8> opcode, string asmstr, string intr, list<dag> patterns> { + def PS : Inst<opcode, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2), + !strconcat(asmstr, "\t$dst, $src1, $src2"), + !foreach(Decls.pattern, patterns, + !foreach(Decls.operand, Decls.pattern, + !subst(INTRINSIC, !cast<Intrinsic>(!subst("SUFFIX", "_ps", intr)), + !subst(REGCLASS, VR128, Decls.operand))))>; + + def PD : Inst<opcode, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2), + !strconcat(asmstr, "\t$dst, $src1, $src2"), + !foreach(Decls.pattern, patterns, + !foreach(Decls.operand, Decls.pattern, + !subst(INTRINSIC, !cast<Intrinsic>(!subst("SUFFIX", "_pd", intr)), + !subst(REGCLASS, VR128, Decls.operand))))>; +} + +defm ADD : arith<0x58, "add", "int_x86_sse2_addSUFFIX", + [(set REGCLASS:$dst, (INTRINSIC REGCLASS:$src1, REGCLASS:$src2))]>; + diff --git a/test/TableGen/foreach.td b/test/TableGen/foreach.td new file mode 100644 index 0000000000..589520a6f0 --- /dev/null +++ b/test/TableGen/foreach.td @@ -0,0 +1,31 @@ +// RUN: tblgen %s | grep {Jr} | count 2 +// RUN: tblgen %s | grep {Sr} | count 2 +// RUN: tblgen %s | not grep {NAME} + +// Variables for foreach +class decls { + string name; +} + +def Decls : decls; + +class A<list<string> names> { + list<string> Names = names; +} + +class B<list<string> names> : A<!foreach(Decls.name, names, !strconcat(Decls.name, ", Sr."))>; + +class C<list<string> names> : A<!foreach(Decls.name, names, !strconcat(Decls.name, ", Jr."))>; + +class D<list<string> names> : A<!foreach(Decls.name, names, !subst("NAME", "John Smith", Decls.name))>; + +class Names { + list<string> values = ["Ken Griffey", "Seymour Cray"]; +} + +def People : Names; + +def Seniors : B<People.values>; +def Juniors : C<People.values>; +def Smiths : D<["NAME", "Jane Smith"]>; +def Unprocessed : D<People.values>; diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp index baff05c6ef..ade17026fb 100644 --- a/utils/TableGen/Record.cpp +++ b/utils/TableGen/Record.cpp @@ -678,6 +678,144 @@ std::string BinOpInit::getAsString() const { return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; } +static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, + Record *CurRec, MultiClass *CurMultiClass); + +static Init *EvaluateOperation(OpInit *RHSo, Init *LHS, Init *Arg, + RecTy *Type, Record *CurRec, + MultiClass *CurMultiClass) { + std::vector<Init *> NewOperands; + + TypedInit *TArg = dynamic_cast<TypedInit*>(Arg); + + // If this is a dag, recurse + if (TArg && TArg->getType()->getAsString() == "dag") { + Init *Result = ForeachHelper(LHS, Arg, RHSo, Type, + CurRec, CurMultiClass); + if (Result != 0) { + return Result; + } + else { + return 0; + } + } + + for (int i = 0; i < RHSo->getNumOperands(); ++i) { + OpInit *RHSoo = dynamic_cast<OpInit*>(RHSo->getOperand(i)); + + if (RHSoo) { + Init *Result = EvaluateOperation(RHSoo, LHS, Arg, + Type, CurRec, CurMultiClass); + if (Result != 0) { + NewOperands.push_back(Result); + } + else { + NewOperands.push_back(Arg); + } + } + else if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { + NewOperands.push_back(Arg); + } + else { + NewOperands.push_back(RHSo->getOperand(i)); + } + } + + // Now run the operator and use its result as the new leaf + OpInit *NewOp = RHSo->clone(NewOperands); + Init *NewVal = NewOp->Fold(CurRec, CurMultiClass); + if (NewVal != NewOp) { + delete NewOp; + return NewVal; + } + return 0; +} + +static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, + Record *CurRec, MultiClass *CurMultiClass) { + DagInit *MHSd = dynamic_cast<DagInit*>(MHS); + ListInit *MHSl = dynamic_cast<ListInit*>(MHS); + + DagRecTy *DagType = dynamic_cast<DagRecTy*>(Type); + ListRecTy *ListType = dynamic_cast<ListRecTy*>(Type); + + OpInit *RHSo = dynamic_cast<OpInit*>(RHS); + + if (!RHSo) { + cerr << "!foreach requires an operator\n"; + assert(0 && "No operator for !foreach"); + } + + TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS); + + if (!LHSt) { + cerr << "!foreach requires typed variable\n"; + assert(0 && "No typed variable for !foreach"); + } + + if (MHSd && DagType || MHSl && ListType) { + if (MHSd) { + Init *Val = MHSd->getOperator(); + Init *Result = EvaluateOperation(RHSo, LHS, Val, + Type, CurRec, CurMultiClass); + if (Result != 0) { + Val = Result; + } + + std::vector<std::pair<Init *, std::string> > args; + for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) { + Init *Arg; + std::string ArgName; + Arg = MHSd->getArg(i); + ArgName = MHSd->getArgName(i); + + // Process args + Init *Result = EvaluateOperation(RHSo, LHS, Arg, Type, + CurRec, CurMultiClass); + if (Result != 0) { + Arg = Result; + } + + // TODO: Process arg names + args.push_back(std::make_pair(Arg, ArgName)); + } + + return new DagInit(Val, "", args); + } + if (MHSl) { + std::vector<Init *> NewOperands; + std::vector<Init *> NewList(MHSl->begin(), MHSl->end()); + + for (ListInit::iterator li = NewList.begin(), + liend = NewList.end(); + li != liend; + ++li) { + Init *Item = *li; + NewOperands.clear(); + for(int i = 0; i < RHSo->getNumOperands(); ++i) { + // First, replace the foreach variable with the list item + if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { + NewOperands.push_back(Item); + } + else { + NewOperands.push_back(RHSo->getOperand(i)); + } + } + + // Now run the operator and use its result as the new list item + OpInit *NewOp = RHSo->clone(NewOperands); + Init *NewItem = NewOp->Fold(CurRec, CurMultiClass); + if (NewItem != NewOp) { + *li = NewItem; + delete NewOp; + } + } + return new ListInit(NewList); + } + } + return 0; +} + Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { switch (getOpcode()) { default: assert(0 && "Unknown binop"); @@ -729,144 +867,10 @@ Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { } case FOREACH: { - DagInit *MHSd = dynamic_cast<DagInit*>(MHS); - ListInit *MHSl = dynamic_cast<ListInit*>(MHS); - - DagRecTy *DagType = dynamic_cast<DagRecTy*>(getType()); - ListRecTy *ListType = dynamic_cast<ListRecTy*>(getType()); - - OpInit *RHSo = dynamic_cast<OpInit*>(RHS); - - if (!RHSo) { - cerr << "!foreach requires an operator\n"; - assert(0 && "No operator for !foreach"); - } - - TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS); - - if (!LHSt) { - cerr << "!foreach requires typed variable\n"; - assert(0 && "No typed variable for !foreach"); - } - - if (MHSd && DagType || MHSl && ListType) { - std::vector<Init *> NewOperands; - if (MHSd) { - Init *Val = MHSd->getOperator(); - TypedInit *TVal = dynamic_cast<TypedInit*>(Val); - - if (TVal && TVal->getType()->typeIsConvertibleTo(LHSt->getType())) { - - // First, replace the foreach variable with the DAG leaf - for (int i = 0; i < RHSo->getNumOperands(); ++i) { - if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { - NewOperands.push_back(Val); - } - else { - NewOperands.push_back(RHSo->getOperand(i)); - } - } - - // Now run the operator and use its result as the new leaf - OpInit *NewOp = RHSo->clone(NewOperands); - Val = NewOp->Fold(CurRec, CurMultiClass); - if (Val != NewOp) { - delete NewOp; - } - } - - std::vector<std::pair<Init *, std::string> > args; - for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) { - Init *Arg; - std::string ArgName; - Arg = MHSd->getArg(i); - ArgName = MHSd->getArgName(i); - - TypedInit *TArg = dynamic_cast<TypedInit*>(Arg); - - if (TArg && TArg->getType()->typeIsConvertibleTo(LHSt->getType())) { - NewOperands.clear(); - - // First, replace the foreach variable with the DAG leaf - for (int i = 0; i < RHSo->getNumOperands(); ++i) { - if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { - NewOperands.push_back(Arg); - } - else { - NewOperands.push_back(RHSo->getOperand(i)); - } - } - - // Now run the operator and use its result as the new leaf - OpInit *NewOp = RHSo->clone(NewOperands); - Arg = NewOp->Fold(CurRec, CurMultiClass); - if (Arg != NewOp) { - delete NewOp; - } - } - - if (LHSt->getType()->getAsString() == "string") { - NewOperands.clear(); - - // First, replace the foreach variable with the DAG leaf - for (int i = 0; i < RHSo->getNumOperands(); ++i) { - if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { - NewOperands.push_back(new StringInit(ArgName)); - } - else { - NewOperands.push_back(RHSo->getOperand(i)); - } - } - - // Now run the operator and use its result as the new leaf - OpInit *NewOp = RHSo->clone(NewOperands); - Init *ArgNameInit = NewOp->Fold(CurRec, CurMultiClass); - StringInit *SArgNameInit = dynamic_cast<StringInit*>(ArgNameInit); - if (SArgNameInit) { - ArgName = SArgNameInit->getValue(); - } - if (ArgNameInit != NewOp) { - delete NewOp; - } - delete ArgNameInit; - } - - args.push_back(std::make_pair(Arg, ArgName)); - } - - return new DagInit(Val, "", args); - } - if (MHSl) { - std::vector<Init *> NewList(MHSl->begin(), MHSl->end()); - - for (ListInit::iterator li = NewList.begin(), - liend = NewList.end(); - li != liend; - ++li) { - Init *Item = *li; - TypedInit *TItem = dynamic_cast<TypedInit*>(Item); - if (TItem && TItem->getType()->typeIsConvertibleTo(LHSt->getType())) { - // First, replace the foreach variable with the list item - for (int i = 0; i < RHSo->getNumOperands(); ++i) { - if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { - NewOperands.push_back(Item); - } - else { - NewOperands.push_back(RHSo->getOperand(i)); - } - } - - // Now run the operator and use its result as the new list item - OpInit *NewOp = RHSo->clone(NewOperands); - *li = NewOp->Fold(CurRec, CurMultiClass); - if (*li != NewOp) { - delete NewOp; - } - } - } - - return new ListInit(NewList); - } + Init *Result = ForeachHelper(LHS, MHS, RHS, getType(), + CurRec, CurMultiClass); + if (Result != 0) { + return Result; } break; } diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h index 59b6348a36..c37f6e6207 100644 --- a/utils/TableGen/Record.h +++ b/utils/TableGen/Record.h @@ -517,6 +517,33 @@ inline std::ostream &operator<<(std::ostream &OS, const Init &I) { I.print(OS); return OS; } +/// TypedInit - This is the common super-class of types that have a specific, +/// explicit, type. +/// +class TypedInit : public Init { + RecTy *Ty; +public: + explicit TypedInit(RecTy *T) : Ty(T) {} + + RecTy *getType() const { return Ty; } + + virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits); + virtual Init *convertInitListSlice(const std::vector<unsigned> &Elements); + + /// resolveBitReference - This method is used to implement + /// VarBitInit::resolveReferences. If the bit is able to be resolved, we + /// simply return the resolved value, otherwise we return null. + /// + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) = 0; + + /// resolveListElementReference - This method is used to implement + /// VarListElementInit::resolveReferences. If the list element is resolvable + /// now, we return the resolved value, otherwise we return null. + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) = 0; +}; + /// UnsetInit - ? - Represents an uninitialized value /// @@ -609,10 +636,10 @@ public: /// StringInit - "foo" - Represent an initialization by a string value. /// -class StringInit : public Init { +class StringInit : public TypedInit { std::string Value; public: - explicit StringInit(const std::string &V) : Value(V) {} + explicit StringInit(const std::string &V) : TypedInit(new StringRecTy), Value(V) {} const std::string &getValue() const { return Value; } @@ -621,6 +648,25 @@ public: } virtual std::string getAsString() const { return "\"" + Value + "\""; } + + /// resolveBitReference - This method is used to implement + /// VarBitInit::resolveReferences. If the bit is able to be resolved, we + /// simply return the resolved value, otherwise we return null. + /// + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) { + assert(0 && "Illegal bit reference off string"); + return 0; + } + + /// resolveListElementReference - This method is used to implement + /// VarListElementInit::resolveReferences. If the list element is resolvable + /// now, we return the resolved value, otherwise we return null. + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) { + assert(0 && "Illegal element reference off string"); + return 0; + } }; /// CodeInit - "[{...}]" - Represent a code fragment. @@ -684,33 +730,6 @@ public: }; -/// TypedInit - This is the common super-class of types that have a specific, -/// explicit, type. -/// -class TypedInit : public Init { - RecTy *Ty; -public: - explicit TypedInit(RecTy *T) : Ty(T) {} - - RecTy *getType() const { return Ty; } - - virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits); - virtual Init *convertInitListSlice(const std::vector<unsigned> &Elements); - - /// resolveBitReference - This method is used to implement - /// VarBitInit::resolveReferences. If the bit is able to be resolved, we - /// simply return the resolved value, otherwise we return null. - /// - virtual Init *resolveBitReference(Record &R, const RecordVal *RV, - unsigned Bit) = 0; - - /// resolveListElementReference - This method is used to implement - /// VarListElementInit::resolveReferences. If the list element is resolvable - /// now, we return the resolved value, otherwise we return null. - virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, - unsigned Elt) = 0; -}; - /// OpInit - Base class for operators /// class OpInit : public TypedInit { @@ -957,10 +976,10 @@ public: /// DefInit - AL - Represent a reference to a 'def' in the description /// -class DefInit : public Init { +class DefInit : public TypedInit { Record *Def; public: - explicit DefInit(Record *D) : Def(D) {} + explicit DefInit(Record *D) : TypedInit(new RecordRecTy(D)), Def(D) {} virtual Init *convertInitializerTo(RecTy *Ty) { return Ty->convertValue(this); @@ -974,6 +993,25 @@ public: virtual Init *getFieldInit(Record &R, const std::string &FieldName) const; virtual std::string getAsString() const; + + /// resolveBitReference - This method is used to implement + /// VarBitInit::resolveReferences. If the bit is able to be resolved, we + /// simply return the resolved value, otherwise we return null. + /// + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) { + assert(0 && "Illegal bit reference off def"); + return 0; + } + + /// resolveListElementReference - This method is used to implement + /// VarListElementInit::resolveReferences. If the list element is resolvable + /// now, we return the resolved value, otherwise we return null. + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) { + assert(0 && "Illegal element reference off def"); + return 0; + } }; @@ -1008,7 +1046,7 @@ public: /// to have at least one value then a (possibly empty) list of arguments. Each /// argument can have a name associated with it. /// -class DagInit : public Init { +class DagInit : public TypedInit { Init *Val; std::string ValName; std::vector<Init*> Args; @@ -1016,7 +1054,7 @@ class DagInit : public Init { public: DagInit(Init *V, std::string VN, const std::vector<std::pair<Init*, std::string> > &args) - : Val(V), ValName(VN) { + : TypedInit(new DagRecTy), Val(V), ValName(VN) { Args.reserve(args.size()); ArgNames.reserve(args.size()); for (unsigned i = 0, e = args.size(); i != e; ++i) { @@ -1026,7 +1064,7 @@ public: } DagInit(Init *V, std::string VN, const std::vector<Init*> &args, const std::vector<std::string> &argNames) - : Val(V), ValName(VN), Args(args), ArgNames(argNames) { + : TypedInit(new DagRecTy), Val(V), ValName(VN), Args(args), ArgNames(argNames) { } virtual Init *convertInitializerTo(RecTy *Ty) { @@ -1077,6 +1115,18 @@ public: inline size_t name_size () const { return ArgNames.size(); } inline bool name_empty() const { return ArgNames.empty(); } + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) { + assert(0 && "Illegal bit reference off dag"); + return 0; + } + + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) { + assert(0 && "Illegal element reference off dag"); + return 0; + } + }; //===----------------------------------------------------------------------===// diff --git a/utils/TableGen/TGLexer.cpp b/utils/TableGen/TGLexer.cpp index 264be4b98b..6215a7267f 100644 --- a/utils/TableGen/TGLexer.cpp +++ b/utils/TableGen/TGLexer.cpp @@ -448,7 +448,7 @@ tgtok::TokKind TGLexer::LexExclaim() { if (Len == 9 && !memcmp(Start, "strconcat", 9)) return tgtok::XStrConcat; if (Len == 10 && !memcmp(Start, "nameconcat", 10)) return tgtok::XNameConcat; if (Len == 5 && !memcmp(Start, "subst", 5)) return tgtok::XSubst; -// if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach; + if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach; if (Len == 4 && !memcmp(Start, "cast", 4)) return tgtok::XCast; return ReturnError(Start-1, "Unknown operator"); diff --git a/utils/TableGen/TGLexer.h b/utils/TableGen/TGLexer.h index f152df0a2f..3993e89d64 100644 --- a/utils/TableGen/TGLexer.h +++ b/utils/TableGen/TGLexer.h @@ -46,7 +46,7 @@ namespace tgtok { // !keywords. XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst, - //XForEach, + XForEach, // Integer value. IntVal, diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp index 967f5d0d5d..bc5d65eea5 100644 --- a/utils/TableGen/TGParser.cpp +++ b/utils/TableGen/TGParser.cpp @@ -792,7 +792,7 @@ Init *TGParser::ParseOperation(Record *CurRec) { return (new BinOpInit(Code, LHS, RHS, Type))->Fold(CurRec, CurMultiClass); } -// case tgtok::XForEach: + case tgtok::XForEach: case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' TernOpInit::TernaryOp Code; RecTy *Type = 0; @@ -802,9 +802,9 @@ Init *TGParser::ParseOperation(Record *CurRec) { Lex.Lex(); // eat the operation switch (LexCode) { default: assert(0 && "Unhandled code!"); - //case tgtok::XForEach: - //Code = TernOpInit::FOREACH; - //break; + case tgtok::XForEach: + Code = TernOpInit::FOREACH; + break; case tgtok::XSubst: Code = TernOpInit::SUBST; break; @@ -844,15 +844,15 @@ Init *TGParser::ParseOperation(Record *CurRec) { switch (LexCode) { default: assert(0 && "Unhandled code!"); - //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::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) { @@ -1079,7 +1079,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec) { case tgtok::XSHL: case tgtok::XStrConcat: case tgtok::XNameConcat: // Value ::= !binop '(' Value ',' Value ')' - // case tgtok::XForEach: + case tgtok::XForEach: case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' return ParseOperation(CurRec); break; |