00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00035 #include "ctrump/analyzer/analyze.h"
00036 #include "ctrump/common/mempool.h"
00037 #include "ctrump/ast/ast.h"
00038 #include "ctrump/analyzer/cfg.h"
00039 #include <stdlib.h>
00040 #include "ctrump/common/abort.h"
00041 #include "ctrump/common/varray.h"
00042 #include "ctrump/common/intmap.h"
00043
00047 struct analyze_allocator
00048 {
00049 struct ctrump_mempool *pool;
00050 int id;
00051 };
00052
00056 struct build_loop_tree_state {
00057 int num_complicated;
00058 struct ctrump_complicated_loop reason;
00059 struct ctrump_intmap *var_info_map;
00060 struct ctrump_varray children;
00061 struct ctrump_varray *loop_tree_roots;
00062 };
00063
00064 static void
00065 init_build_loop_tree_state(struct build_loop_tree_state *st,
00066 struct ctrump_intmap *var_info_map,
00067 struct ctrump_varray *loops)
00068 {
00069 st->num_complicated = 0;
00070 st->var_info_map = var_info_map;
00071 st->loop_tree_roots = loops;
00072
00073 ctrump_varray_init(&st->children, 4, sizeof(struct ctrump_loop_info_node *));
00074 }
00075
00076 static void
00077 destroy_build_loop_tree_state(struct build_loop_tree_state *st)
00078 {
00079 ctrump_varray_discard(&st->children);
00080 }
00081
00082 static int analyze_loop_control_flow(struct build_loop_tree_state *st,
00083 struct ctrump_loop_cfg_info *attr,
00084 struct ctrump_cfg *cfg,
00085 struct ctrump_stmt *loop_body,
00086 struct ctrump_location *loc,
00087 struct analyze_allocator *alloc);
00088
00089 static void analyze_control_flow(struct build_loop_tree_state *st,
00090 struct ctrump_stmt *stmt,
00091 struct ctrump_cfg *cfg,
00092 struct analyze_allocator *alloc);
00093
00094 static void
00095 build_loop_tree_compound_stmt(struct build_loop_tree_state *st,
00096 struct ctrump_compound_stmt *stmt,
00097 struct ctrump_cfg *cfg,
00098 struct analyze_allocator *alloc)
00099 {
00100 int ni = stmt->num_item;
00101 struct ctrump_stmt *items = stmt->items;
00102 int i;
00103
00104 for (i=0; i<ni; i++) {
00105 analyze_control_flow(st, &items[i], cfg, alloc);
00106 }
00107 }
00108 static void
00109 complicated_loop(struct build_loop_tree_state *st,
00110 enum ctrump_complicated_loop_reason_code code,
00111 struct ctrump_stmt *stmt)
00112 {
00113 if (st->num_complicated == 0) {
00114 st->reason.reason = code;
00115 st->reason.stmt = stmt;
00116 }
00117 st->num_complicated ++;
00118 }
00119
00124 static void
00125 analyze_control_flow(struct build_loop_tree_state *st,
00126 struct ctrump_stmt *stmt,
00127 struct ctrump_cfg *cfg,
00128 struct analyze_allocator *alloc)
00129 {
00130 int r;
00131 tailcall:
00132 switch (stmt->code) {
00133 case CTRUMP_STMT_LABELED:
00134 stmt = stmt->u.labeled.stmt;
00135 goto tailcall;
00136
00137 case CTRUMP_STMT_CASE:
00138 stmt = stmt->u.case_.stmt;
00139 goto tailcall;
00140
00141 case CTRUMP_STMT_DEFAULT:
00142 stmt = stmt->u.default_.stmt;
00143 goto tailcall;
00144
00145 case CTRUMP_STMT_COMPOUND:
00146 build_loop_tree_compound_stmt(st, &stmt->u.compound, cfg, alloc);
00147 return ;
00148
00149 case CTRUMP_STMT_IF:
00150 stmt = stmt->u.if_.body;
00151 goto tailcall;
00152
00153 case CTRUMP_STMT_IF_ELSE:
00154 analyze_control_flow(st, stmt->u.if_else.then_body, cfg, alloc);
00155 stmt = stmt->u.if_else.else_body;
00156 goto tailcall;
00157
00158 case CTRUMP_STMT_SWITCH:
00159 stmt = stmt->u.switch_.body;
00160 goto tailcall;
00161
00162 case CTRUMP_STMT_FOR:
00163 r = analyze_loop_control_flow(st,
00164 stmt->u.for_.loop_cfg,
00165 cfg,
00166 stmt->u.for_.body,
00167 &stmt->u.for_.kwd_loc,
00168 alloc);
00169 if (r < 0)
00170 complicated_loop(st, CTRUMP_COMPLICATED_LOOP_HAVE_COMPLICATED_NEST, stmt);
00171 return;
00172
00173 case CTRUMP_STMT_FOR_DECL:
00174 r = analyze_loop_control_flow(st,
00175 stmt->u.for_decl.loop_cfg,
00176 cfg,
00177 stmt->u.for_decl.body,
00178 &stmt->u.for_decl.kwd_loc,
00179 alloc);
00180 if (r < 0)
00181 complicated_loop(st, CTRUMP_COMPLICATED_LOOP_HAVE_COMPLICATED_NEST, stmt);
00182 return;
00183
00184 case CTRUMP_STMT_WHILE:
00185 r = analyze_loop_control_flow(st,
00186 stmt->u.while_.loop_cfg,
00187 cfg,
00188 stmt->u.while_.body,
00189 &stmt->u.while_.kwd_loc,
00190 alloc);
00191 if (r < 0)
00192 complicated_loop(st, CTRUMP_COMPLICATED_LOOP_HAVE_COMPLICATED_NEST, stmt);
00193 return;
00194
00195 case CTRUMP_STMT_GOTO:
00196 complicated_loop(st, CTRUMP_COMPLICATED_LOOP_GOTO, stmt); return;
00197 case CTRUMP_STMT_BREAK:
00198 complicated_loop(st, CTRUMP_COMPLICATED_LOOP_BREAK, stmt); return;
00199 case CTRUMP_STMT_RETURN_EXPR:
00200 case CTRUMP_STMT_RETURN:
00201 complicated_loop(st, CTRUMP_COMPLICATED_LOOP_RETURN, stmt); return;
00202 case CTRUMP_STMT_DO_WHILE:
00203 complicated_loop(st, CTRUMP_COMPLICATED_LOOP_NEST, stmt);
00204 stmt = stmt->u.do_while.body;
00205 goto tailcall;
00206
00207 case CTRUMP_STMT_EXPR:
00208 case CTRUMP_STMT_DECL:
00209 case CTRUMP_STMT_EMPTY:
00210 case CTRUMP_STMT_PRAGMA:
00211 case CTRUMP_STMT_SLASLA_COMMENT:
00212 case CTRUMP_STMT_SLAAST_COMMENT:
00213 case CTRUMP_STMT_DEFINE:
00214 case CTRUMP_STMT_UNDEF:
00215 case CTRUMP_STMT_CONTINUE:
00216 case CTRUMP_STMT_IFDEF:
00217 case CTRUMP_STMT_ASM:
00218 case CTRUMP_STMT_NEWLINE:
00219 return;
00220
00221 case CTRUMP_STMT_LIST:
00222 break;
00223 }
00224
00225 ctrump_unreachable("control_flow");
00226 }
00227
00231 static void
00232 append_root(struct ctrump_varray *roots,
00233 struct ctrump_varray *new_roots)
00234 {
00235 int i, n;
00236 struct ctrump_loop_info_node **children;
00237 n = new_roots->nelem;
00238 children = new_roots->elements;
00239
00240
00241 for (i=0; i<n; i++) {
00242 VA_PUSH(struct ctrump_loop_info_node*,
00243 roots,
00244 children[i]);
00245 }
00246 }
00247
00248 static int
00249 analyze_loop_control_flow(struct build_loop_tree_state *prev_st,
00250 struct ctrump_loop_cfg_info *cfg_info,
00251 struct ctrump_cfg *cfg,
00252 struct ctrump_stmt *body,
00253 struct ctrump_location *loc,
00254 struct analyze_allocator *alloc)
00255 {
00256 struct build_loop_tree_state st;
00257 struct ctrump_loop_info_node *node;
00258
00259 init_build_loop_tree_state(&st, prev_st->var_info_map,
00260 prev_st->loop_tree_roots);
00261
00262 analyze_control_flow(&st, body, cfg, alloc);
00263
00264 if (st.num_complicated != 0) {
00265
00266
00267 cfg_info->code = CTRUMP_LOOP_COMPLICATED;
00268 cfg_info->u.complicated = st.reason;
00269
00270 append_root(prev_st->loop_tree_roots, &st.children);
00271
00272 destroy_build_loop_tree_state(&st);
00273
00274 return -1;
00275 }
00276
00277 node = ctrump_mempool_alloc(alloc->pool, sizeof(*node));
00278 node->id = alloc->id++;
00279 node->nest_level = 0;
00280
00281 if (st.children.nelem) {
00282 node->num_child = st.children.nelem;
00283 node->children = ctrump_varray_copy(&st.children, alloc->pool);
00284 } else {
00285 node->children = NULL;
00286 node->num_child = 0;
00287 }
00288 node->parent = NULL;
00289 node->cfg_info = cfg_info;
00290 node->loc = *loc;
00291
00292 VA_PUSH(struct ctrump_loop_info_node*, &prev_st->children, node);
00293
00294 destroy_build_loop_tree_state(&st);
00295
00296 return 0;
00297 }
00298
00302 static void
00303 build_loop_tree_func(struct ctrump_varray *loops,
00304 struct ctrump_fundef *func,
00305 struct ctrump_cfg *cfg,
00306 struct ctrump_intmap *var_info_map,
00307 const struct ctrump_abi *abi,
00308 struct analyze_allocator *alloc)
00309 {
00310 struct build_loop_tree_state st;
00311 int i, n;
00312 struct ctrump_loop_info_node **roots;
00313
00314 init_build_loop_tree_state(&st, var_info_map, loops);
00315
00316 build_loop_tree_compound_stmt(&st, &func->body, cfg, alloc);
00317
00318 append_root(loops, &st.children);
00319
00320 n = loops->nelem;
00321 roots = loops->elements;
00322 for (i=0; i<n; i++) {
00323 struct ctrump_loop_info *loop_info = ctrump_mempool_alloc(alloc->pool, sizeof(*loop_info));
00324 struct ctrump_loop_info_node *root = roots[i];
00325 loop_info->id = alloc->id++;
00326 loop_info->root = root;
00327 alloc->id = ctrump_analyze_loop(loop_info, &loop_info->nest_level, root, cfg,
00328 var_info_map, abi, alloc->pool, alloc->id);
00329 }
00330
00331 destroy_build_loop_tree_state(&st);
00332 }
00333
00334 int
00335 ctrump_analyze(struct ctrump_translation_unit *unit,
00336 const struct ctrump_abi *abi,
00337 struct ctrump_mempool *pool,
00338 struct ctrump_build_cfg_error *error,
00339 int num_ast,
00340 int id_base)
00341 {
00342 int i, r;
00343 int id = id_base;
00344 int nd = unit->num_decl;
00345 struct analyze_allocator alloc;
00346 struct ctrump_varray loops;
00347
00348 ctrump_varray_init(&loops, 16, sizeof(struct ctrump_loop_info *));
00349
00350 alloc.pool = pool;
00351 for (i=0; i<nd; i++) {
00352 struct ctrump_extdecl *d = unit->decls + i;
00353 struct ctrump_intmap var_info_map;
00354 switch (d->code) {
00355 case CTRUMP_EXT_FUNCTION_DEFINITION:
00356 {
00357 struct ctrump_mempool ana_pool;
00358 ctrump_mempool_init(&ana_pool, 1024);
00359 d->u.func_def.cfg = ctrump_mempool_alloc(pool, sizeof(*d->u.func_def.cfg));
00360 d->u.func_def.cfg->id = id;
00361 id++;
00362 r = ctrump_build_cfg(d->u.func_def.cfg, &var_info_map, error, &d->u.func_def, pool, &ana_pool, id_base, id);
00363 if (r < 0) {
00364 ctrump_mempool_destroy(&ana_pool);
00365 ctrump_varray_discard(&loops);
00366 return r;
00367 }
00368 id = r;
00369 alloc.id = id;
00370
00371 build_loop_tree_func(&loops, &d->u.func_def, d->u.func_def.cfg, &var_info_map, abi, &alloc);
00372
00373 id = alloc.id;
00374
00375 d->u.func_def.cfg->num_loop = loops.nelem;
00376 d->u.func_def.cfg->loop_tree_roots = ctrump_varray_copy(&loops, pool);
00377
00378 ctrump_mempool_destroy(&ana_pool);
00379
00380 loops.nelem = 0;
00381 }
00382 break;
00383
00384 default:
00385 break;
00386 }
00387 }
00388
00389 ctrump_varray_discard(&loops);
00390
00391 return id;
00392 }