summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/c-decl.c2
-rw-r--r--gcc/dwarf2out.c77
-rw-r--r--gcc/except.h1
-rw-r--r--gcc/expr.c2
-rw-r--r--gcc/libgcc2.c24
-rw-r--r--gcc/tree.h1
7 files changed, 111 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 13948ef94c7..bcf67e3d422 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+Sat Sep 27 11:02:38 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * c-decl.c (init_decl_processing): Add __builtin_dwarf_reg_size.
+ * tree.h (built_in_function): Likewise.
+ * expr.c (expand_builtin): Likewise.
+ * except.h: Likewise.
+ * dwarf2out.c (expand_builtin_dwarf_reg_size): New fn.
+ * libgcc2.c (copy_reg): New fn.
+ (__throw): Use it.
+
Fri Sep 26 08:54:59 1997 Paul Eggert <eggert@twinsun.com>
* c-typeck.c (build_binary_op): Warn about comparing signed vs
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 09143e41fce..5774f755b03 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -3200,6 +3200,8 @@ init_decl_processing ()
builtin_function ("__builtin_dwarf_fp_regnum",
build_function_type (unsigned_type_node, endlink),
BUILT_IN_DWARF_FP_REGNUM, NULL_PTR);
+ builtin_function ("__builtin_dwarf_reg_size", int_ftype_int,
+ BUILT_IN_DWARF_REG_SIZE, NULL_PTR);
builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr,
BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 56ce82b8e01..6ad1c1b0ae9 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -502,6 +502,83 @@ reg_number (rtl)
return regno;
}
+struct reg_size_range
+{
+ int beg;
+ int end;
+ int size;
+};
+
+/* Given a register number in REG_TREE, return an rtx for its size in bytes.
+ We do this in kind of a roundabout way, by building up a list of
+ register size ranges and seeing where our register falls in one of those
+ ranges. We need to do it this way because REG_TREE is not a constant,
+ and the target macros were not designed to make this task easy. */
+
+rtx
+expand_builtin_dwarf_reg_size (reg_tree, target)
+ tree reg_tree;
+ rtx target;
+{
+ int i, n_ranges, size;
+ struct reg_size_range ranges[5];
+ tree t, t2;
+
+ ranges[0].beg = 0;
+ ranges[0].size = GET_MODE_SIZE (reg_raw_mode[0]);
+ n_ranges = 1;
+
+ for (i = 1; i < FIRST_PSEUDO_REGISTER; ++i)
+ {
+ size = GET_MODE_SIZE (reg_raw_mode[i]);
+ if (size != ranges[n_ranges-1].size)
+ {
+ ranges[n_ranges-1].end = i-1;
+ ranges[n_ranges].beg = i;
+ ranges[n_ranges].size = GET_MODE_SIZE (reg_raw_mode[i]);
+ ++n_ranges;
+ assert (n_ranges < 5);
+ }
+ }
+ ranges[n_ranges-1].end = i-1;
+
+ /* The usual case: fp regs surrounded by general regs. */
+ if (n_ranges == 3 && ranges[0].size == ranges[2].size)
+ {
+ assert ((DWARF_FRAME_REGNUM (ranges[1].end)
+ - DWARF_FRAME_REGNUM (ranges[1].beg))
+ == ranges[1].end - ranges[1].beg);
+ t = fold (build (GE_EXPR, integer_type_node, reg_tree,
+ build_int_2 (DWARF_FRAME_REGNUM (ranges[1].beg), 0)));
+ t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
+ build_int_2 (DWARF_FRAME_REGNUM (ranges[1].end), 0)));
+ t = fold (build (TRUTH_ANDIF_EXPR, integer_type_node, t, t2));
+ t = fold (build (COND_EXPR, integer_type_node, t,
+ build_int_2 (ranges[1].size, 0),
+ build_int_2 (ranges[0].size, 0)));
+ }
+ else
+ {
+ --n_ranges;
+ t = build_int_2 (ranges[n_ranges].size, 0);
+ size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
+ for (; n_ranges--; )
+ {
+ assert ((DWARF_FRAME_REGNUM (ranges[n_ranges].end)
+ - DWARF_FRAME_REGNUM (ranges[n_ranges].beg))
+ == ranges[n_ranges].end - ranges[n_ranges].beg);
+ assert (DWARF_FRAME_REGNUM (ranges[n_ranges].beg) < size);
+ size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
+ t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
+ build_int_2 (DWARF_FRAME_REGNUM
+ (ranges[n_ranges].end), 0)));
+ t = fold (build (COND_EXPR, integer_type_node, t2,
+ build_int_2 (ranges[n_ranges].size, 0), t));
+ }
+ }
+ return expand_expr (t, target, Pmode, 0);
+}
+
/* Convert a DWARF call frame info. operation to its string name */
static char *
diff --git a/gcc/except.h b/gcc/except.h
index 71c49c25a77..fc2c37b3dbb 100644
--- a/gcc/except.h
+++ b/gcc/except.h
@@ -292,4 +292,5 @@ rtx expand_builtin_frob_return_addr PROTO((tree));
rtx expand_builtin_extract_return_addr PROTO((tree));
void expand_builtin_set_return_addr_reg PROTO((tree));
void expand_builtin_set_eh_regs PROTO((tree, tree));
+rtx expand_builtin_dwarf_reg_size PROTO((tree, rtx));
#endif
diff --git a/gcc/expr.c b/gcc/expr.c
index 4ed0b39d710..1b5d5091c02 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -9159,6 +9159,8 @@ expand_builtin (exp, target, subtarget, mode, ignore)
#ifdef DWARF2_UNWIND_INFO
case BUILT_IN_DWARF_FP_REGNUM:
return expand_builtin_dwarf_fp_regnum ();
+ case BUILT_IN_DWARF_REG_SIZE:
+ return expand_builtin_dwarf_reg_size (TREE_VALUE (arglist), target);
#endif
case BUILT_IN_FROB_RETURN_ADDR:
return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c
index 2b9c6bc8864..6a49a1b2acb 100644
--- a/gcc/libgcc2.c
+++ b/gcc/libgcc2.c
@@ -3556,6 +3556,22 @@ put_reg (unsigned reg, void *val, frame_state *udata)
abort ();
}
+/* Copy the saved value for register REG from frame UDATA to frame
+ TARGET_UDATA. Unlike the previous two functions, this can handle
+ registers that are not one word large. */
+
+static void
+copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
+{
+ if (udata->saved[reg] == REG_SAVED_OFFSET
+ && target_udata->saved[reg] == REG_SAVED_OFFSET)
+ memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
+ udata->cfa + udata->reg_or_offset[reg],
+ __builtin_dwarf_reg_size (reg));
+ else
+ abort ();
+}
+
/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
frame called by UDATA or 0. */
@@ -3729,8 +3745,7 @@ label:
&& udata->reg_or_offset[udata->retaddr_column] == i)
continue;
#endif
- val = get_reg (i, udata, sub_udata);
- put_reg (i, val, my_udata);
+ copy_reg (i, udata, my_udata);
}
pc = get_return_addr (udata, sub_udata) - 1;
@@ -3744,10 +3759,7 @@ label:
{
i = udata->reg_or_offset[udata->retaddr_column];
if (in_reg_window (i, udata))
- {
- val = get_reg (i, udata, sub_udata);
- put_reg (i, val, my_udata);
- }
+ copy_reg (i, udata, sub_udata);
}
#endif
}
diff --git a/gcc/tree.h b/gcc/tree.h
index d594bd92ccd..4f43f6ffe6a 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -105,6 +105,7 @@ enum built_in_function
BUILT_IN_FP, BUILT_IN_SP,
BUILT_IN_UNWIND_INIT,
BUILT_IN_DWARF_FP_REGNUM,
+ BUILT_IN_DWARF_REG_SIZE,
BUILT_IN_FROB_RETURN_ADDR,
BUILT_IN_EXTRACT_RETURN_ADDR,
BUILT_IN_SET_RETURN_ADDR_REG,