Skip to content

Commit

Permalink
TableGen: Allow lists to be concatenated through '#'
Browse files Browse the repository at this point in the history
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<!listconcat([1,2], [3,4])>;
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

llvm-svn: 355414
  • Loading branch information
javedabsar committed Mar 5, 2019
1 parent 05812b6 commit 34d3b80
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 4 deletions.
1 change: 1 addition & 0 deletions llvm/include/llvm/TableGen/Record.h
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,7 @@ class BinOpInit : public OpInit, public FoldingSetNode {
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;

Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/TableGen/Record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Init *, 8> 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<ListRecTy>(LHS->getType()) && "First arg must be a list");

// Shortcut for the common case of concatenating two lists.
if (const ListInit *LHSList = dyn_cast<ListInit>(LHS))
if (const ListInit *RHSList = dyn_cast<ListInit>(RHS))
return ConcatListInits(LHSList, RHSList);
return BinOpInit::get(BinOpInit::LISTCONCAT, LHS, RHS, LHS->getType());
}

Init *BinOpInit::Fold(Record *CurRec) const {
switch (getOpcode()) {
case CONCAT: {
Expand Down
23 changes: 19 additions & 4 deletions llvm/lib/TableGen/TGParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypedInit>(Result);
if (!LHS) {
Error(PasteLoc, "LHS of paste is not typed!");
return nullptr;
}

// Check if it's a 'listA # listB'
if (isa<ListRecTy>(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<TypedInit>(
UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get())
Expand Down
40 changes: 40 additions & 0 deletions llvm/test/TableGen/listpaste.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: llvm-tblgen %s | FileCheck %s

// CHECK: class A<bit A:x = ?> {
// CHECK: list<int> lst = !listconcat([], !if(A:x, [], [4]));
// CHECK: }
class A<bit x> {
list<int> lst = [] # !if(x, [], [4]);
}

// CHECK: class A1<list<int> A1:l = ?> {
// CHECK: list<int> A1List = A1:l;
// CHECK: }
class A1<list<int> l> {
list<int> A1List = l;
}

// CHECK: def A0 {
// CHECK: list<int> lst = [4];
// CHECK: }
def A0 : A<0>;

// CHECK: def A1 {
// CHECK: list<int> lst = [];
// CHECK: }
def A1 : A<1>;

// CHECK: def A1_0 {
// CHECK: list<int> A1List = [1, 2, 3, 4];
// CHECK: }
def A1_0 : A1<[1,2] # [3,4]>;

// CHECK: def A1_1 {
// CHECK: list<int> A1List = [1, 2];
// CHECK: }
def A1_1 : A1<[] # [1,2]>;

// CHECK: def A1_2 { // A1
// CHECK: list<int> A1List = [1, 2];
// CHECK: }
def A1_2 : A1<[1,2] # []>;

0 comments on commit 34d3b80

Please sign in to comment.