Hi,

when a thunk cannot be emitted in assembly directly, cgraph_node::expand_thunk 
generates regular GIMPLE code but unconditionally forces a tail call to the 
target of the thunk.  That's theoretically OK because the thunk essentially 
forwards its parameters to the target, but in practice the RTL expander can 
spill parameters passed by reference on the stack, see assign_parm_setup_reg:

  /* If we were passed a pointer but the actual value can safely live
     in a register, retrieve it and use it directly.  */
  if (data->arg.pass_by_reference && TYPE_MODE (TREE_TYPE (parm)) != BLKmode)
    {
      /* We can't use nominal_mode, because it will have been set to
         Pmode above.  We must use the actual mode of the parm.  */
      if (use_register_for_decl (parm))
        {
          parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
          mark_user_reg (parmreg);
        }
      else
        {
          int align = STACK_SLOT_ALIGNMENT (TREE_TYPE (parm),
                                    TYPE_MODE (TREE_TYPE (parm)),
                            TYPE_ALIGN (TREE_TYPE (parm)));
          parmreg
            = assign_stack_local (TYPE_MODE (TREE_TYPE (parm)),
                  GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (parm))),
                                  align);
          set_mem_attributes (parmreg, parm, 1);
        }

use_register_for_decl always return false at -O0 so, in this case, the thunk 
will pass an address within its frame to its target, so it cannot use a tail 
call to invoke it.

Tested on x86_64-suse-linux, OK for the mainline?


2020-09-14  Eric Botcazou  <ebotca...@adacore.com>

        * cgraphunit.c (cgraph_node::expand_thunk): Force a tail call only
        when optimizing.


2020-09-14  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/thunk1.adb: New test.
        * gnat.dg/thunk1_pkg1.ads: New helper.
        * gnat.dg/thunk1_pkg2.ads: Likewise.
        * gnat.dg/thunk1_pkg2.adb: Likewise.

-- 
Eric Botcazou
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 26d3995a0c0..fe8552e3cf2 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -2170,8 +2170,11 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
 		  bsi = gsi_last_bb (return_bb);
 		}
 	    }
+
+	  /* We can use a tail call, but only when optimizing to be sure that
+	     the RTL expander doesn't spill parameters passed by reference.  */
 	  else
-	    gimple_call_set_tail (call, true);
+	    gimple_call_set_tail (call, optimize);
 
 	  /* Build return value.  */
 	  if (!DECL_BY_REFERENCE (resdecl))
@@ -2183,7 +2186,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
 	}
       else
 	{
-	  gimple_call_set_tail (call, true);
+	  gimple_call_set_tail (call, optimize);
 	  remove_edge (single_succ_edge (bb));
 	}
 
package Thunk1_Pkg2 is

  type Root is tagged record
    I : Integer;
  end record;

  type Iface is interface;
  procedure Op (This : in out Iface; S : String) is abstract;

  type Ext is new Root and Iface with null record;

  procedure Op (This : in out Ext; S : String);

end Thunk1_Pkg2;
-- { dg-do run }

with Thunk1_Pkg1; use Thunk1_Pkg1;

procedure Thunk1 is
  D: Derived;
begin
  D.Op ("Message");
end;
with Thunk1_Pkg2; use Thunk1_Pkg2;

package Thunk1_Pkg1 is

  type Derived is new Ext with null record;

end Thunk1_Pkg1;
package body Thunk1_Pkg2 is

  procedure Op (This : in out Ext; S : String) is
  begin
    if S /= "Message" then
      raise Program_Error;
    end if;
  end;

end Thunk1_Pkg2;

Reply via email to