The models, scripts, and results of the benchmarks performed for a Half Reification Journal paper
1%
2% Main authors:
3% Mats Carlsson <mats.carlsson@ri.se>
4%
5% This file is part of Unison, see http://unison-code.github.io
6%
7% Copyright (c) 2016, RISE SICS AB
8% All rights reserved.
9%
10% Redistribution and use in source and binary forms, with or without
11% modification, are permitted provided that the following conditions are met:
12% 1. Redistributions of source code must retain the above copyright notice,
13% this list of conditions and the following disclaimer.
14% 2. Redistributions in binary form must reproduce the above copyright notice,
15% this list of conditions and the following disclaimer in the documentation
16% and/or other materials provided with the distribution.
17% 3. Neither the name of the copyright holder nor the names of its contributors
18% may be used to endorse or promote products derived from this software
19% without specific prior written permission.
20%
21% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31% POSSIBILITY OF SUCH DAMAGE.
32
33include "globals.mzn";
34
35%% solver parameters
36
37bool: optimize_cycles;
38
39%% some constants
40%% N.B. keep in sync with modeler! see also isreal()!
41
42int: TYPE_LINEAR = 0;
43int: TYPE_BRANCH = 1;
44int: TYPE_CALL = 2;
45int: TYPE_TAIL = 3;
46int: TYPE_IN = 4;
47int: TYPE_OUT = 5;
48int: TYPE_KILL = 6;
49int: TYPE_DEFINE = 7;
50int: TYPE_COMBINE = 8;
51int: TYPE_LOW = 9;
52int: TYPE_HIGH = 10;
53int: TYPE_SPLIT2 = 11;
54int: TYPE_SPLIT4 = 12;
55int: TYPE_FUN = 13;
56int: TYPE_COPY = 14;
57
58%% problem parameters
59
60int: MAXF;
61int: MAXO;
62int: MAXP;
63int: MAXT;
64int: MAXC;
65int: MAXI;
66int: MAXR;
67int: MAXB = max(index_set(bb_ops));
68int: MINL;
69int: MAXL;
70int: MAXINSNS = max(o in 0..MAXO)(card(op_instructions[o]));
71int: MAXTEMPS = max(p in 0..MAXP)(card(operand_temps[p]));
72
73set of int: expr = index_set(expr_op);
74
75%% see JSON freq, maxc, ins, tmp, operands, optional_min
76array[int] of int: bb_order;
77array[int] of set of int: bb_ops;
78array[int] of set of int: bb_operands;
79array[int] of set of int: bb_temps;
80array[int] of set of int: bb_subsumed;
81array[int] of int: bb_frequency;
82array[int] of int: bb_maxcycle;
83array[int] of int: bb_optional_min;
84
85%% see JSON operands, instructions, type
86array[int] of set of int: op_operands;
87array[int] of set of int: op_instructions;
88array[int] of int: op_type;
89array[int] of bool: op_mand;
90
91%% see JSON atoms
92array[int] of set of int: atom_regs; % atom -> registers
93
94%% see JSON calleesaved, callersaved, infinite, bounded, range
95set of int: calleesaved;
96set of int: callersaved;
97set of int: infinite;
98array[int] of bool: bounded;
99array[int] of set of int: range;
100
101%% see JSON cap, con, dur, off
102array[int] of int: res_cap;
103array[int,int] of int: res_con;
104array[int,int] of int: res_dur;
105array[int,int] of int: res_off;
106
107%% see JSON congr
108array[int] of set of int: congr;
109
110%% see JSON strictly_congr
111array[int] of set of int: strictly_congr;
112
113%% see JSON preassign
114array[int] of int: preassign_operand;
115array[int] of int: preassign_reg;
116
117%% see JSON aligned/adist
118array[int] of int: aligned_use;
119array[int] of int: aligned_def;
120array[int] of int: aligned_usei;
121array[int] of int: aligned_defi;
122array[int] of int: aligned_dist;
123
124%% see JSON adjacent
125array[int] of int: adj_from;
126array[int] of int: adj_to;
127
128%% see JSON quasi_adjacent
129array[int] of int: quasi_adj_from;
130array[int] of int: quasi_adj_to;
131
132%% see JSON long_latency
133array[int,int] of set of int: long_latency_index;
134array[int] of int: long_latency_def;
135array[int] of int: long_latency_use;
136
137%% see JSON operands
138array[int] of int: operand_definer; % operand -> defining op
139
140%% see JSON use
141array[int] of bool: operand_use;
142
143%% see JSON last_use
144array[int] of bool: operand_lastuse;
145
146%% see JSON temps
147array[int] of set of int: operand_temps;
148
149%% see JSON class, operands, instructions
150array[int,int] of int: operand_atom; % operand x operation -> atom
151
152%% see JSON temps
153array[int] of set of int: related_temps;
154
155%% see JSON definer, temps, width, minlive
156array[int] of int: temp_definer; % temp -> defining op
157array[int] of int: temp_def; % temp -> defining operand
158array[int] of int: temp_width; % temp -> width
159array[int] of int: temp_minlive; % temp -> minlive
160array[int] of set of int: temp_uses; % temp -> set of use operands
161array[int] of set of int: temp_domain; % temp -> domain of regs
162
163%% see JSON packed, pinstrs
164array[int,int] of int: packed_pq;
165
166%% see JSON before
167array[int] of int: before_pred;
168array[int] of int: before_succ;
169array[int] of expr: before_cond;
170
171%% see JSON E
172array[int] of int: adhoc;
173
174%% see JSON nogoods
175array[int] of expr: nogood;
176
177%% see JSON across
178array[int] of int: across_op;
179array[int] of set of int: across_regs;
180array[int] of set of int: across_items;
181array[int] of int: across_item_temp;
182array[int] of expr: across_item_cond;
183
184%% see JSON set_across
185array[int] of int: setacross_op;
186array[int] of set of int: setacross_regs;
187array[int] of set of int: setacross_tempsets;
188
189%% see JSON difftemps
190array[int] of set of int: difftemp;
191
192%% see JSON diffregs
193array[int] of set of int: diffreg;
194
195%% see JSON domops
196array[int] of set of int: domop_operands;
197array[int] of set of int: domop_temps;
198
199%% see JSON domuse
200array[int] of int: domuse_p;
201array[int] of int: domuse_q;
202array[int] of int: domuse_r;
203
204%% see JSON infassign
205array[int,int] of int: infassign;
206
207%% see JSON space
208array[int] of int: space;
209
210%% see JSON dominates
211array[int] of int: dominate_ing;
212array[int] of int: dominate_ed;
213array[int] of set of int: dominate_instructions;
214array[int] of set of int: dominate_temps;
215
216%% see JSON precedences
217array[int] of expr: precedence;
218
219%% see JSON active_tables, tmp_tables
220array[int] of set of int: table_exists_ops;
221array[int] of set of int: table_iffall_ops;
222array[int] of set of int: relation_ops;
223array[int] of set of int: relation_temps;
224array[int] of int: relation_ntuples;
225array[int] of set of int: relation_range;
226
227%% see JSON calleesaved_spill
228array[int] of set of int: calleesaved_spill;
229array[int,int] of int: cs_spill_transpose;
230
231%% see JSON activators
232array[int] of set of int: activator_insns;
233array[int] of set of int: activator_ops;
234
235%% see JSON value_precede_chain
236array[int] of int: value_precede_min;
237array[int] of int: value_precede_max;
238array[int] of set of int: value_precede_regs;
239array[int] of int: value_precede_temps;
240
241%% see JSON lat
242array[int,int] of int: lat_table;
243
244%% see JSON preschedule
245array[int] of int: preschedule_op;
246array[int] of int: preschedule_cycle;
247
248%% see JSON bypass
249array[int,int] of int: bypass_table;
250
251%% see JSON exrelated, table
252array[int] of int: exrelated_p;
253array[int] of int: exrelated_q;
254array[int] of set of int: exrelated_rows;
255array[int,int] of int: exrelated_ext;
256
257%% see JSON wcet
258array[int,int] of int: wcet;
259
260%% extra storage for constraint expressions
261array[int] of int: expr_op;
262array[int] of int: expr_arg1;
263array[int] of int: expr_arg2;
264array[int] of int: expr_arg3;
265array[int] of set of int: expr_children;
266
267%% extra store for relations in table constraints
268array[int] of int: ints;
269
270%% extra storage: each set is a set of temporaries
271array[int] of set of int: sets;
272
273%% problem variables
274
275var 0..MAXF: objective;
276array[0..MAXO] of var bool: a;
277array[0..MAXO] of var 1..MAXINSNS: ii; % same as in gecode-solver
278array[0..MAXO] of var -1..MAXC: c;
279array[0..MAXP] of var -1..MAXR: rt;
280array[0..MAXP] of var MINL..MAXL: lt; % operand latency
281array[0..MAXP] of var -MAXL..MAXL: s; % global operand slack
282array[0..MAXP] of var 1..MAXTEMPS: y; % same as in gecode-solver
283array[-1..MAXT] of var -1..MAXR: r;
284array[-1..MAXT] of var -1..MAXC: ls;
285array[-1..MAXT] of var 0..MAXC: ld;
286array[-1..MAXT] of var -1..MAXC: le;
287array[1..MAXB] of var 0..MAXC: copysum;
288
289%% PREDICATES AND TESTS
290
291test isreal(int: o) = (op_type[o] in
292 {TYPE_LINEAR, TYPE_BRANCH, TYPE_CALL, TYPE_TAIL, TYPE_FUN, TYPE_COPY});
293
294test fixedop(int: o) = (
295 op_instructions[o] != {0} /\ card(op_instructions[o]) = 1
296);
297
298test all_equal_ints(array[int] of int: x) =
299 forall(i, j in index_set(x) where i < j) ( x[i] = x[j] );
300
301var int: res_con_of_op(int: res, int: o) =
302 let {array[int] of int: I = op_instructions[o]} in
303 let {array[int] of int: ints = [res_con[res,I[i]] | i in index_set(I)]} in
304 if all_equal_ints(ints) then ints[1] else ints[ii[o]] endif;
305
306var int: res_dur_of_op(int: res, int: o) =
307 let {array[int] of int: I = op_instructions[o]} in
308 let {array[int] of int: ints = [res_dur[res,I[i]] | i in index_set(I)]} in
309 if all_equal_ints(ints) then ints[1] else ints[ii[o]] endif;
310
311var int: res_off_of_op(int: res, int: o) =
312 let {array[int] of int: I = op_instructions[o]} in
313 let {array[int] of int: ints = [res_off[res,I[i]] | i in index_set(I)]} in
314 if all_equal_ints(ints) then ints[1] else ints[ii[o]] endif;
315
316predicate insn_eq(int: o, int: x) =
317 let {array[int] of int: I = op_instructions[o]} in
318 exists(j in index_set(I) where I[j]=x)(ii[o]=j);
319
320predicate insn_in(int: o, set of int: X) =
321 if card(X)=0 then
322 false
323 else if card(X)=1 then
324 insn_eq(o, min(X))
325 else
326 let {array[int] of int: I = op_instructions[o]} in
327 ii[o] in {j | j in index_set(I) where I[j] in X}
328 endif endif;
329
330predicate smart_alldiff(array[int] of var int: X) =
331 if length(X)<2 then
332 true
333 else if length(X)=2 then
334 let {set of int: S = index_set(X)} in
335 X[min(S)] != X[max(S)]
336 else
337 all_different(X)
338 endif endif;
339
340predicate ra_diffn(array[int] of var int: R,
341 array[int] of int: W,
342 array[int] of set of int: D,
343 array[int] of var int: LS,
344 array[int] of var int: LD,
345 array[int] of var int: LE) =
346 diffn_nonstrict(R, LS, W, LD);
347
348predicate disjoint1(array[int] of var int: x,
349 array[int] of var int: w) =
350 diffn(x, [1 | i in index_set(x)], w, [1 | i in index_set(x)]) ;
351
352predicate noverlap(array[int] of var int: x,
353 array[int] of var int: w) = (
354 if min([lb(z) | z in w]) < max([ub(z) | z in w]) then
355 disjoint1(x, w)
356 else if length(x) = 2 then
357 x[1] != x[2]
358 else
359 smart_alldiff(x)
360 endif endif
361 );
362
363predicate live_overlap(int: k, int: j) = (ls[k] < le[j] /\ ls[j] < le[k]);
364
365predicate operand_live_overlap(int: p, int: q) = (ls_t(p) < le_t(q) /\ ls_t(q) < le_t(p));
366
367predicate operand_live_before(int: p, int: q) = (le_t(p) <= ls_t(q));
368
369test operand_related(int: p, int: q) =
370 operand_temps[p] subset operand_temps[q] \/ operand_temps[q] subset operand_temps[p];
371
372predicate same_temp(int: p, int: q) =
373 assert(operand_related(p,q), "same_temp[\(p),\(q)] with unrelated operands") /\
374 y[p] = y[q];
375
376predicate temp_eq(int: p, int: t) =
377 let {array[int] of int: ts = operand_temps[p]} in
378 exists(j in index_set(ts) where ts[j]=t)(y[p]=j);
379
380predicate temp_in(int: p, set of int: T) =
381 if card(T)=0 then
382 false
383 else if card(T)=1 then
384 temp_eq(p, min(T))
385 else
386 let {array[int] of int: ts = operand_temps[p]} in
387 y[p] in {j | j in index_set(ts) where ts[j] in T}
388 endif endif;
389
390test temp_is_unsafe(int: t) =
391 if op_type[temp_definer[t]] in {TYPE_IN,TYPE_DEFINE,TYPE_FUN} then
392 false
393 else
394 let {array[int] of int: dlats = [lat_table[j,4] | j in index_set_1of2(lat_table)
395 where
396 lat_table[j,2] != 0 /\
397 lat_table[j,3] = temp_def[t]
398 ],
399 array[int] of int: ulats = [lat_table[j,4] | j in index_set_1of2(lat_table)
400 where
401 lat_table[j,2] != 0 /\
402 lat_table[j,3] in temp_uses[t]
403 ]} in
404 temp_minlive[t] > min(dlats) + min(ulats)
405 endif;
406
407test temp_must_be_real(int: p) =
408 min(operand_temps[p])>=0;
409
410predicate temp_is_real(int: p) =
411 if min(operand_temps[p])>=0 then
412 true
413 else
414 y[p]!=1
415 endif;
416
417predicate temp_is_real_reif(int: p, var bool: re) =
418 if min(operand_temps[p])>=0 then
419 re
420 else
421 re <-> y[p]!=1
422 endif;
423
424predicate insn_is_real_reif(int: o, var bool: re) =
425 if min(op_instructions[o])>=1 then
426 re
427 else
428 re <-> ii[o]!=1
429 endif;
430
431predicate temp_member_reif(set of int: P, int: t, var bool: re) =
432 (re <-> exists(p in P)(temp_eq(p,t)));
433
434var int: t(int: p) =
435 if card(operand_temps[p])=1 then min(operand_temps[p])
436 else if card(operand_temps[p])=2 then
437 let {int: a = min(operand_temps[p]),
438 int: b = max(operand_temps[p])}
439 in (b-a)*y[p] -b+a+a
440 else
441 operand_temps[p][y[p]]
442 endif endif;
443
444var int: ls_t(int: p) = [ls[t] | t in operand_temps[p]][y[p]];
445
446var int: le_t(int: p) = [le[t] | t in operand_temps[p]][y[p]];
447
448%% conditions
449predicate eval_expr(int: l) = (
450 let {int: tag = expr_op[l],
451 int: arg1 = expr_arg1[l],
452 int: arg2 = expr_arg2[l],
453 int: arg3 = expr_arg3[l],
454 } in (
455 if tag=0 then exists(j in expr_children[l])(eval_expr(j))
456 else if tag=1 then forall(j in expr_children[l])(eval_expr(j))
457 else if tag=2 then eval_expr(arg1) xor eval_expr(arg2)
458 else if tag=3 then eval_expr(arg1) -> eval_expr(arg2)
459 else if tag=4 then not eval_expr(arg1)
460 else if tag=5 then a[arg1]
461 else if tag=6 then temp_eq(arg1,arg2)
462 else if tag=7 then insn_eq(arg1,arg2)
463 else if tag=8 then c[arg2] >= c[arg1] + arg3
464 else if tag=9 then same_temp(arg1,arg2)
465 else if tag=10 then operand_live_overlap(arg1,arg2)
466 else if tag=11 then live_overlap(arg1,arg2)
467 else if tag=12 then r[arg1] in callersaved
468 else if tag=13 then rt[arg1] in atom_regs[arg2]
469 else false endif endif endif endif endif endif endif endif endif endif endif endif endif endif
470 )
471);
472
473var int: ite(var bool: cond, var int: thenval, var int: elseval) = (
474 let {array[1..2] of var int: ar = [elseval,thenval]} in
475 ar[cond+1]
476);
477
4780..MAXT: single_temp(int: p) = max(operand_temps[p]);
479
480set of 0..MAXT: real_temps(int: p) = operand_temps[p] intersect 0..MAXT;
481
482%% (mostly) ESSENTIAL CONSTRAINT
483
484%% basic invariants, null instructions
485
486test opt_in_temporary(int: v) =
487 let {int: p = temp_def[v]} in
488 op_type[temp_definer[v]] = TYPE_IN /\ card(operand_temps[p])>1;
489
490constraint
491 r[-1] = -1 /\
492 ls[-1] = -1 /\
493 ld[-1] = 0 /\
494 le[-1] = -1 /\
495 forall(o in 0..MAXO where op_mand[o]) (a[o]) /\
496 forall(o in 0..MAXO where not op_mand[o]) (insn_is_real_reif(o,a[o])) /\
497 forall(o in 0..MAXO) (a[o] <-> c[o] >= 0) /\
498 forall(p in 0..MAXP where card(operand_temps[p])>1) (rt[p] = [r[v] | v in operand_temps[p]][y[p]]) /\
499 forall(p in 0..MAXP where card(operand_temps[p])=1) (rt[p] = r[single_temp(p)]) /\
500 forall(p in 0..MAXP where not op_mand[operand_definer[p]]) % rematerialization
501 (temp_is_real_reif(p,a[operand_definer[p]])) /\
502 forall(v in 0..MAXT) (ls[v]+ld[v] = le[v]) /\
503 forall(v in 0..MAXT where not opt_in_temporary(v)) % rematerialization
504 (ls[v] = c[temp_definer[v]] /\
505 (a[temp_definer[v]] <-> r[v] >= 0)) /\
506 forall(v in 0..MAXT where opt_in_temporary(v)) % rematerialization
507 (ls[v] in -1 .. 0 /\
508 (r[v] >= 0 <-> ls[v]=0) /\
509 (r[v] >= 0 <-> temp_eq(temp_def[v],v))) /\
510 forall(v in 0..MAXT) (
511 let {bool: unsafe = temp_is_unsafe(v),
512 set of int: pset = temp_uses[v],
513 set of int: prange = 1..card(pset),
514 array[prange] of int: parr = [p | p in pset],
515 array[prange] of var -1..MAXC: carr} in (
516 forall(p in prange) (carr[p] = ite(temp_eq(parr[p],v), c[operand_definer[parr[p]]], -1)) /\
517 if card(pset)=1 /\ not unsafe then
518 le[v] = carr[1]
519 else if not unsafe then
520 maximum(le[v], carr)
521 else
522 maximum(le[v], carr++[ls[v]+ % 20130930: live range can extend past last use
523 temp_minlive[v]*bool2int(a[temp_definer[v]])])
524 endif endif
525 )
526 );
527
528%% objective, bounds on (out) cycle
529
530constraint
531 forall(b in 1..MAXB) (
532 forall(o in bb_ops[b])(c[o] in -1..bb_maxcycle[b]) /\
533 c[min(bb_ops[b])] = 0 /\
534 copysum[b] = sum(o in bb_ops[b] where not op_mand[o])(bool2int(a[o])) /\
535 copysum[b] >= bb_optional_min[b]
536 ) /\
537 if optimize_cycles then
538 objective = sum(b in 1..MAXB) (bb_frequency[b] * c[max(bb_ops[b])])
539 else
540 objective = sum(o in 0..MAXO)(res_con_of_op(1,o))
541 endif;
542
543%% domains
544constraint
545 forall(o in 0..MAXO) (ii[o] in 1..card(op_instructions[o]));
546
547constraint
548 forall(q in 0..MAXP) (y[q] in 1..card(operand_temps[q]));
549
550set of int: temp_insn_regs(int: v, int: j) =
551 let {int: p = temp_def[v],
552 int: w = temp_width[v],
553 int: oa = operand_atom[p,j],
554 set of int: ks = {k | k in index_set_1of2(infassign) where infassign[k,1]=v /\ infassign[k,2]=space[oa]},
555 set of int: unaligned =
556 if card(ks)>0 then
557 {r | r in atom_regs[oa]} intersect (infassign[min(ks),3]..infassign[min(ks),4])
558 else
559 {r | r in atom_regs[oa]}
560 endif}
561 in {r | r in unaligned /*where r mod w = 0*/}; % currently, that would over-constrain
562
563set of int: generic_temp_domain(int: t1) =
564 if card(temp_domain[t1]) > 0 then
565 temp_domain[t1]
566 else
567 let {int: p = temp_def[t1],
568 set of int: rdom = array_union([temp_insn_regs(t1,j) | j in 1..MAXI]),
569 set of int: joker = if min(operand_temps[p])>=0 then {} else {-1} endif, % rematerialization
570 } in rdom union joker
571 endif;
572
573constraint
574 forall(t1 in 0..MAXT) (r[t1] in generic_temp_domain(t1));
575
576%% operation selection (register set depending on operation)
577constraint
578 forall(p in 0..MAXP)(
579 let {int: o = operand_definer[p],
580 set of int: joker = if min(operand_temps[p])>=0 then {} else {-1} endif} in
581 if fixedop(o) then
582 rt[p] in atom_regs[operand_atom[p,min(op_instructions[o])]] union joker % rematerialization
583 else
584 let {array[int] of set of int: doms = [ if insn=0 then {-1} else atom_regs[operand_atom[p,insn]] endif
585 | insn in op_instructions[o]
586 ],
587 array[int] of int: extension = [ if k=1 then j else r endif
588 | j in index_set(op_instructions[o]),
589 r in doms[j],
590 k in 1..2
591 ],
592 int: nt = length(extension) div 2} in
593 if forall(i in index_set(doms))(doms[i] = doms[1]) then
594 rt[p] in doms[1]
595 else
596 table([ii[o],rt[p]], array2d(1..nt, 1..2, extension))
597 endif
598 endif
599 );
600
601%% preassignments
602constraint
603 forall(j in index_set(preassign_reg))
604 (rt[preassign_operand[j]] = preassign_reg[j]);
605
606%% congruences
607constraint
608 forall(cgr in strictly_congr) (
609 let {int: junior = min(cgr)} in (
610 forall(j in cgr where j>junior) (rt[junior] = rt[j])
611 )
612 );
613
614%% adjacencies % rematerialization
615constraint
616 forall( j in index_set(adj_from)
617 where not({adj_from[j],adj_to[j]} subset array_union(strictly_congr))
618 ) (
619 let {int: p = adj_from[j],
620 int: q = adj_to[j]} in
621 (temp_is_real(q) -> temp_is_real(p)) /\
622 (temp_is_real(q) -> rt[p] = rt[q]) /\
623 (temp_is_real(p) -> exists(k in index_set(adj_from) where adj_from[k] = p)(temp_is_real(adj_to[k])))
624 );
625
626constraint
627 forall(j in index_set(quasi_adj_from)) (
628 let {int: p = quasi_adj_from[j],
629 int: q = quasi_adj_to[j]} in
630 temp_is_real(q) -> temp_is_real(p)
631 );
632
633%% aligned/adist
634constraint
635 forall(j in index_set(aligned_use)) (
636 let {int: p = aligned_use[j],
637 int: q = aligned_def[j],
638 int: pi = aligned_usei[j],
639 int: qi = aligned_defi[j],
640 int: offset = aligned_dist[j]} in (
641 insn_eq(operand_definer[p],pi) /\ insn_eq(operand_definer[q],qi) -> rt[p] + offset = rt[q]
642 )
643 );
644
645%% disjoint live ranges
646constraint
647 forall(T in bb_temps) (
648 ra_diffn([r[v] | v in T],
649 [temp_width[v] | v in T],
650 [generic_temp_domain(v) | v in T],
651 [ls[v] | v in T],
652 [ld[v] | v in T],
653 [le[v] | v in T])
654 );
655
656%% precedences (with conditions added by presolver)
657constraint
658 forall(P in precedence) (
659 eval_expr(P)
660 );
661
662%% slack and balancing
663
664%% Model::global_operand
665test global_operand(int: p) =
666 exists(j in index_set(adj_from))(adj_from[j]=p) \/
667 exists(j in index_set(adj_to))(adj_to[j]=p);
668
669%% Model::slack
670constraint
671 forall(p in 0..MAXP)(if not global_operand(p) then s[p]=0 else true endif);
672
673%% CompleteModel::post_slack_balancing_constraints
674constraint
675 forall(j in index_set(adj_from)) (
676 s[adj_from[j]] + s[adj_to[j]] = 0
677 );
678
679%% Model::post_operand_latency_definition
680constraint
681 forall(o in 0..MAXO, p in op_operands[o])(
682 let {array[int] of int: lcol = [ lat_table[j,4]
683 | j in index_set_1of2(lat_table)
684 where lat_table[j,1] = o /\ lat_table[j,3] = p
685 ],
686 int: n = length(lcol),
687 bool: simple = if not op_mand[o] then
688 forall(k in 2..n)(lcol[k]=lcol[2])
689 else
690 forall(k in 1..n)(lcol[k]=lcol[1])
691 endif} in
692 if simple then
693 lt[p] = lcol[n]
694 else
695 lt[p] = lcol[ii[o]]
696 endif
697 );
698
699%% Model::post_temporary_use_latency_definition
700var -MAXL..3*MAXL: lat(int: q, int: v) =
701 let {int: p = temp_def[v]} in
702 lt[p] + s[p] + lt[q] + s[q];
703
704%% data precedences with slack and everything
705
706array[int] of var int: opnd_lbs(int: q) =
707 [ if v = -1 then -1
708 else c[temp_definer[v]] + lat(q,v)
709 endif
710 | v in operand_temps[q]
711 ];
712
713predicate post_data_prec(int: q) =
714 let {int: u = operand_definer[q],
715 array[int] of var int: lbs = opnd_lbs(q)} in
716 c[u] >= lbs[1] /\
717 c[u] >= lbs[y[q]];
718
719%% Model::post_data_precedences_constraints
720%% redundant if op_type[operand_definer[q]]!=TYPE_KILL and implied constraints are being posted
721constraint
722 forall(q in 0..MAXP where operand_use[q])(post_data_prec(q));
723
724%% resources
725
726test unit_res_dur_cap(int: res, set of int: active) = (
727 forall(o in active, oi in op_instructions[o])(
728 res_con[res,oi]=res_cap[res] /\
729 res_dur[res,oi]=1 /\
730 res_off[res,oi]=0
731 )
732);
733
734test unit_res_dur(int: res, int: o) = (
735 forall(oi in op_instructions[o])(res_dur[res,oi]=1)
736);
737
738test zero_res_off(int: res, int: o) = (
739 forall(oi in op_instructions[o])(res_off[res,oi]=0)
740);
741
742constraint
743 forall(b in 1..MAXB, res in index_set(res_cap) diff bb_subsumed[b]) (
744 let {set of int: active = {o | o in bb_ops[b] where
745 exists(q in op_instructions[o])(res_con[res,q]>0)}} in (
746 if card(active)<=1 then true
747 else if unit_res_dur_cap(res,active) then
748 smart_alldiff([c[o] | o in active])
749 else
750 cumulative([ if zero_res_off(res,o) then c[o] else c[o]+res_off_of_op(res,o) endif
751 | o in active
752 ],
753 [ if unit_res_dur(res,o) then 1 else res_dur_of_op(res,o) endif
754 | o in active
755 ],
756 [ res_con_of_op(res,o)
757 | o in active
758 ],
759 res_cap[res])
760 endif endif
761 )
762 );
763
764
765%% packing constraints
766%% see Model::post_packing_constraints()
767constraint
768 forall(k in index_set_1of2(packed_pq)) (
769 let {int: p = packed_pq[k,1],
770 int: q = packed_pq[k,2],
771 int: w = temp_width[single_temp(p)],
772 array[int] of int: modtab = [-1,-1]++[ if k=1 then v else v + w - 2*(v mod 2*w) endif
773 | v in 0..MAXR, k in 1..2
774 where v mod w = 0
775 ],
776 int: nt = length(modtab) div 2,
777 } in
778 table([rt[p], rt[q]], array2d(1..nt, 1..2, modtab))
779 );
780
781%% activators
782constraint
783 forall(x in index_set(activator_insns))(
784 let {set of int: is = activator_insns[x],
785 set of int: os = activator_ops[x]} in (
786 (a[min(os)] <-> exists(o in 0..MAXO)(insn_in(o,op_instructions[o] intersect is))) /\
787 forall(i2 in os where i2>min(os))(a[i2] <-> a[min(os)])
788 )
789 );
790
791%% prescheduling
792constraint
793 forall(j in index_set(preschedule_op))(
794 let {int: oper = preschedule_op[j],
795 int: cycle = preschedule_cycle[j],
796 int: bb = min({k | k in index_set(bb_ops) where oper in bb_ops[k]}),
797 int: outop = max(bb_ops[bb])}
798 in (a[oper] -> c[oper] = cycle) /\
799 (a[oper] <-> c[outop] > cycle)
800 );
801
802%% bypass
803constraint
804 forall(j in index_set_1of2(bypass_table))(
805 let {int: o = bypass_table[j,1],
806 int: insn = bypass_table[j,2],
807 int: p = bypass_table[j,3]}
808 in insn_eq(o,insn) -> c[o] = ls_t(p)
809 );
810
811%% exrelated
812constraint
813 forall(j in index_set(exrelated_p))(
814 let {int: p = exrelated_p[j],
815 int: q = exrelated_q[j],
816 array[int] of int: ext = [exrelated_ext[r,k] | r in exrelated_rows[j], k in 1..2]}
817 in table([rt[p],rt[q]], array2d(1..(length(ext) div 2), 1..2, ext))
818 );
819
820%% ad-hoc
821constraint
822 forall(L in adhoc) (
823 eval_expr(L)
824 );
825
826%% IMPLIED CONSTRAINTS
827
828%% effective copy, handling multiple defs and/or uses
829constraint
830 symmetry_breaking_constraint(
831 forall(o in 0..MAXO where op_type[o] = TYPE_COPY)(
832 let {int: src = min([p | p in op_operands[o] where operand_use[p]]),
833 int: dst = min([p | p in op_operands[o] where not operand_use[p]])} in
834 a[o] -> rt[src] != rt[dst]
835 )
836 );
837
838%% dominating copies
839constraint
840 symmetry_breaking_constraint(
841 forall(k in index_set(dominate_ing)) (
842 let {int: ing = dominate_ing[k],
843 int: ed = dominate_ed[k],
844 int: edsrc = min(op_operands[ed]),
845 set of int: iset = dominate_instructions[k],
846 set of int: tset = dominate_temps[k]} in (
847 a[ing] \/ not a[ed] \/ insn_in(ed,iset) \/ temp_in(edsrc,tset)
848 )
849 )
850 );
851
852%% disjoint registers
853constraint
854 redundant_constraint(
855 forall(R in diffreg) (
856 noverlap([rt[j] | j in R],
857 [temp_width[min(operand_temps[j])] | j in R])
858 )
859 );
860
861%% different temporaries
862constraint
863 redundant_constraint(
864 forall(T in difftemp) (
865 let {array[int] of int: TA = T} in
866 forall(j in index_set(TA), k in index_set(TA) where j<k)(
867 assert(operand_related(TA[j],TA[k]), "difftemp(\(T)) with unrelated operands")
868 ) /\
869 smart_alldiff([y[p] | p in T])
870 )
871 );
872
873%% nogoods
874constraint
875 redundant_constraint(
876 forall(N in nogood) (
877 not eval_expr(N)
878 )
879 );
880
881%% Model::post_connected_users_constraints
882constraint
883 redundant_constraint(
884 forall(p in 0..MAXP where not operand_use[p])(
885 let {int: v = single_temp(p)} in (
886 if temp_must_be_real(p) then
887 temp_member_reif(temp_uses[v], v, true)
888 else if opt_in_temporary(v) then
889 let {var bool: rp}
890 in (temp_is_real_reif(p,rp)) /\
891 (temp_member_reif(temp_uses[v], v, rp))
892 else
893 temp_member_reif(temp_uses[v], v, a[operand_definer[p]])
894 endif endif
895 )
896 )
897 );
898
899%% Model::post_connected_users_constraints
900constraint
901 redundant_constraint(
902 forall(p in 0..MAXP where not operand_use[p])(
903 let {int: v = single_temp(p)} in (
904 if temp_must_be_real(p) then
905 member([rt[p] | p in temp_uses[v]], r[v])
906 else
907 member([rt[p] | p in temp_uses[v]]++[-1], r[v])
908 endif
909 )
910 )
911 );
912
913%% disjoint live ranges projected on callee-saved regs
914constraint
915 redundant_constraint(
916 forall(T in bb_temps) (
917 cumulative([ls[v] | v in T],
918 [ld[v] | v in T],
919 [temp_width[v]*bool2int(r[v] in calleesaved) | v in T],
920 card(calleesaved))
921 )
922 );
923
924%% temp symmetry breaking among interchangeable temporaries in their potential use operands
925constraint
926 symmetry_breaking_constraint(
927 forall(j in index_set(domop_operands)) (
928 value_precede_chain(domop_temps[j], [t(o) | o in domop_operands[j]])
929 )
930 );
931
932%% before
933constraint
934 redundant_constraint(
935 forall(j in index_set(before_pred)) (
936 let {int: p = before_pred[j],
937 int: q = before_succ[j],
938 expr: bc = before_cond[j]} in (
939 eval_expr(bc) -> operand_live_before(p,q)
940 )
941 )
942 );
943
944%% active_table, tmp_table
945constraint
946 redundant_constraint(
947 forall(E in table_exists_ops) (
948 exists(j in E)(a[j])
949 )
950 );
951
952constraint
953 redundant_constraint(
954 forall(XOR in table_iffall_ops) (
955 let {int: j = min(XOR),
956 int: k = max(XOR)} in (
957 a[j] <-> a[k]
958 )
959 )
960 );
961
962constraint
963 redundant_constraint(
964 forall(j in index_set(relation_ops)) (
965 let{set of int: ops = relation_ops[j],
966 set of int: temps = relation_temps[j],
967 int: nt = relation_ntuples[j],
968 set of int: range = relation_range[j],
969 set of int: irange = 1..(card(ops)+card(temps)),
970 array[irange] of var int: vars = [bool2int(a[j]) | j in ops]++
971 [t(j) | j in temps]} in (
972 table(vars, array2d(1..nt,irange,[ints[j] | j in range]))
973 )
974 )
975 );
976
977%% combine
978constraint
979 redundant_constraint(
980 forall(o in 0..MAXO where op_type[o] = TYPE_COMBINE)(
981 let {array[int] of int: opnds = [x | x in op_operands[o]],
982 int: src1 = opnds[1],
983 int: src2 = opnds[2],
984 int: def = opnds[3]} in (
985 minimum(ls_t(def), [le_t(src1), le_t(def)]) /\
986 minimum(ls_t(def), [le_t(src2), le_t(def)])
987 )
988 )
989 );
990
991%% low/high
992constraint
993 redundant_constraint(
994 forall(o in 0..MAXO where op_type[o] in {TYPE_HIGH, TYPE_LOW})(
995 let {int: src = min(op_operands[o]),
996 int: def = max(op_operands[o])} in (
997 minimum(ls_t(def), [le_t(src), le_t(def)])
998 )
999 )
1000 );
1001
1002%% useless memory stores
1003constraint
1004 symmetry_breaking_constraint(
1005 forall(T in related_temps) (
1006 sum([bool2int(r[v] in infinite) | v in T]) <= 1
1007 )
1008 );
1009
1010%% across
1011constraint
1012 redundant_constraint(
1013 forall(j in index_set(across_op)) (
1014 let {int: opi = across_op[j],
1015 int: maxwidth = max(temp_width),
1016 set of int: regs = across_regs[j],
1017 set of int: items = across_items[j],
1018 array[items] of int: cand =
1019 array1d(items, [across_item_temp[k] | k in items]),
1020 array[items] of var bool: active,
1021 array[items] of var -maxwidth*(MAXT+1)..MAXR: selected,
1022 array[int] of var int: allreg =
1023 [x | x in callersaved] ++ [x | x in regs] ++ selected,
1024 array[int] of int: allwidth =
1025 [1 | x in callersaved] ++
1026 [1 | x in regs] ++
1027 [temp_width[cand[k]] | k in items]} in (
1028 forall(k in items)(
1029 let {int: ck = cand[k]} in (
1030 ( active[k] <->
1031 eval_expr(across_item_cond[k]) \/
1032 (ls[ck] <= c[opi] /\ c[opi] < le[ck])) /\
1033 selected[k] = ite(active[k], r[ck], -maxwidth*(ck+1))
1034 )
1035 ) /\
1036 noverlap(allreg, allwidth)
1037 )
1038 )
1039 );
1040
1041%% set_across
1042constraint
1043 redundant_constraint(
1044 forall(j in index_set(setacross_op)) (
1045 let {int: opi = setacross_op[j],
1046 set of int: regs = setacross_regs[j],
1047 set of int: itemsset = setacross_tempsets[j],
1048 set of int: items = 1..card(itemsset),
1049 array[items] of set of int: cands = [sets[it] | it in itemsset],
1050 array[items] of var 0..MAXR: selected,
1051 array[items] of var 0..max(temp_width): width,
1052 array[int] of var int: allreg =
1053 [x | x in callersaved] ++ [x | x in regs] ++ selected,
1054 array[int] of var int: allwidth =
1055 [1 | x in callersaved] ++ [1 | x in regs] ++ width} in (
1056 forall(it in items)(
1057 let {set of int: cit = cands[it],
1058 array[int] of int: ws = [temp_width[k] | k in cit],
1059 array[int] of var int: rs = [r[k] | k in cit],
1060 array[int] of var int: lss = [ls[k] | k in cit],
1061 array[int] of var int: les = [le[k] | k in cit],
1062 var 1..card(cit): k} in (
1063 width[it] = if min(ws) < max(ws) then ws[k] else min(ws) endif /\
1064 selected[it] = rs[k] /\
1065 lss[k] <= c[opi] /\ c[opi] < les[k]
1066 )
1067 ) /\
1068 noverlap(allreg, allwidth)
1069 )
1070 )
1071 );
1072
1073%% spill callee-saved if and only if some temp interfers with it
1074constraint
1075 symmetry_breaking_constraint(
1076 if card(index_set(calleesaved_spill))>0 then
1077 let {int: nrows = card(index_set_1of2(cs_spill_transpose)),
1078 int: ncols = card(index_set_2of2(cs_spill_transpose)),
1079 set of int: css_ops = {cs_spill_transpose[j,k] | j in 1..nrows, k in 1..ncols},
1080 set of int: preass_ops = {o | o in 0..MAXO where op_type[o] in {TYPE_IN,TYPE_CALL,TYPE_TAIL,TYPE_FUN}},
1081 set of int: tcands = {o | o in 0..MAXT where not (temp_definer[o] in css_ops union preass_ops)}} in (
1082 forall(j in 1..ncols) (
1083 let {int: theop = cs_spill_transpose[1,j],
1084 int: thepu = min(op_operands[theop]),
1085 int: thetu = single_temp(thepu),
1086 int: thepd = temp_def[thetu],
1087 int: thea = min(k in index_set(preassign_reg) where preassign_operand[k]=thepd)(preassign_reg[k]),
1088 int: thew = temp_width[thetu]} in (
1089 a[theop] <-> exists(ti in tcands)(r[ti]+temp_width[ti] > thea /\ r[ti] in 0..thea+thew-1)
1090 )
1091 )
1092 )
1093 else true endif
1094 );
1095
1096%% break symmetries among which callee-saved to spill
1097constraint
1098 symmetry_breaking_constraint(
1099 if card(index_set(calleesaved_spill))>0 then
1100 forall(j in index_set(calleesaved_spill)) (
1101 let {set of int: cgr = calleesaved_spill[j],
1102 int: cur = min(cgr)} in (
1103 forall(x in cgr where x>cur) (a[cur] <-> a[x])
1104 )
1105 ) /\
1106 let {int: nrows = card(index_set_1of2(cs_spill_transpose)),
1107 int: ncols = card(index_set_2of2(cs_spill_transpose)),
1108 set of int: spill = if nrows>=1 then {cs_spill_transpose[1,j] | j in 1..ncols}
1109 else {} endif,
1110 set of int: unspill = if nrows>=2 then {cs_spill_transpose[2,j] | j in 1..ncols}
1111 else {} endif} in (
1112 decreasing([a[cs_spill_transpose[1,k]] | k in 1..ncols]) /\
1113 forall(k in 2..ncols)(
1114 a[cs_spill_transpose[1,k]] -> c[cs_spill_transpose[1,k-1]] <= c[cs_spill_transpose[1,k]]
1115 ) /\
1116 if spill subset bb_ops[1] /\ unspill subset bb_ops[1] then
1117 forall(k in 1..ncols)(
1118 let {int: u = cs_spill_transpose[2,k],
1119 int: v = cs_spill_transpose[1,k]} in (
1120 a[u] -> c[v] < c[u]
1121 )
1122 )
1123 else true endif
1124 )
1125 else true endif
1126 );
1127
1128%% IMPORTED FROM Model::
1129
1130%% Model::post_minimum_temporary_duration_constraints
1131constraint
1132 redundant_constraint(
1133 forall(o in 0..MAXO, dp in op_operands[o] where not operand_use[dp])(
1134 let {int: v = single_temp(dp)} in
1135 (temp_eq(dp,v) -> ld[v] >= temp_minlive[v]) /\
1136 forall(up in temp_uses[v])(temp_eq(up,v) -> ld[v] >= lat(up,v))
1137 )
1138 );
1139
1140%% Model::post_define_issue_cycle_constraints
1141constraint
1142 symmetry_breaking_constraint(
1143 forall(o in 0..MAXO where op_type[o]=TYPE_DEFINE)(
1144 let {set of int: js = {operand_definer[q] | p in op_operands[o],
1145 v in {single_temp(p)},
1146 q in temp_uses[v]},
1147 array[int] of var int: lats = [lat(q,v) | p in op_operands[o],
1148 v in {single_temp(p)},
1149 q in temp_uses[v]]} in
1150 if card(js) = 1 then
1151 c[min(js)] = c[o] + max(lats)
1152 else true endif
1153 )
1154 );
1155
1156%% DOMINATION: live range of temp occurring in (kill)
1157predicate kill_live_range(int: v) =
1158 (ld[v] = lt[temp_def[v]]);
1159
1160%% Model::post_kill_issue_cycle_constraints
1161constraint
1162 symmetry_breaking_constraint(
1163 forall(o2 in 0..MAXO where op_type[o2] = TYPE_KILL)(
1164 if op_mand[o2] then % e.g. after function call, multiple operands
1165 let {array[int] of var int: lats = [lat(q,v) | q in op_operands[o2],
1166 v in {single_temp(q)}],
1167 array[int] of int: ts = [v | q in op_operands[o2],
1168 v in {single_temp(q)}],
1169 set of int: o1s = {temp_definer[v] | q in op_operands[o2],
1170 v in {single_temp(q)}},
1171 } in
1172 forall(v in ts)(kill_live_range(v)) /\
1173 c[o2] = c[min(o1s)] + max(lats)
1174 else % e.g. after move subject to pack, one operand, multiple temps
1175 let {int: q1 = min(op_operands[o2]),
1176 int: p1 = temp_def[single_temp(q1)],
1177 set of int: o1s = {temp_definer[v] | v in real_temps(q1)},
1178 array[int] of var int: issue = [-1] ++ [c[temp_definer[v]] + lat(q1,v) | v in real_temps(q1)],
1179 } in
1180 card(op_operands[o2]) = 1 /\ % sanity check
1181 forall(v in real_temps(q1))(kill_live_range(v)) /\
1182 c[o2] = issue[y[q1]] /\
1183 if card(real_temps(q1))=1 then
1184 same_temp(p1,q1) /\ rt[p1] = rt[q1]
1185 else
1186 sum(o in o1s)(a[o]) <= 1
1187 endif
1188 endif
1189 )
1190 );
1191
1192%% domination constraint for slack, in fact make it a functional dependency
1193constraint
1194 symmetry_breaking_constraint(
1195 forall(j in index_set_1of2(long_latency_index))(
1196 let {set of int: inps = long_latency_index[j,1],
1197 set of int: inix = long_latency_index[j,2],
1198 set of int: outps = long_latency_index[j,3],
1199 set of int: outix = long_latency_index[j,4],
1200 array[int] of var int: inubs = [ if temp_eq(q,single_temp(p)) then
1201 c[operand_definer[q]] - lt[q] - s[q] - lt[p]
1202 else MAXL endif
1203 | i in inix,
1204 p in [long_latency_def[i]],
1205 q in [long_latency_use[i]]
1206 ],
1207 array[int] of var int: outubs = [ if temp_eq(q,single_temp(p)) then
1208 ld[single_temp(p)] - lt[q] - lt[p] - s[p]
1209 else MAXL endif
1210 | i in outix,
1211 p in [long_latency_def[i]],
1212 q in [long_latency_use[i]]
1213 ]} in
1214 assert((card(inps)>0 /\ card(outps)>0), "invalid long_latency item") /\
1215 let {var int: outlb = if length( inubs)>0 then -min( inubs) else -MAXL endif,
1216 var int: outub = if length(outubs)>0 then min(outubs) else MAXL endif} in
1217 outlb <= outub /\
1218 forall(p in outps)(s[p] = min(outub,max(outlb,0)))
1219 )
1220 );
1221
1222%% domination constraint: sequential schedule as a makespan UB
1223%% Model::post_sequential_upper_bound_constraints
1224constraint
1225 symmetry_breaking_constraint(
1226 forall(bb in index_set(bb_ops))(
1227 let {set of int: os = bb_ops[bb],
1228 array[os] of var 0..MAXC: wc = array1d(os, [o_wcet(o) | o in os])}
1229 in c[max(os)] <= sum(o in os)(wc[o])
1230 )
1231 );
1232
1233var 0..MAXC: o_wcet(0..MAXO: o) =
1234 let {array[int] of var int: wcs = [wcet[jj,3] | jj in index_set_1of2(wcet) where wcet[jj,1] = o],
1235 int: nwcs = length(wcs)}
1236 in if forall(jj in 1..nwcs)(wcs[jj] = 1)
1237 then a[o]
1238 else if not op_mand[o] /\ forall(jj in 2..nwcs)(wcs[jj] = 1)
1239 then a[o]
1240 else
1241 wcs[ii[o]]
1242 endif endif;
1243
1244%% output
1245
1246%------------------------------------------------------------------------------
1247% Solve item
1248
1249solve
1250 :: seq_search([
1251 seq_search([
1252 int_search(
1253 [y[p] | p in bb_operands[b] where operand_use[p] /\ op_mand[operand_definer[p]]],
1254 first_fail, indomain_min, complete
1255 )
1256 ] ++ [
1257 int_search(
1258 [0] ++ [y[p] | p in bb_operands[b] where operand_use[p] /\ not op_mand[operand_definer[p]]],
1259 first_fail, indomain_min, complete
1260 )
1261 ])
1262 | b in bb_order
1263 ] ++ [
1264 int_search([ii[o] | o in bb_ops[b]], input_order, indomain_min, complete)
1265 | b in bb_order
1266 ] ++ [
1267 seq_search([
1268 int_search([c[max(bb_ops[b])]], input_order, indomain_min, complete),
1269 int_search([c[o] | o in bb_ops[b]], smallest, indomain_min, complete)
1270 ])
1271 | b in bb_order
1272 ] ++ [
1273 int_search(
1274 [r[t] | t in bb_temps[b] where op_type[temp_definer[t]] != TYPE_IN]++[0],
1275 first_fail, indomain_min, complete
1276 )
1277 | b in bb_order
1278 ])
1279 minimize objective;
1280
1281%------------------------------------------------------------------------------
1282% Output item
1283
1284output [
1285 "c = array1d(0..\(MAXO), \(c));\n",
1286 "ii = array1d(0..\(MAXO), \(ii));\n",
1287 "y = array1d(0..\(MAXP), \(y));\n",
1288 "r = array1d(-1..\(MAXT), \(r));\n",
1289 "objective = \(objective);\n"
1290];
1291%++
1292% ["\"cost\": "] ++ [show(objective)] ++ ["\n"] ++
1293% ["\"cycles\": "] ++ [show(c)] ++ ["\n"] ++
1294% ["\"instructions\": "] ++ [show([op_instructions[o][fix(ii[o])] | o in 0..MAXO])] ++ ["\n"] ++
1295% ["\"temporaries\": "] ++ [show([operand_temps[p][fix(y[p])] | p in 0..MAXP])] ++ ["\n"] ++
1296% ["\"registers\": "] ++ [show([r[v] | v in 0..MAXT])] ++ ["\n"] ++
1297% ["\"live start\": "] ++ [show([ls[v] | v in 0..MAXT])] ++ ["\n"] ++
1298% ["\"live duration\": "] ++ [show([ld[v] | v in 0..MAXT])] ++ ["\n"] ++
1299% ["\"live end\": "] ++ [show([le[v] | v in 0..MAXT])] ++ ["\n"];
1300