Skip to content

Commit 3cfdc3f

Browse files
committed
[TableGen] Fix concatenation of subreg and artificial subregs
When CoveredBySubRegs is true and a sub-register consists of two parts; a regular subreg and an artificial subreg, then TableGen should consider both as a concatenation of subregs. This happens for example when a 64-bit register 'D0' consists of 32-bit 'S0_HI' (artificial) and 'S0', and 'S0' consists of (16-bit) 'H0_HI' (artificial) and 'H0'. Then the concatenation should be: S0_HI, H0_HI, H0.
1 parent 8cb11b0 commit 3cfdc3f

File tree

2 files changed

+336
-6
lines changed

2 files changed

+336
-6
lines changed

llvm/test/TableGen/ArtificialSubregs.td

Lines changed: 332 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
// RUN: not llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK
1+
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK
22
include "llvm/Target/Target.td"
33

4-
// CHECK: error: No SubRegIndex for S0_S1 in D0_D1_D2
5-
// CHECK-NEXT: def DTuples3 : RegisterTuples<[dsub0, dsub1, dsub2],
6-
74
class MyReg<string n, list<Register> subregs = []>
85
: Register<n> {
96
let Namespace = "Test";
@@ -77,3 +74,334 @@ def DTuples3 : RegisterTuples<[dsub0, dsub1, dsub2],
7774
def DTuplesRC3 : MyClass<192, [untyped], (add DTuples3)>;
7875

7976
def TestTarget : Target;
77+
78+
// CHECK: RegisterClass SRegs:
79+
// CHECK-NEXT: SpillSize: { Default:32 }
80+
// CHECK-NEXT: SpillAlignment: { Default:32 }
81+
// CHECK-NEXT: NumRegs: 3
82+
// CHECK-NEXT: LaneMask: 0000000000000001
83+
// CHECK-NEXT: HasDisjunctSubRegs: 0
84+
// CHECK-NEXT: CoveredBySubRegs: 0
85+
// CHECK-NEXT: Allocatable: 1
86+
// CHECK-NEXT: AllocationPriority: 0
87+
// CHECK-NEXT: BaseClassOrder: None
88+
// CHECK-NEXT: Regs: S0 S1 S2
89+
// CHECK-NEXT: SubClasses: SRegs
90+
// CHECK-NEXT: SuperClasses:
91+
// CHECK-NEXT: RegisterClass DRegs:
92+
// CHECK-NEXT: SpillSize: { Default:64 }
93+
// CHECK-NEXT: SpillAlignment: { Default:64 }
94+
// CHECK-NEXT: NumRegs: 3
95+
// CHECK-NEXT: LaneMask: 0000000000000008
96+
// CHECK-NEXT: HasDisjunctSubRegs: 1
97+
// CHECK-NEXT: CoveredBySubRegs: 1
98+
// CHECK-NEXT: Allocatable: 1
99+
// CHECK-NEXT: AllocationPriority: 0
100+
// CHECK-NEXT: BaseClassOrder: None
101+
// CHECK-NEXT: Regs: D0 D1 D2
102+
// CHECK-NEXT: SubClasses: DRegs
103+
// CHECK-NEXT: SuperClasses:
104+
// CHECK-NEXT: RegisterClass STuplesRC2:
105+
// CHECK-NEXT: SpillSize: { Default:64 }
106+
// CHECK-NEXT: SpillAlignment: { Default:64 }
107+
// CHECK-NEXT: NumRegs: 2
108+
// CHECK-NEXT: LaneMask: 0000000000000030
109+
// CHECK-NEXT: HasDisjunctSubRegs: 1
110+
// CHECK-NEXT: CoveredBySubRegs: 1
111+
// CHECK-NEXT: Allocatable: 1
112+
// CHECK-NEXT: AllocationPriority: 0
113+
// CHECK-NEXT: BaseClassOrder: None
114+
// CHECK-NEXT: Regs: S0_S1 S1_S2
115+
// CHECK-NEXT: SubClasses: STuplesRC2
116+
// CHECK-NEXT: SuperClasses:
117+
// CHECK-NEXT: RegisterClass STuplesRC3:
118+
// CHECK-NEXT: SpillSize: { Default:96 }
119+
// CHECK-NEXT: SpillAlignment: { Default:96 }
120+
// CHECK-NEXT: NumRegs: 1
121+
// CHECK-NEXT: LaneMask: 0000000000000070
122+
// CHECK-NEXT: HasDisjunctSubRegs: 1
123+
// CHECK-NEXT: CoveredBySubRegs: 1
124+
// CHECK-NEXT: Allocatable: 1
125+
// CHECK-NEXT: AllocationPriority: 0
126+
// CHECK-NEXT: BaseClassOrder: None
127+
// CHECK-NEXT: Regs: S0_S1_S2
128+
// CHECK-NEXT: SubClasses: STuplesRC3
129+
// CHECK-NEXT: SuperClasses:
130+
// CHECK-NEXT: RegisterClass QRegs:
131+
// CHECK-NEXT: SpillSize: { Default:128 }
132+
// CHECK-NEXT: SpillAlignment: { Default:128 }
133+
// CHECK-NEXT: NumRegs: 3
134+
// CHECK-NEXT: LaneMask: 0000000000000088
135+
// CHECK-NEXT: HasDisjunctSubRegs: 1
136+
// CHECK-NEXT: CoveredBySubRegs: 1
137+
// CHECK-NEXT: Allocatable: 1
138+
// CHECK-NEXT: AllocationPriority: 0
139+
// CHECK-NEXT: BaseClassOrder: None
140+
// CHECK-NEXT: Regs: Q0 Q1 Q2
141+
// CHECK-NEXT: SubClasses: QRegs
142+
// CHECK-NEXT: SuperClasses:
143+
// CHECK-NEXT: RegisterClass DTuplesRC2:
144+
// CHECK-NEXT: SpillSize: { Default:128 }
145+
// CHECK-NEXT: SpillAlignment: { Default:128 }
146+
// CHECK-NEXT: NumRegs: 2
147+
// CHECK-NEXT: LaneMask: 00000000000001A8
148+
// CHECK-NEXT: HasDisjunctSubRegs: 1
149+
// CHECK-NEXT: CoveredBySubRegs: 1
150+
// CHECK-NEXT: Allocatable: 1
151+
// CHECK-NEXT: AllocationPriority: 0
152+
// CHECK-NEXT: BaseClassOrder: None
153+
// CHECK-NEXT: Regs: D0_D1 D1_D2
154+
// CHECK-NEXT: SubClasses: DTuplesRC2
155+
// CHECK-NEXT: SuperClasses:
156+
// CHECK-NEXT: RegisterClass DTuplesRC3:
157+
// CHECK-NEXT: SpillSize: { Default:192 }
158+
// CHECK-NEXT: SpillAlignment: { Default:192 }
159+
// CHECK-NEXT: NumRegs: 1
160+
// CHECK-NEXT: LaneMask: 00000000000003E8
161+
// CHECK-NEXT: HasDisjunctSubRegs: 1
162+
// CHECK-NEXT: CoveredBySubRegs: 1
163+
// CHECK-NEXT: Allocatable: 1
164+
// CHECK-NEXT: AllocationPriority: 0
165+
// CHECK-NEXT: BaseClassOrder: None
166+
// CHECK-NEXT: Regs: D0_D1_D2
167+
// CHECK-NEXT: SubClasses: DTuplesRC3
168+
// CHECK-NEXT: SuperClasses:
169+
// CHECK-NEXT: SubRegIndex dsub:
170+
// CHECK-NEXT: LaneMask: 0000000000000088
171+
// CHECK-NEXT: AllSuperRegsCovered: 1
172+
// CHECK-NEXT: Offset: { Default:0 }
173+
// CHECK-NEXT: Size: { Default:64 }
174+
// CHECK-NEXT: SubRegIndex dsub0:
175+
// CHECK-NEXT: LaneMask: 0000000000000088
176+
// CHECK-NEXT: AllSuperRegsCovered: 1
177+
// CHECK-NEXT: Offset: { Default:0 }
178+
// CHECK-NEXT: Size: { Default:64 }
179+
// CHECK-NEXT: SubRegIndex dsub1:
180+
// CHECK-NEXT: LaneMask: 0000000000000120
181+
// CHECK-NEXT: AllSuperRegsCovered: 1
182+
// CHECK-NEXT: Offset: { Default:0 }
183+
// CHECK-NEXT: Size: { Default:64 }
184+
// CHECK-NEXT: SubRegIndex dsub2:
185+
// CHECK-NEXT: LaneMask: 0000000000000240
186+
// CHECK-NEXT: AllSuperRegsCovered: 1
187+
// CHECK-NEXT: Offset: { Default:0 }
188+
// CHECK-NEXT: Size: { Default:64 }
189+
// CHECK-NEXT: SubRegIndex dsub_hi:
190+
// CHECK-NEXT: LaneMask: 0000000000000001
191+
// CHECK-NEXT: AllSuperRegsCovered: 1
192+
// CHECK-NEXT: Offset: { Default:64 }
193+
// CHECK-NEXT: Size: { Default:64 }
194+
// CHECK-NEXT: SubRegIndex qsub:
195+
// CHECK-NEXT: LaneMask: 0000000000000002
196+
// CHECK-NEXT: AllSuperRegsCovered: 1
197+
// CHECK-NEXT: Offset: { Default:0 }
198+
// CHECK-NEXT: Size: { Default:128 }
199+
// CHECK-NEXT: SubRegIndex qsub_hi:
200+
// CHECK-NEXT: LaneMask: 0000000000000004
201+
// CHECK-NEXT: AllSuperRegsCovered: 1
202+
// CHECK-NEXT: Offset: { Default:128 }
203+
// CHECK-NEXT: Size: { Default:128 }
204+
// CHECK-NEXT: SubRegIndex ssub:
205+
// CHECK-NEXT: LaneMask: 0000000000000008
206+
// CHECK-NEXT: AllSuperRegsCovered: 1
207+
// CHECK-NEXT: Offset: { Default:0 }
208+
// CHECK-NEXT: Size: { Default:32 }
209+
// CHECK-NEXT: SubRegIndex ssub0:
210+
// CHECK-NEXT: LaneMask: 0000000000000010
211+
// CHECK-NEXT: AllSuperRegsCovered: 1
212+
// CHECK-NEXT: Offset: { Default:0 }
213+
// CHECK-NEXT: Size: { Default:32 }
214+
// CHECK-NEXT: SubRegIndex ssub1:
215+
// CHECK-NEXT: LaneMask: 0000000000000020
216+
// CHECK-NEXT: AllSuperRegsCovered: 1
217+
// CHECK-NEXT: Offset: { Default:0 }
218+
// CHECK-NEXT: Size: { Default:32 }
219+
// CHECK-NEXT: SubRegIndex ssub2:
220+
// CHECK-NEXT: LaneMask: 0000000000000040
221+
// CHECK-NEXT: AllSuperRegsCovered: 1
222+
// CHECK-NEXT: Offset: { Default:0 }
223+
// CHECK-NEXT: Size: { Default:32 }
224+
// CHECK-NEXT: SubRegIndex ssub_hi:
225+
// CHECK-NEXT: LaneMask: 0000000000000080
226+
// CHECK-NEXT: AllSuperRegsCovered: 1
227+
// CHECK-NEXT: Offset: { Default:32 }
228+
// CHECK-NEXT: Size: { Default:32 }
229+
// CHECK-NEXT: SubRegIndex dsub1_then_ssub_hi:
230+
// CHECK-NEXT: LaneMask: 0000000000000100
231+
// CHECK-NEXT: AllSuperRegsCovered: 1
232+
// CHECK-NEXT: Offset: { Default:32 }
233+
// CHECK-NEXT: Size: { Default:32 }
234+
// CHECK-NEXT: SubRegIndex dsub2_then_ssub_hi:
235+
// CHECK-NEXT: LaneMask: 0000000000000200
236+
// CHECK-NEXT: AllSuperRegsCovered: 1
237+
// CHECK-NEXT: Offset: { Default:32 }
238+
// CHECK-NEXT: Size: { Default:32 }
239+
// CHECK-NEXT: SubRegIndex ssub_ssub1:
240+
// CHECK-NEXT: LaneMask: 0000000000000028
241+
// CHECK-NEXT: AllSuperRegsCovered: 1
242+
// CHECK-NEXT: Offset: { Default:65535 }
243+
// CHECK-NEXT: Size: { Default:64 }
244+
// CHECK-NEXT: SubRegIndex dsub0_dsub1:
245+
// CHECK-NEXT: LaneMask: 00000000000001A8
246+
// CHECK-NEXT: AllSuperRegsCovered: 1
247+
// CHECK-NEXT: Offset: { Default:65535 }
248+
// CHECK-NEXT: Size: { Default:128 }
249+
// CHECK-NEXT: SubRegIndex dsub1_dsub2:
250+
// CHECK-NEXT: LaneMask: 0000000000000360
251+
// CHECK-NEXT: AllSuperRegsCovered: 1
252+
// CHECK-NEXT: Offset: { Default:65535 }
253+
// CHECK-NEXT: Size: { Default:128 }
254+
// CHECK-NEXT: SubRegIndex ssub_ssub1_ssub2:
255+
// CHECK-NEXT: LaneMask: 0000000000000068
256+
// CHECK-NEXT: AllSuperRegsCovered: 1
257+
// CHECK-NEXT: Offset: { Default:65535 }
258+
// CHECK-NEXT: Size: { Default:96 }
259+
// CHECK-NEXT: SubRegIndex ssub1_ssub2:
260+
// CHECK-NEXT: LaneMask: 0000000000000060
261+
// CHECK-NEXT: AllSuperRegsCovered: 1
262+
// CHECK-NEXT: Offset: { Default:65535 }
263+
// CHECK-NEXT: Size: { Default:64 }
264+
// CHECK-NEXT: SubRegIndex ssub0_ssub1:
265+
// CHECK-NEXT: LaneMask: 0000000000000030
266+
// CHECK-NEXT: AllSuperRegsCovered: 1
267+
// CHECK-NEXT: Offset: { Default:65535 }
268+
// CHECK-NEXT: Size: { Default:64 }
269+
// CHECK-NEXT: Register D0:
270+
// CHECK-NEXT: CostPerUse: 0
271+
// CHECK-NEXT: CoveredBySubregs: 1
272+
// CHECK-NEXT: HasDisjunctSubRegs: 1
273+
// CHECK-NEXT: SubReg ssub = S0
274+
// CHECK-NEXT: SubReg ssub_hi = S0_HI
275+
// CHECK-NEXT: Register D1:
276+
// CHECK-NEXT: CostPerUse: 0
277+
// CHECK-NEXT: CoveredBySubregs: 1
278+
// CHECK-NEXT: HasDisjunctSubRegs: 1
279+
// CHECK-NEXT: SubReg ssub = S1
280+
// CHECK-NEXT: SubReg ssub_hi = S1_HI
281+
// CHECK-NEXT: Register D2:
282+
// CHECK-NEXT: CostPerUse: 0
283+
// CHECK-NEXT: CoveredBySubregs: 1
284+
// CHECK-NEXT: HasDisjunctSubRegs: 1
285+
// CHECK-NEXT: SubReg ssub = S2
286+
// CHECK-NEXT: SubReg ssub_hi = S2_HI
287+
// CHECK-NEXT: Register Q0:
288+
// CHECK-NEXT: CostPerUse: 0
289+
// CHECK-NEXT: CoveredBySubregs: 1
290+
// CHECK-NEXT: HasDisjunctSubRegs: 1
291+
// CHECK-NEXT: SubReg dsub = D0
292+
// CHECK-NEXT: SubReg dsub_hi = D0_HI
293+
// CHECK-NEXT: SubReg ssub = S0
294+
// CHECK-NEXT: SubReg ssub_hi = S0_HI
295+
// CHECK-NEXT: Register Q1:
296+
// CHECK-NEXT: CostPerUse: 0
297+
// CHECK-NEXT: CoveredBySubregs: 1
298+
// CHECK-NEXT: HasDisjunctSubRegs: 1
299+
// CHECK-NEXT: SubReg dsub = D1
300+
// CHECK-NEXT: SubReg dsub_hi = D1_HI
301+
// CHECK-NEXT: SubReg ssub = S1
302+
// CHECK-NEXT: SubReg ssub_hi = S1_HI
303+
// CHECK-NEXT: Register Q2:
304+
// CHECK-NEXT: CostPerUse: 0
305+
// CHECK-NEXT: CoveredBySubregs: 1
306+
// CHECK-NEXT: HasDisjunctSubRegs: 1
307+
// CHECK-NEXT: SubReg dsub = D2
308+
// CHECK-NEXT: SubReg dsub_hi = D2_HI
309+
// CHECK-NEXT: SubReg ssub = S2
310+
// CHECK-NEXT: SubReg ssub_hi = S2_HI
311+
// CHECK-NEXT: Register S0:
312+
// CHECK-NEXT: CostPerUse: 0
313+
// CHECK-NEXT: CoveredBySubregs: 0
314+
// CHECK-NEXT: HasDisjunctSubRegs: 0
315+
// CHECK-NEXT: Register S1:
316+
// CHECK-NEXT: CostPerUse: 0
317+
// CHECK-NEXT: CoveredBySubregs: 0
318+
// CHECK-NEXT: HasDisjunctSubRegs: 0
319+
// CHECK-NEXT: Register S2:
320+
// CHECK-NEXT: CostPerUse: 0
321+
// CHECK-NEXT: CoveredBySubregs: 0
322+
// CHECK-NEXT: HasDisjunctSubRegs: 0
323+
// CHECK-NEXT: Register D0_HI:
324+
// CHECK-NEXT: CostPerUse: 0
325+
// CHECK-NEXT: CoveredBySubregs: 0
326+
// CHECK-NEXT: HasDisjunctSubRegs: 0
327+
// CHECK-NEXT: Register D1_HI:
328+
// CHECK-NEXT: CostPerUse: 0
329+
// CHECK-NEXT: CoveredBySubregs: 0
330+
// CHECK-NEXT: HasDisjunctSubRegs: 0
331+
// CHECK-NEXT: Register D2_HI:
332+
// CHECK-NEXT: CostPerUse: 0
333+
// CHECK-NEXT: CoveredBySubregs: 0
334+
// CHECK-NEXT: HasDisjunctSubRegs: 0
335+
// CHECK-NEXT: Register S0_HI:
336+
// CHECK-NEXT: CostPerUse: 0
337+
// CHECK-NEXT: CoveredBySubregs: 0
338+
// CHECK-NEXT: HasDisjunctSubRegs: 0
339+
// CHECK-NEXT: Register S1_HI:
340+
// CHECK-NEXT: CostPerUse: 0
341+
// CHECK-NEXT: CoveredBySubregs: 0
342+
// CHECK-NEXT: HasDisjunctSubRegs: 0
343+
// CHECK-NEXT: Register S2_HI:
344+
// CHECK-NEXT: CostPerUse: 0
345+
// CHECK-NEXT: CoveredBySubregs: 0
346+
// CHECK-NEXT: HasDisjunctSubRegs: 0
347+
// CHECK-NEXT: Register D0_D1:
348+
// CHECK-NEXT: CostPerUse: 0
349+
// CHECK-NEXT: CoveredBySubregs: 1
350+
// CHECK-NEXT: HasDisjunctSubRegs: 1
351+
// CHECK-NEXT: SubReg dsub0 = D0
352+
// CHECK-NEXT: SubReg dsub1 = D1
353+
// CHECK-NEXT: SubReg ssub = S0
354+
// CHECK-NEXT: SubReg ssub1 = S1
355+
// CHECK-NEXT: SubReg ssub_hi = S0_HI
356+
// CHECK-NEXT: SubReg dsub1_then_ssub_hi = S1_HI
357+
// CHECK-NEXT: SubReg ssub_ssub1 = S0_S1
358+
// CHECK-NEXT: Register D1_D2:
359+
// CHECK-NEXT: CostPerUse: 0
360+
// CHECK-NEXT: CoveredBySubregs: 1
361+
// CHECK-NEXT: HasDisjunctSubRegs: 1
362+
// CHECK-NEXT: SubReg dsub0 = D1
363+
// CHECK-NEXT: SubReg dsub1 = D2
364+
// CHECK-NEXT: SubReg ssub = S1
365+
// CHECK-NEXT: SubReg ssub1 = S2
366+
// CHECK-NEXT: SubReg ssub_hi = S1_HI
367+
// CHECK-NEXT: SubReg dsub1_then_ssub_hi = S2_HI
368+
// CHECK-NEXT: SubReg ssub_ssub1 = S1_S2
369+
// CHECK-NEXT: Register D0_D1_D2:
370+
// CHECK-NEXT: CostPerUse: 0
371+
// CHECK-NEXT: CoveredBySubregs: 1
372+
// CHECK-NEXT: HasDisjunctSubRegs: 1
373+
// CHECK-NEXT: SubReg dsub0 = D0
374+
// CHECK-NEXT: SubReg dsub1 = D1
375+
// CHECK-NEXT: SubReg dsub2 = D2
376+
// CHECK-NEXT: SubReg ssub = S0
377+
// CHECK-NEXT: SubReg ssub1 = S1
378+
// CHECK-NEXT: SubReg ssub2 = S2
379+
// CHECK-NEXT: SubReg ssub_hi = S0_HI
380+
// CHECK-NEXT: SubReg dsub1_then_ssub_hi = S1_HI
381+
// CHECK-NEXT: SubReg dsub2_then_ssub_hi = S2_HI
382+
// CHECK-NEXT: SubReg ssub_ssub1 = S0_S1
383+
// CHECK-NEXT: SubReg dsub0_dsub1 = D0_D1
384+
// CHECK-NEXT: SubReg dsub1_dsub2 = D1_D2
385+
// CHECK-NEXT: SubReg ssub_ssub1_ssub2 = S0_S1_S2
386+
// CHECK-NEXT: SubReg ssub1_ssub2 = S1_S2
387+
// CHECK-NEXT: Register S0_S1:
388+
// CHECK-NEXT: CostPerUse: 0
389+
// CHECK-NEXT: CoveredBySubregs: 1
390+
// CHECK-NEXT: HasDisjunctSubRegs: 1
391+
// CHECK-NEXT: SubReg ssub0 = S0
392+
// CHECK-NEXT: SubReg ssub1 = S1
393+
// CHECK-NEXT: Register S1_S2:
394+
// CHECK-NEXT: CostPerUse: 0
395+
// CHECK-NEXT: CoveredBySubregs: 1
396+
// CHECK-NEXT: HasDisjunctSubRegs: 1
397+
// CHECK-NEXT: SubReg ssub0 = S1
398+
// CHECK-NEXT: SubReg ssub1 = S2
399+
// CHECK-NEXT: Register S0_S1_S2:
400+
// CHECK-NEXT: CostPerUse: 0
401+
// CHECK-NEXT: CoveredBySubregs: 1
402+
// CHECK-NEXT: HasDisjunctSubRegs: 1
403+
// CHECK-NEXT: SubReg ssub0 = S0
404+
// CHECK-NEXT: SubReg ssub1 = S1
405+
// CHECK-NEXT: SubReg ssub2 = S2
406+
// CHECK-NEXT: SubReg ssub1_ssub2 = S1_S2
407+
// CHECK-NEXT: SubReg ssub0_ssub1 = S0_S1

llvm/utils/TableGen/Common/CodeGenRegisters.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,7 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
399399
// user already specified.
400400
for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) {
401401
CodeGenRegister *SR = ExplicitSubRegs[i];
402-
if (!SR->CoveredBySubRegs || SR->ExplicitSubRegs.size() <= 1 ||
403-
SR->Artificial)
402+
if (!SR->CoveredBySubRegs || SR->Artificial)
404403
continue;
405404

406405
// SR is composed of multiple sub-regs. Find their names in this register.
@@ -411,6 +410,9 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
411410
Parts.push_back(getSubRegIndex(SR->ExplicitSubRegs[j]));
412411
}
413412

413+
if (Parts.size() < 2)
414+
continue;
415+
414416
// Offer this as an existing spelling for the concatenation of Parts.
415417
CodeGenSubRegIndex &Idx = *ExplicitSubRegIndices[i];
416418
Idx.setConcatenationOf(Parts);

0 commit comments

Comments
 (0)