From: Javed Absar Date: Tue, 5 Mar 2019 17:16:07 +0000 (+0000) Subject: TableGen: Allow lists to be concatenated through '#' X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=60e3f9f86c7ae0d7838ae3c30976596454b899b7;p=llvm TableGen: Allow lists to be concatenated through '#' Currently one can concatenate strings using hash(#), but not lists, although that would be a natural thing to do. This patch allows one to write something like: def : A; simply as : def : A<[1,2] # [3,4]>; This was missing feature was highlighted by Nicolai at FOSDEM talk. Reviewed by: nhaehnle, hfinkel Differential Revision: https://reviews.llvm.org/D58895 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@355414 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/TableGen/Record.h b/include/llvm/TableGen/Record.h index 2cb0548a4ca..17b63ec87e9 100644 --- a/include/llvm/TableGen/Record.h +++ b/include/llvm/TableGen/Record.h @@ -820,6 +820,7 @@ public: static BinOpInit *get(BinaryOp opc, Init *lhs, Init *rhs, RecTy *Type); static Init *getStrConcat(Init *lhs, Init *rhs); + static Init *getListConcat(TypedInit *lhs, Init *rhs); void Profile(FoldingSetNodeID &ID) const; diff --git a/lib/TableGen/Record.cpp b/lib/TableGen/Record.cpp index 480a002b64a..4222a0b57fb 100644 --- a/lib/TableGen/Record.cpp +++ b/lib/TableGen/Record.cpp @@ -856,6 +856,24 @@ Init *BinOpInit::getStrConcat(Init *I0, Init *I1) { return BinOpInit::get(BinOpInit::STRCONCAT, I0, I1, StringRecTy::get()); } +static ListInit *ConcatListInits(const ListInit *LHS, + const ListInit *RHS) { + SmallVector Args; + Args.insert(Args.end(), LHS->begin(), LHS->end()); + Args.insert(Args.end(), RHS->begin(), RHS->end()); + return ListInit::get(Args, LHS->getElementType()); +} + +Init *BinOpInit::getListConcat(TypedInit *LHS, Init *RHS) { + assert(isa(LHS->getType()) && "First arg must be a list"); + + // Shortcut for the common case of concatenating two lists. + if (const ListInit *LHSList = dyn_cast(LHS)) + if (const ListInit *RHSList = dyn_cast(RHS)) + return ConcatListInits(LHSList, RHSList); + return BinOpInit::get(BinOpInit::LISTCONCAT, LHS, RHS, LHS->getType()); +} + Init *BinOpInit::Fold(Record *CurRec) const { switch (getOpcode()) { case CONCAT: { diff --git a/lib/TableGen/TGParser.cpp b/lib/TableGen/TGParser.cpp index 58343bda275..90c9b390e10 100644 --- a/lib/TableGen/TGParser.cpp +++ b/lib/TableGen/TGParser.cpp @@ -2119,16 +2119,31 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { case tgtok::paste: SMLoc PasteLoc = Lex.getLoc(); - - // Create a !strconcat() operation, first casting each operand to - // a string if necessary. - TypedInit *LHS = dyn_cast(Result); if (!LHS) { Error(PasteLoc, "LHS of paste is not typed!"); return nullptr; } + // Check if it's a 'listA # listB' + if (isa(LHS->getType())) { + Lex.Lex(); // Eat the '#'. + + switch (Lex.getCode()) { + case tgtok::colon: + case tgtok::semi: + case tgtok::l_brace: + Result = LHS; // trailing paste, ignore. + break; + default: + Init *RHSResult = ParseValue(CurRec, ItemType, ParseNameMode); + Result = BinOpInit::getListConcat(LHS, RHSResult); + } + break; + } + + // Create a !strconcat() operation, first casting each operand to + // a string if necessary. if (LHS->getType() != StringRecTy::get()) { LHS = dyn_cast( UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get()) diff --git a/test/TableGen/listpaste.td b/test/TableGen/listpaste.td new file mode 100644 index 00000000000..3ce761d2955 --- /dev/null +++ b/test/TableGen/listpaste.td @@ -0,0 +1,40 @@ +// RUN: llvm-tblgen %s | FileCheck %s + +// CHECK: class A { +// CHECK: list lst = !listconcat([], !if(A:x, [], [4])); +// CHECK: } +class A { + list lst = [] # !if(x, [], [4]); +} + +// CHECK: class A1 A1:l = ?> { +// CHECK: list A1List = A1:l; +// CHECK: } +class A1 l> { + list A1List = l; +} + +// CHECK: def A0 { +// CHECK: list lst = [4]; +// CHECK: } +def A0 : A<0>; + +// CHECK: def A1 { +// CHECK: list lst = []; +// CHECK: } +def A1 : A<1>; + +// CHECK: def A1_0 { +// CHECK: list A1List = [1, 2, 3, 4]; +// CHECK: } +def A1_0 : A1<[1,2] # [3,4]>; + +// CHECK: def A1_1 { +// CHECK: list A1List = [1, 2]; +// CHECK: } +def A1_1 : A1<[] # [1,2]>; + +// CHECK: def A1_2 { // A1 +// CHECK: list A1List = [1, 2]; +// CHECK: } +def A1_2 : A1<[1,2] # []>;