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
00030
00031
00032
00033
00034
00035
00036 #include "defs.h"
00037 #include "stab.h"
00038 #include "wn.h"
00039 #include "ir_reader.h"
00040 #include "strtab.h"
00041 #include "stblock.h"
00042 #include "data_layout.h"
00043 #include "erbe.h"
00044 #include "cxx_hash.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053 extern "C" {
00054 void Process_Fill_Align_Pragmas (WN* func_wn);
00055 }
00056
00057
00058
00059 void Fill_Align_Initialize_Parameters (INT *L1_sz, INT *L2_sz, INT *pg_sz);
00060
00061 static void Process_Fill_Align_Pragmas_Recursive (WN* wn, WN* func_wn);
00062 static void Fill_Align_Symbol (WN* wn, WN* func_wn);
00063
00064 typedef HASH_TABLE<ST*, BOOL> ST_HASH_TABLE;
00065 static ST_HASH_TABLE *symbol_ht;
00066 static MEM_POOL symbol_ht_pool;
00067 static INT L1_cache_line_sz, L2_cache_line_sz, page_sz;
00068
00069
00070
00071
00072
00073
00074
00075
00076 void Process_Fill_Align_Pragmas (WN* wn) {
00077
00078
00079
00080
00081
00082
00083
00084 static INT initialized = 0;
00085 if (!initialized) {
00086 initialized = 1;
00087 Fill_Align_Initialize_Parameters (&L1_cache_line_sz,
00088 &L2_cache_line_sz,
00089 &page_sz);
00090 MEM_POOL_Initialize (&symbol_ht_pool, "Fill Align Pool", FALSE);
00091 MEM_POOL_Push_Freeze (&symbol_ht_pool);
00092 symbol_ht = CXX_NEW (ST_HASH_TABLE (20, &symbol_ht_pool), &symbol_ht_pool);
00093 }
00094
00095 Process_Fill_Align_Pragmas_Recursive (wn, wn);
00096 }
00097
00098 static void Process_Fill_Align_Pragmas_Recursive (WN* wn, WN* func_wn) {
00099 OPCODE opc;
00100 OPERATOR oper;
00101 INT i;
00102
00103 if (!wn) return;
00104
00105 opc = WN_opcode(wn);
00106 oper = OPCODE_operator(opc);
00107
00108
00109 if (oper == OPR_PRAGMA) {
00110 if (WN_pragma(wn) == WN_PRAGMA_FILL ||
00111 WN_pragma(wn) == WN_PRAGMA_ALIGN) {
00112 Fill_Align_Symbol (wn, func_wn);
00113 }
00114 return;
00115 }
00116
00117 if (WN_operator(wn) == OPR_BLOCK) {
00118 WN* kid = WN_first(wn);
00119 while (kid) {
00120 Process_Fill_Align_Pragmas_Recursive (kid, func_wn);
00121 kid = WN_next(kid);
00122 }
00123 return;
00124 }
00125
00126 for (i=0; i<WN_kid_count(wn); i++) {
00127 Process_Fill_Align_Pragmas_Recursive (WN_kid(wn, i), func_wn);
00128 }
00129 return;
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139 static BOOL Local_Variable (ST* st) {
00140
00141 if (ST_sclass(st) == SCLASS_AUTO ||
00142 ST_sclass(st) == SCLASS_PSTATIC ||
00143 (ST_base(st) &&
00144 ST_sclass(ST_base(st)) == SCLASS_AUTO))
00145 return TRUE;
00146 else return FALSE;
00147
00148 }
00149
00150 static BOOL Global_Variable (ST* st) {
00151
00152 if (Is_Global_Symbol(st) && ST_sclass(st) != SCLASS_COMMON)
00153 return TRUE;
00154 else return FALSE;
00155 }
00156
00157 static BOOL Common_Variable (ST* st) {
00158
00159 if (ST_sclass(st) == SCLASS_COMMON) {
00160 Is_True (Is_Global_Symbol(st) && ST_base_idx(st) != ST_st_idx(st),
00161 ("Symbol %s is SCLASS_COMMON but is weird\n", ST_name(st)));
00162 return TRUE;
00163 }
00164 else return FALSE;
00165
00166 }
00167
00168
00169
00170
00171
00172
00173
00174
00175 static BOOL Known_Size (ST* st) {
00176
00177 INT ndims;
00178 INT i;
00179
00180 TY& ty = Ty_Table[ST_type(st)];
00181
00182
00183 if (TY_kind(ty) != KIND_ARRAY) return TRUE;
00184
00185
00186
00187
00188
00189
00190 ndims = TY_AR_ndims(ty);
00191 for (i=0; i<ndims; i++) {
00192 if (!TY_AR_const_lbnd(ty, i) ||
00193 !TY_AR_const_ubnd(ty, i))
00194 return FALSE;
00195 }
00196 return TRUE;
00197
00198 }
00199
00200
00201 static WN *
00202 Find_Alloca (WN *block, ST *sym)
00203 {
00204 Is_True (block && WN_opcode(block) == OPC_BLOCK,
00205 ("find_alloca: expected a OPC_BLOCK node"));
00206 WN *alloca_wn = WN_first(block);
00207 while (alloca_wn) {
00208 if ((WN_operator(alloca_wn) == OPR_STID) &&
00209 (&St_Table[WN_st_idx(alloca_wn)] == sym)) {
00210 return alloca_wn;
00211 }
00212
00213
00214
00215 if (WN_operator(alloca_wn) == OPR_PRAGMA &&
00216 WN_pragma(alloca_wn) == WN_PRAGMA_PREAMBLE_END) {
00217 DevWarn ("Reached end of preamble w/o finding alloca of %s\n",
00218 ST_name(sym));
00219 }
00220 else if (WN_opcode(alloca_wn) == OPC_REGION) {
00221 WN *alloca_in_region;
00222 alloca_in_region = Find_Alloca (WN_region_body(alloca_wn), sym);
00223 if (alloca_in_region != NULL) {
00224 return alloca_in_region;
00225 }
00226 }
00227 alloca_wn = WN_next(alloca_wn);
00228 }
00229 return alloca_wn;
00230 }
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 static void Fill_Align_Symbol (WN* wn, WN* func_wn) {
00256 ST* st = &St_Table[WN_st_idx(wn)];
00257
00258 INT orig_size;
00259 INT new_size;
00260 INT pad;
00261 INT orig_align;
00262 INT log_orig_align=0;
00263 INT64 new_ofst;
00264
00265
00266 INT fa_value;
00267
00268
00269
00270 BOOL is_fill;
00271
00272
00273
00274 WN* body_wn = WN_func_body(func_wn);
00275
00276 BOOL ignore_global_symbols = FALSE;
00277
00278
00279
00280
00281
00282 if (FILE_INFO_ipa(File_info) && Read_Global_Data) {
00283
00284 ignore_global_symbols = TRUE;
00285 }
00286
00287 is_fill = (WN_pragma(wn) == WN_PRAGMA_FILL);
00288
00289 fa_value = WN_pragma_arg2(wn);
00290 switch (fa_value) {
00291 case -1:
00292
00293 fa_value = L1_cache_line_sz;
00294 break;
00295 case -2:
00296
00297 fa_value = L2_cache_line_sz;
00298 break;
00299 case -3:
00300
00301 fa_value = page_sz;
00302 break;
00303 default:
00304 break;
00305 }
00306
00307
00308
00309
00310 if (!(ST_class(st) == CLASS_VAR && (Local_Variable(st) ||
00311 Global_Variable(st) ||
00312 Common_Variable(st)))) {
00313 ErrMsgSrcpos (EC_Bad_Pragma_Abort, WN_Get_Linenum(wn),
00314 WN_pragmas[WN_pragma(wn)].name,
00315 ST_name(st),
00316 "must be supplied a variable");
00317 }
00318
00319
00320
00321 if (Global_Variable(st) && !Known_Size(st)) {
00322 ErrMsgSrcpos (EC_Bad_Pragma_Abort, WN_Get_Linenum(wn),
00323 WN_pragmas[WN_pragma(wn)].name,
00324 ST_name(st),
00325 "global variable must be completely specified");
00326 }
00327
00328
00329
00330 if (Local_Variable(st) && Known_Size(st) && !is_fill && fa_value > 16) {
00331 ErrMsgSrcpos (EC_Bad_Pragma_Abort, WN_Get_Linenum(wn),
00332 WN_pragmas[WN_pragma(wn)].name,
00333 ST_name(st),
00334 "cannot align automatic variables to greater than 16 bytes");
00335 }
00336
00337 if (Global_Variable(st) && ignore_global_symbols) {
00338 return;
00339 }
00340
00341
00342
00343 if (Is_Global_Symbol(st)) {
00344 if (symbol_ht->Find (st)) {
00345
00346 return;
00347 }
00348 else symbol_ht->Enter (st, TRUE);
00349 }
00350
00351
00352 FmtAssert (Common_Variable(st) || ST_ofst(st) == 0,
00353 ("Fill/Align_Symbol (%s): ST has an unexpected offset %llu\n",
00354 ST_name(st), ST_ofst(st)));
00355
00356
00357
00358
00359
00360 Clear_ST_gprel(st);
00361
00362
00363
00364 orig_align = TY_align(ST_type(st));
00365 while (orig_align) {
00366 if (orig_align & 0x1) break;
00367 log_orig_align++;
00368 orig_align = orig_align >> 1;
00369 }
00370 orig_align = TY_align(ST_type(st));
00371
00372
00373
00374
00375 orig_size = TY_size(ST_type(st));
00376 if (is_fill) {
00377
00378 if (Local_Variable(st) && Known_Size(st) && is_fill) {
00379
00380
00381
00382
00383 if (orig_align > fa_value) {
00384 pad = orig_align+fa_value;
00385 new_ofst = orig_align;
00386 }
00387 else {
00388 pad = 2*fa_value;
00389 new_ofst = fa_value;
00390 }
00391 new_size = orig_size + pad;
00392 }
00393 else {
00394 INT tmp;
00395 tmp = orig_size & (fa_value-1);
00396 if (tmp) new_size = orig_size+fa_value-tmp;
00397 else new_size = orig_size;
00398 pad = fa_value-tmp;
00399 new_ofst = pad/2;
00400 }
00401 }
00402 else {
00403 new_size = orig_size;
00404 pad = 0;
00405 new_ofst = 0;
00406 }
00407
00408
00409
00410
00411 new_ofst = ((new_ofst >> log_orig_align) << log_orig_align);
00412
00413
00414
00415 if (Global_Variable(st) || (Local_Variable(st) && Known_Size(st))) {
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 if (orig_size != new_size) {
00426
00427
00428 ST* base_st;
00429 INT new_align;
00430
00431
00432
00433
00434 new_align = (orig_align > fa_value ? orig_align : fa_value);
00435
00436 base_st = New_ST_Block (Save_Str2("__fill_", ST_name(st)),
00437 Is_Global_Symbol(st),
00438 ST_sclass(st), new_align, new_size);
00439 Enter_ST(base_st);
00440
00441 Set_ST_base(st, base_st);
00442 Set_ST_ofst(st, ST_ofst(st) + new_ofst);
00443 }
00444 else {
00445
00446
00447
00448 if (TY_align(ST_type(st)) < fa_value) {
00449 TY_IDX new_ty = Copy_TY (ST_type(st));
00450 Set_TY_align(new_ty, fa_value);
00451 Set_ST_type(st, new_ty);
00452
00453 FmtAssert (ST_ofst(st) == 0,
00454 ("Fill/Align_Symbol (%s): ST has an unexpected offset %llu\n",
00455 ST_name(st), ST_ofst(st)));
00456 }
00457 }
00458 if (Global_Variable(st)) {
00459 Allocate_Object (st);
00460 }
00461 }
00462
00463 else if (Local_Variable(st) && !Known_Size(st)) {
00464
00465
00466
00467 WN* alloca_wn, *alloca_arg_wn, *alloca_store_wn;
00468 WN* arg_wn;
00469 ST* base_st = ST_base(st);
00470 TYPE_ID rtype;
00471 WN *ldid_wn, *stid_wn;
00472 INT log_fa_value;
00473 INT tmp;
00474
00475
00476
00477
00478
00479
00480 alloca_wn = Find_Alloca (body_wn, base_st);
00481 FmtAssert (alloca_wn, ("Reached end of PU w/o finding alloca of %s\n",
00482 ST_name(st)));
00483
00484 alloca_store_wn = alloca_wn;
00485 if (Alloca_Dealloca_On) {
00486 FmtAssert (WN_operator(WN_kid0(alloca_wn)) == OPR_ALLOCA,
00487 ("fill/align symbol (%s): Expected alloca", ST_name(st)));
00488 } else {
00489 alloca_wn = WN_prev(alloca_wn);
00490 FmtAssert (WN_operator(alloca_wn) == OPR_INTRINSIC_CALL,
00491 ("fill/align symbol (%s): Expected alloca", ST_name(st)));
00492 }
00493
00494
00495
00496
00497 alloca_arg_wn = WN_kid0(WN_kid0(alloca_wn));
00498 rtype = WN_rtype(alloca_arg_wn);
00499
00500
00501 arg_wn = WN_CreateExp2 (OPCODE_make_op(OPR_ADD, rtype, MTYPE_V),
00502 alloca_arg_wn,
00503 WN_CreateIntconst(OPCODE_make_op(OPR_INTCONST,
00504 rtype,
00505 MTYPE_V),
00506 is_fill?(fa_value*2):fa_value));
00507 WN_kid0(WN_kid0(alloca_wn)) = arg_wn;
00508
00509
00510
00511
00512
00513 tmp = fa_value;
00514 log_fa_value = 0;
00515 while (tmp) {
00516 if (tmp & 0x1) break;
00517 log_fa_value++;
00518 tmp = tmp >> 1;
00519 }
00520
00521
00522 rtype = WN_desc(alloca_store_wn);
00523
00524 ldid_wn = WN_RLdid(Mtype_comparison(rtype), rtype, 0, base_st, ST_type(base_st));
00525 ldid_wn = WN_CreateExp2 (OPCODE_make_op(OPR_ADD, rtype, MTYPE_V),
00526 ldid_wn,
00527 WN_CreateIntconst (OPCODE_make_op(OPR_INTCONST,
00528 rtype,
00529 MTYPE_V),
00530 fa_value-1));
00531 ldid_wn = WN_CreateExp2 (OPCODE_make_op(OPR_ASHR, rtype, MTYPE_V),
00532 ldid_wn,
00533 WN_CreateIntconst (OPCODE_make_op(OPR_INTCONST,
00534 rtype,
00535 MTYPE_V),
00536 log_fa_value));
00537 ldid_wn = WN_CreateExp2 (OPCODE_make_op(OPR_SHL, rtype, MTYPE_V),
00538 ldid_wn,
00539 WN_CreateIntconst (OPCODE_make_op(OPR_INTCONST,
00540 rtype,
00541 MTYPE_V),
00542 log_fa_value));
00543 stid_wn = WN_CreateStid (OPCODE_make_op(OPR_STID, MTYPE_V, rtype),
00544 0, base_st, ST_type(base_st), ldid_wn);
00545 WN_next(stid_wn) = WN_next(alloca_store_wn);
00546 WN_prev(WN_next(alloca_store_wn)) = stid_wn;
00547 WN_next(alloca_store_wn) = stid_wn;
00548 WN_prev(stid_wn) = alloca_store_wn;
00549 }
00550
00551 else if (Common_Variable(st)) {
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 if (orig_size != new_size || (ST_ofst(st) % fa_value)) {
00575
00576
00577 ST* cst;
00578 INT delta = new_size - orig_size;
00579
00580
00581
00582
00583
00584 delta += ST_ofst(st) % fa_value;
00585 new_size = orig_size + delta;
00586 new_ofst += ST_ofst(st) % fa_value;
00587
00588
00589
00590
00591 if (delta % 8) {
00592 delta = (((delta+7) >> 3) << 3);
00593 new_size = orig_size + delta;
00594 }
00595
00596 INT i;
00597 FOREACH_SYMBOL(CURRENT_SYMTAB, cst, i) {
00598 if (ST_base(cst) == ST_base(st) && st != cst &&
00599 ST_ofst(cst) > ST_ofst(st)) {
00600
00601
00602 Set_ST_ofst(cst, ST_ofst(cst) + delta);
00603 }
00604 }
00605
00606 TY_IDX common_ty;
00607
00608
00609 common_ty = ST_type(ST_base(st));
00610
00611 Is_True (TY_kind(common_ty) == KIND_STRUCT,
00612 ("fill/align_symbol (%s): expected type struct for common",
00613 ST_name(st)));
00614
00615
00616 TY &ty = Ty_Table[common_ty];
00617 Set_TY_size(ty, TY_size(common_ty) + delta);
00618 FLD_ITER fld_iter = Make_fld_iter (TY_fld (ty));
00619 do {
00620 FLD_HANDLE field (fld_iter);
00621 if (FLD_ofst(field) == ST_ofst(st)) {
00622 Set_FLD_ofst(field, FLD_ofst(field) + new_ofst);
00623 }
00624 else if (FLD_ofst(field) > ST_ofst(st)) {
00625 Set_FLD_ofst(field, FLD_ofst(field) + delta);
00626 }
00627 } while (! FLD_last_field (fld_iter++));
00628
00629
00630 Set_ST_ofst(st, ST_ofst(st) + new_ofst);
00631
00632
00633 if (TY_align(common_ty) < fa_value) {
00634 TY_IDX new_ty = Copy_TY (common_ty);
00635 Set_TY_align(new_ty, fa_value);
00636 Set_ST_type(ST_base(st), new_ty);
00637 }
00638 }
00639
00640 else {
00641
00642
00643
00644 TY_IDX common_ty = ST_type(ST_base(st));
00645
00646 if (TY_align(common_ty) < fa_value) {
00647 TY_IDX new_ty = Copy_TY (common_ty);
00648 Set_TY_align(new_ty, fa_value);
00649 Set_ST_type(ST_base(st), new_ty);
00650 }
00651 }
00652 }
00653 else {
00654
00655 ErrMsgSrcpos (EC_Bad_Pragma_Abort, WN_Get_Linenum(wn),
00656 WN_pragmas[WN_pragma(wn)].name,
00657 ST_name(st),
00658 "variable must be local, global, or common");
00659 }
00660 }