tailcall optimization causing Arm backend to crash in RTL pass: mach

Bug #1973371 reported by visda vokhshoori
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
New
Undecided
Unassigned

Bug Description

hello,

Can you please confirm this is a bug?

update:
turning off the jump modification is an awfully big hammer to fix this.
I have narrowed this down to try_crossjump_to_edge(). This is where the two calls are incorrectly unified.

I currently don't have a good fix for it.
There's no target macro that I can use to prevent this happening for arm architecture.

I have thought of reusing arm_function_ok_for_sibcall.

any guidance is appreciated!

Regards,
Visda

Source:
I have used the compiler explore to compiler the source
https://godbolt.org

The source file is:
#include <stdint.h>
#include <stddef.h>

typedef void (*funcptr_void) (void) __attribute__((cmse_nonsecure_call));
typedef uint32_t TC_COMPARE_STATUS;
funcptr_void secure_tc0_match0_interrupt_callback = NULL;
funcptr_void secure_tc0_overflow_interrupt_callback = NULL;

static void tc0_compare_handler (TC_COMPARE_STATUS status, uintptr_t context)
{
   if (status & ((0x1U) << (4U)))
        secure_tc0_match0_interrupt_callback ();

   else if (status & ((0x1U) << (0U)))
        secure_tc0_overflow_interrupt_callback ();

    else
    {

        while (1);

    }
}

int main ( void )
{
    uint32_t msp_ns = *((uint32_t *)(0x40000));
    volatile funcptr_void NonSecure_ResetHandler;

     TC0_CompareCallbackRegister (tc0_compare_handler, 0);

    if (msp_ns != 0xFFFFFFFF)
    {

        __TZ_set_MSP_NS(msp_ns);

        NonSecure_ResetHandler = (funcptr_void)(*((uint32_t *)((0x40000) + 4U)));

        NonSecure_ResetHandler();
    }

    while (1);

    return (1);
}

Compiler options; -fcrossjumping -mcmse -march=armv8-m.main -mfloat-abit=soft
Compiler version; ARM GCC 10.2.1 (none)
Compiler output; 1 with message message
<source>: In function 'main':
during RTL pass: mach
<source>: In function 'tc0_compare_handler':
<source>:23:1: internal compiler error: Segmentation fault
   23 | }
      | ^
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://gcc.gnu.org/bugs/> for instructions.
Compiler returned: 1

Problem description:

In the example source provided, there are two cmse_nonsecure calls, guarded by a condition. Although the RTL of the calls generated look the same, but they are calls to different function, and hence crossjumping should not unify them.
The code generated after cross jumping pass looks really wrong. However, doesn't segfault.
The segfault occurs in RTL pass mach. where arm backend calls this function: cmse_nonsecure_call_clear_caller_saved(). the call stack at the time of segfault is;

(gdb) where
#0 0x000000000129eed1 in cmse_nonsecure_call_clear_caller_saved () at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/config/arm/arm.c:17830
#1 0x00000000012a00e3 in arm_reorg () at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/config/arm/arm.c:18189
#2 0x0000000000e14e4b in (anonymous namespace)::pass_machine_reorg::execute (this=0x24339d0)
    at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/reorg.c:3979
#3 0x0000000000d76479 in execute_one_pass (pass=0x24339d0) at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/passes.c:2497
#4 0x0000000000d767de in execute_pass_list_1 (pass=0x24339d0) at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/passes.c:2586
#5 0x0000000000d7680f in execute_pass_list_1 (pass=0x24337f0) at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/passes.c:2587
#6 0x0000000000d7680f in execute_pass_list_1 (pass=0x2431bb0) at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/passes.c:2587
#7 0x0000000000d76867 in execute_pass_list (fn=0x7ffff717b420, pass=0x242df80) at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/passes.c:2597
#8 0x000000000096457d in cgraph_node::expand (this=0x7ffff717e2e0) at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/cgraphunit.c:2139
#9 0x0000000000964a38 in expand_all_functions () at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/cgraphunit.c:2275
#10 0x0000000000965548 in symbol_table::compile (this=0x7ffff7248000) at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/cgraphunit.c:2624
#11 0x00000000009657e0 in symbol_table::finalize_compilation_unit (this=0x7ffff7248000)
    at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/cgraphunit.c:2717
#12 0x0000000000ea343e in compile_file () at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/toplev.c:492
#13 0x0000000000ea5e9f in do_compile () at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/toplev.c:2189
#14 0x0000000000ea61a1 in toplev::main (this=0x7fffffffdac6, argc=23, argv=0x7fffffffdbc8)
    at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/toplev.c:2324
#15 0x00000000018e1ac7 in main (argc=23, argv=0x7fffffffdbc8) at /home/parallels/xc32-src/xc32-gcc/gcc/gcc/main.c:39

The statement it is on at the time of crash is:
fntype = TREE_TYPE (MEM_EXPR (address));
 the address is in r4. which is not live, REG_DEAD, in the following RTL expression.
r4 is set in this basic block's predecessor, below
(insn:TI 13 71 81 3 (set (reg:SI 4 r4)
(mem/f/c:SI (reg/f:SI 3 r3 [117]) [1 secure_tc0_match0_interrupt_callback+0 S4 A32])) "../src/main.c":102 878 {*thumb2_movsi_insn}
(expr_list:REG_DEAD (reg/f:SI 3 r3 [117])
(nil)))

My local fix is to define
#undef TARGET_CANNOT_MODIFY_JUMPS_P
#define TARGET_CANNOT_MODIFY_JUMPS_P arm_cannot_modify_jumps_p
and return true if use_cmse==true.

visda vokhshoori (visda)
description: updated
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.