On Mon, 2025-11-17 at 12:34 +0800, WANG Xuerui wrote:
> From: WANG Xuerui <[email protected]>
> 
> The option was introduced a few days ago to provide more control over
> the code generation of __builtin_trap(), but the current form does not
> provide room for further extension should other means of trapping become
> available on future generations of LoongArch cores.  Moreover, using
> out-of-range values to ask for something that's not a "break" is
> counter-intuitive, at least for an option named "break"-something.
> 
> To improve the command-line UX, rename the option to
> -mbuiltin-trap-impl= to better reflect the intent from a user's
> perspective, and make it accept a string that resembles real LoongArch
> assembly if the user were asked to write the trap snippet themselves.
> 
> For now, the accepted forms are "break-CODE" where CODE is an integer
> literal between 0 and 32767 inclusive, and "amswap.w".  Both deviate
> from usual assembly forms somehow for practical reasons:
> 
> 1. Spaces are notorious in CLI argument handling, so for something
>    expected to be passed around often in an unstructured way (read:
>    CFLAGS), it is prudent to use something else.
> 2. The usage of "amswap.w" here (or any other AM* instruction) is
>    exotic, as the LoongArch reference manual does not provide any other
>    way to trigger an INE (instruction non-existent) exception for sure.
>    In this case, the register operands are intentionally illegal, so
>    having them fully spelled out only serves to confuse any reader. In
>    addition, the exact register usage is irrelevant to the option's
>    purpose.
> 
> Since this is now freeform string, any future evolution of the option's
> usage is made possible.
> 
> gcc/ChangeLog:
> 
>       * config/loongarch/genopts/loongarch.opt.in: Rework
>         -mbreak-code= into -mbuiltin-trap-impl=.
>       * config/loongarch/loongarch-opts.cc
>       (loongarch_parse_mbuiltin_trap_impl): New function.
>       (loongarch_init_misc_options): Parse the new option.
>       * config/loongarch/loongarch.opt: Regenerate.

loongarch.opt.urls needs to be regenerated too.

>       * doc/invoke.texi: Amend documentation.
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.target/loongarch/trap-1.c: Move to...
>       * gcc.target/loongarch/builtin-trap-impl-break-1.c: ...here and
>         migrate to new option.
>       * gcc.target/loongarch/trap-default.c: Move to...
>       * gcc.target/loongarch/builtin-trap-impl-default.c: ...here and
>         migrate to new option.
>       * gcc.target/loongarch/builtin-trap-impl-amswap-w.c: New test.
>       * gcc.target/loongarch/builtin-trap-impl-break-0.c: New test.
>       * gcc.target/loongarch/builtin-trap-impl-break-32767.c: New test.
>       * gcc.target/loongarch/builtin-trap-impl-err-1.c: New test.
>       * gcc.target/loongarch/builtin-trap-impl-err-2.c: New test.
>       * gcc.target/loongarch/builtin-trap-impl-test.c: New common test
>         code.
> ---
>  gcc/config/loongarch/genopts/loongarch.opt.in | 11 ++++--
>  gcc/config/loongarch/loongarch-opts.cc        | 38 ++++++++++++++++++
>  gcc/config/loongarch/loongarch.opt            | 11 ++++--
>  gcc/doc/invoke.texi                           | 39 +++++++++++++------
>  .../loongarch/builtin-trap-impl-amswap-w.c    |  6 +++
>  .../loongarch/builtin-trap-impl-break-0.c     |  6 +++
>  .../{trap-1.c => builtin-trap-impl-break-1.c} |  9 ++---
>  .../loongarch/builtin-trap-impl-break-32767.c |  6 +++
>  ...-default.c => builtin-trap-impl-default.c} |  7 +---
>  .../loongarch/builtin-trap-impl-err-1.c       |  7 ++++
>  .../loongarch/builtin-trap-impl-err-2.c       |  7 ++++
>  .../loongarch/builtin-trap-impl-test.c        |  9 +++++
>  12 files changed, 127 insertions(+), 29 deletions(-)
>  create mode 100644 
> gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-amswap-w.c
>  create mode 100644 
> gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-0.c
>  rename gcc/testsuite/gcc.target/loongarch/{trap-1.c => 
> builtin-trap-impl-break-1.c} (58%)
>  create mode 100644 
> gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-32767.c
>  rename gcc/testsuite/gcc.target/loongarch/{trap-default.c => 
> builtin-trap-impl-default.c} (71%)
>  create mode 100644 
> gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-err-1.c
>  create mode 100644 
> gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-err-2.c
>  create mode 100644 
> gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-test.c
> 
> diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in 
> b/gcc/config/loongarch/genopts/loongarch.opt.in
> index f0c089a928e..82f6106992a 100644
> --- a/gcc/config/loongarch/genopts/loongarch.opt.in
> +++ b/gcc/config/loongarch/genopts/loongarch.opt.in
> @@ -205,9 +205,14 @@ mmax-inline-memcpy-size=
>  Target Joined RejectNegative UInteger Var(la_max_inline_memcpy_size) 
> Init(1024) Save
>  -mmax-inline-memcpy-size=SIZE        Set the max size of memcpy to inline, 
> default is 1024.
>  
> -mbreak-code=
> -Target Joined UInteger Var(la_break_code) Init(-1) Save
> --mbreak-code=CODE    Use 'break CODE' for traps supposed to be 
> unrecoverable, or an 'amswap.w' instruction leading to INE if CODE is out of 
> range.
> +TargetVariable
> +int la_break_code = -1
> +
> +mbuiltin-trap-impl=
> +Target Joined RejectNegative Var(la_builtin_trap_impl) Init("") Save
> +Control how __builtin_trap is code-generated and its runtime behavior.
> +Possible values are \"break-CODE\" (0 <= CODE <= 32767) for a BRK with the
> +given CODE, or \"amswap.w\" for a documented INE.
>  
>  Enum
>  Name(explicit_relocs) Type(int)
> diff --git a/gcc/config/loongarch/loongarch-opts.cc 
> b/gcc/config/loongarch/loongarch-opts.cc
> index cacfe370345..3668788b07e 100644
> --- a/gcc/config/loongarch/loongarch-opts.cc
> +++ b/gcc/config/loongarch/loongarch-opts.cc
> @@ -1045,6 +1045,40 @@ loongarch_target_option_override (struct 
> loongarch_target *target,
>  }
>  
>  
> +/* Parser for -mbuiltin-trap-impl=STRATEGY.  */
> +int
> +loongarch_parse_mbuiltin_trap_impl (const char *val)
> +{
> +  if (!val || *val == '\0' || !strcmp (val, "amswap.w"))
> +    return -1;
> +
> +  if (!strncmp (val, "break-", 6))
> +    {
> +      const char *code_substr = val + 6;
> +      int err = 0;
> +      HOST_WIDE_INT r = integral_argument (code_substr, &err, false);
> +      if (err || r < 0 || r > 0x7fff)
> +     {
> +       error ("code %qs invalid for the %qs instruction", code_substr,
> +              "break");
> +       inform (UNKNOWN_LOCATION,
> +               "code for the %qs instruction must be an integer between "
> +               "%d and %d, inclusive",
> +               "break", 0, 0x7fff);
> +       return -1;
> +     }
> +      return (int) r;
> +    }
> +
> +  error ("unrecognized strategy for %<-mbuiltin-trap-impl%>: %qs", val);
> +  inform (UNKNOWN_LOCATION,
> +       "valid values are %<break-CODE%> (CODE between %d and %d, "
> +       "inclusive) and %<amswap.w%>",
> +       0, 0x7fff);
> +  return -1;
> +}
> +
> +
>  /* Resolve options that's not covered by la_target.  */
>  void
>  loongarch_init_misc_options (struct gcc_options *opts,
> @@ -1056,6 +1090,10 @@ loongarch_init_misc_options (struct gcc_options *opts,
>    /* -mrecip options.  */
>    opts->x_recip_mask = loongarch_parse_mrecip_scheme (opts->x_la_recip_name);
>  
> +  /* -mbuiltin-trap-impl.  */
> +  opts->x_la_break_code
> +      = loongarch_parse_mbuiltin_trap_impl (opts->x_la_builtin_trap_impl);
> +
>  #define INIT_TARGET_FLAG(NAME, INIT) \
>    { \
>      if (!(opts_set->x_target_flags & MASK_##NAME)) \
> diff --git a/gcc/config/loongarch/loongarch.opt 
> b/gcc/config/loongarch/loongarch.opt
> index 628eabe8d59..12d9c538dc5 100644
> --- a/gcc/config/loongarch/loongarch.opt
> +++ b/gcc/config/loongarch/loongarch.opt
> @@ -213,9 +213,14 @@ mmax-inline-memcpy-size=
>  Target Joined RejectNegative UInteger Var(la_max_inline_memcpy_size) 
> Init(1024) Save
>  -mmax-inline-memcpy-size=SIZE        Set the max size of memcpy to inline, 
> default is 1024.
>  
> -mbreak-code=
> -Target Joined UInteger Var(la_break_code) Init(-1) Save
> --mbreak-code=CODE    Use 'break CODE' for traps supposed to be 
> unrecoverable, or an 'amswap.w' instruction leading to INE if CODE is out of 
> range.
> +TargetVariable
> +int la_break_code = -1
> +
> +mbuiltin-trap-impl=
> +Target Joined RejectNegative Var(la_builtin_trap_impl) Init("") Save
> +Control how __builtin_trap is code-generated and its runtime behavior.
> +Possible values are \"break-CODE\" (0 <= CODE <= 32767) for a BRK with the
> +given CODE, or \"amswap.w\" for a documented INE.
>  
>  Enum
>  Name(explicit_relocs) Type(int)
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index df4331fbad0..060f70c4d91 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -1155,7 +1155,7 @@ Objective-C and Objective-C++ Dialects}.
>  -mfpu=@var{fpu-type} -msimd=@var{simd-type}
>  -msoft-float -msingle-float -mdouble-float -mlsx -mno-lsx -mlasx -mno-lasx
>  -mbranch-cost=@var{n} -maddr-reg-reg-cost=@var{n}  -mcheck-zero-division
> --mno-check-zero-division -mbreak-code=@var{code}
> +-mno-check-zero-division -mbuiltin-trap-impl=@var{strategy}
>  -mcond-move-int  -mno-cond-move-int
>  -mcond-move-float  -mno-cond-move-float
>  -memcpy  -mno-memcpy -mstrict-align -mno-strict-align -G @var{num}
> @@ -16333,7 +16333,7 @@ as a parameter of @code{free} call or compared with 
> @code{NULL}.  If
>  with @option{-fmalloc-dce=2} also comparisons with @code{NULL} pointer are
>  considered safe to remove.
>  
> -The default is @option{-fmalloc-dce=2}.  See also @option{-fallocation-dce}. 
> +The default is @option{-fmalloc-dce=2}.  See also @option{-fallocation-dce}.
>  
>  @opindex fmove-loop-invariants
>  @item -fmove-loop-invariants
> @@ -28757,16 +28757,31 @@ Trap (do not trap) on integer division by zero.  
> The default is
>  @option{-mcheck-zero-division} for @option{-O0} or @option{-Og}, and
>  @option{-mno-check-zero-division} for other optimization levels.
>  
> -@opindex mbreak-code
> -@item -mbreak-code=@var{code}
> -Emit a @code{break} @var{code} instruction for irrecoverable traps
> -from @code{__builtin_trap} or inserted by the compiler (for example
> -an erroneous path isolated with
> -@option{-fisolate-erroneous-paths-dereference}), or an
> -@code{amswap.w $r0, $r1, $r0} instruction which will cause the hardware
> -to trigger an Instruction Not-defined Exception if @var{code} is negative
> -or greater than 32767.  The default is -1, meaning to use the
> -@code{amswap.w} instruction.
> +@opindex mbuiltin-trap-impl
> +@item -mbuiltin-trap-impl=@var{strategy}
> +Control the code generated for irrecoverable traps from
> +@code{__builtin_trap} or inserted by the compiler (for example an
> +erroneous path isolated with
> +@option{-fisolate-erroneous-paths-dereference}).
> +
> +The following forms are supported for @var{strategy}:
> +
> +@itemize @bullet
> +@item
> +@code{amswap.w}
> +Use @code{amswap.w $r0, $r1, $r0} for traps, which is a documented
> +illegal use of the instruction.  An @code{INE} (Instruction
> +non-existent) exception will be triggered at runtime.
> +
> +@item
> +@code{break-CODE}
> +Use @code{break} @var{CODE} for traps.  @var{CODE} must be an integer
> +literal between 0 and 32767 inclusive, due to the @code{break}
> +instruction's encoding.  A @code{BRK} (Breakpoint) exception will be
> +triggered at runtime.
> +@end itemize
> +
> +The default is to use the @code{amswap.w} strategy.
>  
>  @opindex mcond-move-int
>  @item -mcond-move-int
> diff --git a/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-amswap-w.c 
> b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-amswap-w.c
> new file mode 100644
> index 00000000000..2b4d48088ba
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-amswap-w.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -w -fisolate-erroneous-paths-dereference 
> -mbuiltin-trap-impl=amswap.w" } */
> +/* { dg-final { scan-assembler "amswap\\.w\\t\\\$r0,\\\$r1,\\\$r0" } } */
> +
> +#define BUILTIN_TRAP_IMPL_TEST
> +#include "builtin-trap-impl-test.c"
> diff --git a/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-0.c 
> b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-0.c
> new file mode 100644
> index 00000000000..a20960f0a1c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-0.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -w -fisolate-erroneous-paths-dereference 
> -mbuiltin-trap-impl=break-0" } */
> +/* { dg-final { scan-assembler "break\\t0" } } */
> +
> +#define BUILTIN_TRAP_IMPL_TEST
> +#include "builtin-trap-impl-test.c"
> diff --git a/gcc/testsuite/gcc.target/loongarch/trap-1.c 
> b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-1.c
> similarity index 58%
> rename from gcc/testsuite/gcc.target/loongarch/trap-1.c
> rename to gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-1.c
> index 8936f60cce2..fe6a63c777a 100644
> --- a/gcc/testsuite/gcc.target/loongarch/trap-1.c
> +++ b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-1.c
> @@ -1,9 +1,6 @@
>  /* { dg-do compile } */
> -/* { dg-options "-O2 -w -fisolate-erroneous-paths-dereference 
> -mbreak-code=1" } */
> +/* { dg-options "-O2 -w -fisolate-erroneous-paths-dereference 
> -mbuiltin-trap-impl=break-1" } */
>  /* { dg-final { scan-assembler "break\\t1" } } */
>  
> -int
> -bug (void)
> -{
> -  return *(int *)0;
> -}
> +#define BUILTIN_TRAP_IMPL_TEST
> +#include "builtin-trap-impl-test.c"
> diff --git 
> a/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-32767.c 
> b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-32767.c
> new file mode 100644
> index 00000000000..3ae5b0a68f7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-break-32767.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -w -fisolate-erroneous-paths-dereference 
> -mbuiltin-trap-impl=break-0x7fff" } */
> +/* { dg-final { scan-assembler "break\\t32767" } } */
> +
> +#define BUILTIN_TRAP_IMPL_TEST
> +#include "builtin-trap-impl-test.c"
> diff --git a/gcc/testsuite/gcc.target/loongarch/trap-default.c 
> b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-default.c
> similarity index 71%
> rename from gcc/testsuite/gcc.target/loongarch/trap-default.c
> rename to gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-default.c
> index 32948d4c822..50a17cfc1d5 100644
> --- a/gcc/testsuite/gcc.target/loongarch/trap-default.c
> +++ b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-default.c
> @@ -2,8 +2,5 @@
>  /* { dg-options "-O2 -w -fisolate-erroneous-paths-dereference" } */
>  /* { dg-final { scan-assembler "amswap\\.w\\t\\\$r0,\\\$r1,\\\$r0" } } */
>  
> -int
> -bug (void)
> -{
> -  return *(int *)0;
> -}
> +#define BUILTIN_TRAP_IMPL_TEST
> +#include "builtin-trap-impl-test.c"
> diff --git a/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-err-1.c 
> b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-err-1.c
> new file mode 100644
> index 00000000000..857e5951158
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-err-1.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mbuiltin-trap-impl=break" } */
> +
> +int dummy;
> +
> +/* { dg-error "unrecognized strategy for '-mbuiltin-trap-impl': 'break'" "" 
> { target { "loongarch*-*-*" } } 0 } */
> +/* { dg-message "note: valid values are 'break-CODE' \\(CODE between 0 and 
> 32767, inclusive\\) and 'amswap.w'" "" { target { "loongarch*-*-*" } } 0 } */
> diff --git a/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-err-2.c 
> b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-err-2.c
> new file mode 100644
> index 00000000000..e6ffd00a535
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-err-2.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mbuiltin-trap-impl=break-32768" } */
> +
> +int dummy;
> +
> +/* { dg-error "code '32768' invalid for the 'break' instruction" "" { target 
> { "loongarch*-*-*" } } 0 } */
> +/* { dg-message "note: code for the 'break' instruction must be an integer 
> between 0 and 32767, inclusive" "" { target { "loongarch*-*-*" } } 0 } */
> diff --git a/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-test.c 
> b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-test.c
> new file mode 100644
> index 00000000000..a3daf81b478
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/builtin-trap-impl-test.c
> @@ -0,0 +1,9 @@
> +#ifdef BUILTIN_TRAP_IMPL_TEST
> +int
> +bug (void)
> +{
> +  return *(int *)0;
> +}
> +#endif
> +
> +int dummy;

-- 
Xi Ruoyao <[email protected]>

Reply via email to