https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65358
Bug ID: 65358 Summary: parameter passing bug with tail call optimization on arm Product: gcc Version: 5.0 Status: UNCONFIRMED Severity: critical Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: hong.gyu.kim at lge dot com struct pack { int fine; int victim; int killer; }; int bar(int a, int b, struct pack p); int foo(int arg1, int arg2, int arg3, struct pack p) { return bar(arg2, arg3, p); } When I cross compile the above code with "-O2" option for arm, one variable in "struct pack" is lost. The "vitcim" value is overwritten by "killer" value while passing arguments in "struct pack" from "foo" to "bar". Initially the arguments are passed this way right after foo invoked. r0: arg1 r1: arg2 r2: arg3 r3: p.fine MEM[sp]: p.victim MEM[sp-4]: p.killer Parameter setting for bar must be this way right before bar invoked. r0: arg2 r1: arg3 r2: p.fine r3: p.victim MEM[sp]: p.killer But parameter passing is structured as follows: (p.victim is overwritten by p.killer) r0: arg2 r1: arg3 r2: p.fine r3: p.killer (*) MEM[sp]: p.killer The assembly code of "foo" generated is as follows: foo: @ args = 16, pretend = 8, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 sub sp, sp, #8 mov r0, r1 str lr, [sp, #-4]! add ip, sp, #8 (1) ldr lr, [sp, #16] mov r1, r2 str r3, [sp, #8] (2) str lr, [sp, #12] ldr lr, [sp], #4 ldmia ip, {r2, r3} add sp, sp, #8 b bar The point is that (1) loads "p.killer", then (2) overwrites "p.victim" value. Until this point, "p.victim" is never copied anyway, which makes the value disappear. This bug is not shown when compiled with "-fno-optimize-sibling-calls". This bug is shown in gcc-4.9.2 and also in gcc-5.0.0. I also compiled the same program for x86 and x86_64 and those do not generate this kind of buggy code. This bug is only shown in arm code. I found that this bug is detected right after the RTL expand phase. (with -fdump-rtl-expand)