this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
3/*
4 * Main authors:
5 * Graeme Gange <graeme.gange@monash.edu>
6 */
7
8/* This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11
12#ifndef __MINIZINC_CODEGEN_INTERNAL_HPP__
13#define __MINIZINC_CODEGEN_INTERNAL_HPP__
14// Helper definitions for assorted bytecode generation stuff.
15#include <minizinc/codegen.hh>
16
17namespace MiniZinc {
18
19template <class V>
20void PUSH_INSTR_OPERAND(CG_Instr& i, std::vector<V>& vec) {
21 for (auto v : vec) PUSH_INSTR_OPERAND(i, v);
22}
23void PUSH_INSTR_OPERAND(CG_Instr& i, CG_Value x) { i.params.push_back(x); }
24void PUSH_INSTR_OPERAND(CG_Instr& i, CG_ProcID p) { i.params.push_back(CG_Value::proc(p.p)); }
25void PUSH_INSTR_OPERAND(CG_Instr& i, BytecodeProc::Mode m) { i.params.push_back(CG::i((int)m)); }
26void PUSH_INSTR_OPERAND(CG_Instr& i, AggregationCtx::Symbol s) {
27 i.params.push_back(CG::i((int)s));
28}
29void PUSH_INSTR_OPERANDS(CG_Instr& i) {}
30
31template <class T, typename... Args>
32void PUSH_INSTR_OPERANDS(CG_Instr& i, T x, Args... args) {
33 PUSH_INSTR_OPERAND(i, x);
34 PUSH_INSTR_OPERANDS(i, args...);
35}
36
37template <typename... Args>
38void PUSH_INSTR(CG_Builder& cg, BytecodeStream::Instr i, Args... args) {
39 cg.instrs.push_back(CG_Instr::instr(i));
40 PUSH_INSTR_OPERANDS(cg.instrs.back(), args...);
41}
42
43void PUSH_LABEL(CG_Builder& frag, unsigned int label) {
44 frag.instrs.push_back(CG_Instr::label(label));
45}
46
47// Basic generator manipulation.
48inline int GET_LABEL(CodeGen& cg) { return cg.current_label_count++; }
49inline int GET_REG(CodeGen& cg) { return cg.current_reg_count++; }
50
51struct REG {
52 REG(int _r) : r(_r) {}
53 void operator()(CodeGen& cg, CG_Builder& frag) {
54 PUSH_INSTR(frag, BytecodeStream::PUSH, CG::r(r));
55 }
56 int r;
57};
58
59// Combinators for slightly safer code generation.
60struct PUSH_REG {
61 PUSH_REG(int _r) : r(_r) {}
62 void operator()(CodeGen& cg, CG_Builder& frag) {
63 PUSH_INSTR(frag, BytecodeStream::PUSH, CG::r(r));
64 }
65 int r;
66};
67struct PUSH {
68 PUSH(void) {}
69 PUSH_REG operator()(int r) { return PUSH_REG(r); }
70};
71
72template <class T>
73struct Retn {
74 Retn(T _x) : x(_x) {}
75
76 T operator()(CodeGen& cg, CG_Builder& frag) const { return x; }
77 T x;
78};
79struct RETN {
80 RETN() {}
81
82 template <class T>
83 Retn<T> operator()(T x) {
84 return Retn<T>(x);
85 }
86};
87
88/*
89template<class V, class E>
90struct _LET {
91 V v;
92 E e;
93 auto operator()(CodeGen& cg, CG_Builder& frag) -> decltype(e(0)(cg)) {
94 //
95 int reg(GET_REG(cg));
96 PUSH_INSTR(frag, BytecodeStream::OPEN_AGGREGATION, AggregationCtx::VCTX_OTHER);
97 v(cg, frag);
98 PUSH_INSTR(frag, BytecodeStream::POP, CG::r(reg));
99 PUSH_INSTR(frag, BytecodeStream::CLOSE_AGGREGATION);
100 return e(reg)(cg, frag);
101 }
102};
103template<class V, class E>
104_LET<V, E> LET(V&& v, E&& e) { return _LET<V, E> { std::move(v), std::move(e) }; }
105*/
106
107// Iterating over various things -- vectors, interleaved vectors, and sets.
108template <class V, class E>
109struct _FOREACH {
110 V v;
111 E e;
112 void operator()(CodeGen& cg, CG_Builder& frag) {
113 int r(v(cg, frag)); // Get the register for v.
114 int rB(GET_REG(cg));
115 int rE(GET_REG(cg));
116 int rV(GET_REG(cg));
117 int lblH(GET_LABEL(cg));
118 int lblE(GET_LABEL(cg));
119 // Set up the iterators
120 PUSH_INSTR(frag, BytecodeStream::IMMI, CG::i(1), CG::r(rB));
121 PUSH_INSTR(frag, BytecodeStream::LENGTH, CG::r(r), CG::r(rE));
122 // Check if the vec is non-empty
123 PUSH_INSTR(frag, BytecodeStream::LEI, CG::r(rB), CG::r(rE), CG::r(rV));
124 PUSH_INSTR(frag, BytecodeStream::JMPIFNOT, CG::r(rV), CG::l(lblE));
125 PUSH_LABEL(frag, lblH);
126 // Dereference the iterator
127 PUSH_INSTR(frag, BytecodeStream::GET_VEC, CG::r(r), CG::r(rB), CG::r(rV));
128 // Emit code for the body
129 e(rV)(cg, frag);
130 // Now increment and loop back.
131 PUSH_INSTR(frag, BytecodeStream::INCI, CG::r(rB));
132 PUSH_INSTR(frag, BytecodeStream::LEI, CG::r(rB), CG::r(rE), CG::r(rV));
133 PUSH_INSTR(frag, BytecodeStream::JMPIF, CG::r(rV), CG::l(lblH));
134 PUSH_LABEL(frag, lblE);
135 }
136};
137template <class V, class E>
138_FOREACH<V, E> FOREACH(V&& v, E&& e) {
139 return _FOREACH<V, E>{std::move(v), std::move(e)};
140}
141
142// Slightly nicer version of FOREACH.
143template <class E>
144void ITER_ARRAY(CodeGen& cg, CG_Builder& frag, int r, E e) {
145 int rV(GET_REG(cg));
146 int lblH(GET_LABEL(cg));
147 int lblE(GET_LABEL(cg));
148 PUSH_INSTR(frag, BytecodeStream::ITER_ARRAY, CG::r(r), CG::l(lblE));
149 PUSH_LABEL(frag, lblH);
150 PUSH_INSTR(frag, BytecodeStream::ITER_NEXT, CG::r(rV));
151 e(cg, frag, rV);
152 PUSH_INSTR(frag, BytecodeStream::JMP, CG::l(lblH));
153 PUSH_LABEL(frag, lblE);
154}
155template <class E>
156void ITER_SET(CodeGen& cg, CG_Builder& frag, int r, E e) {
157 int r_elt(GET_REG(cg));
158 int r_range_min(GET_REG(cg));
159 int r_range_max(GET_REG(cg));
160 int lblH1(GET_LABEL(cg));
161 int lblH2(GET_LABEL(cg));
162 int lblE(GET_LABEL(cg));
163 PUSH_INSTR(frag, BytecodeStream::ITER_VEC, CG::r(r), CG::l(lblE));
164 PUSH_LABEL(frag, lblH1);
165 PUSH_INSTR(frag, BytecodeStream::ITER_NEXT, CG::r(r_range_min));
166 PUSH_INSTR(frag, BytecodeStream::ITER_NEXT, CG::r(r_range_max));
167 PUSH_INSTR(frag, BytecodeStream::ITER_RANGE, CG::r(r_range_min), CG::r(r_range_max),
168 CG::l(lblH1));
169 PUSH_LABEL(frag, lblH2);
170 PUSH_INSTR(frag, BytecodeStream::ITER_NEXT, CG::r(r_elt));
171 e(cg, frag, r_elt);
172 PUSH_INSTR(frag, BytecodeStream::JMP, CG::l(lblH2));
173 PUSH_LABEL(frag, lblE);
174}
175
176// Same as FOREACH, but when working with a vector of pairs (i.e. sets)
177/*
178template<class V, class E>
179struct _FOREACH2 {
180 V v;
181 E e;
182 auto operator()(CodeGen& cg, CG_Builder& frag) -> decltype(e(0,0)(cg, frag)) {
183 int r(v(cg, frag)); // Get the register for v.
184 int rB(GET_REG(cg));
185 int rE(GET_REG(cg));
186 int rV1(GET_REG(cg));
187 int rV2(GET_REG(cg));
188 int lblH(GET_LABEL(cg));
189 int lblE(GET_LABEL(cg));
190 // Set up the iterators
191 PUSH_INSTR(frag, BytecodeStream::IMMI, CG::i(0), CG::r(rB));
192 PUSH_INSTR(frag, BytecodeStream::LENGTH, CG::r(r), CG::r(rE));
193 // Check if the vec is non-empty
194 PUSH_INSTR(frag, BytecodeStream::LTI, CG::r(rB), CG::r(rE), CG::r(rV1));
195 PUSH_INSTR(frag, BytecodeStream::JMPIFNOT, CG::r(rV1), CG::l(lblE));
196 PUSH_LABEL(frag, lblH);
197 // Dereference the iterator
198 PUSH_INSTR(frag, BytecodeStream::GET_VEC, CG::r(r), CG::r(rB), CG::r(rV1));
199 PUSH_INSTR(frag, BytecodeStream::INCI, CG::r(rB));
200 PUSH_INSTR(frag, BytecodeStream::GET_VEC, CG::r(r), CG::r(rB), CG::r(rV2));
201 PUSH_INSTR(frag, BytecodeStream::INCI, CG::r(rB));
202 // Emit code for the body
203 e(rV1, rV2)(cg, frag);
204 // Now increment and loop back.
205 PUSH_INSTR(frag, BytecodeStream::LTI, CG::r(rB), CG::r(rE), CG::r(rV1));
206 PUSH_INSTR(frag, BytecodeStream::JMPIF, CG::r(rV1), CG::l(lblH));
207 PUSH_LABEL(frag, lblE);
208 }
209};
210template<class V, class E>
211_FOREACH2<V, E> FOREACH2(V v, E e) { return _FOREACH2<V, E> { v, e }; }
212
213template<class E>
214struct _FORRANGE {
215 int rL;
216 int rU;
217 E e;
218 _FORRANGE(int _rL, int _rU, E _e) : rL(_rL), rU(_rU), e(_e) { }
219
220 auto operator()(CodeGen& cg, CG_Builder& frag) -> decltype(e(0)(cg, frag)) {
221 int lblH(GET_LABEL(cg));
222 int lblE(GET_LABEL(cg));
223 int rV(GET_REG(cg));
224 int rC(GET_REG(cg));
225 // Check if the range is non-empty.
226 PUSH_INSTR(frag, BytecodeStream::LTI, CG::r(rL), CG::r(rU), CG::r(rC));
227 PUSH_INSTR(frag, BytecodeStream::JMPIFNOT, CG::r(rC), CG::l(lblE));
228 PUSH_INSTR(frag, BytecodeStream::MOV, CG::r(rL), CG::r(rV));
229 PUSH_LABEL(frag, lblH);
230 // Emit code for the body
231 e(rV)(cg, frag);
232 // Now increment and loop back.
233 PUSH_INSTR(frag, BytecodeStream::INCI, CG::r(rV));
234 PUSH_INSTR(frag, BytecodeStream::LTI, CG::r(rV), CG::r(rU), CG::r(rC));
235 PUSH_INSTR(frag, BytecodeStream::JMPIF, CG::r(rC), CG::l(lblH));
236 PUSH_LABEL(frag, lblE);
237 }
238};
239template<class E>
240_FORRANGE<E> FORRANGE(int rL, int rU, E e) { return _FORRANGE<E>(rL, rU, e); }
241
242
243// We can use FOREACH2 and FORRANGE to iterate over sets.
244template<class V, class E>
245struct _FORSET {
246 V v;
247 E e;
248 _FORSET(V&& _v, E&& _e) : v(_v), e(_e) { }
249
250 void operator()(CodeGen& cg, CG_Builder& frag) {
251 FOREACH2(v, [this](int rL, int rU) { return FORRANGE(rL, rU, e); })(cg, frag);
252 }
253};
254template<class V, class E>
255_FORSET<V, E> FORSET(V&& v, E&& e) { return _FORSET<V, E>(std::move(v), std::move(e)); }
256*/
257
258// Non-combinator versions of the iteration generators.
259// Less safe, because they don't automatically resolve containment, but more convenient
260// if, say, we need unbounded
261
262struct EmitPost {
263 virtual ~EmitPost(void){};
264 virtual void emit_post(CG_Builder& frag) = 0;
265 virtual int cont(void) = 0;
266};
267
268struct Foreach : public EmitPost {
269#if 0
270 Foreach(CodeGen& _cg, int _r, int k = 1)
271 : cg(_cg), lblCont(-1), lblH(GET_LABEL(cg)), lblE(GET_LABEL(cg))
272 , r(_r), rB(GET_REG(cg)), rE(GET_REG(cg)) {
273 assert(k > 0);
274 for(int ii = 0; ii < k; ++ii)
275 rVS.push_back(GET_REG(cg));
276 }
277
278 void emit_pre(CG_Builder& frag) {
279 // Set up the iterators
280 PUSH_INSTR(frag, BytecodeStream::IMMI, CG::i(1), CG::r(rB));
281 PUSH_INSTR(frag, BytecodeStream::LENGTH, CG::r(r), CG::r(rE));
282 // Check if the vec is non-empty
283 PUSH_INSTR(frag, BytecodeStream::LEI, CG::r(rB), CG::r(rE), CG::r(rVS[0]));
284 PUSH_INSTR(frag, BytecodeStream::JMPIFNOT, CG::r(rVS[0]), CG::l(lblE));
285 PUSH_LABEL(frag, lblH);
286 // Dereference the iterator
287 for(int rv : rVS) {
288 PUSH_INSTR(frag, BytecodeStream::GET_VEC, CG::r(r), CG::r(rB), CG::r(rv));
289 PUSH_INSTR(frag, BytecodeStream::INCI, CG::r(rB));
290 }
291 }
292
293 void emit_post(CG_Builder& frag) {
294 // Now increment and loop back.
295 if(lblCont != -1)
296 PUSH_LABEL(frag, lblCont);
297 PUSH_INSTR(frag, BytecodeStream::LEI, CG::r(rB), CG::r(rE), CG::r(rVS[0]));
298 PUSH_INSTR(frag, BytecodeStream::JMPIF, CG::r(rVS[0]), CG::l(lblH));
299 PUSH_LABEL(frag, lblE);
300 }
301
302 int val(void) const { return rVS[0]; }
303 int val(int i) const { return rVS[i]; }
304 int cont(void) {
305 if(lblCont == -1)
306 lblCont = GET_LABEL(cg);
307 return lblCont;
308 }
309
310 CodeGen& cg;
311 int lblCont;
312 int lblH;
313 int lblE;
314 int r;
315 int rB;
316 int rE;
317 std::vector<int> rVS;
318#else
319 Foreach(CodeGen& _cg, int _r, int k = 1)
320 : cg(_cg), lblH(GET_LABEL(cg)), lblE(GET_LABEL(cg)), r(_r) {
321 assert(k > 0);
322 for (int ii = 0; ii < k; ++ii) rVS.push_back(GET_REG(cg));
323 }
324
325 void emit_pre(CG_Builder& frag) {
326 // Set up the iterators
327 PUSH_INSTR(frag, BytecodeStream::ITER_ARRAY, CG::r(r), CG::l(lblE));
328 PUSH_LABEL(frag, lblH);
329 // Dereference the iterator
330 for (int rv : rVS) {
331 PUSH_INSTR(frag, BytecodeStream::ITER_NEXT, CG::r(rv));
332 }
333 }
334
335 void emit_post(CG_Builder& frag) {
336 // Now increment and loop back.
337 PUSH_INSTR(frag, BytecodeStream::JMP, CG::l(lblH));
338 PUSH_LABEL(frag, lblE);
339 }
340
341 int val(void) const { return rVS[0]; }
342 int val(int i) const { return rVS[i]; }
343 int cont(void) { return lblH; }
344
345 CodeGen& cg;
346 int lblH;
347 int lblE;
348 int r;
349 std::vector<int> rVS;
350#endif
351};
352
353struct Forrange : public EmitPost {
354#if 0
355 Forrange(CodeGen& _cg, int _rL, int _rU)
356 : cg(_cg)
357 , lblH(GET_LABEL(cg)), lblE(GET_LABEL(cg)), lblCont(-1)
358 , rL(_rL), rU(_rU)
359 , rV(GET_REG(cg)), rC(GET_REG(cg)) {
360
361 }
362
363 void emit_pre(CG_Builder& frag) {
364 // Check if the range is non-empty.
365 PUSH_INSTR(frag, BytecodeStream::LEI, CG::r(rL), CG::r(rU), CG::r(rC));
366 PUSH_INSTR(frag, BytecodeStream::JMPIFNOT, CG::r(rC), CG::l(lblE));
367 PUSH_INSTR(frag, BytecodeStream::MOV, CG::r(rL), CG::r(rV));
368 PUSH_LABEL(frag, lblH);
369 }
370
371 void emit_post(CG_Builder& frag) {
372 // Now increment and loop back.
373 if(lblCont != -1)
374 PUSH_LABEL(frag, lblCont);
375 PUSH_INSTR(frag, BytecodeStream::INCI, CG::r(rV));
376 PUSH_INSTR(frag, BytecodeStream::LEI, CG::r(rV), CG::r(rU), CG::r(rC));
377 PUSH_INSTR(frag, BytecodeStream::JMPIF, CG::r(rC), CG::l(lblH));
378 PUSH_LABEL(frag, lblE);
379 }
380 int val(void) const { return rV; }
381 int cont(void) {
382 if(lblCont == -1)
383 lblCont = GET_LABEL(cg);
384 return lblCont;
385 }
386
387 CodeGen& cg;
388 int lblH;
389 int lblE;
390 int lblCont;
391 int rL;
392 int rU;
393 int rV;
394 int rC;
395#else
396 Forrange(CodeGen& _cg, int _rL, int _rU)
397 : cg(_cg), lblH(GET_LABEL(cg)), lblE(GET_LABEL(cg)), rL(_rL), rU(_rU), rV(GET_REG(cg)) {}
398
399 void emit_pre(CG_Builder& frag) {
400 // Set up the loop, and get the first element.
401 PUSH_INSTR(frag, BytecodeStream::ITER_RANGE, CG::r(rL), CG::r(rU), CG::l(lblE));
402 PUSH_LABEL(frag, lblH);
403 PUSH_INSTR(frag, BytecodeStream::ITER_NEXT, CG::r(rV));
404 }
405
406 void emit_post(CG_Builder& frag) {
407 // Jump back if we made it.
408 PUSH_INSTR(frag, BytecodeStream::JMP, CG::l(lblH));
409 PUSH_LABEL(frag, lblE);
410 }
411
412 int val(void) const { return rV; }
413 int cont(void) { return lblH; }
414
415 CodeGen& cg;
416 int lblH;
417 int lblE;
418 int rL;
419 int rU;
420 int rV;
421#endif
422};
423
424struct Forset : public EmitPost {
425 Forset(CodeGen& cg, int r) : ranges(cg, r, 2), values(cg, ranges.val(0), ranges.val(1)) {}
426
427 void emit_pre(CG_Builder& frag) {
428 ranges.emit_pre(frag);
429 values.emit_pre(frag);
430 }
431 void emit_post(CG_Builder& frag) {
432 values.emit_post(frag);
433 ranges.emit_post(frag);
434 }
435
436 int val(void) const { return values.val(); }
437 int cont(void) { return values.cont(); }
438
439 Foreach ranges;
440 Forrange values;
441};
442
443}; // namespace MiniZinc
444
445#endif