/* Interprocedural scalar replacement of aggregates Copyright (C) 2019-2020 Free Software Foundation, Inc. Contributed by Gary Oblock This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "backend.h" #include "tree.h" #include "gimple.h" #include "tree-pass.h" #include "cgraph.h" #include "gimple-iterator.h" #include "pretty-print.h" #include #include #include #include "ipa-structure-reorg.h" #include "dumpfile.h" #include "tree-pretty-print.h" #include "gimple-pretty-print.h" #include "langhooks.h" #include "stringpool.h" #include "stor-layout.h" #include "diagnostic-core.h" #include "ssa.h" #include "tree-ssanames.h" #include "cfghooks.h" #include "function.h" static void str_reorg_instance_interleave_qual_part ( Info *); static void str_reorg_instance_interleave_type_part ( Info *); static void create_new_types ( Info_t *); static void create_a_new_type ( Info_t *, tree); static unsigned int reorg_perf_qual ( Info *); static tree find_coresponding_field ( tree, tree); // These are local to this file by design #define REORG_SP_PTR_PREFIX "_reorg_SP_ptr_type_" #define REORG_SP_PREFIX "_reorg_base_type_" #define REORG_SP_BASE_PREFIX "_reorg_base_var_" int str_reorg_instance_interleave_qual ( Info *info) { // this is the qualification code for instance interleaving // str_reorg_instance_interleave_qual_part ( info); // this modifiies the qualified types. // str_reorg_instance_interleave_type_part ( info); return 0; } int str_reorg_instance_interleave_trans ( Info *info) { DEBUG_L("Start of str_reorg_instance_interleave_trans:\n"); DEBUG_F( print_program, stderr, 4); struct cgraph_node *node; FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) { struct function *func = DECL_STRUCT_FUNCTION ( node->decl); // Ulgy GCC idiom with global pointer to current function. push_cfun ( func); if ( info->show_transforms ) { fprintf( info->reorg_dump_file, "Function \"%s\":\n", //IDENTIFIER_POINTER( DECL_NAME( func))); //IDENTIFIER_POINTER( DECL_NAME( func->decl))); lang_hooks.decl_printable_name ( node->decl, 2)); } basic_block bb; FOR_EACH_BB_FN ( bb, func) { if( info->show_transforms ) { fprintf( info->reorg_dump_file, " Transforming BB%i:\n", bb->index); } gimple_stmt_iterator outer_gsi; gimple_stmt_iterator next_gsi; for ( outer_gsi = gsi_start_bb ( bb); !gsi_end_p ( outer_gsi); outer_gsi = next_gsi ) { next_gsi = outer_gsi; gsi_next ( &next_gsi); // Every statement that uses a reorg type needs to // be examined. Some are harmless and are skipped // whereas others are transformed. However, anything // else is an error. gimple *stmt = gsi_stmt ( outer_gsi); ReorgType_t *ri = contains_a_reorgtype( stmt, info); if ( ri == NULL ) { DEBUG_L("No Transfrom on: "); DEBUG_F( print_gimple_expr, stderr, stmt, 4, TDF_SLIM); DEBUG("\n"); } else { DEBUG_F( print_reorg_with_msg, stderr, ri, 0, "reorg from str_reorg_instance_interleave_trans"); enum ReorgTransformation trans = reorg_recognize ( stmt, node, info); // print out trans and stmt if dumping if ( info->show_transforms ) { print_gimple_expr( info->reorg_dump_file, stmt, 4, TDF_SLIM); } switch ( trans) { case ReorgT_StrAssign: DEBUG_L("ReorgT_StrAssign\n"); // TBD /* tree lhs = gimple_assign_lhs( stmt); tree rhs = gimple_assign_rhs( stmt); ReorgOpTrans lope = recognize_op( lhs, info); ReorgOpTrans rope = recognize_op( rhs, info); for each field in ri { // lhs: ReorgT_Array & rhs ReorgT_Struct, ReorgT_Deref, ReorgT_Array // lhs: ReorgT_Struct & rhs ReorgT_Deref, ReorgT_Array // lhs ReorgT_Deref & rhs ReorgT_Struct, ReorgT_Array, ReorgT_Deref A is new ssa // Gimple for loading this element // Question? What if the element is large? Answer is it's OK. switch( rope) { // Not implemented in single pool //case ReorgT_Array: case ReorgT_Struct: generate A <- rhs.field break; case ReorgT_Deref: B,C is new SSA // Note simplification with type_name( rhs) generate B <- concat( REORG_SP_PREFIX, type_name( rhs)) and insert before stmt generate C <- B->"f" and insert before stmt generate A <- C[rhs] and insert before stmt break default: internal_error( "Reached operand default in RHS enum ReorgOpTrans"); } // Gimple for storing this element switch( lope) // Not implemented in single pool //case ReorgT_Array: case ReorgT_Deref: B,C is new SSA // Note simplification with type_name( lhs) generate B <- concat( REORG_SP_PREFIX, type_name( lhs)) and insert before stmt generate C <- B->"f" and insert before stmt // lhs here is a simplification generate A <- C[lhs] and insert before stmt break; case ReorgT_Struct: generate lhs.field <- A break; default: internal_error( "Reached operand default in LHS enum ReorgOpTrans"); } } */ break; case ReorgT_ElemAssign: { //break; gimple_stmt_iterator gsi = gsi_for_stmt( stmt); DEBUG_L("ReorgT_ElemAssign: "); DEBUG_F( print_gimple_stmt, stderr, stmt, 0); DEBUG("\n"); INDENT(2); // Needed for helloworld tree lhs = gimple_assign_lhs( stmt); tree rhs = gimple_assign_rhs1( stmt); bool ro_on_left = tree_contains_a_reorgtype_p ( lhs, info); DEBUG_L( "Reorg on %s\n", ro_on_left ? "left" : "right"); tree ro_side = ro_on_left ? lhs : rhs; tree nonro_side = ro_on_left ? rhs : lhs; switch ( recognize_op ( ro_side, info) ) // "a->f" { case ReorgOpT_Indirect: { DEBUG_L("%s: ", ro_on_left ? "lhs" : "rhs"); DEBUG_F(print_generic_expr,stderr,ro_side,(dump_flags_t)0); DEBUG("\n"); DEBUG_L("ReorgOpT_Indirect\n"); tree orig_field = TREE_OPERAND( ro_side, 1); tree field_type = TREE_TYPE( orig_field); tree base = ri->instance_interleave.base; DEBUG_L("base: %p\n", base); DEBUG_A(" base: "); DEBUG_F(print_generic_expr, stderr, base, (dump_flags_t)0); DEBUG("\n"); tree base_field = find_coresponding_field ( base, orig_field); DEBUG_L("base_field: %p\n", base_field); DEBUG_A(" base_field: "); DEBUG_F(print_generic_expr, stderr, base_field, (dump_flags_t)0); DEBUG("\n"); tree base_field_type = TREE_TYPE( base_field); DEBUG_L("base_field_type: %p\n", base_field_type); DEBUG_A(" base_field_type: "); DEBUG_F(print_generic_expr, stderr, base_field_type, (dump_flags_t)0); DEBUG("\n"); tree field_val_temp = make_temp_ssa_name( field_type, NULL, "field_val_temp"); DEBUG_L("field_val_temp: %p\n", field_val_temp); DEBUG_A(" field_val_temp: "); DEBUG_F(print_generic_expr, stderr, field_val_temp, (dump_flags_t)0); DEBUG("\n"); tree field_val_temp_type = TREE_TYPE(field_val_temp); // debug only DEBUG_L("field_val_temp_type: %p\n", field_val_temp_type); DEBUG_A(" field_val_temp_type: "); DEBUG_F(print_generic_expr, stderr, field_val_temp_type, (dump_flags_t)0); DEBUG("\n"); tree inner_op = TREE_OPERAND( ro_side, 0); DEBUG_L("inner_op: "); DEBUG_F( print_generic_expr, stderr, inner_op, (dump_flags_t)0); DEBUG("\n"); // For either case generate common code: // field_array = _base.f tree field_arry_addr = make_temp_ssa_name( base_field_type, NULL, "field_arry_addr"); DEBUG_L("field_arry_addr: %p\n", field_arry_addr); DEBUG_A(" field_arry_addr: "); DEBUG_F(print_generic_expr, stderr, field_arry_addr, (dump_flags_t)0); DEBUG("\n"); tree field_arry_addr_type = TREE_TYPE(field_arry_addr); DEBUG_L("field_arry_addr_type: %p\n", field_arry_addr_type); DEBUG_A(" field_arry_addr_type: "); DEBUG_F(print_generic_expr, stderr, field_arry_addr_type, (dump_flags_t)0); DEBUG("\n") tree rhs_faa = build3 ( COMPONENT_REF, // ??? //base_field_type, ptr_type_node, // This seems bogus base, //base_field, // This almost certainly is bogus // If this "works" the the types // of fields are messed up. orig_field, NULL_TREE); DEBUG_L("rhs_faa: %p\n", rhs_faa); DEBUG_A(" rhs_faa: "); DEBUG_F(print_generic_expr, stderr, rhs_faa, (dump_flags_t)0); DEBUG("\n"); tree rhs_faa_type = TREE_TYPE( rhs_faa); DEBUG_L("rhs_faa_type: %p\n", rhs_faa_type); DEBUG_A(" rhs_faa_type: "); DEBUG_F(print_generic_expr, stderr, rhs_faa_type, (dump_flags_t)0); DEBUG("\n"); gimple *get_field_arry_addr = gimple_build_assign( field_arry_addr, rhs_faa); DEBUG_L("get_field_arry_addr: "); DEBUG_F( print_gimple_stmt, stderr, get_field_arry_addr, 0); DEBUG("\n"); // index = a tree index = make_temp_ssa_name( ri->pointer_rep, NULL, "index"); gimple *get_index = gimple_build_assign( index, inner_op); gimple *temp_set; gimple *final_set; // offset = index * size_of_field tree size_of_field = TYPE_SIZE_UNIT ( base_field_type); tree offset = make_temp_ssa_name( sizetype, NULL, "offset"); // TBD sizetype ??? gimple *get_offset = gimple_build_assign ( offset, MULT_EXPR, index, size_of_field); // field_addr = field_array + offset // bug fix here (TBD) type must be *double not double tree field_addr = make_temp_ssa_name( base_field_type, NULL, "field_addr"); DEBUG_L("field_addr: %p\n", field_addr); DEBUG_A(" field_addr: "); DEBUG_F(print_generic_expr, stderr, field_addr, (dump_flags_t)0); DEBUG("\n"); tree field_addr_type = TREE_TYPE(field_addr); // debug only DEBUG_L("field_addr_type: %p\n", field_addr_type); DEBUG_A(" field_addr_type: "); DEBUG_F(print_generic_expr, stderr, field_addr_type, (dump_flags_t)0); DEBUG("\n"); gimple *get_field_addr = gimple_build_assign ( field_addr, PLUS_EXPR, field_arry_addr, offset); if ( ro_on_left ) { // With: a->f = rhs // Generate: // temp = rhs temp_set = gimple_build_assign( field_val_temp, rhs); //// field_array[index] = temp //tree elem_to_set = // build4 ( ARRAY_REF, field_type, field_arry_addr, index, // NULL_TREE, NULL_TREE); //final_set = // gimple_build_assign( elem_to_set, field_val_temp); // *field_addr = temp tree lhs_ref = build1 ( MEM_REF, field_type, field_addr); final_set = gimple_build_assign( lhs_ref, field_val_temp); } else { // With: lhs = a->f // Generate: //// temp = field_array[index] //tree elem_to_get = // build4 ( ARRAY_REF, field_type, field_arry_addr, index, // NULL_TREE, NULL_TREE); //temp_set = // gimple_build_assign( field_val_temp, elem_to_get); // temp = *field_addr tree rhs_ref = build1 ( INDIRECT_REF, field_type, field_addr); DEBUG_L("rhs_ref: %p\n", rhs_ref); DEBUG_A(" rhs_ref: "); DEBUG_F(print_generic_expr, stderr, rhs_ref, (dump_flags_t)0); DEBUG("\n"); tree rhs_ref_type = TREE_TYPE( rhs_ref); // bebug only DEBUG_L("rhs_ref_type: %p\n", rhs_ref_type); DEBUG_A(" rhs_ref_type: "); DEBUG_F(print_generic_expr, stderr, rhs_ref_type, (dump_flags_t)0); DEBUG("\n"); temp_set = gimple_build_assign( field_val_temp, rhs_ref); // lhs = temp final_set = gimple_build_assign( lhs, field_val_temp); } DEBUG_L("get_field_arry_addr: "); DEBUG_F( print_gimple_stmt, stderr, get_field_arry_addr, 0); DEBUG("\n"); DEBUG_L("get_index: "); DEBUG_F( print_gimple_stmt, stderr, get_index, 0); DEBUG("\n"); DEBUG_L("get_offset: "); DEBUG_F( print_gimple_stmt, stderr, get_offset, 0); DEBUG("\n"); DEBUG_L("get_field_addr: "); DEBUG_F( print_gimple_stmt, stderr, get_field_addr, 0); DEBUG("\n"); DEBUG_L("temp_set: "); DEBUG_F( print_gimple_stmt, stderr, temp_set, 0); DEBUG("\n"); DEBUG_L("final_set: "); DEBUG_F( print_gimple_stmt, stderr, final_set, 0); DEBUG("\n"); gsi_insert_before( &gsi, get_field_arry_addr, GSI_SAME_STMT); gsi_insert_before( &gsi, get_index, GSI_SAME_STMT); gsi_insert_before( &gsi, get_offset, GSI_SAME_STMT); gsi_insert_before( &gsi, get_field_addr, GSI_SAME_STMT); gsi_insert_before( &gsi, temp_set, GSI_SAME_STMT); // << malformed??? gsi_insert_before( &gsi, final_set, GSI_SAME_STMT); //delete stmt gsi_remove ( &gsi, true); } // end ReorgOpT_Indirect case break; case ReorgOpT_AryDir: // "x[i].f" // Not implemented in single pool internal_error ( "ReorgOpT_AryDir not possible"); default: internal_error ( "Reached operand default for ReorgOpT_Indirect"); } // end recognize_op ( rhs, info) switch } // end ReorgT_ElemAssign case INDENT(-2); break; case ReorgT_If_Null: case ReorgT_If_NotNull: DEBUG_L("ReorgT_If_(Not)Null\n"); /* gimple_cond_set_rhs( stmt, TYPE_MIN_VALUE( pointer_sized_int_node)); */ break; case ReorgT_IfPtrEQ: case ReorgT_IfPtrNE: case ReorgT_IfPtrLT: case ReorgT_IfPtrGT: case ReorgT_IfPtrLE: case ReorgT_IfPtrGE: DEBUG_L("ReorgT_IfPtr*\n"); // Not needed for single pool. break; case ReorgT_PtrPlusInt: // "a = b + i" DEBUG_L("ReorgT_PtrPlusInt\n"); // Needed for hellowotrld /* // Does the type of stmt need to be adjusted? I assume so. // The ReorgType contains the type of the pointer // if so that should probably be used. Note, the variables // should all be of the correct type (but maybe that's // not reflected here. Punting and assigning the types to // the type of pointer_sized_int_node is probably not correct // even though that's the representation. tree type = TREE_TYPE( gimple_assign_lhs( stmt)); tree tmp = make_temp_ssa_name( type, NULL, "PtrPlusInt") gimple *adjust_stmt = gimple_build_assign( tmp, TRUNC_DIV_EXPR, gimple_assign_rhs2( stmt), build_int_cst( type, TYPE_SIZE_UNIT( ri->gcc_type)), NULL_TREE, NULL_TREE); // Note, gimple_set_op is used in limited places so using it // to modify existed code might be problematic. gimple_set_op( stmt, 2, tmp); gsi = gsi_for_stmt( stmt); gsi_insert_before( gsi, adjust_stmt, GSI_SAME_STMT); */ break; case ReorgT_Ptr2Zero: // "a = 0" DEBUG_L("ReorgT_Ptr2Zero\n"); /* // Note, this is way too simple... just saying. gimple_set_op( stmt, 1, TYPE_MIN_VALUE( pointer_sized_int_node)); */ break; case ReorgT_PtrDiff: // "i = a - b" DEBUG_L("ReorgT_PtrDiff\n"); // Do nothing in the single pool case. break; case ReorgT_Adr2Ptr: // "a = &x[i]" DEBUG_L("ReorgT_Adr2Ptr\n"); /* tree *add_stmt = gimple_build_assign( gimple_assign_lhs( stmt);, PLUS_EXPR, gimple_assign_rhs1( stmt), gimple_assign_rhs2( stmt), NULL_TREE, NULL_TREE); gimple_stmt_iterator *gsi = gsi_for_stmt( stmt); gsi_insert_before( gsi, add_stmt, GSI_SAME_STMT); // delete stmt gsi_remove( gsi, true); */ break; case ReorgT_PtrNull: // "x = a == 0" case ReorgT_PtrNotNull: // "x = a != 0" DEBUG_L("ReorgT_Ptr(Not)Null\n"); /* gimple_set_op( stmt, 2, TYPE_MIN_VALUE( pointer_sized_int_node)); */ break; case ReorgT_PtrEQ: // "i = a == b" case ReorgT_PtrNE: // "i = a != b" case ReorgT_PtrLT: // "i = a < b" case ReorgT_PtrLE: // "i = a <= b" case ReorgT_PtrGT: // "i = a > b" case ReorgT_PtrGE: // "i = a >= b" DEBUG_L("ReorgT_Ptr*\n"); // Not needed for single pool. break; case ReorgT_Malloc: #if 1 { DEBUG_L("Transform ReorgT_Malloc\n"); INDENT(2); // Note, unlike other simpler transformations, // this must build new basic blocks to add new // gimple to and use a phi for the final result. // See appendix on malloc transformation for // each comment starting with "FROM." ReorgType_t *ri = contains_a_reorgtype( stmt, info); // FROM len = val/size tree arg = gimple_call_arg( stmt, 0); // TBD: len is new SSA tree val = gimple_call_lhs( stmt); //DEBUG_L("val is: "); //DEBUG_F( print_generic_expr, stderr, val, (dump_flags_t)-1); //DEBUG(", tree code type: %s\n", code_str(TREE_CODE(TREE_TYPE(val)))); //gcc_assert( TREE_CODE( TREE_TYPE(val)) == INDIRECT_REF); gcc_assert( TREE_CODE( TREE_TYPE(val)) == POINTER_TYPE); tree size = TYPE_SIZE_UNIT( TREE_TYPE( TREE_TYPE( val))); // FROM len = val/size (insert before stmt) <== maybe arg/size //tree len = make_temp_ssa_name( sizetype, NULL, "fail_val"); // The above segfaulted ??? note, it's not an idiom seen in gcc tree int_ptrsize_type = signed_type_for ( ptr_type_node); DEBUG_L("int_ptrsize_type = %p\n", int_ptrsize_type); tree len = make_temp_ssa_name ( int_ptrsize_type, NULL, "malloc_len"); gimple_stmt_iterator gsi = gsi_for_stmt( stmt); //gimple *glen = // gimple_build_assign ( len, TRUNC_DIV_EXPR, val, size); gimple *glen = gimple_build_assign ( len, TRUNC_DIV_EXPR, arg, size); gsi_insert_before( &gsi, glen, GSI_SAME_STMT); // Note in other places in this doc this would // be "insert glen before stmt" instead of this but // here we need to create new basic blocks. // FROM edge = split this block after stmt edge new_edge = split_block ( bb, stmt); // FROM before_bb = edge->src // same as this bb basic_block before_bb = new_edge->src; // // FROM after_bb = edge->dest basic_block after_bb = new_edge->dest; // FROM delete edge remove_edge ( new_edge); // FROM prev_bb = before_bb basic_block prev_bb = before_bb; // FROM prev_ok_field is new label tree prev_ok_field_L = create_artificial_label ( UNKNOWN_LOCATION); // FROM after_label is new label tree after_label_L = create_artificial_label ( UNKNOWN_LOCATION); // FROM add goto for prev_ok_field to end of before_bb gimple *goto_pof = gimple_build_goto ( prev_ok_field_L); gsi_insert_before ( &gsi, goto_pof, GSI_SAME_STMT); // TBD insert after??? // FROM failure_bb = create_empty_block(prev_bb) basic_block failure_bb = create_empty_bb ( prev_bb); // FROM make_edge( failure_bb, after_bb, EDGE_FALLTHRU); // TBD set edge probability and flags edge failure_edge = make_edge ( failure_bb, after_bb, EDGE_FALLTHRU); // FROM bad_field is new label tree bad_field_L = create_artificial_label ( UNKNOWN_LOCATION); // FROM delete stmt gsi_remove ( &gsi, true); tree return_type = TREE_TYPE ( arg); tree fail_val = make_temp_ssa_name ( return_type, NULL, "malloc_fail_val"); tree field; tree reorg_type = ri->gcc_type; // is this useful here? tree reorg_pointer_type = ri->pointer_rep; //tree base = ri->reorg_ver_type; //nopers tree base = ri->instance_interleave.base; // loop setup trickery for gimple idioms // // FROM prev_order = failure_bb basic_block prev_order = failure_bb; // FROM prev_bb = before_bb prev_bb = before_bb; // Generate all the real allocation code tree fndecl_malloc = builtin_decl_explicit( BUILT_IN_MALLOC); // This, after the following loop, will hold the start of the // field related code. tree new_ok_field_L; // FROM (for fields) { for( field = TYPE_FIELDS( reorg_type); field; field = DECL_CHAIN( field)) { // FROM res is new SSA // Note, alternative code would substitute ptr_type_node // for null_pointer_node. // This is probably a duplicate of the def of res below. //tree res = // make_temp_ssa_name( null_pointer_node, NULL, "res"); // FROM new_bb = create_empty_block(prev_order); basic_block new_bb = create_empty_bb ( prev_order); // FROM gsi = gsi_start_bb( new_bb) gimple_stmt_iterator gsi = gsi_start_bb ( new_bb); // Note, switching the order of edge creation and // setting dominator seems to make no difference #if 0 // FROM set imm dom new_bb as prev_bb set_immediate_dominator ( CDI_DOMINATORS, new_bb, prev_bb); // FROM make_edge( prev_bb, new_bb, EDGE_TRUE_VALUE); make_edge ( prev_bb, new_bb, EDGE_TRUE_VALUE); #else // TBD set edge probability and flags make_edge ( prev_bb, new_bb, EDGE_TRUE_VALUE); // TBD what happens if I punt on this???? //set_immediate_dominator ( CDI_DOMINATORS, new_bb, prev_bb); #endif // FROM make_edge( new_bb, failure_bb, EDGE_FALSE_VALUE); // TBD set edge probability and flags make_edge ( new_bb, failure_bb, EDGE_FALSE_VALUE); // FROM new_ok_field is new label new_ok_field_L = create_artificial_label ( UNKNOWN_LOCATION); // FROM gsi_insert_after( &gsi, "if( res NE NULL ) // goto new_ok_field; // goto bad_field") tree res = make_temp_ssa_name ( ptr_type_node, NULL, "res"); gimple *gcond = gimple_build_cond ( NE_EXPR, res, null_pointer_node, new_ok_field_L, bad_field_L); // Moved label her from end gimple *gprev_ok_field = gimple_build_label ( prev_ok_field_L); gsi_insert_after ( &gsi, gprev_ok_field, GSI_NEW_STMT); //gsi_insert_after ( &gsi, gcond, GSI_SAME_STMT); gsi_insert_after ( &gsi, gcond, GSI_SAME_STMT); // FROM gsi_insert_after( &gsi, "base.field = res") tree lhs_ass = build3( COMPONENT_REF, ptr_type_node, base, field, NULL_TREE); DEBUG_L("base: %p\n", base); DEBUG_A(" base: "); DEBUG_F(print_generic_expr, stderr, base, (dump_flags_t)0); DEBUG("\n"); DEBUG_L("field: %p\n", field); DEBUG_A(" : "); DEBUG_F(print_generic_expr, stderr, field, (dump_flags_t)0); DEBUG("\n"); tree field_type = TREE_TYPE( field); DEBUG_L("field_type: %p\n", field_type); DEBUG_A(" : "); DEBUG_F(print_generic_expr, stderr, field_type, (dump_flags_t)0); DEBUG("\n"); DEBUG_L("lhs_ass: %p\n", lhs_ass); DEBUG_A(" lhs_ass: "); DEBUG_F(print_generic_expr, stderr, lhs_ass, (dump_flags_t)0); DEBUG("\n"); gimple *gset_field = gimple_build_assign( lhs_ass, res); gsi_insert_after( &gsi, gset_field, GSI_SAME_STMT); // FROM gsi_insert_after( &gsi, "res = malloc( mem_size)") // The alternative to sizetype are long_integer_type_node // and integer_type_node. tree mem_size = make_temp_ssa_name( sizetype, NULL, "malloc_mem_size"); gcall *malloc_call = gimple_build_call( fndecl_malloc, 1, mem_size); gimple_call_set_lhs( malloc_call, res); gsi_insert_after( &gsi, malloc_call, GSI_SAME_STMT); // FROM gsi_insert_after( &gsi, "mem_size = len * field_size") //gimple *gsize = // gimple_build_assign ( mem_size, MULT_EXPR, TYPE_SIZE(field), // len, NULL_TREE, NULL_TREE); gimple *gsize = gimple_build_assign ( mem_size, MULT_EXPR, TYPE_SIZE ( TREE_TYPE ( field)), len); gsi_insert_after( &gsi, gsize, GSI_SAME_STMT); // Moved label to top //// FROM gsi_insert_after( &gsi, prev_ok_field) //gimple *gprev_ok_field = gimple_build_label ( prev_ok_field_L); //gsi_insert_after ( &gsi, gprev_ok_field, GSI_SAME_STMT); // FROM prev_bb = new_bb prev_bb = new_bb; // FROM prev_order = new_bb prev_order = new_bb; // FROM prev_ok_field = new_ok_field prev_ok_field_L = new_ok_field_L; } // create basic block for success // // FROM success_bb = create_empty_block(prev_bb_order); basic_block success_bb = create_empty_bb ( prev_bb); // FROM set imm dom success_bb as prev_bb // TBD let's punt of the dominators for a bit //set_immediate_dominator ( CDI_DOMINATORS, success_bb, prev_bb); // FROM make_edge( prev_bb, success_bb, EDGE_TRUE_VALUE); // TBD set edge probability and flags make_edge ( prev_bb, success_bb, EDGE_TRUE_VALUE); // FROM make_edge( success_bb, after_bb, EDGE_TRUE_VALUE); edge success_edge = make_edge ( success_bb, after_bb, EDGE_TRUE_VALUE); // code in success_bb // // FROM success_val is new SSA tree success_val = make_temp_ssa_name( reorg_pointer_type, NULL, "malloc_success_val"); // FROM gsi = gsi_start_bb( failure_bb) // Reuse the same gsi??? Or create a new one??? //gimple_stmt_iterator gsi = gsi_start_bb ( failure_bb); gsi = gsi_start_bb ( success_bb); // used to be failure_bb // FROM gsi_insert_after( &gsi, "goto after_label") //gimple *goto_al = gimple_build_goto( after_label_L); // Emit the label first and then everything else after it gimple *gnew_ok_field = gimple_build_label ( new_ok_field_L); gsi_insert_after ( &gsi, gnew_ok_field, GSI_NEW_STMT); gimple *goto_al_succ = gimple_build_goto( after_label_L); gsi_insert_after( &gsi, goto_al_succ, GSI_SAME_STMT); // FROM gsi_insert_after( &gsi, "success_val = 0") gimple *set_succ = gimple_build_assign ( success_val, build_int_cst ( reorg_pointer_type, 0)); gsi_insert_after( &gsi, set_succ, GSI_SAME_STMT); // FROM gsi_insert_after( &gsi, new_ok_field ) //gimple *gnew_ok_field = gimple_build_label ( new_ok_field_L); //gsi_insert_after ( &gsi, gnew_ok_field, GSI_SAME_STMT); // add code to after_bb // // FROM gsi = gsi_start_bb( after_bb) // Reuse gsi //gimple_stmt_iterator gsi = gsi_start_bb( after_bb); gsi = gsi_start_bb( after_bb); // put the label first // FROM gsi_insert_after( &gsi, after_label) gimple *gafter_label = gimple_build_label( after_label_L); gsi_insert_after( &gsi, gafter_label, GSI_NEW_STMT); // FROM gsi_insert_after( &gsi, "lhs = "phi(success_val, fail_val) gphi *der_phi = create_phi_node( val, after_bb); // was lhs?? instead of val add_phi_arg( der_phi, success_val, success_edge, UNKNOWN_LOCATION); add_phi_arg( der_phi, fail_val, failure_edge, UNKNOWN_LOCATION); gsi_insert_after( &gsi, der_phi, GSI_SAME_STMT); //// FROM gsi_insert_after( &gsi, after_label) //gimple *gafter_label = gimple_build_label( after_label_L); //gsi_insert_after( &gsi, gafter_label, GSI_SAME_STMT); // Try failure_bb code here #if 1 // if defed on here... moved this // code in failure_bb // // FROM fail_val is new SSA //tree return_type = TREE_TYPE ( arg); //tree fail_val = // make_temp_ssa_name ( return_type, NULL, "fail_val"); // FROM gsi = gsi_start_bb ( failure_bb) gsi = gsi_start_bb ( failure_bb); // Put the label first // FROM gsi_insert_after( &gsi, bad_field ) gimple *gbad_field = gimple_build_label( bad_field_L); gsi_insert_after( &gsi, gbad_field, GSI_NEW_STMT); // FROM gsi_insert_after ( &gsi, "goto after_label") gimple *goto_al = gimple_build_goto ( after_label_L); gsi_insert_after ( &gsi, goto_al, GSI_SAME_STMT); // (per field) { //tree field; // defined above //tree reorg_type = ri->gcc_type; // is this useful here? //tree reorg_pointer_type = ri->pointer_rep; tree fndecl_free = builtin_decl_explicit( BUILT_IN_FREE); //tree base = ri->reorg_ver_type; for( field = TYPE_FIELDS( reorg_type); field; field = DECL_CHAIN( field)) { // FROM gsi_insert_after( &gsi, "base.field = 0") tree lhs_ass = build3( COMPONENT_REF, ptr_type_node, base, field, NULL_TREE); gimple *gzero = gimple_build_assign( lhs_ass, null_pointer_node); gsi_insert_after( &gsi, gzero, GSI_SAME_STMT); // FROM gsi_insert_after( &gsi, "free(field)") // TBD -- I'm tree to_free = make_temp_ssa_name( reorg_pointer_type, NULL, "malloc_to_free"); gcall *free_call = gimple_build_call( fndecl_free, 1, to_free); gsi_insert_after( &gsi, free_call, GSI_SAME_STMT); tree rhs_ass = build3( COMPONENT_REF, ptr_type_node, base, field, NULL_TREE); gimple *gaddr2free = gimple_build_assign( to_free, rhs_ass); gsi_insert_after( &gsi, gaddr2free, GSI_SAME_STMT); } // FROM gsi_insert_after( &gsi, "fail_val = minint") gimple *gretnull = gimple_build_assign ( fail_val, //build_int_cst ( size_type_node, TYPE_MIN_VALUE ( TREE_TYPE ( fail_val))); // ); gsi_insert_after( &gsi, gretnull, GSI_SAME_STMT); //// FROM gsi_insert_after( &gsi, bad_field ) //gimple *gbad_field = gimple_build_label( bad_field_L); //gsi_insert_after( &gsi, gbad_field, GSI_SAME_STMT); #endif DEBUG_L("End of malloc:\n"); DEBUG_F( print_program, stderr, 4); } #endif INDENT(-2); break; case ReorgT_Calloc: DEBUG_L("ReorgT_Calloc\n"); /* // This used to be almost a clone of the old version of // the malloc code above and needs to transformed just like // what was done above to malloc. tree arg = gimple_call_arg( stmt, 0); len is new SSA tree val = gimple_call_lhs( stmt); gcc_assert( TREE_CODE( TREE_TYPE(val)) == INDIRECT_REF); tree size = TYPE_SIZE_UNIT( TREE_TYPE( TREE_TYPE( val))); gimple *glen = gimple_build_assign( len, TRUNC_DIV_EXPR, val, size, NULL_TREE, NULL_TREE); //insert glen before stmt gimple_stmt_iterator stmt_gsi = gsi_for_stmt ( stmt); gsi_link_before( stmt_gsi, glen, GSI_SAME_STMT); tree lfial = create_artificial_label( UNKNOWN_LOCATION); gimple *gfail = gimple_build_label( lfail); tree lnotfial = create_artificial_label( UNKNOWN_LOCATION); gimple *gnotfail = gimple_build_label( lnotfail); tree base = ri->reorg_ver_type; for (each element of base) // TBD <== { // call malloc tree lok = create_artificial_label( UNKNOWN_LOCATION); gimple *glok = gimple_build_label( lok); tree *fndecl = builtin_decl_explicit( BUILT_IN_MALLOC); mem_size is new SSA gimple *gsize = gimple_build_assign( mem_size, MULT_EXPR, TYPE_SIZE(element), len, NULL_TREE, NULL_TREE); insert gsize before stmt gcall *call = gimple_build_call( fndecl, 1, mem_size); mres is new SSA gimple_call_set_lhs( call, mres) insert call before stmt // Set element to return value of malloc. // Note, the devil is in the details here. gen concat( REORG_SP_PREFIX, type_name( lhs) ).element <- mres and insert before stmt // gen test of return gimple *gcond = gimple_build_cond( EQ_EXPR, mres, null_pointer_node, lfail, lok); insert gcond before stmt insert glok before stmt // call memset fndecl = builtin_decl_explicit( BUILT_IN_MEMSET); call = gimple_build_call( fndecl, 3, mres, int_node_zero, mem_size); insert call before stmt } // fake return value of zero gimple *gretzero = gimple_build_assign( lhs, build_int_cst( TYPE_MIN_VALUE( TREE_TYPE(lhs)), 0)); insert gretzero before stmt gimple *ggoto = gimple_build_goto( lnotfail); insert ggoto before stmt insert glab1 before stmt for each element of base { tree fndecl = builtin_decl_explicit( BUILT_IN_FREE); gcall *call = gimple_build_call( fndecl, 1, element); insert call before stmt set element to null } // fake return value of null gimple *gretnull = gimple_build_assign( lhs, build_int_cst( TYPE_MIN_VALUE( TREE_TYPE(lhs)))); insert gretnull before stmt insert gnotfail before stmt delete stmt */ break; case ReorgT_Realloc: DEBUG_L("ReorgT_Realloc\n"); /* // This used to be closely related to the old version of // the malloc code above and needs to transformed just like // what was done above to malloc. tree arg = gimple_call_arg( stmt, 0); len is new SSA tree val = gimple_call_lhs( stmt); gcc_assert( TREE_CODE( TREE_TYPE(val)) == INDIRECT_REF); tree size = TYPE_SIZE_UNIT( TREE_TYPE( TREE_TYPE( val))); gimple *glen = gimple_build_assign( len, TRUNC_DIV_EXPR, val, size, NULL_TREE, NULL_TREE); insert glen before stmt tree lfial = create_artificial_label( UNKNOWN_LOCATION); gimple *gfail = gimple_build_label( lfail); tree lnotfial = create_artificial_label( UNKNOWN_LOCATION); gimple *gnotfail = gimple_build_label( lnotfail); for each field of base { // call malloc tree lok = create_artificial_label( UNKNOWN_LOCATION); gimple *gok = gimple_build_label( lok); tree fndecl = builtin_decl_explicit( BUILT_IN_REALLOC); // but first compute how much to malloc mem_size, var, ptr are new SSA gimple *gsize = gimple_build_assign( mem_size, MULT_EXPR, TYPE_SIZE(field), len, NULL_TREE, NULL_TREE); insert gsize before stmt generate ptr = base.field & insert before stmt gcall *call = gimple_build_call( fndecl, 3, ptr, len, TYPE_SIZE( field)); gimple_call_set_lhs( call, var); insert call before stmt // gen test of return gimple *gcond = gimple_build_cond( EQ_EXPR, var, null_pointer_node, lfail, lok); insert gcond before stmt insert gok before stmt generate base.field = var & insert before stmt } // fake return value of starting address (an index of zero) gimple *gretzero = gimple_build_assign( lhs, // build_int_cst( TYPE_MIN_VALUE( TREE_TYPE(lhs)), 0)); insert gretzero before stmt gimple *ggoto = gimple_build_goto( lnotfail); insert ggoto before stmt insert glab1 before stmt for each element of base { tree fndecl = builtin_decl_explicit( BUILT_IN_FREE); gcall *call = gimple_build_call( fndecl, 1, element); insert call before stmt set element to null } // fake return value of null (minimum value under this scheme) gimple *gretnull = gimple_build_assign( lhs, build_int_cst( TYPE_MIN_VALUE( TREE_TYPE(lhs)))); insert gretnull before stmt insert gnotfail before stmt delete stmt */ break; case ReorgT_Free: DEBUG_L("ReorgT_Free\n"); // We won't free the base because it a global. /* for each element of base { tree fndecl = builtin_decl_explicit( BUILT_IN_FREE); gcall *call = gimple_build_call( fndecl, 1, element); insert call before stmt } delete stmt */ break; case ReorgT_UserFunc: // Needed for helloworld. // TBD The type must be adjusted (maybe.) DEBUG_L("ReorgT_UserFunc\n"); break; case ReorgT_Return: // TBD The type must be adjusted (maybe.) DEBUG_L("ReorgT_Return\n"); break; default: internal_error( "Invalid transformation"); } } } } pop_cfun (); } } static void str_reorg_instance_interleave_qual_part ( Info *info) { // TBD save the return value so we can bypass further // instance interleaving if none of it is profitable. reorg_perf_qual ( info); } static void str_reorg_instance_interleave_type_part ( Info *info) { create_new_types ( info); } static unsigned int reorg_perf_qual ( Info *info) { // TBD use design in doc but mark ReorgTypes // (do_instance_interleave) that qualify instead of deleting them // unless both dead field elimination and field reorderig are not // viable (use do_dead_field_elim and do_field_reorder in // Reorg_type_t.) // For the mean time assume if a ReorgType made it here then it's qualified. for ( int i = 0; i < info->reorg_type->size (); i++ ) { (*(info->reorg_type))[i].do_instance_interleave = true; } } // create_new_types has to crawl "all" the // types, create new types and transform // other types that must be changed. // A type will change when it's a // a pointer to a ReorgType or it contains // an interior pointer to one. static void create_new_types ( Info_t *info) { std::map < tree, BoolPair_t>::iterator tmi; // TBD what is for( tmi = info->struct_types->begin (); tmi != info->struct_types->end (); tmi++ ) { if ( !tmi->second.processed ) create_a_new_type ( info, tmi->first); } } static void create_a_new_type ( Info_t *info, tree type) { bool layout_changed = false; // skip if already processed if ( ( *( info->struct_types))[type].processed ) return; // Implementation note: Check this for infinite recursion. // I don't think it's possible in a sane universe but // pointers to reorganized types can occur, so does that // an issue (not necessarily here.) // Also, is this even necessary? Singletons don't expand // and static arrays are not allowed "yet." tree field; tree new_fields = NULL; for ( field = TYPE_FIELDS ( type); // WHF, I speced reorg_type_prime here??? field; field = DECL_CHAIN ( field)) { // make sure all the interior types are processed // before processing this type if ( TREE_CODE ( field) == RECORD_TYPE ) { create_a_new_type ( info, field); } } ReorgType_t *ri = get_reorgtype_info ( type, info); if ( ri != NULL ) { // From the comment of build_variant_type_copy it might not what // is needed to here. Comment in tree: // "Create a new variant of TYPE, equivalent but distinct." // Now before we panic le'ts give it a try. // tree reorg_type_prime = build_variant_type_copy ( type MEM_STAT_DECL); ri->reorg_ver_type = reorg_type_prime; /* Multi-pool only // Create pointer_rep // this will be a long and a pointer to the // reorg_type_prime tree pointer_rep = lang_hooks.types.make_type( RECORD_TYPE); tree index_name = get_identifier("index"); tree index_field = build_decl( BUILTINS_LOCATION, FIELD_DECL, index_name, long_integer_type_node); tree base_name = get_identifier("base"); tree base_field = build_decl( BUILTINS_LOCATION, FIELD_DECL, base_name, reorg_type_prime); insert_field_into_struct( pointer_rep, index_field); insert_field_into_struct( pointer_rep, base); reorg_type->pointer_rep = pointer_rep; */ tree pointer_rep = make_node ( INTEGER_TYPE); TYPE_PRECISION ( pointer_rep) = TYPE_PRECISION ( pointer_sized_int_node); //DEBUG("Issue with gcc_ of reorg\n"); //DEBUG_F(print_reorg, stderr, 2, ri); const char *gcc_name = identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( ri->gcc_type))); size_t len = strlen ( REORG_SP_PTR_PREFIX) + strlen ( gcc_name); char *name = ( char *)alloca(len + 1); strcpy ( name, REORG_SP_PTR_PREFIX); strcat ( name, gcc_name); TYPE_NAME ( pointer_rep) = get_identifier ( name); ri->pointer_rep = pointer_rep; DEBUG_L("pointer_rep = "); DEBUG_F( print_generic_expr, stderr, pointer_rep, (dump_flags_t)-1); DEBUG("\n"); // TBD ! Some of the key bits from above seem to be missing below. // Specifically make_node for the base type, setting the base // in the ReorgType. // // Note, someplace (probably here) also has to declare a base type // variable (probably globally.) Doesn't this variable also belong // in the ReorgType? // Set name of reorg_type_prime // TBD shouldn't base_type_name be different from gcc_name above const char *base_type_name = identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( ri->gcc_type))); len = strlen ( REORG_SP_PREFIX) + strlen ( base_type_name); char *rec_name = ( char*)alloca ( len + 1); strcpy ( rec_name, REORG_SP_PREFIX); strcat ( rec_name, base_type_name); // Build the new pointer type fields TYPE_NAME ( reorg_type_prime) = get_identifier ( rec_name); tree field; tree new_fields = NULL; for ( field = TYPE_FIELDS ( reorg_type_prime); field; field = DECL_CHAIN ( field)) { //DEBUG_F( print_generic_decl, stderr, field, TDF_DETAILS); // example tree tree_type = TREE_TYPE ( field); tree new_fld_type = build_pointer_type ( tree_type); tree new_decl = build_decl ( DECL_SOURCE_LOCATION (field), VAR_DECL, DECL_NAME (field), new_fld_type); // Missing a bunch of attributes (see tree-nested.c:899) // Let us seee what happens without them! DECL_CHAIN ( new_decl) = new_fields; // <- bug: need decl, not type new_fields = new_decl; //DEBUG( "built new pointer type field:"); //DEBUG_F( print_generic_decl, stderr, new_decl, TDF_DETAILS); //DEBUG( "\n"); } TYPE_FIELDS ( reorg_type_prime) = new_fields; // fix? // store reversed fields back into reorg_type_prime TYPE_FIELDS ( reorg_type_prime) = NULL; tree next_fld; for ( field = new_fields; field; field = next_fld ) { next_fld = DECL_CHAIN ( field); DECL_CHAIN ( field) = TYPE_FIELDS ( reorg_type_prime); TYPE_FIELDS ( reorg_type_prime) = field; } // Fix-up the layout layout_type ( reorg_type_prime); // HERE // Create the base element for a reorg type. This is for the single // pool case only. tree base_var = build_decl ( UNKNOWN_LOCATION, VAR_DECL, NULL_TREE, ri->reorg_ver_type); const char *type_name = identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( ri->gcc_type))); size_t tlen = strlen ( REORG_SP_BASE_PREFIX) + strlen ( type_name); char *base_name = ( char*)alloca ( tlen + 1); strcpy ( base_name, REORG_SP_BASE_PREFIX); //DECL_NAME ( base_var) = get_identifier ( base_name); strcat ( base_name, type_name); DECL_NAME ( base_var) = get_identifier ( base_name); // wrong spot above??? TREE_STATIC ( base_var) = 1; TREE_ADDRESSABLE ( base_var) = 1; DECL_NONALIASED ( base_var) = 1; SET_DECL_ALIGN ( base_var, TYPE_ALIGN ( ri->reorg_ver_type)); varpool_node::finalize_decl ( base_var); ri->instance_interleave.base = base_var; } // Mess with the original type too because it might // have base_type_fldinterior elements that are modified. for ( field = TYPE_FIELDS ( type); field; field = DECL_CHAIN ( field)) { if ( TREE_CODE ( field) == RECORD_TYPE ) { layout_changed = layout_changed || ( *( info->struct_types)) [ field].layout_changed; } else { // process pointers to reorg types if ( POINTER_TYPE_P ( field) ) { tree field_type = TREE_TYPE ( field); if ( is_reorg_type ( field_type, info) ) { // Change field type. // If multi-pool then set layout_changed to true. // The type pointed to changes for single-pool. ReorgType_t *ri = get_reorgtype_info ( field_type, info); TREE_TYPE ( field) = ri->pointer_rep; } tree base = base_type_of ( field); if ( is_reorg_type ( base, info) ) { // strip off a layer of pointers TREE_TYPE ( field) = TREE_TYPE ( TREE_TYPE( field)); } } } } // Mark the type as processed ( *( info->struct_types)) [ type] = { true, layout_changed}; } static tree find_coresponding_field ( tree base_decl, tree field) { tree reorg_field; for ( reorg_field = TYPE_FIELDS ( TREE_TYPE ( base_decl)); reorg_field; reorg_field = DECL_CHAIN ( reorg_field)) { const char *reorg_field_name = lang_hooks.decl_printable_name ( reorg_field, 2); const char *field_name = lang_hooks.decl_printable_name ( field, 2); //DEBUG_L("LOOK %s, %s\n", reorg_field_name, field_name); if ( strcmp ( reorg_field_name, field_name) == 0 ) { gcc_assert ( TREE_TYPE( field) == TREE_TYPE( TREE_TYPE(reorg_field))); return reorg_field; } } internal_error ( "find_coresponding_field: found no field"); }