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/
20250923061722.24457-1-yangtiezhu@loongson.cn
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.
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:
;; ....................
;;
-(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);
+})
\f
;;
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:
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)
-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}
@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
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { 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;
+}