diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/c-decl.c | 2 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 77 | ||||
-rw-r--r-- | gcc/except.h | 1 | ||||
-rw-r--r-- | gcc/expr.c | 2 | ||||
-rw-r--r-- | gcc/libgcc2.c | 24 | ||||
-rw-r--r-- | gcc/tree.h | 1 |
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, |