Commit 7555009a by Jakub Jelinek Committed by Jakub Jelinek

re PR debug/41558 (gfortran -O code excessive DW_OP_deref's)

	PR debug/41558
	* dwarf2out.c (loc_by_reference): Removed.
	(dw_loc_list_1): New function.
	(dw_loc_list): Remove toplev argument, add want_address argument.
	Don't look at decl_by_reference_p at all.  Use dw_loc_list_1.
	(loc_list_from_tree) <case VAR_DECL>: Pass want_address rather than
	want_address == 2 to dw_loc_list.  For successful dw_loc_list
	set have_address to 1 only if want_address is not 0.

	* gcc.dg/guality/guality.exp: Move gdb-test proc into...
	* lib/gcc-gdb-test.exp: ... here.  New file.
	* gfortran.dg/guality/guality.exp: New file.
	* gfortran.dg/guality/pr41558.f90: New test.
	* gfortran.dg/guality/arg1.f90: New test.

From-SVN: r152467
parent c640a3bd
2009-10-05 Jakub Jelinek <jakub@redhat.com>
PR debug/41558
* dwarf2out.c (loc_by_reference): Removed.
(dw_loc_list_1): New function.
(dw_loc_list): Remove toplev argument, add want_address argument.
Don't look at decl_by_reference_p at all. Use dw_loc_list_1.
(loc_list_from_tree) <case VAR_DECL>: Pass want_address rather than
want_address == 2 to dw_loc_list. For successful dw_loc_list
set have_address to 1 only if want_address is not 0.
2009-10-05 Richard Sandiford <rdsandiford@googlemail.com> 2009-10-05 Richard Sandiford <rdsandiford@googlemail.com>
* config/mips/mips-protos.h (mips_trampoline_code_size): Declare. * config/mips/mips-protos.h (mips_trampoline_code_size): Declare.
...@@ -13596,71 +13596,101 @@ decl_by_reference_p (tree decl) ...@@ -13596,71 +13596,101 @@ decl_by_reference_p (tree decl)
&& DECL_BY_REFERENCE (decl)); && DECL_BY_REFERENCE (decl));
} }
/* Return single element location list containing loc descr REF. */
/* Dereference a location expression LOC if DECL is passed by invisible static dw_loc_list_ref
reference. */ single_element_loc_list (dw_loc_descr_ref ref)
static dw_loc_descr_ref
loc_by_reference (dw_loc_descr_ref loc, tree decl)
{ {
HOST_WIDE_INT size; return new_loc_list (ref, NULL, NULL, NULL, 0);
enum dwarf_location_atom op; }
if (loc == NULL) /* Helper function for dw_loc_list. Compute proper Dwarf location descriptor
return NULL; for VARLOC. */
if (!decl_by_reference_p (decl)) static dw_loc_descr_ref
return loc; dw_loc_list_1 (tree loc, rtx varloc, int want_address,
enum var_init_status initialized)
{
int have_address = 0;
dw_loc_descr_ref descr;
enum machine_mode mode;
/* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead if (want_address != 2)
change it into corresponding DW_OP_breg{0...31,x} 0. Then the
location expression is considered to be address of a memory location,
rather than the register itself. */
if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31)
|| loc->dw_loc_opc == DW_OP_regx)
&& (loc->dw_loc_next == NULL
|| (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit
&& loc->dw_loc_next->dw_loc_next == NULL)))
{ {
if (loc->dw_loc_opc == DW_OP_regx) gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
/* Single part. */
if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
{ {
loc->dw_loc_opc = DW_OP_bregx; varloc = XEXP (XEXP (varloc, 1), 0);
loc->dw_loc_oprnd2.v.val_int = 0; mode = GET_MODE (varloc);
if (MEM_P (varloc))
{
varloc = XEXP (varloc, 0);
have_address = 1;
}
descr = mem_loc_descriptor (varloc, mode, initialized);
} }
else else
return 0;
}
else
{
descr = loc_descriptor (varloc, DECL_MODE (loc), initialized);
have_address = 1;
}
if (!descr)
return 0;
if (want_address == 2 && !have_address
&& (dwarf_version >= 4 || !dwarf_strict))
{
if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
{ {
loc->dw_loc_opc expansion_failed (loc, NULL_RTX,
= (enum dwarf_location_atom) "DWARF address size mismatch");
(loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0)); return 0;
loc->dw_loc_oprnd1.v.val_int = 0;
} }
return loc; add_loc_descr (&descr, new_loc_descr (DW_OP_stack_value, 0, 0));
have_address = 1;
}
/* Show if we can't fill the request for an address. */
if (want_address && !have_address)
{
expansion_failed (loc, NULL_RTX,
"Want address and only have value");
return 0;
} }
size = int_size_in_bytes (TREE_TYPE (decl)); /* If we've got an address and don't want one, dereference. */
if (size > DWARF2_ADDR_SIZE || size == -1) if (!want_address && have_address)
return 0; {
else if (size == DWARF2_ADDR_SIZE) HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
op = DW_OP_deref; enum dwarf_location_atom op;
else
op = DW_OP_deref_size;
add_loc_descr (&loc, new_loc_descr (op, size, 0));
return loc;
}
/* Return single element location list containing loc descr REF. */ if (size > DWARF2_ADDR_SIZE || size == -1)
{
expansion_failed (loc, NULL_RTX,
"DWARF address size mismatch");
return 0;
}
else if (size == DWARF2_ADDR_SIZE)
op = DW_OP_deref;
else
op = DW_OP_deref_size;
static dw_loc_list_ref add_loc_descr (&descr, new_loc_descr (op, size, 0));
single_element_loc_list (dw_loc_descr_ref ref) }
{
return new_loc_list (ref, NULL, NULL, NULL, 0); return descr;
} }
/* Return dwarf representation of location list representing for /* Return dwarf representation of location list representing for
LOC_LIST of DECL. */ LOC_LIST of DECL. WANT_ADDRESS has the same meaning as in
loc_list_from_tree function. */
static dw_loc_list_ref static dw_loc_list_ref
dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) dw_loc_list (var_loc_list * loc_list, tree decl, int want_address)
{ {
const char *endname, *secname; const char *endname, *secname;
dw_loc_list_ref list; dw_loc_list_ref list;
...@@ -13670,8 +13700,6 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) ...@@ -13670,8 +13700,6 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel)
dw_loc_descr_ref descr; dw_loc_descr_ref descr;
char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
bool by_reference = decl_by_reference_p (decl);
/* Now that we know what section we are using for a base, /* Now that we know what section we are using for a base,
actually construct the list of locations. actually construct the list of locations.
The first location information is what is passed to the The first location information is what is passed to the
...@@ -13684,28 +13712,14 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) ...@@ -13684,28 +13712,14 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel)
a range of [last location start, end of function label]. */ a range of [last location start, end of function label]. */
node = loc_list->first; node = loc_list->first;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
secname = secname_for_decl (decl); secname = secname_for_decl (decl);
if (NOTE_VAR_LOCATION_LOC (node->var_loc_note)) if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
else else
initialized = VAR_INIT_STATUS_INITIALIZED; initialized = VAR_INIT_STATUS_INITIALIZED;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
if (!toplevel || by_reference) descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
{
gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
/* Single part. */
if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
descr = loc_by_reference (mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0),
TYPE_MODE (TREE_TYPE (decl)),
initialized),
decl);
else
descr = NULL;
}
else
descr = loc_descriptor (varloc, DECL_MODE (decl), initialized);
if (loc_list && loc_list->first != loc_list->last) if (loc_list && loc_list->first != loc_list->last)
list = new_loc_list (descr, node->label, node->next->label, secname, 1); list = new_loc_list (descr, node->label, node->next->label, secname, 1);
...@@ -13721,22 +13735,9 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) ...@@ -13721,22 +13735,9 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel)
{ {
/* The variable has a location between NODE->LABEL and /* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */ NODE->NEXT->LABEL. */
enum var_init_status initialized = initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
varloc = NOTE_VAR_LOCATION (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->var_loc_note);
if (!toplevel || by_reference) descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
{
gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
/* Single part. */
if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
descr = mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0),
TYPE_MODE (TREE_TYPE (decl)), initialized);
else
descr = NULL;
descr = loc_by_reference (descr, decl);
}
else
descr = loc_descriptor (varloc, DECL_MODE (decl), initialized);
add_loc_descr_to_loc_list (&list, descr, add_loc_descr_to_loc_list (&list, descr,
node->label, node->next->label, secname); node->label, node->next->label, secname);
} }
...@@ -13745,9 +13746,6 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) ...@@ -13745,9 +13746,6 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel)
it keeps its location until the end of function. */ it keeps its location until the end of function. */
if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
{ {
enum var_init_status initialized =
NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
if (!current_function_decl) if (!current_function_decl)
endname = text_end_label; endname = text_end_label;
else else
...@@ -13757,20 +13755,9 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) ...@@ -13757,20 +13755,9 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel)
endname = ggc_strdup (label_id); endname = ggc_strdup (label_id);
} }
initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
varloc = NOTE_VAR_LOCATION (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->var_loc_note);
if (!toplevel || by_reference) descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
{
gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
/* Single part. */
if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
descr = mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0),
TYPE_MODE (TREE_TYPE (decl)), initialized);
else
descr = NULL;
descr = loc_by_reference (descr, decl);
}
else
descr = loc_descriptor (varloc, DECL_MODE (decl), initialized);
add_loc_descr_to_loc_list (&list, descr, node->label, endname, secname); add_loc_descr_to_loc_list (&list, descr, node->label, endname, secname);
} }
return list; return list;
...@@ -13948,11 +13935,7 @@ loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev) ...@@ -13948,11 +13935,7 @@ loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
If WANT_ADDRESS is 1, expression computing address of LOC will be returned If WANT_ADDRESS is 1, expression computing address of LOC will be returned
if WANT_ADDRESS is 2, expression computing address useable in location if WANT_ADDRESS is 2, expression computing address useable in location
will be returned (i.e. DW_OP_reg can be used will be returned (i.e. DW_OP_reg can be used
to refer to register values) to refer to register values). */
TODO: Dwarf4 adds types to the stack machine that ought to be used here
DW_OP_stack_value will help in cases where we fail to find address of the
expression.
*/
static dw_loc_list_ref static dw_loc_list_ref
loc_list_from_tree (tree loc, int want_address) loc_list_from_tree (tree loc, int want_address)
...@@ -14087,8 +14070,8 @@ loc_list_from_tree (tree loc, int want_address) ...@@ -14087,8 +14070,8 @@ loc_list_from_tree (tree loc, int want_address)
var_loc_list *loc_list = lookup_decl_loc (loc); var_loc_list *loc_list = lookup_decl_loc (loc);
if (loc_list && loc_list->first if (loc_list && loc_list->first
&& (list_ret = dw_loc_list (loc_list, loc, want_address == 2))) && (list_ret = dw_loc_list (loc_list, loc, want_address)))
have_address = 1; have_address = want_address != 0;
else if (rtl == NULL_RTX) else if (rtl == NULL_RTX)
{ {
expansion_failed (loc, NULL_RTX, "DECL has no RTL"); expansion_failed (loc, NULL_RTX, "DECL has no RTL");
......
2009-10-05 Jakub Jelinek <jakub@redhat.com>
PR debug/41558
* gcc.dg/guality/guality.exp: Move gdb-test proc into...
* lib/gcc-gdb-test.exp: ... here. New file.
* gfortran.dg/guality/guality.exp: New file.
* gfortran.dg/guality/pr41558.f90: New test.
* gfortran.dg/guality/arg1.f90: New test.
2009-10-05 Paul Thomas <pault@gcc.gnu.org> 2009-10-05 Paul Thomas <pault@gcc.gnu.org>
* gfortran.dg/dynamic_dispatch_1.f90: New test. * gfortran.dg/dynamic_dispatch_1.f90: New test.
......
# This harness is for tests that should be run at all optimisation levels. # This harness is for tests that should be run at all optimisation levels.
load_lib gcc-dg.exp load_lib gcc-dg.exp
load_lib gcc-gdb-test.exp
# Disable on darwin until radr://7264615 is resolved. # Disable on darwin until radr://7264615 is resolved.
if { [istarget *-*-darwin*] } { if { [istarget *-*-darwin*] } {
...@@ -20,82 +21,6 @@ proc check_guality {args} { ...@@ -20,82 +21,6 @@ proc check_guality {args} {
return $ret return $ret
} }
# Utility for testing variable values using gdb, invoked via dg-final.
# Call pass if variable has the desired value, otherwise fail.
#
# Argument 0 is the line number on which to put a breakpoint
# Argument 1 is the name of the variable to be checked
# Argument 2 is the expected value of the variable
# Argument 3 handles expected failures and the like
proc gdb-test { args } {
if { ![isnative] || [is_remote target] } { return }
if { [llength $args] >= 4 } {
switch [dg-process-target [lindex $args 3]] {
"S" { }
"N" { return }
"F" { setup_xfail "*-*-*" }
"P" { }
}
}
# This assumes that we are three frames down from dg-test, and that
# it still stores the filename of the testcase in a local variable "name".
# A cleaner solution would require a new DejaGnu release.
upvar 2 name testcase
upvar 2 prog prog
set gdb_name $::env(GUALITY_GDB_NAME)
set testname "$testcase line [lindex $args 0] [lindex $args 1] == [lindex $args 2]"
set output_file "[file rootname [file tail $prog]].exe"
set cmd_file "[file rootname [file tail $prog]].gdb"
set fd [open $cmd_file "w"]
puts $fd "break [lindex $args 0]"
puts $fd "run"
puts $fd "print [lindex $args 1]"
puts $fd "print [lindex $args 2]"
puts $fd "quit"
close $fd
send_log "Spawning: $gdb_name -nx -nw -quiet -x $cmd_file ./$output_file\n"
set res [remote_spawn target "$gdb_name -nx -nw -quiet -x $cmd_file ./$output_file"]
if { $res < 0 || $res == "" } {
unsupported "$testname"
return
}
remote_expect target [timeout_value] {
-re {[\n\r]\$1 = ([^\n\r]*)[\n\r]+\$2 = ([^\n\r]*)[\n\r]} {
set first $expect_out(1,string)
set second $expect_out(2,string)
if { $first == $second } {
pass "$testname"
} else {
send_log "$first != $second\n"
fail "$testname"
}
remote_close target
return
}
# Too old GDB
-re "Unhandled dwarf expression|Error in sourced command file" {
unsupported "$testname"
remote_close target
return
}
timeout {
unsupported "$testname"
remote_close target
return
}
}
remote_close target
unsupported "$testname"
return
}
dg-init dg-init
global GDB global GDB
......
! { dg-do run }
! { dg-options "-g" }
integer :: a(10), b(12)
call sub (a, 10)
call sub (b, 12)
write (*,*) a, b
end
subroutine sub (a, n)
integer :: a(n), n
do i = 1, n
a(i) = i
end do
write (*,*) a ! { dg-final { gdb-test 14 "a(10)" "10" } }
end subroutine
# This harness is for tests that should be run at all optimisation levels.
load_lib gfortran-dg.exp
load_lib gcc-gdb-test.exp
# Disable on darwin until radr://7264615 is resolved.
if { [istarget *-*-darwin*] } {
return
}
dg-init
global GDB
if ![info exists ::env(GUALITY_GDB_NAME)] {
if [info exists GDB] {
set guality_gdb_name "$GDB"
} else {
set guality_gdb_name "[transform gdb]"
}
setenv GUALITY_GDB_NAME "$guality_gdb_name"
}
gfortran-dg-runtest [lsort [glob $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ]] ""
if [info exists guality_gdb_name] {
unsetenv GUALITY_GDB_NAME
}
dg-finish
! PR debug/41558
! { dg-do run }
! { dg-options "-g" }
subroutine f (s)
character(len=3) :: s
write (*,*), s ! { dg-final { gdb-test 7 "s" "'foo'" } }
end
call f ('foo')
end
# Copyright (C) 2009 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
# Utility for testing variable values using gdb, invoked via dg-final.
# Call pass if variable has the desired value, otherwise fail.
#
# Argument 0 is the line number on which to put a breakpoint
# Argument 1 is the name of the variable to be checked
# Argument 2 is the expected value of the variable
# Argument 3 handles expected failures and the like
proc gdb-test { args } {
if { ![isnative] || [is_remote target] } { return }
if { [llength $args] >= 4 } {
switch [dg-process-target [lindex $args 3]] {
"S" { }
"N" { return }
"F" { setup_xfail "*-*-*" }
"P" { }
}
}
# This assumes that we are three frames down from dg-test, and that
# it still stores the filename of the testcase in a local variable "name".
# A cleaner solution would require a new DejaGnu release.
upvar 2 name testcase
upvar 2 prog prog
set gdb_name $::env(GUALITY_GDB_NAME)
set testname "$testcase line [lindex $args 0] [lindex $args 1] == [lindex $args 2]"
set output_file "[file rootname [file tail $prog]].exe"
set cmd_file "[file rootname [file tail $prog]].gdb"
set fd [open $cmd_file "w"]
puts $fd "break [lindex $args 0]"
puts $fd "run"
puts $fd "print [lindex $args 1]"
puts $fd "print [lindex $args 2]"
puts $fd "quit"
close $fd
send_log "Spawning: $gdb_name -nx -nw -quiet -x $cmd_file ./$output_file\n"
set res [remote_spawn target "$gdb_name -nx -nw -quiet -x $cmd_file ./$output_file"]
if { $res < 0 || $res == "" } {
unsupported "$testname"
return
}
remote_expect target [timeout_value] {
-re {[\n\r]\$1 = ([^\n\r]*)[\n\r]+\$2 = ([^\n\r]*)[\n\r]} {
set first $expect_out(1,string)
set second $expect_out(2,string)
if { $first == $second } {
pass "$testname"
} else {
send_log "$first != $second\n"
fail "$testname"
}
remote_close target
return
}
# Too old GDB
-re "Unhandled dwarf expression|Error in sourced command file" {
unsupported "$testname"
remote_close target
return
}
timeout {
unsupported "$testname"
remote_close target
return
}
}
remote_close target
unsupported "$testname"
return
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment