From e4e8248d79d8461adf8b0cf22086e85a4c9ee0a4 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 1 Jul 2005 06:51:39 +0000 Subject: [PATCH] gas/ 2005-07-01 Jan Beulich * config/tc-ia64.c (line_separator_chars): Add '{' and '}'. (output_spill_psprel, output_spill_psprel_p): Combine. (output_spill_sprel, output_spill_sprel_p): Combine. (output_spill_reg, output_spill_regp_p): Combine. (process_one_record): Handle psp_psprel. (parse_predicate_and_operand): New. (convert_expr_to_ab_reg): Two new parameters. Return void. Always initialize output values. Emit diagnostic case here. (convert_expr_to_xy_reg): Likewise. Don't allow r0, f0, and f1. (add_unwind_entry): New second parameter. Allow first parameter to be NULL. Parse optional tag, emit warning about further support for it otherwise being missing. Check end-of-line when requested. (dot_fframe): Clear operand when wrong. Allow tag. (dot_vframe): Likewise. (dot_vframesp): Likewise. Rename parameter, issue warning when psp relative. (dot_vframepsp): Remove. (dot_altrp): Clear operand when wrong. Allow tag. (dot_save): Likewise. Let default case also go through add_unwind_entry. (dot_savemem): Likewise. (dot_restore): Don't return when wrong operand. Allow tag. (dot_spillreg, dot_spillreg_p): Combine. Simplify by using parse_predicate_and_operand and the new arguments to convert_expr_to_ab_reg and convert_expr_to_xy_reg. Don't return when wrong operand. Allow tag. (dot_restorereg, dot_restorereg_p): Likewise. (dot_spillmem, dot_spillmem_p): Likewise. (dot_saveg): Clear operand when wrong. Perform tighter operand checks. Allow tag. (dot_savef): Likewise. (dot_saveb): Likewise. (dot_savegf): Likewise. (dot_spill): Remove end-of-line check. Combine. Simplify by using parse_predicate_and_operand and the new arguments to convert_expr_to_ab_reg and convert_expr_to_xy_reg. Don't return when wrong operand. Allow tag. (popcount): New. (dot_label_state): Don't return when wrong operand. (dot_copy_state): Likewise. (dot_unwabi): Likewise. Check if in prologue. (dot_body): Don't call demand_empty_rest_of_line. (dot_prologue): Type of mask and grsave is unsigned. Perform tighter operand checks. (md_pseudo_table): Also use dot_restorereg for .restorereg.p. Also use dot_spillreg for .spillreg.p. Also use dot_spillmem for .spillpsp.p and .spillsp.p. Also use dot_vframesp for .vframepsp. (parse_operand): New second parameter. Don't deal with '}' here anymore. Don't advance past end-of-line. (parse_operands): Pass second argument to parse_operand. (ia64_start_line): Prevent out-of-bounds access through input_line_pointer. Deal with '}' here. (ia64_unrecognized_line): Don't deal with '}' here. (dot_alias): Use ignore_rest_of_line not its deprecated alias discard_rest_of_line. gas/testsuite/ 2005-07-01 Jan Beulich * gas/ia64/group-2.s: Use register as second operand of .prologue. * gas/ia64/unwind-err.s: Add check for .vframesp. * gas/ia64/unwind-err.l: Adjust. * gas/ia64/strange.[sd]: New. * gas/ia64/unwind-bad.[sl]: New. * gas/ia64/unwind-ok.[sd]: New. * gas/ia64/ia64.exp: Run new tests. --- gas/ChangeLog | 58 ++ gas/config/tc-ia64.c | 1234 +++++++++++++-------------- gas/testsuite/ChangeLog | 10 + gas/testsuite/gas/ia64/group-2.s | 2 +- gas/testsuite/gas/ia64/ia64.exp | 3 + gas/testsuite/gas/ia64/strange.d | 19 + gas/testsuite/gas/ia64/strange.s | 18 + gas/testsuite/gas/ia64/unwind-bad.l | 51 ++ gas/testsuite/gas/ia64/unwind-bad.s | 155 ++++ gas/testsuite/gas/ia64/unwind-err.l | 37 +- gas/testsuite/gas/ia64/unwind-err.s | 1 + gas/testsuite/gas/ia64/unwind-ok.d | 224 +++++ gas/testsuite/gas/ia64/unwind-ok.s | 272 ++++++ 13 files changed, 1419 insertions(+), 665 deletions(-) create mode 100644 gas/testsuite/gas/ia64/strange.d create mode 100644 gas/testsuite/gas/ia64/strange.s create mode 100644 gas/testsuite/gas/ia64/unwind-bad.l create mode 100644 gas/testsuite/gas/ia64/unwind-bad.s create mode 100644 gas/testsuite/gas/ia64/unwind-ok.d create mode 100644 gas/testsuite/gas/ia64/unwind-ok.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 9798c2881e3..2fd0e6370fb 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,61 @@ +2005-07-01 Jan Beulich + + * config/tc-ia64.c (line_separator_chars): Add '{' and '}'. + (output_spill_psprel, output_spill_psprel_p): Combine. + (output_spill_sprel, output_spill_sprel_p): Combine. + (output_spill_reg, output_spill_regp_p): Combine. + (process_one_record): Handle psp_psprel. + (parse_predicate_and_operand): New. + (convert_expr_to_ab_reg): Two new parameters. Return void. Always + initialize output values. Emit diagnostic case here. + (convert_expr_to_xy_reg): Likewise. Don't allow r0, f0, and f1. + (add_unwind_entry): New second parameter. Allow first parameter to + be NULL. Parse optional tag, emit warning about further support for + it otherwise being missing. Check end-of-line when requested. + (dot_fframe): Clear operand when wrong. Allow tag. + (dot_vframe): Likewise. + (dot_vframesp): Likewise. Rename parameter, issue warning when psp + relative. + (dot_vframepsp): Remove. + (dot_altrp): Clear operand when wrong. Allow tag. + (dot_save): Likewise. Let default case also go through + add_unwind_entry. + (dot_savemem): Likewise. + (dot_restore): Don't return when wrong operand. Allow tag. + (dot_spillreg, dot_spillreg_p): Combine. Simplify by using + parse_predicate_and_operand and the new arguments to + convert_expr_to_ab_reg and convert_expr_to_xy_reg. Don't return + when wrong operand. Allow tag. + (dot_restorereg, dot_restorereg_p): Likewise. + (dot_spillmem, dot_spillmem_p): Likewise. + (dot_saveg): Clear operand when wrong. Perform tighter operand + checks. Allow tag. + (dot_savef): Likewise. + (dot_saveb): Likewise. + (dot_savegf): Likewise. + (dot_spill): Remove end-of-line check. Combine. Simplify by using + parse_predicate_and_operand and the new arguments to + convert_expr_to_ab_reg and convert_expr_to_xy_reg. Don't return + when wrong operand. Allow tag. + (popcount): New. + (dot_label_state): Don't return when wrong operand. + (dot_copy_state): Likewise. + (dot_unwabi): Likewise. Check if in prologue. + (dot_body): Don't call demand_empty_rest_of_line. + (dot_prologue): Type of mask and grsave is unsigned. Perform tighter + operand checks. + (md_pseudo_table): Also use dot_restorereg for .restorereg.p. Also + use dot_spillreg for .spillreg.p. Also use dot_spillmem for + .spillpsp.p and .spillsp.p. Also use dot_vframesp for .vframepsp. + (parse_operand): New second parameter. Don't deal with '}' here + anymore. Don't advance past end-of-line. + (parse_operands): Pass second argument to parse_operand. + (ia64_start_line): Prevent out-of-bounds access through + input_line_pointer. Deal with '}' here. + (ia64_unrecognized_line): Don't deal with '}' here. + (dot_alias): Use ignore_rest_of_line not its deprecated alias + discard_rest_of_line. + 2005-06-30 Zack Weinberg * config/tc-arm.c (T_OPCODE_BRANCH, encode_arm_addr_mode_2) diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c index cab32cd0473..fe0f9a00b2f 100644 --- a/gas/config/tc-ia64.c +++ b/gas/config/tc-ia64.c @@ -193,7 +193,7 @@ const char line_comment_chars[] = "#"; /* Characters which may be used to separate multiple commands on a single line. */ -const char line_separator_chars[] = ";"; +const char line_separator_chars[] = ";{}"; /* Characters which are used to indicate an exponent in a floating point number. */ @@ -736,6 +736,7 @@ static struct /* TRUE if processing unwind directives in a prologue region. */ unsigned int prologue : 1; unsigned int prologue_mask : 4; + unsigned int prologue_gr : 7; unsigned int body : 1; unsigned int insn : 1; unsigned int prologue_count; /* number of .prologues seen so far */ @@ -762,11 +763,9 @@ static void dot_proc PARAMS ((int)); static void dot_fframe PARAMS ((int)); static void dot_vframe PARAMS ((int)); static void dot_vframesp PARAMS ((int)); -static void dot_vframepsp PARAMS ((int)); static void dot_save PARAMS ((int)); static void dot_restore PARAMS ((int)); static void dot_restorereg PARAMS ((int)); -static void dot_restorereg_p PARAMS ((int)); static void dot_handlerdata PARAMS ((int)); static void dot_unwentry PARAMS ((int)); static void dot_altrp PARAMS ((int)); @@ -778,8 +777,6 @@ static void dot_savegf PARAMS ((int)); static void dot_spill PARAMS ((int)); static void dot_spillreg PARAMS ((int)); static void dot_spillmem PARAMS ((int)); -static void dot_spillreg_p PARAMS ((int)); -static void dot_spillmem_p PARAMS ((int)); static void dot_label_state PARAMS ((int)); static void dot_copy_state PARAMS ((int)); static void dot_unwabi PARAMS ((int)); @@ -809,14 +806,14 @@ static void dot_serialize PARAMS ((int)); static void dot_dv_mode PARAMS ((int)); static void dot_entry PARAMS ((int)); static void dot_mem_offset PARAMS ((int)); -static void add_unwind_entry PARAMS((unw_rec_list *ptr)); +static void add_unwind_entry PARAMS((unw_rec_list *, int)); static symbolS *declare_register PARAMS ((const char *name, int regnum)); static void declare_register_set PARAMS ((const char *, int, int)); static unsigned int operand_width PARAMS ((enum ia64_opnd)); static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode *idesc, int index, expressionS *e)); -static int parse_operand PARAMS ((expressionS *e)); +static int parse_operand PARAMS ((expressionS *, int)); static struct ia64_opcode * parse_operands PARAMS ((struct ia64_opcode *)); static void build_insn PARAMS ((struct slot *, bfd_vma *)); static void emit_one_bundle PARAMS ((void)); @@ -937,15 +934,11 @@ static unw_rec_list *output_unwabi PARAMS ((unsigned long, unsigned long)); static unw_rec_list *output_epilogue PARAMS ((unsigned long)); static unw_rec_list *output_label_state PARAMS ((unsigned long)); static unw_rec_list *output_copy_state PARAMS ((unsigned long)); -static unw_rec_list *output_spill_psprel PARAMS ((unsigned int, unsigned int, unsigned int)); -static unw_rec_list *output_spill_sprel PARAMS ((unsigned int, unsigned int, unsigned int)); -static unw_rec_list *output_spill_psprel_p PARAMS ((unsigned int, unsigned int, unsigned int, +static unw_rec_list *output_spill_psprel PARAMS ((unsigned int, unsigned int, unsigned int, unsigned int)); -static unw_rec_list *output_spill_sprel_p PARAMS ((unsigned int, unsigned int, unsigned int, +static unw_rec_list *output_spill_sprel PARAMS ((unsigned int, unsigned int, unsigned int, unsigned int)); static unw_rec_list *output_spill_reg PARAMS ((unsigned int, unsigned int, unsigned int, - unsigned int)); -static unw_rec_list *output_spill_reg_p PARAMS ((unsigned int, unsigned int, unsigned int, unsigned int, unsigned int)); static void process_one_record PARAMS ((unw_rec_list *, vbyte_func)); static void process_unw_records PARAMS ((unw_rec_list *, vbyte_func)); @@ -956,8 +949,9 @@ static unsigned long slot_index PARAMS ((unsigned long, fragS *, int)); static unw_rec_list *optimize_unw_records PARAMS ((unw_rec_list *)); static void fixup_unw_records PARAMS ((unw_rec_list *, int)); -static int convert_expr_to_ab_reg PARAMS ((expressionS *, unsigned int *, unsigned int *)); -static int convert_expr_to_xy_reg PARAMS ((expressionS *, unsigned int *, unsigned int *)); +static int parse_predicate_and_operand PARAMS ((expressionS *, unsigned *, const char *)); +static void convert_expr_to_ab_reg PARAMS ((const expressionS *, unsigned int *, unsigned int *, const char *, int)); +static void convert_expr_to_xy_reg PARAMS ((const expressionS *, unsigned int *, unsigned int *, const char *, int)); static unsigned int get_saved_prologue_count PARAMS ((unsigned long)); static void save_prologue_count PARAMS ((unsigned long, unsigned int)); static void free_saved_prologue_counts PARAMS ((void)); @@ -2288,39 +2282,13 @@ output_copy_state (unsigned long label) } static unw_rec_list * -output_spill_psprel (ab, reg, offset) - unsigned int ab; - unsigned int reg; - unsigned int offset; -{ - unw_rec_list *ptr = alloc_record (spill_psprel); - ptr->r.record.x.ab = ab; - ptr->r.record.x.reg = reg; - ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset); - return ptr; -} - -static unw_rec_list * -output_spill_sprel (ab, reg, offset) - unsigned int ab; - unsigned int reg; - unsigned int offset; -{ - unw_rec_list *ptr = alloc_record (spill_sprel); - ptr->r.record.x.ab = ab; - ptr->r.record.x.reg = reg; - ptr->r.record.x.spoff = offset / 4; - return ptr; -} - -static unw_rec_list * -output_spill_psprel_p (ab, reg, offset, predicate) +output_spill_psprel (ab, reg, offset, predicate) unsigned int ab; unsigned int reg; unsigned int offset; unsigned int predicate; { - unw_rec_list *ptr = alloc_record (spill_psprel_p); + unw_rec_list *ptr = alloc_record (predicate ? spill_psprel_p : spill_psprel); ptr->r.record.x.ab = ab; ptr->r.record.x.reg = reg; ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset); @@ -2329,13 +2297,13 @@ output_spill_psprel_p (ab, reg, offset, predicate) } static unw_rec_list * -output_spill_sprel_p (ab, reg, offset, predicate) +output_spill_sprel (ab, reg, offset, predicate) unsigned int ab; unsigned int reg; unsigned int offset; unsigned int predicate; { - unw_rec_list *ptr = alloc_record (spill_sprel_p); + unw_rec_list *ptr = alloc_record (predicate ? spill_sprel_p : spill_sprel); ptr->r.record.x.ab = ab; ptr->r.record.x.reg = reg; ptr->r.record.x.spoff = offset / 4; @@ -2344,29 +2312,14 @@ output_spill_sprel_p (ab, reg, offset, predicate) } static unw_rec_list * -output_spill_reg (ab, reg, targ_reg, xy) - unsigned int ab; - unsigned int reg; - unsigned int targ_reg; - unsigned int xy; -{ - unw_rec_list *ptr = alloc_record (spill_reg); - ptr->r.record.x.ab = ab; - ptr->r.record.x.reg = reg; - ptr->r.record.x.treg = targ_reg; - ptr->r.record.x.xy = xy; - return ptr; -} - -static unw_rec_list * -output_spill_reg_p (ab, reg, targ_reg, xy, predicate) +output_spill_reg (ab, reg, targ_reg, xy, predicate) unsigned int ab; unsigned int reg; unsigned int targ_reg; unsigned int xy; unsigned int predicate; { - unw_rec_list *ptr = alloc_record (spill_reg_p); + unw_rec_list *ptr = alloc_record (predicate ? spill_reg_p : spill_reg); ptr->r.record.x.ab = ab; ptr->r.record.x.reg = reg; ptr->r.record.x.treg = targ_reg; @@ -2577,6 +2530,28 @@ calc_record_size (list) return vbyte_count; } +/* Return the number of bits set in the input value. + Perhaps this has a better place... */ +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# define popcount __builtin_popcount +#else +static int +popcount (unsigned x) +{ + static const unsigned char popcnt[16] = + { + 0, 1, 1, 2, + 1, 2, 2, 3, + 1, 2, 2, 3, + 2, 3, 3, 4 + }; + + if (x < NELEMS (popcnt)) + return popcnt[x]; + return popcnt[x % NELEMS (popcnt)] + popcount (x / NELEMS (popcnt)); +} +#endif + /* Update IMASK bitmask to reflect the fact that one or more registers of type TYPE are saved starting at instruction with index T. If N bits are set in REGMASK, it is assumed that instructions T through @@ -3000,17 +2975,43 @@ ia64_convert_frag (fragS *frag) } static int -convert_expr_to_ab_reg (e, ab, regp) - expressionS *e; +parse_predicate_and_operand (e, qp, po) + expressionS * e; + unsigned * qp; + const char * po; +{ + int sep = parse_operand (e, ','); + + *qp = e->X_add_number - REG_P; + if (e->X_op != O_register || *qp > 63) + { + as_bad ("First operand to .%s must be a predicate", po); + *qp = 0; + } + else if (*qp == 0) + as_warn ("Pointless use of p0 as first operand to .%s", po); + if (sep == ',') + sep = parse_operand (e, ','); + else + e->X_op = O_absent; + return sep; +} + +static void +convert_expr_to_ab_reg (e, ab, regp, po, n) + const expressionS *e; unsigned int *ab; unsigned int *regp; + const char * po; + int n; { - unsigned int reg; + unsigned int reg = e->X_add_number; + + *ab = *regp = 0; /* Anything valid is good here. */ if (e->X_op != O_register) - return 0; + reg = REG_GR; /* Anything invalid is good here. */ - reg = e->X_add_number; if (reg >= (REG_GR + 4) && reg <= (REG_GR + 7)) { *ab = 0; @@ -3045,31 +3046,33 @@ convert_expr_to_ab_reg (e, ab, regp) case REG_AR + AR_LC: *regp = 10; break; default: - return 0; + as_bad ("Operand %d to .%s must be a preserved register", n, po); + break; } } - return 1; } -static int -convert_expr_to_xy_reg (e, xy, regp) - expressionS *e; +static void +convert_expr_to_xy_reg (e, xy, regp, po, n) + const expressionS *e; unsigned int *xy; unsigned int *regp; + const char * po; + int n; { - unsigned int reg; + unsigned int reg = e->X_add_number; - if (e->X_op != O_register) - return 0; + *xy = *regp = 0; /* Anything valid is good here. */ - reg = e->X_add_number; + if (e->X_op != O_register) + reg = REG_GR; /* Anything invalid is good here. */ - if (/* reg >= REG_GR && */ reg <= (REG_GR + 127)) + if (reg >= (REG_GR + 1) && reg <= (REG_GR + 127)) { *xy = 0; *regp = reg - REG_GR; } - else if (reg >= REG_FR && reg <= (REG_FR + 127)) + else if (reg >= (REG_FR + 2) && reg <= (REG_FR + 127)) { *xy = 1; *regp = reg - REG_FR; @@ -3080,8 +3083,7 @@ convert_expr_to_xy_reg (e, xy, regp) *regp = reg - REG_BR; } else - return -1; - return 1; + as_bad ("Operand %d to .%s must be a writable register", n, po); } static void @@ -3210,18 +3212,48 @@ in_body (const char *directive) } static void -add_unwind_entry (ptr) +add_unwind_entry (ptr, sep) unw_rec_list *ptr; + int sep; { - if (unwind.tail) - unwind.tail->next = ptr; - else - unwind.list = ptr; - unwind.tail = ptr; + if (ptr) + { + if (unwind.tail) + unwind.tail->next = ptr; + else + unwind.list = ptr; + unwind.tail = ptr; + + /* The current entry can in fact be a chain of unwind entries. */ + if (unwind.current_entry == NULL) + unwind.current_entry = ptr; + } /* The current entry can in fact be a chain of unwind entries. */ if (unwind.current_entry == NULL) unwind.current_entry = ptr; + + if (sep == ',') + { + /* Parse a tag permitted for the current directive. */ + int ch; + + SKIP_WHITESPACE (); + ch = get_symbol_end (); + /* FIXME: For now, just issue a warning that this isn't implemented. */ + { + static int warned; + + if (!warned) + { + warned = 1; + as_warn ("Tags on unwind pseudo-ops aren't supported, yet"); + } + } + *input_line_pointer = ch; + } + if (sep != NOT_A_CHAR) + demand_empty_rest_of_line (); } static void @@ -3229,16 +3261,19 @@ dot_fframe (dummy) int dummy ATTRIBUTE_UNUSED; { expressionS e; + int sep; if (!in_prologue ("fframe")) return; - parse_operand (&e); + sep = parse_operand (&e, ','); if (e.X_op != O_constant) - as_bad ("Operand to .fframe must be a constant"); - else - add_unwind_entry (output_mem_stack_f (e.X_add_number)); + { + as_bad ("First operand to .fframe must be a constant"); + e.X_add_number = 0; + } + add_unwind_entry (output_mem_stack_f (e.X_add_number), sep); } static void @@ -3247,58 +3282,47 @@ dot_vframe (dummy) { expressionS e; unsigned reg; + int sep; if (!in_prologue ("vframe")) return; - parse_operand (&e); + sep = parse_operand (&e, ','); reg = e.X_add_number - REG_GR; - if (e.X_op == O_register && reg < 128) + if (e.X_op != O_register || reg > 127) { - add_unwind_entry (output_mem_stack_v ()); - if (! (unwind.prologue_mask & 2)) - add_unwind_entry (output_psp_gr (reg)); + as_bad ("First operand to .vframe must be a general register"); + reg = 0; } - else - as_bad ("First operand to .vframe must be a general register"); + add_unwind_entry (output_mem_stack_v (), sep); + if (! (unwind.prologue_mask & 2)) + add_unwind_entry (output_psp_gr (reg), NOT_A_CHAR); + else if (reg != unwind.prologue_gr + + (unsigned) popcount (unwind.prologue_mask & (-2 << 1))) + as_warn ("Operand of .vframe contradicts .prologue"); } static void -dot_vframesp (dummy) - int dummy ATTRIBUTE_UNUSED; +dot_vframesp (psp) + int psp; { expressionS e; + int sep; - if (!in_prologue ("vframesp")) - return; - - parse_operand (&e); - if (e.X_op == O_constant) - { - add_unwind_entry (output_mem_stack_v ()); - add_unwind_entry (output_psp_sprel (e.X_add_number)); - } - else - as_bad ("Operand to .vframesp must be a constant (sp-relative offset)"); -} - -static void -dot_vframepsp (dummy) - int dummy ATTRIBUTE_UNUSED; -{ - expressionS e; + if (psp) + as_warn (".vframepsp is meaningless, assuming .vframesp was meant"); - if (!in_prologue ("vframepsp")) + if (!in_prologue ("vframesp")) return; - parse_operand (&e); - if (e.X_op == O_constant) + sep = parse_operand (&e, ','); + if (e.X_op != O_constant) { - add_unwind_entry (output_mem_stack_v ()); - add_unwind_entry (output_psp_sprel (e.X_add_number)); + as_bad ("Operand to .vframesp must be a constant (sp-relative offset)"); + e.X_add_number = 0; } - else - as_bad ("Operand to .vframepsp must be a constant (psp-relative offset)"); + add_unwind_entry (output_mem_stack_v (), sep); + add_unwind_entry (output_psp_sprel (e.X_add_number), NOT_A_CHAR); } static void @@ -3306,106 +3330,115 @@ dot_save (dummy) int dummy ATTRIBUTE_UNUSED; { expressionS e1, e2; + unsigned reg1, reg2; int sep; - int reg1, reg2; if (!in_prologue ("save")) return; - sep = parse_operand (&e1); - if (sep != ',') - as_bad ("No second operand to .save"); - sep = parse_operand (&e2); + sep = parse_operand (&e1, ','); + if (sep == ',') + sep = parse_operand (&e2, ','); + else + e2.X_op = O_absent; reg1 = e1.X_add_number; - reg2 = e2.X_add_number - REG_GR; - /* Make sure its a valid ar.xxx reg, OR its br0, aka 'rp'. */ - if (e1.X_op == O_register) + if (e1.X_op != O_register) { - if (e2.X_op == O_register && reg2 >= 0 && reg2 < 128) - { - switch (reg1) - { - case REG_AR + AR_BSP: - add_unwind_entry (output_bsp_when ()); - add_unwind_entry (output_bsp_gr (reg2)); - break; - case REG_AR + AR_BSPSTORE: - add_unwind_entry (output_bspstore_when ()); - add_unwind_entry (output_bspstore_gr (reg2)); - break; - case REG_AR + AR_RNAT: - add_unwind_entry (output_rnat_when ()); - add_unwind_entry (output_rnat_gr (reg2)); - break; - case REG_AR + AR_UNAT: - add_unwind_entry (output_unat_when ()); - add_unwind_entry (output_unat_gr (reg2)); - break; - case REG_AR + AR_FPSR: - add_unwind_entry (output_fpsr_when ()); - add_unwind_entry (output_fpsr_gr (reg2)); - break; - case REG_AR + AR_PFS: - add_unwind_entry (output_pfs_when ()); - if (! (unwind.prologue_mask & 4)) - add_unwind_entry (output_pfs_gr (reg2)); - break; - case REG_AR + AR_LC: - add_unwind_entry (output_lc_when ()); - add_unwind_entry (output_lc_gr (reg2)); - break; - case REG_BR: - add_unwind_entry (output_rp_when ()); - if (! (unwind.prologue_mask & 8)) - add_unwind_entry (output_rp_gr (reg2)); - break; - case REG_PR: - add_unwind_entry (output_preds_when ()); - if (! (unwind.prologue_mask & 1)) - add_unwind_entry (output_preds_gr (reg2)); - break; - case REG_PRIUNAT: - add_unwind_entry (output_priunat_when_gr ()); - add_unwind_entry (output_priunat_gr (reg2)); - break; - default: - as_bad ("First operand not a valid register"); - } - } - else - as_bad (" Second operand not a valid register"); + as_bad ("First operand to .save not a register"); + reg1 = REG_PR; /* Anything valid is good here. */ + } + reg2 = e2.X_add_number - REG_GR; + if (e2.X_op != O_register || reg2 > 127) + { + as_bad ("Second operand to .save not a valid register"); + reg2 = 0; + } + switch (reg1) + { + case REG_AR + AR_BSP: + add_unwind_entry (output_bsp_when (), sep); + add_unwind_entry (output_bsp_gr (reg2), NOT_A_CHAR); + break; + case REG_AR + AR_BSPSTORE: + add_unwind_entry (output_bspstore_when (), sep); + add_unwind_entry (output_bspstore_gr (reg2), NOT_A_CHAR); + break; + case REG_AR + AR_RNAT: + add_unwind_entry (output_rnat_when (), sep); + add_unwind_entry (output_rnat_gr (reg2), NOT_A_CHAR); + break; + case REG_AR + AR_UNAT: + add_unwind_entry (output_unat_when (), sep); + add_unwind_entry (output_unat_gr (reg2), NOT_A_CHAR); + break; + case REG_AR + AR_FPSR: + add_unwind_entry (output_fpsr_when (), sep); + add_unwind_entry (output_fpsr_gr (reg2), NOT_A_CHAR); + break; + case REG_AR + AR_PFS: + add_unwind_entry (output_pfs_when (), sep); + if (! (unwind.prologue_mask & 4)) + add_unwind_entry (output_pfs_gr (reg2), NOT_A_CHAR); + else if (reg2 != unwind.prologue_gr + + (unsigned) popcount (unwind.prologue_mask & (-4 << 1))) + as_warn ("Second operand of .save contradicts .prologue"); + break; + case REG_AR + AR_LC: + add_unwind_entry (output_lc_when (), sep); + add_unwind_entry (output_lc_gr (reg2), NOT_A_CHAR); + break; + case REG_BR: + add_unwind_entry (output_rp_when (), sep); + if (! (unwind.prologue_mask & 8)) + add_unwind_entry (output_rp_gr (reg2), NOT_A_CHAR); + else if (reg2 != unwind.prologue_gr) + as_warn ("Second operand of .save contradicts .prologue"); + break; + case REG_PR: + add_unwind_entry (output_preds_when (), sep); + if (! (unwind.prologue_mask & 1)) + add_unwind_entry (output_preds_gr (reg2), NOT_A_CHAR); + else if (reg2 != unwind.prologue_gr + + (unsigned) popcount (unwind.prologue_mask & (-1 << 1))) + as_warn ("Second operand of .save contradicts .prologue"); + break; + case REG_PRIUNAT: + add_unwind_entry (output_priunat_when_gr (), sep); + add_unwind_entry (output_priunat_gr (reg2), NOT_A_CHAR); + break; + default: + as_bad ("First operand to .save not a valid register"); + add_unwind_entry (NULL, sep); + break; } - else - as_bad ("First operand not a register"); } static void dot_restore (dummy) int dummy ATTRIBUTE_UNUSED; { - expressionS e1, e2; + expressionS e1; unsigned long ecount; /* # of _additional_ regions to pop */ int sep; if (!in_body ("restore")) return; - sep = parse_operand (&e1); + sep = parse_operand (&e1, ','); if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12) - { - as_bad ("First operand to .restore must be stack pointer (sp)"); - return; - } + as_bad ("First operand to .restore must be stack pointer (sp)"); if (sep == ',') { - parse_operand (&e2); + expressionS e2; + + sep = parse_operand (&e2, ','); if (e2.X_op != O_constant || e2.X_add_number < 0) { as_bad ("Second operand to .restore must be a constant >= 0"); - return; + e2.X_add_number = 0; } ecount = e2.X_add_number; } @@ -3416,10 +3449,10 @@ dot_restore (dummy) { as_bad ("Epilogue count of %lu exceeds number of nested prologues (%u)", ecount + 1, unwind.prologue_count); - return; + ecount = 0; } - add_unwind_entry (output_epilogue (ecount)); + add_unwind_entry (output_epilogue (ecount), sep); if (ecount < unwind.prologue_count) unwind.prologue_count -= ecount + 1; @@ -3428,58 +3461,27 @@ dot_restore (dummy) } static void -dot_restorereg (dummy) - int dummy ATTRIBUTE_UNUSED; -{ - unsigned int ab, reg; - expressionS e; - - if (!in_procedure ("restorereg")) - return; - - parse_operand (&e); - - if (!convert_expr_to_ab_reg (&e, &ab, ®)) - { - as_bad ("First operand to .restorereg must be a preserved register"); - return; - } - add_unwind_entry (output_spill_reg (ab, reg, 0, 0)); -} - -static void -dot_restorereg_p (dummy) - int dummy ATTRIBUTE_UNUSED; +dot_restorereg (pred) + int pred; { unsigned int qp, ab, reg; - expressionS e1, e2; + expressionS e; int sep; + const char * const po = pred ? "restorereg.p" : "restorereg"; - if (!in_procedure ("restorereg.p")) + if (!in_procedure (po)) return; - sep = parse_operand (&e1); - if (sep != ',') - { - as_bad ("No second operand to .restorereg.p"); - return; - } - - parse_operand (&e2); - - qp = e1.X_add_number - REG_P; - if (e1.X_op != O_register || qp > 63) + if (pred) + sep = parse_predicate_and_operand (&e, &qp, po); + else { - as_bad ("First operand to .restorereg.p must be a predicate"); - return; + sep = parse_operand (&e, ','); + qp = 0; } + convert_expr_to_ab_reg (&e, &ab, ®, po, 1 + pred); - if (!convert_expr_to_ab_reg (&e2, &ab, ®)) - { - as_bad ("Second operand to .restorereg.p must be a preserved register"); - return; - } - add_unwind_entry (output_spill_reg_p (ab, reg, 0, 0, qp)); + add_unwind_entry (output_spill_reg (ab, reg, 0, 0, qp), sep); } static char *special_linkonce_name[] = @@ -3607,7 +3609,7 @@ generate_unwind_image (const segT text_seg) /* Mark the end of the unwind info, so that we can compute the size of the last unwind region. */ - add_unwind_entry (output_endp ()); + add_unwind_entry (output_endp (), NOT_A_CHAR); /* Force out pending instructions, to make sure all unwind records have a valid slot_number field. */ @@ -3723,12 +3725,14 @@ dot_altrp (dummy) if (!in_prologue ("altrp")) return; - parse_operand (&e); + parse_operand (&e, 0); reg = e.X_add_number - REG_BR; - if (e.X_op == O_register && reg < 8) - add_unwind_entry (output_rp_br (reg)); - else - as_bad ("First operand not a valid branch register"); + if (e.X_op != O_register || reg > 7) + { + as_bad ("First operand to .altrp not a valid branch register"); + reg = 0; + } + add_unwind_entry (output_rp_br (reg), 0); } static void @@ -3738,182 +3742,210 @@ dot_savemem (psprel) expressionS e1, e2; int sep; int reg1, val; + const char * const po = psprel ? "savepsp" : "savesp"; - if (!in_prologue (psprel ? "savepsp" : "savesp")) + if (!in_prologue (po)) return; - sep = parse_operand (&e1); - if (sep != ',') - as_bad ("No second operand to .save%ssp", psprel ? "p" : ""); - sep = parse_operand (&e2); + sep = parse_operand (&e1, ','); + if (sep == ',') + sep = parse_operand (&e2, ','); + else + e2.X_op = O_absent; reg1 = e1.X_add_number; val = e2.X_add_number; /* Make sure its a valid ar.xxx reg, OR its br0, aka 'rp'. */ - if (e1.X_op == O_register) + if (e1.X_op != O_register) { - if (e2.X_op == O_constant) - { - switch (reg1) - { - case REG_AR + AR_BSP: - add_unwind_entry (output_bsp_when ()); - add_unwind_entry ((psprel - ? output_bsp_psprel - : output_bsp_sprel) (val)); - break; - case REG_AR + AR_BSPSTORE: - add_unwind_entry (output_bspstore_when ()); - add_unwind_entry ((psprel - ? output_bspstore_psprel - : output_bspstore_sprel) (val)); - break; - case REG_AR + AR_RNAT: - add_unwind_entry (output_rnat_when ()); - add_unwind_entry ((psprel - ? output_rnat_psprel - : output_rnat_sprel) (val)); - break; - case REG_AR + AR_UNAT: - add_unwind_entry (output_unat_when ()); - add_unwind_entry ((psprel - ? output_unat_psprel - : output_unat_sprel) (val)); - break; - case REG_AR + AR_FPSR: - add_unwind_entry (output_fpsr_when ()); - add_unwind_entry ((psprel - ? output_fpsr_psprel - : output_fpsr_sprel) (val)); - break; - case REG_AR + AR_PFS: - add_unwind_entry (output_pfs_when ()); - add_unwind_entry ((psprel - ? output_pfs_psprel - : output_pfs_sprel) (val)); - break; - case REG_AR + AR_LC: - add_unwind_entry (output_lc_when ()); - add_unwind_entry ((psprel - ? output_lc_psprel - : output_lc_sprel) (val)); - break; - case REG_BR: - add_unwind_entry (output_rp_when ()); - add_unwind_entry ((psprel - ? output_rp_psprel - : output_rp_sprel) (val)); - break; - case REG_PR: - add_unwind_entry (output_preds_when ()); - add_unwind_entry ((psprel - ? output_preds_psprel - : output_preds_sprel) (val)); - break; - case REG_PRIUNAT: - add_unwind_entry (output_priunat_when_mem ()); - add_unwind_entry ((psprel - ? output_priunat_psprel - : output_priunat_sprel) (val)); - break; - default: - as_bad ("First operand not a valid register"); - } - } - else - as_bad (" Second operand not a valid constant"); + as_bad ("First operand to .%s not a register", po); + reg1 = REG_PR; /* Anything valid is good here. */ + } + if (e2.X_op != O_constant) + { + as_bad ("Second operand to .%s not a constant", po); + val = 0; + } + + switch (reg1) + { + case REG_AR + AR_BSP: + add_unwind_entry (output_bsp_when (), sep); + add_unwind_entry ((psprel + ? output_bsp_psprel + : output_bsp_sprel) (val), NOT_A_CHAR); + break; + case REG_AR + AR_BSPSTORE: + add_unwind_entry (output_bspstore_when (), sep); + add_unwind_entry ((psprel + ? output_bspstore_psprel + : output_bspstore_sprel) (val), NOT_A_CHAR); + break; + case REG_AR + AR_RNAT: + add_unwind_entry (output_rnat_when (), sep); + add_unwind_entry ((psprel + ? output_rnat_psprel + : output_rnat_sprel) (val), NOT_A_CHAR); + break; + case REG_AR + AR_UNAT: + add_unwind_entry (output_unat_when (), sep); + add_unwind_entry ((psprel + ? output_unat_psprel + : output_unat_sprel) (val), NOT_A_CHAR); + break; + case REG_AR + AR_FPSR: + add_unwind_entry (output_fpsr_when (), sep); + add_unwind_entry ((psprel + ? output_fpsr_psprel + : output_fpsr_sprel) (val), NOT_A_CHAR); + break; + case REG_AR + AR_PFS: + add_unwind_entry (output_pfs_when (), sep); + add_unwind_entry ((psprel + ? output_pfs_psprel + : output_pfs_sprel) (val), NOT_A_CHAR); + break; + case REG_AR + AR_LC: + add_unwind_entry (output_lc_when (), sep); + add_unwind_entry ((psprel + ? output_lc_psprel + : output_lc_sprel) (val), NOT_A_CHAR); + break; + case REG_BR: + add_unwind_entry (output_rp_when (), sep); + add_unwind_entry ((psprel + ? output_rp_psprel + : output_rp_sprel) (val), NOT_A_CHAR); + break; + case REG_PR: + add_unwind_entry (output_preds_when (), sep); + add_unwind_entry ((psprel + ? output_preds_psprel + : output_preds_sprel) (val), NOT_A_CHAR); + break; + case REG_PRIUNAT: + add_unwind_entry (output_priunat_when_mem (), sep); + add_unwind_entry ((psprel + ? output_priunat_psprel + : output_priunat_sprel) (val), NOT_A_CHAR); + break; + default: + as_bad ("First operand to .%s not a valid register", po); + add_unwind_entry (NULL, sep); + break; } - else - as_bad ("First operand not a register"); } static void dot_saveg (dummy) int dummy ATTRIBUTE_UNUSED; { - expressionS e1, e2; + expressionS e; + unsigned grmask; int sep; if (!in_prologue ("save.g")) return; - sep = parse_operand (&e1); - if (sep == ',') - parse_operand (&e2); + sep = parse_operand (&e, ','); - if (e1.X_op != O_constant) - as_bad ("First operand to .save.g must be a constant."); - else + grmask = e.X_add_number; + if (e.X_op != O_constant + || e.X_add_number <= 0 + || e.X_add_number > 0xf) { - int grmask = e1.X_add_number; - if (sep != ',') - add_unwind_entry (output_gr_mem (grmask)); - else + as_bad ("First operand to .save.g must be a positive 4-bit constant"); + grmask = 0; + } + + if (sep == ',') + { + unsigned reg; + int n = popcount (grmask); + + parse_operand (&e, 0); + reg = e.X_add_number - REG_GR; + if (e.X_op != O_register || reg > 127) { - int reg = e2.X_add_number - REG_GR; - if (e2.X_op == O_register && reg >= 0 && reg < 128) - add_unwind_entry (output_gr_gr (grmask, reg)); - else - as_bad ("Second operand is an invalid register."); + as_bad ("Second operand to .save.g must be a general register"); + reg = 0; + } + else if (reg > 128U - n) + { + as_bad ("Second operand to .save.g must be the first of %d general registers", n); + reg = 0; } + add_unwind_entry (output_gr_gr (grmask, reg), 0); } + else + add_unwind_entry (output_gr_mem (grmask), 0); } static void dot_savef (dummy) int dummy ATTRIBUTE_UNUSED; { - expressionS e1; - int sep; + expressionS e; if (!in_prologue ("save.f")) return; - sep = parse_operand (&e1); + parse_operand (&e, 0); - if (e1.X_op != O_constant) - as_bad ("Operand to .save.f must be a constant."); - else - add_unwind_entry (output_fr_mem (e1.X_add_number)); + if (e.X_op != O_constant + || e.X_add_number <= 0 + || e.X_add_number > 0xfffff) + { + as_bad ("Operand to .save.f must be a positive 20-bit constant"); + e.X_add_number = 0; + } + add_unwind_entry (output_fr_mem (e.X_add_number), 0); } static void dot_saveb (dummy) int dummy ATTRIBUTE_UNUSED; { - expressionS e1, e2; - unsigned int reg; - unsigned char sep; - int brmask; + expressionS e; + unsigned brmask; + int sep; if (!in_prologue ("save.b")) return; - sep = parse_operand (&e1); - if (e1.X_op != O_constant) + sep = parse_operand (&e, ','); + + brmask = e.X_add_number; + if (e.X_op != O_constant + || e.X_add_number <= 0 + || e.X_add_number > 0x1f) { - as_bad ("First operand to .save.b must be a constant."); - return; + as_bad ("First operand to .save.b must be a positive 5-bit constant"); + brmask = 0; } - brmask = e1.X_add_number; if (sep == ',') { - sep = parse_operand (&e2); - reg = e2.X_add_number - REG_GR; - if (e2.X_op != O_register || reg > 127) + unsigned reg; + int n = popcount (brmask); + + parse_operand (&e, 0); + reg = e.X_add_number - REG_GR; + if (e.X_op != O_register || reg > 127) { - as_bad ("Second operand to .save.b must be a general register."); - return; + as_bad ("Second operand to .save.b must be a general register"); + reg = 0; } - add_unwind_entry (output_br_gr (brmask, e2.X_add_number)); + else if (reg > 128U - n) + { + as_bad ("Second operand to .save.b must be the first of %d general registers", n); + reg = 0; + } + add_unwind_entry (output_br_gr (brmask, reg), 0); } else - add_unwind_entry (output_br_mem (brmask)); - - if (!is_end_of_line[sep] && !is_it_end_of_statement ()) - demand_empty_rest_of_line (); + add_unwind_entry (output_br_mem (brmask), 0); } static void @@ -3921,23 +3953,38 @@ dot_savegf (dummy) int dummy ATTRIBUTE_UNUSED; { expressionS e1, e2; - int sep; if (!in_prologue ("save.gf")) return; - sep = parse_operand (&e1); - if (sep == ',') - parse_operand (&e2); - - if (e1.X_op != O_constant || sep != ',' || e2.X_op != O_constant) - as_bad ("Both operands of .save.gf must be constants."); + if (parse_operand (&e1, ',') == ',') + parse_operand (&e2, 0); else + e2.X_op = O_absent; + + if (e1.X_op != O_constant + || e1.X_add_number < 0 + || e1.X_add_number > 0xf) + { + as_bad ("First operand to .save.gf must be a non-negative 4-bit constant"); + e1.X_op = O_absent; + e1.X_add_number = 0; + } + if (e2.X_op != O_constant + || e2.X_add_number < 0 + || e2.X_add_number > 0xfffff) { - int grmask = e1.X_add_number; - int frmask = e2.X_add_number; - add_unwind_entry (output_frgr_mem (grmask, frmask)); + as_bad ("Second operand to .save.gf must be a non-negative 20-bit constant"); + e2.X_op = O_absent; + e2.X_add_number = 0; } + if (e1.X_op == O_constant + && e2.X_op == O_constant + && e1.X_add_number == 0 + && e2.X_add_number == 0) + as_bad ("Operands to .save.gf may not be both zero"); + + add_unwind_entry (output_frgr_mem (e1.X_add_number, e2.X_add_number), 0); } static void @@ -3945,201 +3992,93 @@ dot_spill (dummy) int dummy ATTRIBUTE_UNUSED; { expressionS e; - unsigned char sep; if (!in_prologue ("spill")) return; - sep = parse_operand (&e); - if (!is_end_of_line[sep] && !is_it_end_of_statement ()) - demand_empty_rest_of_line (); + parse_operand (&e, 0); if (e.X_op != O_constant) - as_bad ("Operand to .spill must be a constant"); - else - add_unwind_entry (output_spill_base (e.X_add_number)); -} - -static void -dot_spillreg (dummy) - int dummy ATTRIBUTE_UNUSED; -{ - int sep; - unsigned int ab, xy, reg, treg; - expressionS e1, e2; - - if (!in_procedure ("spillreg")) - return; - - sep = parse_operand (&e1); - if (sep != ',') - { - as_bad ("No second operand to .spillreg"); - return; - } - - parse_operand (&e2); - - if (!convert_expr_to_ab_reg (&e1, &ab, ®)) { - as_bad ("First operand to .spillreg must be a preserved register"); - return; - } - - if (!convert_expr_to_xy_reg (&e2, &xy, &treg)) - { - as_bad ("Second operand to .spillreg must be a register"); - return; + as_bad ("Operand to .spill must be a constant"); + e.X_add_number = 0; } - - add_unwind_entry (output_spill_reg (ab, reg, treg, xy)); + add_unwind_entry (output_spill_base (e.X_add_number), 0); } static void -dot_spillmem (psprel) - int psprel; +dot_spillreg (pred) + int pred; { - expressionS e1, e2; int sep; - unsigned int ab, reg; + unsigned int qp, ab, xy, reg, treg; + expressionS e; + const char * const po = pred ? "spillreg.p" : "spillreg"; - if (!in_procedure ("spillmem")) + if (!in_procedure (po)) return; - sep = parse_operand (&e1); - if (sep != ',') - { - as_bad ("Second operand missing"); - return; - } - - parse_operand (&e2); - - if (!convert_expr_to_ab_reg (&e1, &ab, ®)) - { - as_bad ("First operand to .spill%s must be a preserved register", - psprel ? "psp" : "sp"); - return; - } - - if (e2.X_op != O_constant) - { - as_bad ("Second operand to .spill%s must be a constant", - psprel ? "psp" : "sp"); - return; - } - - if (psprel) - add_unwind_entry (output_spill_psprel (ab, reg, e2.X_add_number)); + if (pred) + sep = parse_predicate_and_operand (&e, &qp, po); else - add_unwind_entry (output_spill_sprel (ab, reg, e2.X_add_number)); -} - -static void -dot_spillreg_p (dummy) - int dummy ATTRIBUTE_UNUSED; -{ - int sep; - unsigned int ab, xy, reg, treg; - expressionS e1, e2, e3; - unsigned int qp; - - if (!in_procedure ("spillreg.p")) - return; - - sep = parse_operand (&e1); - if (sep != ',') - { - as_bad ("No second and third operand to .spillreg.p"); - return; - } - - sep = parse_operand (&e2); - if (sep != ',') - { - as_bad ("No third operand to .spillreg.p"); - return; - } - - parse_operand (&e3); - - qp = e1.X_add_number - REG_P; - - if (e1.X_op != O_register || qp > 63) - { - as_bad ("First operand to .spillreg.p must be a predicate"); - return; - } - - if (!convert_expr_to_ab_reg (&e2, &ab, ®)) { - as_bad ("Second operand to .spillreg.p must be a preserved register"); - return; + sep = parse_operand (&e, ','); + qp = 0; } + convert_expr_to_ab_reg (&e, &ab, ®, po, 1 + pred); - if (!convert_expr_to_xy_reg (&e3, &xy, &treg)) - { - as_bad ("Third operand to .spillreg.p must be a register"); - return; - } + if (sep == ',') + sep = parse_operand (&e, ','); + else + e.X_op = O_absent; + convert_expr_to_xy_reg (&e, &xy, &treg, po, 2 + pred); - add_unwind_entry (output_spill_reg_p (ab, reg, treg, xy, qp)); + add_unwind_entry (output_spill_reg (ab, reg, treg, xy, qp), sep); } static void -dot_spillmem_p (psprel) +dot_spillmem (psprel) int psprel; { - expressionS e1, e2, e3; - int sep; - unsigned int ab, reg; - unsigned int qp; - - if (!in_procedure ("spillmem.p")) - return; - - sep = parse_operand (&e1); - if (sep != ',') - { - as_bad ("Second operand missing"); - return; - } + expressionS e; + int pred = (psprel < 0), sep; + unsigned int qp, ab, reg; + const char * po; - parse_operand (&e2); - if (sep != ',') + if (pred) { - as_bad ("Second operand missing"); - return; + psprel = ~psprel; + po = psprel ? "spillpsp.p" : "spillsp.p"; } + else + po = psprel ? "spillpsp" : "spillsp"; - parse_operand (&e3); - - qp = e1.X_add_number - REG_P; - if (e1.X_op != O_register || qp > 63) - { - as_bad ("First operand to .spill%s_p must be a predicate", - psprel ? "psp" : "sp"); - return; - } + if (!in_procedure (po)) + return; - if (!convert_expr_to_ab_reg (&e2, &ab, ®)) + if (pred) + sep = parse_predicate_and_operand (&e, &qp, po); + else { - as_bad ("Second operand to .spill%s_p must be a preserved register", - psprel ? "psp" : "sp"); - return; + sep = parse_operand (&e, ','); + qp = 0; } + convert_expr_to_ab_reg (&e, &ab, ®, po, 1 + pred); - if (e3.X_op != O_constant) + if (sep == ',') + sep = parse_operand (&e, ','); + else + e.X_op = O_absent; + if (e.X_op != O_constant) { - as_bad ("Third operand to .spill%s_p must be a constant", - psprel ? "psp" : "sp"); - return; + as_bad ("Operand %d to .%s must be a constant", 2 + pred, po); + e.X_add_number = 0; } if (psprel) - add_unwind_entry (output_spill_psprel_p (ab, reg, e3.X_add_number, qp)); + add_unwind_entry (output_spill_psprel (ab, reg, e.X_add_number, qp), sep); else - add_unwind_entry (output_spill_sprel_p (ab, reg, e3.X_add_number, qp)); + add_unwind_entry (output_spill_sprel (ab, reg, e.X_add_number, qp), sep); } static unsigned int @@ -4206,14 +4145,15 @@ dot_label_state (dummy) if (!in_body ("label_state")) return; - parse_operand (&e); - if (e.X_op != O_constant) + parse_operand (&e, 0); + if (e.X_op == O_constant) + save_prologue_count (e.X_add_number, unwind.prologue_count); + else { as_bad ("Operand to .label_state must be a constant"); - return; + e.X_add_number = 0; } - add_unwind_entry (output_label_state (e.X_add_number)); - save_prologue_count (e.X_add_number, unwind.prologue_count); + add_unwind_entry (output_label_state (e.X_add_number), 0); } static void @@ -4225,14 +4165,15 @@ dot_copy_state (dummy) if (!in_body ("copy_state")) return; - parse_operand (&e); - if (e.X_op != O_constant) + parse_operand (&e, 0); + if (e.X_op == O_constant) + unwind.prologue_count = get_saved_prologue_count (e.X_add_number); + else { as_bad ("Operand to .copy_state must be a constant"); - return; + e.X_add_number = 0; } - add_unwind_entry (output_copy_state (e.X_add_number)); - unwind.prologue_count = get_saved_prologue_count (e.X_add_number); + add_unwind_entry (output_copy_state (e.X_add_number), 0); } static void @@ -4242,32 +4183,28 @@ dot_unwabi (dummy) expressionS e1, e2; unsigned char sep; - if (!in_procedure ("unwabi")) + if (!in_prologue ("unwabi")) return; - sep = parse_operand (&e1); - if (sep != ',') - { - as_bad ("Second operand to .unwabi missing"); - return; - } - sep = parse_operand (&e2); - if (!is_end_of_line[sep] && !is_it_end_of_statement ()) - demand_empty_rest_of_line (); + sep = parse_operand (&e1, ','); + if (sep == ',') + parse_operand (&e2, 0); + else + e2.X_op = O_absent; if (e1.X_op != O_constant) { as_bad ("First operand to .unwabi must be a constant"); - return; + e1.X_add_number = 0; } if (e2.X_op != O_constant) { as_bad ("Second operand to .unwabi must be a constant"); - return; + e2.X_add_number = 0; } - add_unwind_entry (output_unwabi (e1.X_add_number, e2.X_add_number)); + add_unwind_entry (output_unwabi (e1.X_add_number, e2.X_add_number), 0); } static void @@ -4374,16 +4311,14 @@ dot_body (dummy) unwind.prologue_mask = 0; unwind.body = 1; - add_unwind_entry (output_body ()); - demand_empty_rest_of_line (); + add_unwind_entry (output_body (), 0); } static void dot_prologue (dummy) int dummy ATTRIBUTE_UNUSED; { - unsigned char sep; - int mask = 0, grsave = 0; + unsigned mask = 0, grsave = 0; if (!in_procedure ("prologue")) return; @@ -4398,36 +4333,53 @@ dot_prologue (dummy) if (!is_it_end_of_statement ()) { - expressionS e1, e2; - sep = parse_operand (&e1); - if (sep != ',') - as_bad ("No second operand to .prologue"); - sep = parse_operand (&e2); - if (!is_end_of_line[sep] && !is_it_end_of_statement ()) - demand_empty_rest_of_line (); - - if (e1.X_op == O_constant) - { - mask = e1.X_add_number; + expressionS e; + int n, sep = parse_operand (&e, ','); - if (e2.X_op == O_constant) - grsave = e2.X_add_number; - else if (e2.X_op == O_register - && (grsave = e2.X_add_number - REG_GR) < 128) - ; - else - as_bad ("Second operand not a constant or general register"); + if (e.X_op != O_constant + || e.X_add_number < 0 + || e.X_add_number > 0xf) + as_bad ("First operand to .prologue must be a positive 4-bit constant"); + else if (e.X_add_number == 0) + as_warn ("Pointless use of zero first operand to .prologue"); + else + mask = e.X_add_number; + n = popcount (mask); - add_unwind_entry (output_prologue_gr (mask, grsave)); - } + if (sep == ',') + parse_operand (&e, 0); else - as_bad ("First operand not a constant"); + e.X_op = O_absent; + if (e.X_op == O_constant + && e.X_add_number >= 0 + && e.X_add_number < 128) + { + if (md.unwind_check == unwind_check_error) + as_warn ("Using a constant as second operand to .prologue is deprecated"); + grsave = e.X_add_number; + } + else if (e.X_op != O_register + || (grsave = e.X_add_number - REG_GR) > 127) + { + as_bad ("Second operand to .prologue must be a general register"); + grsave = 0; + } + else if (grsave > 128U - n) + { + as_bad ("Second operand to .prologue must be the first of %d general registers", n); + grsave = 0; + } + } + + if (mask) + add_unwind_entry (output_prologue_gr (mask, grsave), 0); else - add_unwind_entry (output_prologue ()); + add_unwind_entry (output_prologue (), 0); unwind.prologue = 1; unwind.prologue_mask = mask; + unwind.prologue_gr = grsave; unwind.body = 0; ++unwind.prologue_count; } @@ -5332,11 +5284,11 @@ const pseudo_typeS md_pseudo_table[] = { "fframe", dot_fframe, 0 }, { "vframe", dot_vframe, 0 }, { "vframesp", dot_vframesp, 0 }, - { "vframepsp", dot_vframepsp, 0 }, + { "vframepsp", dot_vframesp, 1 }, { "save", dot_save, 0 }, { "restore", dot_restore, 0 }, { "restorereg", dot_restorereg, 0 }, - { "restorereg.p", dot_restorereg_p, 0 }, + { "restorereg.p", dot_restorereg, 1 }, { "handlerdata", dot_handlerdata, 0 }, { "unwentry", dot_unwentry, 0 }, { "altrp", dot_altrp, 0 }, @@ -5350,9 +5302,9 @@ const pseudo_typeS md_pseudo_table[] = { "spillreg", dot_spillreg, 0 }, { "spillsp", dot_spillmem, 0 }, { "spillpsp", dot_spillmem, 1 }, - { "spillreg.p", dot_spillreg_p, 0 }, - { "spillsp.p", dot_spillmem_p, 0 }, - { "spillpsp.p", dot_spillmem_p, 1 }, + { "spillreg.p", dot_spillreg, 1 }, + { "spillsp.p", dot_spillmem, ~0 }, + { "spillpsp.p", dot_spillmem, ~1 }, { "label_state", dot_label_state, 0 }, { "copy_state", dot_copy_state, 0 }, { "unwabi", dot_unwabi, 0 }, @@ -6045,27 +5997,19 @@ operand_match (idesc, index, e) } static int -parse_operand (e) +parse_operand (e, more) expressionS *e; + int more; { int sep = '\0'; memset (e, 0, sizeof (*e)); e->X_op = O_absent; SKIP_WHITESPACE (); - if (*input_line_pointer != '}') - expression (e); - sep = *input_line_pointer++; - - if (sep == '}') - { - if (!md.manual_bundling) - as_warn ("Found '}' when manual bundling is off"); - else - CURR_SLOT.manual_bundling_off = 1; - md.manual_bundling = 0; - sep = '\0'; - } + expression (e); + sep = *input_line_pointer; + if (more && (sep == ',' || sep == more)) + ++input_line_pointer; return sep; } @@ -6124,7 +6068,7 @@ parse_operands (idesc) { if (i < NELEMS (CURR_SLOT.opnd)) { - sep = parse_operand (CURR_SLOT.opnd + i); + sep = parse_operand (CURR_SLOT.opnd + i, '='); if (CURR_SLOT.opnd[i].X_op == O_absent) break; } @@ -6132,7 +6076,7 @@ parse_operands (idesc) { expressionS dummy; - sep = parse_operand (&dummy); + sep = parse_operand (&dummy, '='); if (dummy.X_op == O_absent) break; } @@ -6177,7 +6121,7 @@ parse_operands (idesc) /* now we can parse the first arg: */ saved_input_pointer = input_line_pointer; input_line_pointer = first_arg; - sep = parse_operand (CURR_SLOT.opnd + 0); + sep = parse_operand (CURR_SLOT.opnd + 0, '='); if (sep != '=') --num_outputs; /* force error */ input_line_pointer = saved_input_pointer; @@ -7614,6 +7558,15 @@ ia64_end_of_source () void ia64_start_line () { + static int first; + + if (!first) { + /* Make sure we don't reference input_line_pointer[-1] when that's + not valid. */ + first = 1; + return; + } + if (md.qp.X_op == O_register) as_bad ("qualifying predicate not followed by instruction"); md.qp.X_op = O_absent; @@ -7636,38 +7589,8 @@ ia64_start_line () else insn_group_break (1, 0, 0); } -} - -/* This is a hook for ia64_frob_label, so that it can distinguish tags from - labels. */ -static int defining_tag = 0; - -int -ia64_unrecognized_line (ch) - int ch; -{ - switch (ch) + else if (input_line_pointer[-1] == '{') { - case '(': - expression (&md.qp); - if (*input_line_pointer++ != ')') - { - as_bad ("Expected ')'"); - return 0; - } - if (md.qp.X_op != O_register) - { - as_bad ("Qualifying predicate expected"); - return 0; - } - if (md.qp.X_add_number < REG_P || md.qp.X_add_number >= REG_P + 64) - { - as_bad ("Predicate register expected"); - return 0; - } - return 1; - - case '{': if (md.manual_bundling) as_warn ("Found '{' when manual bundling is already turned on"); else @@ -7684,9 +7607,9 @@ ia64_unrecognized_line (ch) else as_warn (_("Found '{' after explicit switch to automatic mode")); } - return 1; - - case '}': + } + else if (input_line_pointer[-1] == '}') + { if (!md.manual_bundling) as_warn ("Found '}' when manual bundling is off"); else @@ -7699,17 +7622,36 @@ ia64_unrecognized_line (ch) && !md.mode_explicitly_set && !md.default_explicit_mode) dot_dv_mode ('A'); + } +} - /* Allow '{' to follow on the same line. We also allow ";;", but that - happens automatically because ';' is an end of line marker. */ - SKIP_WHITESPACE (); - if (input_line_pointer[0] == '{') +/* This is a hook for ia64_frob_label, so that it can distinguish tags from + labels. */ +static int defining_tag = 0; + +int +ia64_unrecognized_line (ch) + int ch; +{ + switch (ch) + { + case '(': + expression (&md.qp); + if (*input_line_pointer++ != ')') { - input_line_pointer++; - return ia64_unrecognized_line ('{'); + as_bad ("Expected ')'"); + return 0; + } + if (md.qp.X_op != O_register) + { + as_bad ("Qualifying predicate expected"); + return 0; + } + if (md.qp.X_add_number < REG_P || md.qp.X_add_number >= REG_P + 64) + { + as_bad ("Predicate register expected"); + return 0; } - - demand_empty_rest_of_line (); return 1; case '[': @@ -11732,7 +11674,7 @@ dot_alias (int section) if (name == end_name) { as_bad (_("expected symbol name")); - discard_rest_of_line (); + ignore_rest_of_line (); return; } diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 8c850480046..352f34ac443 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2005-07-01 Jan Beulich + + * gas/ia64/group-2.s: Use register as second operand of .prologue. + * gas/ia64/unwind-err.s: Add check for .vframesp. + * gas/ia64/unwind-err.l: Adjust. + * gas/ia64/strange.[sd]: New. + * gas/ia64/unwind-bad.[sl]: New. + * gas/ia64/unwind-ok.[sd]: New. + * gas/ia64/ia64.exp: Run new tests. + 2005-06-30 Zack Weinberg * gas/arm/arm.exp: Don't special case ldconst, arm7t, or copro diff --git a/gas/testsuite/gas/ia64/group-2.s b/gas/testsuite/gas/ia64/group-2.s index 6ddc94c27a1..6b6b9fc0edf 100644 --- a/gas/testsuite/gas/ia64/group-2.s +++ b/gas/testsuite/gas/ia64/group-2.s @@ -1,6 +1,6 @@ .section .gnu.linkonce.t.foo,"axG",@progbits,foo,comdat .proc foo# foo: - .prologue 12, 33 + .prologue 12, r33 ;; .endp foo# diff --git a/gas/testsuite/gas/ia64/ia64.exp b/gas/testsuite/gas/ia64/ia64.exp index 6199b24c82f..8b4b999ad21 100644 --- a/gas/testsuite/gas/ia64/ia64.exp +++ b/gas/testsuite/gas/ia64/ia64.exp @@ -84,7 +84,10 @@ if [istarget "ia64-*"] then { run_list_test "proc" "-munwind-check=error" run_list_test "radix" "" run_list_test "slot2" "" + run_dump_test "strange" + run_list_test "unwind-bad" "" run_list_test "unwind-err" "-munwind-check=error" + run_dump_test "unwind-ok" run_dump_test "operand-or" run_list_test "hint.b-err" "" run_list_test "hint.b-warn" "-mhint.b=warning" diff --git a/gas/testsuite/gas/ia64/strange.d b/gas/testsuite/gas/ia64/strange.d new file mode 100644 index 00000000000..287d073762d --- /dev/null +++ b/gas/testsuite/gas/ia64/strange.d @@ -0,0 +1,19 @@ +#objdump: -s +#name: ia64 strange + +.*: +file format .* + +Contents of section .text: + 0000 0c000000 01001000 00020000 00000400 .* + 0010 04000000 01000000 00000020 00000400 .* + 0020 0c000000 01002000 00020000 00000400 .* + 0030 04000000 01000000 00000040 00000400 .* + 0040 1c000000 01003000 00020000 00000020 .* + 0050 04000000 01000000 00000080 00000400 .* + 0060 04000000 01000000 000000a0 00000400 .* + 0070 04000000 01000000 000000c0 00000400 .* + 0080 04000000 01000000 000000e0 00000400 .* + 0090 0e000000 01000000 00020000 01000400 .* + 00a0 1d000000 01009000 00020080 00008400 .* +Contents of section .data: + 0000 ffffff .* diff --git a/gas/testsuite/gas/ia64/strange.s b/gas/testsuite/gas/ia64/strange.s new file mode 100644 index 00000000000..9a19b046128 --- /dev/null +++ b/gas/testsuite/gas/ia64/strange.s @@ -0,0 +1,18 @@ +.explicit +.text +_start: +{.mfi + nop.f 1 } nop.x 1 +{.mfi + nop.f 2 +} nop.x 2 +{.mfb + nop.f 3 +.xdata1 .data, -1 } .xdata1 .data, -1 + nop.x 4 { nop.x 5 +} { nop.x 6 } + nop.x 7 {.mmf + nop.f 8 +} .xdata1 .data, -1 { .mfb + nop.f 9 + br.ret.sptk rp } diff --git a/gas/testsuite/gas/ia64/unwind-bad.l b/gas/testsuite/gas/ia64/unwind-bad.l new file mode 100644 index 00000000000..59a4b20e47c --- /dev/null +++ b/gas/testsuite/gas/ia64/unwind-bad.l @@ -0,0 +1,51 @@ +.*: Assembler messages: +.*:8: Error: First operand to \.save\.g must be a positive 4-bit constant +.*:10: Error: First operand to \.save\.g must be a positive 4-bit constant +.*:12: Error: First operand to \.save\.g must be a positive 4-bit constant +#FIXME .*:16: Error: Previous spill incomplete +#FIXME .*:18: Error: Register r4 was already saved +.*:20: Error: Operand to \.save\.f must be a positive 20-bit constant +.*:22: Error: Operand to \.save\.f must be a positive 20-bit constant +.*:24: Error: Operand to \.save\.f must be a positive 20-bit constant +#FIXME .*:28: Error: Previous spill incomplete +#FIXME .*:30: Error: Register f2 was already saved +.*:32: Error: First operand to \.save\.b must be a positive 5-bit constant +.*:34: Error: First operand to \.save\.b must be a positive 5-bit constant +.*:36: Error: First operand to \.save\.b must be a positive 5-bit constant +#FIXME .*:40: Error: Previous spill incomplete +#FIXME .*:42: Error: Register b1 was already saved +.*:44: Error: Operand 2 to \.spillreg must be a writable register +.*:46: Error: Operand 1 to \.spillreg must be a preserved register +.*:48: Error: Operand 1 to \.spillreg must be a preserved register +.*:50: Error: Operand 1 to \.spillreg must be a preserved register +.*:52: Error: Operand 2 to \.spillreg must be a writable register +.*:54: Error: Operand 2 to \.spillreg must be a writable register +.*:56: Error: Operand 1 to \.spillreg must be a preserved register +#FIXME .*:58: Error: Floating point register cannot be spilled to general register +#FIXME .*:60: Error: Floating point register cannot be spilled to branch register +.*:62: Warning: Pointless use of p0 as first operand to \.spillreg\.p +.*:64: Error: Operand 3 to \.spillreg.p must be a writable register +.*:66: Error: Operand 3 to \.spillreg.p must be a writable register +.*:68: Warning: Pointless use of p0 as first operand to \.restorereg\.p +.*:78: Error: Operands to \.save\.gf may not be both zero +.*:80: Error: First operand to \.save\.gf must be a non-negative 4-bit constant +.*:82: Error: Second operand to \.save\.gf must be a non-negative 20-bit constant +.*:84: Error: First operand to \.save\.gf must be a non-negative 4-bit constant +.*:86: Error: Second operand to \.save\.gf must be a non-negative 20-bit constant +#FIXME .*:90: Error: Previous spill incomplete +#FIXME .*:92: Error: Register r4 was already saved +#FIXME .*:94: Error: Register f2 was already saved +.*:98: Error: Epilogue count of 2 exceeds number of nested prologues \(1\) +.*:100: Error: Missing \.label_state 2 +.*:108: Error: First operand to \.save\.g must be a positive 4-bit constant +#FIXME .*:110: Error: Second operand to \.save\.g must be a writable general registers +.*:112: Error: Second operand to \.save\.g must be the first of 2 general registers +.*:115: Error: First operand to \.save\.b must be a positive 5-bit constant +#FIXME .*:117: Error: Second operand to \.save\.b must be a writable general registers +.*:119: Error: Second operand to \.save\.b must be the first of 2 general registers +.*:128: Error: First operand to \.prologue must be a positive 4-bit constant +.*:134: Warning: Pointless use of zero first operand to \.prologue +.*:140: Error: First operand to \.prologue must be a positive 4-bit constant +#FIXME .*:141: Error: Operand to \.vframe must be a writable general registers +#FIXME .*:147: Error: Second operand to \.prologue must be a writable general registers +.*:153: Error: Second operand to \.prologue must be the first of 2 general registers diff --git a/gas/testsuite/gas/ia64/unwind-bad.s b/gas/testsuite/gas/ia64/unwind-bad.s new file mode 100644 index 00000000000..9a4b7beab50 --- /dev/null +++ b/gas/testsuite/gas/ia64/unwind-bad.s @@ -0,0 +1,155 @@ +.text + +.proc full1 +full1: + +.prologue +.spill 0 +.save.g 0 + nop 0 +.save.g 0x10 + nop 0 +.save.g -1 + nop 0 +.save.g 0x3 + nop 0 +.save.g 0x4 + nop 0 +.save.g 0x1 + nop 0 +.save.f 0 + nop 0 +.save.f 0x100000 + nop 0 +.save.f -1 + nop 0 +.save.f 0x3 + nop 0 +.save.f 0x4 + nop 0 +.save.f 0x1 + nop 0 +.save.b 0 + nop 0 +.save.b 0x20 + nop 0 +.save.b -1 + nop 0 +.save.b 0x3 + nop 0 +.save.b 0x4 + nop 0 +.save.b 0x1 + nop 0 +.spillreg r4, r0 + nop 0 +.spillreg r3, r2 + nop 0 +.spillreg r8, r9 + nop 0 +.spillreg b6, r10 + nop 0 +.spillreg f2, f0 + nop 0 +.spillreg f3, f1 + nop 0 +.spillreg f6, f7 + nop 0 +.spillreg f4, r11 + nop 0 +.spillreg f5, b0 + nop 0 +.spillreg.p p0, r4, r3 + nop 0 +.spillreg.p p1, r4, r0 + nop 0 +.spillreg.p p1, f16, f0 + nop 0 +.restorereg.p p0, r4 + nop 0 +.body + br.ret.sptk rp +.endp full1 + +.proc full2 +full2: +.prologue +.spill 0 +.save.gf 0, 0 + nop 0 +.save.gf 0x10, 0 + nop 0 +.save.gf 0, 0x100000 + nop 0 +.save.gf ~0, 0 + nop 0 +.save.gf 0, ~0 + nop 0 +.save.gf 1, 1 + nop 0 +.save.gf 2, 0 + nop 0 +.save.gf 1, 0 + nop 0 +.save.gf 0, 1 + nop 0 +.body +.label_state 1 +.restore sp, 1 + nop.x 0 +.copy_state 2 + br.ret.sptk rp +.endp full2 + +.proc full3 +full3: +.prologue +.spill 0 +.save.g 0x10, r16 + nop 0 +.save.g 0x01, r0 + nop 0 +.save.g 0x06, r127 + nop 0 + nop 0 +.save.b 0x20, r16 + nop 0 +.save.b 0x01, r0 + nop 0 +.save.b 0x18, r127 + nop 0 + nop 0 +.body + br.ret.sptk rp +.endp full3 + +.proc simple1 +simple1: +.prologue 0x10, r2 + br.ret.sptk rp +.endp simple1 + +.proc simple2 +simple2: +.prologue 0, r2 + br.ret.sptk rp +.endp simple2 + +.proc simple3 +simple3: +.prologue -1, r2 +.vframe r0 + br.ret.sptk rp +.endp simple3 + +.proc simple4 +simple4: +.prologue 0x1, r0 + br.ret.sptk rp +.endp simple4 + +.proc simple5 +simple5: +.prologue 0xc, r127 + br.ret.sptk rp +.endp simple5 diff --git a/gas/testsuite/gas/ia64/unwind-err.l b/gas/testsuite/gas/ia64/unwind-err.l index 153451f38bd..71cca18d592 100644 --- a/gas/testsuite/gas/ia64/unwind-err.l +++ b/gas/testsuite/gas/ia64/unwind-err.l @@ -8,27 +8,28 @@ .*:7: Error: .body outside of procedure .*:8: Error: .spillreg outside of procedure .*:9: Error: .spillreg.p outside of procedure -.*:10: Error: .spillmem outside of procedure -.*:11: Error: .spillmem.p outside of procedure -.*:12: Error: .spillmem outside of procedure -.*:13: Error: .spillmem.p outside of procedure +.*:10: Error: .spillsp outside of procedure +.*:11: Error: .spillsp.p outside of procedure +.*:12: Error: .spillpsp outside of procedure +.*:13: Error: .spillpsp.p outside of procedure .*:14: Error: .restorereg outside of procedure .*:15: Error: .restorereg.p outside of procedure .*:24: Error: .label_state outside of body region .*:25: Error: .copy_state outside of body region .*:26: Error: .fframe outside of prologue .*:27: Error: .vframe outside of prologue -.*:28: Error: .spill outside of prologue -.*:29: Error: .restore outside of body region -.*:30: Error: .save outside of prologue -.*:31: Error: .savesp outside of prologue -.*:32: Error: .savepsp outside of prologue -.*:33: Error: .save.g outside of prologue -.*:34: Error: .save.gf outside of prologue -.*:35: Error: .save.f outside of prologue -.*:36: Error: .save.b outside of prologue -.*:37: Error: .altrp outside of prologue -.*:42: Error: .prologue within prologue -.*:50: Error: .body outside of procedure -.*:57: Warning: Initial .prologue.* -.*:64: Warning: Initial .body.* +.*:28: Error: .vframesp outside of prologue +.*:29: Error: .spill outside of prologue +.*:30: Error: .restore outside of body region +.*:31: Error: .save outside of prologue +.*:32: Error: .savesp outside of prologue +.*:33: Error: .savepsp outside of prologue +.*:34: Error: .save.g outside of prologue +.*:35: Error: .save.gf outside of prologue +.*:36: Error: .save.f outside of prologue +.*:37: Error: .save.b outside of prologue +.*:38: Error: .altrp outside of prologue +.*:43: Error: .prologue within prologue +.*:51: Error: .body outside of procedure +.*:58: Warning: Initial .prologue.* +.*:65: Warning: Initial .body.* diff --git a/gas/testsuite/gas/ia64/unwind-err.s b/gas/testsuite/gas/ia64/unwind-err.s index f50cc3d13db..81b25974644 100644 --- a/gas/testsuite/gas/ia64/unwind-err.s +++ b/gas/testsuite/gas/ia64/unwind-err.s @@ -25,6 +25,7 @@ start: .copy_state 1 .fframe 0 .vframe r0 +.vframesp 0 .spill 0 .restore sp .save rp, r0 diff --git a/gas/testsuite/gas/ia64/unwind-ok.d b/gas/testsuite/gas/ia64/unwind-ok.d new file mode 100644 index 00000000000..d35d6dee7ad --- /dev/null +++ b/gas/testsuite/gas/ia64/unwind-ok.d @@ -0,0 +1,224 @@ +#readelf: -u +#name: ia64 unwind descriptors + +Unwind section '\.IA_64\.unwind' at offset 0x[[:xdigit:]]+ contains 8 entries: + +: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08] +[[:space:]]*v[[:digit:]]+, flags=0x3 \( ?ehandler uhandler\), len=[[:digit:]]+ bytes +[[:space:]]*R1:prologue\(rlen=8\) +[[:space:]]*P6:fr_mem\(frmask=\[f2,f5\]\) +[[:space:]]*P6:gr_mem\(grmask=\[r4,r7\]\) +[[:space:]]*P1:br_mem\(brmask=\[b1,b5\]\) +[[:space:]]*P4:spill_mask\(imask=\[rfb,rfb,--\]\) +[[:space:]]*P7:spill_base\(pspoff=0x10-0x10\) +[[:space:]]*P3:rp_br\(reg=b7\) +[[:space:]]*P10:unwabi\(abi=@svr4,context=0x00\) +[[:space:]]*R1:body\(rlen=[[:digit:]]+\) +[[:space:]]*X2:spill_reg\(t=0,reg=r4,treg=r2\) +[[:space:]]*X4:spill_reg_p\(qp=p1,t=1,reg=r7,treg=r31\) +[[:space:]]*X1:spill_sprel\(reg=b1,t=2,spoff=0x8\) +[[:space:]]*X3:spill_sprel_p\(qp=p2,t=3,reg=b5,spoff=0x10\) +[[:space:]]*X1:spill_psprel\(reg=f2,t=4,pspoff=0x10-0x28\) +[[:space:]]*X3:spill_psprel_p\(qp=p4,t=5,reg=f5,pspoff=0x10-0x30\) +[[:space:]]*X2:restore\(t=6,reg=f16\) +[[:space:]]*X4:restore_p\(qp=p8,t=7,reg=f31\) +[[:space:]]*X2:spill_reg\(t=8,reg=ar\.bsp,treg=r16\) +[[:space:]]*X2:spill_reg\(t=9,reg=ar\.bspstore,treg=r17\) +[[:space:]]*X2:spill_reg\(t=10,reg=ar\.fpsr,treg=r18\) +[[:space:]]*X2:spill_reg\(t=11,reg=ar\.lc,treg=r19\) +[[:space:]]*X2:spill_reg\(t=12,reg=ar\.pfs,treg=r20\) +[[:space:]]*X2:spill_reg\(t=13,reg=ar\.rnat,treg=r21\) +[[:space:]]*X2:spill_reg\(t=14,reg=ar\.unat,treg=r22\) +[[:space:]]*X2:spill_reg\(t=15,reg=psp,treg=r23\) +[[:space:]]*X2:spill_reg\(t=16,reg=pr,treg=r24\) +[[:space:]]*X2:spill_reg\(t=17,reg=rp,treg=r25\) +[[:space:]]*X2:spill_reg\(t=18,reg=@priunat,treg=r26\) +[[:space:]]*B1:label_state\(label=1\) +[[:space:]]*B2:epilogue\(t=4,ecount=0\) +[[:space:]]*B1:copy_state\(label=1\) +#... +: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08] +[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes +[[:space:]]*R2:prologue_gr\(mask=\[rp,psp,pr\],grsave=r8,rlen=14\) +[[:space:]]*P5:frgr_mem\(grmask=\[r4,r7\],frmask=\[f2,f31\]\) +[[:space:]]*P4:spill_mask\(imask=\[b-b,bb-,---,---,--\]\) +[[:space:]]*P7:spill_base\(pspoff=0x10-0x10\) +[[:space:]]*P2:br_gr\(brmask=\[b1,b5\],gr=r32\) +[[:space:]]*X2:spill_reg\(t=6,reg=f31,treg=f31\) +[[:space:]]*X4:spill_reg_p\(qp=p63,t=7,reg=f16,treg=f0\) +[[:space:]]*X1:spill_sprel\(reg=f5,t=8,spoff=0x20\) +[[:space:]]*X3:spill_sprel_p\(qp=p31,t=9,reg=f2,spoff=0x18\) +[[:space:]]*X1:spill_psprel\(reg=b5,t=10,pspoff=0x10-0x20\) +[[:space:]]*X3:spill_psprel_p\(qp=p15,t=11,reg=b1,pspoff=0x10-0x18\) +[[:space:]]*X2:restore\(t=12,reg=r7\) +[[:space:]]*X4:restore_p\(qp=p7,t=13,reg=r4\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=0\) +[[:space:]]*R1:prologue\(rlen=0\) +[[:space:]]*R1:body\(rlen=7\) +[[:space:]]*B4:label_state\(label=32\) +[[:space:]]*B3:epilogue\(t=4,ecount=32\) +[[:space:]]*B4:copy_state\(label=32\) +#... +: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08] +[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes +[[:space:]]*R3:prologue\(rlen=33\) +[[:space:]]*P4:spill_mask\(imask=\[rrb,brr,bb-,---,---,---,---,---,---,---,---\]\) +[[:space:]]*P7:spill_base\(pspoff=0x10-0x10\) +[[:space:]]*P9:gr_gr\(grmask=\[r4,r5\],r32\) +[[:space:]]*P2:br_gr\(brmask=\[b1,b2\],gr=r34\) +[[:space:]]*P9:gr_gr\(grmask=\[r6,r7\],r124\) +[[:space:]]*P2:br_gr\(brmask=\[b4,b5\],gr=r126\) +[[:space:]]*R3:body\(rlen=33\) +#... +: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08] +[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes +[[:space:]]*R1:prologue\(rlen=1\) +[[:space:]]*P7:mem_stack_f\(t=0,size=0\) +[[:space:]]*R1:body\(rlen=2\) +#... +: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08] +[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes +[[:space:]]*R1:prologue\(rlen=11\) +[[:space:]]*P7:mem_stack_v\(t=0\) +[[:space:]]*P3:psp_gr\(reg=r16\) +[[:space:]]*P8:bsp_when\(t=1\) +[[:space:]]*P3:bsp_gr\(reg=r17\) +[[:space:]]*P8:bspstore_when\(t=2\) +[[:space:]]*P3:bspstore_gr\(reg=r18\) +[[:space:]]*P7:fpsr_when\(t=3\) +[[:space:]]*P3:fpsr_gr\(reg=r19\) +[[:space:]]*P7:lc_when\(t=4\) +[[:space:]]*P3:lc_gr\(reg=r20\) +[[:space:]]*P7:pfs_when\(t=5\) +[[:space:]]*P3:pfs_gr\(reg=r21\) +[[:space:]]*P8:rnat_when\(t=6\) +[[:space:]]*P3:rnat_gr\(reg=r22\) +[[:space:]]*P7:unat_when\(t=7\) +[[:space:]]*P3:unat_gr\(reg=r23\) +[[:space:]]*P7:pr_when\(t=8\) +[[:space:]]*P3:pr_gr\(reg=r24\) +[[:space:]]*P8:priunat_when_gr\(t=9\) +[[:space:]]*P3:priunat_gr\(reg=r25\) +[[:space:]]*P7:rp_when\(t=10\) +[[:space:]]*P3:rp_gr\(reg=r26\) +[[:space:]]*R1:body\(rlen=1\) +#... +: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08] +[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes +[[:space:]]*R1:prologue\(rlen=11\) +[[:space:]]*P7:mem_stack_v\(t=0\) +[[:space:]]*P7:psp_sprel\(spoff=0x0\) +[[:space:]]*P8:bsp_when\(t=1\) +[[:space:]]*P8:bsp_sprel\(spoff=0x8\) +[[:space:]]*P8:bspstore_when\(t=2\) +[[:space:]]*P8:bspstore_sprel\(spoff=0x10\) +[[:space:]]*P7:fpsr_when\(t=3\) +[[:space:]]*P8:fpsr_sprel\(spoff=0x18\) +[[:space:]]*P7:lc_when\(t=4\) +[[:space:]]*P8:lc_sprel\(spoff=0x20\) +[[:space:]]*P7:pfs_when\(t=5\) +[[:space:]]*P8:pfs_sprel\(spoff=0x28\) +[[:space:]]*P8:rnat_when\(t=6\) +[[:space:]]*P8:rnat_sprel\(spoff=0x30\) +[[:space:]]*P7:unat_when\(t=7\) +[[:space:]]*P8:unat_sprel\(spoff=0x38\) +[[:space:]]*P7:pr_when\(t=8\) +[[:space:]]*P8:pr_sprel\(spoff=0x40\) +[[:space:]]*P8:priunat_when_mem\(t=9\) +[[:space:]]*P8:priunat_sprel\(spoff=0x48\) +[[:space:]]*P7:rp_when\(t=10\) +[[:space:]]*P8:rp_sprel\(spoff=0x50\) +[[:space:]]*R1:body\(rlen=1\) +#... +: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08] +[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes +[[:space:]]*R1:prologue\(rlen=11\) +[[:space:]]*P7:mem_stack_v\(t=0\) +[[:space:]]*P7:psp_sprel\(spoff=0x0\) +[[:space:]]*P8:bsp_when\(t=1\) +[[:space:]]*P8:bsp_psprel\(pspoff=0x10-0x18\) +[[:space:]]*P8:bspstore_when\(t=2\) +[[:space:]]*P8:bspstore_psprel\(pspoff=0x10-0x20\) +[[:space:]]*P7:fpsr_when\(t=3\) +[[:space:]]*P7:fpsr_psprel\(pspoff=0x10-0x28\) +[[:space:]]*P7:lc_when\(t=4\) +[[:space:]]*P7:lc_psprel\(pspoff=0x10-0x30\) +[[:space:]]*P7:pfs_when\(t=5\) +[[:space:]]*P7:pfs_psprel\(pspoff=0x10-0x38\) +[[:space:]]*P8:rnat_when\(t=6\) +[[:space:]]*P8:rnat_psprel\(pspoff=0x10-0x40\) +[[:space:]]*P7:unat_when\(t=7\) +[[:space:]]*P7:unat_psprel\(pspoff=0x10-0x48\) +[[:space:]]*P7:pr_when\(t=8\) +[[:space:]]*P7:pr_psprel\(pspoff=0x10-0x50\) +[[:space:]]*P8:priunat_when_mem\(t=9\) +[[:space:]]*P8:priunat_psprel\(pspoff=0x10-0x58\) +[[:space:]]*P7:rp_when\(t=10\) +[[:space:]]*P7:rp_psprel\(pspoff=0x10-0x60\) +[[:space:]]*R1:body\(rlen=1\) +#... +: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08] +[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes +#pass diff --git a/gas/testsuite/gas/ia64/unwind-ok.s b/gas/testsuite/gas/ia64/unwind-ok.s new file mode 100644 index 00000000000..f2cc0cfffda --- /dev/null +++ b/gas/testsuite/gas/ia64/unwind-ok.s @@ -0,0 +1,272 @@ +.text +.proc personality +personality: + br.ret.sptk rp +.endp personality + +.proc full1 +full1: + +.prologue +.spill 0 +.save.g 0x1 + nop 0 +.save.f 0x1 + nop 0 +.save.b 0x01 + nop 0 +.save.g 0x8 + nop 0 +.save.f 0x8 + nop 0 +.save.b 0x10 + nop 0 +.altrp b7 + nop 0 +.unwabi @svr4, 0 + nop 0 + +.body +.spillreg r4, r2 + nop 0 +.spillreg.p p1, r7, r127 + nop 0 +.spillsp b1, 0x08 + nop 0 +.spillsp.p p2, b5, 0x10 + nop 0 +.spillpsp f2, 0x18 + nop 0 +.spillpsp.p p4, f5, 0x20 + nop 0 +.restorereg f16 + nop 0 +.restorereg.p p8, f31 + nop 0 + +.spillreg ar.bsp, r16 + nop 0 +.spillreg ar.bspstore, r17 + nop 0 +.spillreg ar.fpsr, r18 + nop 0 +.spillreg ar.lc, r19 + nop 0 +.spillreg ar.pfs, r20 + nop 0 +.spillreg ar.rnat, r21 + nop 0 +.spillreg ar.unat, r22 + nop 0 +.spillreg psp, r23 + nop 0 +.spillreg pr, r24 + nop 0 +.spillreg rp, r25 + nop 0 +.spillreg @priunat, r26 + nop 0 + +.label_state 1 + nop 0 +.restore sp + nop.x 0 +.copy_state 1 + br.ret.sptk rp + +.personality personality +.handlerdata + data4 -1 + data4 0 + +.endp full1 + +.proc full2 +full2: + +.prologue 0xb, r8 +.spill 0 +.save.gf 0x1, 0x00001 + nop 0 + nop 0 +.save.b 0x11, r32 + nop 0 + nop 0 +.save.gf 0x8, 0x80000 + nop 0 + nop 0 +.spillreg f31, f127 + nop 0 +.spillreg.p p63, f16, f32 + nop 0 +.spillsp f5, 0x20 + nop 0 +.spillsp.p p31, f2, 0x18 + nop 0 +.spillpsp b5, 0x10 + nop 0 +.spillpsp.p p15, b1, 0x08 + nop 0 +.restorereg r7 + nop 0 +.restorereg.p p7, r4 + nop 0 + +.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue +.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue +.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue +.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue +.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue +.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue +.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue +.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue + +.body +.label_state 32 + nop 0 +.restore sp, 32 + nop.x 0 +.copy_state 32 + br.ret.sptk rp +.endp full2 + +.proc full3 +full3: + +.prologue +.spill 0 +.save.g 0x3, r32 + nop 0 + nop 0 +.save.b 0x03, r34 + nop 0 + nop 0 +.save.g 0xc, r124 + nop 0 + nop 0 +.save.b 0x18, r126 + nop 0 + nop 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 +.body + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + nop.x 0 + br.ret.sptk rp +.endp full3 + +.proc fframe +fframe: +.prologue +.fframe 0 + nop 0 +.body + br.ret.sptk rp +.endp fframe + +.proc vframe +vframe: +.prologue +.vframe r16 + nop 0 +.save ar.bsp, r17 + nop 0 +.save ar.bspstore, r18 + nop 0 +.save ar.fpsr, r19 + nop 0 +.save ar.lc, r20 + nop 0 +.save ar.pfs, r21 + nop 0 +.save ar.rnat, r22 + nop 0 +.save ar.unat, r23 + nop 0 +.save pr, r24 + nop 0 +.save @priunat, r25 + nop 0 +.save rp, r26 + nop 0 +.body + br.ret.sptk rp +.endp vframe + +.proc vframesp +vframesp: +.prologue +.vframesp 0 + nop 0 +.savesp ar.bsp, 0x08 + nop 0 +.savesp ar.bspstore, 0x10 + nop 0 +.savesp ar.fpsr, 0x18 + nop 0 +.savesp ar.lc, 0x20 + nop 0 +.savesp ar.pfs, 0x28 + nop 0 +.savesp ar.rnat, 0x30 + nop 0 +.savesp ar.unat, 0x38 + nop 0 +.savesp pr, 0x40 + nop 0 +.savesp @priunat, 0x48 + nop 0 +.savesp rp, 0x50 + nop 0 +.body + br.ret.sptk rp +.endp vframesp + +.proc psp +psp: +.prologue +.vframesp 0 + nop 0 +.savepsp ar.bsp, 0x08 + nop 0 +.savepsp ar.bspstore, 0x10 + nop 0 +.savepsp ar.fpsr, 0x18 + nop 0 +.savepsp ar.lc, 0x20 + nop 0 +.savepsp ar.pfs, 0x28 + nop 0 +.savepsp ar.rnat, 0x30 + nop 0 +.savepsp ar.unat, 0x38 + nop 0 +.savepsp pr, 0x40 + nop 0 +.savepsp @priunat, 0x48 + nop 0 +.savepsp rp, 0x50 + nop 0 +.body + br.ret.sptk rp +.endp psp + +.proc simple +simple: +.unwentry + br.ret.sptk rp +.endp simple -- 2.30.2