| // RUN: llvm-tblgen %s | FileCheck %s |
| |
| // Test 'let append' and 'let prepend' syntax in body items. |
| |
| def op; |
| |
| class Base { |
| list<int> items = [1, 2]; |
| string text = "hello"; |
| dag d = (op); |
| } |
| |
| class WithCode { |
| code body = [{ int x = 0; }]; |
| } |
| |
| class WithUnset { |
| list<int> vals = ?; |
| string msg = ?; |
| } |
| |
| // Multi-level inheritance accumulation. |
| class Middle : Base { |
| let append items = [3]; |
| let append text = " world"; |
| } |
| |
| // Multiple inheritance classes. |
| class BaseA { |
| list<int> items = [1, 2]; |
| string text = "a"; |
| } |
| |
| class BaseB { |
| list<int> items = [3, 4]; |
| string text = "b"; |
| } |
| |
| // Diamond inheritance classes. |
| class DiamondBase { |
| list<int> items = [1]; |
| } |
| |
| class Left : DiamondBase { |
| let append items = [2]; // items = [1, 2] |
| } |
| |
| class Right : DiamondBase { |
| let append items = [3]; // items = [1, 3] |
| } |
| |
| // Template argument class. |
| class Parameterized<list<int> init> { |
| list<int> items = init; |
| } |
| |
| // Multiclass with append/prepend in body. |
| multiclass MC<list<int> extra> { |
| def _a : Base { |
| let append items = extra; |
| } |
| def _b : Base { |
| let prepend items = extra; |
| } |
| } |
| |
| // Test that 'append' and 'prepend' can be used as field names |
| // (contextual keywords, not reserved). |
| class HasAppendField { |
| list<int> append = [1, 2]; |
| list<int> prepend = [3, 4]; |
| int other = 0; |
| } |
| |
| // Test that scalar fields named 'append'/'prepend' work with plain let. |
| class HasScalarAppendField { |
| int append = 0; |
| int prepend = 0; |
| } |
| |
| // --- Definitions (CHECK lines in alphabetical order of def names) --- |
| |
| // CHECK: def AppendCode |
| // CHECK: code body = [{ int x = 0; int y = 1; }] |
| def AppendCode : WithCode { |
| let append body = [{ int y = 1; }]; |
| } |
| |
| // CHECK: def AppendDag |
| // CHECK: dag d = (op 3:$a); |
| def AppendDag : Base { |
| let append d = (op 3:$a); |
| } |
| |
| // CHECK: def AppendList |
| // CHECK: list<int> items = [1, 2, 3, 4]; |
| def AppendList : Base { |
| let append items = [3, 4]; |
| } |
| |
| // CHECK: def AppendString |
| // CHECK: string text = "hello world"; |
| def AppendString : Base { |
| let append text = " world"; |
| } |
| |
| // CHECK: def AppendUnset |
| // CHECK: list<int> vals = [1]; |
| // CHECK: string msg = "hi"; |
| def AppendUnset : WithUnset { |
| let append vals = [1]; |
| let append msg = "hi"; |
| } |
| |
| // Test 'let append = ...' on a scalar (int) field named 'append'. |
| // CHECK: def AssignScalarAppend |
| // CHECK: int append = 42; |
| // CHECK: int prepend = 99; |
| def AssignScalarAppend : HasScalarAppendField { |
| let append = 42; |
| let prepend = 99; |
| } |
| |
| // Test sequential append + prepend on the same field. |
| // CHECK: def Both |
| // CHECK: list<int> items = [0, 1, 2, 3]; |
| def Both : Base { |
| let append items = [3]; |
| let prepend items = [0]; |
| } |
| |
| // Test 'let append append' where the second 'append' is the field name. |
| // CHECK: def ContextualKeyword |
| // CHECK: list<int> append = [1, 2, 5]; |
| // CHECK: list<int> prepend = [0, 3, 4]; |
| // CHECK: int other = 0; |
| def ContextualKeyword : HasAppendField { |
| let append append = [5]; |
| let prepend prepend = [0]; |
| } |
| |
| // Test diamond inheritance: Right is the last parent, so only Right's |
| // accumulated value survives. Left's append is lost. |
| // CHECK: def Diamond |
| // CHECK: list<int> items = [1, 3, 4]; |
| def Diamond : Left, Right { |
| let append items = [4]; |
| } |
| |
| // Test 'let append = ...' where 'append' is the field name (no mode keyword). |
| // CHECK: def FieldNamedAppend |
| // CHECK: list<int> append = [10, 20]; |
| // CHECK: list<int> prepend = [30, 40]; |
| // CHECK: int other = 5; |
| def FieldNamedAppend : HasAppendField { |
| let append = [10, 20]; |
| let prepend = [30, 40]; |
| let other = 5; |
| } |
| |
| // Test let append on a field set by a template argument. |
| // CHECK: def FromTemplateArg |
| // CHECK: list<int> items = [1, 2, 3]; |
| def FromTemplateArg : Parameterized<[1, 2]> { |
| let append items = [3]; |
| } |
| |
| // Test let append in multiclass body with defm. |
| // CHECK: def MCTest_a |
| // CHECK: list<int> items = [1, 2, 10, 20]; |
| // CHECK: def MCTest_b |
| // CHECK: list<int> items = [10, 20, 1, 2]; |
| defm MCTest : MC<[10, 20]>; |
| |
| // Test multiple inheritance: last parent class wins, then append applies. |
| // CHECK: def MultiInherit |
| // CHECK: list<int> items = [3, 4, 5]; |
| // CHECK: string text = "b!"; |
| def MultiInherit : BaseA, BaseB { |
| let append items = [5]; |
| let append text = "!"; |
| } |
| |
| // CHECK: def MultiLevel |
| // CHECK: list<int> items = [1, 2, 3, 4]; |
| // CHECK: string text = "hello world!"; |
| def MultiLevel : Middle { |
| let append items = [4]; |
| let append text = "!"; |
| } |
| |
| // CHECK: def OverrideAfterAppend |
| // CHECK: list<int> items = [10]; |
| def OverrideAfterAppend : Base { |
| let append items = [3]; |
| let items = [10]; |
| } |
| |
| // CHECK: def PrependDag |
| // CHECK: dag d = (op 0:$z); |
| def PrependDag : Base { |
| let prepend d = (op 0:$z); |
| } |
| |
| // CHECK: def PrependList |
| // CHECK: list<int> items = [0, 1, 2]; |
| def PrependList : Base { |
| let prepend items = [0]; |
| } |
| |
| // CHECK: def PrependString |
| // CHECK: string text = "say hello"; |
| def PrependString : Base { |
| let prepend text = "say "; |
| } |
| |
| // Test prepend on unset fields. |
| // CHECK: def PrependUnset |
| // CHECK: list<int> vals = [1]; |
| // CHECK: string msg = "hi"; |
| def PrependUnset : WithUnset { |
| let prepend vals = [1]; |
| let prepend msg = "hi"; |
| } |