00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023 #include "system.h"
00024 #include "coretypes.h"
00025 #include "tm.h"
00026 #include "tree.h"
00027 #include "diagnostic.h"
00028 #include "tree-flow.h"
00029 #include "tree-pass.h"
00030 #include "tree-ssa-propagate.h"
00031
00032 struct object_size_info
00033 {
00034 int object_size_type;
00035 bitmap visited, reexamine;
00036 int pass;
00037 bool changed;
00038 unsigned int *depths;
00039 unsigned int *stack, *tos;
00040 };
00041
00042 static unsigned HOST_WIDE_INT unknown[4] = { -1, -1, 0, 0 };
00043
00044 static tree compute_object_offset (tree, tree);
00045 static unsigned HOST_WIDE_INT addr_object_size (tree, int);
00046 static unsigned HOST_WIDE_INT alloc_object_size (tree, int);
00047 static tree pass_through_call (tree);
00048 static void collect_object_sizes_for (struct object_size_info *, tree);
00049 static void expr_object_size (struct object_size_info *, tree, tree);
00050 static bool merge_object_sizes (struct object_size_info *, tree, tree,
00051 unsigned HOST_WIDE_INT);
00052 static bool plus_expr_object_size (struct object_size_info *, tree, tree);
00053 static unsigned int compute_object_sizes (void);
00054 static void init_offset_limit (void);
00055 static void check_for_plus_in_loops (struct object_size_info *, tree);
00056 static void check_for_plus_in_loops_1 (struct object_size_info *, tree,
00057 unsigned int);
00058
00059
00060
00061
00062
00063
00064
00065 static unsigned HOST_WIDE_INT *object_sizes[4];
00066
00067
00068 static bitmap computed[4];
00069
00070
00071 static unsigned HOST_WIDE_INT offset_limit;
00072
00073
00074
00075 static void
00076 init_offset_limit (void)
00077 {
00078 if (host_integerp (TYPE_MAX_VALUE (sizetype), 1))
00079 offset_limit = tree_low_cst (TYPE_MAX_VALUE (sizetype), 1);
00080 else
00081 offset_limit = -1;
00082 offset_limit /= 2;
00083 }
00084
00085
00086
00087
00088
00089 static tree
00090 compute_object_offset (tree expr, tree var)
00091 {
00092 enum tree_code code = PLUS_EXPR;
00093 tree base, off, t;
00094
00095 if (expr == var)
00096 return size_zero_node;
00097
00098 switch (TREE_CODE (expr))
00099 {
00100 case COMPONENT_REF:
00101 base = compute_object_offset (TREE_OPERAND (expr, 0), var);
00102 if (base == error_mark_node)
00103 return base;
00104
00105 t = TREE_OPERAND (expr, 1);
00106 off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
00107 size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1)
00108 / BITS_PER_UNIT));
00109 break;
00110
00111 case REALPART_EXPR:
00112 case NOP_EXPR:
00113 case CONVERT_EXPR:
00114 case VIEW_CONVERT_EXPR:
00115 case NON_LVALUE_EXPR:
00116 return compute_object_offset (TREE_OPERAND (expr, 0), var);
00117
00118 case IMAGPART_EXPR:
00119 base = compute_object_offset (TREE_OPERAND (expr, 0), var);
00120 if (base == error_mark_node)
00121 return base;
00122
00123 off = TYPE_SIZE_UNIT (TREE_TYPE (expr));
00124 break;
00125
00126 case ARRAY_REF:
00127 base = compute_object_offset (TREE_OPERAND (expr, 0), var);
00128 if (base == error_mark_node)
00129 return base;
00130
00131 t = TREE_OPERAND (expr, 1);
00132 if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
00133 {
00134 code = MINUS_EXPR;
00135 t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
00136 }
00137 t = fold_convert (sizetype, t);
00138 off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
00139 break;
00140
00141 default:
00142 return error_mark_node;
00143 }
00144
00145 return size_binop (code, base, off);
00146 }
00147
00148
00149
00150
00151
00152
00153 static unsigned HOST_WIDE_INT
00154 addr_object_size (tree ptr, int object_size_type)
00155 {
00156 tree pt_var;
00157
00158 gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
00159
00160 pt_var = TREE_OPERAND (ptr, 0);
00161 if (REFERENCE_CLASS_P (pt_var))
00162 pt_var = get_base_address (pt_var);
00163
00164 if (pt_var
00165 && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
00166 && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
00167 && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
00168 && (unsigned HOST_WIDE_INT)
00169 tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1) < offset_limit)
00170 {
00171 tree bytes;
00172
00173 if (pt_var != TREE_OPERAND (ptr, 0))
00174 {
00175 tree var;
00176
00177 if (object_size_type & 1)
00178 {
00179 var = TREE_OPERAND (ptr, 0);
00180
00181 while (var != pt_var
00182 && TREE_CODE (var) != BIT_FIELD_REF
00183 && TREE_CODE (var) != COMPONENT_REF
00184 && TREE_CODE (var) != ARRAY_REF
00185 && TREE_CODE (var) != ARRAY_RANGE_REF
00186 && TREE_CODE (var) != REALPART_EXPR
00187 && TREE_CODE (var) != IMAGPART_EXPR)
00188 var = TREE_OPERAND (var, 0);
00189 if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
00190 var = TREE_OPERAND (var, 0);
00191 if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
00192 || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
00193 || tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)),
00194 TYPE_SIZE_UNIT (TREE_TYPE (var))))
00195 var = pt_var;
00196 }
00197 else
00198 var = pt_var;
00199
00200 bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
00201 if (bytes != error_mark_node)
00202 {
00203 if (TREE_CODE (bytes) == INTEGER_CST
00204 && tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes))
00205 bytes = size_zero_node;
00206 else
00207 bytes = size_binop (MINUS_EXPR,
00208 TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes);
00209 }
00210 }
00211 else
00212 bytes = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
00213
00214 if (host_integerp (bytes, 1))
00215 return tree_low_cst (bytes, 1);
00216 }
00217
00218 return unknown[object_size_type];
00219 }
00220
00221
00222
00223
00224
00225
00226
00227 static unsigned HOST_WIDE_INT
00228 alloc_object_size (tree call, int object_size_type)
00229 {
00230 tree callee, arglist, a, bytes = NULL_TREE;
00231 unsigned int arg_mask = 0;
00232
00233 gcc_assert (TREE_CODE (call) == CALL_EXPR);
00234
00235 callee = get_callee_fndecl (call);
00236 arglist = TREE_OPERAND (call, 1);
00237 if (callee
00238 && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
00239 switch (DECL_FUNCTION_CODE (callee))
00240 {
00241 case BUILT_IN_MALLOC:
00242 case BUILT_IN_ALLOCA:
00243 arg_mask = 1;
00244 break;
00245
00246
00247
00248
00249
00250 case BUILT_IN_CALLOC:
00251 arg_mask = 3;
00252 break;
00253 default:
00254 break;
00255 }
00256
00257 for (a = arglist; arg_mask && a; arg_mask >>= 1, a = TREE_CHAIN (a))
00258 if (arg_mask & 1)
00259 {
00260 tree arg = TREE_VALUE (a);
00261
00262 if (TREE_CODE (arg) != INTEGER_CST)
00263 break;
00264
00265 if (! bytes)
00266 bytes = fold_convert (sizetype, arg);
00267 else
00268 bytes = size_binop (MULT_EXPR, bytes,
00269 fold_convert (sizetype, arg));
00270 }
00271
00272 if (! arg_mask && bytes && host_integerp (bytes, 1))
00273 return tree_low_cst (bytes, 1);
00274
00275 return unknown[object_size_type];
00276 }
00277
00278
00279
00280
00281
00282
00283 static tree
00284 pass_through_call (tree call)
00285 {
00286 tree callee = get_callee_fndecl (call);
00287 tree arglist = TREE_OPERAND (call, 1);
00288
00289 if (callee
00290 && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
00291 switch (DECL_FUNCTION_CODE (callee))
00292 {
00293 case BUILT_IN_MEMCPY:
00294 case BUILT_IN_MEMMOVE:
00295 case BUILT_IN_MEMSET:
00296 case BUILT_IN_STRCPY:
00297 case BUILT_IN_STRNCPY:
00298 case BUILT_IN_STRCAT:
00299 case BUILT_IN_STRNCAT:
00300 case BUILT_IN_MEMCPY_CHK:
00301 case BUILT_IN_MEMMOVE_CHK:
00302 case BUILT_IN_MEMSET_CHK:
00303 case BUILT_IN_STRCPY_CHK:
00304 case BUILT_IN_STRNCPY_CHK:
00305 case BUILT_IN_STRCAT_CHK:
00306 case BUILT_IN_STRNCAT_CHK:
00307 if (arglist)
00308 return TREE_VALUE (arglist);
00309 break;
00310 default:
00311 break;
00312 }
00313
00314 return NULL_TREE;
00315 }
00316
00317
00318
00319
00320
00321 unsigned HOST_WIDE_INT
00322 compute_builtin_object_size (tree ptr, int object_size_type)
00323 {
00324 gcc_assert (object_size_type >= 0 && object_size_type <= 3);
00325
00326 if (! offset_limit)
00327 init_offset_limit ();
00328
00329 if (TREE_CODE (ptr) == ADDR_EXPR)
00330 return addr_object_size (ptr, object_size_type);
00331 else if (TREE_CODE (ptr) == CALL_EXPR)
00332 {
00333 tree arg = pass_through_call (ptr);
00334
00335 if (arg)
00336 return compute_builtin_object_size (arg, object_size_type);
00337 else
00338 return alloc_object_size (ptr, object_size_type);
00339 }
00340 else if (TREE_CODE (ptr) == SSA_NAME
00341 && POINTER_TYPE_P (TREE_TYPE (ptr))
00342 && object_sizes[object_size_type] != NULL)
00343 {
00344 if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
00345 {
00346 struct object_size_info osi;
00347 bitmap_iterator bi;
00348 unsigned int i;
00349
00350 if (dump_file)
00351 {
00352 fprintf (dump_file, "Computing %s %sobject size for ",
00353 (object_size_type & 2) ? "minimum" : "maximum",
00354 (object_size_type & 1) ? "sub" : "");
00355 print_generic_expr (dump_file, ptr, dump_flags);
00356 fprintf (dump_file, ":\n");
00357 }
00358
00359 osi.visited = BITMAP_ALLOC (NULL);
00360 osi.reexamine = BITMAP_ALLOC (NULL);
00361 osi.object_size_type = object_size_type;
00362 osi.depths = NULL;
00363 osi.stack = NULL;
00364 osi.tos = NULL;
00365
00366
00367
00368
00369
00370 osi.pass = 0;
00371 osi.changed = false;
00372 collect_object_sizes_for (&osi, ptr);
00373
00374
00375
00376
00377 if (! bitmap_empty_p (osi.reexamine))
00378 {
00379 bitmap reexamine = BITMAP_ALLOC (NULL);
00380
00381
00382
00383
00384
00385
00386
00387 if (object_size_type & 2)
00388 {
00389 osi.depths = XCNEWVEC (unsigned int, num_ssa_names);
00390 osi.stack = XNEWVEC (unsigned int, num_ssa_names);
00391 osi.tos = osi.stack;
00392 osi.pass = 1;
00393
00394
00395 bitmap_copy (reexamine, osi.reexamine);
00396 EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
00397 if (bitmap_bit_p (osi.reexamine, i))
00398 check_for_plus_in_loops (&osi, ssa_name (i));
00399
00400 free (osi.depths);
00401 osi.depths = NULL;
00402 free (osi.stack);
00403 osi.stack = NULL;
00404 osi.tos = NULL;
00405 }
00406
00407 do
00408 {
00409 osi.pass = 2;
00410 osi.changed = false;
00411
00412
00413 bitmap_copy (reexamine, osi.reexamine);
00414 EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
00415 if (bitmap_bit_p (osi.reexamine, i))
00416 {
00417 collect_object_sizes_for (&osi, ssa_name (i));
00418 if (dump_file && (dump_flags & TDF_DETAILS))
00419 {
00420 fprintf (dump_file, "Reexamining ");
00421 print_generic_expr (dump_file, ssa_name (i),
00422 dump_flags);
00423 fprintf (dump_file, "\n");
00424 }
00425 }
00426 }
00427 while (osi.changed);
00428
00429 BITMAP_FREE (reexamine);
00430 }
00431 EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi)
00432 bitmap_set_bit (computed[object_size_type], i);
00433
00434
00435 if (dump_file)
00436 {
00437 EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi)
00438 if (object_sizes[object_size_type][i]
00439 != unknown[object_size_type])
00440 {
00441 print_generic_expr (dump_file, ssa_name (i),
00442 dump_flags);
00443 fprintf (dump_file,
00444 ": %s %sobject size "
00445 HOST_WIDE_INT_PRINT_UNSIGNED "\n",
00446 (object_size_type & 2) ? "minimum" : "maximum",
00447 (object_size_type & 1) ? "sub" : "",
00448 object_sizes[object_size_type][i]);
00449 }
00450 }
00451
00452 BITMAP_FREE (osi.reexamine);
00453 BITMAP_FREE (osi.visited);
00454 }
00455
00456 return object_sizes[object_size_type][SSA_NAME_VERSION (ptr)];
00457 }
00458
00459 return unknown[object_size_type];
00460 }
00461
00462
00463
00464
00465
00466 static void
00467 expr_object_size (struct object_size_info *osi, tree ptr, tree value)
00468 {
00469 int object_size_type = osi->object_size_type;
00470 unsigned int varno = SSA_NAME_VERSION (ptr);
00471 unsigned HOST_WIDE_INT bytes;
00472
00473 gcc_assert (object_sizes[object_size_type][varno]
00474 != unknown[object_size_type]);
00475 gcc_assert (osi->pass == 0);
00476
00477 if (TREE_CODE (value) == WITH_SIZE_EXPR)
00478 value = TREE_OPERAND (value, 0);
00479
00480
00481 gcc_assert (TREE_CODE (value) != SSA_NAME
00482 || !POINTER_TYPE_P (TREE_TYPE (value)));
00483
00484 if (TREE_CODE (value) == ADDR_EXPR)
00485 bytes = addr_object_size (value, object_size_type);
00486 else if (TREE_CODE (value) == CALL_EXPR)
00487 bytes = alloc_object_size (value, object_size_type);
00488 else
00489 bytes = unknown[object_size_type];
00490
00491 if ((object_size_type & 2) == 0)
00492 {
00493 if (object_sizes[object_size_type][varno] < bytes)
00494 object_sizes[object_size_type][varno] = bytes;
00495 }
00496 else
00497 {
00498 if (object_sizes[object_size_type][varno] > bytes)
00499 object_sizes[object_size_type][varno] = bytes;
00500 }
00501 }
00502
00503
00504
00505
00506
00507 static bool
00508 merge_object_sizes (struct object_size_info *osi, tree dest, tree orig,
00509 unsigned HOST_WIDE_INT offset)
00510 {
00511 int object_size_type = osi->object_size_type;
00512 unsigned int varno = SSA_NAME_VERSION (dest);
00513 unsigned HOST_WIDE_INT orig_bytes;
00514
00515 if (object_sizes[object_size_type][varno] == unknown[object_size_type])
00516 return false;
00517 if (offset >= offset_limit)
00518 {
00519 object_sizes[object_size_type][varno] = unknown[object_size_type];
00520 return false;
00521 }
00522
00523 if (osi->pass == 0)
00524 collect_object_sizes_for (osi, orig);
00525
00526 orig_bytes = object_sizes[object_size_type][SSA_NAME_VERSION (orig)];
00527 if (orig_bytes != unknown[object_size_type])
00528 orig_bytes = (offset > orig_bytes)
00529 ? (unsigned HOST_WIDE_INT) 0 : orig_bytes - offset;
00530
00531 if ((object_size_type & 2) == 0)
00532 {
00533 if (object_sizes[object_size_type][varno] < orig_bytes)
00534 {
00535 object_sizes[object_size_type][varno] = orig_bytes;
00536 osi->changed = true;
00537 }
00538 }
00539 else
00540 {
00541 if (object_sizes[object_size_type][varno] > orig_bytes)
00542 {
00543 object_sizes[object_size_type][varno] = orig_bytes;
00544 osi->changed = true;
00545 }
00546 }
00547 return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig));
00548 }
00549
00550
00551
00552
00553
00554
00555 static bool
00556 plus_expr_object_size (struct object_size_info *osi, tree var, tree value)
00557 {
00558 tree op0 = TREE_OPERAND (value, 0);
00559 tree op1 = TREE_OPERAND (value, 1);
00560 bool ptr1_p = POINTER_TYPE_P (TREE_TYPE (op0))
00561 && TREE_CODE (op0) != INTEGER_CST;
00562 bool ptr2_p = POINTER_TYPE_P (TREE_TYPE (op1))
00563 && TREE_CODE (op1) != INTEGER_CST;
00564 int object_size_type = osi->object_size_type;
00565 unsigned int varno = SSA_NAME_VERSION (var);
00566 unsigned HOST_WIDE_INT bytes;
00567
00568 gcc_assert (TREE_CODE (value) == PLUS_EXPR);
00569
00570 if (object_sizes[object_size_type][varno] == unknown[object_size_type])
00571 return false;
00572
00573
00574 if (ptr2_p && !ptr1_p)
00575 {
00576 tree tem = op0;
00577 op0 = op1;
00578 op1 = tem;
00579 ptr1_p = true;
00580 ptr2_p = false;
00581 }
00582
00583
00584 if (ptr1_p
00585 && !ptr2_p
00586 && TREE_CODE (op1) == INTEGER_CST
00587 && (TREE_CODE (op0) == SSA_NAME
00588 || TREE_CODE (op0) == ADDR_EXPR))
00589 {
00590 if (! host_integerp (op1, 1))
00591 bytes = unknown[object_size_type];
00592 else if (TREE_CODE (op0) == SSA_NAME)
00593 return merge_object_sizes (osi, var, op0, tree_low_cst (op1, 1));
00594 else
00595 {
00596 unsigned HOST_WIDE_INT off = tree_low_cst (op1, 1);
00597
00598 bytes = compute_builtin_object_size (op0, object_size_type);
00599 if (off > offset_limit)
00600 bytes = unknown[object_size_type];
00601 else if (off > bytes)
00602 bytes = 0;
00603 else
00604 bytes -= off;
00605 }
00606 }
00607 else
00608 bytes = unknown[object_size_type];
00609
00610 if ((object_size_type & 2) == 0)
00611 {
00612 if (object_sizes[object_size_type][varno] < bytes)
00613 object_sizes[object_size_type][varno] = bytes;
00614 }
00615 else
00616 {
00617 if (object_sizes[object_size_type][varno] > bytes)
00618 object_sizes[object_size_type][varno] = bytes;
00619 }
00620 return false;
00621 }
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644 static void
00645 collect_object_sizes_for (struct object_size_info *osi, tree var)
00646 {
00647 int object_size_type = osi->object_size_type;
00648 unsigned int varno = SSA_NAME_VERSION (var);
00649 tree stmt;
00650 bool reexamine;
00651
00652 if (bitmap_bit_p (computed[object_size_type], varno))
00653 return;
00654
00655 if (osi->pass == 0)
00656 {
00657 if (! bitmap_bit_p (osi->visited, varno))
00658 {
00659 bitmap_set_bit (osi->visited, varno);
00660 object_sizes[object_size_type][varno]
00661 = (object_size_type & 2) ? -1 : 0;
00662 }
00663 else
00664 {
00665
00666
00667 bitmap_set_bit (osi->reexamine, varno);
00668 if (dump_file && (dump_flags & TDF_DETAILS))
00669 {
00670 fprintf (dump_file, "Found a dependency loop at ");
00671 print_generic_expr (dump_file, var, dump_flags);
00672 fprintf (dump_file, "\n");
00673 }
00674 return;
00675 }
00676 }
00677
00678 if (dump_file && (dump_flags & TDF_DETAILS))
00679 {
00680 fprintf (dump_file, "Visiting use-def links for ");
00681 print_generic_expr (dump_file, var, dump_flags);
00682 fprintf (dump_file, "\n");
00683 }
00684
00685 stmt = SSA_NAME_DEF_STMT (var);
00686 reexamine = false;
00687
00688 switch (TREE_CODE (stmt))
00689 {
00690 case RETURN_EXPR:
00691 gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
00692 stmt = TREE_OPERAND (stmt, 0);
00693
00694
00695 case MODIFY_EXPR:
00696 {
00697 tree rhs = TREE_OPERAND (stmt, 1), arg;
00698 STRIP_NOPS (rhs);
00699
00700 if (TREE_CODE (rhs) == CALL_EXPR)
00701 {
00702 arg = pass_through_call (rhs);
00703 if (arg)
00704 rhs = arg;
00705 }
00706
00707 if (TREE_CODE (rhs) == SSA_NAME
00708 && POINTER_TYPE_P (TREE_TYPE (rhs)))
00709 reexamine = merge_object_sizes (osi, var, rhs, 0);
00710
00711 else if (TREE_CODE (rhs) == PLUS_EXPR)
00712 reexamine = plus_expr_object_size (osi, var, rhs);
00713
00714 else
00715 expr_object_size (osi, var, rhs);
00716 break;
00717 }
00718
00719 case ASM_EXPR:
00720
00721 object_sizes[object_size_type][varno] = unknown[object_size_type];
00722 break;
00723
00724 case NOP_EXPR:
00725 {
00726 tree decl = SSA_NAME_VAR (var);
00727
00728 gcc_assert (IS_EMPTY_STMT (stmt));
00729
00730 if (TREE_CODE (decl) != PARM_DECL && DECL_INITIAL (decl))
00731 expr_object_size (osi, var, DECL_INITIAL (decl));
00732 else
00733 expr_object_size (osi, var, decl);
00734 }
00735 break;
00736
00737 case PHI_NODE:
00738 {
00739 int i;
00740
00741 for (i = 0; i < PHI_NUM_ARGS (stmt); i++)
00742 {
00743 tree rhs = PHI_ARG_DEF (stmt, i);
00744
00745 if (object_sizes[object_size_type][varno]
00746 == unknown[object_size_type])
00747 break;
00748
00749 if (TREE_CODE (rhs) == SSA_NAME)
00750 reexamine |= merge_object_sizes (osi, var, rhs, 0);
00751 else if (osi->pass == 0)
00752 expr_object_size (osi, var, rhs);
00753 }
00754 break;
00755 }
00756 default:
00757 gcc_unreachable ();
00758 }
00759
00760 if (! reexamine
00761 || object_sizes[object_size_type][varno] == unknown[object_size_type])
00762 {
00763 bitmap_set_bit (computed[object_size_type], varno);
00764 bitmap_clear_bit (osi->reexamine, varno);
00765 }
00766 else
00767 {
00768 bitmap_set_bit (osi->reexamine, varno);
00769 if (dump_file && (dump_flags & TDF_DETAILS))
00770 {
00771 fprintf (dump_file, "Need to reexamine ");
00772 print_generic_expr (dump_file, var, dump_flags);
00773 fprintf (dump_file, "\n");
00774 }
00775 }
00776 }
00777
00778
00779
00780
00781
00782 static void
00783 check_for_plus_in_loops_1 (struct object_size_info *osi, tree var,
00784 unsigned int depth)
00785 {
00786 tree stmt = SSA_NAME_DEF_STMT (var);
00787 unsigned int varno = SSA_NAME_VERSION (var);
00788
00789 if (osi->depths[varno])
00790 {
00791 if (osi->depths[varno] != depth)
00792 {
00793 unsigned int *sp;
00794
00795
00796 for (sp = osi->tos; sp > osi->stack; )
00797 {
00798 --sp;
00799 bitmap_clear_bit (osi->reexamine, *sp);
00800 bitmap_set_bit (computed[osi->object_size_type], *sp);
00801 object_sizes[osi->object_size_type][*sp] = 0;
00802 if (*sp == varno)
00803 break;
00804 }
00805 }
00806 return;
00807 }
00808 else if (! bitmap_bit_p (osi->reexamine, varno))
00809 return;
00810
00811 osi->depths[varno] = depth;
00812 *osi->tos++ = varno;
00813
00814 switch (TREE_CODE (stmt))
00815 {
00816 case RETURN_EXPR:
00817 gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
00818 stmt = TREE_OPERAND (stmt, 0);
00819
00820
00821 case MODIFY_EXPR:
00822 {
00823 tree rhs = TREE_OPERAND (stmt, 1), arg;
00824 STRIP_NOPS (rhs);
00825
00826 if (TREE_CODE (rhs) == CALL_EXPR)
00827 {
00828 arg = pass_through_call (rhs);
00829 if (arg)
00830 rhs = arg;
00831 }
00832
00833 if (TREE_CODE (rhs) == SSA_NAME)
00834 check_for_plus_in_loops_1 (osi, rhs, depth);
00835 else if (TREE_CODE (rhs) == PLUS_EXPR)
00836 {
00837 tree op0 = TREE_OPERAND (rhs, 0);
00838 tree op1 = TREE_OPERAND (rhs, 1);
00839 tree cst, basevar;
00840
00841 if (TREE_CODE (op0) == SSA_NAME)
00842 {
00843 basevar = op0;
00844 cst = op1;
00845 }
00846 else
00847 {
00848 basevar = op1;
00849 cst = op0;
00850 gcc_assert (TREE_CODE (basevar) == SSA_NAME);
00851 }
00852 gcc_assert (TREE_CODE (cst) == INTEGER_CST);
00853
00854 check_for_plus_in_loops_1 (osi, basevar,
00855 depth + !integer_zerop (cst));
00856 }
00857 else
00858 gcc_unreachable ();
00859 break;
00860 }
00861 case PHI_NODE:
00862 {
00863 int i;
00864
00865 for (i = 0; i < PHI_NUM_ARGS (stmt); i++)
00866 {
00867 tree rhs = PHI_ARG_DEF (stmt, i);
00868
00869 if (TREE_CODE (rhs) == SSA_NAME)
00870 check_for_plus_in_loops_1 (osi, rhs, depth);
00871 }
00872 break;
00873 }
00874 default:
00875 gcc_unreachable ();
00876 }
00877
00878 osi->depths[varno] = 0;
00879 osi->tos--;
00880 }
00881
00882
00883
00884
00885
00886
00887 static void
00888 check_for_plus_in_loops (struct object_size_info *osi, tree var)
00889 {
00890 tree stmt = SSA_NAME_DEF_STMT (var);
00891
00892 switch (TREE_CODE (stmt))
00893 {
00894 case RETURN_EXPR:
00895 gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
00896 stmt = TREE_OPERAND (stmt, 0);
00897
00898
00899 case MODIFY_EXPR:
00900 {
00901 tree rhs = TREE_OPERAND (stmt, 1), arg;
00902 STRIP_NOPS (rhs);
00903
00904 if (TREE_CODE (rhs) == CALL_EXPR)
00905 {
00906 arg = pass_through_call (rhs);
00907 if (arg)
00908 rhs = arg;
00909 }
00910
00911 if (TREE_CODE (rhs) == PLUS_EXPR)
00912 {
00913 tree op0 = TREE_OPERAND (rhs, 0);
00914 tree op1 = TREE_OPERAND (rhs, 1);
00915 tree cst, basevar;
00916
00917 if (TREE_CODE (op0) == SSA_NAME)
00918 {
00919 basevar = op0;
00920 cst = op1;
00921 }
00922 else
00923 {
00924 basevar = op1;
00925 cst = op0;
00926 gcc_assert (TREE_CODE (basevar) == SSA_NAME);
00927 }
00928 gcc_assert (TREE_CODE (cst) == INTEGER_CST);
00929
00930 if (integer_zerop (cst))
00931 break;
00932
00933 osi->depths[SSA_NAME_VERSION (basevar)] = 1;
00934 *osi->tos++ = SSA_NAME_VERSION (basevar);
00935 check_for_plus_in_loops_1 (osi, var, 2);
00936 osi->depths[SSA_NAME_VERSION (basevar)] = 0;
00937 osi->tos--;
00938 }
00939 break;
00940 }
00941 default:
00942 break;
00943 }
00944 }
00945
00946
00947
00948
00949 void
00950 init_object_sizes (void)
00951 {
00952 int object_size_type;
00953
00954 if (object_sizes[0])
00955 return;
00956
00957 for (object_size_type = 0; object_size_type <= 3; object_size_type++)
00958 {
00959 object_sizes[object_size_type] = XNEWVEC (unsigned HOST_WIDE_INT, num_ssa_names);
00960 computed[object_size_type] = BITMAP_ALLOC (NULL);
00961 }
00962
00963 init_offset_limit ();
00964 }
00965
00966
00967
00968
00969 void
00970 fini_object_sizes (void)
00971 {
00972 int object_size_type;
00973
00974 for (object_size_type = 0; object_size_type <= 3; object_size_type++)
00975 {
00976 free (object_sizes[object_size_type]);
00977 BITMAP_FREE (computed[object_size_type]);
00978 object_sizes[object_size_type] = NULL;
00979 }
00980 }
00981
00982
00983
00984
00985 static unsigned int
00986 compute_object_sizes (void)
00987 {
00988 basic_block bb;
00989 FOR_EACH_BB (bb)
00990 {
00991 block_stmt_iterator i;
00992 for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
00993 {
00994 tree *stmtp = bsi_stmt_ptr (i);
00995 tree call = get_rhs (*stmtp);
00996 tree callee, result;
00997
00998 if (!call || TREE_CODE (call) != CALL_EXPR)
00999 continue;
01000
01001 callee = get_callee_fndecl (call);
01002 if (!callee
01003 || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
01004 || DECL_FUNCTION_CODE (callee) != BUILT_IN_OBJECT_SIZE)
01005 continue;
01006
01007 init_object_sizes ();
01008 result = fold_builtin (callee, TREE_OPERAND (call, 1), false);
01009 if (!result)
01010 {
01011 tree arglist = TREE_OPERAND (call, 1);
01012
01013 if (arglist != NULL
01014 && POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
01015 && TREE_CHAIN (arglist) != NULL
01016 && TREE_CHAIN (TREE_CHAIN (arglist)) == NULL)
01017 {
01018 tree ost = TREE_VALUE (TREE_CHAIN (arglist));
01019
01020 if (host_integerp (ost, 1))
01021 {
01022 unsigned HOST_WIDE_INT object_size_type
01023 = tree_low_cst (ost, 1);
01024
01025 if (object_size_type < 2)
01026 result = fold_convert (size_type_node,
01027 integer_minus_one_node);
01028 else if (object_size_type < 4)
01029 result = size_zero_node;
01030 }
01031 }
01032
01033 if (!result)
01034 continue;
01035 }
01036
01037 if (dump_file && (dump_flags & TDF_DETAILS))
01038 {
01039 fprintf (dump_file, "Simplified\n ");
01040 print_generic_stmt (dump_file, *stmtp, dump_flags);
01041 }
01042
01043 if (!set_rhs (stmtp, result))
01044 gcc_unreachable ();
01045 update_stmt (*stmtp);
01046
01047 if (dump_file && (dump_flags & TDF_DETAILS))
01048 {
01049 fprintf (dump_file, "to\n ");
01050 print_generic_stmt (dump_file, *stmtp, dump_flags);
01051 fprintf (dump_file, "\n");
01052 }
01053 }
01054 }
01055
01056 fini_object_sizes ();
01057 return 0;
01058 }
01059
01060 struct tree_opt_pass pass_object_sizes =
01061 {
01062 "objsz",
01063 NULL,
01064 compute_object_sizes,
01065 NULL,
01066 NULL,
01067 0,
01068 0,
01069 PROP_cfg | PROP_ssa | PROP_alias,
01070 0,
01071 0,
01072 0,
01073 TODO_dump_func | TODO_verify_ssa,
01074 0
01075 };