On Fri, Oct 16, 2020 at 9:59 PM Gary Oblock via Gcc <gcc@gcc.gnu.org> wrote: > > I have a tiny program composed of a few functions > and one of those functions (setupB) has gone missing. > Since I need to walk its GIMPLE, this is a problem. > > The program: > > -- aux.h ----------------------------------------- > #include "stdlib.h" > typedef struct A A_t; > typedef struct A B_t; > struct A { > int i; > double x; > }; > > #define MAX(x,y) ((x)>(y) ? (x) : (y)) > > extern int max1( A_t *, size_t); > extern double max2( B_t *, size_t); > extern A_t *setupA( size_t); > extern B_t *setupB( size_t); > -- aux.c ---------------------------------------- > #include "aux.h" > #include "stdlib.h" > > A_t * > setupA( size_t size) > { > A_t *data = (A_t *)malloc( size * sizeof(A_t)); > size_t i; > for( i = 0; i < size; i++ ) { > data[i].i = rand(); > data[i].x = drand48(); > } > return data; > } > > B_t * > setupB( size_t size) > { > B_t *data = (B_t *)malloc( size * sizeof(B_t)); > size_t i; > for( i = 0; i < size; i++ ) { > data[i].i = rand(); > data[i].x = drand48(); > } > return data; > } > > int > max1( A_t *array, size_t len) > { > size_t i; > int result = array[0].i; > for( i = 1; i < len; i++ ) { > result = MAX( array[i].i, result); > } > return result; > } > > double > max2( B_t *array, size_t len) > { > size_t i; > double result = array[0].x; > for( i = 1; i < len; i++ ) { > result = MAX( array[i].x, result); > } > return result; > } > -- main.c ------------------------------------- > #include "stdio.h" > > A_t *data1; > > int > main(void) > { > B_t *data2 = setupB(200); > data1 = setupA(100); > > printf("First %d\n" , max1(data1,100)); > printf("Second %e\n", max2(data2,200)); > } > ------------------------------------------------ > > Here is its GIMPLE dump: > (for the sole purpose of letting you see > with your own eyes that setupB is indeed missing) > ------------------------------------------------ > Program: > static struct A_t * data1; > struct A_t * <T623> (size_t) > > ;; Function setupA (setupA, funcdef_no=4, decl_uid=4398, cgraph_uid=6, > symbol_order=48) (executed once) > > setupA (size_t size) > { > size_t i; > struct A_t * data; > > <bb 2> [local count: 118111600]: > _1 = size_8(D) * 16; > data_11 = malloc (_1); > goto <bb 4>; [100.00%] > > <bb 3> [local count: 955630225]: > _2 = i_6 * 16; > _3 = data_11 + _2; > _4 = rand (); > _3->i = _4; > _5 = drand48 (); > _3->x = _5; > i_16 = i_6 + 1; > > <bb 4> [local count: 1073741824]: > # i_6 = PHI <0(2), i_16(3)> > if (i_6 < size_8(D)) > goto <bb 3>; [89.00%] > else > goto <bb 5>; [11.00%] > > <bb 5> [local count: 118111600]: > return data_11; > > } > > > int <T622> (struct A_t *) > > ;; Function max1.constprop (max1.constprop.0, funcdef_no=1, decl_uid=4397, > cgraph_uid=5, symbol_order=58) (executed once) > > max1.constprop (struct A_t * array) > { > size_t i; > int result; > size_t len; > > <bb 6> [local count: 118111600]: > > <bb 2> [local count: 118111600]: > result_2 = array_1(D)->i; > goto <bb 4>; [100.00%] > > <bb 3> [local count: 955630225]: > _4 = i_3 * 16; > _5 = array_1(D) + _4; > _6 = _5->i; > result_8 = MAX_EXPR <_6, result_7>; > i_9 = i_3 + 1; > > <bb 4> [local count: 1073741824]: > # i_3 = PHI <1(2), i_9(3)> > # result_7 = PHI <result_2(2), result_8(3)> > if (i_3 <= 99) > goto <bb 3>; [89.00%] > else > goto <bb 5>; [11.00%] > > <bb 5> [local count: 118111600]: > # result_10 = PHI <result_7(4)> > return result_10; > > } > > > double <T61e> (struct B_t *) > > ;; Function max2.constprop (max2.constprop.0, funcdef_no=3, decl_uid=4395, > cgraph_uid=3, symbol_order=59) (executed once) > > max2.constprop (struct B_t * array) > { > size_t i; > double result; > size_t len; > > <bb 8> [local count: 118111600]: > > <bb 2> [local count: 118111600]: > result_2 = array_1(D)->x; > goto <bb 6>; [100.00%] > > <bb 3> [local count: 955630225]: > _4 = i_3 * 16; > _5 = array_1(D) + _4; > _6 = _5->x; > if (_6 > result_7) > goto <bb 4>; [50.00%] > else > goto <bb 5>; [50.00%] > > <bb 4> [local count: 477815112]: > > <bb 5> [local count: 955630225]: > # _10 = PHI <result_7(3), _6(4)> > i_8 = i_3 + 1; > > <bb 6> [local count: 1073741824]: > # i_3 = PHI <1(2), i_8(5)> > # result_7 = PHI <result_2(2), _10(5)> > if (i_3 <= 199) > goto <bb 3>; [89.00%] > else > goto <bb 7>; [11.00%] > > <bb 7> [local count: 118111600]: > # result_9 = PHI <result_7(6)> > return result_9; > > } > > > int <T619> (void) > > ;; Function main (main, funcdef_no=5, decl_uid=4392, cgraph_uid=1, > symbol_order=25) (executed once) > > main () > { > struct B_t * data2; > > <bb 2> [local count: 1073741824]: > data2_6 = setupB (200); > _1 = setupA (100); > data1 = _1; > _2 = max1 (_1, 100); > printf ("First %d\n", _2); > _3 = max2 (data2_6, 200); > printf ("Second %e\n", _3); > return 0; > > } > ------------------------------------------------ > The pass is invoked at this location in passes.def > > /* Simple IPA passes executed after the regular passes. In WHOPR mode the > passes are executed after partitioning and thus see just parts of the > compiled unit. */ > INSERT_PASSES_AFTER (all_late_ipa_passes) > NEXT_PASS (pass_materialize_all_clones); > NEXT_PASS (pass_ipa_type_escape_analysis); > NEXT_PASS (pass_ipa_structure_reorg); <========== my pass! > NEXT_PASS (pass_ipa_prototype); > NEXT_PASS (pass_ipa_pta); > NEXT_PASS (pass_omp_simd_clone); > TERMINATE_PASS_LIST (all_late_ipa_passes) > > -------------------------------------------------------------------------- > The program was compiled with these options: > > export OPTIONS='-O2 -fdump-passes -flto -flto-partition=one > -fipa-instance-interleave -fdump-ipa-all-details -save-temps -v' > > By the way, changing -flto-partition=one to -flto-partition=none > makes no difference. > > --------------------------------------------------------------------------- > Here is how the dump was done: > > void > print_program ( FILE *file, bool my_format, int leading_space, Info_t *info) > { > struct cgraph_node *node; > fprintf ( file, "%*sProgram:\n", leading_space, ""); > > // Print Global Decls > // > varpool_node *var; > FOR_EACH_VARIABLE ( var) > { > tree decl = var->decl; > fprintf ( file, "%*s", leading_space, ""); > flexible_print ( file, decl, 1, (dump_flags_t)0); > } > > FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) > { > struct function *func = DECL_STRUCT_FUNCTION ( node->decl); > flexible_print ( file, TREE_TYPE( func->decl), 1, (dump_flags_t)0); > dump_function_header ( file, func->decl, (dump_flags_t)0); > dump_function_to_file ( func->decl, file, (dump_flags_t)0); > } > } > > Note, flexible_print is a wrapper that calls either print_generic_decl > or print_generic_expr depending on whether or not it's a decl. The "1" > just causes a "\n" to be emmited... > > I also should mention I spin through the following loop at the > start of my pass to make sure the functions are sane: > > cgraph_node* node; > FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) > node->get_untransformed_body (); > > I don't think I left out any pertinent details. > > Any suggestions (other than don't use lto this way) > are welcome.
Try -fno-ipa-icf - it looks like setupA and setupB are identical. You'll see adjusted calls only after IPA transform. Richard. > Thanks, > > Gary > > > > > CONFIDENTIALITY NOTICE: This e-mail message, including any attachments, is > for the sole use of the intended recipient(s) and contains information that > is confidential and proprietary to Ampere Computing or its subsidiaries. It > is to be used solely for the purpose of furthering the parties' business > relationship. Any unauthorized review, copying, or distribution of this email > (or any attachments thereto) is strictly prohibited. If you are not the > intended recipient, please contact the sender immediately and permanently > delete the original and any copies of this email and any attachments thereto.