BugFix: mode_b lowering might create new control flow (if ir_create_cond_set() is...
[libfirm] / ir / be / arm / arm_spec.pl
1 # Creation: 2006/02/13
2 # Arm Architecure Specification
3 # Author: Matthias Braun, Michael Beck, Oliver Richter, Tobias Gneist
4 # $Id$
5
6 $arch = "arm";
7
8 #
9 # Modes
10 #
11 $mode_gp    = "mode_Iu";
12 $mode_flags = "mode_Bu";
13 $mode_fp    = "mode_E";
14
15 # NOTE: Last entry of each class is the largest Firm-Mode a register can hold
16 %reg_classes = (
17         gp => [
18                 { name => "r0" },
19                 { name => "r1" },
20                 { name => "r2" },
21                 { name => "r3" },
22                 { name => "r4" },
23                 { name => "r5" },
24                 { name => "r6" },
25                 { name => "r7" },
26                 { name => "r8" },
27                 { name => "r9" },
28                 { name => "r10" },
29                 { name => "r11" },
30                 { name => "r12" },
31                 { name => "sp" },
32                 { name => "lr" },
33                 { name => "pc" },
34                 { mode => $mode_gp }
35         ],
36         fpa => [
37                 { name => "f0" },
38                 { name => "f1" },
39                 { name => "f2" },
40                 { name => "f3" },
41                 { name => "f4" },
42                 { name => "f5" },
43                 { name => "f6" },
44                 { name => "f7" },
45                 { mode => $mode_fp }
46         ],
47         flags => [
48                 { name => "fl" },
49                 { mode => $mode_flags, flags => "manual_ra" }
50         ],
51 );
52
53 %emit_templates = (
54         FM  => "${arch}_emit_float_load_store_mode(node);",
55         AM  => "${arch}_emit_float_arithmetic_mode(node);",
56         LM  => "${arch}_emit_load_mode(node);",
57         SM  => "${arch}_emit_store_mode(node);",
58         SO  => "${arch}_emit_shifter_operand(node);",
59         S0  => "${arch}_emit_source_register(node, 0);",
60         SC  => "${arch}_emit_symconst(node);",
61         S1  => "${arch}_emit_source_register(node, 1);",
62         S2  => "${arch}_emit_source_register(node, 2);",
63         S3  => "${arch}_emit_source_register(node, 3);",
64         S4  => "${arch}_emit_source_register(node, 4);",
65         D0  => "${arch}_emit_dest_register(node, 0);",
66         D1  => "${arch}_emit_dest_register(node, 1);",
67         D2  => "${arch}_emit_dest_register(node, 2);",
68         O   => "${arch}_emit_offset(node);",
69 );
70
71 $default_attr_type = "arm_attr_t";
72 $default_copy_attr = "arm_copy_attr";
73
74 %init_attr = (
75         arm_attr_t           => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);",
76         arm_SymConst_attr_t  =>
77                 "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n".
78                 "\tinit_arm_SymConst_attributes(res, entity, symconst_offset);",
79         arm_CondJmp_attr_t   => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);",
80         arm_SwitchJmp_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);",
81         arm_fConst_attr_t    => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);",
82         arm_load_store_attr_t =>
83                 "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n".
84                 "\tinit_arm_load_store_attributes(res, ls_mode, entity, entity_sign, offset, is_frame_entity);",
85         arm_shifter_operand_t =>
86                 "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n",
87         arm_cmp_attr_t =>
88                 "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n",
89         arm_farith_attr_t =>
90                 "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n".
91                 "\tinit_arm_farith_attributes(res, op_mode);",
92         arm_CopyB_attr_t =>
93                 "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n".
94                 "\tinit_arm_CopyB_attributes(res, size);",
95 );
96
97 %compare_attr = (
98         arm_attr_t            => "cmp_attr_arm",
99         arm_SymConst_attr_t   => "cmp_attr_arm_SymConst",
100         arm_CondJmp_attr_t    => "cmp_attr_arm_CondJmp",
101         arm_SwitchJmp_attr_t  => "cmp_attr_arm_SwitchJmp",
102         arm_fConst_attr_t     => "cmp_attr_arm_fConst",
103         arm_load_store_attr_t => "cmp_attr_arm_load_store",
104         arm_shifter_operand_t => "cmp_attr_arm_shifter_operand",
105         arm_CopyB_attr_t      => "cmp_attr_arm_CopyB",
106         arm_cmp_attr_t        => "cmp_attr_arm_cmp",
107         arm_farith_attr_t     => "cmp_attr_arm_farith",
108 );
109
110 my %unop_shifter_operand_constructors = (
111         imm => {
112                 attr       => "unsigned char immediate_value, unsigned char immediate_rot",
113                 custominit => "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);",
114                 reg_req    => { in => [], out => [ "gp" ] },
115         },
116         reg => {
117                 custominit => "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);",
118                 reg_req    => { in => [ "gp" ], out => [ "gp" ] },
119         },
120         reg_shift_reg => {
121                 attr       => "arm_shift_modifier_t shift_modifier",
122                 custominit => "init_arm_shifter_operand(res, 0, shift_modifier, 0);",
123                 reg_req    => { in => [ "gp", "gp" ], out => [ "gp" ] },
124         },
125         reg_shift_imm => {
126                 attr       => "arm_shift_modifier_t shift_modifier, unsigned shift_immediate",
127                 custominit => "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);",
128                 reg_req    => { in => [ "gp" ], out => [ "gp" ] },
129         },
130 );
131
132 my %binop_shifter_operand_constructors = (
133         imm => {
134                 attr       => "unsigned char immediate_value, unsigned char immediate_rot",
135                 custominit => "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);",
136                 reg_req    => { in => [ "gp" ], out => [ "gp" ] },
137                 ins        => [ "left" ],
138         },
139         reg => {
140                 custominit => "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);",
141                 reg_req    => { in => [ "gp", "gp" ], out => [ "gp" ] },
142                 ins        => [ "left", "right" ],
143         },
144         reg_shift_reg => {
145                 attr       => "arm_shift_modifier_t shift_modifier",
146                 custominit => "init_arm_shifter_operand(res, 0, shift_modifier, 0);",
147                 reg_req    => { in => [ "gp", "gp", "gp" ], out => [ "gp" ] },
148                 ins        => [ "left", "right", "shift" ],
149         },
150         reg_shift_imm => {
151                 attr       => "arm_shift_modifier_t shift_modifier, unsigned shift_immediate",
152                 custominit => "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);",
153                 reg_req    => { in => [ "gp", "gp" ], out => [ "gp" ] },
154                 ins        => [ "left", "right" ],
155         },
156 );
157
158 my %cmp_shifter_operand_constructors = (
159         imm => {
160                 attr       => "unsigned char immediate_value, unsigned char immediate_rot, bool ins_permuted, bool is_unsigned",
161                 custominit =>
162                         "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);\n".
163                         "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);",
164                 reg_req    => { in => [ "gp" ], out => [ "flags" ] },
165                 ins        => [ "left" ],
166         },
167         reg => {
168                 attr       => "bool ins_permuted, bool is_unsigned",
169                 custominit =>
170                         "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);\n".
171                         "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);",
172                 reg_req    => { in => [ "gp", "gp" ], out => [ "flags" ] },
173                 ins        => [ "left", "right" ],
174         },
175         reg_shift_reg => {
176                 attr       => "arm_shift_modifier_t shift_modifier, bool ins_permuted, bool is_unsigned",
177                 custominit =>
178                         "init_arm_shifter_operand(res, 0, shift_modifier, 0);\n".
179                         "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);",
180                 reg_req    => { in => [ "gp", "gp", "gp" ], out => [ "flags" ] },
181                 ins        => [ "left", "right", "shift" ],
182         },
183         reg_shift_imm => {
184                 attr       => "arm_shift_modifier_t shift_modifier, unsigned shift_immediate, bool ins_permuted, bool is_unsigned",
185                 custominit =>
186                         "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);\n".
187                         "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);",
188                 reg_req    => { in => [ "gp", "gp" ], out => [ "flags" ] },
189                 ins        => [ "left", "right" ],
190         },
191 );
192
193
194 %nodes = (
195
196 Add => {
197         irn_flags => [ "rematerializable" ],
198         emit      => '. add %D0, %S0, %SO',
199         mode      => $mode_gp,
200         attr_type => "arm_shifter_operand_t",
201         constructors => \%binop_shifter_operand_constructors,
202 },
203
204 Mul => {
205         irn_flags => [ "rematerializable" ],
206         reg_req   => { in => [ "gp", "gp" ], out => [ "!in_r1" ] },
207         emit      =>'. mul %D0, %S0, %S1',
208         mode      => $mode_gp,
209 },
210
211 Smull => {
212         irn_flags => [ "rematerializable" ],
213         reg_req   => { in => [ "gp", "gp" ], out => [ "gp", "gp" ] },
214         emit      =>'. smull %D0, %D1, %S0, %S1',
215         outs      => [ "low", "high" ],
216 },
217
218 Umull => {
219         irn_flags => [ "rematerializable" ],
220         reg_req   => { in => [ "gp", "gp" ], out => [ "gp", "gp" ] },
221         emit      =>'. umull %D0, %D1, %S0, %S1',
222         outs      => [ "low", "high" ],
223         mode      => $mode_gp,
224 },
225
226 Mla => {
227         irn_flags => [ "rematerializable" ],
228         reg_req   => { in => [ "gp", "gp", "gp" ], out => [ "!in_r1" ] },
229         emit      =>'. mla %D0, %S0, %S1, %S2',
230         mode      => $mode_gp,
231 },
232
233 And => {
234         irn_flags => [ "rematerializable" ],
235         emit      => '. and %D0, %S0, %SO',
236         mode      => $mode_gp,
237         attr_type => "arm_shifter_operand_t",
238         constructors => \%binop_shifter_operand_constructors,
239 },
240
241 Or => {
242         irn_flags => [ "rematerializable" ],
243         emit      => '. orr %D0, %S0, %SO',
244         mode      => $mode_gp,
245         attr_type => "arm_shifter_operand_t",
246         constructors => \%binop_shifter_operand_constructors,
247 },
248
249 Eor => {
250         irn_flags => [ "rematerializable" ],
251         emit      => '. eor %D0, %S0, %SO',
252         mode      => $mode_gp,
253         attr_type => "arm_shifter_operand_t",
254         constructors => \%binop_shifter_operand_constructors,
255 },
256
257 Bic => {
258         irn_flags => [ "rematerializable" ],
259         emit      => '. bic %D0, %S0, %SO',
260         mode      => $mode_gp,
261         attr_type => "arm_shifter_operand_t",
262         constructors => \%binop_shifter_operand_constructors,
263 },
264
265 Sub => {
266         irn_flags => [ "rematerializable" ],
267         emit      => '. sub %D0, %S0, %SO',
268         mode      => $mode_gp,
269         attr_type => "arm_shifter_operand_t",
270         constructors => \%binop_shifter_operand_constructors,
271 },
272
273 Rsb => {
274         irn_flags => [ "rematerializable" ],
275         emit      => '. rsb %D0, %S0, %SO',
276         mode      => $mode_gp,
277         attr_type => "arm_shifter_operand_t",
278         constructors => \%binop_shifter_operand_constructors,
279 },
280
281 Mov => {
282         irn_flags => [ "rematerializable" ],
283         arity     => "variable",
284         emit      => '. mov %D0, %SO',
285         mode      => $mode_gp,
286         attr_type => "arm_shifter_operand_t",
287         constructors => \%unop_shifter_operand_constructors,
288 },
289
290 Mvn => {
291         irn_flags => [ "rematerializable" ],
292         attr_type => "arm_shifter_operand_t",
293         arity     => "variable",
294         emit      => '. mvn %D0, %SO',
295         mode      => $mode_gp,
296         constructors => \%unop_shifter_operand_constructors,
297 },
298
299 Clz => {
300         irn_flags => [ "rematerializable" ],
301         reg_req   => { in => [ "gp" ], out => [ "gp" ] },
302         emit      =>'. clz %D0, %S0',
303         mode      => $mode_gp,
304 },
305
306 # mov lr, pc\n mov pc, XXX -- This combination is used for calls to function
307 # pointers
308 LinkMovPC => {
309         state        => "exc_pinned",
310         arity        => "variable",
311         out_arity    => "variable",
312         attr_type    => "arm_shifter_operand_t",
313         attr         => "arm_shift_modifier_t shift_modifier, unsigned char immediate_value, unsigned char immediate_rot",
314         custominit   => "init_arm_shifter_operand(res, immediate_value, shift_modifier, immediate_rot);\n".
315                         "\tarch_irn_add_flags(res, arch_irn_flags_modify_flags);",
316         emit         => ". mov lr, pc\n".
317                         ". mov pc, %SO",
318 },
319
320 # mov lr, pc\n ldr pc, XXX -- This combination is used for calls to function
321 # pointers
322 LinkLdrPC => {
323         state        => "exc_pinned",
324         arity        => "variable",
325         out_arity    => "variable",
326         attr_type    => "arm_load_store_attr_t",
327         attr         => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity",
328         custominit   => "arch_irn_add_flags(res, arch_irn_flags_modify_flags);",
329         emit         => ". mov lr, pc\n".
330                         ". ldr pc, %SO",
331 },
332
333 Bl => {
334         state      => "exc_pinned",
335         arity      => "variable",
336         out_arity  => "variable",
337         attr_type  => "arm_SymConst_attr_t",
338         attr       => "ir_entity *entity, int symconst_offset",
339         custominit => "arch_irn_add_flags(res, arch_irn_flags_modify_flags);",
340         emit       => '. bl %SC',
341 },
342
343 # this node produces ALWAYS an empty (tempary) gp reg and cannot be CSE'd
344 EmptyReg => {
345         op_flags  => [ "constlike" ],
346         irn_flags => [ "rematerializable" ],
347         reg_req   => { out => [ "gp" ] },
348         emit      => '. /* %D0 now available for calculations */',
349         cmp_attr  => 'return 1;',
350         mode      => $mode_gp,
351 },
352
353 CopyB => {
354         op_flags  => [ "fragile" ],
355         state     => "pinned",
356         attr      => "unsigned size",
357         attr_type => "arm_CopyB_attr_t",
358         reg_req   => { in => [ "!sp", "!sp", "gp", "gp", "gp", "none" ], out => [ "none" ] },
359         outs      => [ "M" ],
360 },
361
362 FrameAddr => {
363         op_flags  => [ "constlike" ],
364         irn_flags => [ "rematerializable" ],
365         attr      => "ir_entity *entity, int symconst_offset",
366         reg_req   => { in => [ "gp" ], out => [ "gp" ] },
367         ins       => [ "base" ],
368         attr_type => "arm_SymConst_attr_t",
369         mode      => $mode_gp,
370 },
371
372 SymConst => {
373         op_flags  => [ "constlike" ],
374         irn_flags => [ "rematerializable" ],
375         attr      => "ir_entity *entity, int symconst_offset",
376         reg_req   => { out => [ "gp" ] },
377         attr_type => "arm_SymConst_attr_t",
378         mode      => $mode_gp,
379 },
380
381 Cmp => {
382         irn_flags    => [ "rematerializable", "modify_flags" ],
383         emit         => '. cmp %S0, %SO',
384         mode         => $mode_flags,
385         attr_type    => "arm_cmp_attr_t",
386         constructors => \%cmp_shifter_operand_constructors,
387 },
388
389 Tst => {
390         irn_flags    => [ "rematerializable", "modify_flags" ],
391         emit         => '. tst %S0, %SO',
392         mode         => $mode_flags,
393         attr_type    => "arm_cmp_attr_t",
394         constructors => \%cmp_shifter_operand_constructors,
395 },
396
397 B => {
398         op_flags  => [ "labeled", "cfopcode", "forking" ],
399         state     => "pinned",
400         mode      => "mode_T",
401         reg_req   => { in => [ "flags" ], out => [ "none", "none" ] },
402         attr      => "ir_relation relation",
403         attr_type => "arm_CondJmp_attr_t",
404         init_attr => "\tset_arm_CondJmp_relation(res, relation);",
405 },
406
407 Jmp => {
408         state     => "pinned",
409         op_flags  => [ "cfopcode" ],
410         irn_flags => [ "simple_jump" ],
411         reg_req   => { out => [ "none" ] },
412         mode      => "mode_X",
413 },
414
415 SwitchJmp => {
416         op_flags  => [ "labeled", "cfopcode", "forking" ],
417         state     => "pinned",
418         mode      => "mode_T",
419         attr      => "int n_projs, long def_proj_num",
420         init_attr => "\tset_arm_SwitchJmp_n_projs(res, n_projs);\n".
421                      "\tset_arm_SwitchJmp_default_proj_num(res, def_proj_num);\n".
422                      "\tinfo->out_infos = NULL;",
423         reg_req   => { in => [ "gp" ], out => [ "none" ] },
424         attr_type => "arm_SwitchJmp_attr_t",
425 },
426
427 Ldr => {
428         op_flags  => [ "labeled", "fragile" ],
429         state     => "exc_pinned",
430         ins       => [ "ptr", "mem" ],
431         outs      => [ "res", "M" ],
432         reg_req   => { in => [ "gp", "none" ], out => [ "gp", "none" ] },
433         emit      => '. ldr%LM %D0, [%S0, #%O]',
434         attr_type => "arm_load_store_attr_t",
435         attr      => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity",
436 },
437
438 Str => {
439         op_flags  => [ "labeled", "fragile" ],
440         state     => "exc_pinned",
441         ins       => [ "ptr", "val", "mem" ],
442         outs      => [ "M" ],
443         reg_req   => { in => [ "gp", "gp", "none" ], out => [ "none" ] },
444         emit      => '. str%SM %S1, [%S0, #%O]',
445         mode      => "mode_M",
446         attr_type => "arm_load_store_attr_t",
447         attr      => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity",
448 },
449
450 StoreStackM4Inc => {
451         op_flags  => [ "labeled", "fragile" ],
452         irn_flags => [ "rematerializable" ],
453         state     => "exc_pinned",
454         reg_req   => { in => [ "sp", "gp", "gp", "gp", "gp", "none" ], out => [ "sp:I|S", "none" ] },
455         emit      => '. stmfd %S0!, {%S1, %S2, %S3, %S4}',
456         outs      => [ "ptr", "M" ],
457 },
458
459 LoadStackM3Epilogue => {
460         op_flags  => [ "labeled", "fragile" ],
461         irn_flags => [ "rematerializable" ],
462         state     => "exc_pinned",
463         reg_req   => { in => [ "sp", "none" ], out => [ "r11:I", "sp:I|S", "pc:I", "none" ] },
464         emit      => '. ldmfd %S0, {%D0, %D1, %D2}',
465         outs      => [ "res0", "res1", "res2", "M" ],
466 },
467
468
469
470 Adf => {
471         irn_flags => [ "rematerializable" ],
472         reg_req   => { in => [ "fpa", "fpa" ], out => [ "fpa" ] },
473         emit      => '. adf%AM %D0, %S0, %S1',
474         attr_type => "arm_farith_attr_t",
475         attr      => "ir_mode *op_mode",
476         mode      => $mode_fp,
477 },
478
479 Muf => {
480         irn_flags => [ "rematerializable" ],
481         reg_req   => { in => [ "fpa", "fpa" ], out => [ "fpa" ] },
482         emit      =>'. muf%AM %D0, %S0, %S1',
483         attr_type => "arm_farith_attr_t",
484         attr      => "ir_mode *op_mode",
485         mode      => $mode_fp,
486 },
487
488 Suf => {
489         irn_flags => [ "rematerializable" ],
490         reg_req   => { in => [ "fpa", "fpa" ], out => [ "fpa" ] },
491         emit      => '. suf%AM %D0, %S0, %S1',
492         attr_type => "arm_farith_attr_t",
493         attr      => "ir_mode *op_mode",
494         mode      => $mode_fp,
495 },
496
497 Dvf => {
498         reg_req   => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] },
499         emit      =>'. dvf%AM %D0, %S0, %S1',
500         outs      => [ "res", "M" ],
501         attr_type => "arm_farith_attr_t",
502         attr      => "ir_mode *op_mode",
503         mode      => $mode_fp,
504 },
505
506 Mvf => {
507         irn_flags => [ "rematerializable" ],
508         reg_req   => { in => [ "fpa" ], out => [ "fpa" ] },
509         emit      => '. mvf%AM %S0, %D0',
510         attr_type => "arm_farith_attr_t",
511         attr      => "ir_mode *op_mode",
512         mode      => $mode_fp,
513 },
514
515 FltX => {
516         irn_flags => [ "rematerializable" ],
517         reg_req   => { in => [ "gp" ], out => [ "fpa" ] },
518         emit      => '. flt%AM %D0, %S0',
519         attr_type => "arm_farith_attr_t",
520         attr      => "ir_mode *op_mode",
521         mode      => $mode_fp,
522 },
523
524 Cmfe => {
525         irn_flags => [ "rematerializable", "modify_flags" ],
526         mode      => $mode_flags,
527         attr_type => "arm_cmp_attr_t",
528         attr      => "bool ins_permuted",
529         init_attr => "init_arm_cmp_attr(res, ins_permuted, false);",
530         reg_req   => { in => [ "fpa", "fpa" ], out => [ "flags" ] },
531         emit      => '. cmfe %S0, %S1',
532 },
533
534 Ldf => {
535         op_flags  => [ "labeled", "fragile" ],
536         state     => "exc_pinned",
537         ins       => [ "ptr", "mem" ],
538         outs      => [ "res", "M" ],
539         reg_req   => { in => [ "gp", "none" ], out => [ "fpa", "none" ] },
540         emit      => '. ldf%FM %D0, [%S0, #%O]',
541         attr_type => "arm_load_store_attr_t",
542         attr      => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity",
543 },
544
545 Stf => {
546         op_flags  => [ "labeled", "fragile" ],
547         state     => "exc_pinned",
548         ins       => [ "ptr", "val", "mem" ],
549         outs      => [ "M" ],
550         mode      => "mode_M",
551         reg_req   => { in => [ "gp", "fpa", "none" ], out => [ "none" ] },
552         emit      => '. stf%FM %S1, [%S0, #%O]',
553         attr_type => "arm_load_store_attr_t",
554         attr      => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity",
555 },
556
557 #
558 # floating point constants
559 #
560 fConst => {
561         op_flags  => [ "constlike" ],
562         irn_flags => [ "rematerializable" ],
563         attr      => "ir_tarval *tv",
564         init_attr => "attr->tv = tv;",
565         mode      => "get_tarval_mode(tv)",
566         reg_req   => { out => [ "fpa" ] },
567         attr_type => "arm_fConst_attr_t",
568 }
569
570 ); # end of %nodes