The models, scripts, and results of the benchmarks performed for a Half Reification Journal paper
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
3/*
4 * Main authors:
5 * Guido Tack <guido.tack@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#include <minizinc/astexception.hh>
13#include <minizinc/astiterator.hh>
14#include <minizinc/copy.hh>
15#include <minizinc/eval_par.hh>
16#include <minizinc/flat_exp.hh>
17#include <minizinc/flatten.hh>
18#include <minizinc/hash.hh>
19#include <minizinc/iter.hh>
20
21#include <cmath>
22
23namespace MiniZinc {
24
25bool check_par_domain(EnvI& env, Expression* e, Expression* domain) {
26 if (e->type() == Type::parint()) {
27 IntSetVal* isv = eval_intset(env, domain);
28 if (!isv->contains(eval_int(env, e))) {
29 return false;
30 }
31 } else if (e->type() == Type::parfloat()) {
32 FloatSetVal* fsv = eval_floatset(env, domain);
33 if (!fsv->contains(eval_float(env, e))) {
34 return false;
35 }
36 } else if (e->type() == Type::parsetint()) {
37 IntSetVal* isv = eval_intset(env, domain);
38 IntSetRanges ir(isv);
39 IntSetVal* rsv = eval_intset(env, e);
40 IntSetRanges rr(rsv);
41 if (!Ranges::subset(rr, ir)) {
42 return false;
43 }
44 } else if (e->type() == Type::parsetfloat()) {
45 FloatSetVal* fsv = eval_floatset(env, domain);
46 FloatSetRanges fr(fsv);
47 FloatSetVal* rsv = eval_floatset(env, e);
48 FloatSetRanges rr(rsv);
49 if (!Ranges::subset(rr, fr)) {
50 return false;
51 }
52 }
53 return true;
54}
55
56void check_par_declaration(EnvI& env, VarDecl* vd) {
57 if (vd->type().dim() > 0) {
58 check_index_sets(env, vd, vd->e());
59 if (vd->ti()->domain() != nullptr) {
60 ArrayLit* al = eval_array_lit(env, vd->e());
61 for (unsigned int i = 0; i < al->size(); i++) {
62 if (!check_par_domain(env, (*al)[i], vd->ti()->domain())) {
63 throw ResultUndefinedError(env, vd->e()->loc(), "parameter value out of range");
64 }
65 }
66 }
67 } else {
68 if (vd->ti()->domain() != nullptr) {
69 if (!check_par_domain(env, vd->e(), vd->ti()->domain())) {
70 throw ResultUndefinedError(env, vd->e()->loc(), "parameter value out of range");
71 }
72 }
73 }
74}
75
76template <class E>
77typename E::Val eval_id(EnvI& env, Expression* e) {
78 Id* id = e->cast<Id>();
79 if (!id->decl()) {
80 throw EvalError(env, e->loc(), "undeclared identifier", id->str());
81 }
82 VarDecl* vd = id->decl();
83 while (vd->flat() && vd->flat() != vd) {
84 vd = vd->flat();
85 }
86 if (!vd->e()) {
87 throw EvalError(env, vd->loc(), "cannot evaluate expression", id->str());
88 }
89 typename E::Val r = E::e(env, vd->e());
90 if (!vd->evaluated() && (vd->toplevel() || vd->type().dim() > 0)) {
91 Expression* ne = E::exp(r);
92 vd->e(ne);
93 vd->evaluated(true);
94 }
95 return r;
96}
97
98bool EvalBase::evalBoolCV(EnvI& env, Expression* e) {
99 GCLock lock;
100 if (e->type().cv()) {
101 return eval_bool(env, flat_cv_exp(env, Ctx(), e)());
102 }
103 return eval_bool(env, e);
104};
105
106KeepAlive EvalBase::flattenCV(EnvI& env, Expression* e) {
107 GCLock lock;
108 Ctx ctx;
109 ctx.i = C_MIX;
110 ctx.b = (e->type().bt() == Type::BT_BOOL) ? C_MIX : C_ROOT;
111 EE ee = flat_exp(env, ctx, e, nullptr, constants().varTrue);
112 return ee.r;
113}
114
115class EvalIntLit : public EvalBase {
116public:
117 typedef IntLit* Val;
118 typedef Expression* ArrayVal;
119 static IntLit* e(EnvI& env, Expression* e) { return IntLit::a(eval_int(env, e)); }
120 static Expression* exp(IntLit* e) { return e; }
121};
122class EvalIntVal : public EvalBase {
123public:
124 typedef IntVal Val;
125 typedef IntVal ArrayVal;
126 static IntVal e(EnvI& env, Expression* e) { return eval_int(env, e); }
127 static Expression* exp(IntVal e) { return IntLit::a(e); }
128 static void checkRetVal(EnvI& env, Val v, FunctionI* fi) {
129 if ((fi->ti()->domain() != nullptr) && !fi->ti()->domain()->isa<TIId>()) {
130 IntSetVal* isv = eval_intset(env, fi->ti()->domain());
131 if (!isv->contains(v)) {
132 throw ResultUndefinedError(env, Location().introduce(),
133 "function result violates function type-inst");
134 }
135 }
136 }
137};
138class EvalFloatVal : public EvalBase {
139public:
140 typedef FloatVal Val;
141 typedef FloatVal ArrayVal;
142 static FloatVal e(EnvI& env, Expression* e) { return eval_float(env, e); }
143 static Expression* exp(FloatVal e) { return FloatLit::a(e); }
144 static void checkRetVal(EnvI& env, Val v, FunctionI* fi) {
145 if ((fi->ti()->domain() != nullptr) && !fi->ti()->domain()->isa<TIId>()) {
146 FloatSetVal* fsv = eval_floatset(env, fi->ti()->domain());
147 if (!fsv->contains(v)) {
148 throw ResultUndefinedError(env, Location().introduce(),
149 "function result violates function type-inst");
150 }
151 }
152 }
153};
154class EvalFloatLit : public EvalBase {
155public:
156 typedef FloatLit* Val;
157 typedef Expression* ArrayVal;
158 static FloatLit* e(EnvI& env, Expression* e) { return FloatLit::a(eval_float(env, e)); }
159 static Expression* exp(Expression* e) { return e; }
160};
161class EvalString : public EvalBase {
162public:
163 typedef std::string Val;
164 typedef std::string ArrayVal;
165 static std::string e(EnvI& env, Expression* e) { return eval_string(env, e); }
166 static Expression* exp(const std::string& e) { return new StringLit(Location(), e); }
167 static void checkRetVal(EnvI& env, const Val& v, FunctionI* fi) {}
168};
169class EvalStringLit : public EvalBase {
170public:
171 typedef StringLit* Val;
172 typedef Expression* ArrayVal;
173 static StringLit* e(EnvI& env, Expression* e) {
174 return new StringLit(Location(), eval_string(env, e));
175 }
176 static Expression* exp(Expression* e) { return e; }
177};
178class EvalBoolLit : public EvalBase {
179public:
180 typedef BoolLit* Val;
181 typedef Expression* ArrayVal;
182 static BoolLit* e(EnvI& env, Expression* e) { return constants().boollit(eval_bool(env, e)); }
183 static Expression* exp(Expression* e) { return e; }
184};
185class EvalBoolVal : public EvalBase {
186public:
187 typedef bool Val;
188 static bool e(EnvI& env, Expression* e) { return eval_bool(env, e); }
189 static Expression* exp(bool e) { return constants().boollit(e); }
190 static void checkRetVal(EnvI& env, Val v, FunctionI* fi) {}
191};
192class EvalArrayLit : public EvalBase {
193public:
194 typedef ArrayLit* Val;
195 typedef Expression* ArrayVal;
196 static ArrayLit* e(EnvI& env, Expression* e) { return eval_array_lit(env, e); }
197 static Expression* exp(Expression* e) { return e; }
198};
199class EvalArrayLitCopy : public EvalBase {
200public:
201 typedef ArrayLit* Val;
202 typedef Expression* ArrayVal;
203 static ArrayLit* e(EnvI& env, Expression* e) {
204 return copy(env, eval_array_lit(env, e), true)->cast<ArrayLit>();
205 }
206 static Expression* exp(Expression* e) { return e; }
207 static void checkRetVal(EnvI& env, Val v, FunctionI* fi) {
208 for (unsigned int i = 0; i < fi->ti()->ranges().size(); i++) {
209 if ((fi->ti()->ranges()[i]->domain() != nullptr) &&
210 !fi->ti()->ranges()[i]->domain()->isa<TIId>()) {
211 IntSetVal* isv = eval_intset(env, fi->ti()->ranges()[i]->domain());
212 bool bothEmpty = isv->min() > isv->max() && v->min(i) > v->max(i);
213 if (!bothEmpty && (v->min(i) != isv->min() || v->max(i) != isv->max())) {
214 std::ostringstream oss;
215 oss << "array index set " << (i + 1) << " of function result violates function type-inst";
216 throw ResultUndefinedError(env, fi->e()->loc(), oss.str());
217 }
218 }
219 }
220 if ((fi->ti()->domain() != nullptr) && !fi->ti()->domain()->isa<TIId>() &&
221 fi->ti()->type().ti() == Type::TI_PAR) {
222 Type base_t = fi->ti()->type();
223 if (base_t.bt() == Type::BT_INT) {
224 IntSetVal* isv = eval_intset(env, fi->ti()->domain());
225 if (base_t.st() == Type::ST_PLAIN) {
226 for (unsigned int i = 0; i < v->size(); i++) {
227 IntVal iv = eval_int(env, (*v)[i]);
228 if (!isv->contains(iv)) {
229 std::ostringstream oss;
230 oss << "array contains value " << iv << " which is not contained in " << *isv;
231 throw ResultUndefinedError(
232 env, fi->e()->loc(), "function result violates function type-inst, " + oss.str());
233 }
234 }
235 } else {
236 for (unsigned int i = 0; i < v->size(); i++) {
237 IntSetVal* iv = eval_intset(env, (*v)[i]);
238 IntSetRanges isv_r(isv);
239 IntSetRanges v_r(iv);
240 if (!Ranges::subset(v_r, isv_r)) {
241 std::ostringstream oss;
242 oss << "array contains value " << *iv << " which is not a subset of " << *isv;
243 throw ResultUndefinedError(
244 env, fi->e()->loc(), "function result violates function type-inst, " + oss.str());
245 }
246 }
247 }
248 } else if (base_t.bt() == Type::BT_FLOAT) {
249 FloatSetVal* fsv = eval_floatset(env, fi->ti()->domain());
250 if (base_t.st() == Type::ST_PLAIN) {
251 for (unsigned int i = 0; i < v->size(); i++) {
252 FloatVal fv = eval_float(env, (*v)[i]);
253 if (!fsv->contains(fv)) {
254 std::ostringstream oss;
255 oss << "array contains value " << fv << " which is not contained in " << *fsv;
256 throw ResultUndefinedError(
257 env, fi->e()->loc(), "function result violates function type-inst, " + oss.str());
258 }
259 }
260 } else {
261 for (unsigned int i = 0; i < v->size(); i++) {
262 FloatSetVal* fv = eval_floatset(env, (*v)[i]);
263 FloatSetRanges fsv_r(fsv);
264 FloatSetRanges v_r(fv);
265 if (!Ranges::subset(v_r, fsv_r)) {
266 std::ostringstream oss;
267 oss << "array contains value " << *fv << " which is not a subset of " << *fsv;
268 throw ResultUndefinedError(
269 env, fi->e()->loc(), "function result violates function type-inst, " + oss.str());
270 }
271 }
272 }
273 }
274 }
275 }
276};
277class EvalIntSet : public EvalBase {
278public:
279 typedef IntSetVal* Val;
280 static IntSetVal* e(EnvI& env, Expression* e) { return eval_intset(env, e); }
281 static Expression* exp(IntSetVal* e) { return new SetLit(Location(), e); }
282 static void checkRetVal(EnvI& env, Val v, FunctionI* fi) {
283 if ((fi->ti()->domain() != nullptr) && !fi->ti()->domain()->isa<TIId>()) {
284 IntSetVal* isv = eval_intset(env, fi->ti()->domain());
285 IntSetRanges isv_r(isv);
286 IntSetRanges v_r(v);
287 if (!Ranges::subset(v_r, isv_r)) {
288 throw ResultUndefinedError(env, Location().introduce(),
289 "function result violates function type-inst");
290 }
291 }
292 }
293};
294class EvalFloatSet : public EvalBase {
295public:
296 typedef FloatSetVal* Val;
297 static FloatSetVal* e(EnvI& env, Expression* e) { return eval_floatset(env, e); }
298 static Expression* exp(FloatSetVal* e) { return new SetLit(Location(), e); }
299 static void checkRetVal(EnvI& env, Val v, FunctionI* fi) {
300 if ((fi->ti()->domain() != nullptr) && !fi->ti()->domain()->isa<TIId>()) {
301 FloatSetVal* fsv = eval_floatset(env, fi->ti()->domain());
302 FloatSetRanges fsv_r(fsv);
303 FloatSetRanges v_r(v);
304 if (!Ranges::subset(v_r, fsv_r)) {
305 throw ResultUndefinedError(env, Location().introduce(),
306 "function result violates function type-inst");
307 }
308 }
309 }
310};
311class EvalBoolSet : public EvalBase {
312public:
313 typedef IntSetVal* Val;
314 static IntSetVal* e(EnvI& env, Expression* e) { return eval_boolset(env, e); }
315 static Expression* exp(IntSetVal* e) {
316 auto* sl = new SetLit(Location(), e);
317 sl->type(Type::parsetbool());
318 return sl;
319 }
320 static void checkRetVal(EnvI& env, Val v, FunctionI* fi) {}
321};
322class EvalSetLit : public EvalBase {
323public:
324 typedef SetLit* Val;
325 typedef Expression* ArrayVal;
326 static SetLit* e(EnvI& env, Expression* e) { return eval_set_lit(env, e); }
327 static Expression* exp(Expression* e) { return e; }
328};
329class EvalFloatSetLit : public EvalBase {
330public:
331 typedef SetLit* Val;
332 typedef Expression* ArrayVal;
333 static SetLit* e(EnvI& env, Expression* e) { return new SetLit(e->loc(), eval_floatset(env, e)); }
334 static Expression* exp(Expression* e) { return e; }
335};
336class EvalBoolSetLit : public EvalBase {
337public:
338 typedef SetLit* Val;
339 typedef Expression* ArrayVal;
340 static SetLit* e(EnvI& env, Expression* e) {
341 auto* sl = new SetLit(e->loc(), eval_boolset(env, e));
342 sl->type(Type::parsetbool());
343 return sl;
344 }
345 static Expression* exp(Expression* e) { return e; }
346};
347class EvalCopy : public EvalBase {
348public:
349 typedef Expression* Val;
350 typedef Expression* ArrayVal;
351 static Expression* e(EnvI& env, Expression* e) { return copy(env, e, true); }
352 static Expression* exp(Expression* e) { return e; }
353};
354class EvalPar : public EvalBase {
355public:
356 typedef Expression* Val;
357 typedef Expression* ArrayVal;
358 static Expression* e(EnvI& env, Expression* e) { return eval_par(env, e); }
359 static Expression* exp(Expression* e) { return e; }
360 static void checkRetVal(EnvI& env, Val v, FunctionI* fi) {}
361};
362
363void check_dom(EnvI& env, Id* arg, IntSetVal* dom, Expression* e) {
364 bool oob = false;
365 if (!e->type().isOpt()) {
366 if (e->type().isIntSet()) {
367 IntSetVal* ev = eval_intset(env, e);
368 IntSetRanges ev_r(ev);
369 IntSetRanges dom_r(dom);
370 oob = !Ranges::subset(ev_r, dom_r);
371 } else {
372 oob = !dom->contains(eval_int(env, e));
373 }
374 }
375 if (oob) {
376 std::ostringstream oss;
377 oss << "value for argument `" << *arg << "' out of bounds";
378 throw EvalError(env, e->loc(), oss.str());
379 }
380}
381
382void check_dom(EnvI& env, Id* arg, FloatVal dom_min, FloatVal dom_max, Expression* e) {
383 if (!e->type().isOpt()) {
384 FloatVal ev = eval_float(env, e);
385 if (ev < dom_min || ev > dom_max) {
386 std::ostringstream oss;
387 oss << "value for argument `" << *arg << "' out of bounds";
388 throw EvalError(env, e->loc(), oss.str());
389 }
390 }
391}
392
393template <class Eval, class CallClass = Call>
394typename Eval::Val eval_call(EnvI& env, CallClass* ce) {
395 std::vector<Expression*> previousParameters(ce->decl()->paramCount());
396 std::vector<Expression*> params(ce->decl()->paramCount());
397 for (unsigned int i = 0; i < ce->decl()->paramCount(); i++) {
398 params[i] = eval_par(env, ce->arg(i));
399 }
400 for (unsigned int i = ce->decl()->paramCount(); i--;) {
401 VarDecl* vd = ce->decl()->param(i);
402 if (vd->type().dim() > 0) {
403 // Check array index sets
404 auto* al = params[i]->cast<ArrayLit>();
405 for (unsigned int j = 0; j < vd->ti()->ranges().size(); j++) {
406 TypeInst* range_ti = vd->ti()->ranges()[j];
407 if (range_ti->domain() && !range_ti->domain()->isa<TIId>()) {
408 IntSetVal* isv = eval_intset(env, range_ti->domain());
409 if (isv->min() != al->min(j) || isv->max() != al->max(j)) {
410 std::ostringstream oss;
411 oss << "array index set " << (j + 1) << " of argument " << (i + 1)
412 << " does not match declared index set";
413 throw EvalError(env, ce->loc(), oss.str());
414 }
415 }
416 }
417 }
418 previousParameters[i] = vd->e();
419 vd->flat(vd);
420 vd->e(params[i]);
421 if (vd->e()->type().isPar()) {
422 if (Expression* dom = vd->ti()->domain()) {
423 if (!dom->isa<TIId>()) {
424 if (vd->e()->type().bt() == Type::BT_INT) {
425 IntSetVal* isv = eval_intset(env, dom);
426 if (vd->e()->type().dim() > 0) {
427 ArrayLit* al = eval_array_lit(env, vd->e());
428 for (unsigned int i = 0; i < al->size(); i++) {
429 check_dom(env, vd->id(), isv, (*al)[i]);
430 }
431 } else {
432 check_dom(env, vd->id(), isv, vd->e());
433 }
434 } else if (vd->e()->type().bt() == Type::BT_FLOAT) {
435 GCLock lock;
436 FloatSetVal* fsv = eval_floatset(env, dom);
437 FloatVal dom_min = fsv->min();
438 FloatVal dom_max = fsv->max();
439 check_dom(env, vd->id(), dom_min, dom_max, vd->e());
440 }
441 }
442 }
443 }
444 }
445 KeepAlive previousCapture;
446 if (ce->decl()->capturedAnnotationsVar() != nullptr) {
447 previousCapture = ce->decl()->capturedAnnotationsVar()->e();
448 GCLock lock;
449 ce->decl()->capturedAnnotationsVar()->flat(ce->decl()->capturedAnnotationsVar());
450 ce->decl()->capturedAnnotationsVar()->e(env.createAnnotationArray(C_MIX));
451 }
452 typename Eval::Val ret = Eval::e(env, ce->decl()->e());
453 Eval::checkRetVal(env, ret, ce->decl());
454 for (unsigned int i = ce->decl()->paramCount(); i--;) {
455 VarDecl* vd = ce->decl()->param(i);
456 vd->e(previousParameters[i]);
457 vd->flat(vd->e() ? vd : nullptr);
458 }
459 if (ce->decl()->capturedAnnotationsVar() != nullptr) {
460 ce->decl()->capturedAnnotationsVar()->e(previousCapture());
461 ce->decl()->capturedAnnotationsVar()->flat(ce->decl()->capturedAnnotationsVar()->e() != nullptr
462 ? ce->decl()->capturedAnnotationsVar()
463 : nullptr);
464 }
465 return ret;
466}
467
468ArrayLit* eval_array_comp(EnvI& env, Comprehension* e) {
469 ArrayLit* ret;
470 if (e->type() == Type::parint(1)) {
471 std::vector<Expression*> a = eval_comp<EvalIntLit>(env, e);
472 ret = new ArrayLit(e->loc(), a);
473 } else if (e->type() == Type::parbool(1)) {
474 std::vector<Expression*> a = eval_comp<EvalBoolLit>(env, e);
475 ret = new ArrayLit(e->loc(), a);
476 } else if (e->type() == Type::parfloat(1)) {
477 std::vector<Expression*> a = eval_comp<EvalFloatLit>(env, e);
478 ret = new ArrayLit(e->loc(), a);
479 } else if (e->type().st() == Type::ST_SET) {
480 std::vector<Expression*> a = eval_comp<EvalSetLit>(env, e);
481 ret = new ArrayLit(e->loc(), a);
482 } else if (e->type() == Type::parstring(1)) {
483 std::vector<Expression*> a = eval_comp<EvalStringLit>(env, e);
484 ret = new ArrayLit(e->loc(), a);
485 } else {
486 std::vector<Expression*> a = eval_comp<EvalCopy>(env, e);
487 ret = new ArrayLit(e->loc(), a);
488 }
489 ret->type(e->type());
490 return ret;
491}
492
493ArrayLit* eval_array_lit(EnvI& env, Expression* e) {
494 CallStackItem csi(env, e);
495 switch (e->eid()) {
496 case Expression::E_INTLIT:
497 case Expression::E_FLOATLIT:
498 case Expression::E_BOOLLIT:
499 case Expression::E_STRINGLIT:
500 case Expression::E_SETLIT:
501 case Expression::E_ANON:
502 case Expression::E_TI:
503 case Expression::E_TIID:
504 case Expression::E_VARDECL:
505 throw EvalError(env, e->loc(), "not an array expression");
506 case Expression::E_ID:
507 return eval_id<EvalArrayLit>(env, e);
508 case Expression::E_ARRAYLIT:
509 return e->cast<ArrayLit>();
510 case Expression::E_ARRAYACCESS:
511 throw EvalError(env, e->loc(), "arrays of arrays not supported");
512 case Expression::E_COMP:
513 return eval_array_comp(env, e->cast<Comprehension>());
514 case Expression::E_ITE: {
515 ITE* ite = e->cast<ITE>();
516 for (int i = 0; i < ite->size(); i++) {
517 if (eval_bool(env, ite->ifExpr(i))) {
518 return eval_array_lit(env, ite->thenExpr(i));
519 }
520 }
521 return eval_array_lit(env, ite->elseExpr());
522 }
523 case Expression::E_BINOP: {
524 auto* bo = e->cast<BinOp>();
525 if (bo->op() == BOT_PLUSPLUS) {
526 ArrayLit* al0 = eval_array_lit(env, bo->lhs());
527 ArrayLit* al1 = eval_array_lit(env, bo->rhs());
528 std::vector<Expression*> v(al0->size() + al1->size());
529 for (unsigned int i = al0->size(); (i--) != 0U;) {
530 v[i] = (*al0)[i];
531 }
532 for (unsigned int i = al1->size(); (i--) != 0U;) {
533 v[al0->size() + i] = (*al1)[i];
534 }
535 auto* ret = new ArrayLit(e->loc(), v);
536 ret->flat(al0->flat() && al1->flat());
537 ret->type(e->type());
538 return ret;
539 }
540 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
541 return eval_call<EvalArrayLitCopy, BinOp>(env, bo);
542 }
543 throw EvalError(env, e->loc(), "not an array expression", bo->opToString());
544
545 } break;
546 case Expression::E_UNOP: {
547 UnOp* uo = e->cast<UnOp>();
548 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
549 return eval_call<EvalArrayLitCopy, UnOp>(env, uo);
550 }
551 throw EvalError(env, e->loc(), "not an array expression");
552 }
553 case Expression::E_CALL: {
554 Call* ce = e->cast<Call>();
555 if (ce->decl() == nullptr) {
556 throw EvalError(env, e->loc(), "undeclared function", ce->id());
557 }
558
559 if (ce->decl()->builtins.e != nullptr) {
560 return eval_array_lit(env, ce->decl()->builtins.e(env, ce));
561 }
562
563 if (ce->decl()->e() == nullptr) {
564 std::ostringstream ss;
565 ss << "internal error: missing builtin '" << ce->id() << "'";
566 throw EvalError(env, ce->loc(), ss.str());
567 }
568
569 return eval_call<EvalArrayLitCopy>(env, ce);
570 }
571 case Expression::E_LET: {
572 Let* l = e->cast<Let>();
573 l->pushbindings();
574 for (unsigned int i = 0; i < l->let().size(); i++) {
575 // Evaluate all variable declarations
576 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
577 vdi->e(eval_par(env, vdi->e()));
578 check_par_declaration(env, vdi);
579 } else {
580 // This is a constraint item. Since the let is par,
581 // it can only be a par bool expression. If it evaluates
582 // to false, it means that the value of this let is undefined.
583 if (!eval_bool(env, l->let()[i])) {
584 throw ResultUndefinedError(env, l->let()[i]->loc(), "constraint in let failed");
585 }
586 }
587 }
588 ArrayLit* l_in = eval_array_lit(env, l->in());
589 auto* ret = copy(env, l_in, true)->cast<ArrayLit>();
590 ret->flat(l_in->flat());
591 l->popbindings();
592 return ret;
593 }
594 }
595 assert(false);
596 return nullptr;
597}
598
599Expression* eval_arrayaccess(EnvI& env, ArrayLit* al, const std::vector<IntVal>& idx,
600 bool& success) {
601 success = true;
602 assert(al->dims() == idx.size());
603 IntVal realidx = 0;
604 int realdim = 1;
605 for (int i = 0; i < al->dims(); i++) {
606 realdim *= al->max(i) - al->min(i) + 1;
607 }
608 for (int i = 0; i < al->dims(); i++) {
609 IntVal ix = idx[i];
610 if (ix < al->min(i) || ix > al->max(i)) {
611 success = false;
612 Type t = al->type();
613 t.dim(0);
614 if (t.isint()) {
615 return IntLit::a(0);
616 }
617 if (t.isbool()) {
618 return constants().literalFalse;
619 }
620 if (t.isfloat()) {
621 return FloatLit::a(0.0);
622 }
623 if (t.st() == Type::ST_SET || t.isbot()) {
624 auto* ret = new SetLit(Location(), std::vector<Expression*>());
625 ret->type(t);
626 return ret;
627 }
628 if (t.isstring()) {
629 return new StringLit(Location(), "");
630 }
631 throw EvalError(env, al->loc(), "Internal error: unexpected type in array access expression");
632 }
633 realdim /= al->max(i) - al->min(i) + 1;
634 realidx += (ix - al->min(i)) * realdim;
635 }
636 assert(realidx >= 0 && realidx <= al->size());
637 return (*al)[static_cast<unsigned int>(realidx.toInt())];
638}
639Expression* eval_arrayaccess(EnvI& env, ArrayAccess* e, bool& success) {
640 ArrayLit* al = eval_array_lit(env, e->v());
641 std::vector<IntVal> dims(e->idx().size());
642 for (unsigned int i = e->idx().size(); (i--) != 0U;) {
643 dims[i] = eval_int(env, e->idx()[i]);
644 }
645 return eval_arrayaccess(env, al, dims, success);
646}
647Expression* eval_arrayaccess(EnvI& env, ArrayAccess* e) {
648 bool success;
649 Expression* ret = eval_arrayaccess(env, e, success);
650 if (success) {
651 return ret;
652 }
653 throw ResultUndefinedError(env, e->loc(), "array access out of bounds");
654}
655
656SetLit* eval_set_lit(EnvI& env, Expression* e) {
657 switch (e->type().bt()) {
658 case Type::BT_INT:
659 case Type::BT_BOT:
660 return new SetLit(e->loc(), eval_intset(env, e));
661 case Type::BT_BOOL: {
662 auto* sl = new SetLit(e->loc(), eval_boolset(env, e));
663 sl->type(Type::parsetbool());
664 return sl;
665 }
666 case Type::BT_FLOAT:
667 return new SetLit(e->loc(), eval_floatset(env, e));
668 default:
669 throw InternalError("invalid set literal type");
670 }
671}
672
673IntSetVal* eval_intset(EnvI& env, Expression* e) {
674 if (auto* sl = e->dynamicCast<SetLit>()) {
675 if (sl->isv() != nullptr) {
676 return sl->isv();
677 }
678 }
679 CallStackItem csi(env, e);
680 switch (e->eid()) {
681 case Expression::E_SETLIT: {
682 auto* sl = e->cast<SetLit>();
683 std::vector<IntVal> vals;
684 for (unsigned int i = 0; i < sl->v().size(); i++) {
685 Expression* vi = eval_par(env, sl->v()[i]);
686 if (vi != constants().absent) {
687 vals.push_back(eval_int(env, vi));
688 }
689 }
690 return IntSetVal::a(vals);
691 }
692 case Expression::E_BOOLLIT:
693 case Expression::E_INTLIT:
694 case Expression::E_FLOATLIT:
695 case Expression::E_STRINGLIT:
696 case Expression::E_ANON:
697 case Expression::E_TIID:
698 case Expression::E_VARDECL:
699 case Expression::E_TI:
700 throw EvalError(env, e->loc(), "not a set of int expression");
701 break;
702 case Expression::E_ARRAYLIT: {
703 auto* al = e->cast<ArrayLit>();
704 std::vector<IntVal> vals(al->size());
705 for (unsigned int i = 0; i < al->size(); i++) {
706 vals[i] = eval_int(env, (*al)[i]);
707 }
708 return IntSetVal::a(vals);
709 } break;
710 case Expression::E_COMP: {
711 auto* c = e->cast<Comprehension>();
712 std::vector<IntVal> a = eval_comp<EvalIntVal>(env, c);
713 return IntSetVal::a(a);
714 }
715 case Expression::E_ID: {
716 GCLock lock;
717 return eval_id<EvalSetLit>(env, e)->isv();
718 } break;
719 case Expression::E_ARRAYACCESS: {
720 GCLock lock;
721 return eval_intset(env, eval_arrayaccess(env, e->cast<ArrayAccess>()));
722 } break;
723 case Expression::E_ITE: {
724 ITE* ite = e->cast<ITE>();
725 for (int i = 0; i < ite->size(); i++) {
726 if (eval_bool(env, ite->ifExpr(i))) {
727 return eval_intset(env, ite->thenExpr(i));
728 }
729 }
730 return eval_intset(env, ite->elseExpr());
731 } break;
732 case Expression::E_BINOP: {
733 auto* bo = e->cast<BinOp>();
734 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
735 return eval_call<EvalIntSet, BinOp>(env, bo);
736 }
737 Expression* lhs = eval_par(env, bo->lhs());
738 Expression* rhs = eval_par(env, bo->rhs());
739 if (lhs->type().isIntSet() && rhs->type().isIntSet()) {
740 IntSetVal* v0 = eval_intset(env, lhs);
741 IntSetVal* v1 = eval_intset(env, rhs);
742 IntSetRanges ir0(v0);
743 IntSetRanges ir1(v1);
744 switch (bo->op()) {
745 case BOT_UNION: {
746 Ranges::Union<IntVal, IntSetRanges, IntSetRanges> u(ir0, ir1);
747 return IntSetVal::ai(u);
748 }
749 case BOT_DIFF: {
750 Ranges::Diff<IntVal, IntSetRanges, IntSetRanges> u(ir0, ir1);
751 return IntSetVal::ai(u);
752 }
753 case BOT_SYMDIFF: {
754 Ranges::Union<IntVal, IntSetRanges, IntSetRanges> u(ir0, ir1);
755 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> i(ir0, ir1);
756 Ranges::Diff<IntVal, Ranges::Union<IntVal, IntSetRanges, IntSetRanges>,
757 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges>>
758 sd(u, i);
759 return IntSetVal::ai(sd);
760 }
761 case BOT_INTERSECT: {
762 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> u(ir0, ir1);
763 return IntSetVal::ai(u);
764 }
765 default:
766 throw EvalError(env, e->loc(), "not a set of int expression", bo->opToString());
767 }
768 } else if (lhs->type().isint() && rhs->type().isint()) {
769 if (bo->op() != BOT_DOTDOT) {
770 throw EvalError(env, e->loc(), "not a set of int expression", bo->opToString());
771 }
772 return IntSetVal::a(eval_int(env, lhs), eval_int(env, rhs));
773 } else {
774 throw EvalError(env, e->loc(), "not a set of int expression", bo->opToString());
775 }
776 } break;
777 case Expression::E_UNOP: {
778 UnOp* uo = e->cast<UnOp>();
779 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
780 return eval_call<EvalIntSet, UnOp>(env, uo);
781 }
782 throw EvalError(env, e->loc(), "not a set of int expression");
783 }
784 case Expression::E_CALL: {
785 Call* ce = e->cast<Call>();
786 if (ce->decl() == nullptr) {
787 throw EvalError(env, e->loc(), "undeclared function", ce->id());
788 }
789
790 if (ce->decl()->builtins.s != nullptr) {
791 return ce->decl()->builtins.s(env, ce);
792 }
793
794 if (ce->decl()->builtins.e != nullptr) {
795 return eval_intset(env, ce->decl()->builtins.e(env, ce));
796 }
797
798 if (ce->decl()->e() == nullptr) {
799 std::ostringstream ss;
800 ss << "internal error: missing builtin '" << ce->id() << "'";
801 throw EvalError(env, ce->loc(), ss.str());
802 }
803
804 return eval_call<EvalIntSet>(env, ce);
805 } break;
806 case Expression::E_LET: {
807 Let* l = e->cast<Let>();
808 l->pushbindings();
809 for (unsigned int i = 0; i < l->let().size(); i++) {
810 // Evaluate all variable declarations
811 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
812 vdi->e(eval_par(env, vdi->e()));
813 check_par_declaration(env, vdi);
814 } else {
815 // This is a constraint item. Since the let is par,
816 // it can only be a par bool expression. If it evaluates
817 // to false, it means that the value of this let is undefined.
818 if (!eval_bool(env, l->let()[i])) {
819 throw ResultUndefinedError(env, l->let()[i]->loc(), "constraint in let failed");
820 }
821 }
822 }
823 IntSetVal* ret = eval_intset(env, l->in());
824 l->popbindings();
825 return ret;
826 } break;
827 default:
828 assert(false);
829 return nullptr;
830 }
831}
832
833FloatSetVal* eval_floatset(EnvI& env, Expression* e) {
834 if (auto* sl = e->dynamicCast<SetLit>()) {
835 if (sl->fsv() != nullptr) {
836 return sl->fsv();
837 }
838 if (sl->isv() != nullptr) {
839 IntSetRanges isr(sl->isv());
840 return FloatSetVal::ai(isr);
841 }
842 }
843 CallStackItem csi(env, e);
844 switch (e->eid()) {
845 case Expression::E_SETLIT: {
846 auto* sl = e->cast<SetLit>();
847 std::vector<FloatVal> vals;
848 for (unsigned int i = 0; i < sl->v().size(); i++) {
849 Expression* vi = eval_par(env, sl->v()[i]);
850 if (vi != constants().absent) {
851 vals.push_back(eval_float(env, vi));
852 }
853 }
854 return FloatSetVal::a(vals);
855 }
856 case Expression::E_BOOLLIT:
857 case Expression::E_INTLIT:
858 case Expression::E_FLOATLIT:
859 case Expression::E_STRINGLIT:
860 case Expression::E_ANON:
861 case Expression::E_TIID:
862 case Expression::E_VARDECL:
863 case Expression::E_TI:
864 throw EvalError(env, e->loc(), "not a set of float expression");
865 break;
866 case Expression::E_ARRAYLIT: {
867 auto* al = e->cast<ArrayLit>();
868 std::vector<FloatVal> vals(al->size());
869 for (unsigned int i = 0; i < al->size(); i++) {
870 vals[i] = eval_float(env, (*al)[i]);
871 }
872 return FloatSetVal::a(vals);
873 } break;
874 case Expression::E_COMP: {
875 auto* c = e->cast<Comprehension>();
876 std::vector<FloatVal> a = eval_comp<EvalFloatVal>(env, c);
877 return FloatSetVal::a(a);
878 }
879 case Expression::E_ID: {
880 GCLock lock;
881 return eval_floatset(env, eval_id<EvalFloatSetLit>(env, e));
882 } break;
883 case Expression::E_ARRAYACCESS: {
884 GCLock lock;
885 return eval_floatset(env, eval_arrayaccess(env, e->cast<ArrayAccess>()));
886 } break;
887 case Expression::E_ITE: {
888 ITE* ite = e->cast<ITE>();
889 for (int i = 0; i < ite->size(); i++) {
890 if (eval_bool(env, ite->ifExpr(i))) {
891 return eval_floatset(env, ite->thenExpr(i));
892 }
893 }
894 return eval_floatset(env, ite->elseExpr());
895 } break;
896 case Expression::E_BINOP: {
897 auto* bo = e->cast<BinOp>();
898 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
899 return eval_call<EvalFloatSet, BinOp>(env, bo);
900 }
901 Expression* lhs = eval_par(env, bo->lhs());
902 Expression* rhs = eval_par(env, bo->rhs());
903 if (lhs->type().isFloatSet() && rhs->type().isFloatSet()) {
904 FloatSetVal* v0 = eval_floatset(env, lhs);
905 FloatSetVal* v1 = eval_floatset(env, rhs);
906 FloatSetRanges fr0(v0);
907 FloatSetRanges fr1(v1);
908 switch (bo->op()) {
909 case BOT_UNION: {
910 Ranges::Union<FloatVal, FloatSetRanges, FloatSetRanges> u(fr0, fr1);
911 return FloatSetVal::ai(u);
912 }
913 case BOT_DIFF: {
914 Ranges::Diff<FloatVal, FloatSetRanges, FloatSetRanges> u(fr0, fr1);
915 return FloatSetVal::ai(u);
916 }
917 case BOT_SYMDIFF: {
918 Ranges::Union<FloatVal, FloatSetRanges, FloatSetRanges> u(fr0, fr1);
919 Ranges::Inter<FloatVal, FloatSetRanges, FloatSetRanges> i(fr0, fr1);
920 Ranges::Diff<FloatVal, Ranges::Union<FloatVal, FloatSetRanges, FloatSetRanges>,
921 Ranges::Inter<FloatVal, FloatSetRanges, FloatSetRanges>>
922 sd(u, i);
923 return FloatSetVal::ai(sd);
924 }
925 case BOT_INTERSECT: {
926 Ranges::Inter<FloatVal, FloatSetRanges, FloatSetRanges> u(fr0, fr1);
927 return FloatSetVal::ai(u);
928 }
929 default:
930 throw EvalError(env, e->loc(), "not a set of int expression", bo->opToString());
931 }
932 } else if (lhs->type().isfloat() && rhs->type().isfloat()) {
933 if (bo->op() != BOT_DOTDOT) {
934 throw EvalError(env, e->loc(), "not a set of float expression", bo->opToString());
935 }
936 return FloatSetVal::a(eval_float(env, lhs), eval_float(env, rhs));
937 } else {
938 throw EvalError(env, e->loc(), "not a set of float expression", bo->opToString());
939 }
940 } break;
941 case Expression::E_UNOP: {
942 UnOp* uo = e->cast<UnOp>();
943 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
944 return eval_call<EvalFloatSet, UnOp>(env, uo);
945 }
946 throw EvalError(env, e->loc(), "not a set of float expression");
947 }
948 case Expression::E_CALL: {
949 Call* ce = e->cast<Call>();
950 if (ce->decl() == nullptr) {
951 throw EvalError(env, e->loc(), "undeclared function", ce->id());
952 }
953
954 if (ce->decl()->builtins.e != nullptr) {
955 return eval_floatset(env, ce->decl()->builtins.e(env, ce));
956 }
957
958 if (ce->decl()->e() == nullptr) {
959 std::ostringstream ss;
960 ss << "internal error: missing builtin '" << ce->id() << "'";
961 throw EvalError(env, ce->loc(), ss.str());
962 }
963
964 return eval_call<EvalFloatSet>(env, ce);
965 } break;
966 case Expression::E_LET: {
967 Let* l = e->cast<Let>();
968 l->pushbindings();
969 for (unsigned int i = 0; i < l->let().size(); i++) {
970 // Evaluate all variable declarations
971 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
972 vdi->e(eval_par(env, vdi->e()));
973 check_par_declaration(env, vdi);
974 } else {
975 // This is a constraint item. Since the let is par,
976 // it can only be a par bool expression. If it evaluates
977 // to false, it means that the value of this let is undefined.
978 if (!eval_bool(env, l->let()[i])) {
979 throw ResultUndefinedError(env, l->let()[i]->loc(), "constraint in let failed");
980 }
981 }
982 }
983 FloatSetVal* ret = eval_floatset(env, l->in());
984 l->popbindings();
985 return ret;
986 } break;
987 default:
988 assert(false);
989 return nullptr;
990 }
991}
992
993bool eval_bool(EnvI& env, Expression* e) {
994 CallStackItem csi(env, e);
995 try {
996 if (auto* bl = e->dynamicCast<BoolLit>()) {
997 return bl->v();
998 }
999 switch (e->eid()) {
1000 case Expression::E_INTLIT:
1001 case Expression::E_FLOATLIT:
1002 case Expression::E_STRINGLIT:
1003 case Expression::E_ANON:
1004 case Expression::E_TIID:
1005 case Expression::E_SETLIT:
1006 case Expression::E_ARRAYLIT:
1007 case Expression::E_COMP:
1008 case Expression::E_VARDECL:
1009 case Expression::E_TI:
1010 assert(false);
1011 throw EvalError(env, e->loc(), "not a bool expression");
1012 break;
1013 case Expression::E_ID: {
1014 GCLock lock;
1015 return eval_id<EvalBoolLit>(env, e)->v();
1016 } break;
1017 case Expression::E_ARRAYACCESS: {
1018 GCLock lock;
1019 return eval_bool(env, eval_arrayaccess(env, e->cast<ArrayAccess>()));
1020 } break;
1021 case Expression::E_ITE: {
1022 ITE* ite = e->cast<ITE>();
1023 for (int i = 0; i < ite->size(); i++) {
1024 if (eval_bool(env, ite->ifExpr(i))) {
1025 return eval_bool(env, ite->thenExpr(i));
1026 }
1027 }
1028 return eval_bool(env, ite->elseExpr());
1029 } break;
1030 case Expression::E_BINOP: {
1031 auto* bo = e->cast<BinOp>();
1032 Expression* lhs = bo->lhs();
1033 if (lhs->type().bt() == Type::BT_TOP) {
1034 lhs = eval_par(env, lhs);
1035 }
1036 Expression* rhs = bo->rhs();
1037 if (rhs->type().bt() == Type::BT_TOP) {
1038 rhs = eval_par(env, rhs);
1039 }
1040 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
1041 return eval_call<EvalBoolVal, BinOp>(env, bo);
1042 }
1043
1044 if (lhs->type().isbool() && rhs->type().isbool()) {
1045 try {
1046 switch (bo->op()) {
1047 case BOT_LE:
1048 return static_cast<int>(eval_bool(env, lhs)) <
1049 static_cast<int>(eval_bool(env, rhs));
1050 case BOT_LQ:
1051 return static_cast<int>(eval_bool(env, lhs)) <=
1052 static_cast<int>(eval_bool(env, rhs));
1053 case BOT_GR:
1054 return static_cast<int>(eval_bool(env, lhs)) >
1055 static_cast<int>(eval_bool(env, rhs));
1056 case BOT_GQ:
1057 return static_cast<int>(eval_bool(env, lhs)) >=
1058 static_cast<int>(eval_bool(env, rhs));
1059 case BOT_EQ:
1060 return eval_bool(env, lhs) == eval_bool(env, rhs);
1061 case BOT_NQ:
1062 return eval_bool(env, lhs) != eval_bool(env, rhs);
1063 case BOT_EQUIV:
1064 return eval_bool(env, lhs) == eval_bool(env, rhs);
1065 case BOT_IMPL:
1066 return (!eval_bool(env, lhs)) || eval_bool(env, rhs);
1067 case BOT_RIMPL:
1068 return (!eval_bool(env, rhs)) || eval_bool(env, lhs);
1069 case BOT_OR:
1070 return eval_bool(env, lhs) || eval_bool(env, rhs);
1071 case BOT_AND:
1072 return eval_bool(env, lhs) && eval_bool(env, rhs);
1073 case BOT_XOR:
1074 return eval_bool(env, lhs) ^ eval_bool(env, rhs);
1075 default:
1076 assert(false);
1077 throw EvalError(env, e->loc(), "not a bool expression", bo->opToString());
1078 }
1079 } catch (ResultUndefinedError&) {
1080 return false;
1081 }
1082 } else if (lhs->type().isint() && rhs->type().isint()) {
1083 try {
1084 IntVal v0 = eval_int(env, lhs);
1085 IntVal v1 = eval_int(env, rhs);
1086 switch (bo->op()) {
1087 case BOT_LE:
1088 return v0 < v1;
1089 case BOT_LQ:
1090 return v0 <= v1;
1091 case BOT_GR:
1092 return v0 > v1;
1093 case BOT_GQ:
1094 return v0 >= v1;
1095 case BOT_EQ:
1096 return v0 == v1;
1097 case BOT_NQ:
1098 return v0 != v1;
1099 default:
1100 assert(false);
1101 throw EvalError(env, e->loc(), "not a bool expression", bo->opToString());
1102 }
1103 } catch (ResultUndefinedError&) {
1104 return false;
1105 }
1106 } else if (lhs->type().isfloat() && rhs->type().isfloat()) {
1107 try {
1108 FloatVal v0 = eval_float(env, lhs);
1109 FloatVal v1 = eval_float(env, rhs);
1110 switch (bo->op()) {
1111 case BOT_LE:
1112 return v0 < v1;
1113 case BOT_LQ:
1114 return v0 <= v1;
1115 case BOT_GR:
1116 return v0 > v1;
1117 case BOT_GQ:
1118 return v0 >= v1;
1119 case BOT_EQ:
1120 return v0 == v1;
1121 case BOT_NQ:
1122 return v0 != v1;
1123 default:
1124 assert(false);
1125 throw EvalError(env, e->loc(), "not a bool expression", bo->opToString());
1126 }
1127 } catch (ResultUndefinedError&) {
1128 return false;
1129 }
1130 } else if (lhs->type().isint() && rhs->type().isIntSet()) {
1131 try {
1132 IntVal v0 = eval_int(env, lhs);
1133 GCLock lock;
1134 IntSetVal* v1 = eval_intset(env, rhs);
1135 switch (bo->op()) {
1136 case BOT_IN:
1137 return v1->contains(v0);
1138 default:
1139 assert(false);
1140 throw EvalError(env, e->loc(), "not a bool expression", bo->opToString());
1141 }
1142 } catch (ResultUndefinedError&) {
1143 return false;
1144 }
1145 } else if (lhs->type().isfloat() && rhs->type().isFloatSet()) {
1146 try {
1147 FloatVal v0 = eval_float(env, lhs);
1148 GCLock lock;
1149 FloatSetVal* v1 = eval_floatset(env, rhs);
1150 switch (bo->op()) {
1151 case BOT_IN:
1152 return v1->contains(v0);
1153 default:
1154 assert(false);
1155 throw EvalError(env, e->loc(), "not a bool expression", bo->opToString());
1156 }
1157 } catch (ResultUndefinedError&) {
1158 return false;
1159 }
1160 } else if (lhs->type().isSet() && rhs->type().isSet()) {
1161 try {
1162 GCLock lock;
1163 IntSetVal* v0 = eval_intset(env, lhs);
1164 IntSetVal* v1 = eval_intset(env, rhs);
1165 IntSetRanges ir0(v0);
1166 IntSetRanges ir1(v1);
1167 switch (bo->op()) {
1168 case BOT_LE:
1169 return Ranges::less(ir0, ir1);
1170 case BOT_LQ:
1171 return Ranges::less_eq(ir0, ir1);
1172 case BOT_GR:
1173 return Ranges::less(ir1, ir0);
1174 case BOT_GQ:
1175 return Ranges::less_eq(ir1, ir0);
1176 case BOT_EQ:
1177 return Ranges::equal(ir0, ir1);
1178 case BOT_NQ:
1179 return !Ranges::equal(ir0, ir1);
1180 case BOT_SUBSET:
1181 return Ranges::subset(ir0, ir1);
1182 case BOT_SUPERSET:
1183 return Ranges::subset(ir1, ir0);
1184 default:
1185 throw EvalError(env, e->loc(), "not a bool expression", bo->opToString());
1186 }
1187 } catch (ResultUndefinedError&) {
1188 return false;
1189 }
1190 } else if (lhs->type().isstring() && rhs->type().isstring()) {
1191 try {
1192 GCLock lock;
1193 std::string s0 = eval_string(env, lhs);
1194 std::string s1 = eval_string(env, rhs);
1195 switch (bo->op()) {
1196 case BOT_EQ:
1197 return s0 == s1;
1198 case BOT_NQ:
1199 return s0 != s1;
1200 case BOT_LE:
1201 return s0 < s1;
1202 case BOT_LQ:
1203 return s0 <= s1;
1204 case BOT_GR:
1205 return s0 > s1;
1206 case BOT_GQ:
1207 return s0 >= s1;
1208 default:
1209 throw EvalError(env, e->loc(), "not a bool expression", bo->opToString());
1210 }
1211 } catch (ResultUndefinedError&) {
1212 return false;
1213 }
1214 } else if (bo->op() == BOT_EQ && lhs->type().isAnn()) {
1215 // follow ann id to value, since there might be indirection (e.g. func argument, see
1216 // test_equality_of_indirect_annotations.mzn)
1217 return Expression::equal(follow_id_to_value(lhs), follow_id_to_value(rhs));
1218 } else if (bo->op() == BOT_EQ && lhs->type().dim() > 0 && rhs->type().dim() > 0) {
1219 try {
1220 ArrayLit* al0 = eval_array_lit(env, lhs);
1221 ArrayLit* al1 = eval_array_lit(env, rhs);
1222 if (al0->size() != al1->size()) {
1223 return false;
1224 }
1225 for (unsigned int i = 0; i < al0->size(); i++) {
1226 if (!Expression::equal(eval_par(env, (*al0)[i]), eval_par(env, (*al1)[i]))) {
1227 return false;
1228 }
1229 }
1230 return true;
1231 } catch (ResultUndefinedError&) {
1232 return false;
1233 }
1234 } else {
1235 throw EvalError(env, e->loc(), "not a bool expression", bo->opToString());
1236 }
1237 } break;
1238 case Expression::E_UNOP: {
1239 UnOp* uo = e->cast<UnOp>();
1240 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
1241 return eval_call<EvalBoolVal, UnOp>(env, uo);
1242 }
1243 bool v0 = eval_bool(env, uo->e());
1244 switch (uo->op()) {
1245 case UOT_NOT:
1246 return !v0;
1247 default:
1248 assert(false);
1249 throw EvalError(env, e->loc(), "not a bool expression", uo->opToString());
1250 }
1251 } break;
1252 case Expression::E_CALL: {
1253 try {
1254 Call* ce = e->cast<Call>();
1255 if (ce->decl() == nullptr) {
1256 throw EvalError(env, e->loc(), "undeclared function", ce->id());
1257 }
1258
1259 if (ce->decl()->builtins.b != nullptr) {
1260 return ce->decl()->builtins.b(env, ce);
1261 }
1262
1263 if (ce->decl()->builtins.e != nullptr) {
1264 return eval_bool(env, ce->decl()->builtins.e(env, ce));
1265 }
1266
1267 if (ce->decl()->e() == nullptr) {
1268 std::ostringstream ss;
1269 ss << "internal error: missing builtin '" << ce->id() << "'";
1270 throw EvalError(env, ce->loc(), ss.str());
1271 }
1272
1273 return eval_call<EvalBoolVal>(env, ce);
1274 } catch (ResultUndefinedError&) {
1275 return false;
1276 }
1277 } break;
1278 case Expression::E_LET: {
1279 Let* l = e->cast<Let>();
1280 l->pushbindings();
1281 bool ret = true;
1282 for (unsigned int i = 0; i < l->let().size(); i++) {
1283 // Evaluate all variable declarations
1284 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
1285 vdi->e(eval_par(env, vdi->e()));
1286 bool maybe_partial = vdi->ann().contains(constants().ann.maybe_partial);
1287 if (maybe_partial) {
1288 env.inMaybePartial++;
1289 }
1290 try {
1291 check_par_declaration(env, vdi);
1292 } catch (ResultUndefinedError&) {
1293 ret = false;
1294 }
1295 if (maybe_partial) {
1296 env.inMaybePartial--;
1297 }
1298 } else {
1299 // This is a constraint item. Since the let is par,
1300 // it can only be a par bool expression. If it evaluates
1301 // to false, it means that the value of this let is false.
1302 if (!eval_bool(env, l->let()[i])) {
1303 if (l->let()[i]->ann().contains(constants().ann.maybe_partial)) {
1304 ret = false;
1305 } else {
1306 throw ResultUndefinedError(env, l->let()[i]->loc(),
1307 "domain constraint in let failed");
1308 }
1309 }
1310 }
1311 }
1312 ret = ret && eval_bool(env, l->in());
1313 l->popbindings();
1314 return ret;
1315 } break;
1316 default:
1317 assert(false);
1318 return false;
1319 }
1320 } catch (ResultUndefinedError&) {
1321 // undefined means false
1322 return false;
1323 }
1324}
1325
1326IntSetVal* eval_boolset(EnvI& env, Expression* e) {
1327 CallStackItem csi(env, e);
1328 switch (e->eid()) {
1329 case Expression::E_SETLIT: {
1330 auto* sl = e->cast<SetLit>();
1331 if (sl->isv() != nullptr) {
1332 return sl->isv();
1333 }
1334 std::vector<IntVal> vals;
1335 for (unsigned int i = 0; i < sl->v().size(); i++) {
1336 Expression* vi = eval_par(env, sl->v()[i]);
1337 if (vi != constants().absent) {
1338 vals.push_back(eval_int(env, vi));
1339 }
1340 }
1341 return IntSetVal::a(vals);
1342 }
1343 case Expression::E_BOOLLIT:
1344 case Expression::E_INTLIT:
1345 case Expression::E_FLOATLIT:
1346 case Expression::E_STRINGLIT:
1347 case Expression::E_ANON:
1348 case Expression::E_TIID:
1349 case Expression::E_VARDECL:
1350 case Expression::E_TI:
1351 throw EvalError(env, e->loc(), "not a set of bool expression");
1352 break;
1353 case Expression::E_ARRAYLIT: {
1354 auto* al = e->cast<ArrayLit>();
1355 std::vector<IntVal> vals(al->size());
1356 for (unsigned int i = 0; i < al->size(); i++) {
1357 vals[i] = static_cast<long long>(eval_bool(env, (*al)[i]));
1358 }
1359 return IntSetVal::a(vals);
1360 } break;
1361 case Expression::E_COMP: {
1362 auto* c = e->cast<Comprehension>();
1363 std::vector<IntVal> a = eval_comp<EvalIntVal>(env, c);
1364 return IntSetVal::a(a);
1365 }
1366 case Expression::E_ID: {
1367 GCLock lock;
1368 return eval_id<EvalBoolSetLit>(env, e)->isv();
1369 } break;
1370 case Expression::E_ARRAYACCESS: {
1371 GCLock lock;
1372 return eval_boolset(env, eval_arrayaccess(env, e->cast<ArrayAccess>()));
1373 } break;
1374 case Expression::E_ITE: {
1375 ITE* ite = e->cast<ITE>();
1376 for (int i = 0; i < ite->size(); i++) {
1377 if (eval_bool(env, ite->ifExpr(i))) {
1378 return eval_boolset(env, ite->thenExpr(i));
1379 }
1380 }
1381 return eval_boolset(env, ite->elseExpr());
1382 } break;
1383 case Expression::E_BINOP: {
1384 auto* bo = e->cast<BinOp>();
1385 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
1386 return eval_call<EvalBoolSet, BinOp>(env, bo);
1387 }
1388 Expression* lhs = eval_par(env, bo->lhs());
1389 Expression* rhs = eval_par(env, bo->rhs());
1390 if (lhs->type().isIntSet() && rhs->type().isIntSet()) {
1391 IntSetVal* v0 = eval_boolset(env, lhs);
1392 IntSetVal* v1 = eval_boolset(env, rhs);
1393 IntSetRanges ir0(v0);
1394 IntSetRanges ir1(v1);
1395 switch (bo->op()) {
1396 case BOT_UNION: {
1397 Ranges::Union<IntVal, IntSetRanges, IntSetRanges> u(ir0, ir1);
1398 return IntSetVal::ai(u);
1399 }
1400 case BOT_DIFF: {
1401 Ranges::Diff<IntVal, IntSetRanges, IntSetRanges> u(ir0, ir1);
1402 return IntSetVal::ai(u);
1403 }
1404 case BOT_SYMDIFF: {
1405 Ranges::Union<IntVal, IntSetRanges, IntSetRanges> u(ir0, ir1);
1406 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> i(ir0, ir1);
1407 Ranges::Diff<IntVal, Ranges::Union<IntVal, IntSetRanges, IntSetRanges>,
1408 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges>>
1409 sd(u, i);
1410 return IntSetVal::ai(sd);
1411 }
1412 case BOT_INTERSECT: {
1413 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> u(ir0, ir1);
1414 return IntSetVal::ai(u);
1415 }
1416 default:
1417 throw EvalError(env, e->loc(), "not a set of bool expression", bo->opToString());
1418 }
1419 } else if (lhs->type().isbool() && rhs->type().isbool()) {
1420 if (bo->op() != BOT_DOTDOT) {
1421 throw EvalError(env, e->loc(), "not a set of bool expression", bo->opToString());
1422 }
1423 return IntSetVal::a(static_cast<long long>(eval_bool(env, lhs)),
1424 static_cast<long long>(eval_bool(env, rhs)));
1425 } else {
1426 throw EvalError(env, e->loc(), "not a set of bool expression", bo->opToString());
1427 }
1428 } break;
1429 case Expression::E_UNOP: {
1430 UnOp* uo = e->cast<UnOp>();
1431 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
1432 return eval_call<EvalBoolSet, UnOp>(env, uo);
1433 }
1434 throw EvalError(env, e->loc(), "not a set of bool expression");
1435 }
1436 case Expression::E_CALL: {
1437 Call* ce = e->cast<Call>();
1438 if (ce->decl() == nullptr) {
1439 throw EvalError(env, e->loc(), "undeclared function", ce->id());
1440 }
1441
1442 if (ce->decl()->builtins.s != nullptr) {
1443 return ce->decl()->builtins.s(env, ce);
1444 }
1445
1446 if (ce->decl()->builtins.e != nullptr) {
1447 return eval_boolset(env, ce->decl()->builtins.e(env, ce));
1448 }
1449
1450 if (ce->decl()->e() == nullptr) {
1451 std::ostringstream ss;
1452 ss << "internal error: missing builtin '" << ce->id() << "'";
1453 throw EvalError(env, ce->loc(), ss.str());
1454 }
1455
1456 return eval_call<EvalBoolSet>(env, ce);
1457 } break;
1458 case Expression::E_LET: {
1459 Let* l = e->cast<Let>();
1460 l->pushbindings();
1461 for (unsigned int i = 0; i < l->let().size(); i++) {
1462 // Evaluate all variable declarations
1463 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
1464 vdi->e(eval_par(env, vdi->e()));
1465 check_par_declaration(env, vdi);
1466 } else {
1467 // This is a constraint item. Since the let is par,
1468 // it can only be a par bool expression. If it evaluates
1469 // to false, it means that the value of this let is undefined.
1470 if (!eval_bool(env, l->let()[i])) {
1471 throw ResultUndefinedError(env, l->let()[i]->loc(), "constraint in let failed");
1472 }
1473 }
1474 }
1475 IntSetVal* ret = eval_boolset(env, l->in());
1476 l->popbindings();
1477 return ret;
1478 } break;
1479 default:
1480 assert(false);
1481 return nullptr;
1482 }
1483}
1484
1485IntVal eval_int(EnvI& env, Expression* e) {
1486 if (e->type().isbool()) {
1487 return static_cast<long long>(eval_bool(env, e));
1488 }
1489 if (auto* il = e->dynamicCast<IntLit>()) {
1490 return il->v();
1491 }
1492 CallStackItem csi(env, e);
1493 try {
1494 switch (e->eid()) {
1495 case Expression::E_FLOATLIT:
1496 case Expression::E_BOOLLIT:
1497 case Expression::E_STRINGLIT:
1498 case Expression::E_ANON:
1499 case Expression::E_TIID:
1500 case Expression::E_SETLIT:
1501 case Expression::E_ARRAYLIT:
1502 case Expression::E_COMP:
1503 case Expression::E_VARDECL:
1504 case Expression::E_TI:
1505 throw EvalError(env, e->loc(), "not an integer expression");
1506 break;
1507 case Expression::E_ID: {
1508 GCLock lock;
1509 return eval_id<EvalIntLit>(env, e)->v();
1510 } break;
1511 case Expression::E_ARRAYACCESS: {
1512 GCLock lock;
1513 return eval_int(env, eval_arrayaccess(env, e->cast<ArrayAccess>()));
1514 } break;
1515 case Expression::E_ITE: {
1516 ITE* ite = e->cast<ITE>();
1517 for (int i = 0; i < ite->size(); i++) {
1518 if (eval_bool(env, ite->ifExpr(i))) {
1519 return eval_int(env, ite->thenExpr(i));
1520 }
1521 }
1522 return eval_int(env, ite->elseExpr());
1523 } break;
1524 case Expression::E_BINOP: {
1525 auto* bo = e->cast<BinOp>();
1526 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
1527 return eval_call<EvalIntVal, BinOp>(env, bo);
1528 }
1529 IntVal v0 = eval_int(env, bo->lhs());
1530 IntVal v1 = eval_int(env, bo->rhs());
1531 switch (bo->op()) {
1532 case BOT_PLUS:
1533 return v0 + v1;
1534 case BOT_MINUS:
1535 return v0 - v1;
1536 case BOT_MULT:
1537 return v0 * v1;
1538 case BOT_POW:
1539 return v0.pow(v1);
1540 case BOT_IDIV:
1541 if (v1 == 0) {
1542 throw ResultUndefinedError(env, e->loc(), "division by zero");
1543 }
1544 return v0 / v1;
1545 case BOT_MOD:
1546 if (v1 == 0) {
1547 throw ResultUndefinedError(env, e->loc(), "division by zero");
1548 }
1549 return v0 % v1;
1550 default:
1551 throw EvalError(env, e->loc(), "not an integer expression", bo->opToString());
1552 }
1553 } break;
1554 case Expression::E_UNOP: {
1555 UnOp* uo = e->cast<UnOp>();
1556 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
1557 return eval_call<EvalIntVal, UnOp>(env, uo);
1558 }
1559 IntVal v0 = eval_int(env, uo->e());
1560 switch (uo->op()) {
1561 case UOT_PLUS:
1562 return v0;
1563 case UOT_MINUS:
1564 return -v0;
1565 default:
1566 throw EvalError(env, e->loc(), "not an integer expression", uo->opToString());
1567 }
1568 } break;
1569 case Expression::E_CALL: {
1570 Call* ce = e->cast<Call>();
1571 if (ce->decl() == nullptr) {
1572 throw EvalError(env, e->loc(), "undeclared function", ce->id());
1573 }
1574 if (ce->decl()->builtins.i != nullptr) {
1575 return ce->decl()->builtins.i(env, ce);
1576 }
1577
1578 if (ce->decl()->builtins.e != nullptr) {
1579 return eval_int(env, ce->decl()->builtins.e(env, ce));
1580 }
1581
1582 if (ce->decl()->e() == nullptr) {
1583 std::ostringstream ss;
1584 ss << "internal error: missing builtin '" << ce->id() << "'";
1585 throw EvalError(env, ce->loc(), ss.str());
1586 }
1587
1588 return eval_call<EvalIntVal>(env, ce);
1589 } break;
1590 case Expression::E_LET: {
1591 Let* l = e->cast<Let>();
1592 l->pushbindings();
1593 for (unsigned int i = 0; i < l->let().size(); i++) {
1594 // Evaluate all variable declarations
1595 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
1596 vdi->e(eval_par(env, vdi->e()));
1597 check_par_declaration(env, vdi);
1598 } else {
1599 // This is a constraint item. Since the let is par,
1600 // it can only be a par bool expression. If it evaluates
1601 // to false, it means that the value of this let is undefined.
1602 if (!eval_bool(env, l->let()[i])) {
1603 throw ResultUndefinedError(env, l->let()[i]->loc(), "constraint in let failed");
1604 }
1605 }
1606 }
1607 IntVal ret = eval_int(env, l->in());
1608 l->popbindings();
1609 return ret;
1610 } break;
1611 default:
1612 assert(false);
1613 return 0;
1614 }
1615 } catch (ArithmeticError& err) {
1616 throw EvalError(env, e->loc(), err.msg());
1617 }
1618}
1619
1620FloatVal eval_float(EnvI& env, Expression* e) {
1621 if (e->type().isint()) {
1622 return static_cast<double>(eval_int(env, e).toInt());
1623 }
1624 if (e->type().isbool()) {
1625 return static_cast<double>(eval_bool(env, e));
1626 }
1627 CallStackItem csi(env, e);
1628 try {
1629 if (auto* fl = e->dynamicCast<FloatLit>()) {
1630 return fl->v();
1631 }
1632 switch (e->eid()) {
1633 case Expression::E_INTLIT:
1634 case Expression::E_BOOLLIT:
1635 case Expression::E_STRINGLIT:
1636 case Expression::E_ANON:
1637 case Expression::E_TIID:
1638 case Expression::E_SETLIT:
1639 case Expression::E_ARRAYLIT:
1640 case Expression::E_COMP:
1641 case Expression::E_VARDECL:
1642 case Expression::E_TI:
1643 throw EvalError(env, e->loc(), "not a float expression");
1644 break;
1645 case Expression::E_ID: {
1646 GCLock lock;
1647 return eval_id<EvalFloatLit>(env, e)->v();
1648 } break;
1649 case Expression::E_ARRAYACCESS: {
1650 GCLock lock;
1651 return eval_float(env, eval_arrayaccess(env, e->cast<ArrayAccess>()));
1652 } break;
1653 case Expression::E_ITE: {
1654 ITE* ite = e->cast<ITE>();
1655 for (int i = 0; i < ite->size(); i++) {
1656 if (eval_bool(env, ite->ifExpr(i))) {
1657 return eval_float(env, ite->thenExpr(i));
1658 }
1659 }
1660 return eval_float(env, ite->elseExpr());
1661 } break;
1662 case Expression::E_BINOP: {
1663 auto* bo = e->cast<BinOp>();
1664 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
1665 return eval_call<EvalFloatVal, BinOp>(env, bo);
1666 }
1667 FloatVal v0 = eval_float(env, bo->lhs());
1668 FloatVal v1 = eval_float(env, bo->rhs());
1669 switch (bo->op()) {
1670 case BOT_PLUS:
1671 return v0 + v1;
1672 case BOT_MINUS:
1673 return v0 - v1;
1674 case BOT_MULT:
1675 return v0 * v1;
1676 case BOT_POW:
1677 return std::pow(v0.toDouble(), v1.toDouble());
1678 case BOT_DIV:
1679 if (v1 == 0.0) {
1680 throw ResultUndefinedError(env, e->loc(), "division by zero");
1681 }
1682 return v0 / v1;
1683 default:
1684 throw EvalError(env, e->loc(), "not a float expression", bo->opToString());
1685 }
1686 } break;
1687 case Expression::E_UNOP: {
1688 UnOp* uo = e->cast<UnOp>();
1689 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
1690 return eval_call<EvalFloatVal, UnOp>(env, uo);
1691 }
1692 FloatVal v0 = eval_float(env, uo->e());
1693 switch (uo->op()) {
1694 case UOT_PLUS:
1695 return v0;
1696 case UOT_MINUS:
1697 return -v0;
1698 default:
1699 throw EvalError(env, e->loc(), "not a float expression", uo->opToString());
1700 }
1701 } break;
1702 case Expression::E_CALL: {
1703 Call* ce = e->cast<Call>();
1704 if (ce->decl() == nullptr) {
1705 throw EvalError(env, e->loc(), "undeclared function", ce->id());
1706 }
1707 if (ce->decl()->builtins.f != nullptr) {
1708 return ce->decl()->builtins.f(env, ce);
1709 }
1710
1711 if (ce->decl()->builtins.e != nullptr) {
1712 return eval_float(env, ce->decl()->builtins.e(env, ce));
1713 }
1714
1715 if (ce->decl()->e() == nullptr) {
1716 std::ostringstream ss;
1717 ss << "internal error: missing builtin '" << ce->id() << "'";
1718 throw EvalError(env, ce->loc(), ss.str());
1719 }
1720
1721 return eval_call<EvalFloatVal>(env, ce);
1722 } break;
1723 case Expression::E_LET: {
1724 Let* l = e->cast<Let>();
1725 l->pushbindings();
1726 for (unsigned int i = 0; i < l->let().size(); i++) {
1727 // Evaluate all variable declarations
1728 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
1729 vdi->e(eval_par(env, vdi->e()));
1730 check_par_declaration(env, vdi);
1731 } else {
1732 // This is a constraint item. Since the let is par,
1733 // it can only be a par bool expression. If it evaluates
1734 // to false, it means that the value of this let is undefined.
1735 if (!eval_bool(env, l->let()[i])) {
1736 throw ResultUndefinedError(env, l->let()[i]->loc(), "constraint in let failed");
1737 }
1738 }
1739 }
1740 FloatVal ret = eval_float(env, l->in());
1741 l->popbindings();
1742 return ret;
1743 } break;
1744 default:
1745 assert(false);
1746 return 0.0;
1747 }
1748 } catch (ArithmeticError& err) {
1749 throw EvalError(env, e->loc(), err.msg());
1750 }
1751}
1752
1753std::string eval_string(EnvI& env, Expression* e) {
1754 CallStackItem csi(env, e);
1755 switch (e->eid()) {
1756 case Expression::E_STRINGLIT: {
1757 ASTString str = e->cast<StringLit>()->v();
1758 return std::string(str.c_str(), str.size());
1759 }
1760 case Expression::E_FLOATLIT:
1761 case Expression::E_INTLIT:
1762 case Expression::E_BOOLLIT:
1763 case Expression::E_ANON:
1764 case Expression::E_TIID:
1765 case Expression::E_SETLIT:
1766 case Expression::E_ARRAYLIT:
1767 case Expression::E_COMP:
1768 case Expression::E_VARDECL:
1769 case Expression::E_TI:
1770 throw EvalError(env, e->loc(), "not a string expression");
1771 break;
1772 case Expression::E_ID: {
1773 GCLock lock;
1774 ASTString str = eval_id<EvalStringLit>(env, e)->v();
1775 return std::string(str.c_str(), str.size());
1776 } break;
1777 case Expression::E_ARRAYACCESS: {
1778 GCLock lock;
1779 return eval_string(env, eval_arrayaccess(env, e->cast<ArrayAccess>()));
1780 } break;
1781 case Expression::E_ITE: {
1782 ITE* ite = e->cast<ITE>();
1783 for (int i = 0; i < ite->size(); i++) {
1784 if (eval_bool(env, ite->ifExpr(i))) {
1785 return eval_string(env, ite->thenExpr(i));
1786 }
1787 }
1788 return eval_string(env, ite->elseExpr());
1789 } break;
1790 case Expression::E_BINOP: {
1791 auto* bo = e->cast<BinOp>();
1792 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
1793 return eval_call<EvalString, BinOp>(env, bo);
1794 }
1795 std::string v0 = eval_string(env, bo->lhs());
1796 std::string v1 = eval_string(env, bo->rhs());
1797 switch (bo->op()) {
1798 case BOT_PLUSPLUS:
1799 return v0 + v1;
1800 default:
1801 throw EvalError(env, e->loc(), "not a string expression", bo->opToString());
1802 }
1803 } break;
1804 case Expression::E_UNOP: {
1805 UnOp* uo = e->cast<UnOp>();
1806 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
1807 return eval_call<EvalString, UnOp>(env, uo);
1808 }
1809 throw EvalError(env, e->loc(), "not a string expression");
1810 } break;
1811 case Expression::E_CALL: {
1812 Call* ce = e->cast<Call>();
1813 if (ce->decl() == nullptr) {
1814 throw EvalError(env, e->loc(), "undeclared function", ce->id());
1815 }
1816
1817 if (ce->decl()->builtins.str != nullptr) {
1818 return ce->decl()->builtins.str(env, ce);
1819 }
1820 if (ce->decl()->builtins.e != nullptr) {
1821 return eval_string(env, ce->decl()->builtins.e(env, ce));
1822 }
1823
1824 if (ce->decl()->e() == nullptr) {
1825 std::ostringstream ss;
1826 ss << "internal error: missing builtin '" << ce->id() << "'";
1827 throw EvalError(env, ce->loc(), ss.str());
1828 }
1829
1830 return eval_call<EvalString>(env, ce);
1831 } break;
1832 case Expression::E_LET: {
1833 Let* l = e->cast<Let>();
1834 l->pushbindings();
1835 for (unsigned int i = 0; i < l->let().size(); i++) {
1836 // Evaluate all variable declarations
1837 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
1838 vdi->e(eval_par(env, vdi->e()));
1839 check_par_declaration(env, vdi);
1840 } else {
1841 // This is a constraint item. Since the let is par,
1842 // it can only be a par bool expression. If it evaluates
1843 // to false, it means that the value of this let is undefined.
1844 if (!eval_bool(env, l->let()[i])) {
1845 throw ResultUndefinedError(env, l->let()[i]->loc(), "constraint in let failed");
1846 }
1847 }
1848 }
1849 std::string ret = eval_string(env, l->in());
1850 l->popbindings();
1851 return ret;
1852 } break;
1853 default:
1854 assert(false);
1855 return "";
1856 }
1857}
1858
1859Expression* eval_par(EnvI& env, Expression* e) {
1860 if (e == nullptr) {
1861 return nullptr;
1862 }
1863 switch (e->eid()) {
1864 case Expression::E_ANON:
1865 case Expression::E_TIID: {
1866 return e;
1867 }
1868 case Expression::E_COMP:
1869 if (e->cast<Comprehension>()->set()) {
1870 return EvalSetLit::e(env, e);
1871 }
1872 // fall through
1873 case Expression::E_ARRAYLIT: {
1874 ArrayLit* al = eval_array_lit(env, e);
1875 std::vector<Expression*> args(al->size());
1876 bool allFlat = true;
1877 for (unsigned int i = 0; i < al->size(); i++) {
1878 Expression* ali = (*al)[i];
1879 if (!ali->isa<IntLit>() && !ali->isa<FloatLit>() && !ali->isa<BoolLit>() &&
1880 !(ali->isa<SetLit>() && ali->cast<SetLit>()->evaluated())) {
1881 allFlat = false;
1882 args[i] = eval_par(env, ali);
1883 } else {
1884 args[i] = ali;
1885 }
1886 }
1887 if (allFlat) {
1888 return al;
1889 }
1890 std::vector<std::pair<int, int>> dims(al->dims());
1891 for (unsigned int i = al->dims(); (i--) != 0U;) {
1892 dims[i].first = al->min(i);
1893 dims[i].second = al->max(i);
1894 }
1895 auto* ret = new ArrayLit(al->loc(), args, dims);
1896 Type t = al->type();
1897 if (t.isbot() && ret->size() > 0) {
1898 t.bt((*ret)[0]->type().bt());
1899 }
1900 ret->type(t);
1901 return ret;
1902 }
1903 case Expression::E_VARDECL: {
1904 auto* vd = e->cast<VarDecl>();
1905 throw EvalError(env, vd->loc(), "cannot evaluate variable declaration", vd->id()->v());
1906 }
1907 case Expression::E_TI: {
1908 auto* t = e->cast<TypeInst>();
1909 ASTExprVec<TypeInst> r;
1910 if (t->ranges().size() > 0) {
1911 std::vector<TypeInst*> rv(t->ranges().size());
1912 for (unsigned int i = t->ranges().size(); (i--) != 0U;) {
1913 rv[i] = static_cast<TypeInst*>(eval_par(env, t->ranges()[i]));
1914 }
1915 r = ASTExprVec<TypeInst>(rv);
1916 }
1917 return new TypeInst(Location(), t->type(), r, eval_par(env, t->domain()));
1918 }
1919 case Expression::E_ID: {
1920 if (e == constants().absent) {
1921 return e;
1922 }
1923 Id* id = e->cast<Id>();
1924 if (id->decl() == nullptr) {
1925 throw EvalError(env, e->loc(), "undefined identifier", id->v());
1926 }
1927 if (id->decl()->ti()->domain() != nullptr) {
1928 if (auto* bl = id->decl()->ti()->domain()->dynamicCast<BoolLit>()) {
1929 return bl;
1930 }
1931 if (id->decl()->ti()->type().isint()) {
1932 if (auto* sl = id->decl()->ti()->domain()->dynamicCast<SetLit>()) {
1933 if ((sl->isv() != nullptr) && sl->isv()->min() == sl->isv()->max()) {
1934 return IntLit::a(sl->isv()->min());
1935 }
1936 }
1937 } else if (id->decl()->ti()->type().isfloat()) {
1938 if (id->decl()->ti()->domain() != nullptr) {
1939 FloatSetVal* fsv = eval_floatset(env, id->decl()->ti()->domain());
1940 if (fsv->min() == fsv->max()) {
1941 return FloatLit::a(fsv->min());
1942 }
1943 }
1944 }
1945 }
1946 if (id->decl()->e() == nullptr) {
1947 return id;
1948 }
1949 return eval_par(env, id->decl()->e());
1950 }
1951 case Expression::E_STRINGLIT:
1952 return e;
1953 default: {
1954 if (e->type().dim() != 0) {
1955 ArrayLit* al = eval_array_lit(env, e);
1956 std::vector<Expression*> args(al->size());
1957 for (unsigned int i = al->size(); (i--) != 0U;) {
1958 args[i] = eval_par(env, (*al)[i]);
1959 }
1960 std::vector<std::pair<int, int>> dims(al->dims());
1961 for (unsigned int i = al->dims(); (i--) != 0U;) {
1962 dims[i].first = al->min(i);
1963 dims[i].second = al->max(i);
1964 }
1965 auto* ret = new ArrayLit(al->loc(), args, dims);
1966 Type t = al->type();
1967 if ((t.bt() == Type::BT_BOT || t.bt() == Type::BT_TOP) && ret->size() > 0) {
1968 t.bt((*ret)[0]->type().bt());
1969 }
1970 ret->type(t);
1971 return ret;
1972 }
1973 if (e->type().isPar()) {
1974 if (e->type().isSet()) {
1975 return EvalSetLit::e(env, e);
1976 }
1977 if (e->type() == Type::parint()) {
1978 return EvalIntLit::e(env, e);
1979 }
1980 if (e->type() == Type::parbool()) {
1981 return EvalBoolLit::e(env, e);
1982 }
1983 if (e->type() == Type::parfloat()) {
1984 return EvalFloatLit::e(env, e);
1985 }
1986 if (e->type() == Type::parstring()) {
1987 return EvalStringLit::e(env, e);
1988 }
1989 }
1990 switch (e->eid()) {
1991 case Expression::E_ITE: {
1992 ITE* ite = e->cast<ITE>();
1993 for (int i = 0; i < ite->size(); i++) {
1994 if (ite->ifExpr(i)->type() == Type::parbool()) {
1995 if (eval_bool(env, ite->ifExpr(i))) {
1996 return eval_par(env, ite->thenExpr(i));
1997 }
1998 } else {
1999 std::vector<Expression*> e_ifthen(ite->size() * 2);
2000 for (int i = 0; i < ite->size(); i++) {
2001 e_ifthen[2 * i] = eval_par(env, ite->ifExpr(i));
2002 e_ifthen[2 * i + 1] = eval_par(env, ite->thenExpr(i));
2003 }
2004 ITE* n_ite = new ITE(ite->loc(), e_ifthen, eval_par(env, ite->elseExpr()));
2005 n_ite->type(ite->type());
2006 return n_ite;
2007 }
2008 }
2009 return eval_par(env, ite->elseExpr());
2010 }
2011 case Expression::E_CALL: {
2012 Call* c = e->cast<Call>();
2013 if (c->decl() != nullptr) {
2014 if (c->decl()->builtins.e != nullptr) {
2015 return eval_par(env, c->decl()->builtins.e(env, c));
2016 }
2017 if (c->decl()->e() == nullptr) {
2018 if (c->id() == "deopt" && Expression::equal(c->arg(0), constants().absent)) {
2019 throw ResultUndefinedError(env, e->loc(), "deopt(<>) is undefined");
2020 }
2021 return c;
2022 }
2023 return eval_call<EvalPar>(env, c);
2024 }
2025 std::vector<Expression*> args(c->argCount());
2026 for (unsigned int i = 0; i < args.size(); i++) {
2027 args[i] = eval_par(env, c->arg(i));
2028 }
2029 Call* nc = new Call(c->loc(), c->id(), args);
2030 nc->type(c->type());
2031 return nc;
2032 }
2033 case Expression::E_BINOP: {
2034 auto* bo = e->cast<BinOp>();
2035 if ((bo->decl() != nullptr) && (bo->decl()->e() != nullptr)) {
2036 return eval_call<EvalPar, BinOp>(env, bo);
2037 }
2038 auto* nbo =
2039 new BinOp(e->loc(), eval_par(env, bo->lhs()), bo->op(), eval_par(env, bo->rhs()));
2040 nbo->type(bo->type());
2041 return nbo;
2042 }
2043 case Expression::E_UNOP: {
2044 UnOp* uo = e->cast<UnOp>();
2045 if ((uo->decl() != nullptr) && (uo->decl()->e() != nullptr)) {
2046 return eval_call<EvalPar, UnOp>(env, uo);
2047 }
2048 UnOp* nuo = new UnOp(e->loc(), uo->op(), eval_par(env, uo->e()));
2049 nuo->type(uo->type());
2050 return nuo;
2051 }
2052 case Expression::E_ARRAYACCESS: {
2053 auto* aa = e->cast<ArrayAccess>();
2054 for (unsigned int i = 0; i < aa->idx().size(); i++) {
2055 if (!aa->idx()[i]->type().isPar()) {
2056 std::vector<Expression*> idx(aa->idx().size());
2057 for (unsigned int j = 0; j < aa->idx().size(); j++) {
2058 idx[j] = eval_par(env, aa->idx()[j]);
2059 }
2060 auto* aa_new = new ArrayAccess(e->loc(), eval_par(env, aa->v()), idx);
2061 aa_new->type(aa->type());
2062 return aa_new;
2063 }
2064 }
2065 return eval_par(env, eval_arrayaccess(env, aa));
2066 }
2067 case Expression::E_LET: {
2068 Let* l = e->cast<Let>();
2069 assert(l->type().isPar());
2070 l->pushbindings();
2071 for (unsigned int i = 0; i < l->let().size(); i++) {
2072 // Evaluate all variable declarations
2073 if (auto* vdi = l->let()[i]->dynamicCast<VarDecl>()) {
2074 vdi->e(eval_par(env, vdi->e()));
2075 check_par_declaration(env, vdi);
2076 } else {
2077 // This is a constraint item. Since the let is par,
2078 // it can only be a par bool expression. If it evaluates
2079 // to false, it means that the value of this let is undefined.
2080 if (!eval_bool(env, l->let()[i])) {
2081 throw ResultUndefinedError(env, l->let()[i]->loc(), "constraint in let failed");
2082 }
2083 }
2084 }
2085 Expression* ret = eval_par(env, l->in());
2086 l->popbindings();
2087 return ret;
2088 }
2089 default:
2090 return e;
2091 }
2092 }
2093 }
2094}
2095
2096class ComputeIntBounds : public EVisitor {
2097public:
2098 typedef std::pair<IntVal, IntVal> Bounds;
2099 std::vector<Bounds> bounds;
2100 bool valid;
2101 EnvI& env;
2102 ComputeIntBounds(EnvI& env0) : valid(true), env(env0) {}
2103 bool enter(Expression* e) {
2104 if (e->type().isAnn()) {
2105 return false;
2106 }
2107 if (e->isa<VarDecl>()) {
2108 return false;
2109 }
2110 if (e->type().dim() > 0) {
2111 return false;
2112 }
2113 if (e->type().isPar()) {
2114 if (e->type().isint()) {
2115 Expression* exp = eval_par(env, e);
2116 if (exp == constants().absent) {
2117 valid = false;
2118 } else {
2119 IntVal v = exp->cast<IntLit>()->v();
2120 bounds.emplace_back(v, v);
2121 }
2122 } else {
2123 valid = false;
2124 }
2125 return false;
2126 }
2127 if (e->type().isint()) {
2128 if (ITE* ite = e->dynamicCast<ITE>()) {
2129 Bounds itebounds(IntVal::infinity(), -IntVal::infinity());
2130 for (int i = 0; i < ite->size(); i++) {
2131 if (ite->ifExpr(i)->type().isPar() &&
2132 static_cast<int>(ite->ifExpr(i)->type().cv()) == Type::CV_NO) {
2133 if (eval_bool(env, ite->ifExpr(i))) {
2134 BottomUpIterator<ComputeIntBounds> cbi(*this);
2135 cbi.run(ite->thenExpr(i));
2136 Bounds& back = bounds.back();
2137 back.first = std::min(itebounds.first, back.first);
2138 back.second = std::max(itebounds.second, back.second);
2139 return false;
2140 }
2141 } else {
2142 BottomUpIterator<ComputeIntBounds> cbi(*this);
2143 cbi.run(ite->thenExpr(i));
2144 Bounds back = bounds.back();
2145 bounds.pop_back();
2146 itebounds.first = std::min(itebounds.first, back.first);
2147 itebounds.second = std::max(itebounds.second, back.second);
2148 }
2149 }
2150 BottomUpIterator<ComputeIntBounds> cbi(*this);
2151 cbi.run(ite->elseExpr());
2152 Bounds& back = bounds.back();
2153 back.first = std::min(itebounds.first, back.first);
2154 back.second = std::max(itebounds.second, back.second);
2155 return false;
2156 }
2157 return true;
2158 }
2159 return false;
2160 }
2161 /// Visit integer literal
2162 void vIntLit(const IntLit& i) { bounds.emplace_back(i.v(), i.v()); }
2163 /// Visit floating point literal
2164 void vFloatLit(const FloatLit& /*f*/) {
2165 valid = false;
2166 bounds.emplace_back(0, 0);
2167 }
2168 /// Visit Boolean literal
2169 void vBoolLit(const BoolLit& /*b*/) {
2170 valid = false;
2171 bounds.emplace_back(0, 0);
2172 }
2173 /// Visit set literal
2174 void vSetLit(const SetLit& /*sl*/) {
2175 valid = false;
2176 bounds.emplace_back(0, 0);
2177 }
2178 /// Visit string literal
2179 void vStringLit(const StringLit& /*sl*/) {
2180 valid = false;
2181 bounds.emplace_back(0, 0);
2182 }
2183 /// Visit identifier
2184 void vId(const Id& id) {
2185 VarDecl* vd = id.decl();
2186 while ((vd->flat() != nullptr) && vd->flat() != vd) {
2187 vd = vd->flat();
2188 }
2189 if (vd->ti()->domain() != nullptr) {
2190 GCLock lock;
2191 IntSetVal* isv = eval_intset(env, vd->ti()->domain());
2192 if (isv->size() == 0) {
2193 valid = false;
2194 bounds.emplace_back(0, 0);
2195 } else {
2196 bounds.emplace_back(isv->min(0), isv->max(isv->size() - 1));
2197 }
2198 } else {
2199 if (vd->e() != nullptr) {
2200 BottomUpIterator<ComputeIntBounds> cbi(*this);
2201 cbi.run(vd->e());
2202 } else {
2203 bounds.emplace_back(-IntVal::infinity(), IntVal::infinity());
2204 }
2205 }
2206 }
2207 /// Visit anonymous variable
2208 void vAnonVar(const AnonVar& /*v*/) {
2209 valid = false;
2210 bounds.emplace_back(0, 0);
2211 }
2212 /// Visit array literal
2213 void vArrayLit(const ArrayLit& /*al*/) {}
2214 /// Visit array access
2215 void vArrayAccess(ArrayAccess& aa) {
2216 bool parAccess = true;
2217 for (unsigned int i = aa.idx().size(); (i--) != 0U;) {
2218 bounds.pop_back();
2219 if (!aa.idx()[i]->type().isPar()) {
2220 parAccess = false;
2221 }
2222 }
2223 if (Id* id = aa.v()->dynamicCast<Id>()) {
2224 while ((id->decl()->e() != nullptr) && id->decl()->e()->isa<Id>()) {
2225 id = id->decl()->e()->cast<Id>();
2226 }
2227 if (parAccess && (id->decl()->e() != nullptr)) {
2228 bool success;
2229 Expression* e = eval_arrayaccess(env, &aa, success);
2230 if (success) {
2231 BottomUpIterator<ComputeIntBounds> cbi(*this);
2232 cbi.run(e);
2233 return;
2234 }
2235 }
2236 if (id->decl()->ti()->domain() != nullptr) {
2237 GCLock lock;
2238 IntSetVal* isv = eval_intset(env, id->decl()->ti()->domain());
2239 if (isv->size() > 0) {
2240 bounds.emplace_back(isv->min(0), isv->max(isv->size() - 1));
2241 return;
2242 }
2243 }
2244 }
2245 valid = false;
2246 bounds.emplace_back(0, 0);
2247 }
2248 /// Visit array comprehension
2249 void vComprehension(const Comprehension& c) {
2250 valid = false;
2251 bounds.emplace_back(0, 0);
2252 }
2253 /// Visit if-then-else
2254 void vITE(const ITE& /*ite*/) {
2255 valid = false;
2256 bounds.emplace_back(0, 0);
2257 }
2258 /// Visit binary operator
2259 void vBinOp(const BinOp& bo) {
2260 Bounds b1 = bounds.back();
2261 bounds.pop_back();
2262 Bounds b0 = bounds.back();
2263 bounds.pop_back();
2264 if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() ||
2265 !b0.second.isFinite()) {
2266 valid = false;
2267 bounds.emplace_back(0, 0);
2268 } else {
2269 switch (bo.op()) {
2270 case BOT_PLUS:
2271 bounds.emplace_back(b0.first + b1.first, b0.second + b1.second);
2272 break;
2273 case BOT_MINUS:
2274 bounds.emplace_back(b0.first - b1.second, b0.second - b1.first);
2275 break;
2276 case BOT_MULT: {
2277 IntVal x0 = b0.first * b1.first;
2278 IntVal x1 = b0.first * b1.second;
2279 IntVal x2 = b0.second * b1.first;
2280 IntVal x3 = b0.second * b1.second;
2281 IntVal m = std::min(x0, std::min(x1, std::min(x2, x3)));
2282 IntVal n = std::max(x0, std::max(x1, std::max(x2, x3)));
2283 bounds.emplace_back(m, n);
2284 } break;
2285 case BOT_IDIV: {
2286 IntVal b0f = b0.first == 0 ? 1 : b0.first;
2287 IntVal b0s = b0.second == 0 ? -1 : b0.second;
2288 IntVal b1f = b1.first == 0 ? 1 : b1.first;
2289 IntVal b1s = b1.second == 0 ? -1 : b1.second;
2290 IntVal x0 = b0f / b1f;
2291 IntVal x1 = b0f / b1s;
2292 IntVal x2 = b0s / b1f;
2293 IntVal x3 = b0s / b1s;
2294 IntVal m = std::min(x0, std::min(x1, std::min(x2, x3)));
2295 IntVal n = std::max(x0, std::max(x1, std::max(x2, x3)));
2296 bounds.emplace_back(m, n);
2297 } break;
2298 case BOT_MOD: {
2299 IntVal b0f = b0.first == 0 ? 1 : b0.first;
2300 IntVal b0s = b0.second == 0 ? -1 : b0.second;
2301 IntVal b1f = b1.first == 0 ? 1 : b1.first;
2302 IntVal b1s = b1.second == 0 ? -1 : b1.second;
2303 IntVal x0 = b0f % b1f;
2304 IntVal x1 = b0f % b1s;
2305 IntVal x2 = b0s % b1f;
2306 IntVal x3 = b0s % b1s;
2307 IntVal m = std::min(x0, std::min(x1, std::min(x2, x3)));
2308 IntVal n = std::max(x0, std::max(x1, std::max(x2, x3)));
2309 bounds.emplace_back(m, n);
2310 } break;
2311 case BOT_POW: {
2312 IntVal exp_min = std::min(0, b1.first);
2313 IntVal exp_max = std::min(0, b1.second);
2314
2315 IntVal x0 = b0.first.pow(exp_min);
2316 IntVal x1 = b0.first.pow(exp_max);
2317 IntVal x2 = b0.second.pow(exp_min);
2318 IntVal x3 = b0.second.pow(exp_max);
2319 IntVal m = std::min(x0, std::min(x1, std::min(x2, x3)));
2320 IntVal n = std::max(x0, std::max(x1, std::max(x2, x3)));
2321 bounds.emplace_back(m, n);
2322 } break;
2323 case BOT_DIV:
2324 case BOT_LE:
2325 case BOT_LQ:
2326 case BOT_GR:
2327 case BOT_GQ:
2328 case BOT_EQ:
2329 case BOT_NQ:
2330 case BOT_IN:
2331 case BOT_SUBSET:
2332 case BOT_SUPERSET:
2333 case BOT_UNION:
2334 case BOT_DIFF:
2335 case BOT_SYMDIFF:
2336 case BOT_INTERSECT:
2337 case BOT_PLUSPLUS:
2338 case BOT_EQUIV:
2339 case BOT_IMPL:
2340 case BOT_RIMPL:
2341 case BOT_OR:
2342 case BOT_AND:
2343 case BOT_XOR:
2344 case BOT_DOTDOT:
2345 valid = false;
2346 bounds.emplace_back(0, 0);
2347 }
2348 }
2349 }
2350 /// Visit unary operator
2351 void vUnOp(const UnOp& uo) {
2352 switch (uo.op()) {
2353 case UOT_PLUS:
2354 break;
2355 case UOT_MINUS:
2356 bounds.back().first = -bounds.back().first;
2357 bounds.back().second = -bounds.back().second;
2358 std::swap(bounds.back().first, bounds.back().second);
2359 break;
2360 case UOT_NOT:
2361 valid = false;
2362 }
2363 }
2364 /// Visit call
2365 void vCall(Call& c) {
2366 if (c.id() == constants().ids.lin_exp || c.id() == constants().ids.sum) {
2367 bool le = c.id() == constants().ids.lin_exp;
2368 ArrayLit* coeff = le ? eval_array_lit(env, c.arg(0)) : nullptr;
2369 if (c.arg(le ? 1 : 0)->type().isOpt()) {
2370 valid = false;
2371 bounds.emplace_back(0, 0);
2372 return;
2373 }
2374 ArrayLit* al = eval_array_lit(env, c.arg(le ? 1 : 0));
2375 if (le) {
2376 bounds.pop_back(); // remove constant (third arg) from stack
2377 }
2378
2379 IntVal d = le ? c.arg(2)->cast<IntLit>()->v() : 0;
2380 int stacktop = static_cast<int>(bounds.size());
2381 for (unsigned int i = al->size(); (i--) != 0U;) {
2382 BottomUpIterator<ComputeIntBounds> cbi(*this);
2383 cbi.run((*al)[i]);
2384 if (!valid) {
2385 for (unsigned int j = al->size() - 1; j > i; j--) {
2386 bounds.pop_back();
2387 }
2388 return;
2389 }
2390 }
2391 assert(stacktop + al->size() == bounds.size());
2392 IntVal lb = d;
2393 IntVal ub = d;
2394 for (unsigned int i = 0; i < al->size(); i++) {
2395 Bounds b = bounds.back();
2396 bounds.pop_back();
2397 IntVal cv = le ? eval_int(env, (*coeff)[i]) : 1;
2398 if (cv > 0) {
2399 if (b.first.isFinite()) {
2400 if (lb.isFinite()) {
2401 lb += cv * b.first;
2402 }
2403 } else {
2404 lb = b.first;
2405 }
2406 if (b.second.isFinite()) {
2407 if (ub.isFinite()) {
2408 ub += cv * b.second;
2409 }
2410 } else {
2411 ub = b.second;
2412 }
2413 } else {
2414 if (b.second.isFinite()) {
2415 if (lb.isFinite()) {
2416 lb += cv * b.second;
2417 }
2418 } else {
2419 lb = -b.second;
2420 }
2421 if (b.first.isFinite()) {
2422 if (ub.isFinite()) {
2423 ub += cv * b.first;
2424 }
2425 } else {
2426 ub = -b.first;
2427 }
2428 }
2429 }
2430 bounds.emplace_back(lb, ub);
2431 } else if (c.id() == "card") {
2432 if (IntSetVal* isv = compute_intset_bounds(env, c.arg(0))) {
2433 IntSetRanges isr(isv);
2434 bounds.emplace_back(0, Ranges::cardinality(isr));
2435 } else {
2436 valid = false;
2437 bounds.emplace_back(0, 0);
2438 }
2439 } else if (c.id() == "int_times") {
2440 Bounds b1 = bounds.back();
2441 bounds.pop_back();
2442 Bounds b0 = bounds.back();
2443 bounds.pop_back();
2444 if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() ||
2445 !b0.second.isFinite()) {
2446 valid = false;
2447 bounds.emplace_back(0, 0);
2448 } else {
2449 IntVal x0 = b0.first * b1.first;
2450 IntVal x1 = b0.first * b1.second;
2451 IntVal x2 = b0.second * b1.first;
2452 IntVal x3 = b0.second * b1.second;
2453 IntVal m = std::min(x0, std::min(x1, std::min(x2, x3)));
2454 IntVal n = std::max(x0, std::max(x1, std::max(x2, x3)));
2455 bounds.emplace_back(m, n);
2456 }
2457 } else if (c.id() == constants().ids.bool2int) {
2458 bounds.emplace_back(0, 1);
2459 } else if (c.id() == "abs") {
2460 Bounds b0 = bounds.back();
2461 if (b0.first < 0) {
2462 bounds.pop_back();
2463 if (b0.second < 0) {
2464 bounds.emplace_back(-b0.second, -b0.first);
2465 } else {
2466 bounds.emplace_back(0, std::max(-b0.first, b0.second));
2467 }
2468 }
2469 } else if ((c.decl() != nullptr) && (c.decl()->ti()->domain() != nullptr) &&
2470 !c.decl()->ti()->domain()->isa<TIId>()) {
2471 for (int i = 0; i < c.argCount(); i++) {
2472 if (c.arg(i)->type().isint()) {
2473 assert(!bounds.empty());
2474 bounds.pop_back();
2475 }
2476 }
2477 IntSetVal* isv = eval_intset(env, c.decl()->ti()->domain());
2478 bounds.emplace_back(isv->min(), isv->max());
2479 } else {
2480 valid = false;
2481 bounds.emplace_back(0, 0);
2482 }
2483 }
2484 /// Visit let
2485 void vLet(const Let& l) {
2486 valid = false;
2487 bounds.emplace_back(0, 0);
2488 }
2489 /// Visit variable declaration
2490 void vVarDecl(const VarDecl& vd) {
2491 valid = false;
2492 bounds.emplace_back(0, 0);
2493 }
2494 /// Visit annotation
2495 void vAnnotation(const Annotation& e) {
2496 valid = false;
2497 bounds.emplace_back(0, 0);
2498 }
2499 /// Visit type inst
2500 void vTypeInst(const TypeInst& e) {
2501 valid = false;
2502 bounds.emplace_back(0, 0);
2503 }
2504 /// Visit TIId
2505 void vTIId(const TIId& e) {
2506 valid = false;
2507 bounds.emplace_back(0, 0);
2508 }
2509};
2510
2511IntBounds compute_int_bounds(EnvI& env, Expression* e) {
2512 try {
2513 ComputeIntBounds cb(env);
2514 BottomUpIterator<ComputeIntBounds> cbi(cb);
2515 cbi.run(e);
2516 if (cb.valid) {
2517 assert(cb.bounds.size() == 1);
2518 return IntBounds(cb.bounds.back().first, cb.bounds.back().second, true);
2519 }
2520 return IntBounds(0, 0, false);
2521
2522 } catch (ResultUndefinedError&) {
2523 return IntBounds(0, 0, false);
2524 }
2525}
2526
2527class ComputeFloatBounds : public EVisitor {
2528protected:
2529 typedef std::pair<FloatVal, FloatVal> FBounds;
2530
2531public:
2532 std::vector<FBounds> bounds;
2533 bool valid;
2534 EnvI& env;
2535 ComputeFloatBounds(EnvI& env0) : valid(true), env(env0) {}
2536 bool enter(Expression* e) {
2537 if (e->type().isAnn()) {
2538 return false;
2539 }
2540 if (e->isa<VarDecl>()) {
2541 return false;
2542 }
2543 if (e->type().dim() > 0) {
2544 return false;
2545 }
2546 if (e->type().isPar()) {
2547 if (e->type().isfloat()) {
2548 Expression* exp = eval_par(env, e);
2549 if (exp == constants().absent) {
2550 valid = false;
2551 } else {
2552 FloatVal v = exp->cast<FloatLit>()->v();
2553 bounds.emplace_back(v, v);
2554 }
2555 }
2556 return false;
2557 }
2558 if (e->type().isfloat()) {
2559 if (ITE* ite = e->dynamicCast<ITE>()) {
2560 FBounds itebounds(FloatVal::infinity(), -FloatVal::infinity());
2561 for (int i = 0; i < ite->size(); i++) {
2562 if (ite->ifExpr(i)->type().isPar() &&
2563 static_cast<int>(ite->ifExpr(i)->type().cv()) == Type::CV_NO) {
2564 if (eval_bool(env, ite->ifExpr(i))) {
2565 BottomUpIterator<ComputeFloatBounds> cbi(*this);
2566 cbi.run(ite->thenExpr(i));
2567 FBounds& back = bounds.back();
2568 back.first = std::min(itebounds.first, back.first);
2569 back.second = std::max(itebounds.second, back.second);
2570 return false;
2571 }
2572 } else {
2573 BottomUpIterator<ComputeFloatBounds> cbi(*this);
2574 cbi.run(ite->thenExpr(i));
2575 FBounds back = bounds.back();
2576 bounds.pop_back();
2577 itebounds.first = std::min(itebounds.first, back.first);
2578 itebounds.second = std::max(itebounds.second, back.second);
2579 }
2580 }
2581 BottomUpIterator<ComputeFloatBounds> cbi(*this);
2582 cbi.run(ite->elseExpr());
2583 FBounds& back = bounds.back();
2584 back.first = std::min(itebounds.first, back.first);
2585 back.second = std::max(itebounds.second, back.second);
2586 return false;
2587 }
2588 return true;
2589 }
2590 return false;
2591 }
2592 /// Visit integer literal
2593 void vIntLit(const IntLit& i) {
2594 valid = false;
2595 bounds.emplace_back(0.0, 0.0);
2596 }
2597 /// Visit floating point literal
2598 void vFloatLit(const FloatLit& f) { bounds.emplace_back(f.v(), f.v()); }
2599 /// Visit Boolean literal
2600 void vBoolLit(const BoolLit& /*b*/) {
2601 valid = false;
2602 bounds.emplace_back(0.0, 0.0);
2603 }
2604 /// Visit set literal
2605 void vSetLit(const SetLit& /*sl*/) {
2606 valid = false;
2607 bounds.emplace_back(0.0, 0.0);
2608 }
2609 /// Visit string literal
2610 void vStringLit(const StringLit& /*sl*/) {
2611 valid = false;
2612 bounds.emplace_back(0.0, 0.0);
2613 }
2614 /// Visit identifier
2615 void vId(const Id& id) {
2616 VarDecl* vd = id.decl();
2617 while ((vd->flat() != nullptr) && vd->flat() != vd) {
2618 vd = vd->flat();
2619 }
2620 if (vd->ti()->domain() != nullptr) {
2621 GCLock lock;
2622 FloatSetVal* fsv = eval_floatset(env, vd->ti()->domain());
2623 if (fsv->size() == 0) {
2624 valid = false;
2625 bounds.emplace_back(0, 0);
2626 } else {
2627 bounds.emplace_back(fsv->min(0), fsv->max(fsv->size() - 1));
2628 }
2629 } else {
2630 if (vd->e() != nullptr) {
2631 BottomUpIterator<ComputeFloatBounds> cbi(*this);
2632 cbi.run(vd->e());
2633 } else {
2634 bounds.emplace_back(-FloatVal::infinity(), FloatVal::infinity());
2635 }
2636 }
2637 }
2638 /// Visit anonymous variable
2639 void vAnonVar(const AnonVar& v) {
2640 valid = false;
2641 bounds.emplace_back(0.0, 0.0);
2642 }
2643 /// Visit array literal
2644 void vArrayLit(const ArrayLit& al) {}
2645 /// Visit array access
2646 void vArrayAccess(ArrayAccess& aa) {
2647 bool parAccess = true;
2648 for (unsigned int i = aa.idx().size(); (i--) != 0U;) {
2649 if (!aa.idx()[i]->type().isPar()) {
2650 parAccess = false;
2651 }
2652 }
2653 if (Id* id = aa.v()->dynamicCast<Id>()) {
2654 while ((id->decl()->e() != nullptr) && id->decl()->e()->isa<Id>()) {
2655 id = id->decl()->e()->cast<Id>();
2656 }
2657 if (parAccess && (id->decl()->e() != nullptr)) {
2658 bool success;
2659 Expression* e = eval_arrayaccess(env, &aa, success);
2660 if (success) {
2661 BottomUpIterator<ComputeFloatBounds> cbi(*this);
2662 cbi.run(e);
2663 return;
2664 }
2665 }
2666 if (id->decl()->ti()->domain() != nullptr) {
2667 FloatSetVal* fsv = eval_floatset(env, id->decl()->ti()->domain());
2668 FBounds b(fsv->min(), fsv->max());
2669 bounds.push_back(b);
2670 return;
2671 }
2672 }
2673 valid = false;
2674 bounds.emplace_back(0.0, 0.0);
2675 }
2676 /// Visit array comprehension
2677 void vComprehension(const Comprehension& c) {
2678 valid = false;
2679 bounds.emplace_back(0.0, 0.0);
2680 }
2681 /// Visit if-then-else
2682 void vITE(const ITE& ite) {
2683 valid = false;
2684 bounds.emplace_back(0.0, 0.0);
2685 }
2686 /// Visit binary operator
2687 void vBinOp(const BinOp& bo) {
2688 FBounds b1 = bounds.back();
2689 bounds.pop_back();
2690 FBounds b0 = bounds.back();
2691 bounds.pop_back();
2692 if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() ||
2693 !b0.second.isFinite()) {
2694 valid = false;
2695 bounds.emplace_back(0.0, 0.0);
2696 } else {
2697 switch (bo.op()) {
2698 case BOT_PLUS:
2699 bounds.emplace_back(b0.first + b1.first, b0.second + b1.second);
2700 break;
2701 case BOT_MINUS:
2702 bounds.emplace_back(b0.first - b1.second, b0.second - b1.first);
2703 break;
2704 case BOT_MULT: {
2705 FloatVal x0 = b0.first * b1.first;
2706 FloatVal x1 = b0.first * b1.second;
2707 FloatVal x2 = b0.second * b1.first;
2708 FloatVal x3 = b0.second * b1.second;
2709 FloatVal m = std::min(x0, std::min(x1, std::min(x2, x3)));
2710 FloatVal n = std::max(x0, std::max(x1, std::max(x2, x3)));
2711 bounds.emplace_back(m, n);
2712 } break;
2713 case BOT_POW: {
2714 FloatVal x0 = std::pow(b0.first.toDouble(), b1.first.toDouble());
2715 FloatVal x1 = std::pow(b0.first.toDouble(), b1.second.toDouble());
2716 FloatVal x2 = std::pow(b0.second.toDouble(), b1.first.toDouble());
2717 FloatVal x3 = std::pow(b0.second.toDouble(), b1.second.toDouble());
2718 FloatVal m = std::min(x0, std::min(x1, std::min(x2, x3)));
2719 FloatVal n = std::max(x0, std::max(x1, std::max(x2, x3)));
2720 bounds.emplace_back(m, n);
2721 } break;
2722 case BOT_DIV:
2723 case BOT_IDIV:
2724 case BOT_MOD:
2725 case BOT_LE:
2726 case BOT_LQ:
2727 case BOT_GR:
2728 case BOT_GQ:
2729 case BOT_EQ:
2730 case BOT_NQ:
2731 case BOT_IN:
2732 case BOT_SUBSET:
2733 case BOT_SUPERSET:
2734 case BOT_UNION:
2735 case BOT_DIFF:
2736 case BOT_SYMDIFF:
2737 case BOT_INTERSECT:
2738 case BOT_PLUSPLUS:
2739 case BOT_EQUIV:
2740 case BOT_IMPL:
2741 case BOT_RIMPL:
2742 case BOT_OR:
2743 case BOT_AND:
2744 case BOT_XOR:
2745 case BOT_DOTDOT:
2746 valid = false;
2747 bounds.emplace_back(0.0, 0.0);
2748 }
2749 }
2750 }
2751 /// Visit unary operator
2752 void vUnOp(const UnOp& uo) {
2753 switch (uo.op()) {
2754 case UOT_PLUS:
2755 break;
2756 case UOT_MINUS:
2757 bounds.back().first = -bounds.back().first;
2758 bounds.back().second = -bounds.back().second;
2759 break;
2760 case UOT_NOT:
2761 valid = false;
2762 bounds.emplace_back(0.0, 0.0);
2763 }
2764 }
2765 /// Visit call
2766 void vCall(Call& c) {
2767 if (c.id() == constants().ids.lin_exp || c.id() == constants().ids.sum) {
2768 bool le = c.id() == constants().ids.lin_exp;
2769 ArrayLit* coeff = le ? eval_array_lit(env, c.arg(0)) : nullptr;
2770 if (le) {
2771 bounds.pop_back(); // remove constant (third arg) from stack
2772 }
2773 if (c.arg(le ? 1 : 0)->type().isOpt()) {
2774 valid = false;
2775 bounds.emplace_back(0.0, 0.0);
2776 return;
2777 }
2778 ArrayLit* al = eval_array_lit(env, c.arg(le ? 1 : 0));
2779 FloatVal d = le ? c.arg(2)->cast<FloatLit>()->v() : 0.0;
2780 int stacktop = static_cast<int>(bounds.size());
2781 for (unsigned int i = al->size(); (i--) != 0U;) {
2782 BottomUpIterator<ComputeFloatBounds> cbi(*this);
2783 cbi.run((*al)[i]);
2784 if (!valid) {
2785 return;
2786 }
2787 }
2788 assert(stacktop + al->size() == bounds.size());
2789 FloatVal lb = d;
2790 FloatVal ub = d;
2791 for (unsigned int i = 0; i < (*al).size(); i++) {
2792 FBounds b = bounds.back();
2793 bounds.pop_back();
2794 FloatVal cv = le ? eval_float(env, (*coeff)[i]) : 1.0;
2795
2796 if (cv > 0) {
2797 if (b.first.isFinite()) {
2798 if (lb.isFinite()) {
2799 lb += cv * b.first;
2800 }
2801 } else {
2802 lb = b.first;
2803 }
2804 if (b.second.isFinite()) {
2805 if (ub.isFinite()) {
2806 ub += cv * b.second;
2807 }
2808 } else {
2809 ub = b.second;
2810 }
2811 } else {
2812 if (b.second.isFinite()) {
2813 if (lb.isFinite()) {
2814 lb += cv * b.second;
2815 }
2816 } else {
2817 lb = -b.second;
2818 }
2819 if (b.first.isFinite()) {
2820 if (ub.isFinite()) {
2821 ub += cv * b.first;
2822 }
2823 } else {
2824 ub = -b.first;
2825 }
2826 }
2827 }
2828 bounds.emplace_back(lb, ub);
2829 } else if (c.id() == "float_times") {
2830 BottomUpIterator<ComputeFloatBounds> cbi(*this);
2831 cbi.run(c.arg(0));
2832 cbi.run(c.arg(1));
2833 FBounds b1 = bounds.back();
2834 bounds.pop_back();
2835 FBounds b0 = bounds.back();
2836 bounds.pop_back();
2837 if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() ||
2838 !b0.second.isFinite()) {
2839 valid = false;
2840 bounds.emplace_back(0, 0);
2841 } else {
2842 FloatVal x0 = b0.first * b1.first;
2843 FloatVal x1 = b0.first * b1.second;
2844 FloatVal x2 = b0.second * b1.first;
2845 FloatVal x3 = b0.second * b1.second;
2846 FloatVal m = std::min(x0, std::min(x1, std::min(x2, x3)));
2847 FloatVal n = std::max(x0, std::max(x1, std::max(x2, x3)));
2848 bounds.emplace_back(m, n);
2849 }
2850 } else if (c.id() == "int2float") {
2851 ComputeIntBounds ib(env);
2852 BottomUpIterator<ComputeIntBounds> cbi(ib);
2853 cbi.run(c.arg(0));
2854 if (!ib.valid) {
2855 valid = false;
2856 }
2857 ComputeIntBounds::Bounds result = ib.bounds.back();
2858 if (!result.first.isFinite() || !result.second.isFinite()) {
2859 valid = false;
2860 bounds.emplace_back(0.0, 0.0);
2861 } else {
2862 bounds.emplace_back(static_cast<double>(result.first.toInt()),
2863 static_cast<double>(result.second.toInt()));
2864 }
2865 } else if (c.id() == "abs") {
2866 BottomUpIterator<ComputeFloatBounds> cbi(*this);
2867 cbi.run(c.arg(0));
2868 FBounds b0 = bounds.back();
2869 if (b0.first < 0) {
2870 bounds.pop_back();
2871 if (b0.second < 0) {
2872 bounds.emplace_back(-b0.second, -b0.first);
2873 } else {
2874 bounds.emplace_back(0.0, std::max(-b0.first, b0.second));
2875 }
2876 }
2877 } else if ((c.decl() != nullptr) && (c.decl()->ti()->domain() != nullptr) &&
2878 !c.decl()->ti()->domain()->isa<TIId>()) {
2879 for (int i = 0; i < c.argCount(); i++) {
2880 if (c.arg(i)->type().isfloat()) {
2881 assert(!bounds.empty());
2882 bounds.pop_back();
2883 }
2884 }
2885 FloatSetVal* fsv = eval_floatset(env, c.decl()->ti()->domain());
2886 bounds.emplace_back(fsv->min(), fsv->max());
2887 } else {
2888 valid = false;
2889 bounds.emplace_back(0.0, 0.0);
2890 }
2891 }
2892 /// Visit let
2893 void vLet(const Let& l) {
2894 valid = false;
2895 bounds.emplace_back(0.0, 0.0);
2896 }
2897 /// Visit variable declaration
2898 void vVarDecl(const VarDecl& vd) {
2899 valid = false;
2900 bounds.emplace_back(0.0, 0.0);
2901 }
2902 /// Visit annotation
2903 void vAnnotation(const Annotation& e) {
2904 valid = false;
2905 bounds.emplace_back(0.0, 0.0);
2906 }
2907 /// Visit type inst
2908 void vTypeInst(const TypeInst& e) {
2909 valid = false;
2910 bounds.emplace_back(0.0, 0.0);
2911 }
2912 /// Visit TIId
2913 void vTIId(const TIId& e) {
2914 valid = false;
2915 bounds.emplace_back(0.0, 0.0);
2916 }
2917};
2918
2919FloatBounds compute_float_bounds(EnvI& env, Expression* e) {
2920 try {
2921 ComputeFloatBounds cb(env);
2922 BottomUpIterator<ComputeFloatBounds> cbi(cb);
2923 cbi.run(e);
2924 if (cb.valid) {
2925 assert(!cb.bounds.empty());
2926 return FloatBounds(cb.bounds.back().first, cb.bounds.back().second, true);
2927 }
2928 return FloatBounds(0.0, 0.0, false);
2929
2930 } catch (ResultUndefinedError&) {
2931 return FloatBounds(0.0, 0.0, false);
2932 }
2933}
2934
2935class ComputeIntSetBounds : public EVisitor {
2936public:
2937 std::vector<IntSetVal*> bounds;
2938 bool valid;
2939 EnvI& env;
2940 ComputeIntSetBounds(EnvI& env0) : valid(true), env(env0) {}
2941 bool enter(Expression* e) {
2942 if (e->type().isAnn()) {
2943 return false;
2944 }
2945 if (e->isa<VarDecl>()) {
2946 return false;
2947 }
2948 if (e->type().dim() > 0) {
2949 return false;
2950 }
2951 if (!e->type().isIntSet()) {
2952 return false;
2953 }
2954 if (e->type().isPar()) {
2955 bounds.push_back(eval_intset(env, e));
2956 return false;
2957 }
2958 return true;
2959 }
2960 /// Visit set literal
2961 void vSetLit(const SetLit& sl) {
2962 assert(sl.type().isvar());
2963 assert(sl.isv() == nullptr);
2964
2965 IntSetVal* isv = IntSetVal::a();
2966 for (unsigned int i = 0; i < sl.v().size(); i++) {
2967 IntSetRanges i0(isv);
2968 IntBounds ib = compute_int_bounds(env, sl.v()[i]);
2969 if (!ib.valid || !ib.l.isFinite() || !ib.u.isFinite()) {
2970 valid = false;
2971 bounds.push_back(nullptr);
2972 return;
2973 }
2974 Ranges::Const<IntVal> cr(ib.l, ib.u);
2975 Ranges::Union<IntVal, IntSetRanges, Ranges::Const<IntVal>> u(i0, cr);
2976 isv = IntSetVal::ai(u);
2977 }
2978 bounds.push_back(isv);
2979 }
2980 /// Visit identifier
2981 void vId(const Id& id) {
2982 if ((id.decl()->ti()->domain() != nullptr) && !id.decl()->ti()->domain()->isa<TIId>()) {
2983 bounds.push_back(eval_intset(env, id.decl()->ti()->domain()));
2984 } else {
2985 if (id.decl()->e() != nullptr) {
2986 BottomUpIterator<ComputeIntSetBounds> cbi(*this);
2987 cbi.run(id.decl()->e());
2988 } else {
2989 valid = false;
2990 bounds.push_back(nullptr);
2991 }
2992 }
2993 }
2994 /// Visit anonymous variable
2995 void vAnonVar(const AnonVar& v) {
2996 valid = false;
2997 bounds.push_back(nullptr);
2998 }
2999 /// Visit array access
3000 void vArrayAccess(ArrayAccess& aa) {
3001 bool parAccess = true;
3002 for (unsigned int i = aa.idx().size(); (i--) != 0U;) {
3003 if (!aa.idx()[i]->type().isPar()) {
3004 parAccess = false;
3005 break;
3006 }
3007 }
3008 if (Id* id = aa.v()->dynamicCast<Id>()) {
3009 while ((id->decl()->e() != nullptr) && id->decl()->e()->isa<Id>()) {
3010 id = id->decl()->e()->cast<Id>();
3011 }
3012 if (parAccess && (id->decl()->e() != nullptr)) {
3013 bool success;
3014 Expression* e = eval_arrayaccess(env, &aa, success);
3015 if (success) {
3016 BottomUpIterator<ComputeIntSetBounds> cbi(*this);
3017 cbi.run(e);
3018 return;
3019 }
3020 }
3021 if (id->decl()->ti()->domain() != nullptr) {
3022 bounds.push_back(eval_intset(env, id->decl()->ti()->domain()));
3023 return;
3024 }
3025 }
3026 valid = false;
3027 bounds.push_back(nullptr);
3028 }
3029 /// Visit array comprehension
3030 void vComprehension(const Comprehension& c) {
3031 valid = false;
3032 bounds.push_back(nullptr);
3033 }
3034 /// Visit if-then-else
3035 void vITE(const ITE& ite) {
3036 valid = false;
3037 bounds.push_back(nullptr);
3038 }
3039 /// Visit binary operator
3040 void vBinOp(const BinOp& bo) {
3041 if (bo.op() == BOT_DOTDOT) {
3042 IntBounds lb = compute_int_bounds(env, bo.lhs());
3043 IntBounds ub = compute_int_bounds(env, bo.rhs());
3044 valid = valid && lb.valid && ub.valid;
3045 bounds.push_back(IntSetVal::a(lb.l, ub.u));
3046 } else {
3047 IntSetVal* b1 = bounds.back();
3048 bounds.pop_back();
3049 IntSetVal* b0 = bounds.back();
3050 bounds.pop_back();
3051 switch (bo.op()) {
3052 case BOT_INTERSECT:
3053 case BOT_UNION: {
3054 IntSetRanges b0r(b0);
3055 IntSetRanges b1r(b1);
3056 Ranges::Union<IntVal, IntSetRanges, IntSetRanges> u(b0r, b1r);
3057 bounds.push_back(IntSetVal::ai(u));
3058 } break;
3059 case BOT_DIFF: {
3060 bounds.push_back(b0);
3061 } break;
3062 case BOT_SYMDIFF:
3063 valid = false;
3064 bounds.push_back(nullptr);
3065 break;
3066 case BOT_PLUS:
3067 case BOT_MINUS:
3068 case BOT_MULT:
3069 case BOT_POW:
3070 case BOT_DIV:
3071 case BOT_IDIV:
3072 case BOT_MOD:
3073 case BOT_LE:
3074 case BOT_LQ:
3075 case BOT_GR:
3076 case BOT_GQ:
3077 case BOT_EQ:
3078 case BOT_NQ:
3079 case BOT_IN:
3080 case BOT_SUBSET:
3081 case BOT_SUPERSET:
3082 case BOT_PLUSPLUS:
3083 case BOT_EQUIV:
3084 case BOT_IMPL:
3085 case BOT_RIMPL:
3086 case BOT_OR:
3087 case BOT_AND:
3088 case BOT_XOR:
3089 case BOT_DOTDOT:
3090 valid = false;
3091 bounds.push_back(nullptr);
3092 }
3093 }
3094 }
3095 /// Visit unary operator
3096 void vUnOp(const UnOp& uo) {
3097 valid = false;
3098 bounds.push_back(nullptr);
3099 }
3100 /// Visit call
3101 void vCall(Call& c) {
3102 if (valid && (c.id() == "set_intersect" || c.id() == "set_union")) {
3103 IntSetVal* b0 = bounds.back();
3104 bounds.pop_back();
3105 IntSetVal* b1 = bounds.back();
3106 bounds.pop_back();
3107 IntSetRanges b0r(b0);
3108 IntSetRanges b1r(b1);
3109 Ranges::Union<IntVal, IntSetRanges, IntSetRanges> u(b0r, b1r);
3110 bounds.push_back(IntSetVal::ai(u));
3111 } else if (valid && c.id() == "set_diff") {
3112 IntSetVal* b0 = bounds.back();
3113 bounds.pop_back();
3114 bounds.pop_back(); // don't need bounds of right hand side
3115 bounds.push_back(b0);
3116 } else if ((c.decl() != nullptr) && (c.decl()->ti()->domain() != nullptr) &&
3117 !c.decl()->ti()->domain()->isa<TIId>()) {
3118 for (int i = 0; i < c.argCount(); i++) {
3119 if (c.arg(i)->type().isIntSet()) {
3120 assert(!bounds.empty());
3121 bounds.pop_back();
3122 }
3123 }
3124 IntSetVal* fsv = eval_intset(env, c.decl()->ti()->domain());
3125 bounds.push_back(fsv);
3126 } else {
3127 valid = false;
3128 bounds.push_back(nullptr);
3129 }
3130 }
3131 /// Visit let
3132 void vLet(const Let& l) {
3133 valid = false;
3134 bounds.push_back(nullptr);
3135 }
3136 /// Visit variable declaration
3137 void vVarDecl(const VarDecl& vd) {
3138 valid = false;
3139 bounds.push_back(nullptr);
3140 }
3141 /// Visit annotation
3142 void vAnnotation(const Annotation& e) {
3143 valid = false;
3144 bounds.push_back(nullptr);
3145 }
3146 /// Visit type inst
3147 void vTypeInst(const TypeInst& e) {
3148 valid = false;
3149 bounds.push_back(nullptr);
3150 }
3151 /// Visit TIId
3152 void vTIId(const TIId& e) {
3153 valid = false;
3154 bounds.push_back(nullptr);
3155 }
3156};
3157
3158IntSetVal* compute_intset_bounds(EnvI& env, Expression* e) {
3159 try {
3160 ComputeIntSetBounds cb(env);
3161 BottomUpIterator<ComputeIntSetBounds> cbi(cb);
3162 cbi.run(e);
3163 if (cb.valid) {
3164 return cb.bounds.back();
3165 }
3166 return nullptr;
3167
3168 } catch (ResultUndefinedError&) {
3169 return nullptr;
3170 }
3171}
3172
3173Expression* follow_id(Expression* e) {
3174 for (;;) {
3175 if (e == nullptr) {
3176 return nullptr;
3177 }
3178 if (e->eid() == Expression::E_ID && e != constants().absent) {
3179 e = e->cast<Id>()->decl()->e();
3180 } else {
3181 return e;
3182 }
3183 }
3184}
3185
3186Expression* follow_id_to_decl(Expression* e) {
3187 for (;;) {
3188 if (e == nullptr) {
3189 return nullptr;
3190 }
3191 if (e == constants().absent) {
3192 return e;
3193 }
3194 switch (e->eid()) {
3195 case Expression::E_ID:
3196 e = e->cast<Id>()->decl();
3197 break;
3198 case Expression::E_VARDECL: {
3199 Expression* vd_e = e->cast<VarDecl>()->e();
3200 if ((vd_e != nullptr) && vd_e->isa<Id>() && vd_e != constants().absent) {
3201 e = vd_e;
3202 } else {
3203 return e;
3204 }
3205 break;
3206 }
3207 default:
3208 return e;
3209 }
3210 }
3211}
3212
3213Expression* follow_id_to_value(Expression* e) {
3214 Expression* decl = follow_id_to_decl(e);
3215 if (auto* vd = decl->dynamicCast<VarDecl>()) {
3216 if ((vd->e() != nullptr) && vd->e()->type().isPar()) {
3217 return vd->e();
3218 }
3219 return vd->id();
3220 }
3221 return decl;
3222}
3223
3224} // namespace MiniZinc