https://gcc.gnu.org/g:15c8169ec55b52630ab884dd7a30c3237ada98b2

commit r16-4701-g15c8169ec55b52630ab884dd7a30c3237ada98b2
Author: Xi Ruoyao <[email protected]>
Date:   Sun Oct 26 13:20:20 2025 +0800

    LoongArch: Make the code generation of the trap pattern configurable
    
    In some applications (notably the Linux kernel), "break 0" is used as a
    trap that a handler may be able to recover.  But in GCC the "trap"
    pattern is meant to make the program rightfully die instead.
    
    As [1] describes, sometimes it's vital to distinguish between the two
    cases.  The kernel developers prefer "break 1" here, but in the
    user-space it's better to trigger a SIGILL instead of SIGTRAP as the
    latter is more likely used as a application-defined trap.
    
    To support both cases, make the code generation configurable with a new
    option.
    
    [1]:https://lore.kernel.org/[email protected]
    
    gcc/
    
            * config/loongarch/genopts/loongarch.opt.in (-mbreak-code=):
            New.
            * config/loongarch/loongarch.opt: Regenerate.
            * config/loongarch/loongarch.md (trap): Separate to a
            define_insn and a define_expand which takes la_break_code.
            * doc/invoke.texi (-mbreak-code=): Document.
            * config/loongarch/loongarch.opt.urls: Regenerate.
    
    gcc/testsuite
    
            * gcc.target/loongarch/trap-default.c: New test.
            * gcc.target/loongarch/trap-1.c: New test.

Diff:
---
 gcc/config/loongarch/genopts/loongarch.opt.in     |  4 ++++
 gcc/config/loongarch/loongarch.md                 | 14 +++++++++++---
 gcc/config/loongarch/loongarch.opt                |  4 ++++
 gcc/config/loongarch/loongarch.opt.urls           |  3 +++
 gcc/doc/invoke.texi                               | 13 ++++++++++++-
 gcc/testsuite/gcc.target/loongarch/trap-1.c       |  9 +++++++++
 gcc/testsuite/gcc.target/loongarch/trap-default.c |  9 +++++++++
 7 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in 
b/gcc/config/loongarch/genopts/loongarch.opt.in
index 39c1545e5408..f0c089a928ec 100644
--- a/gcc/config/loongarch/genopts/loongarch.opt.in
+++ b/gcc/config/loongarch/genopts/loongarch.opt.in
@@ -205,6 +205,10 @@ 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.
+
 Enum
 Name(explicit_relocs) Type(int)
 The code model option names for -mexplicit-relocs:
diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index be9a2351dd6e..625f30ca2658 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -679,14 +679,22 @@
 ;;  ....................
 ;;
 
-(define_insn "trap"
-  [(trap_if (const_int 1) (const_int 0))]
+(define_insn "*trap"
+  [(trap_if (const_int 1) (match_operand 0 "const_int_operand"))]
   ""
 {
-  return "break\t0";
+  return (const_uimm15_operand (operands[0], VOIDmode)
+         ? "break\t%0"
+         : "amswap.w\t$r0,$r1,$r0");
 }
   [(set_attr "type" "trap")])
 
+(define_expand "trap"
+  [(trap_if (const_int 1) (match_dup 0))]
+  ""
+{
+  operands[0] = GEN_INT (la_break_code);
+})
 
 
 ;;
diff --git a/gcc/config/loongarch/loongarch.opt 
b/gcc/config/loongarch/loongarch.opt
index fbe61c0bf7c2..628eabe8d591 100644
--- a/gcc/config/loongarch/loongarch.opt
+++ b/gcc/config/loongarch/loongarch.opt
@@ -213,6 +213,10 @@ 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.
+
 Enum
 Name(explicit_relocs) Type(int)
 The code model option names for -mexplicit-relocs:
diff --git a/gcc/config/loongarch/loongarch.opt.urls 
b/gcc/config/loongarch/loongarch.opt.urls
index 606a211f3223..c93f04683e1c 100644
--- a/gcc/config/loongarch/loongarch.opt.urls
+++ b/gcc/config/loongarch/loongarch.opt.urls
@@ -48,6 +48,9 @@ UrlSuffix(gcc/LoongArch-Options.html#index-mstrict-align-1)
 mmax-inline-memcpy-size=
 UrlSuffix(gcc/LoongArch-Options.html#index-mmax-inline-memcpy-size)
 
+mbreak-code=
+UrlSuffix(gcc/LoongArch-Options.html#index-mbreak-code)
+
 mexplicit-relocs=
 UrlSuffix(gcc/LoongArch-Options.html#index-mexplicit-relocs-1)
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index b40fc892fa0d..32b9c48f155c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1097,7 +1097,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
+-mno-check-zero-division -mbreak-code=@var{code}
 -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}
@@ -28457,6 +28457,17 @@ 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 mcond-move-int
 @item -mcond-move-int
 @itemx -mno-cond-move-int
diff --git a/gcc/testsuite/gcc.target/loongarch/trap-1.c 
b/gcc/testsuite/gcc.target/loongarch/trap-1.c
new file mode 100644
index 000000000000..8936f60cce20
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/trap-1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -w -fisolate-erroneous-paths-dereference -mbreak-code=1" 
} */
+/* { dg-final { scan-assembler "break\\t1" } } */
+
+int
+bug (void)
+{
+  return *(int *)0;
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/trap-default.c 
b/gcc/testsuite/gcc.target/loongarch/trap-default.c
new file mode 100644
index 000000000000..32948d4c8227
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/trap-default.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -w -fisolate-erroneous-paths-dereference" } */
+/* { dg-final { scan-assembler "amswap\\.w\\t\\\$r0,\\\$r1,\\\$r0" } } */
+
+int
+bug (void)
+{
+  return *(int *)0;
+}

Reply via email to