00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00026
00027 #define __STDC_LIMIT_MACROS
00028 #include <stdint.h>
00029 #include <math.h>
00030
00031 #include "defs.h"
00032 #include "wn.h"
00033 #include "wn_util.h"
00034 #include "symtab.h"
00035 #include "config_ipa.h"
00036
00037 #include "ipa_cg.h"
00038 #include "ipo_parent.h"
00039 #include "ipa_struct_opt.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 mUINT32 candidate_ty_idx = 0;
00065 mUINT32 candidate_fld_id = 0;
00066 mUINT32 Struct_split_candidate_index = 0;
00067 mUINT32 Struct_update_index = 0;
00068
00069 static WN_MAP PU_Parent_Map = 0;
00070 static WN_MAP_TAB * PU_Map_Tab = NULL;
00071
00072
00073
00074
00075
00076
00077
00078 ST * fld_st[10];
00079 TY_IDX Struct_split_types[20];
00080
00081 WN_OFFSET preg_id = 0;
00082
00083 struct FLD_MAP
00084 {
00085 mUINT32 old_field_id;
00086 mUINT32 new_field_id;
00087 WN_OFFSET old_ofst;
00088 WN_OFFSET new_ofst;
00089 };
00090
00091 static FLD_MAP * field_map_info;
00092
00093
00094
00095 WN * size_wn (WN * expr)
00096 {
00097 WN * wn = NULL;
00098 if (WN_operator(expr) == OPR_INTCONST)
00099 wn = expr;
00100 else if (WN_operator(expr) == OPR_MPY)
00101 wn = WN_kid1(expr);
00102 else Fail_FmtAssertion ("Unrecognized expression");
00103
00104 FmtAssert (WN_operator(wn) == OPR_INTCONST, ("Constant size expected"));
00105 FmtAssert (WN_const_val(wn) >= TY_size(Ty_tab[candidate_ty_idx]),
00106 ("allocation constant cannot be less than type size"));
00107 return wn;
00108 }
00109
00110
00111
00112 WN * size_expr (WN * call)
00113 {
00114 FmtAssert (WN_operator(call) == OPR_CALL, ("Call stmt expected"));
00115 FmtAssert (!strcmp(ST_name(WN_st(call)), "malloc") ||
00116 !strcmp(ST_name(WN_st(call)), "realloc") ||
00117 !strcmp(ST_name(WN_st(call)), "calloc"),
00118 ("Unexpected function call"));
00119
00120 if (!strcmp(ST_name(WN_st(call)), "malloc"))
00121 return size_wn(WN_kid0(WN_kid0(call)));
00122 else
00123 return size_wn(WN_kid0(WN_kid1(call)));
00124 }
00125
00126
00127 void fixup_realloc_pointer (WN * call)
00128 {
00129 Is_True (WN_operator(call) == OPR_CALL, ("Expected call stmt"));
00130 WN * ptr = WN_kid0(WN_kid0(call));
00131
00132 if (WN_operator(ptr) == OPR_ILOAD && WN_operator(WN_kid0(ptr)) == OPR_LDID &&
00133 TY_IDX_index(WN_ty(ptr)) == Struct_update_index)
00134 {
00135 UINT field_id = WN_field_id(ptr);
00136 FmtAssert (field_id == candidate_fld_id, ("Unexpected field id in iload"));
00137 UINT cur_field_id = 0;
00138 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8, ++field_id, cur_field_id);
00139 FmtAssert (!fld.Is_Null(), ("Field not found"));
00140 WN_set_field_id(ptr, field_id);
00141 WN_offset(ptr) = FLD_ofst(fld);
00142 }
00143 }
00144
00145
00146 void handle_function_return (WN * block, WN * wn)
00147 {
00148 FmtAssert (WN_operator(wn) == OPR_STID, ("Stid expected"));
00149
00150
00151 WN * call = WN_prev(wn);
00152 FmtAssert (call && WN_operator(call) == OPR_CALL, ("Call stmt expected"));
00153
00154
00155 WN * new_call = WN_COPY_Tree (call);
00156
00157 WN * size = size_expr(call);
00158
00159 INT num_elements = WN_const_val(size) / TY_size(Ty_tab[candidate_ty_idx]);
00160
00161 TY_IDX type = TY_IDX_ZERO;
00162 TY_IDX ptr_ty[10];
00163 for (INT i=0; i<Struct_split_count; i++)
00164 {
00165 type = Struct_split_types[i];
00166 ptr_ty[i] = Make_Pointer_Type(type);
00167 fld_st[i] = Gen_Temp_Symbol (ptr_ty[i], "fld");
00168 }
00169
00170
00171 WN_const_val(size) = num_elements * TY_size(Struct_split_types[0]);
00172
00173 {
00174
00175 ST * sym = WN_st(wn);
00176 FmtAssert (ST_class(sym) == CLASS_PREG,
00177 ("handle_function_return: Expected return store into preg"));
00178 preg_id = WN_offset(wn);
00179 }
00180 WN_st_idx(wn) = ST_st_idx(fld_st[0]);
00181 WN_offset(wn) = 0;
00182 WN_set_ty(wn, ptr_ty[0]);
00183 WN_set_ty(WN_kid0(wn), ptr_ty[0]);
00184
00185
00186 if (!strcmp(ST_name(WN_st(new_call)), "realloc"))
00187 {
00188
00189 fixup_realloc_pointer(new_call);
00190 }
00191
00192 WN * last_alloc = new_call;
00193 for (INT i=1; i<Struct_split_count; i++)
00194 {
00195 if (i < Struct_split_count-1)
00196 new_call = WN_COPY_Tree (new_call);
00197 size = size_expr(last_alloc);
00198 WN_const_val(size) = num_elements * TY_size(Struct_split_types[i]);
00199 WN * val = WN_Ldid(WN_desc(WN_kid0(wn)), -1, Return_Val_Preg, ptr_ty[i]);
00200 WN * stid = WN_Stid(WN_rtype(val), 0, fld_st[i], ST_type(fld_st[i]), val);
00201 WN_INSERT_BlockLast(block, last_alloc);
00202 WN_INSERT_BlockLast(block, stid);
00203 last_alloc = new_call;
00204 }
00205 }
00206
00207
00208 void handle_assignment (WN * block, WN * wn)
00209 {
00210 FmtAssert (WN_operator(wn) == OPR_STID, ("Expected assignment stmt"));
00211
00212 if (IPA_Enable_Struct_Opt == 2 &&
00213 TY_kind(WN_ty(wn)) == KIND_POINTER &&
00214 TY_IDX_index(TY_pointed(WN_ty(wn))) == candidate_ty_idx)
00215 {
00216
00217 WN * kid = WN_kid0(wn);
00218
00219 Is_True (WN_operator(kid) == OPR_LDID &&
00220 ST_class(WN_st(kid)) == CLASS_PREG, ("NYI"));
00221
00222 TY_IDX ptr_ty0 = Make_Pointer_Type(Struct_field_layout[0].u.new_ty);
00223 WN_set_ty(kid, ptr_ty0);
00224 WN_st_idx(kid) = ST_st_idx(fld_st[0]);
00225 WN_offset(kid) = 0;
00226 WN_set_ty(wn, ptr_ty0);
00227 WN_st_idx(wn) = Struct_field_layout[0].st_idx;
00228
00229
00230 for (INT i=1; i<Struct_split_count; i++)
00231 {
00232 TY_IDX ptr_ty = Make_Pointer_Type(Struct_field_layout[i].u.new_ty);
00233 WN * stid = WN_Stid(WN_desc(wn),
00234 0,
00235 &St_Table[Struct_field_layout[i].st_idx],
00236 ptr_ty,
00237 WN_Ldid(WN_desc(wn), 0, fld_st[i], ptr_ty));
00238 WN_INSERT_BlockLast(block, stid);
00239 }
00240 }
00241 else if (TY_IDX_index(WN_ty(wn)) == Struct_update_index)
00242 {
00243 UINT32 field_id = WN_field_id(wn);
00244 FmtAssert (field_id != 0, ("Field-id should be non-zero"));
00245 UINT32 new_field_id = field_map_info[field_id-1].new_field_id;
00246
00247 FmtAssert (new_field_id == candidate_fld_id, ("Unexpected field-id found"));
00248
00249 UINT cur_field_id = 0;
00250 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00251 new_field_id, cur_field_id);
00252 FmtAssert (!fld.Is_Null(), ("Field not found"));
00253
00254 WN_set_field_id(wn, new_field_id);
00255 WN_offset(wn) = FLD_ofst(fld);
00256 WN_Delete(WN_kid0(wn));
00257 WN_kid0(wn) = WN_Ldid(WN_desc(wn), 0, fld_st[0], Make_Pointer_Type(FLD_type(fld)));
00258
00259
00260 cur_field_id = 0;
00261 fld = FLD_get_to_field (Struct_update_index<<8, ++new_field_id, cur_field_id);
00262 FmtAssert (!fld.Is_Null(), ("Field not found"));
00263
00264
00265 WN * val = WN_Ldid(WN_desc(WN_kid0(wn)), 0, fld_st[1], Make_Pointer_Type(FLD_type(fld)));
00266 WN * stid = WN_Stid(WN_rtype(val), FLD_ofst(fld), WN_st(wn), WN_ty(wn), val, new_field_id);
00267 WN_INSERT_BlockLast(block, stid);
00268 }
00269 }
00270
00271
00272 WN * handle_function_call (WN * parent, WN * wn)
00273 {
00274 FmtAssert (WN_operator(wn) == OPR_CALL, ("Call stmt expected"));
00275
00276 WN * call = wn;
00277
00278 if (!strcmp(ST_name(WN_st(call)), "free"))
00279 {
00280
00281 WN * ptr = WN_kid0(WN_kid0(call));
00282
00283
00284 WN_st_idx(ptr) = ST_st_idx(fld_st[0]);
00285 WN_offset(ptr) = 0;
00286 WN_set_ty(ptr, Make_Pointer_Type(Struct_split_types[0]));
00287
00288
00289 for (INT i=1; i<Struct_split_count; i++)
00290 {
00291 WN * new_call = WN_COPY_Tree (call);
00292 WN_st_idx(WN_kid0(WN_kid0(new_call))) = ST_st_idx(fld_st[i]);
00293 WN_set_ty(WN_kid0(WN_kid0(new_call)),
00294 Make_Pointer_Type(Struct_split_types[i]));
00295
00296 WN_INSERT_BlockAfter(parent, wn, new_call);
00297 call = new_call;
00298 }
00299 return call;
00300 }
00301 else Fail_FmtAssertion ("NYI");
00302
00303 return NULL;
00304 }
00305
00306
00307
00308 void duplicate_call (WN * block, WN * call)
00309 {
00310 FmtAssert (WN_operator(call) == OPR_CALL, ("Call stmt expected"));
00311
00312 if (!strcmp(ST_name(WN_st(call)), "realloc"))
00313 return;
00314
00315 FmtAssert (!strcmp(ST_name(WN_st(call)), "free") && WN_kid_count(call) == 1,
00316 ("Unexpected function call"));
00317
00318 WN * new_call = WN_COPY_Tree (call);
00319 WN * addr = WN_kid0(WN_kid0(new_call));
00320
00321 UINT32 new_field_id = WN_field_id(addr);
00322
00323 UINT cur_field_id = 0;
00324 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00325 ++new_field_id, cur_field_id);
00326 FmtAssert (!fld.Is_Null(), ("Field not found"));
00327 WN_set_field_id(addr, new_field_id);
00328 WN_offset(addr) = FLD_ofst(fld);
00329
00330 WN_INSERT_BlockLast (block, new_call);
00331 }
00332
00333
00334 void handle_istore_assignment (WN * block, WN * stmt)
00335 {
00336 FmtAssert (WN_operator(stmt) == OPR_ISTORE,
00337 ("handle_istore_assignment: expected ISTORE"));
00338 if (TY_IDX_index(TY_pointed(WN_ty(stmt))) == Struct_update_index)
00339 {
00340
00341 UINT field_id = WN_field_id(stmt);
00342 FmtAssert (field_id == candidate_fld_id,
00343 ("handle_istore_assignment: unexpected field id"));
00344 WN * new_istore = WN_COPY_Tree(stmt);
00345 UINT cur_field_id = 0;
00346 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00347 field_id, cur_field_id);
00348 FmtAssert (!fld.Is_Null(), ("Field not found"));
00349 FmtAssert (FLD_ofst(fld) == WN_offset(stmt),
00350 ("handle_istore_assignment: Unexpected offset in ISTORE"));
00351 FmtAssert (field_id == field_map_info[field_id-1].new_field_id,
00352 ("Error in field-id computation"));
00353
00354
00355 cur_field_id = 0;
00356 fld = FLD_get_to_field (Struct_update_index<<8,
00357 ++field_id, cur_field_id);
00358 FmtAssert (!fld.Is_Null(), ("Field not found"));
00359 WN_set_field_id(new_istore, field_id);
00360 WN_offset(new_istore) = FLD_ofst(fld);
00361
00362 WN * rhs = WN_kid0(stmt);
00363 if (WN_operator(rhs) == OPR_LDID)
00364 {
00365
00366 FmtAssert (TY_kind(WN_ty(rhs)) == KIND_POINTER &&
00367 TY_IDX_index(TY_pointed(WN_ty(rhs))) == candidate_ty_idx,
00368 ("Unexpected pointer"));
00369
00370 TY_IDX ty = Struct_field_layout[0].u.new_ty;
00371 WN_kid0(stmt) = WN_Ldid(WN_desc(rhs),
00372 0,
00373 fld_st[0],
00374 Make_Pointer_Type(ty));
00375 WN_Delete(rhs);
00376
00377 ty = Struct_field_layout[1].u.new_ty;
00378 rhs = WN_kid0(new_istore);
00379 WN_kid0(new_istore) = WN_Ldid(WN_desc(rhs),
00380 0,
00381 fld_st[1],
00382 Make_Pointer_Type(ty));
00383 WN_Delete(rhs);
00384 }
00385 else
00386 {
00387 FmtAssert (WN_operator(rhs) == OPR_INTCONST, ("NYI"));
00388 }
00389 WN_INSERT_BlockLast(block, new_istore);
00390 }
00391 else Fail_FmtAssertion ("NYI");
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401 void handle_kid_of_istore (WN * block, WN * parent, WN * wn, INT kidid, UINT field_id, BOOL lhs)
00402 {
00403 FmtAssert (!OPERATOR_is_stmt(WN_operator(wn)),
00404 ("ISTORE cannot have a statement as its kid"));
00405
00406 if (!OPCODE_is_leaf (WN_opcode (wn)))
00407 {
00408 INT kidno;
00409 WN* kid;
00410 for (kidno=0; kidno<WN_kid_count(wn); kidno++)
00411 {
00412 kid = WN_kid (wn, kidno);
00413 if (kid)
00414 {
00415 UINT id = field_id;
00416
00417 if (WN_operator(wn) == OPR_ILOAD &&
00418 TY_IDX_index(WN_ty(wn)) == candidate_ty_idx &&
00419 WN_field_id(wn))
00420 id = WN_field_id(wn);
00421 handle_kid_of_istore (block, wn, kid, kidno, id, lhs);
00422 }
00423 }
00424 }
00425
00426 if (WN_operator(wn) == OPR_ILOAD)
00427 {
00428 WN * addr = WN_kid0(wn);
00429 if (TY_IDX_index(WN_ty(wn)) == Struct_update_index && WN_field_id(wn))
00430 {
00431 FmtAssert (WN_operator(addr) == OPR_LDID, ("NYI"));
00432 UINT id = WN_field_id(wn);
00433 UINT32 new_field_id = field_map_info[id-1].new_field_id;
00434 if (id == candidate_fld_id && field_id == 2)
00435 new_field_id++;
00436
00437 UINT cur_field_id = 0;
00438 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00439 new_field_id, cur_field_id);
00440 FmtAssert (!fld.Is_Null(), ("Field not found"));
00441 WN_set_field_id(wn, new_field_id);
00442 WN_offset(wn) = FLD_ofst(fld);
00443 }
00444 else if (TY_IDX_index(WN_ty(wn)) == candidate_ty_idx && WN_field_id(wn))
00445 {
00446 INT field_id = WN_field_id(wn);
00447 TY_IDX ty = Struct_field_layout[field_id-1].u.new_ty;
00448 INT field_num = 0;
00449
00450 if (TY_kind(ty) == KIND_STRUCT)
00451 field_num = Struct_field_layout[field_id-1].fld_id;
00452
00453
00454 if (WN_operator(WN_kid0(wn)) == OPR_ADD &&
00455 WN_operator(WN_kid1(WN_kid0(wn))) == OPR_MPY)
00456 {
00457 WN * size = WN_kid1(WN_kid1(WN_kid0(wn)));
00458 FmtAssert (WN_operator(size) == OPR_INTCONST &&
00459 WN_const_val(size) == TY_size(Ty_tab[candidate_ty_idx]),
00460 ("Error while updating type size under iload"));
00461 WN_const_val(size) = TY_size(ty);
00462 }
00463
00464 WN_kid(parent, kidid) = WN_Iload(WN_desc(wn), 0, ty, addr, field_num);
00465 WN_Delete(wn);
00466 }
00467 }
00468 else if (WN_operator(wn) == OPR_LDID &&
00469 (lhs ||
00470 IPA_Enable_Struct_Opt == 2) &&
00471 TY_kind(WN_ty(wn)) == KIND_POINTER &&
00472 TY_IDX_index(TY_pointed(WN_ty(wn))) == candidate_ty_idx)
00473 {
00474 ST * base_st = fld_st[field_id - 1];
00475 TY_IDX ty = Struct_field_layout[field_id - 1].u.new_ty;
00476
00477 if (IPA_Enable_Struct_Opt == 2 &&
00478 ST_class(WN_st(wn)) == CLASS_VAR &&
00479 Is_Global_Symbol(WN_st(wn)))
00480 base_st = &St_Table[Struct_field_layout[field_id - 1].st_idx];
00481
00482 WN_kid(parent, kidid) = WN_Ldid(WN_desc(wn),
00483 0,
00484 base_st,
00485 Make_Pointer_Type(ty));
00486 WN_Delete(wn);
00487
00488 wn = WN_kid(parent, kidid);
00489 WN_set_field_id(wn,0);
00490 WN_offset(wn) = 0;
00491 WN_set_ty(wn, Make_Pointer_Type(ty));
00492 }
00493 }
00494
00495 void handle_istore (WN * block, WN * parent, WN * wn)
00496 {
00497
00498 handle_kid_of_istore(block, wn, WN_kid1(wn), 1, WN_field_id(wn), TRUE);
00499 handle_kid_of_istore(block, wn, WN_kid0(wn), 0, WN_field_id(wn), FALSE);
00500
00501
00502 if (TY_IDX_index(TY_pointed(WN_ty(wn))) == candidate_ty_idx &&
00503 WN_field_id(wn))
00504 {
00505 WN * addr = WN_kid1(wn);
00506 const INT field_id = WN_field_id(wn);
00507
00508 TY_IDX ty = Struct_field_layout[field_id - 1].u.new_ty;
00509
00510
00511 if (WN_operator(addr) == OPR_ADD && WN_operator(WN_kid1(addr)) == OPR_MPY)
00512 {
00513 WN * size = WN_kid1(WN_kid1(addr));
00514 FmtAssert (WN_operator(size) == OPR_INTCONST &&
00515 WN_const_val(size) == TY_size(Ty_tab[candidate_ty_idx]),
00516 ("Error while updating type size under istore"));
00517 WN_const_val(size) = TY_size(ty);
00518 }
00519 if (TY_kind(ty) == KIND_STRUCT)
00520 WN_set_field_id(wn, Struct_field_layout[field_id - 1].fld_id);
00521 else
00522 WN_set_field_id(wn, 0);
00523 WN_offset(wn) = 0;
00524 WN_set_ty(wn, Make_Pointer_Type(ty));
00525 }
00526 else if (TY_IDX_index(TY_pointed(WN_ty(wn))) == Struct_update_index &&
00527
00528 WN_field_id(wn))
00529 {
00530 UINT field_id = WN_field_id(wn);
00531 if (field_id != candidate_fld_id)
00532 {
00533 UINT new_field_id = field_map_info[field_id-1].new_field_id;
00534 UINT cur_field_id = 0;
00535 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00536 new_field_id, cur_field_id);
00537 FmtAssert (!fld.Is_Null(), ("Field not found"));
00538 WN_set_field_id (wn, new_field_id);
00539 WN_offset(wn) = FLD_ofst(fld);
00540 }
00541 else
00542 {
00543
00544 handle_istore_assignment (block, wn);
00545 }
00546 }
00547 }
00548
00549
00550
00551 WN * analyze_addressof_ty_being_split (WN * parent, WN * wn, WN * addr,
00552 INT kidid)
00553 {
00554 Is_True (WN_operator(wn) == OPR_ILOAD && TY_IDX_index(WN_ty(wn)) == candidate_ty_idx,
00555 ("Expected ILOAD through pointer to TY being split"));
00556
00557 FLD_HANDLE fld1 = TY_fld(Ty_tab[candidate_ty_idx]);
00558 FLD_HANDLE fld2 = FLD_next(fld1);
00559
00560 switch (WN_operator(addr))
00561 {
00562 case OPR_LDID:
00563 {
00564
00565
00566 WN_OFFSET ofst = 0;
00567 TY_IDX ty = TY_IDX_ZERO;
00568 ST * base_st = NULL;
00569 if (WN_field_id(wn) == 1)
00570 {
00571 ofst = FLD_ofst(fld1);
00572 ty = FLD_type(fld1);
00573 base_st = fld_st[0];
00574 }
00575 else
00576 {
00577 Is_True (WN_field_id(wn) == 2, ("Unexpected field id"));
00578 ofst = FLD_ofst(fld2);
00579 ty = FLD_type(fld2);
00580 base_st = fld_st[1];
00581 }
00582 INT index = (WN_load_offset(wn)-ofst) / TY_size(Ty_tab[candidate_ty_idx]);
00583 WN * base = WN_Ldid(WN_desc(addr), 0, base_st, Make_Pointer_Type(ty));
00584 WN_kid(parent, kidid) = WN_Iload(WN_desc(wn), index*TY_size(ty), ty, base);
00585
00586 WN_DELETE_Tree(wn);
00587 wn = WN_kid(parent, kidid);
00588 }
00589 break;
00590
00591 case OPR_ADD:
00592 {
00593 WN * base = WN_kid0(addr);
00594 WN * ofst = WN_kid1(addr);
00595
00596 FmtAssert (WN_operator(ofst) == OPR_MPY, ("Unexpected offset expression"));
00597 if (WN_operator(base) == OPR_LDID &&
00598 TY_IDX_index(WN_ty(base)) == Struct_update_index)
00599 {
00600
00601
00602
00603 TY_IDX ty = TY_IDX_ZERO;
00604 UINT32 field_id = field_map_info[WN_field_id(base)-1].new_field_id;
00605 if (WN_field_id(wn) == 1)
00606 {
00607 ty = Struct_split_types[0];
00608 }
00609 else
00610 {
00611 ty = Struct_split_types[1];
00612 field_id++;
00613 }
00614 UINT cur_field_id = 0;
00615 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00616 field_id, cur_field_id);
00617 FmtAssert (!fld.Is_Null(), ("Field not found"));
00618 WN_set_field_id(base, field_id);
00619 WN_offset(base) = FLD_ofst(fld);
00620
00621
00622 WN * size = WN_kid1(ofst);
00623 FmtAssert (WN_operator(size) == OPR_INTCONST, ("NYI"));
00624 WN_const_val(size) = TY_size(ty);
00625
00626
00627 UINT load_ofst = WN_load_offset(wn) >= 0 ? 0 : WN_load_offset(wn);
00628 WN_kid(parent, kidid) = WN_Iload(WN_desc(wn), load_ofst, ty, addr);
00629 WN_Delete(wn);
00630 wn = WN_kid(parent, kidid);
00631 }
00632 else if (WN_operator(base) == OPR_LDID)
00633 {
00634 const INT field_id = WN_field_id(wn);
00635 ST * base_st = fld_st[field_id - 1];
00636 TY_IDX ty = Struct_field_layout[field_id - 1].u.new_ty;
00637
00638 if (IPA_Enable_Struct_Opt == 2 &&
00639 ST_class(WN_st(base)) == CLASS_VAR &&
00640 Is_Global_Symbol(WN_st(base)))
00641 base_st = &St_Table[Struct_field_layout[field_id - 1].st_idx];
00642
00643
00644 WN * size = WN_kid1(ofst);
00645 FmtAssert (WN_operator(size) == OPR_INTCONST, ("NYI"));
00646 WN_const_val(size) = TY_size(ty);
00647
00648 WN_kid0(addr) = WN_Ldid(WN_desc(base), 0, base_st, Make_Pointer_Type(ty));
00649 WN_kid(parent, kidid) = WN_Iload(WN_desc(wn), 0, ty, addr);
00650
00651 WN_DELETE_Tree(base);
00652 WN_Delete(wn);
00653 wn = WN_kid(parent, kidid);
00654 }
00655 else
00656 {
00657 TY_IDX ty = Struct_field_layout[WN_field_id(wn) - 1].u.new_ty;
00658
00659 WN * size = WN_kid1(ofst);
00660 FmtAssert (WN_operator(size) == OPR_INTCONST, ("NYI"));
00661 WN_const_val(size) = TY_size(ty);
00662 WN_kid(parent, kidid) = WN_Iload(WN_desc(wn), 0, ty, addr);
00663 WN_Delete(wn);
00664 wn = WN_kid(parent, kidid);
00665 }
00666 }
00667 break;
00668
00669 case OPR_ILOAD:
00670 if (TY_IDX_index(WN_ty(addr)) == Struct_update_index)
00671 {
00672
00673 WN_OFFSET ofst = 0;
00674 TY_IDX ty = TY_IDX_ZERO;
00675 if (WN_field_id(wn) == 1)
00676 {
00677 ofst = FLD_ofst(fld1);
00678 ty = FLD_type(fld1);
00679 }
00680 else
00681 {
00682 ofst = FLD_ofst(fld2);
00683 ty = FLD_type(fld2);
00684 }
00685 INT index = (WN_load_offset(wn)-ofst) / TY_size(Ty_tab[candidate_ty_idx]);
00686 WN_kid(parent, kidid) = WN_Iload(WN_desc(wn), index*TY_size(ty), ty, addr, 0);
00687
00688 WN_Delete(wn);
00689 wn = WN_kid(parent, kidid);
00690 }
00691 break;
00692
00693 default: Fail_FmtAssertion ("NYI");
00694 }
00695
00696 return wn;
00697 }
00698
00699 void handle_compare (WN * g)
00700 {
00701 if (preg_id == 0)
00702 return;
00703
00704 WN * p = WN_kid0(g);
00705 WN * w = WN_kid0(p);
00706
00707 Is_True (WN_operator(w) == OPR_LDID, (""));
00708
00709 ST * sym = WN_st(w);
00710
00711 if (ST_class(sym) != CLASS_PREG ||
00712 WN_offset(w) != preg_id)
00713 return;
00714
00715
00716 if (WN_operator(p) != OPR_EQ)
00717 Fail_FmtAssertion ("NYI");
00718
00719 WN * kid1 = WN_kid1(p);
00720 Is_True (kid1 != w, (""));
00721
00722 if (WN_operator(kid1) != OPR_INTCONST ||
00723 WN_const_val(kid1) != 0)
00724 return;
00725
00726 WN * sym1 = WN_Ldid(WN_desc(w), 0, fld_st[0], ST_type(fld_st[0]));
00727 WN * sym2 = WN_Ldid(WN_desc(w), 0, fld_st[1], ST_type(fld_st[1]));
00728
00729 WN * cond = WN_CIOR(WN_EQ(WN_desc(p), sym1, WN_Intconst(MTYPE_U4, 0)),
00730 WN_EQ(WN_desc(p), sym2, WN_Intconst(MTYPE_U4, 0)));
00731
00732 for (INT id=0; id<WN_kid_count(g); id++)
00733 if (WN_kid(g,id) == p)
00734 {
00735 WN_kid(g,id) = cond;
00736 break;
00737 }
00738
00739 WN_DELETE_Tree(p);
00740 }
00741
00742 WN * traverse_wn_tree (WN * block, WN * grandparent, WN * parent, WN * wn, INT kidid)
00743 {
00744 if (wn == NULL) return NULL;
00745
00746
00747 if (!OPCODE_is_leaf (WN_opcode (wn)))
00748 {
00749 if (WN_opcode(wn) == OPC_BLOCK)
00750 {
00751 WN* kid = WN_first (wn);
00752 while (kid)
00753 {
00754 WN * out = WN_CreateBlock();
00755 kid = traverse_wn_tree (out, parent, wn, kid, 0);
00756 if (WN_last(out))
00757 {
00758 WN * ptr = kid;
00759 kid = WN_last(out);
00760 WN_INSERT_BlockAfter (wn, ptr, out);
00761 }
00762 kid = WN_next (kid);
00763 }
00764 }
00765 else if (WN_operator(wn) != OPR_ISTORE)
00766 {
00767 INT kidno;
00768 WN* kid;
00769 for (kidno=0; kidno<WN_kid_count(wn); kidno++)
00770 {
00771 kid = WN_kid (wn, kidno);
00772 if (kid)
00773 traverse_wn_tree (block, parent, wn, kid, kidno);
00774 }
00775 }
00776 }
00777
00778 switch (WN_operator(wn))
00779 {
00780 case OPR_STID:
00781 {
00782 if (TY_IDX_index(WN_ty(wn)) == Struct_update_index && WN_field_id(wn))
00783 {
00784
00785
00786 if (WN_field_id(wn) != candidate_fld_id)
00787 {
00788 UINT32 field_id = WN_field_id(wn);
00789 UINT32 new_field_id = field_map_info[field_id-1].new_field_id;
00790 UINT cur_field_id = 0;
00791 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00792 new_field_id, cur_field_id);
00793 FmtAssert (!fld.Is_Null(), ("Field not found"));
00794 WN_set_field_id(wn, new_field_id);
00795 WN_offset(wn) = FLD_ofst(fld);
00796 }
00797 }
00798 }
00799 break;
00800
00801 case OPR_IF:
00802 {
00803
00804
00805
00806 WN * test = WN_if_test(wn);
00807
00808 if (WN_operator(test) == OPR_EQ &&
00809 WN_operator(WN_kid0(test)) == OPR_LDID)
00810 {
00811 TY_IDX ty = WN_ty(WN_kid0(test));
00812 if (TY_kind(ty) == KIND_POINTER &&
00813 TY_IDX_index(TY_pointed(ty)) == candidate_ty_idx)
00814 handle_compare (wn);
00815 }
00816 }
00817 break;
00818
00819 case OPR_LDID:
00820 {
00821 TY_IDX ty = WN_ty(wn);
00822 if (TY_kind(ty) == KIND_POINTER &&
00823 TY_IDX_index(TY_pointed(ty)) == candidate_ty_idx)
00824 {
00825 if (WN_st(wn) == Return_Val_Preg)
00826 handle_function_return (block, parent);
00827 else if (WN_operator(parent) == OPR_STID)
00828
00829 handle_assignment (block, parent);
00830 else if (WN_operator(parent) == OPR_ISTORE)
00831 {
00832 Fail_FmtAssertion ("Should not reach here");
00833
00834 }
00835 }
00836 else if (TY_IDX_index(ty) == Struct_update_index)
00837 {
00838
00839
00840 if (WN_field_id(wn) == candidate_fld_id)
00841 {
00842 if (WN_operator(parent) == OPR_PARM)
00843 duplicate_call(block, grandparent);
00844 }
00845 else if (WN_field_id(wn))
00846 {
00847 UINT32 field_id = WN_field_id(wn);
00848 UINT32 new_field_id = field_map_info[field_id-1].new_field_id;
00849 UINT cur_field_id = 0;
00850 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00851 new_field_id, cur_field_id);
00852 FmtAssert (!fld.Is_Null(), ("Field not found"));
00853 WN_set_field_id(wn, new_field_id);
00854 WN_offset(wn) = FLD_ofst(fld);
00855 }
00856 }
00857 }
00858 break;
00859
00860 case OPR_ILOAD:
00861 {
00862 if (TY_IDX_index(WN_ty(wn)) == candidate_ty_idx)
00863 {
00864 wn = analyze_addressof_ty_being_split (parent, wn, WN_kid0(wn), kidid);
00865 }
00866 else if (TY_IDX_index(WN_ty(wn)) == Struct_update_index && WN_field_id(wn))
00867 {
00868 if (WN_operator(parent) == OPR_PARM &&
00869 WN_field_id(wn) == candidate_fld_id)
00870 duplicate_call(block, grandparent);
00871 else
00872 {
00873 UINT32 field_id = WN_field_id(wn);
00874 FmtAssert (field_id != 0, ("Non-zero field-id expected"));
00875 UINT32 new_field_id = field_map_info[field_id-1].new_field_id;
00876 WN * addr = WN_operator(parent) == OPR_ILOAD ? parent :
00877 WN_operator(grandparent) == OPR_ILOAD ? grandparent :
00878 NULL;
00879 if (addr &&
00880 TY_IDX_index(WN_ty(addr)) == candidate_ty_idx &&
00881 WN_field_id(addr) == 2)
00882 new_field_id++;
00883 else
00884 {
00885 addr = WN_operator(parent) == OPR_ISTORE ? parent :
00886 WN_operator(grandparent) == OPR_ISTORE ? grandparent :
00887 NULL;
00888 if (addr &&
00889 TY_IDX_index(TY_pointed(WN_ty(addr))) == candidate_ty_idx &&
00890 WN_field_id(addr) == 2)
00891 new_field_id++;
00892 }
00893 UINT cur_field_id = 0;
00894 FLD_HANDLE fld = FLD_get_to_field (Struct_update_index<<8,
00895 new_field_id, cur_field_id);
00896 FmtAssert (!fld.Is_Null(), ("Field not found"));
00897 WN_set_field_id(wn, new_field_id);
00898 WN_offset(wn) = FLD_ofst(fld);
00899 }
00900 }
00901 }
00902 break;
00903
00904 case OPR_ISTORE:
00905 handle_istore (block, parent, wn);
00906 break;
00907
00908 case OPR_CALL:
00909 {
00910 if (!strcmp(ST_name(WN_st(wn)), "free") && WN_kid_count(wn) == 1)
00911 {
00912 WN * arg = WN_kid0(WN_kid0(wn));
00913 if (WN_operator(arg) == OPR_LDID &&
00914 TY_kind(WN_ty(arg)) == KIND_POINTER &&
00915 TY_IDX_index(TY_pointed(WN_ty(arg))) == candidate_ty_idx)
00916 wn = handle_function_call (parent, wn);
00917 }
00918 }
00919 break;
00920
00921 default: break;
00922 }
00923
00924 return wn;
00925 }
00926
00927 extern INT struct_field_count(TY_IDX);
00928 static BOOL new_types_created = FALSE;
00929
00930 void IPO_generate_new_types (mUINT32 ty)
00931 {
00932 TY_IDX orig_ty = ty << 8;
00933 new_types_created = TRUE;
00934
00935 INT field_count = struct_field_count (orig_ty);
00936
00937 INT idx = 0;
00938 INT type_count = 0;
00939
00940 while (idx < field_count)
00941 {
00942 const INT struct_id = Struct_field_layout[idx].u.struct_id;
00943 BOOL create_new_ty = TRUE;
00944 FLD_HANDLE last_fld = FLD_HANDLE();
00945 INT offset = 0;
00946 TY_IDX new_ty = TY_IDX_ZERO;
00947
00948
00949
00950
00951 UINT cur_field_id = 0;
00952 FLD_HANDLE orig = FLD_get_to_field (orig_ty, idx+1, cur_field_id);
00953
00954 for (INT i=idx+1; i<field_count; i++)
00955 {
00956 if (struct_id == Struct_field_layout[i].u.struct_id)
00957 {
00958
00959
00960 if (create_new_ty)
00961 {
00962
00963 FLD_HANDLE fld = New_FLD();
00964 memcpy (fld.Entry(), orig.Entry(), sizeof(FLD));
00965 Is_True (offset == 0, ("First field should have offset zero"));
00966 Set_FLD_ofst (fld, offset);
00967 offset += TY_size(FLD_type(fld));
00968
00969
00970
00971
00972 TY_Init (New_TY(new_ty), sizeof(int) ,
00973 KIND_STRUCT, MTYPE_M,
00974 Save_Str2i(TY_name(orig_ty), "..", idx+1));
00975 Set_TY_fld(new_ty, fld);
00976 create_new_ty = FALSE;
00977 }
00978 cur_field_id = 0;
00979 orig = FLD_get_to_field (orig_ty, i+1, cur_field_id);
00980
00981 FLD_HANDLE fld = New_FLD();
00982 memcpy (fld.Entry(), orig.Entry(), sizeof(FLD));
00983 INT align = TY_align(FLD_type(fld));
00984 offset = (INT)ceil(((double)offset)/align)*align;
00985 Set_FLD_ofst (fld, offset);
00986 offset += TY_size(FLD_type(fld));
00987 last_fld = fld;
00988 }
00989 }
00990
00991 if (create_new_ty)
00992 {
00993
00994
00995 new_ty = FLD_type(orig);
00996 }
00997 else
00998 {
00999
01000 Is_True (new_ty != TY_IDX_ZERO, (""));
01001 Is_True (TY_kind(new_ty) == KIND_STRUCT, (""));
01002 Is_True (!last_fld.Is_Null(), (""));
01003 Set_FLD_last_field (last_fld);
01004 Set_TY_size (new_ty, offset);
01005 }
01006
01007 ST * st = NULL;
01008 if (IPA_Enable_Struct_Opt == 2)
01009 {
01010 st = New_ST(GLOBAL_SYMTAB);
01011 ST_Init (st, Save_Str2i("aa", "..", idx), CLASS_VAR, SCLASS_COMMON, EXPORT_PREEMPTIBLE, Make_Pointer_Type(new_ty));
01012 }
01013
01014 while (idx < field_count &&
01015 struct_id == Struct_field_layout[idx].u.struct_id)
01016 {
01017 if (IPA_Enable_Struct_Opt == 2)
01018 Struct_field_layout[idx].st_idx = ST_st_idx(st);
01019 Struct_field_layout[idx++].u.new_ty = new_ty;
01020 }
01021
01022 Struct_split_types[type_count++] = new_ty;
01023 }
01024
01025 FmtAssert (type_count == Struct_split_count, (""));
01026 Struct_split_types[type_count] = TY_IDX_ZERO;
01027 }
01028
01029 static BOOL fld_table_updated = FALSE;
01030
01031
01032 void IPO_Fld_Table_Update_For_Struct_Opt (mUINT32 ty)
01033 {
01034 fld_table_updated = TRUE;
01035
01036 mUINT32 old_field_id, new_field_id;
01037 WN_OFFSET old_ofst, new_ofst;
01038
01039 old_field_id = new_field_id = 1;
01040 old_ofst = new_ofst = 0;
01041
01042 FmtAssert (TY_kind(Ty_tab[ty]) == KIND_STRUCT, ("struct type expected"));
01043
01044 FLD_ITER fld_iter = Make_fld_iter(TY_fld(Ty_tab[ty]));
01045 FLD_IDX first_fld_idx = Fld_Table.size();
01046 FLD_HANDLE last_field;
01047 BOOL child_flattened = FALSE;
01048
01049 UINT32 fld_count = 1;
01050 do
01051 {
01052 fld_count++;
01053 } while (!FLD_last_field(fld_iter++));
01054
01055 FmtAssert (fld_count > 1, ("This struct should have > 1 field"));
01056
01057 field_map_info = (FLD_MAP *) malloc (fld_count * sizeof(FLD_MAP));
01058
01059 fld_iter = Make_fld_iter(TY_fld(Ty_tab[ty]));
01060 do
01061 {
01062 FLD_HANDLE fld(fld_iter);
01063 FLD_HANDLE new_fld = New_FLD();
01064
01065 field_map_info[old_field_id-1].old_field_id = old_field_id;
01066 field_map_info[old_field_id-1].new_field_id = new_field_id;
01067
01068 if (TY_kind(FLD_type(fld)) == KIND_POINTER &&
01069 TY_IDX_index(TY_pointed(FLD_type(fld))) == candidate_ty_idx)
01070 {
01071 FmtAssert (!child_flattened, ("Unexpected struct-type field"));
01072 FmtAssert (old_field_id == new_field_id, ("Field update error"));
01073 candidate_fld_id = old_field_id;
01074 child_flattened = TRUE;
01075 UINT32 ofst = FLD_ofst(fld);
01076 FmtAssert (TY_kind(Ty_tab[candidate_ty_idx]) == KIND_STRUCT, ("struct expected"));
01077 FLD_HANDLE nested = TY_fld(Ty_tab[candidate_ty_idx]);
01078 memcpy (&Fld_Table[new_fld.Idx()], &Fld_Table[nested.Idx()], sizeof(FLD));
01079 FmtAssert (FLD_ofst(new_fld) == 0, ("Offset mismatch"));
01080 Set_FLD_ofst (new_fld, ofst);
01081 Set_FLD_type (new_fld, Make_Pointer_Type (FLD_type(new_fld)));
01082
01083 new_fld = New_FLD();
01084 new_field_id++;
01085 memcpy (&Fld_Table[new_fld.Idx()], &Fld_Table[nested.Idx()+1], sizeof(FLD));
01086 Set_FLD_ofst (new_fld, ofst+Pointer_Size);
01087 Set_FLD_type (new_fld, Make_Pointer_Type (FLD_type(new_fld)));
01088
01089 FmtAssert (FLD_last_field(new_fld), ("Last field flag missing"));
01090 Clear_FLD_last_field(new_fld);
01091 last_field = new_fld;
01092 }
01093 else
01094 {
01095 memcpy (&Fld_Table[new_fld.Idx()], &Fld_Table[fld.Idx()], sizeof(FLD));
01096 if (child_flattened)
01097 Set_FLD_ofst (new_fld, FLD_ofst(new_fld)+Pointer_Size);
01098 last_field = new_fld;
01099 }
01100 old_field_id++;
01101 new_field_id++;
01102 } while (!FLD_last_field(fld_iter++));
01103
01104 Ty_tab[ty].Set_fld(first_fld_idx);
01105 Set_TY_size(Ty_tab[ty], TY_size(Ty_tab[ty])+Pointer_Size);
01106 Set_FLD_last_field(last_field);
01107 }
01108
01109
01110 void IPO_WN_Update_For_Struct_Opt (IPA_NODE * node)
01111 {
01112 if (IPA_Update_Struct)
01113 {
01114
01115
01116 Struct_split_candidate_index = IPA_Enable_Struct_Opt;
01117 Struct_update_index = IPA_Update_Struct;
01118 }
01119
01120 if (!Struct_split_candidate_index)
01121 return;
01122
01123 WN * tree = node->Whirl_Tree();
01124 preg_id = 0;
01125 FmtAssert (tree, ("Null whirl tree"));
01126
01127 PU_Parent_Map = node->Parent_Map();
01128 PU_Map_Tab = node->Map_Table();
01129
01130
01131
01132
01133 IPA_Call_Graph->Map_Callsites(node);
01134
01135
01136 WN_Parentize(tree, PU_Parent_Map, PU_Map_Tab);
01137 candidate_ty_idx = Struct_split_candidate_index;
01138
01139 FmtAssert (candidate_ty_idx != 0, ("No TY to optimize"));
01140 if (Struct_update_index && !fld_table_updated)
01141 IPO_Fld_Table_Update_For_Struct_Opt (Struct_update_index);
01142
01143 if (!new_types_created)
01144 IPO_generate_new_types (Struct_split_candidate_index);
01145 traverse_wn_tree (NULL, NULL, tree, WN_func_body(tree), 0);
01146
01147 WN_Parentize(tree, PU_Parent_Map, PU_Map_Tab);
01148 }