Author: dcoakley Date: 2011-07-18 19:22:29 -0400 (Mon, 18 Jul 2011) New Revision: 3697
Modified: trunk/osprey/be/com/fb_whirl.cxx trunk/osprey/be/com/fb_whirl.h trunk/osprey/be/com/wn_lower.cxx trunk/osprey/be/opt/opt_cfg.cxx trunk/osprey/be/opt/opt_cfg.h trunk/osprey/common/com/config.h trunk/osprey/common/com/config_opt.cxx trunk/osprey/common/com/fb_freq.h trunk/osprey/common/com/wn.cxx trunk/osprey/common/com/wn.h Log: Enable more if-conversion in WOPT. Convert: if (a && b) x = ... To: if (a) if (b) x = ... Without this transformation, WHIRL-lowering creates control flow that WOPT-if-conversion can't handle. With this transformation, this now looks like any other if-conversion opportunity to WOPT. So this transformation enables more if-conversion (i.e. replace branch with conditional move). The transformation is enabled when the internal flag OPT_Lower_Splitsinglecand is on (the default) and when if-conversion is enabled in WOPT. It is applied when the action flag LOWER_SHORTCIRCUIT is set (mainopt phase). As part of the transformation, all profile info is updated to be consistent: in-edge weights equal out-edge weights, all new edges have weights, overall incoming/outgoing frequency to the original node does not change, and the frequency of "if a && b" is true is equal to the frequency of "if a/if b" is true. Approved by: Sun Chan Modified: trunk/osprey/be/com/fb_whirl.cxx =================================================================== --- trunk/osprey/be/com/fb_whirl.cxx 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/be/com/fb_whirl.cxx 2011-07-18 23:22:29 UTC (rev 3697) @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Advanced Micro Devices, Inc. All Rights Reserved. + * Copyright (C) 2010-2011 Advanced Micro Devices, Inc. All Rights Reserved. */ /* @@ -1417,6 +1417,81 @@ } } +// When transforming: +// From: +// if (a && b) { +// x = ... +// } +// else { +// <empty> +// } +// To: +// if (a) { +// if (b) { +// x = ... +// } +// else { +// <empty> +// } +// } +// else { +// <empty> +// } +// +// We adjust the frequency data as follows: +// From: +// if (a && b) +// TK / \ NT +// / \ +// To: +// +// if (a) +// TKnew / \ NTnew +// / \ +// if (b) +// TKinner / \ NTinner +// / \ +// Where: +// TOT = TK + NT +// TK% = TK / TOT +// TK%new = sqrt(TK%) +// TKnew = TOT * TK%new +// NTnew = TOT - TKnew +// TKinner = TKnew * TK%new +// NTinner = TKnew - TKinner +// +void +FEEDBACK::FB_split_cand_if( WN *wn_outer_if, WN *wn_inner_if ) +{ + if ( _trace ) + fprintf( TFile, "FEEDBACK::FB_split_cand(0x%p, 0x%p):\n", + wn_outer_if, wn_inner_if ); + + Is_True( wn_outer_if != NULL && wn_inner_if != NULL, + ( "FEEDBACK::FB_cplit_can expects non-NULL wn_outer_if and wn_inner_if" ) ); + + Is_True( WN_operator( wn_outer_if ) == OPR_IF && + WN_operator( wn_inner_if ) == OPR_IF, + ( "FEEDBACK::FB_split_cand expects IF wn_outer_if and wn_inner_if" ) ); + + const FB_Info_Branch& info_branch = Query_branch( wn_outer_if ); + FB_FREQ freq_tkn = info_branch.freq_taken; + FB_FREQ freq_not = info_branch.freq_not_taken; + FB_FREQ freq_total = freq_tkn + freq_not; + FB_FREQ freq_tkn_pct = freq_tkn / freq_total; + FB_FREQ freq_tkn_pct_new = freq_tkn_pct.sqrt(); + FB_FREQ freq_tkn_new_outer = freq_total * freq_tkn_pct_new; + FB_FREQ freq_not_new_outer = freq_total - freq_tkn_new_outer; + Annot_branch( wn_outer_if, FB_Info_Branch( freq_tkn_new_outer, + freq_not_new_outer, + OPR_IF ) ); + FB_FREQ freq_tkn_new_inner = freq_tkn_new_outer * freq_tkn_pct_new; + FB_FREQ freq_not_new_inner = freq_tkn_new_outer - freq_tkn_new_inner; + Annot_branch( wn_inner_if, FB_Info_Branch( freq_tkn_new_inner, + freq_not_new_inner, + OPR_IF ) ); +} + // ==================================================================== // The following procedures update the feedback information for whirl // nodes created or modified during lowering transformations. Modified: trunk/osprey/be/com/fb_whirl.h =================================================================== --- trunk/osprey/be/com/fb_whirl.h 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/be/com/fb_whirl.h 2011-07-18 23:22:29 UTC (rev 3697) @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Advanced Micro Devices, Inc. All Rights Reserved. + * Copyright (C) 2010-2011 Advanced Micro Devices, Inc. All Rights Reserved. */ /* -*- c++ -*- @@ -271,6 +271,7 @@ // Lower feedback info + void FB_split_cand_if ( WN *wn_outer_if, WN *wn_inner_if ); void FB_lower_branch ( WN *wn_br, WN *wn_branch ); void FB_lower_circuit ( WN *wn_cand, WN *wn_left_br, WN *wn_right_br ); void FB_factor_circuit( WN *wn_left, WN *wn_right, Modified: trunk/osprey/be/com/wn_lower.cxx =================================================================== --- trunk/osprey/be/com/wn_lower.cxx 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/be/com/wn_lower.cxx 2011-07-18 23:22:29 UTC (rev 3697) @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. All Rights Reserved. + * Copyright (C) 2008-2011 Advanced Micro Devices, Inc. All Rights Reserved. */ /* @@ -118,6 +118,7 @@ #include "targ_const_private.h" // for TCON_R4, TCON_R8, .. #endif #include "be_memop_annot.h" +#include "config_wopt.h" // for WOPT_Enable_Simple_If_Conv #ifdef TARG_X8664 #include <ext/hash_set> @@ -13694,6 +13695,96 @@ } #endif +/* Similar to above tree_has_cand_cior, but more specialized. Check if: + * - tree's op is a CAND + * - tree has no other nested cand/cor/cselect + */ +static BOOL tree_has_only_one_cand (WN *tree) +{ + WN_ITER *wni; + WN *wn; + INT count = 0; + + if (WN_operator(tree) != OPR_CAND) + return 0; + for (wni = WN_WALK_TreeIter (tree); + wni != NULL; + wni = WN_WALK_TreeNext (wni)) + { + wn = WN_ITER_wn (wni); + if (WN_operator_is(wn, OPR_CAND)) + ++count; + if (WN_operator_is(wn, OPR_CIOR) || + WN_operator_is(wn, OPR_CSELECT)) + return 0; + } + return (count == 1); +} + +/* =================================================================== + * In order to enable if-conversion in WOPT, tranform: + * + * From: + * if (a && b) { + * x = ... + * } + * else { + * <empty> + * } + * + * To: + * if (a) { + * if (b) { + * x = ... + * } + * else { + * <empty> + * } + * } + * else { + * <empty> + * } + * ================================================================== + */ +static void lower_split_single_cand(WN * tree, LOWER_ACTIONS actions) +{ + FmtAssert(WN_operator(tree) == OPR_IF, ("Expect a if-condition")); + + if (WN_block_nonempty(WN_then(tree)) && + !WN_block_nonempty(WN_else(tree)) && + tree_has_only_one_cand(WN_if_test(tree)) && + WN_is_assign(WN_then(tree))) + { + WN *outer_then = WN_then(tree); + INT64 if_line = WN_Get_Linenum(tree); + INT64 then_line = WN_Get_Linenum(WN_then(tree)); + INT64 else_line = WN_Get_Linenum(WN_else(tree)); + WN *outer_cond = lower_copy_tree(WN_kid0(WN_if_test(tree)), actions); + WN *inner_cond = lower_copy_tree(WN_kid1(WN_if_test(tree)), actions); + WN_DELETE_Tree(WN_if_test(tree)); + WN_if_test(tree) = outer_cond; + WN *inner_then_block = WN_CreateBlock(); + WN_Set_Linenum(inner_then_block, if_line); + WN *inner_else_block = WN_CreateBlock(); + WN_Set_Linenum(inner_else_block, else_line); + WN *inner_if = WN_CreateIf(inner_cond, inner_then_block, inner_else_block); + WN_Set_Linenum(inner_if, if_line); + WN * wn_next; + // Move statements from outer-then clause to new inner-then clause. + for (WN * wn_tmp = WN_first(outer_then); wn_tmp; wn_tmp = wn_next) + { + wn_next = WN_next(wn_tmp); + WN_INSERT_BlockLast(inner_then_block, lower_copy_tree(wn_tmp, actions)); + WN_DELETE_FromBlock(outer_then, wn_tmp); + } + WN_INSERT_BlockLast(outer_then, inner_if); + if (Cur_PU_Feedback) + { + Cur_PU_Feedback->FB_split_cand_if( tree, inner_if ); + } + } +} + /* ==================================================================== * * WN *lower_if(WN *block, WN *tree, LOWER_ACTIONS actions, WN ** ret_next) @@ -13739,7 +13830,17 @@ lower_simp_if_flip(tree, actions, ret_next); lower_simp_bit_and(tree, actions); } - + + // Check for special case, to enable more if-conversion. Do not check if: + // - disabled (OPT_Lower_Splitsinglecand == 0) + // or + // - if-conversion not enabled (WOPT_Enable_Simple_If_Conv < 1) + if (Action(LOWER_SHORTCIRCUIT) && + OPT_Lower_Splitsinglecand && WOPT_Enable_Simple_If_Conv >= 1) + { + lower_split_single_cand(tree, actions); + } + #ifndef SHORTCIRCUIT_HACK if (Action(LOWER_IF)) #else Modified: trunk/osprey/be/opt/opt_cfg.cxx =================================================================== --- trunk/osprey/be/opt/opt_cfg.cxx 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/be/opt/opt_cfg.cxx 2011-07-18 23:22:29 UTC (rev 3697) @@ -1602,28 +1602,6 @@ return FALSE; } -BOOL CFG::wn_is_assign(WN *wn) -{ - WN *wn_first = WN_first(wn); - WN *wn_last = WN_last(wn); - return ((wn_first && (wn_first == wn_last) && OPERATOR_is_store(WN_operator(wn_first))) - || WN_operator(wn) == OPR_SELECT); -} - -BOOL CFG::wn_is_assign_return(WN *wn) -{ - WN *wn_first = WN_first(wn); - WN *wn_last = WN_last(wn); - - if (wn_last) { - WN *wn_last_prev = WN_prev(WN_last(wn)); - return ((WN_operator(wn_last) == OPR_RETURN) - && (wn_first == wn_last_prev) && OPERATOR_is_store(WN_operator(wn_first))); - } else { - return FALSE; - } -} - BOOL CFG::Cand_is_return_inside_select(WN *wn) { FmtAssert(WN_operator(wn) == OPR_IF, ("Extract_Return: Unexpected WN")); @@ -1654,12 +1632,12 @@ return FALSE; /* then is not empty and not assign-return, return FALSE */ - if (then_wn_prev && !wn_is_assign_return(then_wn)) { + if (then_wn_prev && !WN_is_assign_return(then_wn)) { return FALSE; } /* then is not empty and not assign-return, return FALSE */ - if (else_wn_prev && !wn_is_assign_return(else_wn)) { + if (else_wn_prev && !WN_is_assign_return(else_wn)) { return FALSE; } @@ -1720,11 +1698,11 @@ return FALSE; // either the else-stmt is empty or has one assignment - if (!empty_else && !(wn_is_assign(else_wn))) + if (!empty_else && !(WN_is_assign(else_wn))) return FALSE; // either the then-stmt is empty or has one assignment - if (!empty_then && !wn_is_assign(then_wn)) + if (!empty_then && !WN_is_assign(then_wn)) return FALSE; // both the then and else are empty or has one assignment with same lhs Modified: trunk/osprey/be/opt/opt_cfg.h =================================================================== --- trunk/osprey/be/opt/opt_cfg.h 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/be/opt/opt_cfg.h 2011-07-18 23:22:29 UTC (rev 3697) @@ -378,8 +378,6 @@ INT Is_simple_expr(WN *wn); void Lower_if_stmt(WN *wn, END_BLOCK *ends_bb ); WN *if_convert(WN *wn); - BOOL wn_is_assign(WN *wn); - BOOL wn_is_assign_return(WN *wn); BOOL wn_is_return_convert(WN *wn); // add various high-level construct statements to CFG so they can // later be raised back up (mostly preopt phase) Modified: trunk/osprey/common/com/config.h =================================================================== --- trunk/osprey/common/com/config.h 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/common/com/config.h 2011-07-18 23:22:29 UTC (rev 3697) @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. All Rights Reserved. + * Copyright (C) 2008-2011 Advanced Micro Devices, Inc. All Rights Reserved. */ /* @@ -583,6 +583,7 @@ extern BOOL OPT_unroll_times_overridden; extern INT32 OPT_unroll_size; extern BOOL OPT_unroll_size_overridden; +extern BOOL OPT_Lower_Splitsinglecand; extern BOOL OPT_Lower_Speculate; extern BOOL OPT_Lower_Treeheight; extern BOOL OPT_Inline_Divide; Modified: trunk/osprey/common/com/config_opt.cxx =================================================================== --- trunk/osprey/common/com/config_opt.cxx 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/common/com/config_opt.cxx 2011-07-18 23:22:29 UTC (rev 3697) @@ -228,6 +228,8 @@ BOOL OPT_Reorg_Common_Set = FALSE; /* ... option seen? */ BOOL OPT_Unroll_Analysis = TRUE; /* Enable unroll limitations? */ BOOL OPT_Unroll_Analysis_Set = FALSE; /* ... option seen? */ +BOOL OPT_Lower_Splitsinglecand = TRUE; +BOOL OPT_Lower_Splitsinglecand_Set = FALSE; #if defined(TARG_NVISA) BOOL OPT_Lower_Speculate = TRUE; /* speculate CAND/CIOR */ #else @@ -720,6 +722,10 @@ 0, 0, 0, &OPT_Space, NULL, "Bias optimizations to minimize code space" }, + { OVK_BOOL, OV_INTERNAL, TRUE, "split_single_cand", "", + 0, 0, 0, &OPT_Lower_Splitsinglecand, &OPT_Lower_Splitsinglecand_Set, + "Allow splitting of single CAND for enabling if_conversion" }, + { OVK_BOOL, OV_INTERNAL, TRUE, "speculate", "", 0, 0, 0, &OPT_Lower_Speculate, &OPT_Lower_Speculate_Set, "Allow speculation for CAND/COR operators" }, Modified: trunk/osprey/common/com/fb_freq.h =================================================================== --- trunk/osprey/common/com/fb_freq.h 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/common/com/fb_freq.h 2011-07-18 23:22:29 UTC (rev 3697) @@ -97,6 +97,7 @@ #ifndef fb_freq_INCLUDED #define fb_freq_INCLUDED +#include <math.h> #include "defs.h" #ifndef ERRORS_INCLUDED #include "errors.h" @@ -310,6 +311,17 @@ return FB_FREQ_TYPE_BETTER( _type, freq._type ); } + FB_FREQ sqrt() { + if ( Zero() && Exact() ) + return FB_FREQ( FB_FREQ_TYPE_EXACT, 0.0 ); + FB_FREQ_TYPE type = FB_FREQ_TYPE_COMBINE( _type, FB_FREQ_TYPE_GUESS ); + if ( FB_FREQ_TYPE_NOT_KNOWN( type ) ) + return FB_FREQ( type ); + Is_True( _value >= 0, ( "FB_FREQ: negative value %ld", _value ) ); + return FB_FREQ( type, ::sqrt((double)_value) ); + return *this; + } + // Operators FB_FREQ operator+= ( const FB_FREQ freq ) { Modified: trunk/osprey/common/com/wn.cxx =================================================================== --- trunk/osprey/common/com/wn.cxx 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/common/com/wn.cxx 2011-07-18 23:22:29 UTC (rev 3697) @@ -3753,3 +3753,27 @@ return NULL; } + +BOOL +WN_is_assign(WN * wn) +{ + WN *wn_first = WN_first(wn); + WN *wn_last = WN_last(wn); + return ((wn_first && (wn_first == wn_last) && OPERATOR_is_store(WN_operator(wn_first))) + || WN_operator(wn) == OPR_SELECT); +} + +BOOL +WN_is_assign_return(WN * wn) +{ + WN *wn_first = WN_first(wn); + WN *wn_last = WN_last(wn); + + if (wn_last) { + WN *wn_last_prev = WN_prev(WN_last(wn)); + return ((WN_operator(wn_last) == OPR_RETURN) + && (wn_first == wn_last_prev) && OPERATOR_is_store(WN_operator(wn_first))); + } else { + return FALSE; + } +} Modified: trunk/osprey/common/com/wn.h =================================================================== --- trunk/osprey/common/com/wn.h 2011-07-18 20:10:34 UTC (rev 3696) +++ trunk/osprey/common/com/wn.h 2011-07-18 23:22:29 UTC (rev 3697) @@ -1546,7 +1546,9 @@ extern BOOL WN_has_const_diff(WN *, WN *, int *); extern BOOL WN_has_compatible_iter_space(WN *, WN *, int *, int *, BOOL); - +extern BOOL WN_is_assign(WN *); +extern BOOL WN_is_assign_return(WN *); + #if defined(TARG_SL) extern WN* WN_CreateFork(INT32 label_number, BOOL major); extern BOOL WN_Intrinsic_OP_Slave(WN * wn); ------------------------------------------------------------------------------ Storage Efficiency Calculator This modeling tool is based on patent-pending intellectual property that has been used successfully in hundreds of IBM storage optimization engage- ments, worldwide. Store less, Store more with what you own, Move data to the right place. Try It Now! http://www.accelacomm.com/jaw/sfnl/114/51427378/ _______________________________________________ Open64-devel mailing list Open64-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/open64-devel