this repo has no description
at develop 14 kB view raw
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