this repo has no description
1#include <minizinc/codegen.hh>
2
3#include <../lib/codegen/analysis.hpp>
4
5namespace MiniZinc {
6
7/// Visit identifier
8void ModeAnalysis::vId(Id& x, Occurrence o, CG::Mode m) {
9 // Use sites follow
10 VarDecl* decl(x.decl());
11 if (o == Use && decl) update(decl, o, m);
12}
13/// Visit array literal
14void ModeAnalysis::vArrayLit(ArrayLit& a, Occurrence o, CG::Mode m) {
15 // If the array contents are Boolean, this doesn't count as an occurrence;
16 // we care about the context of the access.
17 // But for anything else, the partiality emerges at the occurrence site.
18 int sz(a.size());
19 for (int ii = 0; ii < sz; ++ii) {
20 Expression* elt(a[ii]);
21 if (o == Use || elt->type().bt() != Type::BT_BOOL) {
22 update(elt, o, m);
23 }
24 }
25}
26/// Visit array access
27void ModeAnalysis::vArrayAccess(ArrayAccess& a, Occurrence o, CG::Mode m) {
28 ASTExprVec<Expression> idx(a.idx());
29 for (int ii = 0; ii < idx.size(); ++ii) update(idx[ii], o, m);
30 if (a.type().bt() == Type::BT_BOOL)
31 update(a.v(), o, +m);
32 else
33 update(a.v(), o, m);
34}
35/// Visit array comprehension
36void ModeAnalysis::vComprehension(Comprehension& comp, Occurrence o, CG::Mode m) {
37 // Comprehension behaves like an array access:
38 // The current mode propagates to the generators, but only to non-Boolean bodies.
39 if (o == Def) {
40 int g_n(comp.n_generators());
41 for (int gg = 0; gg < g_n; ++gg) {
42 int d_n(comp.n_decls(gg));
43 for (int d = 0; d < d_n; ++d) update(comp.decl(gg, d), o, m);
44 update(comp.in(gg), o, m);
45 if (comp.where(gg)) {
46 update(comp.where(gg), Use, BytecodeProc::FUN);
47 }
48 }
49 }
50 if (o == Use || comp.e()->type().bt() != Type::BT_BOOL) {
51 int g_n(comp.n_generators());
52 for (int gg = 0; gg < comp.n_generators(); ++gg) {
53 if (comp.where(gg)) {
54 update(comp.where(gg), Use, BytecodeProc::FUN);
55 }
56 }
57 update(comp.e(), o, m);
58 }
59}
60/// Visit if-then-else
61void ModeAnalysis::vITE(ITE& ite, Occurrence o, CG::Mode m) {
62 int sz(ite.size());
63 for (int ii = 0; ii < sz; ++ii) {
64 // We need the condition to compute the value.
65 update(ite.e_if(ii), Use, BytecodeProc::FUN);
66 update(ite.e_then(ii), o, m);
67 }
68 update(ite.e_else(), o, m);
69}
70
71/// Visit binary operator
72void ModeAnalysis::vBinOp(BinOp& b, Occurrence o, CG::Mode m) {
73 switch (b.op()) {
74 case BOT_IMPL: {
75 CG::Mode m_c = m.is_neg() ? m : +m;
76 update(b.lhs(), o, -m_c);
77 update(b.rhs(), o, m_c);
78 break;
79 }
80 case BOT_RIMPL: {
81 CG::Mode m_c = m.is_neg() ? m : +m;
82 update(b.lhs(), o, m_c);
83 update(b.rhs(), o, -m_c);
84 break;
85 }
86 case BOT_OR: {
87 CG::Mode m_c = m.is_neg() ? m : +m;
88 update(b.lhs(), o, m_c);
89 update(b.rhs(), o, m_c);
90 break;
91 }
92 case BOT_AND: {
93 CG::Mode m_c = m.is_neg() ? +m : m;
94 update(b.lhs(), o, m_c);
95 update(b.rhs(), o, m_c);
96 break;
97 }
98 case BOT_EQ:
99 case BOT_NQ: {
100 CG::Mode m_l = b.lhs()->type().bt() == Type::BT_BOOL ? CG::Mode(BytecodeProc::FUN) : +m;
101 CG::Mode m_r = b.rhs()->type().bt() == Type::BT_BOOL ? CG::Mode(BytecodeProc::FUN) : +m;
102 update(b.lhs(), o, m_l);
103 update(b.rhs(), o, m_r);
104 }
105 case BOT_EQUIV:
106 case BOT_XOR:
107 update(b.lhs(), o, BytecodeProc::FUN);
108 update(b.rhs(), o, BytecodeProc::FUN);
109 break;
110 default:
111 update(b.lhs(), o, m);
112 update(b.rhs(), o, m);
113 }
114}
115/// Visit unary operator
116void ModeAnalysis::vUnOp(UnOp& u, Occurrence o, CG::Mode m) {
117 switch (u.op()) {
118 case UOT_NOT:
119 update(u.e(), o, -m);
120 break;
121 default:
122 update(u.e(), o, m);
123 }
124}
125
126/// Visit call
127// TODO: Add special cases for builtin calls, and interprocedural analysis
128// so we can get more precise mode analysis.
129void ModeAnalysis::vCall(Call& call, Occurrence o, CG::Mode m) {
130 int sz(call.n_args());
131 if (call.id() == constants().ids.forall) {
132 assert(sz == 1);
133 CG::Mode m_r(m.is_neg() ? +m : m);
134 update(call.arg(0), o, m_r);
135 } else if (call.id() == constants().ids.exists) {
136 assert(sz == 1);
137 CG::Mode m_r(m.is_neg() ? m : +m);
138 update(call.arg(0), o, m_r);
139 } else if (call.id() == constants().ids.clause) {
140 assert(sz == 2);
141 CG::Mode m_r(m.is_neg() ? m : +m);
142 update(call.arg(0), o, m_r);
143 update(call.arg(1), o, -m_r);
144 } else if (call.id() == constants().ids.assert) {
145 update(call.arg(0), Use, BytecodeProc::ROOT);
146 if (sz == 3) update(call.arg(2), o, m);
147 } else if (call.id() == "array1d") {
148 // No-op
149 update(call.arg(sz - 1), o, m);
150 } else if (call.id() == "index_set" || call.id() == "length") {
151 if (o == Def) update(call.arg(0), Def, m);
152 } else if (call.id() == "symmetry_breaking_constraint" || call.id() == "redundant_constraint") {
153 // No-op
154 update(call.arg(0), o, m);
155 } else {
156 // Propagate to the other functions.
157 for (int ii = 0; ii < sz; ++ii) {
158 Expression* arg(call.arg(ii));
159 // If arg is non-Boolean, this the partiality gets embedded here.
160 // But if arg is Boolean, we have to assume the callee can do
161 // anything with it, so the occurrence is considered FUN.
162 if (arg->type().bt() == Type::BT_BOOL) {
163 update(arg, Use, BytecodeProc::FUN);
164 } else {
165 update(arg, o, m);
166 }
167 }
168 }
169}
170/// Visit let
171void ModeAnalysis::vLet(Let& let, Occurrence o, CG::Mode m) {
172 ASTExprVec<Expression> bindings(let.let());
173 if (o == Def || let.type().bt() == Type::BT_BOOL) {
174 // If the let has Boolean type, the _use_ of the let defines
175 // the def-mode of the bound variables.
176 for (Expression* e : bindings) {
177 // Check whether this is a decl with a def.
178 if (auto vd = e->dyn_cast<VarDecl>()) {
179 if (vd->type().bt() != Type::BT_BOOL) update(vd, Def, m);
180 /*
181 if(Expression* v_e = vd->e()) {
182 if(!v_e->type().isbool()) {
183 update(v_e, Def, m);
184 }
185 }
186 */
187 } else {
188 // Must be a constraint, so it's a use.
189 assert(e->type().isbool());
190 update(e, Use, m);
191 }
192 }
193 update(let.in(), o, m);
194 } else {
195 // Non-Boolean use; the partiality is in an enclosing
196 // context.
197 update(let.in(), o, m);
198 }
199}
200/// Visit variable declaration
201void ModeAnalysis::vVarDecl(VarDecl& decl, Occurrence o, CG::Mode m) {
202 if (Id* x = decl.id()) update(x, o, m);
203 if (Expression* d = decl.ti()->domain()) {
204 if (o == Def) {
205 update(d, Def, m);
206 update(d, Use, m);
207 }
208 }
209 if (Expression* e = decl.e()) update(e, o, m);
210}
211
212void ModeAnalysis::vFunctionI(FunctionI& fun, Occurrence o, CG::Mode m) {
213 // DO STUFF
214}
215}; // namespace MiniZinc