[PATCH][RFC] Come up with -flive-patching master option.

Martin Liška mliska@suse.cz
Wed Nov 14 15:03:00 GMT 2018


On 11/13/18 10:16 PM, Qing Zhao wrote:
> Hi,
> 
>> On Nov 13, 2018, at 1:18 PM, Miroslav Benes <mbenes@suse.cz> wrote:
>>
>>> Attached is the patch for new -flive-patching=[inline-only-static | inline-clone] master option.
>>>
>>> '-flive-patching=LEVEL'
>>>     Control GCC's optimizations to provide a safe compilation for
>>>     live-patching.  Provides multiple-level control on how many of the
>>>     optimizations are enabled by users' request.  The LEVEL argument
>>>     should be one of the following:
>>>
>>>     'inline-only-static'
>>>
>>>          Only enable inlining of static functions, disable all other
>>>          ipa optimizations/analyses.  As a result, when patching a
>>>          static routine, all its callers need to be patches as well.
>>>
>>>     'inline-clone'
>>>
>>>          Only enable inlining and all optimizations that internally
>>>          create clone, for example, cloning, ipa-sra, partial inlining,
>>>          etc.; disable all other ipa optimizations/analyses.  As a
>>>          result, when patching a routine, all its callers and its
>>>          clones' callers need to be patched as well.
>> Based on our previous discussion I assume that "clone" optimizations are 
>> safe (for LP) and the others are not. Anyway I'd welcome a note mentioning 
>> that disabled optimizations are dangerous for LP.
> actually, I don’t think that those disabled optimizations are “dangerous” for live-patching. one of the major reasons we disable them
> is because that currently the compiler does NOT provide a good way to compute the impacted function list for those optimizations.
> therefore, we disable them at this time. 
> 
> many of them could be enabled too if the compiler can report the impacted function list accurately in the future.
> 
> 
> 
>> I know it may be the same for you, but it is not for me as a GCC user. 
>> "internally create clone" sounds very... well, internal. It does not 
>> describe the option much for ordinary user whow has no knowledge about GCC 
>> internals.
>>
>> So could you rephrase it a bit, please?
> I tried to make this clear. please see the following:
> 
> '-flive-patching=LEVEL'
>      Control GCC's optimizations to provide a safe compilation for
>      live-patching.
> 
>      If the compiler's optimization uses a function's body or
>      information extracted from its body to optimize/change another
>      function, the latter is called an impacted function of the former.
>      If a function is patched, its impacted functions should be patched
>      too.
> 
>      The impacted functions are decided by the compiler's
>      interprocedural optimizations.  For example, inlining a function
>      into its caller, cloning a function and changing its caller to call
>      this new clone, or extracting a function's pureness/constness
>      information to optimize its direct or indirect callers, etc.
> 
>      Usually, the more ipa optimizations enabled, the larger the number
>      of impacted functions for each function.  In order to control the
>      number of impacted functions and computed the list of impacted
>      function easily, we provide control to partially enable ipa
>      optimizations on two different levels.
> 
>      The LEVEL argument should be one of the following:
> 
>      'inline-only-static'
> 
>           Only enable inlining of static functions, disable all other
>           interprocedural optimizations/analyses.  As a result, when
>           patching a static routine, all its callers need to be patches
>           as well.
> 
>      'inline-clone'
> 
>           Only enable inlining and cloning optimizations, which includes
>           inlining, cloning, interprocedural scalar replacement of
>           aggregates and partial inlining.  Disable all other
>           interprocedural optimizations/analyses.  As a result, when
>           patching a routine, all its callers and its clones' callers
>           need to be patched as well.
> 
>      When -flive-patching specified without any value, the default value
>      is "inline-clone".
> 
>      This flag is disabled by default.
> 
> 
>>>     When -flive-patching specified without any value, the default value
>>>     is "inline-clone".
>>>
>>>     This flag is disabled by default.
>>>
>>> let me know your comments and suggestions on the implementation.
>> I compared it to Martin's patch and ipa-icf-variables is not covered in 
>> yours (I may have missed something).
> Yes, you are right. I added this into my patch.
> 
> I am attaching the new patch here.

Hello.

Please use
git diff HEAD~ > /tmp/patch && ~/Programming/gcc/contrib/check_GNU_style.py /tmp/patch

in order to address many formatting issues of the patch (skip the ones reported in common.opt).

> 
> 
> flive-patching.patch
> 
> From c0785675eb29599754aaf11c70901c12dd3ea821 Mon Sep 17 00:00:00 2001
> From: qing zhao <qing.zhao@oracle.com>
> Date: Tue, 13 Nov 2018 13:02:57 -0800
> Subject: [PATCH] Add -flive-patching to support live patching
> 
> ---
>  gcc/cif-code.def                       |  6 +++
>  gcc/common.opt                         | 18 +++++++++
>  gcc/doc/invoke.texi                    | 49 +++++++++++++++++++++++-
>  gcc/flag-types.h                       |  8 ++++
>  gcc/ipa-inline.c                       |  6 +++
>  gcc/opts.c                             | 68 ++++++++++++++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/live-patching-1.c | 22 +++++++++++
>  7 files changed, 176 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gcc.dg/live-patching-1.c
> 
> diff --git a/gcc/cif-code.def b/gcc/cif-code.def
> index 19a7621..dffe15f 100644
> --- a/gcc/cif-code.def
> +++ b/gcc/cif-code.def
> @@ -132,6 +132,12 @@ DEFCIFCODE(USES_COMDAT_LOCAL, CIF_FINAL_ERROR,
>  DEFCIFCODE(ATTRIBUTE_MISMATCH, CIF_FINAL_ERROR,
>  	   N_("function attribute mismatch"))
>  
> +/* We can't inline because the user requests only static functions 
> +   but the function has external linkage for live patching purpose.  */
> +DEFCIFCODE(EXTERN_LIVE_ONLY_STATIC, CIF_FINAL_ERROR,
> +	   N_("function has external linkage when the user requests only"
> +	      " inlining static for live patching"))
> +
>  /* We proved that the call is unreachable.  */
>  DEFCIFCODE(UNREACHABLE, CIF_FINAL_ERROR,
>  	   N_("unreachable"))
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 98e8eb0..346a361 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2152,6 +2152,24 @@ starts and when the destructor finishes.
>  flifetime-dse=
>  Common Joined RejectNegative UInteger Var(flag_lifetime_dse) Optimization IntegerRange(0, 2)
>  
> +flive-patching
> +Common RejectNegative Alias(flive-patching=,inline-clone) Optimization
> +
> +flive-patching=
> +Common Report Joined RejectNegative Enum(live_patching_level) Var(flag_live_patching) Init(LIVE_NONE) Optimization
> +-flive-patching=[inline-only-static|inline-clone]	Control ipa optimizations to provide a 

Please use 'IPA' instead of 'ipa', similarly in documentation.

> +safe compilation for live-patching. At the same time, provides multiple-level control on the  
> +enabled optimizations. 
> +
> +Enum
> +Name(live_patching_level) Type(enum live_patching_level) UnknownError(unknown Live-Patching Level %qs)
> +
> +EnumValue
> +Enum(live_patching_level) String(inline-only-static) Value(LIVE_INLINE_ONLY_STATIC)
> +
> +EnumValue
> +Enum(live_patching_level) String(inline-clone) Value(LIVE_INLINE_CLONE)
> +
>  flive-range-shrinkage
>  Common Report Var(flag_live_range_shrinkage) Init(0) Optimization
>  Relief of register pressure through live range shrinkage.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 4ea93a7..c473049 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -411,10 +411,11 @@ Objective-C and Objective-C++ Dialects}.
>  -fgcse-sm  -fhoist-adjacent-loads  -fif-conversion @gol
>  -fif-conversion2  -findirect-inlining @gol
>  -finline-functions  -finline-functions-called-once  -finline-limit=@var{n} @gol
> --finline-small-functions  -fipa-cp  -fipa-cp-clone @gol
> +-finline-small-functions -fipa-cp  -fipa-cp-clone @gol

This changes is probably not intended.

>  -fipa-bit-cp -fipa-vrp @gol
>  -fipa-pta  -fipa-profile  -fipa-pure-const  -fipa-reference  -fipa-reference-addressable @gol
>  -fipa-stack-alignment  -fipa-icf  -fira-algorithm=@var{algorithm} @gol
> +-flive-patching=@var{level} @gol
>  -fira-region=@var{region}  -fira-hoist-pressure @gol
>  -fira-loop-pressure  -fno-ira-share-save-slots @gol
>  -fno-ira-share-spill-slots @gol
> @@ -8982,6 +8983,52 @@ equivalences that are found only by GCC and equivalences found only by Gold.
>  
>  This flag is enabled by default at @option{-O2} and @option{-Os}.
>  
> +@item -flive-patching=@var{level}
> +@opindex flive-patching
> +Control GCC's optimizations to provide a safe compilation for live-patching.
> +
> +If the compiler's optimization uses a function's body or information extracted 
> +from its body to optimize/change another function, the latter is called an
> +impacted function of the former.  If a function is patched, its impacted
> +functions should be patched too.
> +
> +The impacted functions are decided by the compiler's interprocedural
> +optimizations. For example, inlining a function into its caller, cloning 
> +a function and changing its caller to call this new clone, or extracting
> +a function's pureness/constness information to optimize its direct or 
> +indirect callers, etc.
> +
> +Usually, the more ipa optimizations enabled, the larger the number of
> +impacted functions for each function. In order to control the number of
> +impacted functions and computed the list of impacted function easily, 
> +we provide control to partially enable ipa optimizations on two different 
> +levels.
> +
> +The @var{level} argument should be one of the following:
> +
> +@table @samp
> +
> +@item inline-only-static
> +
> +Only enable inlining of static functions, disable all other interprocedural 
> +optimizations/analyses. As a result, when patching a static routine,
> +all its callers need to be patches as well.
> +
> +@item inline-clone 
> +
> +Only enable inlining and cloning optimizations, which includes inlining, 
> +cloning, interprocedural scalar replacement of aggregates and partial inlining.
> +Disable all other interprocedural optimizations/analyses.
> +As a result, when patching a routine, all its callers and its clones'
> +callers need to be patched as well.
> +
> +@end table
> +
> +When -flive-patching specified without any value, the default value
> +is "inline-clone".
> +
> +This flag is disabled by default.
> +
>  @item -fisolate-erroneous-paths-dereference
>  @opindex fisolate-erroneous-paths-dereference
>  Detect paths that trigger erroneous or undefined behavior due to
> diff --git a/gcc/flag-types.h b/gcc/flag-types.h
> index 500f663..72e0f0f 100644
> --- a/gcc/flag-types.h
> +++ b/gcc/flag-types.h
> @@ -123,6 +123,14 @@ enum stack_reuse_level
>    SR_ALL
>  };
>  
> +/* The live patching level. */
> +enum live_patching_level
> +{
> +  LIVE_NONE = 0,
> +  LIVE_INLINE_ONLY_STATIC,
> +  LIVE_INLINE_CLONE

Maybe better LIVE_PATCHING_INLINE_CLONE, without the 'PATCHING' the enum
values are bit unclear.

> +};
> +
>  /* The algorithm used for basic block reordering.  */
>  enum reorder_blocks_algorithm
>  {
> diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
> index e04ede7..fadb437 100644
> --- a/gcc/ipa-inline.c
> +++ b/gcc/ipa-inline.c
> @@ -377,6 +377,12 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
>        e->inline_failed = CIF_ATTRIBUTE_MISMATCH;
>        inlinable = false;
>      }
> +  else if (callee->externally_visible 
> +	   && flag_live_patching == LIVE_INLINE_ONLY_STATIC) 
> +    {
> +      e->inline_failed = CIF_EXTERN_LIVE_ONLY_STATIC;
> +      inlinable = false;
> +    }
>    if (!inlinable && report)
>      report_inline_failed_reason (e);
>    return inlinable;
> diff --git a/gcc/opts.c b/gcc/opts.c
> index e21967b..281f9f4 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -691,6 +691,64 @@ default_options_optimization (struct gcc_options *opts,
>  			 lang_mask, handlers, loc, dc);
>  }
>  
> +/* Control ipa optimizations based on different live patching LEVEL */
> +static void
> +control_optimizations_for_live_patching (struct gcc_options *opts, 
> +					 struct gcc_options *opts_set, 
> +					 enum live_patching_level level)
> +{
> +  gcc_assert (level > LIVE_NONE);
> +
> +  switch (level)
> +    {
> +    case LIVE_INLINE_ONLY_STATIC:
> +      if (!opts_set->x_flag_ipa_cp_clone)
> +        opts->x_flag_ipa_cp_clone = 0;      
> +      if (!opts_set->x_flag_ipa_sra)
> +        opts->x_flag_ipa_sra = 0;
> +      if (!opts_set->x_flag_partial_inlining)
> +        opts->x_flag_partial_inlining = 0;
> +      if (!opts_set->x_flag_ipa_cp)
> +        opts->x_flag_ipa_cp = 0;      
> +      /* FALLTHROUGH */
> +    case LIVE_INLINE_CLONE:
> +      /* live patching should disable whole-program optimization.  */
> +      if (!opts_set->x_flag_whole_program)
> +        opts->x_flag_whole_program = 0;
> +      /* visibility change should be excluded by !flag_whole_program 
> +	 && !in_lto_p && !flag_ipa_cp_clone && !flag_ipa_sra 

You added sorry about LTO, maybe then !in_lto_p would be always true?

> +	 && !flag_partial_inlining.  */
> +      if (!opts_set->x_flag_ipa_pta)
> +        opts->x_flag_ipa_pta = 0;
> +      if (!opts_set->x_flag_ipa_reference)
> +        opts->x_flag_ipa_reference = 0;
> +      if (!opts_set->x_flag_ipa_ra)
> +        opts->x_flag_ipa_ra = 0;
> +      if (!opts_set->x_flag_ipa_icf)
> +        opts->x_flag_ipa_icf = 0;
> +      if (!opts_set->x_flag_ipa_icf_functions)
> +        opts->x_flag_ipa_icf_functions = 0;
> +      if (!opts_set->x_flag_ipa_icf_variables)
> +        opts->x_flag_ipa_icf_variables = 0;
> +      if (!opts_set->x_flag_ipa_bit_cp)
> +        opts->x_flag_ipa_bit_cp = 0;
> +      if (!opts_set->x_flag_ipa_vrp)
> +        opts->x_flag_ipa_vrp = 0;
> +      if (!opts_set->x_flag_ipa_pure_const)

Can you please explain why you included:
      if (!opts_set->x_flag_ipa_bit_cp)
        opts->x_flag_ipa_bit_cp = 0;
      if (!opts_set->x_flag_ipa_vrp)
        opts->x_flag_ipa_vrp = 0;

?

> +        opts->x_flag_ipa_pure_const = 0;
> +      /* unreachable code removal.  */
> +      /* discovery of functions/variables with no address taken.  */

^^^ these 2 comments looks misaligned.

> +      if (!opts_set->x_flag_ipa_reference_addressable)
> +        opts->x_flag_ipa_reference_addressable = 0;
> +      /* ipa stack alignment propagation.  */
> +      if (!opts_set->x_flag_ipa_stack_alignment)
> +        opts->x_flag_ipa_stack_alignment = 0;
> +      break;
> +    default: 
> +      gcc_assert (0);  
> +    }
> +}
> +
>  /* After all options at LOC have been read into OPTS and OPTS_SET,
>     finalize settings of those options and diagnose incompatible
>     combinations.  */
> @@ -1040,6 +1098,10 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>    if ((opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS) && opts->x_flag_tm)
>      sorry ("transactional memory is not supported with "
>  	   "%<-fsanitize=kernel-address%>");
> +
> +  /* Currently live patching is not support for LTO.  */
> +  if (opts->x_flag_live_patching && in_lto_p) 
> +    sorry ("live patching is not supported with LTO");
>  }
>  
>  #define LEFT_COLUMN	27
> @@ -2266,6 +2328,12 @@ common_handle_option (struct gcc_options *opts,
>  	(&opts->x_flag_instrument_functions_exclude_files, arg);
>        break;
>  
> +    case OPT_flive_patching_:
> +      if (value)
> +    	control_optimizations_for_live_patching (opts, opts_set,
> +						 opts->x_flag_live_patching);
> +      break;
> +
>      case OPT_fmessage_length_:
>        pp_set_line_maximum_length (dc->printer, value);
>        diagnostic_set_caret_max_width (dc, value);
> diff --git a/gcc/testsuite/gcc.dg/live-patching-1.c b/gcc/testsuite/gcc.dg/live-patching-1.c
> new file mode 100644
> index 0000000..6a1ea38
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/live-patching-1.c
> @@ -0,0 +1,22 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -flive-patching=inline-only-static -fdump-ipa-inline" } */
> +
> +extern int sum, n, m;
> +
> +int foo (int a)
> +{
> +  return a + n;
> +}
> +
> +static int bar (int b)
> +{
> +  return b * m;
> +}
> +
> +int main()
> +{
> +  sum = foo (m) + bar (n); 
> +  return 0;
> +}
> +
> +/* { dg-final { scan-ipa-dump "foo/0 function has external linkage when the user requests only inlining static for live patching"  "inline" } } */
> -- 1.9.1

It would be also handy to test the newly added option.
Please add ChangeLog entry for the patch. Have you bootstrapped the patch and run test-suite?

Thanks,
Martin

> 
> 
> 
>> Thanks,
>> Miroslav
> 



More information about the Gcc-patches mailing list