this repo has no description
at develop 7.5 kB view raw
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Graeme Gange <graeme.gange@monash.edu> 6 */ 7 8/* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12#ifndef __MINIZINC_CODEGEN_ANALYSIS_HPP__ 13#define __MINIZINC_CODEGEN_ANALYSIS_HPP__ 14#include <minizinc/ast.hh> 15#include <minizinc/astiterator.hh> 16#include <minizinc/codegen.hh> 17 18#include <queue> 19 20// From a given top-level expression and 21// mode, what is the weakest mode covering 22// all occurrences of each sub-expression? 23namespace MiniZinc { 24 25static void annotate_total(FunctionI* func) { 26 class AnnotateTotal : public EVisitor { 27 public: 28 void vLet(Let& let) { 29 let.addAnnotation(constants().ann.promise_total); 30 ASTExprVec<Expression> bindings(let.let()); 31 for (auto expr : bindings) { 32 if (expr->eid() != Expression::E_VARDECL) { 33 // Must be a constraint, so it's a use. 34 assert(expr->type().isbool()); 35 expr->addAnnotation(constants().ann.promise_total); 36 } 37 } 38 } 39 } _at; 40 if (func->ann().contains(constants().ann.promise_total)) { 41 topDown(_at, func->e()); 42 } 43} 44 45class ModeAnalysis { 46 enum Occurrence { Def = 0, Use = 1 }; 47 48public: 49 // There are two relevant modes for an expression: the mode 50 // where the value is introduced, and the mode where the value 51 // is used. 52 // This distinction mostly matters for let-bindings or definitions 53 // which construct results containing Booleans (i.e. array [int] of var bool). 54 // At the end, Boolean values are built according to their use-context, and 55 // non-Boolean values by their def-context. 56 57 // We use user_flag0 and user_flag1 to track whether 58 // the definition and use-modes are queued. 59 inline void enqueue(Expression* e, Occurrence o) { 60 if (e->isUnboxedVal()) return; 61 if (o == Def) { 62 if (!e->user_flag0()) { 63 e->user_flag0(true); 64 worklist.push(reinterpret_cast<uintptr_t>(e)); 65 } 66 } else { 67 if (!e->user_flag1()) { 68 e->user_flag1(true); 69 worklist.push(reinterpret_cast<uintptr_t>(e) | 1); 70 } 71 } 72 } 73 74 void update(Expression* e, Occurrence o, CG::Mode m) { 75 if (e->type().isbool()) { 76 if (o == Def) { 77 // We only keep Use-modes for Boolean things. 78 return; 79 } 80 if (e->ann().contains(constants().ann.promise_total)) { 81 m = BytecodeProc::ROOT; 82 } 83 } 84 ExprMap<CG::Mode>::t& t(o == Def ? def_map : use_map); 85 auto it(t.find(e)); 86 if (it == t.end()) { 87 // First time we've seen e. 88 t.insert(std::make_pair(e, m)); 89 } else { 90 if (it->second.is_submode(m)) return; 91 it->second = it->second.join(m); 92 } 93 enqueue(e, o); 94 } 95 96 void update(FunctionI* fun, Occurrence o, CG::Mode m) { 97 // We only keep Use-modes for Boolean things. 98 /* 99 if(o == Def) { 100 if(e->type().isbool()) 101 return; 102 if(e->ann().contains(constants().ann.promise_total)) 103 m = BytecodeProc::ROOT; 104 } 105 ExprMap<CG::Mode>::t& t(o == Def ? def_map : use_map); 106 auto it(t.find(e)); 107 if(it == t.end()) { 108 // First time we've seen e. 109 t.insert(std::make_pair(e, m)); 110 } else { 111 if(it->second.is_submode(m)) 112 return; 113 it->second = it->second.join(m); 114 } 115 enqueue(e, o); 116 */ 117 } 118 119 // Better to make this fifo, but... whatever. 120 void process(void) { 121 while (!worklist.empty()) { 122 uintptr_t tag(worklist.front()); 123 worklist.pop(); 124 Expression* e(reinterpret_cast<Expression*>(tag & ~((uintptr_t)1))); 125 Occurrence o(static_cast<Occurrence>(tag & 1)); 126 // Clear the queued-ness flags 127 if (o == Def) 128 e->user_flag0(false); 129 else 130 e->user_flag1(false); 131 132 // Get the updated mode for e. 133 ExprMap<CG::Mode>::t& t(o == Def ? def_map : use_map); 134 CG::Mode m(t.at(e)); 135 switch (e->eid()) { 136 case Expression::E_INTLIT: 137 case Expression::E_FLOATLIT: 138 case Expression::E_SETLIT: 139 case Expression::E_BOOLLIT: 140 case Expression::E_STRINGLIT: 141 case Expression::E_ANON: 142 break; 143 case Expression::E_ID: 144 vId(*e->template cast<Id>(), o, m); 145 break; 146 case Expression::E_ARRAYLIT: 147 vArrayLit(*e->template cast<ArrayLit>(), o, m); 148 break; 149 case Expression::E_ARRAYACCESS: 150 vArrayAccess(*e->template cast<ArrayAccess>(), o, m); 151 break; 152 case Expression::E_COMP: 153 vComprehension(*e->template cast<Comprehension>(), o, m); 154 break; 155 case Expression::E_ITE: 156 vITE(*e->template cast<ITE>(), o, m); 157 break; 158 case Expression::E_BINOP: 159 vBinOp(*e->template cast<BinOp>(), o, m); 160 break; 161 case Expression::E_UNOP: 162 vUnOp(*e->template cast<UnOp>(), o, m); 163 break; 164 case Expression::E_CALL: 165 vCall(*e->template cast<Call>(), o, m); 166 break; 167 case Expression::E_VARDECL: 168 vVarDecl(*e->template cast<VarDecl>(), o, m); 169 break; 170 case Expression::E_LET: 171 vLet(*e->template cast<Let>(), o, m); 172 break; 173 /* 174 case Expression::E_TI: 175 _t.vTypeInst(*c._e->template cast<TypeInst>()); 176 break; 177 case Expression::E_TIID: 178 _t.vTIId(*c._e->template cast<TIId>()); 179 break; 180 */ 181 default: 182 throw InternalError("Mode analyser encounted unexpected expression type."); 183 } 184 } 185 } 186 187 ModeAnalysis(void) {} 188 189 void def(Expression* e, CG::Mode m) { update(e, Def, m); } 190 191 void use(Expression* e, CG::Mode m) { 192 if (e->type().isbool()) 193 update(e, Use, m); 194 else 195 update(e, Def, m); 196 } 197 198 ExprMap<CG::Mode>::t extract(void) { 199 // Compute the fixpoint. 200 process(); 201 // Now fuse the two maps. 202 // Start from the def_map, and add any Boolean uses. 203 ExprMap<CG::Mode>::t fused(def_map); 204 for (auto p : use_map) { 205 /* 206 if(p.first->type().isbool()) 207 fused.insert(p); 208 */ 209 // If we haven't stored a def-mode, we should 210 // apply the use-mode. 211 fused.insert(p); 212 } 213 return fused; 214 } 215 /* 216 static ExprMap<CG::Mode> run(Expression* e, CG::Mode m) { 217 ModeAnalysis analyzer; 218 analyzer.update(e, Use, m); 219 analyzer.process(); 220 221 // Now we fuse the two maps. 222 } 223 */ 224 225 std::queue<uintptr_t> worklist; 226 ExprMap<CG::Mode>::t def_map; 227 ExprMap<CG::Mode>::t use_map; 228 229 /// Visit identifier 230 void vId(Id&, Occurrence, CG::Mode); 231 /// Visit array literal 232 void vArrayLit(ArrayLit&, Occurrence, CG::Mode); 233 /// Visit array access 234 void vArrayAccess(ArrayAccess&, Occurrence, CG::Mode); 235 /// Visit array comprehension 236 void vComprehension(Comprehension&, Occurrence, CG::Mode); 237 /// Visit if-then-else 238 void vITE(ITE&, Occurrence, CG::Mode); 239 /// Visit binary operator 240 void vBinOp(BinOp&, Occurrence, CG::Mode); 241 /// Visit unary operator 242 void vUnOp(UnOp&, Occurrence, CG::Mode); 243 /// Visit call 244 void vCall(Call&, Occurrence, CG::Mode); 245 /// Visit let 246 void vLet(Let&, Occurrence, CG::Mode); 247 /// Visit variable declaration 248 void vVarDecl(VarDecl&, Occurrence, CG::Mode); 249 250 // Process a function body. 251 void vFunctionI(FunctionI&, Occurrence, CG::Mode); 252}; 253 254}; // namespace MiniZinc 255 256#endif