184865Sobrien/* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
2218822Sdim   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
3218822Sdim   Free Software Foundation, Inc.
484865Sobrien   Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
584865Sobrien
684865Sobrien   This file is part of GAS, the GNU Assembler.
784865Sobrien
884865Sobrien   GAS is free software; you can redistribute it and/or modify
984865Sobrien   it under the terms of the GNU General Public License as published by
1084865Sobrien   the Free Software Foundation; either version 2, or (at your option)
1184865Sobrien   any later version.
1284865Sobrien
1384865Sobrien   GAS is distributed in the hope that it will be useful,
1484865Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1584865Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1684865Sobrien   GNU General Public License for more details.
1784865Sobrien
1884865Sobrien   You should have received a copy of the GNU General Public License
1984865Sobrien   along with GAS; see the file COPYING.  If not, write to
20218822Sdim   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
21218822Sdim   Boston, MA 02110-1301, USA.  */
2284865Sobrien
2384865Sobrien/*
2484865Sobrien  TODO:
2584865Sobrien
2684865Sobrien  - optional operands
2784865Sobrien  - directives:
2884865Sobrien	.eb
2984865Sobrien	.estate
3084865Sobrien	.lb
3184865Sobrien	.popsection
3284865Sobrien	.previous
3384865Sobrien	.psr
3484865Sobrien	.pushsection
3584865Sobrien  - labels are wrong if automatic alignment is introduced
3684865Sobrien    (e.g., checkout the second real10 definition in test-data.s)
3784865Sobrien  - DV-related stuff:
3884865Sobrien	<reg>.safe_across_calls and any other DV-related directives I don't
3984865Sobrien	  have documentation for.
4084865Sobrien	verify mod-sched-brs reads/writes are checked/marked (and other
4184865Sobrien	notes)
4284865Sobrien
4384865Sobrien */
4484865Sobrien
4584865Sobrien#include "as.h"
4689857Sobrien#include "safe-ctype.h"
4784865Sobrien#include "dwarf2dbg.h"
4884865Sobrien#include "subsegs.h"
4984865Sobrien
5084865Sobrien#include "opcode/ia64.h"
5184865Sobrien
5284865Sobrien#include "elf/ia64.h"
5384865Sobrien
54218822Sdim#ifdef HAVE_LIMITS_H
55218822Sdim#include <limits.h>
56218822Sdim#endif
57218822Sdim
5884865Sobrien#define NELEMS(a)	((int) (sizeof (a)/sizeof ((a)[0])))
59218822Sdim
60218822Sdim/* Some systems define MIN in, e.g., param.h.  */
61218822Sdim#undef MIN
6284865Sobrien#define MIN(a,b)	((a) < (b) ? (a) : (b))
6384865Sobrien
6484865Sobrien#define NUM_SLOTS	4
6584865Sobrien#define PREV_SLOT	md.slot[(md.curr_slot + NUM_SLOTS - 1) % NUM_SLOTS]
6684865Sobrien#define CURR_SLOT	md.slot[md.curr_slot]
6784865Sobrien
6884865Sobrien#define O_pseudo_fixup (O_max + 1)
6984865Sobrien
7084865Sobrienenum special_section
7184865Sobrien  {
7289857Sobrien    /* IA-64 ABI section pseudo-ops.  */
7384865Sobrien    SPECIAL_SECTION_BSS = 0,
7484865Sobrien    SPECIAL_SECTION_SBSS,
7584865Sobrien    SPECIAL_SECTION_SDATA,
7684865Sobrien    SPECIAL_SECTION_RODATA,
7784865Sobrien    SPECIAL_SECTION_COMMENT,
7884865Sobrien    SPECIAL_SECTION_UNWIND,
7989857Sobrien    SPECIAL_SECTION_UNWIND_INFO,
8089857Sobrien    /* HPUX specific section pseudo-ops.  */
8189857Sobrien    SPECIAL_SECTION_INIT_ARRAY,
8289857Sobrien    SPECIAL_SECTION_FINI_ARRAY,
8384865Sobrien  };
8484865Sobrien
8584865Sobrienenum reloc_func
8684865Sobrien  {
87104834Sobrien    FUNC_DTP_MODULE,
88104834Sobrien    FUNC_DTP_RELATIVE,
8984865Sobrien    FUNC_FPTR_RELATIVE,
9084865Sobrien    FUNC_GP_RELATIVE,
9184865Sobrien    FUNC_LT_RELATIVE,
92130561Sobrien    FUNC_LT_RELATIVE_X,
9384865Sobrien    FUNC_PC_RELATIVE,
9484865Sobrien    FUNC_PLT_RELATIVE,
9584865Sobrien    FUNC_SEC_RELATIVE,
9684865Sobrien    FUNC_SEG_RELATIVE,
97104834Sobrien    FUNC_TP_RELATIVE,
9884865Sobrien    FUNC_LTV_RELATIVE,
9984865Sobrien    FUNC_LT_FPTR_RELATIVE,
100104834Sobrien    FUNC_LT_DTP_MODULE,
101104834Sobrien    FUNC_LT_DTP_RELATIVE,
102104834Sobrien    FUNC_LT_TP_RELATIVE,
10389857Sobrien    FUNC_IPLT_RELOC,
10484865Sobrien  };
10584865Sobrien
10684865Sobrienenum reg_symbol
10784865Sobrien  {
10884865Sobrien    REG_GR	= 0,
10984865Sobrien    REG_FR	= (REG_GR + 128),
11084865Sobrien    REG_AR	= (REG_FR + 128),
11184865Sobrien    REG_CR	= (REG_AR + 128),
11284865Sobrien    REG_P	= (REG_CR + 128),
11384865Sobrien    REG_BR	= (REG_P  + 64),
11484865Sobrien    REG_IP	= (REG_BR + 8),
11584865Sobrien    REG_CFM,
11684865Sobrien    REG_PR,
11784865Sobrien    REG_PR_ROT,
11884865Sobrien    REG_PSR,
11984865Sobrien    REG_PSR_L,
12084865Sobrien    REG_PSR_UM,
12184865Sobrien    /* The following are pseudo-registers for use by gas only.  */
12284865Sobrien    IND_CPUID,
12384865Sobrien    IND_DBR,
12484865Sobrien    IND_DTR,
12584865Sobrien    IND_ITR,
12684865Sobrien    IND_IBR,
12784865Sobrien    IND_MSR,
12884865Sobrien    IND_PKR,
12984865Sobrien    IND_PMC,
13084865Sobrien    IND_PMD,
13184865Sobrien    IND_RR,
13284865Sobrien    /* The following pseudo-registers are used for unwind directives only:  */
13384865Sobrien    REG_PSP,
13484865Sobrien    REG_PRIUNAT,
13584865Sobrien    REG_NUM
13684865Sobrien  };
13784865Sobrien
13884865Sobrienenum dynreg_type
13984865Sobrien  {
14084865Sobrien    DYNREG_GR = 0,	/* dynamic general purpose register */
14184865Sobrien    DYNREG_FR,		/* dynamic floating point register */
14284865Sobrien    DYNREG_PR,		/* dynamic predicate register */
14384865Sobrien    DYNREG_NUM_TYPES
14484865Sobrien  };
14584865Sobrien
14684865Sobrienenum operand_match_result
14784865Sobrien  {
14884865Sobrien    OPERAND_MATCH,
14984865Sobrien    OPERAND_OUT_OF_RANGE,
15084865Sobrien    OPERAND_MISMATCH
15184865Sobrien  };
15284865Sobrien
15384865Sobrien/* On the ia64, we can't know the address of a text label until the
15484865Sobrien   instructions are packed into a bundle.  To handle this, we keep
15584865Sobrien   track of the list of labels that appear in front of each
15684865Sobrien   instruction.  */
15784865Sobrienstruct label_fix
15884865Sobrien{
15984865Sobrien  struct label_fix *next;
16084865Sobrien  struct symbol *sym;
161218822Sdim  bfd_boolean dw2_mark_labels;
16284865Sobrien};
16384865Sobrien
164218822Sdim/* This is the endianness of the current section.  */
16584865Sobrienextern int target_big_endian;
16684865Sobrien
167218822Sdim/* This is the default endianness.  */
168218822Sdimstatic int default_big_endian = TARGET_BYTES_BIG_ENDIAN;
169218822Sdim
170130561Sobrienvoid (*ia64_number_to_chars) PARAMS ((char *, valueT, int));
171130561Sobrien
172130561Sobrienstatic void ia64_float_to_chars_bigendian
173130561Sobrien  PARAMS ((char *, LITTLENUM_TYPE *, int));
174130561Sobrienstatic void ia64_float_to_chars_littleendian
175130561Sobrien  PARAMS ((char *, LITTLENUM_TYPE *, int));
176130561Sobrienstatic void (*ia64_float_to_chars)
177130561Sobrien  PARAMS ((char *, LITTLENUM_TYPE *, int));
178130561Sobrien
179130561Sobrienstatic struct hash_control *alias_hash;
180130561Sobrienstatic struct hash_control *alias_name_hash;
181130561Sobrienstatic struct hash_control *secalias_hash;
182130561Sobrienstatic struct hash_control *secalias_name_hash;
183130561Sobrien
184218822Sdim/* List of chars besides those in app.c:symbol_chars that can start an
185218822Sdim   operand.  Used to prevent the scrubber eating vital white-space.  */
186218822Sdimconst char ia64_symbol_chars[] = "@?";
187218822Sdim
18884865Sobrien/* Characters which always start a comment.  */
18984865Sobrienconst char comment_chars[] = "";
19084865Sobrien
19184865Sobrien/* Characters which start a comment at the beginning of a line.  */
19284865Sobrienconst char line_comment_chars[] = "#";
19384865Sobrien
19484865Sobrien/* Characters which may be used to separate multiple commands on a
19584865Sobrien   single line.  */
196218822Sdimconst char line_separator_chars[] = ";{}";
19784865Sobrien
19884865Sobrien/* Characters which are used to indicate an exponent in a floating
19984865Sobrien   point number.  */
20084865Sobrienconst char EXP_CHARS[] = "eE";
20184865Sobrien
20284865Sobrien/* Characters which mean that a number is a floating point constant,
20384865Sobrien   as in 0d1.0.  */
20484865Sobrienconst char FLT_CHARS[] = "rRsSfFdDxXpP";
20584865Sobrien
20684865Sobrien/* ia64-specific option processing:  */
20784865Sobrien
20884865Sobrienconst char *md_shortopts = "m:N:x::";
20984865Sobrien
21084865Sobrienstruct option md_longopts[] =
21184865Sobrien  {
21284865Sobrien#define OPTION_MCONSTANT_GP (OPTION_MD_BASE + 1)
21384865Sobrien    {"mconstant-gp", no_argument, NULL, OPTION_MCONSTANT_GP},
21484865Sobrien#define OPTION_MAUTO_PIC (OPTION_MD_BASE + 2)
21584865Sobrien    {"mauto-pic", no_argument, NULL, OPTION_MAUTO_PIC}
21684865Sobrien  };
21784865Sobrien
21884865Sobriensize_t md_longopts_size = sizeof (md_longopts);
21984865Sobrien
22084865Sobrienstatic struct
22184865Sobrien  {
22284865Sobrien    struct hash_control *pseudo_hash;	/* pseudo opcode hash table */
22384865Sobrien    struct hash_control *reg_hash;	/* register name hash table */
22484865Sobrien    struct hash_control *dynreg_hash;	/* dynamic register hash table */
22584865Sobrien    struct hash_control *const_hash;	/* constant hash table */
22684865Sobrien    struct hash_control *entry_hash;    /* code entry hint hash table */
22784865Sobrien
22884865Sobrien    /* If X_op is != O_absent, the registername for the instruction's
22984865Sobrien       qualifying predicate.  If NULL, p0 is assumed for instructions
23084865Sobrien       that are predicatable.  */
23184865Sobrien    expressionS qp;
23284865Sobrien
233218822Sdim    /* Optimize for which CPU.  */
234218822Sdim    enum
235218822Sdim      {
236218822Sdim	itanium1,
237218822Sdim	itanium2
238218822Sdim      } tune;
239218822Sdim
240218822Sdim    /* What to do when hint.b is used.  */
241218822Sdim    enum
242218822Sdim      {
243218822Sdim	hint_b_error,
244218822Sdim	hint_b_warning,
245218822Sdim	hint_b_ok
246218822Sdim      } hint_b;
247218822Sdim
24884865Sobrien    unsigned int
24984865Sobrien      manual_bundling : 1,
25084865Sobrien      debug_dv: 1,
25184865Sobrien      detect_dv: 1,
25284865Sobrien      explicit_mode : 1,            /* which mode we're in */
25384865Sobrien      default_explicit_mode : 1,    /* which mode is the default */
25484865Sobrien      mode_explicitly_set : 1,      /* was the current mode explicitly set? */
25584865Sobrien      auto_align : 1,
25684865Sobrien      keep_pending_output : 1;
25784865Sobrien
258218822Sdim    /* What to do when something is wrong with unwind directives.  */
259218822Sdim    enum
260218822Sdim      {
261218822Sdim	unwind_check_warning,
262218822Sdim	unwind_check_error
263218822Sdim      } unwind_check;
264218822Sdim
26584865Sobrien    /* Each bundle consists of up to three instructions.  We keep
26684865Sobrien       track of four most recent instructions so we can correctly set
26784865Sobrien       the end_of_insn_group for the last instruction in a bundle.  */
26884865Sobrien    int curr_slot;
26984865Sobrien    int num_slots_in_use;
27084865Sobrien    struct slot
27184865Sobrien      {
27284865Sobrien	unsigned int
27384865Sobrien	  end_of_insn_group : 1,
27484865Sobrien	  manual_bundling_on : 1,
275218822Sdim	  manual_bundling_off : 1,
276218822Sdim	  loc_directive_seen : 1;
27784865Sobrien	signed char user_template;	/* user-selected template, if any */
27884865Sobrien	unsigned char qp_regno;		/* qualifying predicate */
27984865Sobrien	/* This duplicates a good fraction of "struct fix" but we
28084865Sobrien	   can't use a "struct fix" instead since we can't call
28184865Sobrien	   fix_new_exp() until we know the address of the instruction.  */
28284865Sobrien	int num_fixups;
28384865Sobrien	struct insn_fix
28484865Sobrien	  {
28584865Sobrien	    bfd_reloc_code_real_type code;
28684865Sobrien	    enum ia64_opnd opnd;	/* type of operand in need of fix */
28784865Sobrien	    unsigned int is_pcrel : 1;	/* is operand pc-relative? */
28884865Sobrien	    expressionS expr;		/* the value to be inserted */
28984865Sobrien	  }
29084865Sobrien	fixup[2];			/* at most two fixups per insn */
29184865Sobrien	struct ia64_opcode *idesc;
29284865Sobrien	struct label_fix *label_fixups;
29384865Sobrien	struct label_fix *tag_fixups;
29484865Sobrien	struct unw_rec_list *unwind_record;	/* Unwind directive.  */
29584865Sobrien	expressionS opnd[6];
29684865Sobrien	char *src_file;
29784865Sobrien	unsigned int src_line;
29884865Sobrien	struct dwarf2_line_info debug_line;
29984865Sobrien      }
30084865Sobrien    slot[NUM_SLOTS];
30184865Sobrien
30284865Sobrien    segT last_text_seg;
30384865Sobrien
30484865Sobrien    struct dynreg
30584865Sobrien      {
30684865Sobrien	struct dynreg *next;		/* next dynamic register */
30784865Sobrien	const char *name;
30884865Sobrien	unsigned short base;		/* the base register number */
30984865Sobrien	unsigned short num_regs;	/* # of registers in this set */
31084865Sobrien      }
31184865Sobrien    *dynreg[DYNREG_NUM_TYPES], in, loc, out, rot;
31284865Sobrien
31384865Sobrien    flagword flags;			/* ELF-header flags */
31484865Sobrien
31584865Sobrien    struct mem_offset {
31684865Sobrien      unsigned hint:1;              /* is this hint currently valid? */
31784865Sobrien      bfd_vma offset;               /* mem.offset offset */
31884865Sobrien      bfd_vma base;                 /* mem.offset base */
31984865Sobrien    } mem_offset;
32084865Sobrien
32184865Sobrien    int path;                       /* number of alt. entry points seen */
32284865Sobrien    const char **entry_labels;      /* labels of all alternate paths in
32384865Sobrien				       the current DV-checking block.  */
32484865Sobrien    int maxpaths;                   /* size currently allocated for
32584865Sobrien				       entry_labels */
32684865Sobrien
32789857Sobrien    int pointer_size;       /* size in bytes of a pointer */
32889857Sobrien    int pointer_size_shift; /* shift size of a pointer for alignment */
329218822Sdim
330218822Sdim    symbolS *indregsym[IND_RR - IND_CPUID + 1];
33184865Sobrien  }
33284865Sobrienmd;
33384865Sobrien
334218822Sdim/* These are not const, because they are modified to MMI for non-itanium1
335218822Sdim   targets below.  */
336218822Sdim/* MFI bundle of nops.  */
337218822Sdimstatic unsigned char le_nop[16] =
338218822Sdim{
339218822Sdim  0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
340218822Sdim  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00
341218822Sdim};
342218822Sdim/* MFI bundle of nops with stop-bit.  */
343218822Sdimstatic unsigned char le_nop_stop[16] =
344218822Sdim{
345218822Sdim  0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
346218822Sdim  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00
347218822Sdim};
348218822Sdim
34984865Sobrien/* application registers:  */
35084865Sobrien
35184865Sobrien#define AR_K0		0
35284865Sobrien#define AR_K7		7
35384865Sobrien#define AR_RSC		16
35484865Sobrien#define AR_BSP		17
35584865Sobrien#define AR_BSPSTORE	18
35684865Sobrien#define AR_RNAT		19
357218822Sdim#define AR_FCR		21
358218822Sdim#define AR_EFLAG	24
359218822Sdim#define AR_CSD		25
360218822Sdim#define AR_SSD		26
361218822Sdim#define AR_CFLG		27
362218822Sdim#define AR_FSR		28
363218822Sdim#define AR_FIR		29
364218822Sdim#define AR_FDR		30
365218822Sdim#define AR_CCV		32
36684865Sobrien#define AR_UNAT		36
36784865Sobrien#define AR_FPSR		40
36884865Sobrien#define AR_ITC		44
36984865Sobrien#define AR_PFS		64
37084865Sobrien#define AR_LC		65
371218822Sdim#define AR_EC		66
37284865Sobrien
37384865Sobrienstatic const struct
37484865Sobrien  {
37584865Sobrien    const char *name;
376218822Sdim    unsigned int regnum;
37784865Sobrien  }
37884865Sobrienar[] =
37984865Sobrien  {
380218822Sdim    {"ar.k0",		AR_K0},		{"ar.k1",	AR_K0 + 1},
381218822Sdim    {"ar.k2",		AR_K0 + 2},	{"ar.k3",	AR_K0 + 3},
382218822Sdim    {"ar.k4",		AR_K0 + 4},	{"ar.k5",	AR_K0 + 5},
383218822Sdim    {"ar.k6",		AR_K0 + 6},	{"ar.k7",	AR_K7},
384218822Sdim    {"ar.rsc",		AR_RSC},	{"ar.bsp",	AR_BSP},
385218822Sdim    {"ar.bspstore",	AR_BSPSTORE},	{"ar.rnat",	AR_RNAT},
386218822Sdim    {"ar.fcr",		AR_FCR},	{"ar.eflag",	AR_EFLAG},
387218822Sdim    {"ar.csd",		AR_CSD},	{"ar.ssd",	AR_SSD},
388218822Sdim    {"ar.cflg",		AR_CFLG},	{"ar.fsr",	AR_FSR},
389218822Sdim    {"ar.fir",		AR_FIR},	{"ar.fdr",	AR_FDR},
390218822Sdim    {"ar.ccv",		AR_CCV},	{"ar.unat",	AR_UNAT},
391218822Sdim    {"ar.fpsr",		AR_FPSR},	{"ar.itc",	AR_ITC},
392218822Sdim    {"ar.pfs",		AR_PFS},	{"ar.lc",	AR_LC},
393218822Sdim    {"ar.ec",		AR_EC},
39484865Sobrien  };
39584865Sobrien
396218822Sdim/* control registers:  */
397218822Sdim
398218822Sdim#define CR_DCR           0
399218822Sdim#define CR_ITM           1
400218822Sdim#define CR_IVA           2
401218822Sdim#define CR_PTA           8
402218822Sdim#define CR_GPTA          9
40384865Sobrien#define CR_IPSR         16
40484865Sobrien#define CR_ISR          17
40584865Sobrien#define CR_IIP          19
40684865Sobrien#define CR_IFA          20
40784865Sobrien#define CR_ITIR         21
40884865Sobrien#define CR_IIPA         22
40984865Sobrien#define CR_IFS          23
41084865Sobrien#define CR_IIM          24
41184865Sobrien#define CR_IHA          25
412218822Sdim#define CR_LID          64
41384865Sobrien#define CR_IVR          65
41484865Sobrien#define CR_TPR          66
41584865Sobrien#define CR_EOI          67
41684865Sobrien#define CR_IRR0         68
41784865Sobrien#define CR_IRR3         71
418218822Sdim#define CR_ITV          72
419218822Sdim#define CR_PMV          73
420218822Sdim#define CR_CMCV         74
42184865Sobrien#define CR_LRR0         80
42284865Sobrien#define CR_LRR1         81
42384865Sobrien
42484865Sobrienstatic const struct
42584865Sobrien  {
42684865Sobrien    const char *name;
427218822Sdim    unsigned int regnum;
42884865Sobrien  }
42984865Sobriencr[] =
43084865Sobrien  {
431218822Sdim    {"cr.dcr",	CR_DCR},
432218822Sdim    {"cr.itm",	CR_ITM},
433218822Sdim    {"cr.iva",	CR_IVA},
434218822Sdim    {"cr.pta",	CR_PTA},
435218822Sdim    {"cr.gpta",	CR_GPTA},
436218822Sdim    {"cr.ipsr",	CR_IPSR},
437218822Sdim    {"cr.isr",	CR_ISR},
438218822Sdim    {"cr.iip",	CR_IIP},
439218822Sdim    {"cr.ifa",	CR_IFA},
440218822Sdim    {"cr.itir",	CR_ITIR},
441218822Sdim    {"cr.iipa",	CR_IIPA},
442218822Sdim    {"cr.ifs",	CR_IFS},
443218822Sdim    {"cr.iim",	CR_IIM},
444218822Sdim    {"cr.iha",	CR_IHA},
445218822Sdim    {"cr.lid",	CR_LID},
446218822Sdim    {"cr.ivr",	CR_IVR},
447218822Sdim    {"cr.tpr",	CR_TPR},
448218822Sdim    {"cr.eoi",	CR_EOI},
449218822Sdim    {"cr.irr0",	CR_IRR0},
450218822Sdim    {"cr.irr1",	CR_IRR0 + 1},
451218822Sdim    {"cr.irr2",	CR_IRR0 + 2},
452218822Sdim    {"cr.irr3",	CR_IRR3},
453218822Sdim    {"cr.itv",	CR_ITV},
454218822Sdim    {"cr.pmv",	CR_PMV},
455218822Sdim    {"cr.cmcv",	CR_CMCV},
456218822Sdim    {"cr.lrr0",	CR_LRR0},
457218822Sdim    {"cr.lrr1",	CR_LRR1}
45884865Sobrien  };
45984865Sobrien
46084865Sobrien#define PSR_MFL         4
46184865Sobrien#define PSR_IC          13
46284865Sobrien#define PSR_DFL         18
46384865Sobrien#define PSR_CPL         32
46484865Sobrien
46584865Sobrienstatic const struct const_desc
46684865Sobrien  {
46784865Sobrien    const char *name;
46884865Sobrien    valueT value;
46984865Sobrien  }
47084865Sobrienconst_bits[] =
47184865Sobrien  {
47284865Sobrien    /* PSR constant masks:  */
47384865Sobrien
47484865Sobrien    /* 0: reserved */
47584865Sobrien    {"psr.be",	((valueT) 1) << 1},
47684865Sobrien    {"psr.up",	((valueT) 1) << 2},
47784865Sobrien    {"psr.ac",	((valueT) 1) << 3},
47884865Sobrien    {"psr.mfl",	((valueT) 1) << 4},
47984865Sobrien    {"psr.mfh",	((valueT) 1) << 5},
48084865Sobrien    /* 6-12: reserved */
48184865Sobrien    {"psr.ic",	((valueT) 1) << 13},
48284865Sobrien    {"psr.i",	((valueT) 1) << 14},
48384865Sobrien    {"psr.pk",	((valueT) 1) << 15},
48484865Sobrien    /* 16: reserved */
48584865Sobrien    {"psr.dt",	((valueT) 1) << 17},
48684865Sobrien    {"psr.dfl",	((valueT) 1) << 18},
48784865Sobrien    {"psr.dfh",	((valueT) 1) << 19},
48884865Sobrien    {"psr.sp",	((valueT) 1) << 20},
48984865Sobrien    {"psr.pp",	((valueT) 1) << 21},
49084865Sobrien    {"psr.di",	((valueT) 1) << 22},
49184865Sobrien    {"psr.si",	((valueT) 1) << 23},
49284865Sobrien    {"psr.db",	((valueT) 1) << 24},
49384865Sobrien    {"psr.lp",	((valueT) 1) << 25},
49484865Sobrien    {"psr.tb",	((valueT) 1) << 26},
49584865Sobrien    {"psr.rt",	((valueT) 1) << 27},
49684865Sobrien    /* 28-31: reserved */
49784865Sobrien    /* 32-33: cpl (current privilege level) */
49884865Sobrien    {"psr.is",	((valueT) 1) << 34},
49984865Sobrien    {"psr.mc",	((valueT) 1) << 35},
50084865Sobrien    {"psr.it",	((valueT) 1) << 36},
50184865Sobrien    {"psr.id",	((valueT) 1) << 37},
50284865Sobrien    {"psr.da",	((valueT) 1) << 38},
50384865Sobrien    {"psr.dd",	((valueT) 1) << 39},
50484865Sobrien    {"psr.ss",	((valueT) 1) << 40},
50584865Sobrien    /* 41-42: ri (restart instruction) */
50684865Sobrien    {"psr.ed",	((valueT) 1) << 43},
50784865Sobrien    {"psr.bn",	((valueT) 1) << 44},
50884865Sobrien  };
50984865Sobrien
51084865Sobrien/* indirect register-sets/memory:  */
51184865Sobrien
51284865Sobrienstatic const struct
51384865Sobrien  {
51484865Sobrien    const char *name;
515218822Sdim    unsigned int regnum;
51684865Sobrien  }
51784865Sobrienindirect_reg[] =
51884865Sobrien  {
51984865Sobrien    { "CPUID",	IND_CPUID },
52084865Sobrien    { "cpuid",	IND_CPUID },
52184865Sobrien    { "dbr",	IND_DBR },
52284865Sobrien    { "dtr",	IND_DTR },
52384865Sobrien    { "itr",	IND_ITR },
52484865Sobrien    { "ibr",	IND_IBR },
52584865Sobrien    { "msr",	IND_MSR },
52684865Sobrien    { "pkr",	IND_PKR },
52784865Sobrien    { "pmc",	IND_PMC },
52884865Sobrien    { "pmd",	IND_PMD },
52984865Sobrien    { "rr",	IND_RR },
53084865Sobrien  };
53184865Sobrien
53284865Sobrien/* Pseudo functions used to indicate relocation types (these functions
53384865Sobrien   start with an at sign (@).  */
53484865Sobrienstatic struct
53584865Sobrien  {
53684865Sobrien    const char *name;
53784865Sobrien    enum pseudo_type
53884865Sobrien      {
53984865Sobrien	PSEUDO_FUNC_NONE,
54084865Sobrien	PSEUDO_FUNC_RELOC,
54184865Sobrien	PSEUDO_FUNC_CONST,
54284865Sobrien	PSEUDO_FUNC_REG,
54384865Sobrien	PSEUDO_FUNC_FLOAT
54484865Sobrien      }
54584865Sobrien    type;
54684865Sobrien    union
54784865Sobrien      {
54884865Sobrien	unsigned long ival;
54984865Sobrien	symbolS *sym;
55084865Sobrien      }
55184865Sobrien    u;
55284865Sobrien  }
55384865Sobrienpseudo_func[] =
55484865Sobrien  {
55584865Sobrien    /* reloc pseudo functions (these must come first!):  */
556104834Sobrien    { "dtpmod",	PSEUDO_FUNC_RELOC, { 0 } },
557104834Sobrien    { "dtprel",	PSEUDO_FUNC_RELOC, { 0 } },
55884865Sobrien    { "fptr",	PSEUDO_FUNC_RELOC, { 0 } },
55984865Sobrien    { "gprel",	PSEUDO_FUNC_RELOC, { 0 } },
56084865Sobrien    { "ltoff",	PSEUDO_FUNC_RELOC, { 0 } },
561130561Sobrien    { "ltoffx",	PSEUDO_FUNC_RELOC, { 0 } },
56284865Sobrien    { "pcrel",	PSEUDO_FUNC_RELOC, { 0 } },
56384865Sobrien    { "pltoff",	PSEUDO_FUNC_RELOC, { 0 } },
56484865Sobrien    { "secrel",	PSEUDO_FUNC_RELOC, { 0 } },
56584865Sobrien    { "segrel",	PSEUDO_FUNC_RELOC, { 0 } },
566104834Sobrien    { "tprel",	PSEUDO_FUNC_RELOC, { 0 } },
56784865Sobrien    { "ltv",	PSEUDO_FUNC_RELOC, { 0 } },
568218822Sdim    { NULL, 0, { 0 } },	/* placeholder for FUNC_LT_FPTR_RELATIVE */
569218822Sdim    { NULL, 0, { 0 } },	/* placeholder for FUNC_LT_DTP_MODULE */
570218822Sdim    { NULL, 0, { 0 } },	/* placeholder for FUNC_LT_DTP_RELATIVE */
571218822Sdim    { NULL, 0, { 0 } },	/* placeholder for FUNC_LT_TP_RELATIVE */
57289857Sobrien    { "iplt",	PSEUDO_FUNC_RELOC, { 0 } },
57384865Sobrien
57484865Sobrien    /* mbtype4 constants:  */
57584865Sobrien    { "alt",	PSEUDO_FUNC_CONST, { 0xa } },
57684865Sobrien    { "brcst",	PSEUDO_FUNC_CONST, { 0x0 } },
57784865Sobrien    { "mix",	PSEUDO_FUNC_CONST, { 0x8 } },
57884865Sobrien    { "rev",	PSEUDO_FUNC_CONST, { 0xb } },
57984865Sobrien    { "shuf",	PSEUDO_FUNC_CONST, { 0x9 } },
58084865Sobrien
58184865Sobrien    /* fclass constants:  */
58284865Sobrien    { "nat",	PSEUDO_FUNC_CONST, { 0x100 } },
58384865Sobrien    { "qnan",	PSEUDO_FUNC_CONST, { 0x080 } },
58484865Sobrien    { "snan",	PSEUDO_FUNC_CONST, { 0x040 } },
58584865Sobrien    { "pos",	PSEUDO_FUNC_CONST, { 0x001 } },
58684865Sobrien    { "neg",	PSEUDO_FUNC_CONST, { 0x002 } },
58784865Sobrien    { "zero",	PSEUDO_FUNC_CONST, { 0x004 } },
58884865Sobrien    { "unorm",	PSEUDO_FUNC_CONST, { 0x008 } },
58984865Sobrien    { "norm",	PSEUDO_FUNC_CONST, { 0x010 } },
59084865Sobrien    { "inf",	PSEUDO_FUNC_CONST, { 0x020 } },
59184865Sobrien
59284865Sobrien    { "natval",	PSEUDO_FUNC_CONST, { 0x100 } }, /* old usage */
59384865Sobrien
594130561Sobrien    /* hint constants: */
595130561Sobrien    { "pause",	PSEUDO_FUNC_CONST, { 0x0 } },
596130561Sobrien
59784865Sobrien    /* unwind-related constants:  */
598130561Sobrien    { "svr4",	PSEUDO_FUNC_CONST,	{ ELFOSABI_NONE } },
599130561Sobrien    { "hpux",	PSEUDO_FUNC_CONST,	{ ELFOSABI_HPUX } },
600130561Sobrien    { "nt",	PSEUDO_FUNC_CONST,	{ 2 } },		/* conflicts w/ELFOSABI_NETBSD */
601130561Sobrien    { "linux",	PSEUDO_FUNC_CONST,	{ ELFOSABI_LINUX } },
602130561Sobrien    { "freebsd", PSEUDO_FUNC_CONST,	{ ELFOSABI_FREEBSD } },
603130561Sobrien    { "openvms", PSEUDO_FUNC_CONST,	{ ELFOSABI_OPENVMS } },
604130561Sobrien    { "nsk",	PSEUDO_FUNC_CONST,	{ ELFOSABI_NSK } },
60584865Sobrien
60684865Sobrien    /* unwind-related registers:  */
60784865Sobrien    { "priunat",PSEUDO_FUNC_REG, { REG_PRIUNAT } }
60884865Sobrien  };
60984865Sobrien
61084865Sobrien/* 41-bit nop opcodes (one per unit):  */
61184865Sobrienstatic const bfd_vma nop[IA64_NUM_UNITS] =
61284865Sobrien  {
61384865Sobrien    0x0000000000LL,	/* NIL => break 0 */
61484865Sobrien    0x0008000000LL,	/* I-unit nop */
61584865Sobrien    0x0008000000LL,	/* M-unit nop */
61684865Sobrien    0x4000000000LL,	/* B-unit nop */
61784865Sobrien    0x0008000000LL,	/* F-unit nop */
618218822Sdim    0x0000000000LL,	/* L-"unit" nop immediate */
61984865Sobrien    0x0008000000LL,	/* X-unit nop */
62084865Sobrien  };
62184865Sobrien
62284865Sobrien/* Can't be `const' as it's passed to input routines (which have the
62384865Sobrien   habit of setting temporary sentinels.  */
62484865Sobrienstatic char special_section_name[][20] =
62584865Sobrien  {
62684865Sobrien    {".bss"}, {".sbss"}, {".sdata"}, {".rodata"}, {".comment"},
62789857Sobrien    {".IA_64.unwind"}, {".IA_64.unwind_info"},
62889857Sobrien    {".init_array"}, {".fini_array"}
62984865Sobrien  };
63084865Sobrien
63184865Sobrien/* The best template for a particular sequence of up to three
63284865Sobrien   instructions:  */
63384865Sobrien#define N	IA64_NUM_TYPES
63484865Sobrienstatic unsigned char best_template[N][N][N];
63584865Sobrien#undef N
63684865Sobrien
63784865Sobrien/* Resource dependencies currently in effect */
63884865Sobrienstatic struct rsrc {
63984865Sobrien  int depind;                       /* dependency index */
64084865Sobrien  const struct ia64_dependency *dependency; /* actual dependency */
64184865Sobrien  unsigned specific:1,              /* is this a specific bit/regno? */
64284865Sobrien    link_to_qp_branch:1;           /* will a branch on the same QP clear it?*/
64384865Sobrien  int index;                        /* specific regno/bit within dependency */
64484865Sobrien  int note;                         /* optional qualifying note (0 if none) */
64584865Sobrien#define STATE_NONE 0
64684865Sobrien#define STATE_STOP 1
64784865Sobrien#define STATE_SRLZ 2
64884865Sobrien  int insn_srlz;                    /* current insn serialization state */
64984865Sobrien  int data_srlz;                    /* current data serialization state */
65084865Sobrien  int qp_regno;                     /* qualifying predicate for this usage */
65184865Sobrien  char *file;                       /* what file marked this dependency */
65284865Sobrien  unsigned int line;                /* what line marked this dependency */
65384865Sobrien  struct mem_offset mem_offset;     /* optional memory offset hint */
65484865Sobrien  enum { CMP_NONE, CMP_OR, CMP_AND } cmp_type; /* OR or AND compare? */
65584865Sobrien  int path;                         /* corresponding code entry index */
65684865Sobrien} *regdeps = NULL;
65784865Sobrienstatic int regdepslen = 0;
65884865Sobrienstatic int regdepstotlen = 0;
65984865Sobrienstatic const char *dv_mode[] = { "RAW", "WAW", "WAR" };
66084865Sobrienstatic const char *dv_sem[] = { "none", "implied", "impliedf",
66184865Sobrien				"data", "instr", "specific", "stop", "other" };
66284865Sobrienstatic const char *dv_cmp_type[] = { "none", "OR", "AND" };
66384865Sobrien
66484865Sobrien/* Current state of PR mutexation */
66584865Sobrienstatic struct qpmutex {
66684865Sobrien  valueT prmask;
66784865Sobrien  int path;
66884865Sobrien} *qp_mutexes = NULL;          /* QP mutex bitmasks */
66984865Sobrienstatic int qp_mutexeslen = 0;
67084865Sobrienstatic int qp_mutexestotlen = 0;
67184865Sobrienstatic valueT qp_safe_across_calls = 0;
67284865Sobrien
67384865Sobrien/* Current state of PR implications */
67484865Sobrienstatic struct qp_imply {
67584865Sobrien  unsigned p1:6;
67684865Sobrien  unsigned p2:6;
67784865Sobrien  unsigned p2_branched:1;
67884865Sobrien  int path;
67984865Sobrien} *qp_implies = NULL;
68084865Sobrienstatic int qp_implieslen = 0;
68184865Sobrienstatic int qp_impliestotlen = 0;
68284865Sobrien
68384865Sobrien/* Keep track of static GR values so that indirect register usage can
68484865Sobrien   sometimes be tracked.  */
68584865Sobrienstatic struct gr {
68684865Sobrien  unsigned known:1;
68784865Sobrien  int path;
68884865Sobrien  valueT value;
689218822Sdim} gr_values[128] = {
690218822Sdim  {
691218822Sdim    1,
692218822Sdim#ifdef INT_MAX
693218822Sdim    INT_MAX,
694218822Sdim#else
695218822Sdim    (((1 << (8 * sizeof(gr_values->path) - 2)) - 1) << 1) + 1,
696218822Sdim#endif
697218822Sdim    0
698218822Sdim  }
699218822Sdim};
70084865Sobrien
701130561Sobrien/* Remember the alignment frag.  */
702130561Sobrienstatic fragS *align_frag;
703130561Sobrien
70484865Sobrien/* These are the routines required to output the various types of
70584865Sobrien   unwind records.  */
70684865Sobrien
70784865Sobrien/* A slot_number is a frag address plus the slot index (0-2).  We use the
70884865Sobrien   frag address here so that if there is a section switch in the middle of
70984865Sobrien   a function, then instructions emitted to a different section are not
71084865Sobrien   counted.  Since there may be more than one frag for a function, this
71184865Sobrien   means we also need to keep track of which frag this address belongs to
71284865Sobrien   so we can compute inter-frag distances.  This also nicely solves the
71384865Sobrien   problem with nops emitted for align directives, which can't easily be
71484865Sobrien   counted, but can easily be derived from frag sizes.  */
71584865Sobrien
71684865Sobrientypedef struct unw_rec_list {
71784865Sobrien  unwind_record r;
71884865Sobrien  unsigned long slot_number;
71984865Sobrien  fragS *slot_frag;
72084865Sobrien  struct unw_rec_list *next;
72184865Sobrien} unw_rec_list;
72284865Sobrien
72384865Sobrien#define SLOT_NUM_NOT_SET        (unsigned)-1
72484865Sobrien
72592828Sobrien/* Linked list of saved prologue counts.  A very poor
72692828Sobrien   implementation of a map from label numbers to prologue counts.  */
72792828Sobrientypedef struct label_prologue_count
72892828Sobrien{
72992828Sobrien  struct label_prologue_count *next;
73092828Sobrien  unsigned long label_number;
73192828Sobrien  unsigned int prologue_count;
73292828Sobrien} label_prologue_count;
73392828Sobrien
734218822Sdimtypedef struct proc_pending
735218822Sdim{
736218822Sdim  symbolS *sym;
737218822Sdim  struct proc_pending *next;
738218822Sdim} proc_pending;
739218822Sdim
74084865Sobrienstatic struct
74184865Sobrien{
74284865Sobrien  /* Maintain a list of unwind entries for the current function.  */
74384865Sobrien  unw_rec_list *list;
74484865Sobrien  unw_rec_list *tail;
74584865Sobrien
74684865Sobrien  /* Any unwind entires that should be attached to the current slot
74784865Sobrien     that an insn is being constructed for.  */
74884865Sobrien  unw_rec_list *current_entry;
74984865Sobrien
75084865Sobrien  /* These are used to create the unwind table entry for this function.  */
751218822Sdim  proc_pending proc_pending;
75284865Sobrien  symbolS *info;		/* pointer to unwind info */
75384865Sobrien  symbolS *personality_routine;
75484865Sobrien  segT saved_text_seg;
75584865Sobrien  subsegT saved_text_subseg;
75684865Sobrien  unsigned int force_unwind_entry : 1;	/* force generation of unwind entry? */
75784865Sobrien
75884865Sobrien  /* TRUE if processing unwind directives in a prologue region.  */
759218822Sdim  unsigned int prologue : 1;
760218822Sdim  unsigned int prologue_mask : 4;
761218822Sdim  unsigned int prologue_gr : 7;
762218822Sdim  unsigned int body : 1;
763218822Sdim  unsigned int insn : 1;
76484865Sobrien  unsigned int prologue_count;	/* number of .prologues seen so far */
76592828Sobrien  /* Prologue counts at previous .label_state directives.  */
76692828Sobrien  struct label_prologue_count * saved_prologue_counts;
767218822Sdim
768218822Sdim  /* List of split up .save-s.  */
769218822Sdim  unw_p_record *pending_saves;
77084865Sobrien} unwind;
77184865Sobrien
772218822Sdim/* The input value is a negated offset from psp, and specifies an address
773218822Sdim   psp - offset.  The encoded value is psp + 16 - (4 * offset).  Thus we
774218822Sdim   must add 16 and divide by 4 to get the encoded value.  */
775218822Sdim
776218822Sdim#define ENCODED_PSP_OFFSET(OFFSET) (((OFFSET) + 16) / 4)
777218822Sdim
77884865Sobrientypedef void (*vbyte_func) PARAMS ((int, char *, char *));
77984865Sobrien
780130561Sobrien/* Forward declarations:  */
78184865Sobrienstatic void set_section PARAMS ((char *name));
78284865Sobrienstatic unsigned int set_regstack PARAMS ((unsigned int, unsigned int,
78384865Sobrien					  unsigned int, unsigned int));
784130561Sobrienstatic void dot_align (int);
78584865Sobrienstatic void dot_radix PARAMS ((int));
78684865Sobrienstatic void dot_special_section PARAMS ((int));
78784865Sobrienstatic void dot_proc PARAMS ((int));
78884865Sobrienstatic void dot_fframe PARAMS ((int));
78984865Sobrienstatic void dot_vframe PARAMS ((int));
79084865Sobrienstatic void dot_vframesp PARAMS ((int));
79184865Sobrienstatic void dot_save PARAMS ((int));
79284865Sobrienstatic void dot_restore PARAMS ((int));
79384865Sobrienstatic void dot_restorereg PARAMS ((int));
79484865Sobrienstatic void dot_handlerdata  PARAMS ((int));
79584865Sobrienstatic void dot_unwentry PARAMS ((int));
79684865Sobrienstatic void dot_altrp PARAMS ((int));
79784865Sobrienstatic void dot_savemem PARAMS ((int));
79884865Sobrienstatic void dot_saveg PARAMS ((int));
79984865Sobrienstatic void dot_savef PARAMS ((int));
80084865Sobrienstatic void dot_saveb PARAMS ((int));
80184865Sobrienstatic void dot_savegf PARAMS ((int));
80284865Sobrienstatic void dot_spill PARAMS ((int));
80384865Sobrienstatic void dot_spillreg PARAMS ((int));
80484865Sobrienstatic void dot_spillmem PARAMS ((int));
80584865Sobrienstatic void dot_label_state PARAMS ((int));
80684865Sobrienstatic void dot_copy_state PARAMS ((int));
80784865Sobrienstatic void dot_unwabi PARAMS ((int));
80884865Sobrienstatic void dot_personality PARAMS ((int));
80984865Sobrienstatic void dot_body PARAMS ((int));
81084865Sobrienstatic void dot_prologue PARAMS ((int));
81184865Sobrienstatic void dot_endp PARAMS ((int));
81284865Sobrienstatic void dot_template PARAMS ((int));
81384865Sobrienstatic void dot_regstk PARAMS ((int));
81484865Sobrienstatic void dot_rot PARAMS ((int));
81584865Sobrienstatic void dot_byteorder PARAMS ((int));
81684865Sobrienstatic void dot_psr PARAMS ((int));
81784865Sobrienstatic void dot_alias PARAMS ((int));
81884865Sobrienstatic void dot_ln PARAMS ((int));
819218822Sdimstatic void cross_section PARAMS ((int ref, void (*cons) PARAMS((int)), int ua));
82084865Sobrienstatic void dot_xdata PARAMS ((int));
82184865Sobrienstatic void stmt_float_cons PARAMS ((int));
82284865Sobrienstatic void stmt_cons_ua PARAMS ((int));
82384865Sobrienstatic void dot_xfloat_cons PARAMS ((int));
82484865Sobrienstatic void dot_xstringer PARAMS ((int));
82584865Sobrienstatic void dot_xdata_ua PARAMS ((int));
82684865Sobrienstatic void dot_xfloat_cons_ua PARAMS ((int));
82784865Sobrienstatic void print_prmask PARAMS ((valueT mask));
82884865Sobrienstatic void dot_pred_rel PARAMS ((int));
82984865Sobrienstatic void dot_reg_val PARAMS ((int));
830218822Sdimstatic void dot_serialize PARAMS ((int));
83184865Sobrienstatic void dot_dv_mode PARAMS ((int));
83284865Sobrienstatic void dot_entry PARAMS ((int));
83384865Sobrienstatic void dot_mem_offset PARAMS ((int));
834218822Sdimstatic void add_unwind_entry PARAMS((unw_rec_list *, int));
835218822Sdimstatic symbolS *declare_register PARAMS ((const char *name, unsigned int regnum));
836218822Sdimstatic void declare_register_set PARAMS ((const char *, unsigned int, unsigned int));
83784865Sobrienstatic unsigned int operand_width PARAMS ((enum ia64_opnd));
83884865Sobrienstatic enum operand_match_result operand_match PARAMS ((const struct ia64_opcode *idesc,
83984865Sobrien							int index,
84084865Sobrien							expressionS *e));
841218822Sdimstatic int parse_operand PARAMS ((expressionS *, int));
84284865Sobrienstatic struct ia64_opcode * parse_operands PARAMS ((struct ia64_opcode *));
84384865Sobrienstatic void build_insn PARAMS ((struct slot *, bfd_vma *));
84484865Sobrienstatic void emit_one_bundle PARAMS ((void));
84584865Sobrienstatic void fix_insn PARAMS ((fixS *, const struct ia64_operand *, valueT));
84684865Sobrienstatic bfd_reloc_code_real_type ia64_gen_real_reloc_type PARAMS ((struct symbol *sym,
84784865Sobrien								  bfd_reloc_code_real_type r_type));
84884865Sobrienstatic void insn_group_break PARAMS ((int, int, int));
84984865Sobrienstatic void mark_resource PARAMS ((struct ia64_opcode *, const struct ia64_dependency *,
85084865Sobrien				   struct rsrc *, int depind, int path));
85184865Sobrienstatic void add_qp_mutex PARAMS((valueT mask));
85284865Sobrienstatic void add_qp_imply PARAMS((int p1, int p2));
85384865Sobrienstatic void clear_qp_branch_flag PARAMS((valueT mask));
85484865Sobrienstatic void clear_qp_mutex PARAMS((valueT mask));
85584865Sobrienstatic void clear_qp_implies PARAMS((valueT p1_mask, valueT p2_mask));
85689857Sobrienstatic int has_suffix_p PARAMS((const char *, const char *));
85784865Sobrienstatic void clear_register_values PARAMS ((void));
85884865Sobrienstatic void print_dependency PARAMS ((const char *action, int depind));
85984865Sobrienstatic void instruction_serialization PARAMS ((void));
86084865Sobrienstatic void data_serialization PARAMS ((void));
86184865Sobrienstatic void remove_marked_resource PARAMS ((struct rsrc *));
86284865Sobrienstatic int is_conditional_branch PARAMS ((struct ia64_opcode *));
86384865Sobrienstatic int is_taken_branch PARAMS ((struct ia64_opcode *));
86484865Sobrienstatic int is_interruption_or_rfi PARAMS ((struct ia64_opcode *));
86584865Sobrienstatic int depends_on PARAMS ((int, struct ia64_opcode *));
86684865Sobrienstatic int specify_resource PARAMS ((const struct ia64_dependency *,
86784865Sobrien				     struct ia64_opcode *, int, struct rsrc [], int, int));
86884865Sobrienstatic int check_dv PARAMS((struct ia64_opcode *idesc));
86984865Sobrienstatic void check_dependencies PARAMS((struct ia64_opcode *));
87084865Sobrienstatic void mark_resources PARAMS((struct ia64_opcode *));
87184865Sobrienstatic void update_dependencies PARAMS((struct ia64_opcode *));
87284865Sobrienstatic void note_register_values PARAMS((struct ia64_opcode *));
87384865Sobrienstatic int qp_mutex PARAMS ((int, int, int));
87484865Sobrienstatic int resources_match PARAMS ((struct rsrc *, struct ia64_opcode *, int, int, int));
87584865Sobrienstatic void output_vbyte_mem PARAMS ((int, char *, char *));
87684865Sobrienstatic void count_output PARAMS ((int, char *, char *));
87784865Sobrienstatic void output_R1_format PARAMS ((vbyte_func, unw_record_type, int));
87884865Sobrienstatic void output_R2_format PARAMS ((vbyte_func, int, int, unsigned long));
87984865Sobrienstatic void output_R3_format PARAMS ((vbyte_func, unw_record_type, unsigned long));
88084865Sobrienstatic void output_P1_format PARAMS ((vbyte_func, int));
88184865Sobrienstatic void output_P2_format PARAMS ((vbyte_func, int, int));
88284865Sobrienstatic void output_P3_format PARAMS ((vbyte_func, unw_record_type, int));
88384865Sobrienstatic void output_P4_format PARAMS ((vbyte_func, unsigned char *, unsigned long));
88484865Sobrienstatic void output_P5_format PARAMS ((vbyte_func, int, unsigned long));
88584865Sobrienstatic void output_P6_format PARAMS ((vbyte_func, unw_record_type, int));
88684865Sobrienstatic void output_P7_format PARAMS ((vbyte_func, unw_record_type, unsigned long, unsigned long));
88784865Sobrienstatic void output_P8_format PARAMS ((vbyte_func, unw_record_type, unsigned long));
88884865Sobrienstatic void output_P9_format PARAMS ((vbyte_func, int, int));
88984865Sobrienstatic void output_P10_format PARAMS ((vbyte_func, int, int));
89084865Sobrienstatic void output_B1_format PARAMS ((vbyte_func, unw_record_type, unsigned long));
89184865Sobrienstatic void output_B2_format PARAMS ((vbyte_func, unsigned long, unsigned long));
89284865Sobrienstatic void output_B3_format PARAMS ((vbyte_func, unsigned long, unsigned long));
89384865Sobrienstatic void output_B4_format PARAMS ((vbyte_func, unw_record_type, unsigned long));
89484865Sobrienstatic char format_ab_reg PARAMS ((int, int));
89584865Sobrienstatic void output_X1_format PARAMS ((vbyte_func, unw_record_type, int, int, unsigned long,
89684865Sobrien				      unsigned long));
89784865Sobrienstatic void output_X2_format PARAMS ((vbyte_func, int, int, int, int, int, unsigned long));
89884865Sobrienstatic void output_X3_format PARAMS ((vbyte_func, unw_record_type, int, int, int, unsigned long,
89984865Sobrien				      unsigned long));
90084865Sobrienstatic void output_X4_format PARAMS ((vbyte_func, int, int, int, int, int, int, unsigned long));
901130561Sobrienstatic unw_rec_list *output_endp PARAMS ((void));
90284865Sobrienstatic unw_rec_list *output_prologue PARAMS ((void));
90384865Sobrienstatic unw_rec_list *output_prologue_gr PARAMS ((unsigned int, unsigned int));
90484865Sobrienstatic unw_rec_list *output_body PARAMS ((void));
90584865Sobrienstatic unw_rec_list *output_mem_stack_f PARAMS ((unsigned int));
90684865Sobrienstatic unw_rec_list *output_mem_stack_v PARAMS ((void));
90784865Sobrienstatic unw_rec_list *output_psp_gr PARAMS ((unsigned int));
90884865Sobrienstatic unw_rec_list *output_psp_sprel PARAMS ((unsigned int));
90984865Sobrienstatic unw_rec_list *output_rp_when PARAMS ((void));
91084865Sobrienstatic unw_rec_list *output_rp_gr PARAMS ((unsigned int));
91184865Sobrienstatic unw_rec_list *output_rp_br PARAMS ((unsigned int));
91284865Sobrienstatic unw_rec_list *output_rp_psprel PARAMS ((unsigned int));
91384865Sobrienstatic unw_rec_list *output_rp_sprel PARAMS ((unsigned int));
91484865Sobrienstatic unw_rec_list *output_pfs_when PARAMS ((void));
91584865Sobrienstatic unw_rec_list *output_pfs_gr PARAMS ((unsigned int));
91684865Sobrienstatic unw_rec_list *output_pfs_psprel PARAMS ((unsigned int));
91784865Sobrienstatic unw_rec_list *output_pfs_sprel PARAMS ((unsigned int));
91884865Sobrienstatic unw_rec_list *output_preds_when PARAMS ((void));
91984865Sobrienstatic unw_rec_list *output_preds_gr PARAMS ((unsigned int));
92084865Sobrienstatic unw_rec_list *output_preds_psprel PARAMS ((unsigned int));
92184865Sobrienstatic unw_rec_list *output_preds_sprel PARAMS ((unsigned int));
92284865Sobrienstatic unw_rec_list *output_fr_mem PARAMS ((unsigned int));
92384865Sobrienstatic unw_rec_list *output_frgr_mem PARAMS ((unsigned int, unsigned int));
92484865Sobrienstatic unw_rec_list *output_gr_gr PARAMS ((unsigned int, unsigned int));
92584865Sobrienstatic unw_rec_list *output_gr_mem PARAMS ((unsigned int));
92684865Sobrienstatic unw_rec_list *output_br_mem PARAMS ((unsigned int));
92784865Sobrienstatic unw_rec_list *output_br_gr PARAMS ((unsigned int, unsigned int));
92884865Sobrienstatic unw_rec_list *output_spill_base PARAMS ((unsigned int));
92984865Sobrienstatic unw_rec_list *output_unat_when PARAMS ((void));
93084865Sobrienstatic unw_rec_list *output_unat_gr PARAMS ((unsigned int));
93184865Sobrienstatic unw_rec_list *output_unat_psprel PARAMS ((unsigned int));
93284865Sobrienstatic unw_rec_list *output_unat_sprel PARAMS ((unsigned int));
93384865Sobrienstatic unw_rec_list *output_lc_when PARAMS ((void));
93484865Sobrienstatic unw_rec_list *output_lc_gr PARAMS ((unsigned int));
93584865Sobrienstatic unw_rec_list *output_lc_psprel PARAMS ((unsigned int));
93684865Sobrienstatic unw_rec_list *output_lc_sprel PARAMS ((unsigned int));
93784865Sobrienstatic unw_rec_list *output_fpsr_when PARAMS ((void));
93884865Sobrienstatic unw_rec_list *output_fpsr_gr PARAMS ((unsigned int));
93984865Sobrienstatic unw_rec_list *output_fpsr_psprel PARAMS ((unsigned int));
94084865Sobrienstatic unw_rec_list *output_fpsr_sprel PARAMS ((unsigned int));
94184865Sobrienstatic unw_rec_list *output_priunat_when_gr PARAMS ((void));
94284865Sobrienstatic unw_rec_list *output_priunat_when_mem PARAMS ((void));
94384865Sobrienstatic unw_rec_list *output_priunat_gr PARAMS ((unsigned int));
94484865Sobrienstatic unw_rec_list *output_priunat_psprel PARAMS ((unsigned int));
94584865Sobrienstatic unw_rec_list *output_priunat_sprel PARAMS ((unsigned int));
94684865Sobrienstatic unw_rec_list *output_bsp_when PARAMS ((void));
94784865Sobrienstatic unw_rec_list *output_bsp_gr PARAMS ((unsigned int));
94884865Sobrienstatic unw_rec_list *output_bsp_psprel PARAMS ((unsigned int));
94984865Sobrienstatic unw_rec_list *output_bsp_sprel PARAMS ((unsigned int));
95084865Sobrienstatic unw_rec_list *output_bspstore_when PARAMS ((void));
95184865Sobrienstatic unw_rec_list *output_bspstore_gr PARAMS ((unsigned int));
95284865Sobrienstatic unw_rec_list *output_bspstore_psprel PARAMS ((unsigned int));
95384865Sobrienstatic unw_rec_list *output_bspstore_sprel PARAMS ((unsigned int));
95484865Sobrienstatic unw_rec_list *output_rnat_when PARAMS ((void));
95584865Sobrienstatic unw_rec_list *output_rnat_gr PARAMS ((unsigned int));
95684865Sobrienstatic unw_rec_list *output_rnat_psprel PARAMS ((unsigned int));
95784865Sobrienstatic unw_rec_list *output_rnat_sprel PARAMS ((unsigned int));
95884865Sobrienstatic unw_rec_list *output_unwabi PARAMS ((unsigned long, unsigned long));
95984865Sobrienstatic unw_rec_list *output_epilogue PARAMS ((unsigned long));
96084865Sobrienstatic unw_rec_list *output_label_state PARAMS ((unsigned long));
96184865Sobrienstatic unw_rec_list *output_copy_state PARAMS ((unsigned long));
962218822Sdimstatic unw_rec_list *output_spill_psprel PARAMS ((unsigned int, unsigned int, unsigned int,
96384865Sobrien						    unsigned int));
964218822Sdimstatic unw_rec_list *output_spill_sprel PARAMS ((unsigned int, unsigned int, unsigned int,
96584865Sobrien						   unsigned int));
96684865Sobrienstatic unw_rec_list *output_spill_reg PARAMS ((unsigned int, unsigned int, unsigned int,
96784865Sobrien						 unsigned int, unsigned int));
96884865Sobrienstatic void process_one_record PARAMS ((unw_rec_list *, vbyte_func));
96984865Sobrienstatic void process_unw_records PARAMS ((unw_rec_list *, vbyte_func));
97084865Sobrienstatic int calc_record_size PARAMS ((unw_rec_list *));
97184865Sobrienstatic void set_imask PARAMS ((unw_rec_list *, unsigned long, unsigned long, unsigned int));
97284865Sobrienstatic unsigned long slot_index PARAMS ((unsigned long, fragS *,
973130561Sobrien					 unsigned long, fragS *,
974130561Sobrien					 int));
97584865Sobrienstatic unw_rec_list *optimize_unw_records PARAMS ((unw_rec_list *));
976130561Sobrienstatic void fixup_unw_records PARAMS ((unw_rec_list *, int));
977218822Sdimstatic int parse_predicate_and_operand PARAMS ((expressionS *, unsigned *, const char *));
978218822Sdimstatic void convert_expr_to_ab_reg PARAMS ((const expressionS *, unsigned int *, unsigned int *, const char *, int));
979218822Sdimstatic void convert_expr_to_xy_reg PARAMS ((const expressionS *, unsigned int *, unsigned int *, const char *, int));
98092828Sobrienstatic unsigned int get_saved_prologue_count PARAMS ((unsigned long));
98192828Sobrienstatic void save_prologue_count PARAMS ((unsigned long, unsigned int));
98292828Sobrienstatic void free_saved_prologue_counts PARAMS ((void));
98384865Sobrien
984218822Sdim/* Determine if application register REGNUM resides only in the integer
98584865Sobrien   unit (as opposed to the memory unit).  */
98684865Sobrienstatic int
987218822Sdimar_is_only_in_integer_unit (int reg)
98884865Sobrien{
98984865Sobrien  reg -= REG_AR;
990218822Sdim  return reg >= 64 && reg <= 111;
991218822Sdim}
99284865Sobrien
993218822Sdim/* Determine if application register REGNUM resides only in the memory
994218822Sdim   unit (as opposed to the integer unit).  */
995218822Sdimstatic int
996218822Sdimar_is_only_in_memory_unit (int reg)
997218822Sdim{
998218822Sdim  reg -= REG_AR;
999218822Sdim  return reg >= 0 && reg <= 47;
100084865Sobrien}
100184865Sobrien
100284865Sobrien/* Switch to section NAME and create section if necessary.  It's
100384865Sobrien   rather ugly that we have to manipulate input_line_pointer but I
100484865Sobrien   don't see any other way to accomplish the same thing without
100584865Sobrien   changing obj-elf.c (which may be the Right Thing, in the end).  */
100684865Sobrienstatic void
100784865Sobrienset_section (name)
100884865Sobrien     char *name;
100984865Sobrien{
101084865Sobrien  char *saved_input_line_pointer;
101184865Sobrien
101284865Sobrien  saved_input_line_pointer = input_line_pointer;
101384865Sobrien  input_line_pointer = name;
101484865Sobrien  obj_elf_section (0);
101584865Sobrien  input_line_pointer = saved_input_line_pointer;
101684865Sobrien}
101784865Sobrien
101889857Sobrien/* Map 's' to SHF_IA_64_SHORT.  */
101989857Sobrien
102089857Sobrienint
102189857Sobrienia64_elf_section_letter (letter, ptr_msg)
102289857Sobrien     int letter;
102389857Sobrien     char **ptr_msg;
102489857Sobrien{
102589857Sobrien  if (letter == 's')
102689857Sobrien    return SHF_IA_64_SHORT;
1027130561Sobrien  else if (letter == 'o')
1028130561Sobrien    return SHF_LINK_ORDER;
102989857Sobrien
1030130561Sobrien  *ptr_msg = _("Bad .section directive: want a,o,s,w,x,M,S,G,T in string");
1031130561Sobrien  return -1;
103289857Sobrien}
103389857Sobrien
103484865Sobrien/* Map SHF_IA_64_SHORT to SEC_SMALL_DATA.  */
103584865Sobrien
103684865Sobrienflagword
103784865Sobrienia64_elf_section_flags (flags, attr, type)
103884865Sobrien     flagword flags;
103984865Sobrien     int attr, type ATTRIBUTE_UNUSED;
104084865Sobrien{
104184865Sobrien  if (attr & SHF_IA_64_SHORT)
104284865Sobrien    flags |= SEC_SMALL_DATA;
104384865Sobrien  return flags;
104484865Sobrien}
104584865Sobrien
104684865Sobrienint
104784865Sobrienia64_elf_section_type (str, len)
1048104834Sobrien     const char *str;
1049104834Sobrien     size_t len;
105084865Sobrien{
105189857Sobrien#define STREQ(s) ((len == sizeof (s) - 1) && (strncmp (str, s, sizeof (s) - 1) == 0))
1052104834Sobrien
105389857Sobrien  if (STREQ (ELF_STRING_ia64_unwind_info))
105484865Sobrien    return SHT_PROGBITS;
105584865Sobrien
105689857Sobrien  if (STREQ (ELF_STRING_ia64_unwind_info_once))
105789857Sobrien    return SHT_PROGBITS;
105889857Sobrien
105989857Sobrien  if (STREQ (ELF_STRING_ia64_unwind))
106084865Sobrien    return SHT_IA_64_UNWIND;
106184865Sobrien
106289857Sobrien  if (STREQ (ELF_STRING_ia64_unwind_once))
106389857Sobrien    return SHT_IA_64_UNWIND;
106489857Sobrien
1065130561Sobrien  if (STREQ ("unwind"))
1066130561Sobrien    return SHT_IA_64_UNWIND;
1067130561Sobrien
106884865Sobrien  return -1;
106989857Sobrien#undef STREQ
107084865Sobrien}
107184865Sobrien
107284865Sobrienstatic unsigned int
107384865Sobrienset_regstack (ins, locs, outs, rots)
107484865Sobrien     unsigned int ins, locs, outs, rots;
107584865Sobrien{
107684865Sobrien  /* Size of frame.  */
107784865Sobrien  unsigned int sof;
107884865Sobrien
107984865Sobrien  sof = ins + locs + outs;
108084865Sobrien  if (sof > 96)
108184865Sobrien    {
108284865Sobrien      as_bad ("Size of frame exceeds maximum of 96 registers");
108384865Sobrien      return 0;
108484865Sobrien    }
108584865Sobrien  if (rots > sof)
108684865Sobrien    {
108784865Sobrien      as_warn ("Size of rotating registers exceeds frame size");
108884865Sobrien      return 0;
108984865Sobrien    }
109084865Sobrien  md.in.base = REG_GR + 32;
109184865Sobrien  md.loc.base = md.in.base + ins;
109284865Sobrien  md.out.base = md.loc.base + locs;
109384865Sobrien
109484865Sobrien  md.in.num_regs  = ins;
109584865Sobrien  md.loc.num_regs = locs;
109684865Sobrien  md.out.num_regs = outs;
109784865Sobrien  md.rot.num_regs = rots;
109884865Sobrien  return sof;
109984865Sobrien}
110084865Sobrien
110184865Sobrienvoid
110284865Sobrienia64_flush_insns ()
110384865Sobrien{
110484865Sobrien  struct label_fix *lfix;
110584865Sobrien  segT saved_seg;
110684865Sobrien  subsegT saved_subseg;
110784865Sobrien  unw_rec_list *ptr;
1108218822Sdim  bfd_boolean mark;
110984865Sobrien
111084865Sobrien  if (!md.last_text_seg)
111184865Sobrien    return;
111284865Sobrien
111384865Sobrien  saved_seg = now_seg;
111484865Sobrien  saved_subseg = now_subseg;
111584865Sobrien
111684865Sobrien  subseg_set (md.last_text_seg, 0);
111784865Sobrien
111884865Sobrien  while (md.num_slots_in_use > 0)
111984865Sobrien    emit_one_bundle ();		/* force out queued instructions */
112084865Sobrien
112184865Sobrien  /* In case there are labels following the last instruction, resolve
1122218822Sdim     those now.  */
1123218822Sdim  mark = FALSE;
112484865Sobrien  for (lfix = CURR_SLOT.label_fixups; lfix; lfix = lfix->next)
112584865Sobrien    {
1126218822Sdim      symbol_set_value_now (lfix->sym);
1127218822Sdim      mark |= lfix->dw2_mark_labels;
112884865Sobrien    }
1129218822Sdim  if (mark)
1130218822Sdim    {
1131218822Sdim      dwarf2_where (&CURR_SLOT.debug_line);
1132218822Sdim      CURR_SLOT.debug_line.flags |= DWARF2_FLAG_BASIC_BLOCK;
1133218822Sdim      dwarf2_gen_line_info (frag_now_fix (), &CURR_SLOT.debug_line);
1134218822Sdim    }
113584865Sobrien  CURR_SLOT.label_fixups = 0;
1136218822Sdim
113784865Sobrien  for (lfix = CURR_SLOT.tag_fixups; lfix; lfix = lfix->next)
1138218822Sdim    symbol_set_value_now (lfix->sym);
113984865Sobrien  CURR_SLOT.tag_fixups = 0;
114084865Sobrien
114184865Sobrien  /* In case there are unwind directives following the last instruction,
1142130561Sobrien     resolve those now.  We only handle prologue, body, and endp directives
1143130561Sobrien     here.  Give an error for others.  */
114484865Sobrien  for (ptr = unwind.current_entry; ptr; ptr = ptr->next)
114584865Sobrien    {
1146130561Sobrien      switch (ptr->r.type)
114784865Sobrien	{
1148130561Sobrien	case prologue:
1149130561Sobrien	case prologue_gr:
1150130561Sobrien	case body:
1151130561Sobrien	case endp:
115284865Sobrien	  ptr->slot_number = (unsigned long) frag_more (0);
115384865Sobrien	  ptr->slot_frag = frag_now;
1154130561Sobrien	  break;
1155130561Sobrien
1156130561Sobrien	  /* Allow any record which doesn't have a "t" field (i.e.,
1157130561Sobrien	     doesn't relate to a particular instruction).  */
1158130561Sobrien	case unwabi:
1159130561Sobrien	case br_gr:
1160130561Sobrien	case copy_state:
1161130561Sobrien	case fr_mem:
1162130561Sobrien	case frgr_mem:
1163130561Sobrien	case gr_gr:
1164130561Sobrien	case gr_mem:
1165130561Sobrien	case label_state:
1166130561Sobrien	case rp_br:
1167130561Sobrien	case spill_base:
1168130561Sobrien	case spill_mask:
1169130561Sobrien	  /* nothing */
1170130561Sobrien	  break;
1171130561Sobrien
1172130561Sobrien	default:
1173130561Sobrien	  as_bad (_("Unwind directive not followed by an instruction."));
1174130561Sobrien	  break;
117584865Sobrien	}
117684865Sobrien    }
117784865Sobrien  unwind.current_entry = NULL;
117884865Sobrien
117984865Sobrien  subseg_set (saved_seg, saved_subseg);
118084865Sobrien
118184865Sobrien  if (md.qp.X_op == O_register)
118284865Sobrien    as_bad ("qualifying predicate not followed by instruction");
118384865Sobrien}
118484865Sobrien
1185130561Sobrienstatic void
1186130561Sobrienia64_do_align (int nbytes)
118784865Sobrien{
118884865Sobrien  char *saved_input_line_pointer = input_line_pointer;
118984865Sobrien
119084865Sobrien  input_line_pointer = "";
119184865Sobrien  s_align_bytes (nbytes);
119284865Sobrien  input_line_pointer = saved_input_line_pointer;
119384865Sobrien}
119484865Sobrien
119584865Sobrienvoid
119684865Sobrienia64_cons_align (nbytes)
119784865Sobrien     int nbytes;
119884865Sobrien{
119984865Sobrien  if (md.auto_align)
120084865Sobrien    {
120184865Sobrien      char *saved_input_line_pointer = input_line_pointer;
120284865Sobrien      input_line_pointer = "";
120384865Sobrien      s_align_bytes (nbytes);
120484865Sobrien      input_line_pointer = saved_input_line_pointer;
120584865Sobrien    }
120684865Sobrien}
120784865Sobrien
120884865Sobrien/* Output COUNT bytes to a memory location.  */
1209218822Sdimstatic char *vbyte_mem_ptr = NULL;
121084865Sobrien
121184865Sobrienvoid
121284865Sobrienoutput_vbyte_mem (count, ptr, comment)
121384865Sobrien     int count;
121484865Sobrien     char *ptr;
121584865Sobrien     char *comment ATTRIBUTE_UNUSED;
121684865Sobrien{
121784865Sobrien  int x;
121884865Sobrien  if (vbyte_mem_ptr == NULL)
121984865Sobrien    abort ();
122084865Sobrien
122184865Sobrien  if (count == 0)
122284865Sobrien    return;
122384865Sobrien  for (x = 0; x < count; x++)
122484865Sobrien    *(vbyte_mem_ptr++) = ptr[x];
122584865Sobrien}
122684865Sobrien
122784865Sobrien/* Count the number of bytes required for records.  */
122884865Sobrienstatic int vbyte_count = 0;
122984865Sobrienvoid
123084865Sobriencount_output (count, ptr, comment)
123184865Sobrien     int count;
123284865Sobrien     char *ptr ATTRIBUTE_UNUSED;
123384865Sobrien     char *comment ATTRIBUTE_UNUSED;
123484865Sobrien{
123584865Sobrien  vbyte_count += count;
123684865Sobrien}
123784865Sobrien
123884865Sobrienstatic void
123984865Sobrienoutput_R1_format (f, rtype, rlen)
124084865Sobrien     vbyte_func f;
124184865Sobrien     unw_record_type rtype;
124284865Sobrien     int rlen;
124384865Sobrien{
124484865Sobrien  int r = 0;
124584865Sobrien  char byte;
124684865Sobrien  if (rlen > 0x1f)
124784865Sobrien    {
124884865Sobrien      output_R3_format (f, rtype, rlen);
124984865Sobrien      return;
125084865Sobrien    }
125184865Sobrien
125284865Sobrien  if (rtype == body)
125384865Sobrien    r = 1;
125484865Sobrien  else if (rtype != prologue)
125584865Sobrien    as_bad ("record type is not valid");
125684865Sobrien
125784865Sobrien  byte = UNW_R1 | (r << 5) | (rlen & 0x1f);
125884865Sobrien  (*f) (1, &byte, NULL);
125984865Sobrien}
126084865Sobrien
126184865Sobrienstatic void
126284865Sobrienoutput_R2_format (f, mask, grsave, rlen)
126384865Sobrien     vbyte_func f;
126484865Sobrien     int mask, grsave;
126584865Sobrien     unsigned long rlen;
126684865Sobrien{
126784865Sobrien  char bytes[20];
126884865Sobrien  int count = 2;
126984865Sobrien  mask = (mask & 0x0f);
127084865Sobrien  grsave = (grsave & 0x7f);
127184865Sobrien
127284865Sobrien  bytes[0] = (UNW_R2 | (mask >> 1));
127384865Sobrien  bytes[1] = (((mask & 0x01) << 7) | grsave);
127484865Sobrien  count += output_leb128 (bytes + 2, rlen, 0);
127584865Sobrien  (*f) (count, bytes, NULL);
127684865Sobrien}
127784865Sobrien
127884865Sobrienstatic void
127984865Sobrienoutput_R3_format (f, rtype, rlen)
128084865Sobrien     vbyte_func f;
128184865Sobrien     unw_record_type rtype;
128284865Sobrien     unsigned long rlen;
128384865Sobrien{
128484865Sobrien  int r = 0, count;
128584865Sobrien  char bytes[20];
128684865Sobrien  if (rlen <= 0x1f)
128784865Sobrien    {
128884865Sobrien      output_R1_format (f, rtype, rlen);
128984865Sobrien      return;
129084865Sobrien    }
129184865Sobrien
129284865Sobrien  if (rtype == body)
129384865Sobrien    r = 1;
129484865Sobrien  else if (rtype != prologue)
129584865Sobrien    as_bad ("record type is not valid");
129684865Sobrien  bytes[0] = (UNW_R3 | r);
129784865Sobrien  count = output_leb128 (bytes + 1, rlen, 0);
129884865Sobrien  (*f) (count + 1, bytes, NULL);
129984865Sobrien}
130084865Sobrien
130184865Sobrienstatic void
130284865Sobrienoutput_P1_format (f, brmask)
130384865Sobrien     vbyte_func f;
130484865Sobrien     int brmask;
130584865Sobrien{
130684865Sobrien  char byte;
130784865Sobrien  byte = UNW_P1 | (brmask & 0x1f);
130884865Sobrien  (*f) (1, &byte, NULL);
130984865Sobrien}
131084865Sobrien
131184865Sobrienstatic void
131284865Sobrienoutput_P2_format (f, brmask, gr)
131384865Sobrien     vbyte_func f;
131484865Sobrien     int brmask;
131584865Sobrien     int gr;
131684865Sobrien{
131784865Sobrien  char bytes[2];
131884865Sobrien  brmask = (brmask & 0x1f);
131984865Sobrien  bytes[0] = UNW_P2 | (brmask >> 1);
132084865Sobrien  bytes[1] = (((brmask & 1) << 7) | gr);
132184865Sobrien  (*f) (2, bytes, NULL);
132284865Sobrien}
132384865Sobrien
132484865Sobrienstatic void
132584865Sobrienoutput_P3_format (f, rtype, reg)
132684865Sobrien     vbyte_func f;
132784865Sobrien     unw_record_type rtype;
132884865Sobrien     int reg;
132984865Sobrien{
133084865Sobrien  char bytes[2];
133184865Sobrien  int r = 0;
133284865Sobrien  reg = (reg & 0x7f);
133384865Sobrien  switch (rtype)
133484865Sobrien    {
133584865Sobrien    case psp_gr:
133684865Sobrien      r = 0;
133784865Sobrien      break;
133884865Sobrien    case rp_gr:
133984865Sobrien      r = 1;
134084865Sobrien      break;
134184865Sobrien    case pfs_gr:
134284865Sobrien      r = 2;
134384865Sobrien      break;
134484865Sobrien    case preds_gr:
134584865Sobrien      r = 3;
134684865Sobrien      break;
134784865Sobrien    case unat_gr:
134884865Sobrien      r = 4;
134984865Sobrien      break;
135084865Sobrien    case lc_gr:
135184865Sobrien      r = 5;
135284865Sobrien      break;
135384865Sobrien    case rp_br:
135484865Sobrien      r = 6;
135584865Sobrien      break;
135684865Sobrien    case rnat_gr:
135784865Sobrien      r = 7;
135884865Sobrien      break;
135984865Sobrien    case bsp_gr:
136084865Sobrien      r = 8;
136184865Sobrien      break;
136284865Sobrien    case bspstore_gr:
136384865Sobrien      r = 9;
136484865Sobrien      break;
136584865Sobrien    case fpsr_gr:
136684865Sobrien      r = 10;
136784865Sobrien      break;
136884865Sobrien    case priunat_gr:
136984865Sobrien      r = 11;
137084865Sobrien      break;
137184865Sobrien    default:
137284865Sobrien      as_bad ("Invalid record type for P3 format.");
137384865Sobrien    }
137484865Sobrien  bytes[0] = (UNW_P3 | (r >> 1));
137584865Sobrien  bytes[1] = (((r & 1) << 7) | reg);
137684865Sobrien  (*f) (2, bytes, NULL);
137784865Sobrien}
137884865Sobrien
137984865Sobrienstatic void
138084865Sobrienoutput_P4_format (f, imask, imask_size)
138184865Sobrien     vbyte_func f;
138284865Sobrien     unsigned char *imask;
138384865Sobrien     unsigned long imask_size;
138484865Sobrien{
138584865Sobrien  imask[0] = UNW_P4;
1386218822Sdim  (*f) (imask_size, (char *) imask, NULL);
138784865Sobrien}
138884865Sobrien
138984865Sobrienstatic void
139084865Sobrienoutput_P5_format (f, grmask, frmask)
139184865Sobrien     vbyte_func f;
139284865Sobrien     int grmask;
139384865Sobrien     unsigned long frmask;
139484865Sobrien{
139584865Sobrien  char bytes[4];
139684865Sobrien  grmask = (grmask & 0x0f);
139784865Sobrien
139884865Sobrien  bytes[0] = UNW_P5;
139984865Sobrien  bytes[1] = ((grmask << 4) | ((frmask & 0x000f0000) >> 16));
140084865Sobrien  bytes[2] = ((frmask & 0x0000ff00) >> 8);
140184865Sobrien  bytes[3] = (frmask & 0x000000ff);
140284865Sobrien  (*f) (4, bytes, NULL);
140384865Sobrien}
140484865Sobrien
140584865Sobrienstatic void
140684865Sobrienoutput_P6_format (f, rtype, rmask)
140784865Sobrien     vbyte_func f;
140884865Sobrien     unw_record_type rtype;
140984865Sobrien     int rmask;
141084865Sobrien{
141184865Sobrien  char byte;
141284865Sobrien  int r = 0;
141384865Sobrien
141484865Sobrien  if (rtype == gr_mem)
141584865Sobrien    r = 1;
141684865Sobrien  else if (rtype != fr_mem)
141784865Sobrien    as_bad ("Invalid record type for format P6");
141884865Sobrien  byte = (UNW_P6 | (r << 4) | (rmask & 0x0f));
141984865Sobrien  (*f) (1, &byte, NULL);
142084865Sobrien}
142184865Sobrien
142284865Sobrienstatic void
142384865Sobrienoutput_P7_format (f, rtype, w1, w2)
142484865Sobrien     vbyte_func f;
142584865Sobrien     unw_record_type rtype;
142684865Sobrien     unsigned long w1;
142784865Sobrien     unsigned long w2;
142884865Sobrien{
142984865Sobrien  char bytes[20];
143084865Sobrien  int count = 1;
143184865Sobrien  int r = 0;
143284865Sobrien  count += output_leb128 (bytes + 1, w1, 0);
143384865Sobrien  switch (rtype)
143484865Sobrien    {
143584865Sobrien    case mem_stack_f:
143684865Sobrien      r = 0;
143784865Sobrien      count += output_leb128 (bytes + count, w2 >> 4, 0);
143884865Sobrien      break;
143984865Sobrien    case mem_stack_v:
144084865Sobrien      r = 1;
144184865Sobrien      break;
144284865Sobrien    case spill_base:
144384865Sobrien      r = 2;
144484865Sobrien      break;
144584865Sobrien    case psp_sprel:
144684865Sobrien      r = 3;
144784865Sobrien      break;
144884865Sobrien    case rp_when:
144984865Sobrien      r = 4;
145084865Sobrien      break;
145184865Sobrien    case rp_psprel:
145284865Sobrien      r = 5;
145384865Sobrien      break;
145484865Sobrien    case pfs_when:
145584865Sobrien      r = 6;
145684865Sobrien      break;
145784865Sobrien    case pfs_psprel:
145884865Sobrien      r = 7;
145984865Sobrien      break;
146084865Sobrien    case preds_when:
146184865Sobrien      r = 8;
146284865Sobrien      break;
146384865Sobrien    case preds_psprel:
146484865Sobrien      r = 9;
146584865Sobrien      break;
146684865Sobrien    case lc_when:
146784865Sobrien      r = 10;
146884865Sobrien      break;
146984865Sobrien    case lc_psprel:
147084865Sobrien      r = 11;
147184865Sobrien      break;
147284865Sobrien    case unat_when:
147384865Sobrien      r = 12;
147484865Sobrien      break;
147584865Sobrien    case unat_psprel:
147684865Sobrien      r = 13;
147784865Sobrien      break;
147884865Sobrien    case fpsr_when:
147984865Sobrien      r = 14;
148084865Sobrien      break;
148184865Sobrien    case fpsr_psprel:
148284865Sobrien      r = 15;
148384865Sobrien      break;
148484865Sobrien    default:
148584865Sobrien      break;
148684865Sobrien    }
148784865Sobrien  bytes[0] = (UNW_P7 | r);
148884865Sobrien  (*f) (count, bytes, NULL);
148984865Sobrien}
149084865Sobrien
149184865Sobrienstatic void
149284865Sobrienoutput_P8_format (f, rtype, t)
149384865Sobrien     vbyte_func f;
149484865Sobrien     unw_record_type rtype;
149584865Sobrien     unsigned long t;
149684865Sobrien{
149784865Sobrien  char bytes[20];
149884865Sobrien  int r = 0;
149984865Sobrien  int count = 2;
150084865Sobrien  bytes[0] = UNW_P8;
150184865Sobrien  switch (rtype)
150284865Sobrien    {
150384865Sobrien    case rp_sprel:
150484865Sobrien      r = 1;
150584865Sobrien      break;
150684865Sobrien    case pfs_sprel:
150784865Sobrien      r = 2;
150884865Sobrien      break;
150984865Sobrien    case preds_sprel:
151084865Sobrien      r = 3;
151184865Sobrien      break;
151284865Sobrien    case lc_sprel:
151384865Sobrien      r = 4;
151484865Sobrien      break;
151584865Sobrien    case unat_sprel:
151684865Sobrien      r = 5;
151784865Sobrien      break;
151884865Sobrien    case fpsr_sprel:
151984865Sobrien      r = 6;
152084865Sobrien      break;
152184865Sobrien    case bsp_when:
152284865Sobrien      r = 7;
152384865Sobrien      break;
152484865Sobrien    case bsp_psprel:
152584865Sobrien      r = 8;
152684865Sobrien      break;
152784865Sobrien    case bsp_sprel:
152884865Sobrien      r = 9;
152984865Sobrien      break;
153084865Sobrien    case bspstore_when:
153184865Sobrien      r = 10;
153284865Sobrien      break;
153384865Sobrien    case bspstore_psprel:
153484865Sobrien      r = 11;
153584865Sobrien      break;
153684865Sobrien    case bspstore_sprel:
153784865Sobrien      r = 12;
153884865Sobrien      break;
153984865Sobrien    case rnat_when:
154084865Sobrien      r = 13;
154184865Sobrien      break;
154284865Sobrien    case rnat_psprel:
154384865Sobrien      r = 14;
154484865Sobrien      break;
154584865Sobrien    case rnat_sprel:
154684865Sobrien      r = 15;
154784865Sobrien      break;
154884865Sobrien    case priunat_when_gr:
154984865Sobrien      r = 16;
155084865Sobrien      break;
155184865Sobrien    case priunat_psprel:
155284865Sobrien      r = 17;
155384865Sobrien      break;
155484865Sobrien    case priunat_sprel:
155584865Sobrien      r = 18;
155684865Sobrien      break;
155784865Sobrien    case priunat_when_mem:
155884865Sobrien      r = 19;
155984865Sobrien      break;
156084865Sobrien    default:
156184865Sobrien      break;
156284865Sobrien    }
156384865Sobrien  bytes[1] = r;
156484865Sobrien  count += output_leb128 (bytes + 2, t, 0);
156584865Sobrien  (*f) (count, bytes, NULL);
156684865Sobrien}
156784865Sobrien
156884865Sobrienstatic void
156984865Sobrienoutput_P9_format (f, grmask, gr)
157084865Sobrien     vbyte_func f;
157184865Sobrien     int grmask;
157284865Sobrien     int gr;
157384865Sobrien{
157484865Sobrien  char bytes[3];
157584865Sobrien  bytes[0] = UNW_P9;
157684865Sobrien  bytes[1] = (grmask & 0x0f);
157784865Sobrien  bytes[2] = (gr & 0x7f);
157884865Sobrien  (*f) (3, bytes, NULL);
157984865Sobrien}
158084865Sobrien
158184865Sobrienstatic void
158284865Sobrienoutput_P10_format (f, abi, context)
158384865Sobrien     vbyte_func f;
158484865Sobrien     int abi;
158584865Sobrien     int context;
158684865Sobrien{
158784865Sobrien  char bytes[3];
158884865Sobrien  bytes[0] = UNW_P10;
158984865Sobrien  bytes[1] = (abi & 0xff);
159084865Sobrien  bytes[2] = (context & 0xff);
159184865Sobrien  (*f) (3, bytes, NULL);
159284865Sobrien}
159384865Sobrien
159484865Sobrienstatic void
159584865Sobrienoutput_B1_format (f, rtype, label)
159684865Sobrien     vbyte_func f;
159784865Sobrien     unw_record_type rtype;
159884865Sobrien     unsigned long label;
159984865Sobrien{
160084865Sobrien  char byte;
160184865Sobrien  int r = 0;
160284865Sobrien  if (label > 0x1f)
160384865Sobrien    {
160484865Sobrien      output_B4_format (f, rtype, label);
160584865Sobrien      return;
160684865Sobrien    }
160784865Sobrien  if (rtype == copy_state)
160884865Sobrien    r = 1;
160984865Sobrien  else if (rtype != label_state)
161084865Sobrien    as_bad ("Invalid record type for format B1");
161184865Sobrien
161284865Sobrien  byte = (UNW_B1 | (r << 5) | (label & 0x1f));
161384865Sobrien  (*f) (1, &byte, NULL);
161484865Sobrien}
161584865Sobrien
161684865Sobrienstatic void
161784865Sobrienoutput_B2_format (f, ecount, t)
161884865Sobrien     vbyte_func f;
161984865Sobrien     unsigned long ecount;
162084865Sobrien     unsigned long t;
162184865Sobrien{
162284865Sobrien  char bytes[20];
162384865Sobrien  int count = 1;
162484865Sobrien  if (ecount > 0x1f)
162584865Sobrien    {
162684865Sobrien      output_B3_format (f, ecount, t);
162784865Sobrien      return;
162884865Sobrien    }
162984865Sobrien  bytes[0] = (UNW_B2 | (ecount & 0x1f));
163084865Sobrien  count += output_leb128 (bytes + 1, t, 0);
163184865Sobrien  (*f) (count, bytes, NULL);
163284865Sobrien}
163384865Sobrien
163484865Sobrienstatic void
163584865Sobrienoutput_B3_format (f, ecount, t)
163684865Sobrien     vbyte_func f;
163784865Sobrien     unsigned long ecount;
163884865Sobrien     unsigned long t;
163984865Sobrien{
164084865Sobrien  char bytes[20];
164184865Sobrien  int count = 1;
164284865Sobrien  if (ecount <= 0x1f)
164384865Sobrien    {
164484865Sobrien      output_B2_format (f, ecount, t);
164584865Sobrien      return;
164684865Sobrien    }
164784865Sobrien  bytes[0] = UNW_B3;
164884865Sobrien  count += output_leb128 (bytes + 1, t, 0);
164984865Sobrien  count += output_leb128 (bytes + count, ecount, 0);
165084865Sobrien  (*f) (count, bytes, NULL);
165184865Sobrien}
165284865Sobrien
165384865Sobrienstatic void
165484865Sobrienoutput_B4_format (f, rtype, label)
165584865Sobrien     vbyte_func f;
165684865Sobrien     unw_record_type rtype;
165784865Sobrien     unsigned long label;
165884865Sobrien{
165984865Sobrien  char bytes[20];
166084865Sobrien  int r = 0;
166184865Sobrien  int count = 1;
166284865Sobrien  if (label <= 0x1f)
166384865Sobrien    {
166484865Sobrien      output_B1_format (f, rtype, label);
166584865Sobrien      return;
166684865Sobrien    }
166784865Sobrien
166884865Sobrien  if (rtype == copy_state)
166984865Sobrien    r = 1;
167084865Sobrien  else if (rtype != label_state)
167184865Sobrien    as_bad ("Invalid record type for format B1");
167284865Sobrien
167384865Sobrien  bytes[0] = (UNW_B4 | (r << 3));
167484865Sobrien  count += output_leb128 (bytes + 1, label, 0);
167584865Sobrien  (*f) (count, bytes, NULL);
167684865Sobrien}
167784865Sobrien
167884865Sobrienstatic char
167984865Sobrienformat_ab_reg (ab, reg)
168084865Sobrien     int ab;
168184865Sobrien     int reg;
168284865Sobrien{
168384865Sobrien  int ret;
168484865Sobrien  ab = (ab & 3);
168584865Sobrien  reg = (reg & 0x1f);
168684865Sobrien  ret = (ab << 5) | reg;
168784865Sobrien  return ret;
168884865Sobrien}
168984865Sobrien
169084865Sobrienstatic void
169184865Sobrienoutput_X1_format (f, rtype, ab, reg, t, w1)
169284865Sobrien     vbyte_func f;
169384865Sobrien     unw_record_type rtype;
169484865Sobrien     int ab, reg;
169584865Sobrien     unsigned long t;
169684865Sobrien     unsigned long w1;
169784865Sobrien{
169884865Sobrien  char bytes[20];
169984865Sobrien  int r = 0;
170084865Sobrien  int count = 2;
170184865Sobrien  bytes[0] = UNW_X1;
170284865Sobrien
170384865Sobrien  if (rtype == spill_sprel)
170484865Sobrien    r = 1;
170584865Sobrien  else if (rtype != spill_psprel)
170684865Sobrien    as_bad ("Invalid record type for format X1");
170784865Sobrien  bytes[1] = ((r << 7) | format_ab_reg (ab, reg));
170884865Sobrien  count += output_leb128 (bytes + 2, t, 0);
170984865Sobrien  count += output_leb128 (bytes + count, w1, 0);
171084865Sobrien  (*f) (count, bytes, NULL);
171184865Sobrien}
171284865Sobrien
171384865Sobrienstatic void
171484865Sobrienoutput_X2_format (f, ab, reg, x, y, treg, t)
171584865Sobrien     vbyte_func f;
171684865Sobrien     int ab, reg;
171784865Sobrien     int x, y, treg;
171884865Sobrien     unsigned long t;
171984865Sobrien{
172084865Sobrien  char bytes[20];
172184865Sobrien  int count = 3;
172284865Sobrien  bytes[0] = UNW_X2;
172384865Sobrien  bytes[1] = (((x & 1) << 7) | format_ab_reg (ab, reg));
172484865Sobrien  bytes[2] = (((y & 1) << 7) | (treg & 0x7f));
172584865Sobrien  count += output_leb128 (bytes + 3, t, 0);
172684865Sobrien  (*f) (count, bytes, NULL);
172784865Sobrien}
172884865Sobrien
172984865Sobrienstatic void
173084865Sobrienoutput_X3_format (f, rtype, qp, ab, reg, t, w1)
173184865Sobrien     vbyte_func f;
173284865Sobrien     unw_record_type rtype;
173384865Sobrien     int qp;
173484865Sobrien     int ab, reg;
173584865Sobrien     unsigned long t;
173684865Sobrien     unsigned long w1;
173784865Sobrien{
173884865Sobrien  char bytes[20];
173984865Sobrien  int r = 0;
174084865Sobrien  int count = 3;
174184865Sobrien  bytes[0] = UNW_X3;
174284865Sobrien
174384865Sobrien  if (rtype == spill_sprel_p)
174484865Sobrien    r = 1;
174584865Sobrien  else if (rtype != spill_psprel_p)
174684865Sobrien    as_bad ("Invalid record type for format X3");
174784865Sobrien  bytes[1] = ((r << 7) | (qp & 0x3f));
174884865Sobrien  bytes[2] = format_ab_reg (ab, reg);
174984865Sobrien  count += output_leb128 (bytes + 3, t, 0);
175084865Sobrien  count += output_leb128 (bytes + count, w1, 0);
175184865Sobrien  (*f) (count, bytes, NULL);
175284865Sobrien}
175384865Sobrien
175484865Sobrienstatic void
175584865Sobrienoutput_X4_format (f, qp, ab, reg, x, y, treg, t)
175684865Sobrien     vbyte_func f;
175784865Sobrien     int qp;
175884865Sobrien     int ab, reg;
175984865Sobrien     int x, y, treg;
176084865Sobrien     unsigned long t;
176184865Sobrien{
176284865Sobrien  char bytes[20];
176384865Sobrien  int count = 4;
176484865Sobrien  bytes[0] = UNW_X4;
176584865Sobrien  bytes[1] = (qp & 0x3f);
176684865Sobrien  bytes[2] = (((x & 1) << 7) | format_ab_reg (ab, reg));
176784865Sobrien  bytes[3] = (((y & 1) << 7) | (treg & 0x7f));
176884865Sobrien  count += output_leb128 (bytes + 4, t, 0);
176984865Sobrien  (*f) (count, bytes, NULL);
177084865Sobrien}
177184865Sobrien
1772218822Sdim/* This function checks whether there are any outstanding .save-s and
1773218822Sdim   discards them if so.  */
1774218822Sdim
1775218822Sdimstatic void
1776218822Sdimcheck_pending_save (void)
1777218822Sdim{
1778218822Sdim  if (unwind.pending_saves)
1779218822Sdim    {
1780218822Sdim      unw_rec_list *cur, *prev;
1781218822Sdim
1782218822Sdim      as_warn ("Previous .save incomplete");
1783218822Sdim      for (cur = unwind.list, prev = NULL; cur; )
1784218822Sdim	if (&cur->r.record.p == unwind.pending_saves)
1785218822Sdim	  {
1786218822Sdim	    if (prev)
1787218822Sdim	      prev->next = cur->next;
1788218822Sdim	    else
1789218822Sdim	      unwind.list = cur->next;
1790218822Sdim	    if (cur == unwind.tail)
1791218822Sdim	      unwind.tail = prev;
1792218822Sdim	    if (cur == unwind.current_entry)
1793218822Sdim	      unwind.current_entry = cur->next;
1794218822Sdim	    /* Don't free the first discarded record, it's being used as
1795218822Sdim	       terminator for (currently) br_gr and gr_gr processing, and
1796218822Sdim	       also prevents leaving a dangling pointer to it in its
1797218822Sdim	       predecessor.  */
1798218822Sdim	    cur->r.record.p.grmask = 0;
1799218822Sdim	    cur->r.record.p.brmask = 0;
1800218822Sdim	    cur->r.record.p.frmask = 0;
1801218822Sdim	    prev = cur->r.record.p.next;
1802218822Sdim	    cur->r.record.p.next = NULL;
1803218822Sdim	    cur = prev;
1804218822Sdim	    break;
1805218822Sdim	  }
1806218822Sdim	else
1807218822Sdim	  {
1808218822Sdim	    prev = cur;
1809218822Sdim	    cur = cur->next;
1810218822Sdim	  }
1811218822Sdim      while (cur)
1812218822Sdim	{
1813218822Sdim	  prev = cur;
1814218822Sdim	  cur = cur->r.record.p.next;
1815218822Sdim	  free (prev);
1816218822Sdim	}
1817218822Sdim      unwind.pending_saves = NULL;
1818218822Sdim    }
1819218822Sdim}
1820218822Sdim
182184865Sobrien/* This function allocates a record list structure, and initializes fields.  */
182284865Sobrien
182384865Sobrienstatic unw_rec_list *
182484865Sobrienalloc_record (unw_record_type t)
182584865Sobrien{
182684865Sobrien  unw_rec_list *ptr;
182784865Sobrien  ptr = xmalloc (sizeof (*ptr));
1828218822Sdim  memset (ptr, 0, sizeof (*ptr));
182984865Sobrien  ptr->slot_number = SLOT_NUM_NOT_SET;
183084865Sobrien  ptr->r.type = t;
183184865Sobrien  return ptr;
183284865Sobrien}
183384865Sobrien
1834130561Sobrien/* Dummy unwind record used for calculating the length of the last prologue or
1835130561Sobrien   body region.  */
183684865Sobrien
1837130561Sobrienstatic unw_rec_list *
1838130561Sobrienoutput_endp ()
183984865Sobrien{
1840130561Sobrien  unw_rec_list *ptr = alloc_record (endp);
1841130561Sobrien  return ptr;
184284865Sobrien}
184384865Sobrien
184484865Sobrienstatic unw_rec_list *
184584865Sobrienoutput_prologue ()
184684865Sobrien{
184784865Sobrien  unw_rec_list *ptr = alloc_record (prologue);
184884865Sobrien  memset (&ptr->r.record.r.mask, 0, sizeof (ptr->r.record.r.mask));
184984865Sobrien  return ptr;
185084865Sobrien}
185184865Sobrien
185284865Sobrienstatic unw_rec_list *
185384865Sobrienoutput_prologue_gr (saved_mask, reg)
185484865Sobrien     unsigned int saved_mask;
185584865Sobrien     unsigned int reg;
185684865Sobrien{
185784865Sobrien  unw_rec_list *ptr = alloc_record (prologue_gr);
185884865Sobrien  memset (&ptr->r.record.r.mask, 0, sizeof (ptr->r.record.r.mask));
185984865Sobrien  ptr->r.record.r.grmask = saved_mask;
186084865Sobrien  ptr->r.record.r.grsave = reg;
186184865Sobrien  return ptr;
186284865Sobrien}
186384865Sobrien
186484865Sobrienstatic unw_rec_list *
186584865Sobrienoutput_body ()
186684865Sobrien{
186784865Sobrien  unw_rec_list *ptr = alloc_record (body);
186884865Sobrien  return ptr;
186984865Sobrien}
187084865Sobrien
187184865Sobrienstatic unw_rec_list *
187284865Sobrienoutput_mem_stack_f (size)
187384865Sobrien     unsigned int size;
187484865Sobrien{
187584865Sobrien  unw_rec_list *ptr = alloc_record (mem_stack_f);
187684865Sobrien  ptr->r.record.p.size = size;
187784865Sobrien  return ptr;
187884865Sobrien}
187984865Sobrien
188084865Sobrienstatic unw_rec_list *
188184865Sobrienoutput_mem_stack_v ()
188284865Sobrien{
188384865Sobrien  unw_rec_list *ptr = alloc_record (mem_stack_v);
188484865Sobrien  return ptr;
188584865Sobrien}
188684865Sobrien
188784865Sobrienstatic unw_rec_list *
188884865Sobrienoutput_psp_gr (gr)
188984865Sobrien     unsigned int gr;
189084865Sobrien{
189184865Sobrien  unw_rec_list *ptr = alloc_record (psp_gr);
1892218822Sdim  ptr->r.record.p.r.gr = gr;
189384865Sobrien  return ptr;
189484865Sobrien}
189584865Sobrien
189684865Sobrienstatic unw_rec_list *
189784865Sobrienoutput_psp_sprel (offset)
189884865Sobrien     unsigned int offset;
189984865Sobrien{
190084865Sobrien  unw_rec_list *ptr = alloc_record (psp_sprel);
1901218822Sdim  ptr->r.record.p.off.sp = offset / 4;
190284865Sobrien  return ptr;
190384865Sobrien}
190484865Sobrien
190584865Sobrienstatic unw_rec_list *
190684865Sobrienoutput_rp_when ()
190784865Sobrien{
190884865Sobrien  unw_rec_list *ptr = alloc_record (rp_when);
190984865Sobrien  return ptr;
191084865Sobrien}
191184865Sobrien
191284865Sobrienstatic unw_rec_list *
191384865Sobrienoutput_rp_gr (gr)
191484865Sobrien     unsigned int gr;
191584865Sobrien{
191684865Sobrien  unw_rec_list *ptr = alloc_record (rp_gr);
1917218822Sdim  ptr->r.record.p.r.gr = gr;
191884865Sobrien  return ptr;
191984865Sobrien}
192084865Sobrien
192184865Sobrienstatic unw_rec_list *
192284865Sobrienoutput_rp_br (br)
192384865Sobrien     unsigned int br;
192484865Sobrien{
192584865Sobrien  unw_rec_list *ptr = alloc_record (rp_br);
1926218822Sdim  ptr->r.record.p.r.br = br;
192784865Sobrien  return ptr;
192884865Sobrien}
192984865Sobrien
193084865Sobrienstatic unw_rec_list *
193184865Sobrienoutput_rp_psprel (offset)
193284865Sobrien     unsigned int offset;
193384865Sobrien{
193484865Sobrien  unw_rec_list *ptr = alloc_record (rp_psprel);
1935218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
193684865Sobrien  return ptr;
193784865Sobrien}
193884865Sobrien
193984865Sobrienstatic unw_rec_list *
194084865Sobrienoutput_rp_sprel (offset)
194184865Sobrien     unsigned int offset;
194284865Sobrien{
194384865Sobrien  unw_rec_list *ptr = alloc_record (rp_sprel);
1944218822Sdim  ptr->r.record.p.off.sp = offset / 4;
194584865Sobrien  return ptr;
194684865Sobrien}
194784865Sobrien
194884865Sobrienstatic unw_rec_list *
194984865Sobrienoutput_pfs_when ()
195084865Sobrien{
195184865Sobrien  unw_rec_list *ptr = alloc_record (pfs_when);
195284865Sobrien  return ptr;
195384865Sobrien}
195484865Sobrien
195584865Sobrienstatic unw_rec_list *
195684865Sobrienoutput_pfs_gr (gr)
195784865Sobrien     unsigned int gr;
195884865Sobrien{
195984865Sobrien  unw_rec_list *ptr = alloc_record (pfs_gr);
1960218822Sdim  ptr->r.record.p.r.gr = gr;
196184865Sobrien  return ptr;
196284865Sobrien}
196384865Sobrien
196484865Sobrienstatic unw_rec_list *
196584865Sobrienoutput_pfs_psprel (offset)
196684865Sobrien     unsigned int offset;
196784865Sobrien{
196884865Sobrien  unw_rec_list *ptr = alloc_record (pfs_psprel);
1969218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
197084865Sobrien  return ptr;
197184865Sobrien}
197284865Sobrien
197384865Sobrienstatic unw_rec_list *
197484865Sobrienoutput_pfs_sprel (offset)
197584865Sobrien     unsigned int offset;
197684865Sobrien{
197784865Sobrien  unw_rec_list *ptr = alloc_record (pfs_sprel);
1978218822Sdim  ptr->r.record.p.off.sp = offset / 4;
197984865Sobrien  return ptr;
198084865Sobrien}
198184865Sobrien
198284865Sobrienstatic unw_rec_list *
198384865Sobrienoutput_preds_when ()
198484865Sobrien{
198584865Sobrien  unw_rec_list *ptr = alloc_record (preds_when);
198684865Sobrien  return ptr;
198784865Sobrien}
198884865Sobrien
198984865Sobrienstatic unw_rec_list *
199084865Sobrienoutput_preds_gr (gr)
199184865Sobrien     unsigned int gr;
199284865Sobrien{
199384865Sobrien  unw_rec_list *ptr = alloc_record (preds_gr);
1994218822Sdim  ptr->r.record.p.r.gr = gr;
199584865Sobrien  return ptr;
199684865Sobrien}
199784865Sobrien
199884865Sobrienstatic unw_rec_list *
199984865Sobrienoutput_preds_psprel (offset)
200084865Sobrien     unsigned int offset;
200184865Sobrien{
200284865Sobrien  unw_rec_list *ptr = alloc_record (preds_psprel);
2003218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
200484865Sobrien  return ptr;
200584865Sobrien}
200684865Sobrien
200784865Sobrienstatic unw_rec_list *
200884865Sobrienoutput_preds_sprel (offset)
200984865Sobrien     unsigned int offset;
201084865Sobrien{
201184865Sobrien  unw_rec_list *ptr = alloc_record (preds_sprel);
2012218822Sdim  ptr->r.record.p.off.sp = offset / 4;
201384865Sobrien  return ptr;
201484865Sobrien}
201584865Sobrien
201684865Sobrienstatic unw_rec_list *
201784865Sobrienoutput_fr_mem (mask)
201884865Sobrien     unsigned int mask;
201984865Sobrien{
202084865Sobrien  unw_rec_list *ptr = alloc_record (fr_mem);
2021218822Sdim  unw_rec_list *cur = ptr;
2022218822Sdim
2023218822Sdim  ptr->r.record.p.frmask = mask;
2024218822Sdim  unwind.pending_saves = &ptr->r.record.p;
2025218822Sdim  for (;;)
2026218822Sdim    {
2027218822Sdim      unw_rec_list *prev = cur;
2028218822Sdim
2029218822Sdim      /* Clear least significant set bit.  */
2030218822Sdim      mask &= ~(mask & (~mask + 1));
2031218822Sdim      if (!mask)
2032218822Sdim	return ptr;
2033218822Sdim      cur = alloc_record (fr_mem);
2034218822Sdim      cur->r.record.p.frmask = mask;
2035218822Sdim      /* Retain only least significant bit.  */
2036218822Sdim      prev->r.record.p.frmask ^= mask;
2037218822Sdim      prev->r.record.p.next = cur;
2038218822Sdim    }
203984865Sobrien}
204084865Sobrien
204184865Sobrienstatic unw_rec_list *
204284865Sobrienoutput_frgr_mem (gr_mask, fr_mask)
204384865Sobrien     unsigned int gr_mask;
204484865Sobrien     unsigned int fr_mask;
204584865Sobrien{
204684865Sobrien  unw_rec_list *ptr = alloc_record (frgr_mem);
2047218822Sdim  unw_rec_list *cur = ptr;
2048218822Sdim
2049218822Sdim  unwind.pending_saves = &cur->r.record.p;
2050218822Sdim  cur->r.record.p.frmask = fr_mask;
2051218822Sdim  while (fr_mask)
2052218822Sdim    {
2053218822Sdim      unw_rec_list *prev = cur;
2054218822Sdim
2055218822Sdim      /* Clear least significant set bit.  */
2056218822Sdim      fr_mask &= ~(fr_mask & (~fr_mask + 1));
2057218822Sdim      if (!gr_mask && !fr_mask)
2058218822Sdim	return ptr;
2059218822Sdim      cur = alloc_record (frgr_mem);
2060218822Sdim      cur->r.record.p.frmask = fr_mask;
2061218822Sdim      /* Retain only least significant bit.  */
2062218822Sdim      prev->r.record.p.frmask ^= fr_mask;
2063218822Sdim      prev->r.record.p.next = cur;
2064218822Sdim    }
2065218822Sdim  cur->r.record.p.grmask = gr_mask;
2066218822Sdim  for (;;)
2067218822Sdim    {
2068218822Sdim      unw_rec_list *prev = cur;
2069218822Sdim
2070218822Sdim      /* Clear least significant set bit.  */
2071218822Sdim      gr_mask &= ~(gr_mask & (~gr_mask + 1));
2072218822Sdim      if (!gr_mask)
2073218822Sdim	return ptr;
2074218822Sdim      cur = alloc_record (frgr_mem);
2075218822Sdim      cur->r.record.p.grmask = gr_mask;
2076218822Sdim      /* Retain only least significant bit.  */
2077218822Sdim      prev->r.record.p.grmask ^= gr_mask;
2078218822Sdim      prev->r.record.p.next = cur;
2079218822Sdim    }
208084865Sobrien}
208184865Sobrien
208284865Sobrienstatic unw_rec_list *
208384865Sobrienoutput_gr_gr (mask, reg)
208484865Sobrien     unsigned int mask;
208584865Sobrien     unsigned int reg;
208684865Sobrien{
208784865Sobrien  unw_rec_list *ptr = alloc_record (gr_gr);
2088218822Sdim  unw_rec_list *cur = ptr;
2089218822Sdim
209084865Sobrien  ptr->r.record.p.grmask = mask;
2091218822Sdim  ptr->r.record.p.r.gr = reg;
2092218822Sdim  unwind.pending_saves = &ptr->r.record.p;
2093218822Sdim  for (;;)
2094218822Sdim    {
2095218822Sdim      unw_rec_list *prev = cur;
2096218822Sdim
2097218822Sdim      /* Clear least significant set bit.  */
2098218822Sdim      mask &= ~(mask & (~mask + 1));
2099218822Sdim      if (!mask)
2100218822Sdim	return ptr;
2101218822Sdim      cur = alloc_record (gr_gr);
2102218822Sdim      cur->r.record.p.grmask = mask;
2103218822Sdim      /* Indicate this record shouldn't be output.  */
2104218822Sdim      cur->r.record.p.r.gr = REG_NUM;
2105218822Sdim      /* Retain only least significant bit.  */
2106218822Sdim      prev->r.record.p.grmask ^= mask;
2107218822Sdim      prev->r.record.p.next = cur;
2108218822Sdim    }
210984865Sobrien}
211084865Sobrien
211184865Sobrienstatic unw_rec_list *
211284865Sobrienoutput_gr_mem (mask)
211384865Sobrien     unsigned int mask;
211484865Sobrien{
211584865Sobrien  unw_rec_list *ptr = alloc_record (gr_mem);
2116218822Sdim  unw_rec_list *cur = ptr;
2117218822Sdim
2118218822Sdim  ptr->r.record.p.grmask = mask;
2119218822Sdim  unwind.pending_saves = &ptr->r.record.p;
2120218822Sdim  for (;;)
2121218822Sdim    {
2122218822Sdim      unw_rec_list *prev = cur;
2123218822Sdim
2124218822Sdim      /* Clear least significant set bit.  */
2125218822Sdim      mask &= ~(mask & (~mask + 1));
2126218822Sdim      if (!mask)
2127218822Sdim	return ptr;
2128218822Sdim      cur = alloc_record (gr_mem);
2129218822Sdim      cur->r.record.p.grmask = mask;
2130218822Sdim      /* Retain only least significant bit.  */
2131218822Sdim      prev->r.record.p.grmask ^= mask;
2132218822Sdim      prev->r.record.p.next = cur;
2133218822Sdim    }
213484865Sobrien}
213584865Sobrien
213684865Sobrienstatic unw_rec_list *
213784865Sobrienoutput_br_mem (unsigned int mask)
213884865Sobrien{
213984865Sobrien  unw_rec_list *ptr = alloc_record (br_mem);
2140218822Sdim  unw_rec_list *cur = ptr;
2141218822Sdim
214284865Sobrien  ptr->r.record.p.brmask = mask;
2143218822Sdim  unwind.pending_saves = &ptr->r.record.p;
2144218822Sdim  for (;;)
2145218822Sdim    {
2146218822Sdim      unw_rec_list *prev = cur;
2147218822Sdim
2148218822Sdim      /* Clear least significant set bit.  */
2149218822Sdim      mask &= ~(mask & (~mask + 1));
2150218822Sdim      if (!mask)
2151218822Sdim	return ptr;
2152218822Sdim      cur = alloc_record (br_mem);
2153218822Sdim      cur->r.record.p.brmask = mask;
2154218822Sdim      /* Retain only least significant bit.  */
2155218822Sdim      prev->r.record.p.brmask ^= mask;
2156218822Sdim      prev->r.record.p.next = cur;
2157218822Sdim    }
215884865Sobrien}
215984865Sobrien
216084865Sobrienstatic unw_rec_list *
2161218822Sdimoutput_br_gr (mask, reg)
2162218822Sdim     unsigned int mask;
216384865Sobrien     unsigned int reg;
216484865Sobrien{
216584865Sobrien  unw_rec_list *ptr = alloc_record (br_gr);
2166218822Sdim  unw_rec_list *cur = ptr;
2167218822Sdim
2168218822Sdim  ptr->r.record.p.brmask = mask;
2169218822Sdim  ptr->r.record.p.r.gr = reg;
2170218822Sdim  unwind.pending_saves = &ptr->r.record.p;
2171218822Sdim  for (;;)
2172218822Sdim    {
2173218822Sdim      unw_rec_list *prev = cur;
2174218822Sdim
2175218822Sdim      /* Clear least significant set bit.  */
2176218822Sdim      mask &= ~(mask & (~mask + 1));
2177218822Sdim      if (!mask)
2178218822Sdim	return ptr;
2179218822Sdim      cur = alloc_record (br_gr);
2180218822Sdim      cur->r.record.p.brmask = mask;
2181218822Sdim      /* Indicate this record shouldn't be output.  */
2182218822Sdim      cur->r.record.p.r.gr = REG_NUM;
2183218822Sdim      /* Retain only least significant bit.  */
2184218822Sdim      prev->r.record.p.brmask ^= mask;
2185218822Sdim      prev->r.record.p.next = cur;
2186218822Sdim    }
218784865Sobrien}
218884865Sobrien
218984865Sobrienstatic unw_rec_list *
219084865Sobrienoutput_spill_base (offset)
219184865Sobrien     unsigned int offset;
219284865Sobrien{
219384865Sobrien  unw_rec_list *ptr = alloc_record (spill_base);
2194218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
219584865Sobrien  return ptr;
219684865Sobrien}
219784865Sobrien
219884865Sobrienstatic unw_rec_list *
219984865Sobrienoutput_unat_when ()
220084865Sobrien{
220184865Sobrien  unw_rec_list *ptr = alloc_record (unat_when);
220284865Sobrien  return ptr;
220384865Sobrien}
220484865Sobrien
220584865Sobrienstatic unw_rec_list *
220684865Sobrienoutput_unat_gr (gr)
220784865Sobrien     unsigned int gr;
220884865Sobrien{
220984865Sobrien  unw_rec_list *ptr = alloc_record (unat_gr);
2210218822Sdim  ptr->r.record.p.r.gr = gr;
221184865Sobrien  return ptr;
221284865Sobrien}
221384865Sobrien
221484865Sobrienstatic unw_rec_list *
221584865Sobrienoutput_unat_psprel (offset)
221684865Sobrien     unsigned int offset;
221784865Sobrien{
221884865Sobrien  unw_rec_list *ptr = alloc_record (unat_psprel);
2219218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
222084865Sobrien  return ptr;
222184865Sobrien}
222284865Sobrien
222384865Sobrienstatic unw_rec_list *
222484865Sobrienoutput_unat_sprel (offset)
222584865Sobrien     unsigned int offset;
222684865Sobrien{
222784865Sobrien  unw_rec_list *ptr = alloc_record (unat_sprel);
2228218822Sdim  ptr->r.record.p.off.sp = offset / 4;
222984865Sobrien  return ptr;
223084865Sobrien}
223184865Sobrien
223284865Sobrienstatic unw_rec_list *
223384865Sobrienoutput_lc_when ()
223484865Sobrien{
223584865Sobrien  unw_rec_list *ptr = alloc_record (lc_when);
223684865Sobrien  return ptr;
223784865Sobrien}
223884865Sobrien
223984865Sobrienstatic unw_rec_list *
224084865Sobrienoutput_lc_gr (gr)
224184865Sobrien     unsigned int gr;
224284865Sobrien{
224384865Sobrien  unw_rec_list *ptr = alloc_record (lc_gr);
2244218822Sdim  ptr->r.record.p.r.gr = gr;
224584865Sobrien  return ptr;
224684865Sobrien}
224784865Sobrien
224884865Sobrienstatic unw_rec_list *
224984865Sobrienoutput_lc_psprel (offset)
225084865Sobrien     unsigned int offset;
225184865Sobrien{
225284865Sobrien  unw_rec_list *ptr = alloc_record (lc_psprel);
2253218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
225484865Sobrien  return ptr;
225584865Sobrien}
225684865Sobrien
225784865Sobrienstatic unw_rec_list *
225884865Sobrienoutput_lc_sprel (offset)
225984865Sobrien     unsigned int offset;
226084865Sobrien{
226184865Sobrien  unw_rec_list *ptr = alloc_record (lc_sprel);
2262218822Sdim  ptr->r.record.p.off.sp = offset / 4;
226384865Sobrien  return ptr;
226484865Sobrien}
226584865Sobrien
226684865Sobrienstatic unw_rec_list *
226784865Sobrienoutput_fpsr_when ()
226884865Sobrien{
226984865Sobrien  unw_rec_list *ptr = alloc_record (fpsr_when);
227084865Sobrien  return ptr;
227184865Sobrien}
227284865Sobrien
227384865Sobrienstatic unw_rec_list *
227484865Sobrienoutput_fpsr_gr (gr)
227584865Sobrien     unsigned int gr;
227684865Sobrien{
227784865Sobrien  unw_rec_list *ptr = alloc_record (fpsr_gr);
2278218822Sdim  ptr->r.record.p.r.gr = gr;
227984865Sobrien  return ptr;
228084865Sobrien}
228184865Sobrien
228284865Sobrienstatic unw_rec_list *
228384865Sobrienoutput_fpsr_psprel (offset)
228484865Sobrien     unsigned int offset;
228584865Sobrien{
228684865Sobrien  unw_rec_list *ptr = alloc_record (fpsr_psprel);
2287218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
228884865Sobrien  return ptr;
228984865Sobrien}
229084865Sobrien
229184865Sobrienstatic unw_rec_list *
229284865Sobrienoutput_fpsr_sprel (offset)
229384865Sobrien     unsigned int offset;
229484865Sobrien{
229584865Sobrien  unw_rec_list *ptr = alloc_record (fpsr_sprel);
2296218822Sdim  ptr->r.record.p.off.sp = offset / 4;
229784865Sobrien  return ptr;
229884865Sobrien}
229984865Sobrien
230084865Sobrienstatic unw_rec_list *
230184865Sobrienoutput_priunat_when_gr ()
230284865Sobrien{
230384865Sobrien  unw_rec_list *ptr = alloc_record (priunat_when_gr);
230484865Sobrien  return ptr;
230584865Sobrien}
230684865Sobrien
230784865Sobrienstatic unw_rec_list *
230884865Sobrienoutput_priunat_when_mem ()
230984865Sobrien{
231084865Sobrien  unw_rec_list *ptr = alloc_record (priunat_when_mem);
231184865Sobrien  return ptr;
231284865Sobrien}
231384865Sobrien
231484865Sobrienstatic unw_rec_list *
231584865Sobrienoutput_priunat_gr (gr)
231684865Sobrien     unsigned int gr;
231784865Sobrien{
231884865Sobrien  unw_rec_list *ptr = alloc_record (priunat_gr);
2319218822Sdim  ptr->r.record.p.r.gr = gr;
232084865Sobrien  return ptr;
232184865Sobrien}
232284865Sobrien
232384865Sobrienstatic unw_rec_list *
232484865Sobrienoutput_priunat_psprel (offset)
232584865Sobrien     unsigned int offset;
232684865Sobrien{
232784865Sobrien  unw_rec_list *ptr = alloc_record (priunat_psprel);
2328218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
232984865Sobrien  return ptr;
233084865Sobrien}
233184865Sobrien
233284865Sobrienstatic unw_rec_list *
233384865Sobrienoutput_priunat_sprel (offset)
233484865Sobrien     unsigned int offset;
233584865Sobrien{
233684865Sobrien  unw_rec_list *ptr = alloc_record (priunat_sprel);
2337218822Sdim  ptr->r.record.p.off.sp = offset / 4;
233884865Sobrien  return ptr;
233984865Sobrien}
234084865Sobrien
234184865Sobrienstatic unw_rec_list *
234284865Sobrienoutput_bsp_when ()
234384865Sobrien{
234484865Sobrien  unw_rec_list *ptr = alloc_record (bsp_when);
234584865Sobrien  return ptr;
234684865Sobrien}
234784865Sobrien
234884865Sobrienstatic unw_rec_list *
234984865Sobrienoutput_bsp_gr (gr)
235084865Sobrien     unsigned int gr;
235184865Sobrien{
235284865Sobrien  unw_rec_list *ptr = alloc_record (bsp_gr);
2353218822Sdim  ptr->r.record.p.r.gr = gr;
235484865Sobrien  return ptr;
235584865Sobrien}
235684865Sobrien
235784865Sobrienstatic unw_rec_list *
235884865Sobrienoutput_bsp_psprel (offset)
235984865Sobrien     unsigned int offset;
236084865Sobrien{
236184865Sobrien  unw_rec_list *ptr = alloc_record (bsp_psprel);
2362218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
236384865Sobrien  return ptr;
236484865Sobrien}
236584865Sobrien
236684865Sobrienstatic unw_rec_list *
236784865Sobrienoutput_bsp_sprel (offset)
236884865Sobrien     unsigned int offset;
236984865Sobrien{
237084865Sobrien  unw_rec_list *ptr = alloc_record (bsp_sprel);
2371218822Sdim  ptr->r.record.p.off.sp = offset / 4;
237284865Sobrien  return ptr;
237384865Sobrien}
237484865Sobrien
237584865Sobrienstatic unw_rec_list *
237684865Sobrienoutput_bspstore_when ()
237784865Sobrien{
237884865Sobrien  unw_rec_list *ptr = alloc_record (bspstore_when);
237984865Sobrien  return ptr;
238084865Sobrien}
238184865Sobrien
238284865Sobrienstatic unw_rec_list *
238384865Sobrienoutput_bspstore_gr (gr)
238484865Sobrien     unsigned int gr;
238584865Sobrien{
238684865Sobrien  unw_rec_list *ptr = alloc_record (bspstore_gr);
2387218822Sdim  ptr->r.record.p.r.gr = gr;
238884865Sobrien  return ptr;
238984865Sobrien}
239084865Sobrien
239184865Sobrienstatic unw_rec_list *
239284865Sobrienoutput_bspstore_psprel (offset)
239384865Sobrien     unsigned int offset;
239484865Sobrien{
239584865Sobrien  unw_rec_list *ptr = alloc_record (bspstore_psprel);
2396218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
239784865Sobrien  return ptr;
239884865Sobrien}
239984865Sobrien
240084865Sobrienstatic unw_rec_list *
240184865Sobrienoutput_bspstore_sprel (offset)
240284865Sobrien     unsigned int offset;
240384865Sobrien{
240484865Sobrien  unw_rec_list *ptr = alloc_record (bspstore_sprel);
2405218822Sdim  ptr->r.record.p.off.sp = offset / 4;
240684865Sobrien  return ptr;
240784865Sobrien}
240884865Sobrien
240984865Sobrienstatic unw_rec_list *
241084865Sobrienoutput_rnat_when ()
241184865Sobrien{
241284865Sobrien  unw_rec_list *ptr = alloc_record (rnat_when);
241384865Sobrien  return ptr;
241484865Sobrien}
241584865Sobrien
241684865Sobrienstatic unw_rec_list *
241784865Sobrienoutput_rnat_gr (gr)
241884865Sobrien     unsigned int gr;
241984865Sobrien{
242084865Sobrien  unw_rec_list *ptr = alloc_record (rnat_gr);
2421218822Sdim  ptr->r.record.p.r.gr = gr;
242284865Sobrien  return ptr;
242384865Sobrien}
242484865Sobrien
242584865Sobrienstatic unw_rec_list *
242684865Sobrienoutput_rnat_psprel (offset)
242784865Sobrien     unsigned int offset;
242884865Sobrien{
242984865Sobrien  unw_rec_list *ptr = alloc_record (rnat_psprel);
2430218822Sdim  ptr->r.record.p.off.psp = ENCODED_PSP_OFFSET (offset);
243184865Sobrien  return ptr;
243284865Sobrien}
243384865Sobrien
243484865Sobrienstatic unw_rec_list *
243584865Sobrienoutput_rnat_sprel (offset)
243684865Sobrien     unsigned int offset;
243784865Sobrien{
243884865Sobrien  unw_rec_list *ptr = alloc_record (rnat_sprel);
2439218822Sdim  ptr->r.record.p.off.sp = offset / 4;
244084865Sobrien  return ptr;
244184865Sobrien}
244284865Sobrien
244384865Sobrienstatic unw_rec_list *
244484865Sobrienoutput_unwabi (abi, context)
244584865Sobrien     unsigned long abi;
244684865Sobrien     unsigned long context;
244784865Sobrien{
244884865Sobrien  unw_rec_list *ptr = alloc_record (unwabi);
244984865Sobrien  ptr->r.record.p.abi = abi;
245084865Sobrien  ptr->r.record.p.context = context;
245184865Sobrien  return ptr;
245284865Sobrien}
245384865Sobrien
245484865Sobrienstatic unw_rec_list *
245584865Sobrienoutput_epilogue (unsigned long ecount)
245684865Sobrien{
245784865Sobrien  unw_rec_list *ptr = alloc_record (epilogue);
245884865Sobrien  ptr->r.record.b.ecount = ecount;
245984865Sobrien  return ptr;
246084865Sobrien}
246184865Sobrien
246284865Sobrienstatic unw_rec_list *
246384865Sobrienoutput_label_state (unsigned long label)
246484865Sobrien{
246584865Sobrien  unw_rec_list *ptr = alloc_record (label_state);
246684865Sobrien  ptr->r.record.b.label = label;
246784865Sobrien  return ptr;
246884865Sobrien}
246984865Sobrien
247084865Sobrienstatic unw_rec_list *
247184865Sobrienoutput_copy_state (unsigned long label)
247284865Sobrien{
247384865Sobrien  unw_rec_list *ptr = alloc_record (copy_state);
247484865Sobrien  ptr->r.record.b.label = label;
247584865Sobrien  return ptr;
247684865Sobrien}
247784865Sobrien
247884865Sobrienstatic unw_rec_list *
2479218822Sdimoutput_spill_psprel (ab, reg, offset, predicate)
248084865Sobrien     unsigned int ab;
248184865Sobrien     unsigned int reg;
248284865Sobrien     unsigned int offset;
248384865Sobrien     unsigned int predicate;
248484865Sobrien{
2485218822Sdim  unw_rec_list *ptr = alloc_record (predicate ? spill_psprel_p : spill_psprel);
248684865Sobrien  ptr->r.record.x.ab = ab;
248784865Sobrien  ptr->r.record.x.reg = reg;
2488218822Sdim  ptr->r.record.x.where.pspoff = ENCODED_PSP_OFFSET (offset);
248984865Sobrien  ptr->r.record.x.qp = predicate;
249084865Sobrien  return ptr;
249184865Sobrien}
249284865Sobrien
249384865Sobrienstatic unw_rec_list *
2494218822Sdimoutput_spill_sprel (ab, reg, offset, predicate)
249584865Sobrien     unsigned int ab;
249684865Sobrien     unsigned int reg;
249784865Sobrien     unsigned int offset;
249884865Sobrien     unsigned int predicate;
249984865Sobrien{
2500218822Sdim  unw_rec_list *ptr = alloc_record (predicate ? spill_sprel_p : spill_sprel);
250184865Sobrien  ptr->r.record.x.ab = ab;
250284865Sobrien  ptr->r.record.x.reg = reg;
2503218822Sdim  ptr->r.record.x.where.spoff = offset / 4;
250484865Sobrien  ptr->r.record.x.qp = predicate;
250584865Sobrien  return ptr;
250684865Sobrien}
250784865Sobrien
250884865Sobrienstatic unw_rec_list *
2509218822Sdimoutput_spill_reg (ab, reg, targ_reg, xy, predicate)
251084865Sobrien     unsigned int ab;
251184865Sobrien     unsigned int reg;
251284865Sobrien     unsigned int targ_reg;
251384865Sobrien     unsigned int xy;
251484865Sobrien     unsigned int predicate;
251584865Sobrien{
2516218822Sdim  unw_rec_list *ptr = alloc_record (predicate ? spill_reg_p : spill_reg);
251784865Sobrien  ptr->r.record.x.ab = ab;
251884865Sobrien  ptr->r.record.x.reg = reg;
2519218822Sdim  ptr->r.record.x.where.reg = targ_reg;
252084865Sobrien  ptr->r.record.x.xy = xy;
252184865Sobrien  ptr->r.record.x.qp = predicate;
252284865Sobrien  return ptr;
252384865Sobrien}
252484865Sobrien
252584865Sobrien/* Given a unw_rec_list process the correct format with the
252684865Sobrien   specified function.  */
252784865Sobrien
252884865Sobrienstatic void
252984865Sobrienprocess_one_record (ptr, f)
253084865Sobrien     unw_rec_list *ptr;
253184865Sobrien     vbyte_func f;
253284865Sobrien{
2533218822Sdim  unsigned int fr_mask, gr_mask;
253484865Sobrien
253584865Sobrien  switch (ptr->r.type)
253684865Sobrien    {
2537130561Sobrien      /* This is a dummy record that takes up no space in the output.  */
2538130561Sobrien    case endp:
2539130561Sobrien      break;
2540130561Sobrien
254184865Sobrien    case gr_mem:
254284865Sobrien    case fr_mem:
254384865Sobrien    case br_mem:
254484865Sobrien    case frgr_mem:
254584865Sobrien      /* These are taken care of by prologue/prologue_gr.  */
254684865Sobrien      break;
254784865Sobrien
254884865Sobrien    case prologue_gr:
254984865Sobrien    case prologue:
255084865Sobrien      if (ptr->r.type == prologue_gr)
255184865Sobrien	output_R2_format (f, ptr->r.record.r.grmask,
255284865Sobrien			  ptr->r.record.r.grsave, ptr->r.record.r.rlen);
255384865Sobrien      else
255484865Sobrien	output_R1_format (f, ptr->r.type, ptr->r.record.r.rlen);
255584865Sobrien
255684865Sobrien      /* Output descriptor(s) for union of register spills (if any).  */
255784865Sobrien      gr_mask = ptr->r.record.r.mask.gr_mem;
255884865Sobrien      fr_mask = ptr->r.record.r.mask.fr_mem;
255984865Sobrien      if (fr_mask)
256084865Sobrien	{
256184865Sobrien	  if ((fr_mask & ~0xfUL) == 0)
256284865Sobrien	    output_P6_format (f, fr_mem, fr_mask);
256384865Sobrien	  else
256484865Sobrien	    {
256584865Sobrien	      output_P5_format (f, gr_mask, fr_mask);
256684865Sobrien	      gr_mask = 0;
256784865Sobrien	    }
256884865Sobrien	}
256984865Sobrien      if (gr_mask)
257084865Sobrien	output_P6_format (f, gr_mem, gr_mask);
257184865Sobrien      if (ptr->r.record.r.mask.br_mem)
257284865Sobrien	output_P1_format (f, ptr->r.record.r.mask.br_mem);
257384865Sobrien
257484865Sobrien      /* output imask descriptor if necessary:  */
257584865Sobrien      if (ptr->r.record.r.mask.i)
257684865Sobrien	output_P4_format (f, ptr->r.record.r.mask.i,
257784865Sobrien			  ptr->r.record.r.imask_size);
257884865Sobrien      break;
257984865Sobrien
258084865Sobrien    case body:
258184865Sobrien      output_R1_format (f, ptr->r.type, ptr->r.record.r.rlen);
258284865Sobrien      break;
258384865Sobrien    case mem_stack_f:
258484865Sobrien    case mem_stack_v:
258584865Sobrien      output_P7_format (f, ptr->r.type, ptr->r.record.p.t,
258684865Sobrien			ptr->r.record.p.size);
258784865Sobrien      break;
258884865Sobrien    case psp_gr:
258984865Sobrien    case rp_gr:
259084865Sobrien    case pfs_gr:
259184865Sobrien    case preds_gr:
259284865Sobrien    case unat_gr:
259384865Sobrien    case lc_gr:
259484865Sobrien    case fpsr_gr:
259584865Sobrien    case priunat_gr:
259684865Sobrien    case bsp_gr:
259784865Sobrien    case bspstore_gr:
259884865Sobrien    case rnat_gr:
2599218822Sdim      output_P3_format (f, ptr->r.type, ptr->r.record.p.r.gr);
260084865Sobrien      break;
260184865Sobrien    case rp_br:
2602218822Sdim      output_P3_format (f, rp_br, ptr->r.record.p.r.br);
260384865Sobrien      break;
260484865Sobrien    case psp_sprel:
2605218822Sdim      output_P7_format (f, psp_sprel, ptr->r.record.p.off.sp, 0);
260684865Sobrien      break;
260784865Sobrien    case rp_when:
260884865Sobrien    case pfs_when:
260984865Sobrien    case preds_when:
261084865Sobrien    case unat_when:
261184865Sobrien    case lc_when:
261284865Sobrien    case fpsr_when:
261384865Sobrien      output_P7_format (f, ptr->r.type, ptr->r.record.p.t, 0);
261484865Sobrien      break;
261584865Sobrien    case rp_psprel:
261684865Sobrien    case pfs_psprel:
261784865Sobrien    case preds_psprel:
261884865Sobrien    case unat_psprel:
261984865Sobrien    case lc_psprel:
262084865Sobrien    case fpsr_psprel:
262184865Sobrien    case spill_base:
2622218822Sdim      output_P7_format (f, ptr->r.type, ptr->r.record.p.off.psp, 0);
262384865Sobrien      break;
262484865Sobrien    case rp_sprel:
262584865Sobrien    case pfs_sprel:
262684865Sobrien    case preds_sprel:
262784865Sobrien    case unat_sprel:
262884865Sobrien    case lc_sprel:
262984865Sobrien    case fpsr_sprel:
263084865Sobrien    case priunat_sprel:
263184865Sobrien    case bsp_sprel:
263284865Sobrien    case bspstore_sprel:
263384865Sobrien    case rnat_sprel:
2634218822Sdim      output_P8_format (f, ptr->r.type, ptr->r.record.p.off.sp);
263584865Sobrien      break;
263684865Sobrien    case gr_gr:
2637218822Sdim      if (ptr->r.record.p.r.gr < REG_NUM)
2638218822Sdim	{
2639218822Sdim	  const unw_rec_list *cur = ptr;
2640218822Sdim
2641218822Sdim	  gr_mask = cur->r.record.p.grmask;
2642218822Sdim	  while ((cur = cur->r.record.p.next) != NULL)
2643218822Sdim	    gr_mask |= cur->r.record.p.grmask;
2644218822Sdim	  output_P9_format (f, gr_mask, ptr->r.record.p.r.gr);
2645218822Sdim	}
264684865Sobrien      break;
264784865Sobrien    case br_gr:
2648218822Sdim      if (ptr->r.record.p.r.gr < REG_NUM)
2649218822Sdim	{
2650218822Sdim	  const unw_rec_list *cur = ptr;
2651218822Sdim
2652218822Sdim	  gr_mask = cur->r.record.p.brmask;
2653218822Sdim	  while ((cur = cur->r.record.p.next) != NULL)
2654218822Sdim	    gr_mask |= cur->r.record.p.brmask;
2655218822Sdim	  output_P2_format (f, gr_mask, ptr->r.record.p.r.gr);
2656218822Sdim	}
265784865Sobrien      break;
265884865Sobrien    case spill_mask:
265984865Sobrien      as_bad ("spill_mask record unimplemented.");
266084865Sobrien      break;
266184865Sobrien    case priunat_when_gr:
266284865Sobrien    case priunat_when_mem:
266384865Sobrien    case bsp_when:
266484865Sobrien    case bspstore_when:
266584865Sobrien    case rnat_when:
266684865Sobrien      output_P8_format (f, ptr->r.type, ptr->r.record.p.t);
266784865Sobrien      break;
266884865Sobrien    case priunat_psprel:
266984865Sobrien    case bsp_psprel:
267084865Sobrien    case bspstore_psprel:
267184865Sobrien    case rnat_psprel:
2672218822Sdim      output_P8_format (f, ptr->r.type, ptr->r.record.p.off.psp);
267384865Sobrien      break;
267484865Sobrien    case unwabi:
267584865Sobrien      output_P10_format (f, ptr->r.record.p.abi, ptr->r.record.p.context);
267684865Sobrien      break;
267784865Sobrien    case epilogue:
267884865Sobrien      output_B3_format (f, ptr->r.record.b.ecount, ptr->r.record.b.t);
267984865Sobrien      break;
268084865Sobrien    case label_state:
268184865Sobrien    case copy_state:
268284865Sobrien      output_B4_format (f, ptr->r.type, ptr->r.record.b.label);
268384865Sobrien      break;
268484865Sobrien    case spill_psprel:
268584865Sobrien      output_X1_format (f, ptr->r.type, ptr->r.record.x.ab,
268684865Sobrien			ptr->r.record.x.reg, ptr->r.record.x.t,
2687218822Sdim			ptr->r.record.x.where.pspoff);
268884865Sobrien      break;
268984865Sobrien    case spill_sprel:
269084865Sobrien      output_X1_format (f, ptr->r.type, ptr->r.record.x.ab,
269184865Sobrien			ptr->r.record.x.reg, ptr->r.record.x.t,
2692218822Sdim			ptr->r.record.x.where.spoff);
269384865Sobrien      break;
269484865Sobrien    case spill_reg:
269584865Sobrien      output_X2_format (f, ptr->r.record.x.ab, ptr->r.record.x.reg,
269684865Sobrien			ptr->r.record.x.xy >> 1, ptr->r.record.x.xy,
2697218822Sdim			ptr->r.record.x.where.reg, ptr->r.record.x.t);
269884865Sobrien      break;
269984865Sobrien    case spill_psprel_p:
270084865Sobrien      output_X3_format (f, ptr->r.type, ptr->r.record.x.qp,
270184865Sobrien			ptr->r.record.x.ab, ptr->r.record.x.reg,
2702218822Sdim			ptr->r.record.x.t, ptr->r.record.x.where.pspoff);
270384865Sobrien      break;
270484865Sobrien    case spill_sprel_p:
270584865Sobrien      output_X3_format (f, ptr->r.type, ptr->r.record.x.qp,
270684865Sobrien			ptr->r.record.x.ab, ptr->r.record.x.reg,
2707218822Sdim			ptr->r.record.x.t, ptr->r.record.x.where.spoff);
270884865Sobrien      break;
270984865Sobrien    case spill_reg_p:
271084865Sobrien      output_X4_format (f, ptr->r.record.x.qp, ptr->r.record.x.ab,
271184865Sobrien			ptr->r.record.x.reg, ptr->r.record.x.xy >> 1,
2712218822Sdim			ptr->r.record.x.xy, ptr->r.record.x.where.reg,
271384865Sobrien			ptr->r.record.x.t);
271484865Sobrien      break;
271584865Sobrien    default:
271684865Sobrien      as_bad ("record_type_not_valid");
271784865Sobrien      break;
271884865Sobrien    }
271984865Sobrien}
272084865Sobrien
272184865Sobrien/* Given a unw_rec_list list, process all the records with
272284865Sobrien   the specified function.  */
272384865Sobrienstatic void
272484865Sobrienprocess_unw_records (list, f)
272584865Sobrien     unw_rec_list *list;
272684865Sobrien     vbyte_func f;
272784865Sobrien{
272884865Sobrien  unw_rec_list *ptr;
272984865Sobrien  for (ptr = list; ptr; ptr = ptr->next)
273084865Sobrien    process_one_record (ptr, f);
273184865Sobrien}
273284865Sobrien
273384865Sobrien/* Determine the size of a record list in bytes.  */
273484865Sobrienstatic int
273584865Sobriencalc_record_size (list)
273684865Sobrien     unw_rec_list *list;
273784865Sobrien{
273884865Sobrien  vbyte_count = 0;
273984865Sobrien  process_unw_records (list, count_output);
274084865Sobrien  return vbyte_count;
274184865Sobrien}
274284865Sobrien
2743218822Sdim/* Return the number of bits set in the input value.
2744218822Sdim   Perhaps this has a better place...  */
2745218822Sdim#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
2746218822Sdim# define popcount __builtin_popcount
2747218822Sdim#else
2748218822Sdimstatic int
2749218822Sdimpopcount (unsigned x)
2750218822Sdim{
2751218822Sdim  static const unsigned char popcnt[16] =
2752218822Sdim    {
2753218822Sdim      0, 1, 1, 2,
2754218822Sdim      1, 2, 2, 3,
2755218822Sdim      1, 2, 2, 3,
2756218822Sdim      2, 3, 3, 4
2757218822Sdim    };
2758218822Sdim
2759218822Sdim  if (x < NELEMS (popcnt))
2760218822Sdim    return popcnt[x];
2761218822Sdim  return popcnt[x % NELEMS (popcnt)] + popcount (x / NELEMS (popcnt));
2762218822Sdim}
2763218822Sdim#endif
2764218822Sdim
276584865Sobrien/* Update IMASK bitmask to reflect the fact that one or more registers
276684865Sobrien   of type TYPE are saved starting at instruction with index T.  If N
276784865Sobrien   bits are set in REGMASK, it is assumed that instructions T through
276884865Sobrien   T+N-1 save these registers.
276984865Sobrien
277084865Sobrien   TYPE values:
277184865Sobrien	0: no save
277284865Sobrien	1: instruction saves next fp reg
277384865Sobrien	2: instruction saves next general reg
277484865Sobrien	3: instruction saves next branch reg */
277584865Sobrienstatic void
277684865Sobrienset_imask (region, regmask, t, type)
277784865Sobrien     unw_rec_list *region;
277884865Sobrien     unsigned long regmask;
277984865Sobrien     unsigned long t;
278084865Sobrien     unsigned int type;
278184865Sobrien{
278284865Sobrien  unsigned char *imask;
278384865Sobrien  unsigned long imask_size;
278484865Sobrien  unsigned int i;
278584865Sobrien  int pos;
278684865Sobrien
278784865Sobrien  imask = region->r.record.r.mask.i;
278884865Sobrien  imask_size = region->r.record.r.imask_size;
278984865Sobrien  if (!imask)
279084865Sobrien    {
279184865Sobrien      imask_size = (region->r.record.r.rlen * 2 + 7) / 8 + 1;
279284865Sobrien      imask = xmalloc (imask_size);
279384865Sobrien      memset (imask, 0, imask_size);
279484865Sobrien
279584865Sobrien      region->r.record.r.imask_size = imask_size;
279684865Sobrien      region->r.record.r.mask.i = imask;
279784865Sobrien    }
279884865Sobrien
279984865Sobrien  i = (t / 4) + 1;
280084865Sobrien  pos = 2 * (3 - t % 4);
280184865Sobrien  while (regmask)
280284865Sobrien    {
280384865Sobrien      if (i >= imask_size)
280484865Sobrien	{
280584865Sobrien	  as_bad ("Ignoring attempt to spill beyond end of region");
280684865Sobrien	  return;
280784865Sobrien	}
280884865Sobrien
280984865Sobrien      imask[i] |= (type & 0x3) << pos;
281084865Sobrien
281184865Sobrien      regmask &= (regmask - 1);
281284865Sobrien      pos -= 2;
281384865Sobrien      if (pos < 0)
281484865Sobrien	{
281584865Sobrien	  pos = 0;
281684865Sobrien	  ++i;
281784865Sobrien	}
281884865Sobrien    }
281984865Sobrien}
282084865Sobrien
282184865Sobrien/* Return the number of instruction slots from FIRST_ADDR to SLOT_ADDR.
282284865Sobrien   SLOT_FRAG is the frag containing SLOT_ADDR, and FIRST_FRAG is the frag
2823130561Sobrien   containing FIRST_ADDR.  If BEFORE_RELAX, then we use worst-case estimates
2824130561Sobrien   for frag sizes.  */
282584865Sobrien
282684865Sobrienunsigned long
2827130561Sobrienslot_index (slot_addr, slot_frag, first_addr, first_frag, before_relax)
282884865Sobrien     unsigned long slot_addr;
282984865Sobrien     fragS *slot_frag;
283084865Sobrien     unsigned long first_addr;
283184865Sobrien     fragS *first_frag;
2832130561Sobrien     int before_relax;
283384865Sobrien{
283484865Sobrien  unsigned long index = 0;
283584865Sobrien
283684865Sobrien  /* First time we are called, the initial address and frag are invalid.  */
283784865Sobrien  if (first_addr == 0)
283884865Sobrien    return 0;
283984865Sobrien
284084865Sobrien  /* If the two addresses are in different frags, then we need to add in
284184865Sobrien     the remaining size of this frag, and then the entire size of intermediate
284284865Sobrien     frags.  */
284384865Sobrien  while (slot_frag != first_frag)
284484865Sobrien    {
284584865Sobrien      unsigned long start_addr = (unsigned long) &first_frag->fr_literal;
284684865Sobrien
2847130561Sobrien      if (! before_relax)
2848130561Sobrien	{
2849130561Sobrien	  /* We can get the final addresses only during and after
2850130561Sobrien	     relaxation.  */
2851130561Sobrien	  if (first_frag->fr_next && first_frag->fr_next->fr_address)
2852130561Sobrien	    index += 3 * ((first_frag->fr_next->fr_address
2853130561Sobrien			   - first_frag->fr_address
2854130561Sobrien			     - first_frag->fr_fix) >> 4);
2855130561Sobrien	}
2856130561Sobrien      else
2857130561Sobrien	/* We don't know what the final addresses will be. We try our
2858130561Sobrien	   best to estimate.  */
2859130561Sobrien	switch (first_frag->fr_type)
2860130561Sobrien	  {
2861130561Sobrien	  default:
2862130561Sobrien	    break;
2863130561Sobrien
2864130561Sobrien	  case rs_space:
2865130561Sobrien	    as_fatal ("only constant space allocation is supported");
2866130561Sobrien	    break;
2867130561Sobrien
2868130561Sobrien	  case rs_align:
2869130561Sobrien	  case rs_align_code:
2870130561Sobrien	  case rs_align_test:
2871130561Sobrien	    /* Take alignment into account.  Assume the worst case
2872130561Sobrien	       before relaxation.  */
2873130561Sobrien	    index += 3 * ((1 << first_frag->fr_offset) >> 4);
2874130561Sobrien	    break;
2875130561Sobrien
2876130561Sobrien	  case rs_org:
2877130561Sobrien	    if (first_frag->fr_symbol)
2878130561Sobrien	      {
2879130561Sobrien		as_fatal ("only constant offsets are supported");
2880130561Sobrien		break;
2881130561Sobrien	      }
2882130561Sobrien	  case rs_fill:
2883130561Sobrien	    index += 3 * (first_frag->fr_offset >> 4);
2884130561Sobrien	    break;
2885130561Sobrien	  }
2886130561Sobrien
288784865Sobrien      /* Add in the full size of the frag converted to instruction slots.  */
288884865Sobrien      index += 3 * (first_frag->fr_fix >> 4);
288984865Sobrien      /* Subtract away the initial part before first_addr.  */
289084865Sobrien      index -= (3 * ((first_addr >> 4) - (start_addr >> 4))
289184865Sobrien		+ ((first_addr & 0x3) - (start_addr & 0x3)));
289284865Sobrien
289384865Sobrien      /* Move to the beginning of the next frag.  */
289484865Sobrien      first_frag = first_frag->fr_next;
289584865Sobrien      first_addr = (unsigned long) &first_frag->fr_literal;
2896218822Sdim
2897218822Sdim      /* This can happen if there is section switching in the middle of a
2898218822Sdim	 function, causing the frag chain for the function to be broken.
2899218822Sdim	 It is too difficult to recover safely from this problem, so we just
2900218822Sdim	 exit with an error.  */
2901218822Sdim      if (first_frag == NULL)
2902218822Sdim	as_fatal ("Section switching in code is not supported.");
290384865Sobrien    }
290484865Sobrien
290584865Sobrien  /* Add in the used part of the last frag.  */
290684865Sobrien  index += (3 * ((slot_addr >> 4) - (first_addr >> 4))
290784865Sobrien	    + ((slot_addr & 0x3) - (first_addr & 0x3)));
290884865Sobrien  return index;
290984865Sobrien}
291084865Sobrien
291184865Sobrien/* Optimize unwind record directives.  */
291284865Sobrien
291384865Sobrienstatic unw_rec_list *
291484865Sobrienoptimize_unw_records (list)
291584865Sobrien     unw_rec_list *list;
291684865Sobrien{
291784865Sobrien  if (!list)
291884865Sobrien    return NULL;
291984865Sobrien
292084865Sobrien  /* If the only unwind record is ".prologue" or ".prologue" followed
292184865Sobrien     by ".body", then we can optimize the unwind directives away.  */
292284865Sobrien  if (list->r.type == prologue
2923130561Sobrien      && (list->next->r.type == endp
2924130561Sobrien	  || (list->next->r.type == body && list->next->next->r.type == endp)))
292584865Sobrien    return NULL;
292684865Sobrien
292784865Sobrien  return list;
292884865Sobrien}
292984865Sobrien
293084865Sobrien/* Given a complete record list, process any records which have
293184865Sobrien   unresolved fields, (ie length counts for a prologue).  After
2932130561Sobrien   this has been run, all necessary information should be available
293384865Sobrien   within each record to generate an image.  */
293484865Sobrien
293584865Sobrienstatic void
2936130561Sobrienfixup_unw_records (list, before_relax)
293784865Sobrien     unw_rec_list *list;
2938130561Sobrien     int before_relax;
293984865Sobrien{
294084865Sobrien  unw_rec_list *ptr, *region = 0;
294184865Sobrien  unsigned long first_addr = 0, rlen = 0, t;
294284865Sobrien  fragS *first_frag = 0;
294384865Sobrien
294484865Sobrien  for (ptr = list; ptr; ptr = ptr->next)
294584865Sobrien    {
294684865Sobrien      if (ptr->slot_number == SLOT_NUM_NOT_SET)
294784865Sobrien	as_bad (" Insn slot not set in unwind record.");
294884865Sobrien      t = slot_index (ptr->slot_number, ptr->slot_frag,
2949130561Sobrien		      first_addr, first_frag, before_relax);
295084865Sobrien      switch (ptr->r.type)
295184865Sobrien	{
295284865Sobrien	case prologue:
295384865Sobrien	case prologue_gr:
295484865Sobrien	case body:
295584865Sobrien	  {
295684865Sobrien	    unw_rec_list *last;
2957130561Sobrien	    int size;
2958130561Sobrien	    unsigned long last_addr = 0;
2959130561Sobrien	    fragS *last_frag = NULL;
296084865Sobrien
296184865Sobrien	    first_addr = ptr->slot_number;
296284865Sobrien	    first_frag = ptr->slot_frag;
296384865Sobrien	    /* Find either the next body/prologue start, or the end of
2964130561Sobrien	       the function, and determine the size of the region.  */
296584865Sobrien	    for (last = ptr->next; last != NULL; last = last->next)
296684865Sobrien	      if (last->r.type == prologue || last->r.type == prologue_gr
2967130561Sobrien		  || last->r.type == body || last->r.type == endp)
296884865Sobrien		{
296984865Sobrien		  last_addr = last->slot_number;
297084865Sobrien		  last_frag = last->slot_frag;
297184865Sobrien		  break;
297284865Sobrien		}
2973130561Sobrien	    size = slot_index (last_addr, last_frag, first_addr, first_frag,
2974130561Sobrien			       before_relax);
297584865Sobrien	    rlen = ptr->r.record.r.rlen = size;
297694536Sobrien	    if (ptr->r.type == body)
297794536Sobrien	      /* End of region.  */
297894536Sobrien	      region = 0;
297994536Sobrien	    else
298094536Sobrien	      region = ptr;
298184865Sobrien	    break;
298284865Sobrien	  }
298384865Sobrien	case epilogue:
2984218822Sdim	  if (t < rlen)
2985218822Sdim	    ptr->r.record.b.t = rlen - 1 - t;
2986218822Sdim	  else
2987218822Sdim	    /* This happens when a memory-stack-less procedure uses a
2988218822Sdim	       ".restore sp" directive at the end of a region to pop
2989218822Sdim	       the frame state.  */
2990218822Sdim	    ptr->r.record.b.t = 0;
299184865Sobrien	  break;
299284865Sobrien
299384865Sobrien	case mem_stack_f:
299484865Sobrien	case mem_stack_v:
299584865Sobrien	case rp_when:
299684865Sobrien	case pfs_when:
299784865Sobrien	case preds_when:
299884865Sobrien	case unat_when:
299984865Sobrien	case lc_when:
300084865Sobrien	case fpsr_when:
300184865Sobrien	case priunat_when_gr:
300284865Sobrien	case priunat_when_mem:
300384865Sobrien	case bsp_when:
300484865Sobrien	case bspstore_when:
300584865Sobrien	case rnat_when:
300684865Sobrien	  ptr->r.record.p.t = t;
300784865Sobrien	  break;
300884865Sobrien
300984865Sobrien	case spill_reg:
301084865Sobrien	case spill_sprel:
301184865Sobrien	case spill_psprel:
301284865Sobrien	case spill_reg_p:
301384865Sobrien	case spill_sprel_p:
301484865Sobrien	case spill_psprel_p:
301584865Sobrien	  ptr->r.record.x.t = t;
301684865Sobrien	  break;
301784865Sobrien
301884865Sobrien	case frgr_mem:
301984865Sobrien	  if (!region)
302084865Sobrien	    {
3021218822Sdim	      as_bad ("frgr_mem record before region record!");
302284865Sobrien	      return;
302384865Sobrien	    }
302484865Sobrien	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.frmask;
302584865Sobrien	  region->r.record.r.mask.gr_mem |= ptr->r.record.p.grmask;
302684865Sobrien	  set_imask (region, ptr->r.record.p.frmask, t, 1);
302784865Sobrien	  set_imask (region, ptr->r.record.p.grmask, t, 2);
302884865Sobrien	  break;
302984865Sobrien	case fr_mem:
303084865Sobrien	  if (!region)
303184865Sobrien	    {
3032218822Sdim	      as_bad ("fr_mem record before region record!");
303384865Sobrien	      return;
303484865Sobrien	    }
3035218822Sdim	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.frmask;
3036218822Sdim	  set_imask (region, ptr->r.record.p.frmask, t, 1);
303784865Sobrien	  break;
303884865Sobrien	case gr_mem:
303984865Sobrien	  if (!region)
304084865Sobrien	    {
3041218822Sdim	      as_bad ("gr_mem record before region record!");
304284865Sobrien	      return;
304384865Sobrien	    }
3044218822Sdim	  region->r.record.r.mask.gr_mem |= ptr->r.record.p.grmask;
3045218822Sdim	  set_imask (region, ptr->r.record.p.grmask, t, 2);
304684865Sobrien	  break;
304784865Sobrien	case br_mem:
304884865Sobrien	  if (!region)
304984865Sobrien	    {
3050218822Sdim	      as_bad ("br_mem record before region record!");
305184865Sobrien	      return;
305284865Sobrien	    }
305384865Sobrien	  region->r.record.r.mask.br_mem |= ptr->r.record.p.brmask;
305484865Sobrien	  set_imask (region, ptr->r.record.p.brmask, t, 3);
305584865Sobrien	  break;
305684865Sobrien
305784865Sobrien	case gr_gr:
305884865Sobrien	  if (!region)
305984865Sobrien	    {
3060218822Sdim	      as_bad ("gr_gr record before region record!");
306184865Sobrien	      return;
306284865Sobrien	    }
306384865Sobrien	  set_imask (region, ptr->r.record.p.grmask, t, 2);
306484865Sobrien	  break;
306584865Sobrien	case br_gr:
306684865Sobrien	  if (!region)
306784865Sobrien	    {
3068218822Sdim	      as_bad ("br_gr record before region record!");
306984865Sobrien	      return;
307084865Sobrien	    }
307184865Sobrien	  set_imask (region, ptr->r.record.p.brmask, t, 3);
307284865Sobrien	  break;
307384865Sobrien
307484865Sobrien	default:
307584865Sobrien	  break;
307684865Sobrien	}
307784865Sobrien    }
307884865Sobrien}
307984865Sobrien
3080130561Sobrien/* Estimate the size of a frag before relaxing.  We only have one type of frag
3081130561Sobrien   to handle here, which is the unwind info frag.  */
308289857Sobrien
3083130561Sobrienint
3084130561Sobrienia64_estimate_size_before_relax (fragS *frag,
3085130561Sobrien				 asection *segtype ATTRIBUTE_UNUSED)
308689857Sobrien{
3087130561Sobrien  unw_rec_list *list;
3088130561Sobrien  int len, size, pad;
3089130561Sobrien
3090130561Sobrien  /* ??? This code is identical to the first part of ia64_convert_frag.  */
3091130561Sobrien  list = (unw_rec_list *) frag->fr_opcode;
3092130561Sobrien  fixup_unw_records (list, 0);
3093130561Sobrien
3094130561Sobrien  len = calc_record_size (list);
3095130561Sobrien  /* pad to pointer-size boundary.  */
3096130561Sobrien  pad = len % md.pointer_size;
3097130561Sobrien  if (pad != 0)
3098130561Sobrien    len += md.pointer_size - pad;
3099218822Sdim  /* Add 8 for the header.  */
3100218822Sdim  size = len + 8;
3101218822Sdim  /* Add a pointer for the personality offset.  */
3102218822Sdim  if (frag->fr_offset)
3103218822Sdim    size += md.pointer_size;
3104130561Sobrien
3105130561Sobrien  /* fr_var carries the max_chars that we created the fragment with.
3106130561Sobrien     We must, of course, have allocated enough memory earlier.  */
3107130561Sobrien  assert (frag->fr_var >= size);
3108130561Sobrien
3109130561Sobrien  return frag->fr_fix + size;
3110130561Sobrien}
3111130561Sobrien
3112130561Sobrien/* This function converts a rs_machine_dependent variant frag into a
3113130561Sobrien  normal fill frag with the unwind image from the the record list.  */
3114130561Sobrienvoid
3115130561Sobrienia64_convert_frag (fragS *frag)
3116130561Sobrien{
3117130561Sobrien  unw_rec_list *list;
3118130561Sobrien  int len, size, pad;
311989857Sobrien  valueT flag_value;
312089857Sobrien
3121130561Sobrien  /* ??? This code is identical to ia64_estimate_size_before_relax.  */
3122130561Sobrien  list = (unw_rec_list *) frag->fr_opcode;
3123130561Sobrien  fixup_unw_records (list, 0);
312489857Sobrien
3125130561Sobrien  len = calc_record_size (list);
3126130561Sobrien  /* pad to pointer-size boundary.  */
3127130561Sobrien  pad = len % md.pointer_size;
3128130561Sobrien  if (pad != 0)
3129130561Sobrien    len += md.pointer_size - pad;
3130218822Sdim  /* Add 8 for the header.  */
3131218822Sdim  size = len + 8;
3132218822Sdim  /* Add a pointer for the personality offset.  */
3133218822Sdim  if (frag->fr_offset)
3134218822Sdim    size += md.pointer_size;
313589857Sobrien
3136130561Sobrien  /* fr_var carries the max_chars that we created the fragment with.
3137130561Sobrien     We must, of course, have allocated enough memory earlier.  */
3138130561Sobrien  assert (frag->fr_var >= size);
313989857Sobrien
3140130561Sobrien  /* Initialize the header area. fr_offset is initialized with
3141130561Sobrien     unwind.personality_routine.  */
3142130561Sobrien  if (frag->fr_offset)
314389857Sobrien    {
314489857Sobrien      if (md.flags & EF_IA_64_ABI64)
314589857Sobrien	flag_value = (bfd_vma) 3 << 32;
314689857Sobrien      else
314789857Sobrien	/* 32-bit unwind info block.  */
314889857Sobrien	flag_value = (bfd_vma) 0x1003 << 32;
314989857Sobrien    }
315089857Sobrien  else
315189857Sobrien    flag_value = 0;
315289857Sobrien
3153130561Sobrien md_number_to_chars (frag->fr_literal,
3154130561Sobrien		     (((bfd_vma) 1 << 48) /* Version.  */
3155130561Sobrien		      | flag_value        /* U & E handler flags.  */
3156130561Sobrien		      | (len / md.pointer_size)), /* Length.  */
3157130561Sobrien		     8);
315889857Sobrien
3159130561Sobrien  /* Skip the header.  */
3160130561Sobrien  vbyte_mem_ptr = frag->fr_literal + 8;
3161130561Sobrien  process_unw_records (list, output_vbyte_mem);
316289857Sobrien
3163130561Sobrien  /* Fill the padding bytes with zeros.  */
3164130561Sobrien  if (pad != 0)
3165130561Sobrien    md_number_to_chars (frag->fr_literal + len + 8 - md.pointer_size + pad, 0,
3166130561Sobrien			md.pointer_size - pad);
316784865Sobrien
3168130561Sobrien  frag->fr_fix += size;
3169130561Sobrien  frag->fr_type = rs_fill;
3170130561Sobrien  frag->fr_var = 0;
3171130561Sobrien  frag->fr_offset = 0;
317284865Sobrien}
317384865Sobrien
317484865Sobrienstatic int
3175218822Sdimparse_predicate_and_operand (e, qp, po)
3176218822Sdim     expressionS * e;
3177218822Sdim     unsigned * qp;
3178218822Sdim     const char * po;
3179218822Sdim{
3180218822Sdim  int sep = parse_operand (e, ',');
3181218822Sdim
3182218822Sdim  *qp = e->X_add_number - REG_P;
3183218822Sdim  if (e->X_op != O_register || *qp > 63)
3184218822Sdim    {
3185218822Sdim      as_bad ("First operand to .%s must be a predicate", po);
3186218822Sdim      *qp = 0;
3187218822Sdim    }
3188218822Sdim  else if (*qp == 0)
3189218822Sdim    as_warn ("Pointless use of p0 as first operand to .%s", po);
3190218822Sdim  if (sep == ',')
3191218822Sdim    sep = parse_operand (e, ',');
3192218822Sdim  else
3193218822Sdim    e->X_op = O_absent;
3194218822Sdim  return sep;
3195218822Sdim}
3196218822Sdim
3197218822Sdimstatic void
3198218822Sdimconvert_expr_to_ab_reg (e, ab, regp, po, n)
3199218822Sdim     const expressionS *e;
320084865Sobrien     unsigned int *ab;
320184865Sobrien     unsigned int *regp;
3202218822Sdim     const char * po;
3203218822Sdim     int n;
320484865Sobrien{
3205218822Sdim  unsigned int reg = e->X_add_number;
320684865Sobrien
3207218822Sdim  *ab = *regp = 0; /* Anything valid is good here.  */
3208218822Sdim
320984865Sobrien  if (e->X_op != O_register)
3210218822Sdim    reg = REG_GR; /* Anything invalid is good here.  */
321184865Sobrien
321284865Sobrien  if (reg >= (REG_GR + 4) && reg <= (REG_GR + 7))
321384865Sobrien    {
321484865Sobrien      *ab = 0;
321584865Sobrien      *regp = reg - REG_GR;
321684865Sobrien    }
321784865Sobrien  else if ((reg >= (REG_FR + 2) && reg <= (REG_FR + 5))
321884865Sobrien	   || (reg >= (REG_FR + 16) && reg <= (REG_FR + 31)))
321984865Sobrien    {
322084865Sobrien      *ab = 1;
322184865Sobrien      *regp = reg - REG_FR;
322284865Sobrien    }
322384865Sobrien  else if (reg >= (REG_BR + 1) && reg <= (REG_BR + 5))
322484865Sobrien    {
322584865Sobrien      *ab = 2;
322684865Sobrien      *regp = reg - REG_BR;
322784865Sobrien    }
322884865Sobrien  else
322984865Sobrien    {
323084865Sobrien      *ab = 3;
323184865Sobrien      switch (reg)
323284865Sobrien	{
323384865Sobrien	case REG_PR:		*regp =  0; break;
323484865Sobrien	case REG_PSP:		*regp =  1; break;
323584865Sobrien	case REG_PRIUNAT:	*regp =  2; break;
323684865Sobrien	case REG_BR + 0:	*regp =  3; break;
323784865Sobrien	case REG_AR + AR_BSP:	*regp =  4; break;
323884865Sobrien	case REG_AR + AR_BSPSTORE: *regp = 5; break;
323984865Sobrien	case REG_AR + AR_RNAT:	*regp =  6; break;
324084865Sobrien	case REG_AR + AR_UNAT:	*regp =  7; break;
324184865Sobrien	case REG_AR + AR_FPSR:	*regp =  8; break;
324284865Sobrien	case REG_AR + AR_PFS:	*regp =  9; break;
324384865Sobrien	case REG_AR + AR_LC:	*regp = 10; break;
324484865Sobrien
324584865Sobrien	default:
3246218822Sdim	  as_bad ("Operand %d to .%s must be a preserved register", n, po);
3247218822Sdim	  break;
324884865Sobrien	}
324984865Sobrien    }
325084865Sobrien}
325184865Sobrien
3252218822Sdimstatic void
3253218822Sdimconvert_expr_to_xy_reg (e, xy, regp, po, n)
3254218822Sdim     const expressionS *e;
325584865Sobrien     unsigned int *xy;
325684865Sobrien     unsigned int *regp;
3257218822Sdim     const char * po;
3258218822Sdim     int n;
325984865Sobrien{
3260218822Sdim  unsigned int reg = e->X_add_number;
326184865Sobrien
3262218822Sdim  *xy = *regp = 0; /* Anything valid is good here.  */
3263218822Sdim
326484865Sobrien  if (e->X_op != O_register)
3265218822Sdim    reg = REG_GR; /* Anything invalid is good here.  */
326684865Sobrien
3267218822Sdim  if (reg >= (REG_GR + 1) && reg <= (REG_GR + 127))
326884865Sobrien    {
326984865Sobrien      *xy = 0;
327084865Sobrien      *regp = reg - REG_GR;
327184865Sobrien    }
3272218822Sdim  else if (reg >= (REG_FR + 2) && reg <= (REG_FR + 127))
327384865Sobrien    {
327484865Sobrien      *xy = 1;
327584865Sobrien      *regp = reg - REG_FR;
327684865Sobrien    }
327784865Sobrien  else if (reg >= REG_BR && reg <= (REG_BR + 7))
327884865Sobrien    {
327984865Sobrien      *xy = 2;
328084865Sobrien      *regp = reg - REG_BR;
328184865Sobrien    }
328284865Sobrien  else
3283218822Sdim    as_bad ("Operand %d to .%s must be a writable register", n, po);
328484865Sobrien}
328584865Sobrien
328684865Sobrienstatic void
3287130561Sobriendot_align (int arg)
3288130561Sobrien{
3289130561Sobrien  /* The current frag is an alignment frag.  */
3290130561Sobrien  align_frag = frag_now;
3291130561Sobrien  s_align_bytes (arg);
3292130561Sobrien}
3293130561Sobrien
3294130561Sobrienstatic void
329584865Sobriendot_radix (dummy)
329684865Sobrien     int dummy ATTRIBUTE_UNUSED;
329784865Sobrien{
3298218822Sdim  char *radix;
3299218822Sdim  int ch;
330084865Sobrien
330184865Sobrien  SKIP_WHITESPACE ();
330284865Sobrien
3303218822Sdim  if (is_it_end_of_statement ())
3304218822Sdim    return;
3305218822Sdim  radix = input_line_pointer;
3306218822Sdim  ch = get_symbol_end ();
3307218822Sdim  ia64_canonicalize_symbol_name (radix);
3308218822Sdim  if (strcasecmp (radix, "C"))
3309218822Sdim    as_bad ("Radix `%s' unsupported or invalid", radix);
3310218822Sdim  *input_line_pointer = ch;
3311218822Sdim  demand_empty_rest_of_line ();
331284865Sobrien}
331384865Sobrien
3314218822Sdim/* Helper function for .loc directives.  If the assembler is not generating
3315218822Sdim   line number info, then we need to remember which instructions have a .loc
3316218822Sdim   directive, and only call dwarf2_gen_line_info for those instructions.  */
3317218822Sdim
3318218822Sdimstatic void
3319218822Sdimdot_loc (int x)
3320218822Sdim{
3321218822Sdim  CURR_SLOT.loc_directive_seen = 1;
3322218822Sdim  dwarf2_directive_loc (x);
3323218822Sdim}
3324218822Sdim
332584865Sobrien/* .sbss, .bss etc. are macros that expand into ".section SECNAME".  */
332684865Sobrienstatic void
332784865Sobriendot_special_section (which)
332884865Sobrien     int which;
332984865Sobrien{
333084865Sobrien  set_section ((char *) special_section_name[which]);
333184865Sobrien}
333284865Sobrien
3333218822Sdim/* Return -1 for warning and 0 for error.  */
3334218822Sdim
3335218822Sdimstatic int
3336218822Sdimunwind_diagnostic (const char * region, const char *directive)
3337218822Sdim{
3338218822Sdim  if (md.unwind_check == unwind_check_warning)
3339218822Sdim    {
3340218822Sdim      as_warn (".%s outside of %s", directive, region);
3341218822Sdim      return -1;
3342218822Sdim    }
3343218822Sdim  else
3344218822Sdim    {
3345218822Sdim      as_bad (".%s outside of %s", directive, region);
3346218822Sdim      ignore_rest_of_line ();
3347218822Sdim      return 0;
3348218822Sdim    }
3349218822Sdim}
3350218822Sdim
3351218822Sdim/* Return 1 if a directive is in a procedure, -1 if a directive isn't in
3352218822Sdim   a procedure but the unwind directive check is set to warning, 0 if
3353218822Sdim   a directive isn't in a procedure and the unwind directive check is set
3354218822Sdim   to error.  */
3355218822Sdim
3356218822Sdimstatic int
3357218822Sdimin_procedure (const char *directive)
3358218822Sdim{
3359218822Sdim  if (unwind.proc_pending.sym
3360218822Sdim      && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
3361218822Sdim    return 1;
3362218822Sdim  return unwind_diagnostic ("procedure", directive);
3363218822Sdim}
3364218822Sdim
3365218822Sdim/* Return 1 if a directive is in a prologue, -1 if a directive isn't in
3366218822Sdim   a prologue but the unwind directive check is set to warning, 0 if
3367218822Sdim   a directive isn't in a prologue and the unwind directive check is set
3368218822Sdim   to error.  */
3369218822Sdim
3370218822Sdimstatic int
3371218822Sdimin_prologue (const char *directive)
3372218822Sdim{
3373218822Sdim  int in = in_procedure (directive);
3374218822Sdim
3375218822Sdim  if (in > 0 && !unwind.prologue)
3376218822Sdim    in = unwind_diagnostic ("prologue", directive);
3377218822Sdim  check_pending_save ();
3378218822Sdim  return in;
3379218822Sdim}
3380218822Sdim
3381218822Sdim/* Return 1 if a directive is in a body, -1 if a directive isn't in
3382218822Sdim   a body but the unwind directive check is set to warning, 0 if
3383218822Sdim   a directive isn't in a body and the unwind directive check is set
3384218822Sdim   to error.  */
3385218822Sdim
3386218822Sdimstatic int
3387218822Sdimin_body (const char *directive)
3388218822Sdim{
3389218822Sdim  int in = in_procedure (directive);
3390218822Sdim
3391218822Sdim  if (in > 0 && !unwind.body)
3392218822Sdim    in = unwind_diagnostic ("body region", directive);
3393218822Sdim  return in;
3394218822Sdim}
3395218822Sdim
339684865Sobrienstatic void
3397218822Sdimadd_unwind_entry (ptr, sep)
339884865Sobrien     unw_rec_list *ptr;
3399218822Sdim     int sep;
340084865Sobrien{
3401218822Sdim  if (ptr)
3402218822Sdim    {
3403218822Sdim      if (unwind.tail)
3404218822Sdim	unwind.tail->next = ptr;
3405218822Sdim      else
3406218822Sdim	unwind.list = ptr;
3407218822Sdim      unwind.tail = ptr;
340884865Sobrien
3409218822Sdim      /* The current entry can in fact be a chain of unwind entries.  */
3410218822Sdim      if (unwind.current_entry == NULL)
3411218822Sdim	unwind.current_entry = ptr;
3412218822Sdim    }
3413218822Sdim
341484865Sobrien  /* The current entry can in fact be a chain of unwind entries.  */
341584865Sobrien  if (unwind.current_entry == NULL)
341684865Sobrien    unwind.current_entry = ptr;
3417218822Sdim
3418218822Sdim  if (sep == ',')
3419218822Sdim    {
3420218822Sdim      /* Parse a tag permitted for the current directive.  */
3421218822Sdim      int ch;
3422218822Sdim
3423218822Sdim      SKIP_WHITESPACE ();
3424218822Sdim      ch = get_symbol_end ();
3425218822Sdim      /* FIXME: For now, just issue a warning that this isn't implemented.  */
3426218822Sdim      {
3427218822Sdim	static int warned;
3428218822Sdim
3429218822Sdim	if (!warned)
3430218822Sdim	  {
3431218822Sdim	    warned = 1;
3432218822Sdim	    as_warn ("Tags on unwind pseudo-ops aren't supported, yet");
3433218822Sdim	  }
3434218822Sdim      }
3435218822Sdim      *input_line_pointer = ch;
3436218822Sdim    }
3437218822Sdim  if (sep != NOT_A_CHAR)
3438218822Sdim    demand_empty_rest_of_line ();
343984865Sobrien}
344084865Sobrien
344184865Sobrienstatic void
344284865Sobriendot_fframe (dummy)
344384865Sobrien     int dummy ATTRIBUTE_UNUSED;
344484865Sobrien{
344584865Sobrien  expressionS e;
3446218822Sdim  int sep;
344784865Sobrien
3448218822Sdim  if (!in_prologue ("fframe"))
3449218822Sdim    return;
345084865Sobrien
3451218822Sdim  sep = parse_operand (&e, ',');
3452218822Sdim
345384865Sobrien  if (e.X_op != O_constant)
3454218822Sdim    {
3455218822Sdim      as_bad ("First operand to .fframe must be a constant");
3456218822Sdim      e.X_add_number = 0;
3457218822Sdim    }
3458218822Sdim  add_unwind_entry (output_mem_stack_f (e.X_add_number), sep);
345984865Sobrien}
346084865Sobrien
346184865Sobrienstatic void
346284865Sobriendot_vframe (dummy)
346384865Sobrien     int dummy ATTRIBUTE_UNUSED;
346484865Sobrien{
346584865Sobrien  expressionS e;
346684865Sobrien  unsigned reg;
3467218822Sdim  int sep;
346884865Sobrien
3469218822Sdim  if (!in_prologue ("vframe"))
3470218822Sdim    return;
3471218822Sdim
3472218822Sdim  sep = parse_operand (&e, ',');
347384865Sobrien  reg = e.X_add_number - REG_GR;
3474218822Sdim  if (e.X_op != O_register || reg > 127)
347584865Sobrien    {
3476218822Sdim      as_bad ("First operand to .vframe must be a general register");
3477218822Sdim      reg = 0;
347884865Sobrien    }
3479218822Sdim  add_unwind_entry (output_mem_stack_v (), sep);
3480218822Sdim  if (! (unwind.prologue_mask & 2))
3481218822Sdim    add_unwind_entry (output_psp_gr (reg), NOT_A_CHAR);
3482218822Sdim  else if (reg != unwind.prologue_gr
3483218822Sdim		  + (unsigned) popcount (unwind.prologue_mask & (-2 << 1)))
3484218822Sdim    as_warn ("Operand of .vframe contradicts .prologue");
348584865Sobrien}
348684865Sobrien
348784865Sobrienstatic void
3488218822Sdimdot_vframesp (psp)
3489218822Sdim     int psp;
349084865Sobrien{
349184865Sobrien  expressionS e;
3492218822Sdim  int sep;
349384865Sobrien
3494218822Sdim  if (psp)
3495218822Sdim    as_warn (".vframepsp is meaningless, assuming .vframesp was meant");
349684865Sobrien
3497218822Sdim  if (!in_prologue ("vframesp"))
3498218822Sdim    return;
349984865Sobrien
3500218822Sdim  sep = parse_operand (&e, ',');
3501218822Sdim  if (e.X_op != O_constant)
350284865Sobrien    {
3503218822Sdim      as_bad ("Operand to .vframesp must be a constant (sp-relative offset)");
3504218822Sdim      e.X_add_number = 0;
350584865Sobrien    }
3506218822Sdim  add_unwind_entry (output_mem_stack_v (), sep);
3507218822Sdim  add_unwind_entry (output_psp_sprel (e.X_add_number), NOT_A_CHAR);
350884865Sobrien}
350984865Sobrien
351084865Sobrienstatic void
351184865Sobriendot_save (dummy)
351284865Sobrien     int dummy ATTRIBUTE_UNUSED;
351384865Sobrien{
351484865Sobrien  expressionS e1, e2;
3515218822Sdim  unsigned reg1, reg2;
351684865Sobrien  int sep;
351784865Sobrien
3518218822Sdim  if (!in_prologue ("save"))
3519218822Sdim    return;
352084865Sobrien
3521218822Sdim  sep = parse_operand (&e1, ',');
3522218822Sdim  if (sep == ',')
3523218822Sdim    sep = parse_operand (&e2, ',');
3524218822Sdim  else
3525218822Sdim    e2.X_op = O_absent;
3526218822Sdim
352784865Sobrien  reg1 = e1.X_add_number;
352884865Sobrien  /* Make sure its a valid ar.xxx reg, OR its br0, aka 'rp'.  */
3529218822Sdim  if (e1.X_op != O_register)
353084865Sobrien    {
3531218822Sdim      as_bad ("First operand to .save not a register");
3532218822Sdim      reg1 = REG_PR; /* Anything valid is good here.  */
353384865Sobrien    }
3534218822Sdim  reg2 = e2.X_add_number - REG_GR;
3535218822Sdim  if (e2.X_op != O_register || reg2 > 127)
3536218822Sdim    {
3537218822Sdim      as_bad ("Second operand to .save not a valid register");
3538218822Sdim      reg2 = 0;
3539218822Sdim    }
3540218822Sdim  switch (reg1)
3541218822Sdim    {
3542218822Sdim    case REG_AR + AR_BSP:
3543218822Sdim      add_unwind_entry (output_bsp_when (), sep);
3544218822Sdim      add_unwind_entry (output_bsp_gr (reg2), NOT_A_CHAR);
3545218822Sdim      break;
3546218822Sdim    case REG_AR + AR_BSPSTORE:
3547218822Sdim      add_unwind_entry (output_bspstore_when (), sep);
3548218822Sdim      add_unwind_entry (output_bspstore_gr (reg2), NOT_A_CHAR);
3549218822Sdim      break;
3550218822Sdim    case REG_AR + AR_RNAT:
3551218822Sdim      add_unwind_entry (output_rnat_when (), sep);
3552218822Sdim      add_unwind_entry (output_rnat_gr (reg2), NOT_A_CHAR);
3553218822Sdim      break;
3554218822Sdim    case REG_AR + AR_UNAT:
3555218822Sdim      add_unwind_entry (output_unat_when (), sep);
3556218822Sdim      add_unwind_entry (output_unat_gr (reg2), NOT_A_CHAR);
3557218822Sdim      break;
3558218822Sdim    case REG_AR + AR_FPSR:
3559218822Sdim      add_unwind_entry (output_fpsr_when (), sep);
3560218822Sdim      add_unwind_entry (output_fpsr_gr (reg2), NOT_A_CHAR);
3561218822Sdim      break;
3562218822Sdim    case REG_AR + AR_PFS:
3563218822Sdim      add_unwind_entry (output_pfs_when (), sep);
3564218822Sdim      if (! (unwind.prologue_mask & 4))
3565218822Sdim	add_unwind_entry (output_pfs_gr (reg2), NOT_A_CHAR);
3566218822Sdim      else if (reg2 != unwind.prologue_gr
3567218822Sdim		       + (unsigned) popcount (unwind.prologue_mask & (-4 << 1)))
3568218822Sdim	as_warn ("Second operand of .save contradicts .prologue");
3569218822Sdim      break;
3570218822Sdim    case REG_AR + AR_LC:
3571218822Sdim      add_unwind_entry (output_lc_when (), sep);
3572218822Sdim      add_unwind_entry (output_lc_gr (reg2), NOT_A_CHAR);
3573218822Sdim      break;
3574218822Sdim    case REG_BR:
3575218822Sdim      add_unwind_entry (output_rp_when (), sep);
3576218822Sdim      if (! (unwind.prologue_mask & 8))
3577218822Sdim	add_unwind_entry (output_rp_gr (reg2), NOT_A_CHAR);
3578218822Sdim      else if (reg2 != unwind.prologue_gr)
3579218822Sdim	as_warn ("Second operand of .save contradicts .prologue");
3580218822Sdim      break;
3581218822Sdim    case REG_PR:
3582218822Sdim      add_unwind_entry (output_preds_when (), sep);
3583218822Sdim      if (! (unwind.prologue_mask & 1))
3584218822Sdim	add_unwind_entry (output_preds_gr (reg2), NOT_A_CHAR);
3585218822Sdim      else if (reg2 != unwind.prologue_gr
3586218822Sdim		       + (unsigned) popcount (unwind.prologue_mask & (-1 << 1)))
3587218822Sdim	as_warn ("Second operand of .save contradicts .prologue");
3588218822Sdim      break;
3589218822Sdim    case REG_PRIUNAT:
3590218822Sdim      add_unwind_entry (output_priunat_when_gr (), sep);
3591218822Sdim      add_unwind_entry (output_priunat_gr (reg2), NOT_A_CHAR);
3592218822Sdim      break;
3593218822Sdim    default:
3594218822Sdim      as_bad ("First operand to .save not a valid register");
3595218822Sdim      add_unwind_entry (NULL, sep);
3596218822Sdim      break;
3597218822Sdim    }
359884865Sobrien}
359984865Sobrien
360084865Sobrienstatic void
360184865Sobriendot_restore (dummy)
360284865Sobrien     int dummy ATTRIBUTE_UNUSED;
360384865Sobrien{
3604218822Sdim  expressionS e1;
360584865Sobrien  unsigned long ecount;	/* # of _additional_ regions to pop */
360684865Sobrien  int sep;
360784865Sobrien
3608218822Sdim  if (!in_body ("restore"))
3609218822Sdim    return;
3610218822Sdim
3611218822Sdim  sep = parse_operand (&e1, ',');
361284865Sobrien  if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12)
3613218822Sdim    as_bad ("First operand to .restore must be stack pointer (sp)");
361484865Sobrien
361584865Sobrien  if (sep == ',')
361684865Sobrien    {
3617218822Sdim      expressionS e2;
3618218822Sdim
3619218822Sdim      sep = parse_operand (&e2, ',');
362084865Sobrien      if (e2.X_op != O_constant || e2.X_add_number < 0)
362184865Sobrien	{
362284865Sobrien	  as_bad ("Second operand to .restore must be a constant >= 0");
3623218822Sdim	  e2.X_add_number = 0;
362484865Sobrien	}
362584865Sobrien      ecount = e2.X_add_number;
362684865Sobrien    }
362784865Sobrien  else
362884865Sobrien    ecount = unwind.prologue_count - 1;
362992828Sobrien
363092828Sobrien  if (ecount >= unwind.prologue_count)
363192828Sobrien    {
363292828Sobrien      as_bad ("Epilogue count of %lu exceeds number of nested prologues (%u)",
363392828Sobrien	      ecount + 1, unwind.prologue_count);
3634218822Sdim      ecount = 0;
363592828Sobrien    }
363692828Sobrien
3637218822Sdim  add_unwind_entry (output_epilogue (ecount), sep);
363884865Sobrien
363984865Sobrien  if (ecount < unwind.prologue_count)
364084865Sobrien    unwind.prologue_count -= ecount + 1;
364184865Sobrien  else
364284865Sobrien    unwind.prologue_count = 0;
364384865Sobrien}
364484865Sobrien
364584865Sobrienstatic void
3646218822Sdimdot_restorereg (pred)
3647218822Sdim     int pred;
364884865Sobrien{
3649218822Sdim  unsigned int qp, ab, reg;
365084865Sobrien  expressionS e;
3651218822Sdim  int sep;
3652218822Sdim  const char * const po = pred ? "restorereg.p" : "restorereg";
365384865Sobrien
3654218822Sdim  if (!in_procedure (po))
3655218822Sdim    return;
365684865Sobrien
3657218822Sdim  if (pred)
3658218822Sdim    sep = parse_predicate_and_operand (&e, &qp, po);
3659218822Sdim  else
366084865Sobrien    {
3661218822Sdim      sep = parse_operand (&e, ',');
3662218822Sdim      qp = 0;
366384865Sobrien    }
3664218822Sdim  convert_expr_to_ab_reg (&e, &ab, &reg, po, 1 + pred);
3665218822Sdim
3666218822Sdim  add_unwind_entry (output_spill_reg (ab, reg, 0, 0, qp), sep);
366784865Sobrien}
366884865Sobrien
3669218822Sdimstatic char *special_linkonce_name[] =
3670218822Sdim  {
3671218822Sdim    ".gnu.linkonce.ia64unw.", ".gnu.linkonce.ia64unwi."
3672218822Sdim  };
3673218822Sdim
367484865Sobrienstatic void
3675218822Sdimstart_unwind_section (const segT text_seg, int sec_index)
367684865Sobrien{
3677218822Sdim  /*
3678218822Sdim    Use a slightly ugly scheme to derive the unwind section names from
3679218822Sdim    the text section name:
368084865Sobrien
3681218822Sdim    text sect.  unwind table sect.
3682218822Sdim    name:       name:                      comments:
3683218822Sdim    ----------  -----------------          --------------------------------
3684218822Sdim    .text       .IA_64.unwind
3685218822Sdim    .text.foo   .IA_64.unwind.text.foo
3686218822Sdim    .foo        .IA_64.unwind.foo
3687218822Sdim    .gnu.linkonce.t.foo
3688218822Sdim		.gnu.linkonce.ia64unw.foo
3689218822Sdim    _info       .IA_64.unwind_info         gas issues error message (ditto)
3690218822Sdim    _infoFOO    .IA_64.unwind_infoFOO      gas issues error message (ditto)
3691218822Sdim
3692218822Sdim    This mapping is done so that:
3693218822Sdim
3694218822Sdim	(a) An object file with unwind info only in .text will use
3695218822Sdim	    unwind section names .IA_64.unwind and .IA_64.unwind_info.
3696218822Sdim	    This follows the letter of the ABI and also ensures backwards
3697218822Sdim	    compatibility with older toolchains.
3698218822Sdim
3699218822Sdim	(b) An object file with unwind info in multiple text sections
3700218822Sdim	    will use separate unwind sections for each text section.
3701218822Sdim	    This allows us to properly set the "sh_info" and "sh_link"
3702218822Sdim	    fields in SHT_IA_64_UNWIND as required by the ABI and also
3703218822Sdim	    lets GNU ld support programs with multiple segments
3704218822Sdim	    containing unwind info (as might be the case for certain
3705218822Sdim	    embedded applications).
3706218822Sdim
3707218822Sdim	(c) An error is issued if there would be a name clash.
3708218822Sdim  */
3709218822Sdim
3710218822Sdim  const char *text_name, *sec_text_name;
3711218822Sdim  char *sec_name;
3712218822Sdim  const char *prefix = special_section_name [sec_index];
3713218822Sdim  const char *suffix;
3714218822Sdim  size_t prefix_len, suffix_len, sec_name_len;
3715218822Sdim
3716218822Sdim  sec_text_name = segment_name (text_seg);
3717218822Sdim  text_name = sec_text_name;
3718218822Sdim  if (strncmp (text_name, "_info", 5) == 0)
371984865Sobrien    {
3720218822Sdim      as_bad ("Illegal section name `%s' (causes unwind section name clash)",
3721218822Sdim	      text_name);
3722218822Sdim      ignore_rest_of_line ();
372384865Sobrien      return;
372484865Sobrien    }
3725218822Sdim  if (strcmp (text_name, ".text") == 0)
3726218822Sdim    text_name = "";
372784865Sobrien
3728218822Sdim  /* Build the unwind section name by appending the (possibly stripped)
3729218822Sdim     text section name to the unwind prefix.  */
3730218822Sdim  suffix = text_name;
3731218822Sdim  if (strncmp (text_name, ".gnu.linkonce.t.",
3732218822Sdim	       sizeof (".gnu.linkonce.t.") - 1) == 0)
373384865Sobrien    {
3734218822Sdim      prefix = special_linkonce_name [sec_index - SPECIAL_SECTION_UNWIND];
3735218822Sdim      suffix += sizeof (".gnu.linkonce.t.") - 1;
373684865Sobrien    }
373784865Sobrien
3738218822Sdim  prefix_len = strlen (prefix);
3739218822Sdim  suffix_len = strlen (suffix);
3740218822Sdim  sec_name_len = prefix_len + suffix_len;
3741218822Sdim  sec_name = alloca (sec_name_len + 1);
3742218822Sdim  memcpy (sec_name, prefix, prefix_len);
3743218822Sdim  memcpy (sec_name + prefix_len, suffix, suffix_len);
3744218822Sdim  sec_name [sec_name_len] = '\0';
3745218822Sdim
3746218822Sdim  /* Handle COMDAT group.  */
3747218822Sdim  if ((text_seg->flags & SEC_LINK_ONCE) != 0
3748218822Sdim      && (elf_section_flags (text_seg) & SHF_GROUP) != 0)
374984865Sobrien    {
3750218822Sdim      char *section;
3751218822Sdim      size_t len, group_name_len;
3752218822Sdim      const char *group_name = elf_group_name (text_seg);
3753218822Sdim
3754218822Sdim      if (group_name == NULL)
3755218822Sdim	{
3756218822Sdim	  as_bad ("Group section `%s' has no group signature",
3757218822Sdim		  sec_text_name);
3758218822Sdim	  ignore_rest_of_line ();
3759218822Sdim	  return;
3760218822Sdim	}
3761218822Sdim      /* We have to construct a fake section directive. */
3762218822Sdim      group_name_len = strlen (group_name);
3763218822Sdim      len = (sec_name_len
3764218822Sdim	     + 16			/* ,"aG",@progbits,  */
3765218822Sdim	     + group_name_len		/* ,group_name  */
3766218822Sdim	     + 7);			/* ,comdat  */
3767218822Sdim
3768218822Sdim      section = alloca (len + 1);
3769218822Sdim      memcpy (section, sec_name, sec_name_len);
3770218822Sdim      memcpy (section + sec_name_len, ",\"aG\",@progbits,", 16);
3771218822Sdim      memcpy (section + sec_name_len + 16, group_name, group_name_len);
3772218822Sdim      memcpy (section + len - 7, ",comdat", 7);
3773218822Sdim      section [len] = '\0';
3774218822Sdim      set_section (section);
377584865Sobrien    }
3776218822Sdim  else
3777218822Sdim    {
3778218822Sdim      set_section (sec_name);
3779218822Sdim      bfd_set_section_flags (stdoutput, now_seg,
3780218822Sdim			     SEC_LOAD | SEC_ALLOC | SEC_READONLY);
3781218822Sdim    }
3782218822Sdim
3783218822Sdim  elf_linked_to_section (now_seg) = text_seg;
378484865Sobrien}
378584865Sobrien
3786130561Sobrienstatic void
3787218822Sdimgenerate_unwind_image (const segT text_seg)
378884865Sobrien{
3789130561Sobrien  int size, pad;
3790130561Sobrien  unw_rec_list *list;
379184865Sobrien
3792130561Sobrien  /* Mark the end of the unwind info, so that we can compute the size of the
3793130561Sobrien     last unwind region.  */
3794218822Sdim  add_unwind_entry (output_endp (), NOT_A_CHAR);
3795130561Sobrien
379684865Sobrien  /* Force out pending instructions, to make sure all unwind records have
379784865Sobrien     a valid slot_number field.  */
379884865Sobrien  ia64_flush_insns ();
379984865Sobrien
380084865Sobrien  /* Generate the unwind record.  */
3801130561Sobrien  list = optimize_unw_records (unwind.list);
3802130561Sobrien  fixup_unw_records (list, 1);
3803130561Sobrien  size = calc_record_size (list);
380494536Sobrien
3805130561Sobrien  if (size > 0 || unwind.force_unwind_entry)
3806130561Sobrien    {
3807130561Sobrien      unwind.force_unwind_entry = 0;
3808130561Sobrien      /* pad to pointer-size boundary.  */
3809130561Sobrien      pad = size % md.pointer_size;
3810130561Sobrien      if (pad != 0)
3811130561Sobrien	size += md.pointer_size - pad;
3812218822Sdim      /* Add 8 for the header.  */
3813218822Sdim      size += 8;
3814218822Sdim      /* Add a pointer for the personality offset.  */
3815218822Sdim      if (unwind.personality_routine)
3816218822Sdim	size += md.pointer_size;
3817130561Sobrien    }
3818130561Sobrien
381984865Sobrien  /* If there are unwind records, switch sections, and output the info.  */
382084865Sobrien  if (size != 0)
382184865Sobrien    {
382284865Sobrien      expressionS exp;
382389857Sobrien      bfd_reloc_code_real_type reloc;
382484865Sobrien
3825218822Sdim      start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO);
382684865Sobrien
382789857Sobrien      /* Make sure the section has 4 byte alignment for ILP32 and
382889857Sobrien	 8 byte alignment for LP64.  */
382989857Sobrien      frag_align (md.pointer_size_shift, 0, 0);
383089857Sobrien      record_alignment (now_seg, md.pointer_size_shift);
383184865Sobrien
383284865Sobrien      /* Set expression which points to start of unwind descriptor area.  */
383384865Sobrien      unwind.info = expr_build_dot ();
3834130561Sobrien
3835130561Sobrien      frag_var (rs_machine_dependent, size, size, 0, 0,
3836218822Sdim		(offsetT) (long) unwind.personality_routine,
3837218822Sdim		(char *) list);
383884865Sobrien
383984865Sobrien      /* Add the personality address to the image.  */
384084865Sobrien      if (unwind.personality_routine != 0)
384184865Sobrien	{
3842104834Sobrien	  exp.X_op = O_symbol;
384384865Sobrien	  exp.X_add_symbol = unwind.personality_routine;
384484865Sobrien	  exp.X_add_number = 0;
384589857Sobrien
384689857Sobrien	  if (md.flags & EF_IA_64_BE)
384789857Sobrien	    {
384889857Sobrien	      if (md.flags & EF_IA_64_ABI64)
384989857Sobrien		reloc = BFD_RELOC_IA64_LTOFF_FPTR64MSB;
385089857Sobrien	      else
385189857Sobrien		reloc = BFD_RELOC_IA64_LTOFF_FPTR32MSB;
385289857Sobrien	    }
3853104834Sobrien	  else
385489857Sobrien	    {
385589857Sobrien	      if (md.flags & EF_IA_64_ABI64)
385689857Sobrien		reloc = BFD_RELOC_IA64_LTOFF_FPTR64LSB;
385789857Sobrien	      else
385889857Sobrien		reloc = BFD_RELOC_IA64_LTOFF_FPTR32LSB;
385989857Sobrien	    }
386089857Sobrien
386189857Sobrien	  fix_new_exp (frag_now, frag_now_fix () - md.pointer_size,
3862104834Sobrien		       md.pointer_size, &exp, 0, reloc);
386384865Sobrien	  unwind.personality_routine = 0;
386484865Sobrien	}
386584865Sobrien    }
386684865Sobrien
386792828Sobrien  free_saved_prologue_counts ();
386884865Sobrien  unwind.list = unwind.tail = unwind.current_entry = NULL;
386984865Sobrien}
387084865Sobrien
387184865Sobrienstatic void
387284865Sobriendot_handlerdata (dummy)
387384865Sobrien     int dummy ATTRIBUTE_UNUSED;
387484865Sobrien{
3875218822Sdim  if (!in_procedure ("handlerdata"))
3876218822Sdim    return;
387784865Sobrien  unwind.force_unwind_entry = 1;
387884865Sobrien
387984865Sobrien  /* Remember which segment we're in so we can switch back after .endp */
388084865Sobrien  unwind.saved_text_seg = now_seg;
388184865Sobrien  unwind.saved_text_subseg = now_subseg;
388284865Sobrien
388384865Sobrien  /* Generate unwind info into unwind-info section and then leave that
388484865Sobrien     section as the currently active one so dataXX directives go into
388584865Sobrien     the language specific data area of the unwind info block.  */
3886218822Sdim  generate_unwind_image (now_seg);
388784865Sobrien  demand_empty_rest_of_line ();
388884865Sobrien}
388984865Sobrien
389084865Sobrienstatic void
389184865Sobriendot_unwentry (dummy)
389284865Sobrien     int dummy ATTRIBUTE_UNUSED;
389384865Sobrien{
3894218822Sdim  if (!in_procedure ("unwentry"))
3895218822Sdim    return;
389684865Sobrien  unwind.force_unwind_entry = 1;
389784865Sobrien  demand_empty_rest_of_line ();
389884865Sobrien}
389984865Sobrien
390084865Sobrienstatic void
390184865Sobriendot_altrp (dummy)
390284865Sobrien     int dummy ATTRIBUTE_UNUSED;
390384865Sobrien{
390484865Sobrien  expressionS e;
390584865Sobrien  unsigned reg;
390684865Sobrien
3907218822Sdim  if (!in_prologue ("altrp"))
3908218822Sdim    return;
3909218822Sdim
3910218822Sdim  parse_operand (&e, 0);
391184865Sobrien  reg = e.X_add_number - REG_BR;
3912218822Sdim  if (e.X_op != O_register || reg > 7)
3913218822Sdim    {
3914218822Sdim      as_bad ("First operand to .altrp not a valid branch register");
3915218822Sdim      reg = 0;
3916218822Sdim    }
3917218822Sdim  add_unwind_entry (output_rp_br (reg), 0);
391884865Sobrien}
391984865Sobrien
392084865Sobrienstatic void
392184865Sobriendot_savemem (psprel)
392284865Sobrien     int psprel;
392384865Sobrien{
392484865Sobrien  expressionS e1, e2;
392584865Sobrien  int sep;
392684865Sobrien  int reg1, val;
3927218822Sdim  const char * const po = psprel ? "savepsp" : "savesp";
392884865Sobrien
3929218822Sdim  if (!in_prologue (po))
3930218822Sdim    return;
393184865Sobrien
3932218822Sdim  sep = parse_operand (&e1, ',');
3933218822Sdim  if (sep == ',')
3934218822Sdim    sep = parse_operand (&e2, ',');
3935218822Sdim  else
3936218822Sdim    e2.X_op = O_absent;
3937218822Sdim
393884865Sobrien  reg1 = e1.X_add_number;
393984865Sobrien  val = e2.X_add_number;
394084865Sobrien
394184865Sobrien  /* Make sure its a valid ar.xxx reg, OR its br0, aka 'rp'.  */
3942218822Sdim  if (e1.X_op != O_register)
394384865Sobrien    {
3944218822Sdim      as_bad ("First operand to .%s not a register", po);
3945218822Sdim      reg1 = REG_PR; /* Anything valid is good here.  */
394684865Sobrien    }
3947218822Sdim  if (e2.X_op != O_constant)
3948218822Sdim    {
3949218822Sdim      as_bad ("Second operand to .%s not a constant", po);
3950218822Sdim      val = 0;
3951218822Sdim    }
395284865Sobrien
3953218822Sdim  switch (reg1)
395484865Sobrien    {
3955218822Sdim    case REG_AR + AR_BSP:
3956218822Sdim      add_unwind_entry (output_bsp_when (), sep);
3957218822Sdim      add_unwind_entry ((psprel
3958218822Sdim			 ? output_bsp_psprel
3959218822Sdim			 : output_bsp_sprel) (val), NOT_A_CHAR);
3960218822Sdim      break;
3961218822Sdim    case REG_AR + AR_BSPSTORE:
3962218822Sdim      add_unwind_entry (output_bspstore_when (), sep);
3963218822Sdim      add_unwind_entry ((psprel
3964218822Sdim			 ? output_bspstore_psprel
3965218822Sdim			 : output_bspstore_sprel) (val), NOT_A_CHAR);
3966218822Sdim      break;
3967218822Sdim    case REG_AR + AR_RNAT:
3968218822Sdim      add_unwind_entry (output_rnat_when (), sep);
3969218822Sdim      add_unwind_entry ((psprel
3970218822Sdim			 ? output_rnat_psprel
3971218822Sdim			 : output_rnat_sprel) (val), NOT_A_CHAR);
3972218822Sdim      break;
3973218822Sdim    case REG_AR + AR_UNAT:
3974218822Sdim      add_unwind_entry (output_unat_when (), sep);
3975218822Sdim      add_unwind_entry ((psprel
3976218822Sdim			 ? output_unat_psprel
3977218822Sdim			 : output_unat_sprel) (val), NOT_A_CHAR);
3978218822Sdim      break;
3979218822Sdim    case REG_AR + AR_FPSR:
3980218822Sdim      add_unwind_entry (output_fpsr_when (), sep);
3981218822Sdim      add_unwind_entry ((psprel
3982218822Sdim			 ? output_fpsr_psprel
3983218822Sdim			 : output_fpsr_sprel) (val), NOT_A_CHAR);
3984218822Sdim      break;
3985218822Sdim    case REG_AR + AR_PFS:
3986218822Sdim      add_unwind_entry (output_pfs_when (), sep);
3987218822Sdim      add_unwind_entry ((psprel
3988218822Sdim			 ? output_pfs_psprel
3989218822Sdim			 : output_pfs_sprel) (val), NOT_A_CHAR);
3990218822Sdim      break;
3991218822Sdim    case REG_AR + AR_LC:
3992218822Sdim      add_unwind_entry (output_lc_when (), sep);
3993218822Sdim      add_unwind_entry ((psprel
3994218822Sdim			 ? output_lc_psprel
3995218822Sdim			 : output_lc_sprel) (val), NOT_A_CHAR);
3996218822Sdim      break;
3997218822Sdim    case REG_BR:
3998218822Sdim      add_unwind_entry (output_rp_when (), sep);
3999218822Sdim      add_unwind_entry ((psprel
4000218822Sdim			 ? output_rp_psprel
4001218822Sdim			 : output_rp_sprel) (val), NOT_A_CHAR);
4002218822Sdim      break;
4003218822Sdim    case REG_PR:
4004218822Sdim      add_unwind_entry (output_preds_when (), sep);
4005218822Sdim      add_unwind_entry ((psprel
4006218822Sdim			 ? output_preds_psprel
4007218822Sdim			 : output_preds_sprel) (val), NOT_A_CHAR);
4008218822Sdim      break;
4009218822Sdim    case REG_PRIUNAT:
4010218822Sdim      add_unwind_entry (output_priunat_when_mem (), sep);
4011218822Sdim      add_unwind_entry ((psprel
4012218822Sdim			 ? output_priunat_psprel
4013218822Sdim			 : output_priunat_sprel) (val), NOT_A_CHAR);
4014218822Sdim      break;
4015218822Sdim    default:
4016218822Sdim      as_bad ("First operand to .%s not a valid register", po);
4017218822Sdim      add_unwind_entry (NULL, sep);
4018218822Sdim      break;
401984865Sobrien    }
402084865Sobrien}
402184865Sobrien
402284865Sobrienstatic void
4023218822Sdimdot_saveg (dummy)
402484865Sobrien     int dummy ATTRIBUTE_UNUSED;
402584865Sobrien{
4026218822Sdim  expressionS e;
4027218822Sdim  unsigned grmask;
402884865Sobrien  int sep;
402984865Sobrien
4030218822Sdim  if (!in_prologue ("save.g"))
4031218822Sdim    return;
403284865Sobrien
4033218822Sdim  sep = parse_operand (&e, ',');
403484865Sobrien
4035218822Sdim  grmask = e.X_add_number;
4036218822Sdim  if (e.X_op != O_constant
4037218822Sdim      || e.X_add_number <= 0
4038218822Sdim      || e.X_add_number > 0xf)
403984865Sobrien    {
4040218822Sdim      as_bad ("First operand to .save.g must be a positive 4-bit constant");
4041218822Sdim      grmask = 0;
404284865Sobrien    }
404384865Sobrien
404484865Sobrien  if (sep == ',')
404584865Sobrien    {
4046218822Sdim      unsigned reg;
4047218822Sdim      int n = popcount (grmask);
4048218822Sdim
4049218822Sdim      parse_operand (&e, 0);
4050218822Sdim      reg = e.X_add_number - REG_GR;
4051218822Sdim      if (e.X_op != O_register || reg > 127)
405284865Sobrien	{
4053218822Sdim	  as_bad ("Second operand to .save.g must be a general register");
4054218822Sdim	  reg = 0;
405584865Sobrien	}
4056218822Sdim      else if (reg > 128U - n)
4057218822Sdim	{
4058218822Sdim	  as_bad ("Second operand to .save.g must be the first of %d general registers", n);
4059218822Sdim	  reg = 0;
4060218822Sdim	}
4061218822Sdim      add_unwind_entry (output_gr_gr (grmask, reg), 0);
406284865Sobrien    }
406384865Sobrien  else
4064218822Sdim    add_unwind_entry (output_gr_mem (grmask), 0);
406584865Sobrien}
406684865Sobrien
406784865Sobrienstatic void
4068218822Sdimdot_savef (dummy)
406984865Sobrien     int dummy ATTRIBUTE_UNUSED;
407084865Sobrien{
4071218822Sdim  expressionS e;
407284865Sobrien
4073218822Sdim  if (!in_prologue ("save.f"))
4074218822Sdim    return;
4075218822Sdim
4076218822Sdim  parse_operand (&e, 0);
4077218822Sdim
4078218822Sdim  if (e.X_op != O_constant
4079218822Sdim      || e.X_add_number <= 0
4080218822Sdim      || e.X_add_number > 0xfffff)
408184865Sobrien    {
4082218822Sdim      as_bad ("Operand to .save.f must be a positive 20-bit constant");
4083218822Sdim      e.X_add_number = 0;
408484865Sobrien    }
4085218822Sdim  add_unwind_entry (output_fr_mem (e.X_add_number), 0);
408684865Sobrien}
408784865Sobrien
408884865Sobrienstatic void
4089218822Sdimdot_saveb (dummy)
409084865Sobrien     int dummy ATTRIBUTE_UNUSED;
409184865Sobrien{
409284865Sobrien  expressionS e;
4093218822Sdim  unsigned brmask;
4094218822Sdim  int sep;
409584865Sobrien
4096218822Sdim  if (!in_prologue ("save.b"))
4097218822Sdim    return;
409884865Sobrien
4099218822Sdim  sep = parse_operand (&e, ',');
410084865Sobrien
4101218822Sdim  brmask = e.X_add_number;
4102218822Sdim  if (e.X_op != O_constant
4103218822Sdim      || e.X_add_number <= 0
4104218822Sdim      || e.X_add_number > 0x1f)
410584865Sobrien    {
4106218822Sdim      as_bad ("First operand to .save.b must be a positive 5-bit constant");
4107218822Sdim      brmask = 0;
410884865Sobrien    }
410984865Sobrien
4110218822Sdim  if (sep == ',')
411184865Sobrien    {
4112218822Sdim      unsigned reg;
4113218822Sdim      int n = popcount (brmask);
411484865Sobrien
4115218822Sdim      parse_operand (&e, 0);
4116218822Sdim      reg = e.X_add_number - REG_GR;
4117218822Sdim      if (e.X_op != O_register || reg > 127)
4118218822Sdim	{
4119218822Sdim	  as_bad ("Second operand to .save.b must be a general register");
4120218822Sdim	  reg = 0;
4121218822Sdim	}
4122218822Sdim      else if (reg > 128U - n)
4123218822Sdim	{
4124218822Sdim	  as_bad ("Second operand to .save.b must be the first of %d general registers", n);
4125218822Sdim	  reg = 0;
4126218822Sdim	}
4127218822Sdim      add_unwind_entry (output_br_gr (brmask, reg), 0);
412884865Sobrien    }
4129218822Sdim  else
4130218822Sdim    add_unwind_entry (output_br_mem (brmask), 0);
413184865Sobrien}
413284865Sobrien
413384865Sobrienstatic void
4134218822Sdimdot_savegf (dummy)
4135218822Sdim     int dummy ATTRIBUTE_UNUSED;
413684865Sobrien{
413784865Sobrien  expressionS e1, e2;
413884865Sobrien
4139218822Sdim  if (!in_prologue ("save.gf"))
4140218822Sdim    return;
414184865Sobrien
4142218822Sdim  if (parse_operand (&e1, ',') == ',')
4143218822Sdim    parse_operand (&e2, 0);
4144218822Sdim  else
4145218822Sdim    e2.X_op = O_absent;
414684865Sobrien
4147218822Sdim  if (e1.X_op != O_constant
4148218822Sdim      || e1.X_add_number < 0
4149218822Sdim      || e1.X_add_number > 0xf)
415084865Sobrien    {
4151218822Sdim      as_bad ("First operand to .save.gf must be a non-negative 4-bit constant");
4152218822Sdim      e1.X_op = O_absent;
4153218822Sdim      e1.X_add_number = 0;
415484865Sobrien    }
4155218822Sdim  if (e2.X_op != O_constant
4156218822Sdim      || e2.X_add_number < 0
4157218822Sdim      || e2.X_add_number > 0xfffff)
415884865Sobrien    {
4159218822Sdim      as_bad ("Second operand to .save.gf must be a non-negative 20-bit constant");
4160218822Sdim      e2.X_op = O_absent;
4161218822Sdim      e2.X_add_number = 0;
416284865Sobrien    }
4163218822Sdim  if (e1.X_op == O_constant
4164218822Sdim      && e2.X_op == O_constant
4165218822Sdim      && e1.X_add_number == 0
4166218822Sdim      && e2.X_add_number == 0)
4167218822Sdim    as_bad ("Operands to .save.gf may not be both zero");
416884865Sobrien
4169218822Sdim  add_unwind_entry (output_frgr_mem (e1.X_add_number, e2.X_add_number), 0);
417084865Sobrien}
417184865Sobrien
417284865Sobrienstatic void
4173218822Sdimdot_spill (dummy)
417484865Sobrien     int dummy ATTRIBUTE_UNUSED;
417584865Sobrien{
4176218822Sdim  expressionS e;
417784865Sobrien
4178218822Sdim  if (!in_prologue ("spill"))
4179218822Sdim    return;
418084865Sobrien
4181218822Sdim  parse_operand (&e, 0);
4182218822Sdim
4183218822Sdim  if (e.X_op != O_constant)
418484865Sobrien    {
4185218822Sdim      as_bad ("Operand to .spill must be a constant");
4186218822Sdim      e.X_add_number = 0;
418784865Sobrien    }
4188218822Sdim  add_unwind_entry (output_spill_base (e.X_add_number), 0);
4189218822Sdim}
419084865Sobrien
4191218822Sdimstatic void
4192218822Sdimdot_spillreg (pred)
4193218822Sdim     int pred;
4194218822Sdim{
4195218822Sdim  int sep;
4196218822Sdim  unsigned int qp, ab, xy, reg, treg;
4197218822Sdim  expressionS e;
4198218822Sdim  const char * const po = pred ? "spillreg.p" : "spillreg";
419984865Sobrien
4200218822Sdim  if (!in_procedure (po))
4201218822Sdim    return;
420284865Sobrien
4203218822Sdim  if (pred)
4204218822Sdim    sep = parse_predicate_and_operand (&e, &qp, po);
4205218822Sdim  else
420684865Sobrien    {
4207218822Sdim      sep = parse_operand (&e, ',');
4208218822Sdim      qp = 0;
420984865Sobrien    }
4210218822Sdim  convert_expr_to_ab_reg (&e, &ab, &reg, po, 1 + pred);
421184865Sobrien
4212218822Sdim  if (sep == ',')
4213218822Sdim    sep = parse_operand (&e, ',');
4214218822Sdim  else
4215218822Sdim    e.X_op = O_absent;
4216218822Sdim  convert_expr_to_xy_reg (&e, &xy, &treg, po, 2 + pred);
421784865Sobrien
4218218822Sdim  add_unwind_entry (output_spill_reg (ab, reg, treg, xy, qp), sep);
421984865Sobrien}
422084865Sobrien
422184865Sobrienstatic void
4222218822Sdimdot_spillmem (psprel)
422384865Sobrien     int psprel;
422484865Sobrien{
4225218822Sdim  expressionS e;
4226218822Sdim  int pred = (psprel < 0), sep;
4227218822Sdim  unsigned int qp, ab, reg;
4228218822Sdim  const char * po;
422984865Sobrien
4230218822Sdim  if (pred)
423184865Sobrien    {
4232218822Sdim      psprel = ~psprel;
4233218822Sdim      po = psprel ? "spillpsp.p" : "spillsp.p";
423484865Sobrien    }
4235218822Sdim  else
4236218822Sdim    po = psprel ? "spillpsp" : "spillsp";
423784865Sobrien
4238218822Sdim  if (!in_procedure (po))
4239218822Sdim    return;
424084865Sobrien
4241218822Sdim  if (pred)
4242218822Sdim    sep = parse_predicate_and_operand (&e, &qp, po);
4243218822Sdim  else
424484865Sobrien    {
4245218822Sdim      sep = parse_operand (&e, ',');
4246218822Sdim      qp = 0;
424784865Sobrien    }
4248218822Sdim  convert_expr_to_ab_reg (&e, &ab, &reg, po, 1 + pred);
424984865Sobrien
4250218822Sdim  if (sep == ',')
4251218822Sdim    sep = parse_operand (&e, ',');
4252218822Sdim  else
4253218822Sdim    e.X_op = O_absent;
4254218822Sdim  if (e.X_op != O_constant)
425584865Sobrien    {
4256218822Sdim      as_bad ("Operand %d to .%s must be a constant", 2 + pred, po);
4257218822Sdim      e.X_add_number = 0;
425884865Sobrien    }
425984865Sobrien
426084865Sobrien  if (psprel)
4261218822Sdim    add_unwind_entry (output_spill_psprel (ab, reg, e.X_add_number, qp), sep);
426284865Sobrien  else
4263218822Sdim    add_unwind_entry (output_spill_sprel (ab, reg, e.X_add_number, qp), sep);
426484865Sobrien}
426584865Sobrien
426692828Sobrienstatic unsigned int
426792828Sobrienget_saved_prologue_count (lbl)
426892828Sobrien     unsigned long lbl;
426992828Sobrien{
427092828Sobrien  label_prologue_count *lpc = unwind.saved_prologue_counts;
427192828Sobrien
427292828Sobrien  while (lpc != NULL && lpc->label_number != lbl)
427392828Sobrien    lpc = lpc->next;
427492828Sobrien
427592828Sobrien  if (lpc != NULL)
427692828Sobrien    return lpc->prologue_count;
427792828Sobrien
427892828Sobrien  as_bad ("Missing .label_state %ld", lbl);
427992828Sobrien  return 1;
428092828Sobrien}
428192828Sobrien
428284865Sobrienstatic void
428392828Sobriensave_prologue_count (lbl, count)
428492828Sobrien     unsigned long lbl;
428592828Sobrien     unsigned int count;
428692828Sobrien{
428792828Sobrien  label_prologue_count *lpc = unwind.saved_prologue_counts;
428892828Sobrien
428992828Sobrien  while (lpc != NULL && lpc->label_number != lbl)
429092828Sobrien    lpc = lpc->next;
429192828Sobrien
429292828Sobrien  if (lpc != NULL)
429392828Sobrien    lpc->prologue_count = count;
429492828Sobrien  else
429592828Sobrien    {
4296104834Sobrien      label_prologue_count *new_lpc = xmalloc (sizeof (* new_lpc));
429792828Sobrien
429892828Sobrien      new_lpc->next = unwind.saved_prologue_counts;
429992828Sobrien      new_lpc->label_number = lbl;
430092828Sobrien      new_lpc->prologue_count = count;
430192828Sobrien      unwind.saved_prologue_counts = new_lpc;
430292828Sobrien    }
430392828Sobrien}
430492828Sobrien
430592828Sobrienstatic void
430692828Sobrienfree_saved_prologue_counts ()
430792828Sobrien{
4308104834Sobrien  label_prologue_count *lpc = unwind.saved_prologue_counts;
4309104834Sobrien  label_prologue_count *next;
431092828Sobrien
431192828Sobrien  while (lpc != NULL)
431292828Sobrien    {
431392828Sobrien      next = lpc->next;
431492828Sobrien      free (lpc);
431592828Sobrien      lpc = next;
431692828Sobrien    }
431792828Sobrien
431892828Sobrien  unwind.saved_prologue_counts = NULL;
431992828Sobrien}
432092828Sobrien
432192828Sobrienstatic void
432284865Sobriendot_label_state (dummy)
432384865Sobrien     int dummy ATTRIBUTE_UNUSED;
432484865Sobrien{
432584865Sobrien  expressionS e;
432684865Sobrien
4327218822Sdim  if (!in_body ("label_state"))
4328218822Sdim    return;
4329218822Sdim
4330218822Sdim  parse_operand (&e, 0);
4331218822Sdim  if (e.X_op == O_constant)
4332218822Sdim    save_prologue_count (e.X_add_number, unwind.prologue_count);
4333218822Sdim  else
433484865Sobrien    {
433584865Sobrien      as_bad ("Operand to .label_state must be a constant");
4336218822Sdim      e.X_add_number = 0;
433784865Sobrien    }
4338218822Sdim  add_unwind_entry (output_label_state (e.X_add_number), 0);
433984865Sobrien}
434084865Sobrien
434184865Sobrienstatic void
434284865Sobriendot_copy_state (dummy)
434384865Sobrien     int dummy ATTRIBUTE_UNUSED;
434484865Sobrien{
434584865Sobrien  expressionS e;
434684865Sobrien
4347218822Sdim  if (!in_body ("copy_state"))
4348218822Sdim    return;
4349218822Sdim
4350218822Sdim  parse_operand (&e, 0);
4351218822Sdim  if (e.X_op == O_constant)
4352218822Sdim    unwind.prologue_count = get_saved_prologue_count (e.X_add_number);
4353218822Sdim  else
435484865Sobrien    {
435584865Sobrien      as_bad ("Operand to .copy_state must be a constant");
4356218822Sdim      e.X_add_number = 0;
435784865Sobrien    }
4358218822Sdim  add_unwind_entry (output_copy_state (e.X_add_number), 0);
435984865Sobrien}
436084865Sobrien
436184865Sobrienstatic void
436284865Sobriendot_unwabi (dummy)
436384865Sobrien     int dummy ATTRIBUTE_UNUSED;
436484865Sobrien{
436584865Sobrien  expressionS e1, e2;
436684865Sobrien  unsigned char sep;
436784865Sobrien
4368218822Sdim  if (!in_prologue ("unwabi"))
4369218822Sdim    return;
437084865Sobrien
4371218822Sdim  sep = parse_operand (&e1, ',');
4372218822Sdim  if (sep == ',')
4373218822Sdim    parse_operand (&e2, 0);
4374218822Sdim  else
4375218822Sdim    e2.X_op = O_absent;
4376218822Sdim
437784865Sobrien  if (e1.X_op != O_constant)
437884865Sobrien    {
437984865Sobrien      as_bad ("First operand to .unwabi must be a constant");
4380218822Sdim      e1.X_add_number = 0;
438184865Sobrien    }
438284865Sobrien
438384865Sobrien  if (e2.X_op != O_constant)
438484865Sobrien    {
438584865Sobrien      as_bad ("Second operand to .unwabi must be a constant");
4386218822Sdim      e2.X_add_number = 0;
438784865Sobrien    }
438884865Sobrien
4389218822Sdim  add_unwind_entry (output_unwabi (e1.X_add_number, e2.X_add_number), 0);
439084865Sobrien}
439184865Sobrien
439284865Sobrienstatic void
439384865Sobriendot_personality (dummy)
439484865Sobrien     int dummy ATTRIBUTE_UNUSED;
439584865Sobrien{
439684865Sobrien  char *name, *p, c;
4397218822Sdim  if (!in_procedure ("personality"))
4398218822Sdim    return;
439984865Sobrien  SKIP_WHITESPACE ();
440084865Sobrien  name = input_line_pointer;
440184865Sobrien  c = get_symbol_end ();
440284865Sobrien  p = input_line_pointer;
440384865Sobrien  unwind.personality_routine = symbol_find_or_make (name);
440484865Sobrien  unwind.force_unwind_entry = 1;
440584865Sobrien  *p = c;
440684865Sobrien  SKIP_WHITESPACE ();
440784865Sobrien  demand_empty_rest_of_line ();
440884865Sobrien}
440984865Sobrien
441084865Sobrienstatic void
441184865Sobriendot_proc (dummy)
441284865Sobrien     int dummy ATTRIBUTE_UNUSED;
441384865Sobrien{
441484865Sobrien  char *name, *p, c;
441584865Sobrien  symbolS *sym;
4416218822Sdim  proc_pending *pending, *last_pending;
441784865Sobrien
4418218822Sdim  if (unwind.proc_pending.sym)
4419218822Sdim    {
4420218822Sdim      (md.unwind_check == unwind_check_warning
4421218822Sdim       ? as_warn
4422218822Sdim       : as_bad) ("Missing .endp after previous .proc");
4423218822Sdim      while (unwind.proc_pending.next)
4424218822Sdim	{
4425218822Sdim	  pending = unwind.proc_pending.next;
4426218822Sdim	  unwind.proc_pending.next = pending->next;
4427218822Sdim	  free (pending);
4428218822Sdim	}
4429218822Sdim    }
4430218822Sdim  last_pending = NULL;
4431218822Sdim
443284865Sobrien  /* Parse names of main and alternate entry points and mark them as
443384865Sobrien     function symbols:  */
443484865Sobrien  while (1)
443584865Sobrien    {
443684865Sobrien      SKIP_WHITESPACE ();
443784865Sobrien      name = input_line_pointer;
443884865Sobrien      c = get_symbol_end ();
443984865Sobrien      p = input_line_pointer;
4440218822Sdim      if (!*name)
4441218822Sdim	as_bad ("Empty argument of .proc");
4442218822Sdim      else
444384865Sobrien	{
4444218822Sdim	  sym = symbol_find_or_make (name);
4445218822Sdim	  if (S_IS_DEFINED (sym))
4446218822Sdim	    as_bad ("`%s' was already defined", name);
4447218822Sdim	  else if (!last_pending)
4448218822Sdim	    {
4449218822Sdim	      unwind.proc_pending.sym = sym;
4450218822Sdim	      last_pending = &unwind.proc_pending;
4451218822Sdim	    }
4452218822Sdim	  else
4453218822Sdim	    {
4454218822Sdim	      pending = xmalloc (sizeof (*pending));
4455218822Sdim	      pending->sym = sym;
4456218822Sdim	      last_pending = last_pending->next = pending;
4457218822Sdim	    }
4458218822Sdim	  symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
445984865Sobrien	}
446084865Sobrien      *p = c;
446184865Sobrien      SKIP_WHITESPACE ();
446284865Sobrien      if (*input_line_pointer != ',')
446384865Sobrien	break;
446484865Sobrien      ++input_line_pointer;
446584865Sobrien    }
4466218822Sdim  if (!last_pending)
4467218822Sdim    {
4468218822Sdim      unwind.proc_pending.sym = expr_build_dot ();
4469218822Sdim      last_pending = &unwind.proc_pending;
4470218822Sdim    }
4471218822Sdim  last_pending->next = NULL;
447284865Sobrien  demand_empty_rest_of_line ();
447384865Sobrien  ia64_do_align (16);
447484865Sobrien
4475218822Sdim  unwind.prologue = 0;
447684865Sobrien  unwind.prologue_count = 0;
4477218822Sdim  unwind.body = 0;
4478218822Sdim  unwind.insn = 0;
447984865Sobrien  unwind.list = unwind.tail = unwind.current_entry = NULL;
448084865Sobrien  unwind.personality_routine = 0;
448184865Sobrien}
448284865Sobrien
448384865Sobrienstatic void
448484865Sobriendot_body (dummy)
448584865Sobrien     int dummy ATTRIBUTE_UNUSED;
448684865Sobrien{
4487218822Sdim  if (!in_procedure ("body"))
4488218822Sdim    return;
4489218822Sdim  if (!unwind.prologue && !unwind.body && unwind.insn)
4490218822Sdim    as_warn ("Initial .body should precede any instructions");
4491218822Sdim  check_pending_save ();
4492218822Sdim
449384865Sobrien  unwind.prologue = 0;
449484865Sobrien  unwind.prologue_mask = 0;
4495218822Sdim  unwind.body = 1;
449684865Sobrien
4497218822Sdim  add_unwind_entry (output_body (), 0);
449884865Sobrien}
449984865Sobrien
450084865Sobrienstatic void
450184865Sobriendot_prologue (dummy)
450284865Sobrien     int dummy ATTRIBUTE_UNUSED;
450384865Sobrien{
4504218822Sdim  unsigned mask = 0, grsave = 0;
450584865Sobrien
4506218822Sdim  if (!in_procedure ("prologue"))
4507218822Sdim    return;
4508218822Sdim  if (unwind.prologue)
4509218822Sdim    {
4510218822Sdim      as_bad (".prologue within prologue");
4511218822Sdim      ignore_rest_of_line ();
4512218822Sdim      return;
4513218822Sdim    }
4514218822Sdim  if (!unwind.body && unwind.insn)
4515218822Sdim    as_warn ("Initial .prologue should precede any instructions");
4516218822Sdim
451784865Sobrien  if (!is_it_end_of_statement ())
451884865Sobrien    {
4519218822Sdim      expressionS e;
4520218822Sdim      int n, sep = parse_operand (&e, ',');
452184865Sobrien
4522218822Sdim      if (e.X_op != O_constant
4523218822Sdim	  || e.X_add_number < 0
4524218822Sdim	  || e.X_add_number > 0xf)
4525218822Sdim	as_bad ("First operand to .prologue must be a positive 4-bit constant");
4526218822Sdim      else if (e.X_add_number == 0)
4527218822Sdim	as_warn ("Pointless use of zero first operand to .prologue");
4528218822Sdim      else
4529218822Sdim	mask = e.X_add_number;
4530218822Sdim	n = popcount (mask);
4531218822Sdim
4532218822Sdim      if (sep == ',')
4533218822Sdim	parse_operand (&e, 0);
4534218822Sdim      else
4535218822Sdim	e.X_op = O_absent;
4536218822Sdim      if (e.X_op == O_constant
4537218822Sdim	  && e.X_add_number >= 0
4538218822Sdim	  && e.X_add_number < 128)
453984865Sobrien	{
4540218822Sdim	  if (md.unwind_check == unwind_check_error)
4541218822Sdim	    as_warn ("Using a constant as second operand to .prologue is deprecated");
4542218822Sdim	  grsave = e.X_add_number;
4543218822Sdim	}
4544218822Sdim      else if (e.X_op != O_register
4545218822Sdim	       || (grsave = e.X_add_number - REG_GR) > 127)
4546218822Sdim	{
4547218822Sdim	  as_bad ("Second operand to .prologue must be a general register");
4548218822Sdim	  grsave = 0;
4549218822Sdim	}
4550218822Sdim      else if (grsave > 128U - n)
4551218822Sdim	{
4552218822Sdim	  as_bad ("Second operand to .prologue must be the first of %d general registers", n);
4553218822Sdim	  grsave = 0;
4554218822Sdim	}
455584865Sobrien
4556218822Sdim    }
455784865Sobrien
4558218822Sdim  if (mask)
4559218822Sdim    add_unwind_entry (output_prologue_gr (mask, grsave), 0);
456084865Sobrien  else
4561218822Sdim    add_unwind_entry (output_prologue (), 0);
456284865Sobrien
456384865Sobrien  unwind.prologue = 1;
456484865Sobrien  unwind.prologue_mask = mask;
4565218822Sdim  unwind.prologue_gr = grsave;
4566218822Sdim  unwind.body = 0;
456784865Sobrien  ++unwind.prologue_count;
456884865Sobrien}
456984865Sobrien
457084865Sobrienstatic void
457184865Sobriendot_endp (dummy)
457284865Sobrien     int dummy ATTRIBUTE_UNUSED;
457384865Sobrien{
457484865Sobrien  expressionS e;
457584865Sobrien  int bytes_per_address;
457684865Sobrien  long where;
457784865Sobrien  segT saved_seg;
457884865Sobrien  subsegT saved_subseg;
4579218822Sdim  proc_pending *pending;
4580218822Sdim  int unwind_check = md.unwind_check;
458184865Sobrien
4582218822Sdim  md.unwind_check = unwind_check_error;
4583218822Sdim  if (!in_procedure ("endp"))
4584218822Sdim    return;
4585218822Sdim  md.unwind_check = unwind_check;
4586218822Sdim
458784865Sobrien  if (unwind.saved_text_seg)
458884865Sobrien    {
458984865Sobrien      saved_seg = unwind.saved_text_seg;
459084865Sobrien      saved_subseg = unwind.saved_text_subseg;
459184865Sobrien      unwind.saved_text_seg = NULL;
459284865Sobrien    }
459384865Sobrien  else
459484865Sobrien    {
459584865Sobrien      saved_seg = now_seg;
459684865Sobrien      saved_subseg = now_subseg;
459784865Sobrien    }
459884865Sobrien
459984865Sobrien  insn_group_break (1, 0, 0);
460084865Sobrien
460184865Sobrien  /* If there wasn't a .handlerdata, we haven't generated an image yet.  */
460284865Sobrien  if (!unwind.info)
4603218822Sdim    generate_unwind_image (saved_seg);
460484865Sobrien
460584865Sobrien  if (unwind.info || unwind.force_unwind_entry)
460684865Sobrien    {
4607218822Sdim      symbolS *proc_end;
4608218822Sdim
460984865Sobrien      subseg_set (md.last_text_seg, 0);
4610218822Sdim      proc_end = expr_build_dot ();
461184865Sobrien
4612218822Sdim      start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND);
461384865Sobrien
461489857Sobrien      /* Make sure that section has 4 byte alignment for ILP32 and
461589857Sobrien         8 byte alignment for LP64.  */
461689857Sobrien      record_alignment (now_seg, md.pointer_size_shift);
461784865Sobrien
461889857Sobrien      /* Need space for 3 pointers for procedure start, procedure end,
461989857Sobrien	 and unwind info.  */
4620218822Sdim      memset (frag_more (3 * md.pointer_size), 0, 3 * md.pointer_size);
462189857Sobrien      where = frag_now_fix () - (3 * md.pointer_size);
462284865Sobrien      bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
462384865Sobrien
4624104834Sobrien      /* Issue the values of  a) Proc Begin, b) Proc End, c) Unwind Record.  */
462584865Sobrien      e.X_op = O_pseudo_fixup;
462684865Sobrien      e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
462784865Sobrien      e.X_add_number = 0;
4628218822Sdim      if (!S_IS_LOCAL (unwind.proc_pending.sym)
4629218822Sdim	  && S_IS_DEFINED (unwind.proc_pending.sym))
4630218822Sdim	e.X_add_symbol = symbol_temp_new (S_GET_SEGMENT (unwind.proc_pending.sym),
4631218822Sdim					  S_GET_VALUE (unwind.proc_pending.sym),
4632218822Sdim					  symbol_get_frag (unwind.proc_pending.sym));
4633218822Sdim      else
4634218822Sdim	e.X_add_symbol = unwind.proc_pending.sym;
463584865Sobrien      ia64_cons_fix_new (frag_now, where, bytes_per_address, &e);
463684865Sobrien
463784865Sobrien      e.X_op = O_pseudo_fixup;
463884865Sobrien      e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
463984865Sobrien      e.X_add_number = 0;
4640218822Sdim      e.X_add_symbol = proc_end;
464184865Sobrien      ia64_cons_fix_new (frag_now, where + bytes_per_address,
464284865Sobrien			 bytes_per_address, &e);
464384865Sobrien
464484865Sobrien      if (unwind.info)
464584865Sobrien	{
464684865Sobrien	  e.X_op = O_pseudo_fixup;
464784865Sobrien	  e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
464884865Sobrien	  e.X_add_number = 0;
464984865Sobrien	  e.X_add_symbol = unwind.info;
465084865Sobrien	  ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2),
465184865Sobrien			     bytes_per_address, &e);
465284865Sobrien	}
465384865Sobrien    }
465484865Sobrien  subseg_set (saved_seg, saved_subseg);
465589857Sobrien
4656218822Sdim  /* Set symbol sizes.  */
4657218822Sdim  pending = &unwind.proc_pending;
4658218822Sdim  if (S_GET_NAME (pending->sym))
4659218822Sdim    {
4660218822Sdim      do
4661218822Sdim	{
4662218822Sdim	  symbolS *sym = pending->sym;
4663218822Sdim
4664218822Sdim	  if (!S_IS_DEFINED (sym))
4665218822Sdim	    as_bad ("`%s' was not defined within procedure", S_GET_NAME (sym));
4666218822Sdim	  else if (S_GET_SIZE (sym) == 0
4667218822Sdim		   && symbol_get_obj (sym)->size == NULL)
4668218822Sdim	    {
4669218822Sdim	      fragS *frag = symbol_get_frag (sym);
4670218822Sdim
4671218822Sdim	      if (frag)
4672218822Sdim		{
4673218822Sdim		  if (frag == frag_now && SEG_NORMAL (now_seg))
4674218822Sdim		    S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
4675218822Sdim		  else
4676218822Sdim		    {
4677218822Sdim		      symbol_get_obj (sym)->size =
4678218822Sdim			(expressionS *) xmalloc (sizeof (expressionS));
4679218822Sdim		      symbol_get_obj (sym)->size->X_op = O_subtract;
4680218822Sdim		      symbol_get_obj (sym)->size->X_add_symbol
4681218822Sdim			= symbol_new (FAKE_LABEL_NAME, now_seg,
4682218822Sdim				      frag_now_fix (), frag_now);
4683218822Sdim		      symbol_get_obj (sym)->size->X_op_symbol = sym;
4684218822Sdim		      symbol_get_obj (sym)->size->X_add_number = 0;
4685218822Sdim		    }
4686218822Sdim		}
4687218822Sdim	    }
4688218822Sdim	} while ((pending = pending->next) != NULL);
4689218822Sdim    }
4690218822Sdim
4691218822Sdim  /* Parse names of main and alternate entry points.  */
469289857Sobrien  while (1)
469389857Sobrien    {
4694218822Sdim      char *name, *p, c;
4695218822Sdim
469689857Sobrien      SKIP_WHITESPACE ();
469789857Sobrien      name = input_line_pointer;
469889857Sobrien      c = get_symbol_end ();
469989857Sobrien      p = input_line_pointer;
4700218822Sdim      if (!*name)
4701218822Sdim	(md.unwind_check == unwind_check_warning
4702218822Sdim	 ? as_warn
4703218822Sdim	 : as_bad) ("Empty argument of .endp");
4704218822Sdim      else
470589857Sobrien	{
4706218822Sdim	  symbolS *sym = symbol_find (name);
470789857Sobrien
4708218822Sdim	  for (pending = &unwind.proc_pending; pending; pending = pending->next)
470989857Sobrien	    {
4710218822Sdim	      if (sym == pending->sym)
471189857Sobrien		{
4712218822Sdim		  pending->sym = NULL;
4713218822Sdim		  break;
471489857Sobrien		}
471589857Sobrien	    }
4716218822Sdim	  if (!sym || !pending)
4717218822Sdim	    as_warn ("`%s' was not specified with previous .proc", name);
471889857Sobrien	}
471989857Sobrien      *p = c;
472089857Sobrien      SKIP_WHITESPACE ();
472189857Sobrien      if (*input_line_pointer != ',')
472289857Sobrien	break;
472389857Sobrien      ++input_line_pointer;
472489857Sobrien    }
472589857Sobrien  demand_empty_rest_of_line ();
4726218822Sdim
4727218822Sdim  /* Deliberately only checking for the main entry point here; the
4728218822Sdim     language spec even says all arguments to .endp are ignored.  */
4729218822Sdim  if (unwind.proc_pending.sym
4730218822Sdim      && S_GET_NAME (unwind.proc_pending.sym)
4731218822Sdim      && strcmp (S_GET_NAME (unwind.proc_pending.sym), FAKE_LABEL_NAME))
4732218822Sdim    as_warn ("`%s' should be an operand to this .endp",
4733218822Sdim	     S_GET_NAME (unwind.proc_pending.sym));
4734218822Sdim  while (unwind.proc_pending.next)
4735218822Sdim    {
4736218822Sdim      pending = unwind.proc_pending.next;
4737218822Sdim      unwind.proc_pending.next = pending->next;
4738218822Sdim      free (pending);
4739218822Sdim    }
4740218822Sdim  unwind.proc_pending.sym = unwind.info = NULL;
474184865Sobrien}
474284865Sobrien
474384865Sobrienstatic void
474484865Sobriendot_template (template)
474584865Sobrien     int template;
474684865Sobrien{
474784865Sobrien  CURR_SLOT.user_template = template;
474884865Sobrien}
474984865Sobrien
475084865Sobrienstatic void
475184865Sobriendot_regstk (dummy)
475284865Sobrien     int dummy ATTRIBUTE_UNUSED;
475384865Sobrien{
475484865Sobrien  int ins, locs, outs, rots;
475584865Sobrien
475684865Sobrien  if (is_it_end_of_statement ())
475784865Sobrien    ins = locs = outs = rots = 0;
475884865Sobrien  else
475984865Sobrien    {
476084865Sobrien      ins = get_absolute_expression ();
476184865Sobrien      if (*input_line_pointer++ != ',')
476284865Sobrien	goto err;
476384865Sobrien      locs = get_absolute_expression ();
476484865Sobrien      if (*input_line_pointer++ != ',')
476584865Sobrien	goto err;
476684865Sobrien      outs = get_absolute_expression ();
476784865Sobrien      if (*input_line_pointer++ != ',')
476884865Sobrien	goto err;
476984865Sobrien      rots = get_absolute_expression ();
477084865Sobrien    }
477184865Sobrien  set_regstack (ins, locs, outs, rots);
477284865Sobrien  return;
477384865Sobrien
477484865Sobrien err:
477584865Sobrien  as_bad ("Comma expected");
477684865Sobrien  ignore_rest_of_line ();
477784865Sobrien}
477884865Sobrien
477984865Sobrienstatic void
478084865Sobriendot_rot (type)
478184865Sobrien     int type;
478284865Sobrien{
4783218822Sdim  offsetT num_regs;
4784218822Sdim  valueT num_alloced = 0;
478584865Sobrien  struct dynreg **drpp, *dr;
478684865Sobrien  int ch, base_reg = 0;
478784865Sobrien  char *name, *start;
478884865Sobrien  size_t len;
478984865Sobrien
479084865Sobrien  switch (type)
479184865Sobrien    {
479284865Sobrien    case DYNREG_GR: base_reg = REG_GR + 32; break;
479384865Sobrien    case DYNREG_FR: base_reg = REG_FR + 32; break;
479484865Sobrien    case DYNREG_PR: base_reg = REG_P + 16; break;
479584865Sobrien    default: break;
479684865Sobrien    }
479784865Sobrien
479884865Sobrien  /* First, remove existing names from hash table.  */
479984865Sobrien  for (dr = md.dynreg[type]; dr && dr->num_regs; dr = dr->next)
480084865Sobrien    {
480184865Sobrien      hash_delete (md.dynreg_hash, dr->name);
4802218822Sdim      /* FIXME: Free dr->name.  */
480384865Sobrien      dr->num_regs = 0;
480484865Sobrien    }
480584865Sobrien
480684865Sobrien  drpp = &md.dynreg[type];
480784865Sobrien  while (1)
480884865Sobrien    {
480984865Sobrien      start = input_line_pointer;
481084865Sobrien      ch = get_symbol_end ();
4811218822Sdim      len = strlen (ia64_canonicalize_symbol_name (start));
481284865Sobrien      *input_line_pointer = ch;
481384865Sobrien
481484865Sobrien      SKIP_WHITESPACE ();
481584865Sobrien      if (*input_line_pointer != '[')
481684865Sobrien	{
481784865Sobrien	  as_bad ("Expected '['");
481884865Sobrien	  goto err;
481984865Sobrien	}
482084865Sobrien      ++input_line_pointer;	/* skip '[' */
482184865Sobrien
482284865Sobrien      num_regs = get_absolute_expression ();
482384865Sobrien
482484865Sobrien      if (*input_line_pointer++ != ']')
482584865Sobrien	{
482684865Sobrien	  as_bad ("Expected ']'");
482784865Sobrien	  goto err;
482884865Sobrien	}
4829218822Sdim      if (num_regs <= 0)
4830218822Sdim	{
4831218822Sdim	  as_bad ("Number of elements must be positive");
4832218822Sdim	  goto err;
4833218822Sdim	}
483484865Sobrien      SKIP_WHITESPACE ();
483584865Sobrien
483684865Sobrien      num_alloced += num_regs;
483784865Sobrien      switch (type)
483884865Sobrien	{
483984865Sobrien	case DYNREG_GR:
484084865Sobrien	  if (num_alloced > md.rot.num_regs)
484184865Sobrien	    {
484284865Sobrien	      as_bad ("Used more than the declared %d rotating registers",
484384865Sobrien		      md.rot.num_regs);
484484865Sobrien	      goto err;
484584865Sobrien	    }
484684865Sobrien	  break;
484784865Sobrien	case DYNREG_FR:
484884865Sobrien	  if (num_alloced > 96)
484984865Sobrien	    {
485084865Sobrien	      as_bad ("Used more than the available 96 rotating registers");
485184865Sobrien	      goto err;
485284865Sobrien	    }
485384865Sobrien	  break;
485484865Sobrien	case DYNREG_PR:
485584865Sobrien	  if (num_alloced > 48)
485684865Sobrien	    {
485784865Sobrien	      as_bad ("Used more than the available 48 rotating registers");
485884865Sobrien	      goto err;
485984865Sobrien	    }
486084865Sobrien	  break;
486184865Sobrien
486284865Sobrien	default:
486384865Sobrien	  break;
486484865Sobrien	}
486584865Sobrien
486684865Sobrien      if (!*drpp)
486784865Sobrien	{
486884865Sobrien	  *drpp = obstack_alloc (&notes, sizeof (*dr));
486984865Sobrien	  memset (*drpp, 0, sizeof (*dr));
487084865Sobrien	}
487184865Sobrien
4872218822Sdim      name = obstack_alloc (&notes, len + 1);
4873218822Sdim      memcpy (name, start, len);
4874218822Sdim      name[len] = '\0';
4875218822Sdim
487684865Sobrien      dr = *drpp;
487784865Sobrien      dr->name = name;
487884865Sobrien      dr->num_regs = num_regs;
487984865Sobrien      dr->base = base_reg;
488084865Sobrien      drpp = &dr->next;
488184865Sobrien      base_reg += num_regs;
488284865Sobrien
488384865Sobrien      if (hash_insert (md.dynreg_hash, name, dr))
488484865Sobrien	{
488584865Sobrien	  as_bad ("Attempt to redefine register set `%s'", name);
4886218822Sdim	  obstack_free (&notes, name);
488784865Sobrien	  goto err;
488884865Sobrien	}
488984865Sobrien
489084865Sobrien      if (*input_line_pointer != ',')
489184865Sobrien	break;
489284865Sobrien      ++input_line_pointer;	/* skip comma */
489384865Sobrien      SKIP_WHITESPACE ();
489484865Sobrien    }
489584865Sobrien  demand_empty_rest_of_line ();
489684865Sobrien  return;
489784865Sobrien
489884865Sobrien err:
489984865Sobrien  ignore_rest_of_line ();
490084865Sobrien}
490184865Sobrien
490284865Sobrienstatic void
490384865Sobriendot_byteorder (byteorder)
490484865Sobrien     int byteorder;
490584865Sobrien{
4906130561Sobrien  segment_info_type *seginfo = seg_info (now_seg);
4907130561Sobrien
4908130561Sobrien  if (byteorder == -1)
4909130561Sobrien    {
4910130561Sobrien      if (seginfo->tc_segment_info_data.endian == 0)
4911218822Sdim	seginfo->tc_segment_info_data.endian = default_big_endian ? 1 : 2;
4912130561Sobrien      byteorder = seginfo->tc_segment_info_data.endian == 1;
4913130561Sobrien    }
4914130561Sobrien  else
4915130561Sobrien    seginfo->tc_segment_info_data.endian = byteorder ? 1 : 2;
4916130561Sobrien
4917130561Sobrien  if (target_big_endian != byteorder)
4918130561Sobrien    {
4919130561Sobrien      target_big_endian = byteorder;
4920130561Sobrien      if (target_big_endian)
4921130561Sobrien	{
4922130561Sobrien	  ia64_number_to_chars = number_to_chars_bigendian;
4923130561Sobrien	  ia64_float_to_chars = ia64_float_to_chars_bigendian;
4924130561Sobrien	}
4925130561Sobrien      else
4926130561Sobrien	{
4927130561Sobrien	  ia64_number_to_chars = number_to_chars_littleendian;
4928130561Sobrien	  ia64_float_to_chars = ia64_float_to_chars_littleendian;
4929130561Sobrien	}
4930130561Sobrien    }
493184865Sobrien}
493284865Sobrien
493384865Sobrienstatic void
493484865Sobriendot_psr (dummy)
493584865Sobrien     int dummy ATTRIBUTE_UNUSED;
493684865Sobrien{
493784865Sobrien  char *option;
493884865Sobrien  int ch;
493984865Sobrien
494084865Sobrien  while (1)
494184865Sobrien    {
494284865Sobrien      option = input_line_pointer;
494384865Sobrien      ch = get_symbol_end ();
494484865Sobrien      if (strcmp (option, "lsb") == 0)
494584865Sobrien	md.flags &= ~EF_IA_64_BE;
494684865Sobrien      else if (strcmp (option, "msb") == 0)
494784865Sobrien	md.flags |= EF_IA_64_BE;
494884865Sobrien      else if (strcmp (option, "abi32") == 0)
494984865Sobrien	md.flags &= ~EF_IA_64_ABI64;
495084865Sobrien      else if (strcmp (option, "abi64") == 0)
495184865Sobrien	md.flags |= EF_IA_64_ABI64;
495284865Sobrien      else
495384865Sobrien	as_bad ("Unknown psr option `%s'", option);
495484865Sobrien      *input_line_pointer = ch;
495584865Sobrien
495684865Sobrien      SKIP_WHITESPACE ();
495784865Sobrien      if (*input_line_pointer != ',')
495884865Sobrien	break;
495984865Sobrien
496084865Sobrien      ++input_line_pointer;
496184865Sobrien      SKIP_WHITESPACE ();
496284865Sobrien    }
496384865Sobrien  demand_empty_rest_of_line ();
496484865Sobrien}
496584865Sobrien
496684865Sobrienstatic void
496784865Sobriendot_ln (dummy)
496884865Sobrien     int dummy ATTRIBUTE_UNUSED;
496984865Sobrien{
497084865Sobrien  new_logical_line (0, get_absolute_expression ());
497184865Sobrien  demand_empty_rest_of_line ();
497284865Sobrien}
497384865Sobrien
4974218822Sdimstatic void
4975218822Sdimcross_section (ref, cons, ua)
4976218822Sdim     int ref;
4977218822Sdim     void (*cons) PARAMS((int));
4978218822Sdim     int ua;
497984865Sobrien{
4980218822Sdim  char *start, *end;
4981218822Sdim  int saved_auto_align;
4982218822Sdim  unsigned int section_count;
498384865Sobrien
498484865Sobrien  SKIP_WHITESPACE ();
4985218822Sdim  start = input_line_pointer;
4986218822Sdim  if (*start == '"')
498784865Sobrien    {
4988218822Sdim      int len;
4989218822Sdim      char *name;
4990218822Sdim
4991218822Sdim      name = demand_copy_C_string (&len);
4992218822Sdim      obstack_free(&notes, name);
4993218822Sdim      if (!name)
4994218822Sdim	{
4995218822Sdim	  ignore_rest_of_line ();
4996218822Sdim	  return;
4997218822Sdim	}
499884865Sobrien    }
4999218822Sdim  else
500084865Sobrien    {
5001218822Sdim      char c = get_symbol_end ();
5002218822Sdim
5003218822Sdim      if (input_line_pointer == start)
5004218822Sdim	{
5005218822Sdim	  as_bad ("Missing section name");
5006218822Sdim	  ignore_rest_of_line ();
5007218822Sdim	  return;
5008218822Sdim	}
5009218822Sdim      *input_line_pointer = c;
501084865Sobrien    }
5011218822Sdim  end = input_line_pointer;
501284865Sobrien  SKIP_WHITESPACE ();
501384865Sobrien  if (*input_line_pointer != ',')
501484865Sobrien    {
501584865Sobrien      as_bad ("Comma expected after section name");
501684865Sobrien      ignore_rest_of_line ();
5017218822Sdim      return;
501884865Sobrien    }
5019218822Sdim  *end = '\0';
5020218822Sdim  end = input_line_pointer + 1;		/* skip comma */
5021218822Sdim  input_line_pointer = start;
5022218822Sdim  md.keep_pending_output = 1;
5023218822Sdim  section_count = bfd_count_sections(stdoutput);
5024218822Sdim  obj_elf_section (0);
5025218822Sdim  if (section_count != bfd_count_sections(stdoutput))
5026218822Sdim    as_warn ("Creating sections with .xdataN/.xrealN/.xstringZ is deprecated.");
5027218822Sdim  input_line_pointer = end;
5028218822Sdim  saved_auto_align = md.auto_align;
5029218822Sdim  if (ua)
5030218822Sdim    md.auto_align = 0;
5031218822Sdim  (*cons) (ref);
5032218822Sdim  if (ua)
5033218822Sdim    md.auto_align = saved_auto_align;
5034218822Sdim  obj_elf_previous (0);
5035218822Sdim  md.keep_pending_output = 0;
503684865Sobrien}
503784865Sobrien
503884865Sobrienstatic void
503984865Sobriendot_xdata (size)
504084865Sobrien     int size;
504184865Sobrien{
5042218822Sdim  cross_section (size, cons, 0);
504384865Sobrien}
504484865Sobrien
504584865Sobrien/* Why doesn't float_cons() call md_cons_align() the way cons() does?  */
504684865Sobrien
504784865Sobrienstatic void
504884865Sobrienstmt_float_cons (kind)
504984865Sobrien     int kind;
505084865Sobrien{
5051130561Sobrien  size_t alignment;
505284865Sobrien
505384865Sobrien  switch (kind)
505484865Sobrien    {
5055130561Sobrien    case 'd':
5056130561Sobrien      alignment = 8;
5057130561Sobrien      break;
505884865Sobrien
5059130561Sobrien    case 'x':
5060130561Sobrien    case 'X':
5061130561Sobrien      alignment = 16;
5062130561Sobrien      break;
5063130561Sobrien
506484865Sobrien    case 'f':
506584865Sobrien    default:
5066130561Sobrien      alignment = 4;
506784865Sobrien      break;
506884865Sobrien    }
5069130561Sobrien  ia64_do_align (alignment);
507084865Sobrien  float_cons (kind);
507184865Sobrien}
507284865Sobrien
507384865Sobrienstatic void
507484865Sobrienstmt_cons_ua (size)
507584865Sobrien     int size;
507684865Sobrien{
507784865Sobrien  int saved_auto_align = md.auto_align;
507884865Sobrien
507984865Sobrien  md.auto_align = 0;
508084865Sobrien  cons (size);
508184865Sobrien  md.auto_align = saved_auto_align;
508284865Sobrien}
508384865Sobrien
508484865Sobrienstatic void
508584865Sobriendot_xfloat_cons (kind)
508684865Sobrien     int kind;
508784865Sobrien{
5088218822Sdim  cross_section (kind, stmt_float_cons, 0);
508984865Sobrien}
509084865Sobrien
509184865Sobrienstatic void
509284865Sobriendot_xstringer (zero)
509384865Sobrien     int zero;
509484865Sobrien{
5095218822Sdim  cross_section (zero, stringer, 0);
509684865Sobrien}
509784865Sobrien
509884865Sobrienstatic void
509984865Sobriendot_xdata_ua (size)
510084865Sobrien     int size;
510184865Sobrien{
5102218822Sdim  cross_section (size, cons, 1);
510384865Sobrien}
510484865Sobrien
510584865Sobrienstatic void
510684865Sobriendot_xfloat_cons_ua (kind)
510784865Sobrien     int kind;
510884865Sobrien{
5109218822Sdim  cross_section (kind, float_cons, 1);
511084865Sobrien}
511184865Sobrien
511284865Sobrien/* .reg.val <regname>,value */
511384865Sobrien
511484865Sobrienstatic void
511584865Sobriendot_reg_val (dummy)
511684865Sobrien     int dummy ATTRIBUTE_UNUSED;
511784865Sobrien{
511884865Sobrien  expressionS reg;
511984865Sobrien
5120218822Sdim  expression_and_evaluate (&reg);
512184865Sobrien  if (reg.X_op != O_register)
512284865Sobrien    {
512384865Sobrien      as_bad (_("Register name expected"));
512484865Sobrien      ignore_rest_of_line ();
512584865Sobrien    }
512684865Sobrien  else if (*input_line_pointer++ != ',')
512784865Sobrien    {
512884865Sobrien      as_bad (_("Comma expected"));
512984865Sobrien      ignore_rest_of_line ();
513084865Sobrien    }
513184865Sobrien  else
513284865Sobrien    {
513384865Sobrien      valueT value = get_absolute_expression ();
513484865Sobrien      int regno = reg.X_add_number;
5135218822Sdim      if (regno <= REG_GR || regno > REG_GR + 127)
513684865Sobrien	as_warn (_("Register value annotation ignored"));
513784865Sobrien      else
513884865Sobrien	{
513984865Sobrien	  gr_values[regno - REG_GR].known = 1;
514084865Sobrien	  gr_values[regno - REG_GR].value = value;
514184865Sobrien	  gr_values[regno - REG_GR].path = md.path;
514284865Sobrien	}
514384865Sobrien    }
514484865Sobrien  demand_empty_rest_of_line ();
514584865Sobrien}
514684865Sobrien
5147218822Sdim/*
5148218822Sdim  .serialize.data
5149218822Sdim  .serialize.instruction
5150218822Sdim */
5151218822Sdimstatic void
5152218822Sdimdot_serialize (type)
5153218822Sdim     int type;
5154218822Sdim{
5155218822Sdim  insn_group_break (0, 0, 0);
5156218822Sdim  if (type)
5157218822Sdim    instruction_serialization ();
5158218822Sdim  else
5159218822Sdim    data_serialization ();
5160218822Sdim  insn_group_break (0, 0, 0);
5161218822Sdim  demand_empty_rest_of_line ();
5162218822Sdim}
5163218822Sdim
516484865Sobrien/* select dv checking mode
516584865Sobrien   .auto
516684865Sobrien   .explicit
516784865Sobrien   .default
516884865Sobrien
516984865Sobrien   A stop is inserted when changing modes
517084865Sobrien */
517184865Sobrien
517284865Sobrienstatic void
517384865Sobriendot_dv_mode (type)
517484865Sobrien     int type;
517584865Sobrien{
517684865Sobrien  if (md.manual_bundling)
517784865Sobrien    as_warn (_("Directive invalid within a bundle"));
517884865Sobrien
517984865Sobrien  if (type == 'E' || type == 'A')
518084865Sobrien    md.mode_explicitly_set = 0;
518184865Sobrien  else
518284865Sobrien    md.mode_explicitly_set = 1;
518384865Sobrien
518484865Sobrien  md.detect_dv = 1;
518584865Sobrien  switch (type)
518684865Sobrien    {
518784865Sobrien    case 'A':
518884865Sobrien    case 'a':
518984865Sobrien      if (md.explicit_mode)
519084865Sobrien	insn_group_break (1, 0, 0);
519184865Sobrien      md.explicit_mode = 0;
519284865Sobrien      break;
519384865Sobrien    case 'E':
519484865Sobrien    case 'e':
519584865Sobrien      if (!md.explicit_mode)
519684865Sobrien	insn_group_break (1, 0, 0);
519784865Sobrien      md.explicit_mode = 1;
519884865Sobrien      break;
519984865Sobrien    default:
520084865Sobrien    case 'd':
520184865Sobrien      if (md.explicit_mode != md.default_explicit_mode)
520284865Sobrien	insn_group_break (1, 0, 0);
520384865Sobrien      md.explicit_mode = md.default_explicit_mode;
520484865Sobrien      md.mode_explicitly_set = 0;
520584865Sobrien      break;
520684865Sobrien    }
520784865Sobrien}
520884865Sobrien
520984865Sobrienstatic void
521084865Sobrienprint_prmask (mask)
521184865Sobrien     valueT mask;
521284865Sobrien{
521384865Sobrien  int regno;
521484865Sobrien  char *comma = "";
521584865Sobrien  for (regno = 0; regno < 64; regno++)
521684865Sobrien    {
521784865Sobrien      if (mask & ((valueT) 1 << regno))
521884865Sobrien	{
521984865Sobrien	  fprintf (stderr, "%s p%d", comma, regno);
522084865Sobrien	  comma = ",";
522184865Sobrien	}
522284865Sobrien    }
522384865Sobrien}
522484865Sobrien
522584865Sobrien/*
5226218822Sdim  .pred.rel.clear [p1 [,p2 [,...]]]     (also .pred.rel "clear" or @clear)
5227218822Sdim  .pred.rel.imply p1, p2                (also .pred.rel "imply" or @imply)
5228218822Sdim  .pred.rel.mutex p1, p2 [,...]         (also .pred.rel "mutex" or @mutex)
522984865Sobrien  .pred.safe_across_calls p1 [, p2 [,...]]
523084865Sobrien */
523184865Sobrien
523284865Sobrienstatic void
523384865Sobriendot_pred_rel (type)
523484865Sobrien     int type;
523584865Sobrien{
523684865Sobrien  valueT mask = 0;
523784865Sobrien  int count = 0;
523884865Sobrien  int p1 = -1, p2 = -1;
523984865Sobrien
524084865Sobrien  if (type == 0)
524184865Sobrien    {
5242218822Sdim      if (*input_line_pointer == '"')
524384865Sobrien	{
524484865Sobrien	  int len;
524584865Sobrien	  char *form = demand_copy_C_string (&len);
5246218822Sdim
524784865Sobrien	  if (strcmp (form, "mutex") == 0)
524884865Sobrien	    type = 'm';
524984865Sobrien	  else if (strcmp (form, "clear") == 0)
525084865Sobrien	    type = 'c';
525184865Sobrien	  else if (strcmp (form, "imply") == 0)
525284865Sobrien	    type = 'i';
5253218822Sdim	  obstack_free (&notes, form);
525484865Sobrien	}
5255218822Sdim      else if (*input_line_pointer == '@')
5256218822Sdim	{
5257218822Sdim	  char *form = ++input_line_pointer;
5258218822Sdim	  char c = get_symbol_end();
5259218822Sdim
5260218822Sdim	  if (strcmp (form, "mutex") == 0)
5261218822Sdim	    type = 'm';
5262218822Sdim	  else if (strcmp (form, "clear") == 0)
5263218822Sdim	    type = 'c';
5264218822Sdim	  else if (strcmp (form, "imply") == 0)
5265218822Sdim	    type = 'i';
5266218822Sdim	  *input_line_pointer = c;
5267218822Sdim	}
5268218822Sdim      else
5269218822Sdim	{
5270218822Sdim	  as_bad (_("Missing predicate relation type"));
5271218822Sdim	  ignore_rest_of_line ();
5272218822Sdim	  return;
5273218822Sdim	}
5274218822Sdim      if (type == 0)
5275218822Sdim	{
5276218822Sdim	  as_bad (_("Unrecognized predicate relation type"));
5277218822Sdim	  ignore_rest_of_line ();
5278218822Sdim	  return;
5279218822Sdim	}
528084865Sobrien      if (*input_line_pointer == ',')
528184865Sobrien	++input_line_pointer;
528284865Sobrien      SKIP_WHITESPACE ();
528384865Sobrien    }
528484865Sobrien
528584865Sobrien  SKIP_WHITESPACE ();
528684865Sobrien  while (1)
528784865Sobrien    {
5288218822Sdim      valueT bits = 1;
528984865Sobrien      int regno;
5290218822Sdim      expressionS pr, *pr1, *pr2;
529184865Sobrien
5292218822Sdim      expression_and_evaluate (&pr);
5293218822Sdim      if (pr.X_op == O_register
5294218822Sdim	  && pr.X_add_number >= REG_P
5295218822Sdim	  && pr.X_add_number <= REG_P + 63)
529684865Sobrien	{
5297218822Sdim	  regno = pr.X_add_number - REG_P;
5298218822Sdim	  bits <<= regno;
5299218822Sdim	  count++;
5300218822Sdim	  if (p1 == -1)
5301218822Sdim	    p1 = regno;
5302218822Sdim	  else if (p2 == -1)
5303218822Sdim	    p2 = regno;
530484865Sobrien	}
5305218822Sdim      else if (type != 'i'
5306218822Sdim	  && pr.X_op == O_subtract
5307218822Sdim	  && (pr1 = symbol_get_value_expression (pr.X_add_symbol))
5308218822Sdim	  && pr1->X_op == O_register
5309218822Sdim	  && pr1->X_add_number >= REG_P
5310218822Sdim	  && pr1->X_add_number <= REG_P + 63
5311218822Sdim	  && (pr2 = symbol_get_value_expression (pr.X_op_symbol))
5312218822Sdim	  && pr2->X_op == O_register
5313218822Sdim	  && pr2->X_add_number >= REG_P
5314218822Sdim	  && pr2->X_add_number <= REG_P + 63)
531584865Sobrien	{
5316218822Sdim	  /* It's a range.  */
5317218822Sdim	  int stop;
531884865Sobrien
5319218822Sdim	  regno = pr1->X_add_number - REG_P;
5320218822Sdim	  stop = pr2->X_add_number - REG_P;
5321218822Sdim	  if (regno >= stop)
532284865Sobrien	    {
532384865Sobrien	      as_bad (_("Bad register range"));
532484865Sobrien	      ignore_rest_of_line ();
532584865Sobrien	      return;
532684865Sobrien	    }
5327218822Sdim	  bits = ((bits << stop) << 1) - (bits << regno);
5328218822Sdim	  count += stop - regno + 1;
532984865Sobrien	}
5330218822Sdim      else
5331218822Sdim	{
5332218822Sdim	  as_bad (_("Predicate register expected"));
5333218822Sdim	  ignore_rest_of_line ();
5334218822Sdim	  return;
5335218822Sdim	}
5336218822Sdim      if (mask & bits)
5337218822Sdim	as_warn (_("Duplicate predicate register ignored"));
5338218822Sdim      mask |= bits;
533984865Sobrien      if (*input_line_pointer != ',')
534084865Sobrien	break;
534184865Sobrien      ++input_line_pointer;
534284865Sobrien      SKIP_WHITESPACE ();
534384865Sobrien    }
534484865Sobrien
534584865Sobrien  switch (type)
534684865Sobrien    {
534784865Sobrien    case 'c':
534884865Sobrien      if (count == 0)
534984865Sobrien	mask = ~(valueT) 0;
535084865Sobrien      clear_qp_mutex (mask);
535184865Sobrien      clear_qp_implies (mask, (valueT) 0);
535284865Sobrien      break;
535384865Sobrien    case 'i':
535484865Sobrien      if (count != 2 || p1 == -1 || p2 == -1)
535584865Sobrien	as_bad (_("Predicate source and target required"));
535684865Sobrien      else if (p1 == 0 || p2 == 0)
535784865Sobrien	as_bad (_("Use of p0 is not valid in this context"));
535884865Sobrien      else
535984865Sobrien	add_qp_imply (p1, p2);
536084865Sobrien      break;
536184865Sobrien    case 'm':
536284865Sobrien      if (count < 2)
536384865Sobrien	{
536484865Sobrien	  as_bad (_("At least two PR arguments expected"));
536584865Sobrien	  break;
536684865Sobrien	}
536784865Sobrien      else if (mask & 1)
536884865Sobrien	{
536984865Sobrien	  as_bad (_("Use of p0 is not valid in this context"));
537084865Sobrien	  break;
537184865Sobrien	}
537284865Sobrien      add_qp_mutex (mask);
537384865Sobrien      break;
537484865Sobrien    case 's':
537584865Sobrien      /* note that we don't override any existing relations */
537684865Sobrien      if (count == 0)
537784865Sobrien	{
537884865Sobrien	  as_bad (_("At least one PR argument expected"));
537984865Sobrien	  break;
538084865Sobrien	}
538184865Sobrien      if (md.debug_dv)
538284865Sobrien	{
538384865Sobrien	  fprintf (stderr, "Safe across calls: ");
538484865Sobrien	  print_prmask (mask);
538584865Sobrien	  fprintf (stderr, "\n");
538684865Sobrien	}
538784865Sobrien      qp_safe_across_calls = mask;
538884865Sobrien      break;
538984865Sobrien    }
539084865Sobrien  demand_empty_rest_of_line ();
539184865Sobrien}
539284865Sobrien
539384865Sobrien/* .entry label [, label [, ...]]
539484865Sobrien   Hint to DV code that the given labels are to be considered entry points.
539584865Sobrien   Otherwise, only global labels are considered entry points.  */
539684865Sobrien
539784865Sobrienstatic void
539884865Sobriendot_entry (dummy)
539984865Sobrien     int dummy ATTRIBUTE_UNUSED;
540084865Sobrien{
540184865Sobrien  const char *err;
540284865Sobrien  char *name;
540384865Sobrien  int c;
540484865Sobrien  symbolS *symbolP;
540584865Sobrien
540684865Sobrien  do
540784865Sobrien    {
540884865Sobrien      name = input_line_pointer;
540984865Sobrien      c = get_symbol_end ();
541084865Sobrien      symbolP = symbol_find_or_make (name);
541184865Sobrien
541284865Sobrien      err = hash_insert (md.entry_hash, S_GET_NAME (symbolP), (PTR) symbolP);
541384865Sobrien      if (err)
541484865Sobrien	as_fatal (_("Inserting \"%s\" into entry hint table failed: %s"),
541584865Sobrien		  name, err);
541684865Sobrien
541784865Sobrien      *input_line_pointer = c;
541884865Sobrien      SKIP_WHITESPACE ();
541984865Sobrien      c = *input_line_pointer;
542084865Sobrien      if (c == ',')
542184865Sobrien	{
542284865Sobrien	  input_line_pointer++;
542384865Sobrien	  SKIP_WHITESPACE ();
542484865Sobrien	  if (*input_line_pointer == '\n')
542584865Sobrien	    c = '\n';
542684865Sobrien	}
542784865Sobrien    }
542884865Sobrien  while (c == ',');
542984865Sobrien
543084865Sobrien  demand_empty_rest_of_line ();
543184865Sobrien}
543284865Sobrien
543384865Sobrien/* .mem.offset offset, base
543484865Sobrien   "base" is used to distinguish between offsets from a different base.  */
543584865Sobrien
543684865Sobrienstatic void
543784865Sobriendot_mem_offset (dummy)
543884865Sobrien  int dummy ATTRIBUTE_UNUSED;
543984865Sobrien{
544084865Sobrien  md.mem_offset.hint = 1;
544184865Sobrien  md.mem_offset.offset = get_absolute_expression ();
544284865Sobrien  if (*input_line_pointer != ',')
544384865Sobrien    {
544484865Sobrien      as_bad (_("Comma expected"));
544584865Sobrien      ignore_rest_of_line ();
544684865Sobrien      return;
544784865Sobrien    }
544884865Sobrien  ++input_line_pointer;
544984865Sobrien  md.mem_offset.base = get_absolute_expression ();
545084865Sobrien  demand_empty_rest_of_line ();
545184865Sobrien}
545284865Sobrien
545384865Sobrien/* ia64-specific pseudo-ops:  */
545484865Sobrienconst pseudo_typeS md_pseudo_table[] =
545584865Sobrien  {
545684865Sobrien    { "radix", dot_radix, 0 },
545784865Sobrien    { "lcomm", s_lcomm_bytes, 1 },
5458218822Sdim    { "loc", dot_loc, 0 },
545984865Sobrien    { "bss", dot_special_section, SPECIAL_SECTION_BSS },
546084865Sobrien    { "sbss", dot_special_section, SPECIAL_SECTION_SBSS },
546184865Sobrien    { "sdata", dot_special_section, SPECIAL_SECTION_SDATA },
546284865Sobrien    { "rodata", dot_special_section, SPECIAL_SECTION_RODATA },
546384865Sobrien    { "comment", dot_special_section, SPECIAL_SECTION_COMMENT },
546484865Sobrien    { "ia_64.unwind", dot_special_section, SPECIAL_SECTION_UNWIND },
546584865Sobrien    { "ia_64.unwind_info", dot_special_section, SPECIAL_SECTION_UNWIND_INFO },
546689857Sobrien    { "init_array", dot_special_section, SPECIAL_SECTION_INIT_ARRAY },
546789857Sobrien    { "fini_array", dot_special_section, SPECIAL_SECTION_FINI_ARRAY },
546884865Sobrien    { "proc", dot_proc, 0 },
546984865Sobrien    { "body", dot_body, 0 },
547084865Sobrien    { "prologue", dot_prologue, 0 },
547184865Sobrien    { "endp", dot_endp, 0 },
547284865Sobrien
547384865Sobrien    { "fframe", dot_fframe, 0 },
547484865Sobrien    { "vframe", dot_vframe, 0 },
547584865Sobrien    { "vframesp", dot_vframesp, 0 },
5476218822Sdim    { "vframepsp", dot_vframesp, 1 },
547784865Sobrien    { "save", dot_save, 0 },
547884865Sobrien    { "restore", dot_restore, 0 },
547984865Sobrien    { "restorereg", dot_restorereg, 0 },
5480218822Sdim    { "restorereg.p", dot_restorereg, 1 },
548184865Sobrien    { "handlerdata", dot_handlerdata, 0 },
548284865Sobrien    { "unwentry", dot_unwentry, 0 },
548384865Sobrien    { "altrp", dot_altrp, 0 },
548484865Sobrien    { "savesp", dot_savemem, 0 },
548584865Sobrien    { "savepsp", dot_savemem, 1 },
548684865Sobrien    { "save.g", dot_saveg, 0 },
548784865Sobrien    { "save.f", dot_savef, 0 },
548884865Sobrien    { "save.b", dot_saveb, 0 },
548984865Sobrien    { "save.gf", dot_savegf, 0 },
549084865Sobrien    { "spill", dot_spill, 0 },
549184865Sobrien    { "spillreg", dot_spillreg, 0 },
549284865Sobrien    { "spillsp", dot_spillmem, 0 },
549384865Sobrien    { "spillpsp", dot_spillmem, 1 },
5494218822Sdim    { "spillreg.p", dot_spillreg, 1 },
5495218822Sdim    { "spillsp.p", dot_spillmem, ~0 },
5496218822Sdim    { "spillpsp.p", dot_spillmem, ~1 },
549784865Sobrien    { "label_state", dot_label_state, 0 },
549884865Sobrien    { "copy_state", dot_copy_state, 0 },
549984865Sobrien    { "unwabi", dot_unwabi, 0 },
550084865Sobrien    { "personality", dot_personality, 0 },
550184865Sobrien    { "mii", dot_template, 0x0 },
550284865Sobrien    { "mli", dot_template, 0x2 }, /* old format, for compatibility */
550384865Sobrien    { "mlx", dot_template, 0x2 },
550484865Sobrien    { "mmi", dot_template, 0x4 },
550584865Sobrien    { "mfi", dot_template, 0x6 },
550684865Sobrien    { "mmf", dot_template, 0x7 },
550784865Sobrien    { "mib", dot_template, 0x8 },
550884865Sobrien    { "mbb", dot_template, 0x9 },
550984865Sobrien    { "bbb", dot_template, 0xb },
551084865Sobrien    { "mmb", dot_template, 0xc },
551184865Sobrien    { "mfb", dot_template, 0xe },
5512130561Sobrien    { "align", dot_align, 0 },
551384865Sobrien    { "regstk", dot_regstk, 0 },
551484865Sobrien    { "rotr", dot_rot, DYNREG_GR },
551584865Sobrien    { "rotf", dot_rot, DYNREG_FR },
551684865Sobrien    { "rotp", dot_rot, DYNREG_PR },
551784865Sobrien    { "lsb", dot_byteorder, 0 },
551884865Sobrien    { "msb", dot_byteorder, 1 },
551984865Sobrien    { "psr", dot_psr, 0 },
552084865Sobrien    { "alias", dot_alias, 0 },
5521130561Sobrien    { "secalias", dot_alias, 1 },
552284865Sobrien    { "ln", dot_ln, 0 },		/* source line info (for debugging) */
552384865Sobrien
552484865Sobrien    { "xdata1", dot_xdata, 1 },
552584865Sobrien    { "xdata2", dot_xdata, 2 },
552684865Sobrien    { "xdata4", dot_xdata, 4 },
552784865Sobrien    { "xdata8", dot_xdata, 8 },
5528218822Sdim    { "xdata16", dot_xdata, 16 },
552984865Sobrien    { "xreal4", dot_xfloat_cons, 'f' },
553084865Sobrien    { "xreal8", dot_xfloat_cons, 'd' },
553184865Sobrien    { "xreal10", dot_xfloat_cons, 'x' },
5532130561Sobrien    { "xreal16", dot_xfloat_cons, 'X' },
553384865Sobrien    { "xstring", dot_xstringer, 0 },
553484865Sobrien    { "xstringz", dot_xstringer, 1 },
553584865Sobrien
553684865Sobrien    /* unaligned versions:  */
553784865Sobrien    { "xdata2.ua", dot_xdata_ua, 2 },
553884865Sobrien    { "xdata4.ua", dot_xdata_ua, 4 },
553984865Sobrien    { "xdata8.ua", dot_xdata_ua, 8 },
5540218822Sdim    { "xdata16.ua", dot_xdata_ua, 16 },
554184865Sobrien    { "xreal4.ua", dot_xfloat_cons_ua, 'f' },
554284865Sobrien    { "xreal8.ua", dot_xfloat_cons_ua, 'd' },
554384865Sobrien    { "xreal10.ua", dot_xfloat_cons_ua, 'x' },
5544130561Sobrien    { "xreal16.ua", dot_xfloat_cons_ua, 'X' },
554584865Sobrien
554684865Sobrien    /* annotations/DV checking support */
554784865Sobrien    { "entry", dot_entry, 0 },
554884865Sobrien    { "mem.offset", dot_mem_offset, 0 },
554984865Sobrien    { "pred.rel", dot_pred_rel, 0 },
555084865Sobrien    { "pred.rel.clear", dot_pred_rel, 'c' },
555184865Sobrien    { "pred.rel.imply", dot_pred_rel, 'i' },
555284865Sobrien    { "pred.rel.mutex", dot_pred_rel, 'm' },
555384865Sobrien    { "pred.safe_across_calls", dot_pred_rel, 's' },
555484865Sobrien    { "reg.val", dot_reg_val, 0 },
5555218822Sdim    { "serialize.data", dot_serialize, 0 },
5556218822Sdim    { "serialize.instruction", dot_serialize, 1 },
555784865Sobrien    { "auto", dot_dv_mode, 'a' },
555884865Sobrien    { "explicit", dot_dv_mode, 'e' },
555984865Sobrien    { "default", dot_dv_mode, 'd' },
556084865Sobrien
556189857Sobrien    /* ??? These are needed to make gas/testsuite/gas/elf/ehopt.s work.
556289857Sobrien       IA-64 aligns data allocation pseudo-ops by default, so we have to
556389857Sobrien       tell it that these ones are supposed to be unaligned.  Long term,
556489857Sobrien       should rewrite so that only IA-64 specific data allocation pseudo-ops
556589857Sobrien       are aligned by default.  */
556689857Sobrien    {"2byte", stmt_cons_ua, 2},
556789857Sobrien    {"4byte", stmt_cons_ua, 4},
556889857Sobrien    {"8byte", stmt_cons_ua, 8},
556989857Sobrien
557084865Sobrien    { NULL, 0, 0 }
557184865Sobrien  };
557284865Sobrien
557384865Sobrienstatic const struct pseudo_opcode
557484865Sobrien  {
557584865Sobrien    const char *name;
557684865Sobrien    void (*handler) (int);
557784865Sobrien    int arg;
557884865Sobrien  }
557984865Sobrienpseudo_opcode[] =
558084865Sobrien  {
558184865Sobrien    /* these are more like pseudo-ops, but don't start with a dot */
558284865Sobrien    { "data1", cons, 1 },
558384865Sobrien    { "data2", cons, 2 },
558484865Sobrien    { "data4", cons, 4 },
558584865Sobrien    { "data8", cons, 8 },
558689857Sobrien    { "data16", cons, 16 },
558784865Sobrien    { "real4", stmt_float_cons, 'f' },
558884865Sobrien    { "real8", stmt_float_cons, 'd' },
558984865Sobrien    { "real10", stmt_float_cons, 'x' },
5590130561Sobrien    { "real16", stmt_float_cons, 'X' },
559184865Sobrien    { "string", stringer, 0 },
559284865Sobrien    { "stringz", stringer, 1 },
559384865Sobrien
559484865Sobrien    /* unaligned versions:  */
559584865Sobrien    { "data2.ua", stmt_cons_ua, 2 },
559684865Sobrien    { "data4.ua", stmt_cons_ua, 4 },
559784865Sobrien    { "data8.ua", stmt_cons_ua, 8 },
559889857Sobrien    { "data16.ua", stmt_cons_ua, 16 },
559984865Sobrien    { "real4.ua", float_cons, 'f' },
560084865Sobrien    { "real8.ua", float_cons, 'd' },
560184865Sobrien    { "real10.ua", float_cons, 'x' },
5602130561Sobrien    { "real16.ua", float_cons, 'X' },
560384865Sobrien  };
560484865Sobrien
560584865Sobrien/* Declare a register by creating a symbol for it and entering it in
560684865Sobrien   the symbol table.  */
560784865Sobrien
560884865Sobrienstatic symbolS *
560984865Sobriendeclare_register (name, regnum)
561084865Sobrien     const char *name;
5611218822Sdim     unsigned int regnum;
561284865Sobrien{
561384865Sobrien  const char *err;
561484865Sobrien  symbolS *sym;
561584865Sobrien
5616218822Sdim  sym = symbol_create (name, reg_section, regnum, &zero_address_frag);
561784865Sobrien
561884865Sobrien  err = hash_insert (md.reg_hash, S_GET_NAME (sym), (PTR) sym);
561984865Sobrien  if (err)
562084865Sobrien    as_fatal ("Inserting \"%s\" into register table failed: %s",
562184865Sobrien	      name, err);
562284865Sobrien
562384865Sobrien  return sym;
562484865Sobrien}
562584865Sobrien
562684865Sobrienstatic void
562784865Sobriendeclare_register_set (prefix, num_regs, base_regnum)
562884865Sobrien     const char *prefix;
5629218822Sdim     unsigned int num_regs;
5630218822Sdim     unsigned int base_regnum;
563184865Sobrien{
563284865Sobrien  char name[8];
5633218822Sdim  unsigned int i;
563484865Sobrien
563584865Sobrien  for (i = 0; i < num_regs; ++i)
563684865Sobrien    {
5637218822Sdim      snprintf (name, sizeof (name), "%s%u", prefix, i);
563884865Sobrien      declare_register (name, base_regnum + i);
563984865Sobrien    }
564084865Sobrien}
564184865Sobrien
564284865Sobrienstatic unsigned int
564384865Sobrienoperand_width (opnd)
564484865Sobrien     enum ia64_opnd opnd;
564584865Sobrien{
564684865Sobrien  const struct ia64_operand *odesc = &elf64_ia64_operands[opnd];
564784865Sobrien  unsigned int bits = 0;
564884865Sobrien  int i;
564984865Sobrien
565084865Sobrien  bits = 0;
565184865Sobrien  for (i = 0; i < NELEMS (odesc->field) && odesc->field[i].bits; ++i)
565284865Sobrien    bits += odesc->field[i].bits;
565384865Sobrien
565484865Sobrien  return bits;
565584865Sobrien}
565684865Sobrien
565784865Sobrienstatic enum operand_match_result
565884865Sobrienoperand_match (idesc, index, e)
565984865Sobrien     const struct ia64_opcode *idesc;
566084865Sobrien     int index;
566184865Sobrien     expressionS *e;
566284865Sobrien{
566384865Sobrien  enum ia64_opnd opnd = idesc->operands[index];
566484865Sobrien  int bits, relocatable = 0;
566584865Sobrien  struct insn_fix *fix;
566684865Sobrien  bfd_signed_vma val;
566784865Sobrien
566884865Sobrien  switch (opnd)
566984865Sobrien    {
567084865Sobrien      /* constants:  */
567184865Sobrien
567284865Sobrien    case IA64_OPND_AR_CCV:
567384865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_AR + 32)
567484865Sobrien	return OPERAND_MATCH;
567584865Sobrien      break;
567684865Sobrien
5677130561Sobrien    case IA64_OPND_AR_CSD:
5678130561Sobrien      if (e->X_op == O_register && e->X_add_number == REG_AR + 25)
5679130561Sobrien	return OPERAND_MATCH;
5680130561Sobrien      break;
5681130561Sobrien
568284865Sobrien    case IA64_OPND_AR_PFS:
568384865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_AR + 64)
568484865Sobrien	return OPERAND_MATCH;
568584865Sobrien      break;
568684865Sobrien
568784865Sobrien    case IA64_OPND_GR0:
568884865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_GR + 0)
568984865Sobrien	return OPERAND_MATCH;
569084865Sobrien      break;
569184865Sobrien
569284865Sobrien    case IA64_OPND_IP:
569384865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_IP)
569484865Sobrien	return OPERAND_MATCH;
569584865Sobrien      break;
569684865Sobrien
569784865Sobrien    case IA64_OPND_PR:
569884865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_PR)
569984865Sobrien	return OPERAND_MATCH;
570084865Sobrien      break;
570184865Sobrien
570284865Sobrien    case IA64_OPND_PR_ROT:
570384865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_PR_ROT)
570484865Sobrien	return OPERAND_MATCH;
570584865Sobrien      break;
570684865Sobrien
570784865Sobrien    case IA64_OPND_PSR:
570884865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_PSR)
570984865Sobrien	return OPERAND_MATCH;
571084865Sobrien      break;
571184865Sobrien
571284865Sobrien    case IA64_OPND_PSR_L:
571384865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_PSR_L)
571484865Sobrien	return OPERAND_MATCH;
571584865Sobrien      break;
571684865Sobrien
571784865Sobrien    case IA64_OPND_PSR_UM:
571884865Sobrien      if (e->X_op == O_register && e->X_add_number == REG_PSR_UM)
571984865Sobrien	return OPERAND_MATCH;
572084865Sobrien      break;
572184865Sobrien
572284865Sobrien    case IA64_OPND_C1:
572384865Sobrien      if (e->X_op == O_constant)
572484865Sobrien	{
572584865Sobrien	  if (e->X_add_number == 1)
572684865Sobrien	    return OPERAND_MATCH;
572784865Sobrien	  else
572884865Sobrien	    return OPERAND_OUT_OF_RANGE;
572984865Sobrien	}
573084865Sobrien      break;
573184865Sobrien
573284865Sobrien    case IA64_OPND_C8:
573384865Sobrien      if (e->X_op == O_constant)
573484865Sobrien	{
573584865Sobrien	  if (e->X_add_number == 8)
573684865Sobrien	    return OPERAND_MATCH;
573784865Sobrien	  else
573884865Sobrien	    return OPERAND_OUT_OF_RANGE;
573984865Sobrien	}
574084865Sobrien      break;
574184865Sobrien
574284865Sobrien    case IA64_OPND_C16:
574384865Sobrien      if (e->X_op == O_constant)
574484865Sobrien	{
574584865Sobrien	  if (e->X_add_number == 16)
574684865Sobrien	    return OPERAND_MATCH;
574784865Sobrien	  else
574884865Sobrien	    return OPERAND_OUT_OF_RANGE;
574984865Sobrien	}
575084865Sobrien      break;
575184865Sobrien
575284865Sobrien      /* register operands:  */
575384865Sobrien
575484865Sobrien    case IA64_OPND_AR3:
575584865Sobrien      if (e->X_op == O_register && e->X_add_number >= REG_AR
575684865Sobrien	  && e->X_add_number < REG_AR + 128)
575784865Sobrien	return OPERAND_MATCH;
575884865Sobrien      break;
575984865Sobrien
576084865Sobrien    case IA64_OPND_B1:
576184865Sobrien    case IA64_OPND_B2:
576284865Sobrien      if (e->X_op == O_register && e->X_add_number >= REG_BR
576384865Sobrien	  && e->X_add_number < REG_BR + 8)
576484865Sobrien	return OPERAND_MATCH;
576584865Sobrien      break;
576684865Sobrien
576784865Sobrien    case IA64_OPND_CR3:
576884865Sobrien      if (e->X_op == O_register && e->X_add_number >= REG_CR
576984865Sobrien	  && e->X_add_number < REG_CR + 128)
577084865Sobrien	return OPERAND_MATCH;
577184865Sobrien      break;
577284865Sobrien
577384865Sobrien    case IA64_OPND_F1:
577484865Sobrien    case IA64_OPND_F2:
577584865Sobrien    case IA64_OPND_F3:
577684865Sobrien    case IA64_OPND_F4:
577784865Sobrien      if (e->X_op == O_register && e->X_add_number >= REG_FR
577884865Sobrien	  && e->X_add_number < REG_FR + 128)
577984865Sobrien	return OPERAND_MATCH;
578084865Sobrien      break;
578184865Sobrien
578284865Sobrien    case IA64_OPND_P1:
578384865Sobrien    case IA64_OPND_P2:
578484865Sobrien      if (e->X_op == O_register && e->X_add_number >= REG_P
578584865Sobrien	  && e->X_add_number < REG_P + 64)
578684865Sobrien	return OPERAND_MATCH;
578784865Sobrien      break;
578884865Sobrien
578984865Sobrien    case IA64_OPND_R1:
579084865Sobrien    case IA64_OPND_R2:
579184865Sobrien    case IA64_OPND_R3:
579284865Sobrien      if (e->X_op == O_register && e->X_add_number >= REG_GR
579384865Sobrien	  && e->X_add_number < REG_GR + 128)
579484865Sobrien	return OPERAND_MATCH;
579584865Sobrien      break;
579684865Sobrien
579784865Sobrien    case IA64_OPND_R3_2:
579884865Sobrien      if (e->X_op == O_register && e->X_add_number >= REG_GR)
5799104834Sobrien	{
580084865Sobrien	  if (e->X_add_number < REG_GR + 4)
580184865Sobrien	    return OPERAND_MATCH;
580284865Sobrien	  else if (e->X_add_number < REG_GR + 128)
580384865Sobrien	    return OPERAND_OUT_OF_RANGE;
580484865Sobrien	}
580584865Sobrien      break;
580684865Sobrien
580784865Sobrien      /* indirect operands:  */
580884865Sobrien    case IA64_OPND_CPUID_R3:
580984865Sobrien    case IA64_OPND_DBR_R3:
581084865Sobrien    case IA64_OPND_DTR_R3:
581184865Sobrien    case IA64_OPND_ITR_R3:
581284865Sobrien    case IA64_OPND_IBR_R3:
581384865Sobrien    case IA64_OPND_MSR_R3:
581484865Sobrien    case IA64_OPND_PKR_R3:
581584865Sobrien    case IA64_OPND_PMC_R3:
581684865Sobrien    case IA64_OPND_PMD_R3:
581784865Sobrien    case IA64_OPND_RR_R3:
581884865Sobrien      if (e->X_op == O_index && e->X_op_symbol
581984865Sobrien	  && (S_GET_VALUE (e->X_op_symbol) - IND_CPUID
582084865Sobrien	      == opnd - IA64_OPND_CPUID_R3))
582184865Sobrien	return OPERAND_MATCH;
582284865Sobrien      break;
582384865Sobrien
582484865Sobrien    case IA64_OPND_MR3:
582584865Sobrien      if (e->X_op == O_index && !e->X_op_symbol)
582684865Sobrien	return OPERAND_MATCH;
582784865Sobrien      break;
582884865Sobrien
582984865Sobrien      /* immediate operands:  */
583084865Sobrien    case IA64_OPND_CNT2a:
583184865Sobrien    case IA64_OPND_LEN4:
583284865Sobrien    case IA64_OPND_LEN6:
583384865Sobrien      bits = operand_width (idesc->operands[index]);
583484865Sobrien      if (e->X_op == O_constant)
583584865Sobrien	{
583684865Sobrien	  if ((bfd_vma) (e->X_add_number - 1) < ((bfd_vma) 1 << bits))
583784865Sobrien	    return OPERAND_MATCH;
583884865Sobrien	  else
583984865Sobrien	    return OPERAND_OUT_OF_RANGE;
584084865Sobrien	}
584184865Sobrien      break;
584284865Sobrien
584384865Sobrien    case IA64_OPND_CNT2b:
584484865Sobrien      if (e->X_op == O_constant)
584584865Sobrien	{
584684865Sobrien	  if ((bfd_vma) (e->X_add_number - 1) < 3)
584784865Sobrien	    return OPERAND_MATCH;
584884865Sobrien	  else
584984865Sobrien	    return OPERAND_OUT_OF_RANGE;
585084865Sobrien	}
585184865Sobrien      break;
585284865Sobrien
585384865Sobrien    case IA64_OPND_CNT2c:
585484865Sobrien      val = e->X_add_number;
585584865Sobrien      if (e->X_op == O_constant)
585684865Sobrien	{
585784865Sobrien	  if ((val == 0 || val == 7 || val == 15 || val == 16))
585884865Sobrien	    return OPERAND_MATCH;
585984865Sobrien	  else
586084865Sobrien	    return OPERAND_OUT_OF_RANGE;
586184865Sobrien	}
586284865Sobrien      break;
586384865Sobrien
586484865Sobrien    case IA64_OPND_SOR:
586584865Sobrien      /* SOR must be an integer multiple of 8 */
586684865Sobrien      if (e->X_op == O_constant && e->X_add_number & 0x7)
586784865Sobrien	return OPERAND_OUT_OF_RANGE;
586884865Sobrien    case IA64_OPND_SOF:
586984865Sobrien    case IA64_OPND_SOL:
587084865Sobrien      if (e->X_op == O_constant)
587184865Sobrien	{
587284865Sobrien	  if ((bfd_vma) e->X_add_number <= 96)
587384865Sobrien	    return OPERAND_MATCH;
587484865Sobrien	  else
587584865Sobrien	    return OPERAND_OUT_OF_RANGE;
587684865Sobrien	}
587784865Sobrien      break;
587884865Sobrien
587984865Sobrien    case IA64_OPND_IMMU62:
588084865Sobrien      if (e->X_op == O_constant)
588184865Sobrien	{
588284865Sobrien	  if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << 62))
588384865Sobrien	    return OPERAND_MATCH;
588484865Sobrien	  else
588584865Sobrien	    return OPERAND_OUT_OF_RANGE;
588684865Sobrien	}
588784865Sobrien      else
588884865Sobrien	{
588984865Sobrien	  /* FIXME -- need 62-bit relocation type */
589084865Sobrien	  as_bad (_("62-bit relocation not yet implemented"));
589184865Sobrien	}
589284865Sobrien      break;
589384865Sobrien
589484865Sobrien    case IA64_OPND_IMMU64:
589584865Sobrien      if (e->X_op == O_symbol || e->X_op == O_pseudo_fixup
589684865Sobrien	  || e->X_op == O_subtract)
589784865Sobrien	{
589884865Sobrien	  fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
589984865Sobrien	  fix->code = BFD_RELOC_IA64_IMM64;
590084865Sobrien	  if (e->X_op != O_subtract)
590184865Sobrien	    {
590284865Sobrien	      fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
590384865Sobrien	      if (e->X_op == O_pseudo_fixup)
590484865Sobrien		e->X_op = O_symbol;
590584865Sobrien	    }
590684865Sobrien
590784865Sobrien	  fix->opnd = idesc->operands[index];
590884865Sobrien	  fix->expr = *e;
590984865Sobrien	  fix->is_pcrel = 0;
591084865Sobrien	  ++CURR_SLOT.num_fixups;
591184865Sobrien	  return OPERAND_MATCH;
591284865Sobrien	}
591384865Sobrien      else if (e->X_op == O_constant)
591484865Sobrien	return OPERAND_MATCH;
591584865Sobrien      break;
591684865Sobrien
5917218822Sdim    case IA64_OPND_IMMU5b:
5918218822Sdim      if (e->X_op == O_constant)
5919218822Sdim	{
5920218822Sdim	  val = e->X_add_number;
5921218822Sdim	  if (val >= 32 && val <= 63)
5922218822Sdim	    return OPERAND_MATCH;
5923218822Sdim	  else
5924218822Sdim	    return OPERAND_OUT_OF_RANGE;
5925218822Sdim	}
5926218822Sdim      break;
5927218822Sdim
592884865Sobrien    case IA64_OPND_CCNT5:
592984865Sobrien    case IA64_OPND_CNT5:
593084865Sobrien    case IA64_OPND_CNT6:
593184865Sobrien    case IA64_OPND_CPOS6a:
593284865Sobrien    case IA64_OPND_CPOS6b:
593384865Sobrien    case IA64_OPND_CPOS6c:
593484865Sobrien    case IA64_OPND_IMMU2:
593584865Sobrien    case IA64_OPND_IMMU7a:
593684865Sobrien    case IA64_OPND_IMMU7b:
593784865Sobrien    case IA64_OPND_IMMU21:
593884865Sobrien    case IA64_OPND_IMMU24:
593984865Sobrien    case IA64_OPND_MBTYPE4:
594084865Sobrien    case IA64_OPND_MHTYPE8:
594184865Sobrien    case IA64_OPND_POS6:
594284865Sobrien      bits = operand_width (idesc->operands[index]);
594384865Sobrien      if (e->X_op == O_constant)
594484865Sobrien	{
594584865Sobrien	  if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
594684865Sobrien	    return OPERAND_MATCH;
594784865Sobrien	  else
594884865Sobrien	    return OPERAND_OUT_OF_RANGE;
594984865Sobrien	}
595084865Sobrien      break;
595184865Sobrien
595284865Sobrien    case IA64_OPND_IMMU9:
595384865Sobrien      bits = operand_width (idesc->operands[index]);
595484865Sobrien      if (e->X_op == O_constant)
595584865Sobrien	{
595684865Sobrien	  if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
595784865Sobrien	    {
595884865Sobrien	      int lobits = e->X_add_number & 0x3;
595984865Sobrien	      if (((bfd_vma) e->X_add_number & 0x3C) != 0 && lobits == 0)
596084865Sobrien		e->X_add_number |= (bfd_vma) 0x3;
596184865Sobrien	      return OPERAND_MATCH;
596284865Sobrien	    }
596384865Sobrien	  else
596484865Sobrien	    return OPERAND_OUT_OF_RANGE;
596584865Sobrien	}
596684865Sobrien      break;
596784865Sobrien
596884865Sobrien    case IA64_OPND_IMM44:
596984865Sobrien      /* least 16 bits must be zero */
597084865Sobrien      if ((e->X_add_number & 0xffff) != 0)
597184865Sobrien	/* XXX technically, this is wrong: we should not be issuing warning
597284865Sobrien	   messages until we're sure this instruction pattern is going to
597384865Sobrien	   be used! */
597484865Sobrien	as_warn (_("lower 16 bits of mask ignored"));
597584865Sobrien
597684865Sobrien      if (e->X_op == O_constant)
597784865Sobrien	{
597884865Sobrien	  if (((e->X_add_number >= 0
597984865Sobrien		&& (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 44))
598084865Sobrien	       || (e->X_add_number < 0
598184865Sobrien		   && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 44))))
598284865Sobrien	    {
598384865Sobrien	      /* sign-extend */
598484865Sobrien	      if (e->X_add_number >= 0
598584865Sobrien		  && (e->X_add_number & ((bfd_vma) 1 << 43)) != 0)
598684865Sobrien		{
598784865Sobrien		  e->X_add_number |= ~(((bfd_vma) 1 << 44) - 1);
598884865Sobrien		}
598984865Sobrien	      return OPERAND_MATCH;
599084865Sobrien	    }
599184865Sobrien	  else
599284865Sobrien	    return OPERAND_OUT_OF_RANGE;
599384865Sobrien	}
599484865Sobrien      break;
599584865Sobrien
599684865Sobrien    case IA64_OPND_IMM17:
599784865Sobrien      /* bit 0 is a don't care (pr0 is hardwired to 1) */
599884865Sobrien      if (e->X_op == O_constant)
599984865Sobrien	{
600084865Sobrien	  if (((e->X_add_number >= 0
600184865Sobrien		&& (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 17))
600284865Sobrien	       || (e->X_add_number < 0
600384865Sobrien		   && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 17))))
600484865Sobrien	    {
600584865Sobrien	      /* sign-extend */
600684865Sobrien	      if (e->X_add_number >= 0
600784865Sobrien		  && (e->X_add_number & ((bfd_vma) 1 << 16)) != 0)
600884865Sobrien		{
600984865Sobrien		  e->X_add_number |= ~(((bfd_vma) 1 << 17) - 1);
601084865Sobrien		}
601184865Sobrien	      return OPERAND_MATCH;
601284865Sobrien	    }
601384865Sobrien	  else
601484865Sobrien	    return OPERAND_OUT_OF_RANGE;
601584865Sobrien	}
601684865Sobrien      break;
601784865Sobrien
601884865Sobrien    case IA64_OPND_IMM14:
601984865Sobrien    case IA64_OPND_IMM22:
602084865Sobrien      relocatable = 1;
602184865Sobrien    case IA64_OPND_IMM1:
602284865Sobrien    case IA64_OPND_IMM8:
602384865Sobrien    case IA64_OPND_IMM8U4:
602484865Sobrien    case IA64_OPND_IMM8M1:
602584865Sobrien    case IA64_OPND_IMM8M1U4:
602684865Sobrien    case IA64_OPND_IMM8M1U8:
602784865Sobrien    case IA64_OPND_IMM9a:
602884865Sobrien    case IA64_OPND_IMM9b:
602984865Sobrien      bits = operand_width (idesc->operands[index]);
603084865Sobrien      if (relocatable && (e->X_op == O_symbol
603184865Sobrien			  || e->X_op == O_subtract
603284865Sobrien			  || e->X_op == O_pseudo_fixup))
603384865Sobrien	{
603484865Sobrien	  fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
603584865Sobrien
603684865Sobrien	  if (idesc->operands[index] == IA64_OPND_IMM14)
603784865Sobrien	    fix->code = BFD_RELOC_IA64_IMM14;
603884865Sobrien	  else
603984865Sobrien	    fix->code = BFD_RELOC_IA64_IMM22;
604084865Sobrien
604184865Sobrien	  if (e->X_op != O_subtract)
604284865Sobrien	    {
604384865Sobrien	      fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
604484865Sobrien	      if (e->X_op == O_pseudo_fixup)
604584865Sobrien		e->X_op = O_symbol;
604684865Sobrien	    }
604784865Sobrien
604884865Sobrien	  fix->opnd = idesc->operands[index];
604984865Sobrien	  fix->expr = *e;
605084865Sobrien	  fix->is_pcrel = 0;
605184865Sobrien	  ++CURR_SLOT.num_fixups;
605284865Sobrien	  return OPERAND_MATCH;
605384865Sobrien	}
605484865Sobrien      else if (e->X_op != O_constant
605584865Sobrien	       && ! (e->X_op == O_big && opnd == IA64_OPND_IMM8M1U8))
605684865Sobrien	return OPERAND_MISMATCH;
605784865Sobrien
605884865Sobrien      if (opnd == IA64_OPND_IMM8M1U4)
605984865Sobrien	{
606084865Sobrien	  /* Zero is not valid for unsigned compares that take an adjusted
606184865Sobrien	     constant immediate range.  */
606284865Sobrien	  if (e->X_add_number == 0)
606384865Sobrien	    return OPERAND_OUT_OF_RANGE;
606484865Sobrien
606584865Sobrien	  /* Sign-extend 32-bit unsigned numbers, so that the following range
606684865Sobrien	     checks will work.  */
606784865Sobrien	  val = e->X_add_number;
606884865Sobrien	  if (((val & (~(bfd_vma) 0 << 32)) == 0)
606984865Sobrien	      && ((val & ((bfd_vma) 1 << 31)) != 0))
607084865Sobrien	    val = ((val << 32) >> 32);
607184865Sobrien
607284865Sobrien	  /* Check for 0x100000000.  This is valid because
607384865Sobrien	     0x100000000-1 is the same as ((uint32_t) -1).  */
607484865Sobrien	  if (val == ((bfd_signed_vma) 1 << 32))
607584865Sobrien	    return OPERAND_MATCH;
607684865Sobrien
607784865Sobrien	  val = val - 1;
607884865Sobrien	}
607984865Sobrien      else if (opnd == IA64_OPND_IMM8M1U8)
608084865Sobrien	{
608184865Sobrien	  /* Zero is not valid for unsigned compares that take an adjusted
608284865Sobrien	     constant immediate range.  */
608384865Sobrien	  if (e->X_add_number == 0)
608484865Sobrien	    return OPERAND_OUT_OF_RANGE;
608584865Sobrien
608684865Sobrien	  /* Check for 0x10000000000000000.  */
608784865Sobrien	  if (e->X_op == O_big)
608884865Sobrien	    {
608984865Sobrien	      if (generic_bignum[0] == 0
609084865Sobrien		  && generic_bignum[1] == 0
609184865Sobrien		  && generic_bignum[2] == 0
609284865Sobrien		  && generic_bignum[3] == 0
609384865Sobrien		  && generic_bignum[4] == 1)
609484865Sobrien		return OPERAND_MATCH;
609584865Sobrien	      else
609684865Sobrien		return OPERAND_OUT_OF_RANGE;
609784865Sobrien	    }
609884865Sobrien	  else
609984865Sobrien	    val = e->X_add_number - 1;
610084865Sobrien	}
610184865Sobrien      else if (opnd == IA64_OPND_IMM8M1)
610284865Sobrien	val = e->X_add_number - 1;
610384865Sobrien      else if (opnd == IA64_OPND_IMM8U4)
610484865Sobrien	{
610584865Sobrien	  /* Sign-extend 32-bit unsigned numbers, so that the following range
610684865Sobrien	     checks will work.  */
610784865Sobrien	  val = e->X_add_number;
610884865Sobrien	  if (((val & (~(bfd_vma) 0 << 32)) == 0)
610984865Sobrien	      && ((val & ((bfd_vma) 1 << 31)) != 0))
611084865Sobrien	    val = ((val << 32) >> 32);
611184865Sobrien	}
611284865Sobrien      else
611384865Sobrien	val = e->X_add_number;
611484865Sobrien
611584865Sobrien      if ((val >= 0 && (bfd_vma) val < ((bfd_vma) 1 << (bits - 1)))
611684865Sobrien	  || (val < 0 && (bfd_vma) -val <= ((bfd_vma) 1 << (bits - 1))))
611784865Sobrien	return OPERAND_MATCH;
611884865Sobrien      else
611984865Sobrien	return OPERAND_OUT_OF_RANGE;
612084865Sobrien
612184865Sobrien    case IA64_OPND_INC3:
612284865Sobrien      /* +/- 1, 4, 8, 16 */
612384865Sobrien      val = e->X_add_number;
612484865Sobrien      if (val < 0)
612584865Sobrien	val = -val;
612684865Sobrien      if (e->X_op == O_constant)
612784865Sobrien	{
612884865Sobrien	  if ((val == 1 || val == 4 || val == 8 || val == 16))
612984865Sobrien	    return OPERAND_MATCH;
613084865Sobrien	  else
613184865Sobrien	    return OPERAND_OUT_OF_RANGE;
613284865Sobrien	}
613384865Sobrien      break;
613484865Sobrien
613584865Sobrien    case IA64_OPND_TGT25:
613684865Sobrien    case IA64_OPND_TGT25b:
613784865Sobrien    case IA64_OPND_TGT25c:
613884865Sobrien    case IA64_OPND_TGT64:
613984865Sobrien      if (e->X_op == O_symbol)
614084865Sobrien	{
614184865Sobrien	  fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
614284865Sobrien	  if (opnd == IA64_OPND_TGT25)
614384865Sobrien	    fix->code = BFD_RELOC_IA64_PCREL21F;
614484865Sobrien	  else if (opnd == IA64_OPND_TGT25b)
614584865Sobrien	    fix->code = BFD_RELOC_IA64_PCREL21M;
614684865Sobrien	  else if (opnd == IA64_OPND_TGT25c)
614784865Sobrien	    fix->code = BFD_RELOC_IA64_PCREL21B;
614884865Sobrien	  else if (opnd == IA64_OPND_TGT64)
614984865Sobrien	    fix->code = BFD_RELOC_IA64_PCREL60B;
615084865Sobrien	  else
615184865Sobrien	    abort ();
615284865Sobrien
615384865Sobrien	  fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
615484865Sobrien	  fix->opnd = idesc->operands[index];
615584865Sobrien	  fix->expr = *e;
615684865Sobrien	  fix->is_pcrel = 1;
615784865Sobrien	  ++CURR_SLOT.num_fixups;
615884865Sobrien	  return OPERAND_MATCH;
615984865Sobrien	}
616084865Sobrien    case IA64_OPND_TAG13:
616184865Sobrien    case IA64_OPND_TAG13b:
616284865Sobrien      switch (e->X_op)
616384865Sobrien	{
616484865Sobrien	case O_constant:
616584865Sobrien	  return OPERAND_MATCH;
616684865Sobrien
616784865Sobrien	case O_symbol:
616884865Sobrien	  fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
616989857Sobrien	  /* There are no external relocs for TAG13/TAG13b fields, so we
6170218822Sdim	     create a dummy reloc.  This will not live past md_apply_fix.  */
617189857Sobrien	  fix->code = BFD_RELOC_UNUSED;
617289857Sobrien	  fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
617384865Sobrien	  fix->opnd = idesc->operands[index];
617484865Sobrien	  fix->expr = *e;
617584865Sobrien	  fix->is_pcrel = 1;
617684865Sobrien	  ++CURR_SLOT.num_fixups;
617784865Sobrien	  return OPERAND_MATCH;
617884865Sobrien
617984865Sobrien	default:
618084865Sobrien	  break;
618184865Sobrien	}
618284865Sobrien      break;
618384865Sobrien
6184130561Sobrien    case IA64_OPND_LDXMOV:
6185130561Sobrien      fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
6186130561Sobrien      fix->code = BFD_RELOC_IA64_LDXMOV;
6187130561Sobrien      fix->opnd = idesc->operands[index];
6188130561Sobrien      fix->expr = *e;
6189130561Sobrien      fix->is_pcrel = 0;
6190130561Sobrien      ++CURR_SLOT.num_fixups;
6191130561Sobrien      return OPERAND_MATCH;
6192130561Sobrien
619384865Sobrien    default:
619484865Sobrien      break;
619584865Sobrien    }
619684865Sobrien  return OPERAND_MISMATCH;
619784865Sobrien}
619884865Sobrien
619984865Sobrienstatic int
6200218822Sdimparse_operand (e, more)
620184865Sobrien     expressionS *e;
6202218822Sdim     int more;
620384865Sobrien{
620484865Sobrien  int sep = '\0';
620584865Sobrien
620684865Sobrien  memset (e, 0, sizeof (*e));
620784865Sobrien  e->X_op = O_absent;
620884865Sobrien  SKIP_WHITESPACE ();
6209218822Sdim  expression_and_evaluate (e);
6210218822Sdim  sep = *input_line_pointer;
6211218822Sdim  if (more && (sep == ',' || sep == more))
6212218822Sdim    ++input_line_pointer;
621384865Sobrien  return sep;
621484865Sobrien}
621584865Sobrien
621684865Sobrien/* Returns the next entry in the opcode table that matches the one in
621784865Sobrien   IDESC, and frees the entry in IDESC.  If no matching entry is
621884865Sobrien   found, NULL is returned instead.  */
621984865Sobrien
622084865Sobrienstatic struct ia64_opcode *
622184865Sobrienget_next_opcode (struct ia64_opcode *idesc)
622284865Sobrien{
622384865Sobrien  struct ia64_opcode *next = ia64_find_next_opcode (idesc);
622484865Sobrien  ia64_free_opcode (idesc);
622584865Sobrien  return next;
622684865Sobrien}
622784865Sobrien
622884865Sobrien/* Parse the operands for the opcode and find the opcode variant that
622984865Sobrien   matches the specified operands, or NULL if no match is possible.  */
623084865Sobrien
623184865Sobrienstatic struct ia64_opcode *
623284865Sobrienparse_operands (idesc)
623384865Sobrien     struct ia64_opcode *idesc;
623484865Sobrien{
623584865Sobrien  int i = 0, highest_unmatched_operand, num_operands = 0, num_outputs = 0;
623684865Sobrien  int error_pos, out_of_range_pos, curr_out_of_range_pos, sep = 0;
6237218822Sdim  int reg1, reg2;
6238218822Sdim  char reg_class;
623984865Sobrien  enum ia64_opnd expected_operand = IA64_OPND_NIL;
624084865Sobrien  enum operand_match_result result;
624184865Sobrien  char mnemonic[129];
624284865Sobrien  char *first_arg = 0, *end, *saved_input_pointer;
624384865Sobrien  unsigned int sof;
624484865Sobrien
624584865Sobrien  assert (strlen (idesc->name) <= 128);
624684865Sobrien
624784865Sobrien  strcpy (mnemonic, idesc->name);
6248218822Sdim  if (idesc->operands[2] == IA64_OPND_SOF
6249218822Sdim      || idesc->operands[1] == IA64_OPND_SOF)
625084865Sobrien    {
625184865Sobrien      /* To make the common idiom "alloc loc?=ar.pfs,0,1,0,0" work, we
625284865Sobrien	 can't parse the first operand until we have parsed the
625384865Sobrien	 remaining operands of the "alloc" instruction.  */
625484865Sobrien      SKIP_WHITESPACE ();
625584865Sobrien      first_arg = input_line_pointer;
625684865Sobrien      end = strchr (input_line_pointer, '=');
625784865Sobrien      if (!end)
625884865Sobrien	{
625984865Sobrien	  as_bad ("Expected separator `='");
626084865Sobrien	  return 0;
626184865Sobrien	}
626284865Sobrien      input_line_pointer = end + 1;
626384865Sobrien      ++i;
626484865Sobrien      ++num_outputs;
626584865Sobrien    }
626684865Sobrien
6267218822Sdim  for (; ; ++i)
626884865Sobrien    {
6269218822Sdim      if (i < NELEMS (CURR_SLOT.opnd))
6270218822Sdim	{
6271218822Sdim	  sep = parse_operand (CURR_SLOT.opnd + i, '=');
6272218822Sdim	  if (CURR_SLOT.opnd[i].X_op == O_absent)
6273218822Sdim	    break;
6274218822Sdim	}
6275218822Sdim      else
6276218822Sdim	{
6277218822Sdim	  expressionS dummy;
627884865Sobrien
6279218822Sdim	  sep = parse_operand (&dummy, '=');
6280218822Sdim	  if (dummy.X_op == O_absent)
6281218822Sdim	    break;
6282218822Sdim	}
6283218822Sdim
628484865Sobrien      ++num_operands;
628584865Sobrien
628684865Sobrien      if (sep != '=' && sep != ',')
628784865Sobrien	break;
628884865Sobrien
628984865Sobrien      if (sep == '=')
629084865Sobrien	{
629184865Sobrien	  if (num_outputs > 0)
629284865Sobrien	    as_bad ("Duplicate equal sign (=) in instruction");
629384865Sobrien	  else
629484865Sobrien	    num_outputs = i + 1;
629584865Sobrien	}
629684865Sobrien    }
629784865Sobrien  if (sep != '\0')
629884865Sobrien    {
629984865Sobrien      as_bad ("Illegal operand separator `%c'", sep);
630084865Sobrien      return 0;
630184865Sobrien    }
630284865Sobrien
6303218822Sdim  if (idesc->operands[2] == IA64_OPND_SOF
6304218822Sdim      || idesc->operands[1] == IA64_OPND_SOF)
630584865Sobrien    {
6306218822Sdim      /* Map alloc r1=ar.pfs,i,l,o,r to alloc r1=ar.pfs,(i+l+o),(i+l),r.
6307218822Sdim	 Note, however, that due to that mapping operand numbers in error
6308218822Sdim	 messages for any of the constant operands will not be correct.  */
630984865Sobrien      know (strcmp (idesc->name, "alloc") == 0);
6310218822Sdim      /* The first operand hasn't been parsed/initialized, yet (but
6311218822Sdim	 num_operands intentionally doesn't account for that).  */
6312218822Sdim      i = num_operands > 4 ? 2 : 1;
6313218822Sdim#define FORCE_CONST(n) (CURR_SLOT.opnd[n].X_op == O_constant \
6314218822Sdim			? CURR_SLOT.opnd[n].X_add_number \
6315218822Sdim			: 0)
6316218822Sdim      sof = set_regstack (FORCE_CONST(i),
6317218822Sdim			  FORCE_CONST(i + 1),
6318218822Sdim			  FORCE_CONST(i + 2),
6319218822Sdim			  FORCE_CONST(i + 3));
6320218822Sdim#undef FORCE_CONST
632184865Sobrien
6322218822Sdim      /* now we can parse the first arg:  */
6323218822Sdim      saved_input_pointer = input_line_pointer;
6324218822Sdim      input_line_pointer = first_arg;
6325218822Sdim      sep = parse_operand (CURR_SLOT.opnd + 0, '=');
6326218822Sdim      if (sep != '=')
6327218822Sdim	--num_outputs;	/* force error */
6328218822Sdim      input_line_pointer = saved_input_pointer;
632984865Sobrien
6330218822Sdim      CURR_SLOT.opnd[i].X_add_number = sof;
6331218822Sdim      if (CURR_SLOT.opnd[i + 1].X_op == O_constant
6332218822Sdim	  && CURR_SLOT.opnd[i + 2].X_op == O_constant)
6333218822Sdim	CURR_SLOT.opnd[i + 1].X_add_number
6334218822Sdim	  = sof - CURR_SLOT.opnd[i + 2].X_add_number;
6335218822Sdim      else
6336218822Sdim	CURR_SLOT.opnd[i + 1].X_op = O_illegal;
6337218822Sdim      CURR_SLOT.opnd[i + 2] = CURR_SLOT.opnd[i + 3];
633884865Sobrien    }
633984865Sobrien
6340218822Sdim  highest_unmatched_operand = -4;
634184865Sobrien  curr_out_of_range_pos = -1;
634284865Sobrien  error_pos = 0;
634384865Sobrien  for (; idesc; idesc = get_next_opcode (idesc))
634484865Sobrien    {
634584865Sobrien      if (num_outputs != idesc->num_outputs)
634684865Sobrien	continue;		/* mismatch in # of outputs */
6347218822Sdim      if (highest_unmatched_operand < 0)
6348218822Sdim	highest_unmatched_operand |= 1;
6349218822Sdim      if (num_operands > NELEMS (idesc->operands)
6350218822Sdim	  || (num_operands < NELEMS (idesc->operands)
6351218822Sdim	   && idesc->operands[num_operands])
6352218822Sdim	  || (num_operands > 0 && !idesc->operands[num_operands - 1]))
6353218822Sdim	continue;		/* mismatch in number of arguments */
6354218822Sdim      if (highest_unmatched_operand < 0)
6355218822Sdim	highest_unmatched_operand |= 2;
635684865Sobrien
635784865Sobrien      CURR_SLOT.num_fixups = 0;
635884865Sobrien
635984865Sobrien      /* Try to match all operands.  If we see an out-of-range operand,
636084865Sobrien	 then continue trying to match the rest of the operands, since if
636184865Sobrien	 the rest match, then this idesc will give the best error message.  */
636284865Sobrien
636384865Sobrien      out_of_range_pos = -1;
636484865Sobrien      for (i = 0; i < num_operands && idesc->operands[i]; ++i)
636584865Sobrien	{
636684865Sobrien	  result = operand_match (idesc, i, CURR_SLOT.opnd + i);
636784865Sobrien	  if (result != OPERAND_MATCH)
636884865Sobrien	    {
636984865Sobrien	      if (result != OPERAND_OUT_OF_RANGE)
637084865Sobrien		break;
637184865Sobrien	      if (out_of_range_pos < 0)
637284865Sobrien		/* remember position of the first out-of-range operand: */
637384865Sobrien		out_of_range_pos = i;
637484865Sobrien	    }
637584865Sobrien	}
637684865Sobrien
637784865Sobrien      /* If we did not match all operands, or if at least one operand was
637884865Sobrien	 out-of-range, then this idesc does not match.  Keep track of which
637984865Sobrien	 idesc matched the most operands before failing.  If we have two
638084865Sobrien	 idescs that failed at the same position, and one had an out-of-range
638184865Sobrien	 operand, then prefer the out-of-range operand.  Thus if we have
638284865Sobrien	 "add r0=0x1000000,r1" we get an error saying the constant is out
638384865Sobrien	 of range instead of an error saying that the constant should have been
638484865Sobrien	 a register.  */
638584865Sobrien
638684865Sobrien      if (i != num_operands || out_of_range_pos >= 0)
638784865Sobrien	{
638884865Sobrien	  if (i > highest_unmatched_operand
638984865Sobrien	      || (i == highest_unmatched_operand
639084865Sobrien		  && out_of_range_pos > curr_out_of_range_pos))
639184865Sobrien	    {
639284865Sobrien	      highest_unmatched_operand = i;
639384865Sobrien	      if (out_of_range_pos >= 0)
639484865Sobrien		{
639584865Sobrien		  expected_operand = idesc->operands[out_of_range_pos];
639684865Sobrien		  error_pos = out_of_range_pos;
639784865Sobrien		}
639884865Sobrien	      else
639984865Sobrien		{
640084865Sobrien		  expected_operand = idesc->operands[i];
640184865Sobrien		  error_pos = i;
640284865Sobrien		}
640384865Sobrien	      curr_out_of_range_pos = out_of_range_pos;
640484865Sobrien	    }
640584865Sobrien	  continue;
640684865Sobrien	}
640784865Sobrien
640884865Sobrien      break;
640984865Sobrien    }
641084865Sobrien  if (!idesc)
641184865Sobrien    {
641284865Sobrien      if (expected_operand)
641384865Sobrien	as_bad ("Operand %u of `%s' should be %s",
641484865Sobrien		error_pos + 1, mnemonic,
641584865Sobrien		elf64_ia64_operands[expected_operand].desc);
6416218822Sdim      else if (highest_unmatched_operand < 0 && !(highest_unmatched_operand & 1))
6417218822Sdim	as_bad ("Wrong number of output operands");
6418218822Sdim      else if (highest_unmatched_operand < 0 && !(highest_unmatched_operand & 2))
6419218822Sdim	as_bad ("Wrong number of input operands");
642084865Sobrien      else
642184865Sobrien	as_bad ("Operand mismatch");
642284865Sobrien      return 0;
642384865Sobrien    }
642484865Sobrien
6425218822Sdim  /* Check that the instruction doesn't use
6426218822Sdim     - r0, f0, or f1 as output operands
6427218822Sdim     - the same predicate twice as output operands
6428218822Sdim     - r0 as address of a base update load or store
6429218822Sdim     - the same GR as output and address of a base update load
6430218822Sdim     - two even- or two odd-numbered FRs as output operands of a floating
6431218822Sdim       point parallel load.
6432218822Sdim     At most two (conflicting) output (or output-like) operands can exist,
6433218822Sdim     (floating point parallel loads have three outputs, but the base register,
6434218822Sdim     if updated, cannot conflict with the actual outputs).  */
6435218822Sdim  reg2 = reg1 = -1;
6436218822Sdim  for (i = 0; i < num_operands; ++i)
643784865Sobrien    {
6438218822Sdim      int regno = 0;
643984865Sobrien
6440218822Sdim      reg_class = 0;
6441218822Sdim      switch (idesc->operands[i])
644284865Sobrien	{
6443218822Sdim	case IA64_OPND_R1:
6444218822Sdim	case IA64_OPND_R2:
6445218822Sdim	case IA64_OPND_R3:
6446218822Sdim	  if (i < num_outputs)
644784865Sobrien	    {
6448218822Sdim	      if (CURR_SLOT.opnd[i].X_add_number == REG_GR)
6449218822Sdim		reg_class = 'r';
6450218822Sdim	      else if (reg1 < 0)
6451218822Sdim		reg1 = CURR_SLOT.opnd[i].X_add_number;
6452218822Sdim	      else if (reg2 < 0)
6453218822Sdim		reg2 = CURR_SLOT.opnd[i].X_add_number;
645484865Sobrien	    }
6455218822Sdim	  break;
6456218822Sdim	case IA64_OPND_P1:
6457218822Sdim	case IA64_OPND_P2:
6458218822Sdim	  if (i < num_outputs)
6459218822Sdim	    {
6460218822Sdim	      if (reg1 < 0)
6461218822Sdim		reg1 = CURR_SLOT.opnd[i].X_add_number;
6462218822Sdim	      else if (reg2 < 0)
6463218822Sdim		reg2 = CURR_SLOT.opnd[i].X_add_number;
6464218822Sdim	    }
6465218822Sdim	  break;
6466218822Sdim	case IA64_OPND_F1:
6467218822Sdim	case IA64_OPND_F2:
6468218822Sdim	case IA64_OPND_F3:
6469218822Sdim	case IA64_OPND_F4:
6470218822Sdim	  if (i < num_outputs)
6471218822Sdim	    {
6472218822Sdim	      if (CURR_SLOT.opnd[i].X_add_number >= REG_FR
6473218822Sdim		  && CURR_SLOT.opnd[i].X_add_number <= REG_FR + 1)
6474218822Sdim		{
6475218822Sdim		  reg_class = 'f';
6476218822Sdim		  regno = CURR_SLOT.opnd[i].X_add_number - REG_FR;
6477218822Sdim		}
6478218822Sdim	      else if (reg1 < 0)
6479218822Sdim		reg1 = CURR_SLOT.opnd[i].X_add_number;
6480218822Sdim	      else if (reg2 < 0)
6481218822Sdim		reg2 = CURR_SLOT.opnd[i].X_add_number;
6482218822Sdim	    }
6483218822Sdim	  break;
6484218822Sdim	case IA64_OPND_MR3:
6485218822Sdim	  if (idesc->flags & IA64_OPCODE_POSTINC)
6486218822Sdim	    {
6487218822Sdim	      if (CURR_SLOT.opnd[i].X_add_number == REG_GR)
6488218822Sdim		reg_class = 'm';
6489218822Sdim	      else if (reg1 < 0)
6490218822Sdim		reg1 = CURR_SLOT.opnd[i].X_add_number;
6491218822Sdim	      else if (reg2 < 0)
6492218822Sdim		reg2 = CURR_SLOT.opnd[i].X_add_number;
6493218822Sdim	    }
6494218822Sdim	  break;
6495218822Sdim	default:
6496218822Sdim	  break;
649784865Sobrien	}
6498218822Sdim      switch (reg_class)
6499218822Sdim	{
6500218822Sdim	case 0:
6501218822Sdim	  break;
6502218822Sdim	default:
6503218822Sdim	  as_warn ("Invalid use of `%c%d' as output operand", reg_class, regno);
6504218822Sdim	  break;
6505218822Sdim	case 'm':
6506218822Sdim	  as_warn ("Invalid use of `r%d' as base update address operand", regno);
6507218822Sdim	  break;
6508218822Sdim	}
650984865Sobrien    }
6510218822Sdim  if (reg1 == reg2)
6511218822Sdim    {
6512218822Sdim      if (reg1 >= REG_GR && reg1 <= REG_GR + 127)
6513218822Sdim	{
6514218822Sdim	  reg1 -= REG_GR;
6515218822Sdim	  reg_class = 'r';
6516218822Sdim	}
6517218822Sdim      else if (reg1 >= REG_P && reg1 <= REG_P + 63)
6518218822Sdim	{
6519218822Sdim	  reg1 -= REG_P;
6520218822Sdim	  reg_class = 'p';
6521218822Sdim	}
6522218822Sdim      else if (reg1 >= REG_FR && reg1 <= REG_FR + 127)
6523218822Sdim	{
6524218822Sdim	  reg1 -= REG_FR;
6525218822Sdim	  reg_class = 'f';
6526218822Sdim	}
6527218822Sdim      else
6528218822Sdim	reg_class = 0;
6529218822Sdim      if (reg_class)
6530218822Sdim	as_warn ("Invalid duplicate use of `%c%d'", reg_class, reg1);
6531218822Sdim    }
6532218822Sdim  else if (((reg1 >= REG_FR && reg1 <= REG_FR + 31
6533218822Sdim	     && reg2 >= REG_FR && reg2 <= REG_FR + 31)
6534218822Sdim	    || (reg1 >= REG_FR + 32 && reg1 <= REG_FR + 127
6535218822Sdim	     && reg2 >= REG_FR + 32 && reg2 <= REG_FR + 127))
6536218822Sdim	   && ! ((reg1 ^ reg2) & 1))
6537218822Sdim    as_warn ("Invalid simultaneous use of `f%d' and `f%d'",
6538218822Sdim	     reg1 - REG_FR, reg2 - REG_FR);
6539218822Sdim  else if ((reg1 >= REG_FR && reg1 <= REG_FR + 31
6540218822Sdim	    && reg2 >= REG_FR + 32 && reg2 <= REG_FR + 127)
6541218822Sdim	   || (reg1 >= REG_FR + 32 && reg1 <= REG_FR + 127
6542218822Sdim	    && reg2 >= REG_FR && reg2 <= REG_FR + 31))
6543218822Sdim    as_warn ("Dangerous simultaneous use of `f%d' and `f%d'",
6544218822Sdim	     reg1 - REG_FR, reg2 - REG_FR);
6545218822Sdim  return idesc;
654684865Sobrien}
654784865Sobrien
654884865Sobrienstatic void
654984865Sobrienbuild_insn (slot, insnp)
655084865Sobrien     struct slot *slot;
655184865Sobrien     bfd_vma *insnp;
655284865Sobrien{
655384865Sobrien  const struct ia64_operand *odesc, *o2desc;
655484865Sobrien  struct ia64_opcode *idesc = slot->idesc;
6555218822Sdim  bfd_vma insn;
6556218822Sdim  bfd_signed_vma val;
655784865Sobrien  const char *err;
655884865Sobrien  int i;
655984865Sobrien
656084865Sobrien  insn = idesc->opcode | slot->qp_regno;
656184865Sobrien
656284865Sobrien  for (i = 0; i < NELEMS (idesc->operands) && idesc->operands[i]; ++i)
656384865Sobrien    {
656484865Sobrien      if (slot->opnd[i].X_op == O_register
656584865Sobrien	  || slot->opnd[i].X_op == O_constant
656684865Sobrien	  || slot->opnd[i].X_op == O_index)
656784865Sobrien	val = slot->opnd[i].X_add_number;
656884865Sobrien      else if (slot->opnd[i].X_op == O_big)
656984865Sobrien	{
657084865Sobrien	  /* This must be the value 0x10000000000000000.  */
657184865Sobrien	  assert (idesc->operands[i] == IA64_OPND_IMM8M1U8);
657284865Sobrien	  val = 0;
657384865Sobrien	}
657484865Sobrien      else
657584865Sobrien	val = 0;
657684865Sobrien
657784865Sobrien      switch (idesc->operands[i])
657884865Sobrien	{
657984865Sobrien	case IA64_OPND_IMMU64:
658084865Sobrien	  *insnp++ = (val >> 22) & 0x1ffffffffffLL;
658184865Sobrien	  insn |= (((val & 0x7f) << 13) | (((val >> 7) & 0x1ff) << 27)
658284865Sobrien		   | (((val >> 16) & 0x1f) << 22) | (((val >> 21) & 0x1) << 21)
658384865Sobrien		   | (((val >> 63) & 0x1) << 36));
658484865Sobrien	  continue;
658584865Sobrien
658684865Sobrien	case IA64_OPND_IMMU62:
658784865Sobrien	  val &= 0x3fffffffffffffffULL;
658884865Sobrien	  if (val != slot->opnd[i].X_add_number)
658984865Sobrien	    as_warn (_("Value truncated to 62 bits"));
659084865Sobrien	  *insnp++ = (val >> 21) & 0x1ffffffffffLL;
659184865Sobrien	  insn |= (((val & 0xfffff) << 6) | (((val >> 20) & 0x1) << 36));
659284865Sobrien	  continue;
659384865Sobrien
659484865Sobrien	case IA64_OPND_TGT64:
659584865Sobrien	  val >>= 4;
659684865Sobrien	  *insnp++ = ((val >> 20) & 0x7fffffffffLL) << 2;
659784865Sobrien	  insn |= ((((val >> 59) & 0x1) << 36)
659884865Sobrien		   | (((val >> 0) & 0xfffff) << 13));
659984865Sobrien	  continue;
660084865Sobrien
660184865Sobrien	case IA64_OPND_AR3:
660284865Sobrien	  val -= REG_AR;
660384865Sobrien	  break;
660484865Sobrien
660584865Sobrien	case IA64_OPND_B1:
660684865Sobrien	case IA64_OPND_B2:
660784865Sobrien	  val -= REG_BR;
660884865Sobrien	  break;
660984865Sobrien
661084865Sobrien	case IA64_OPND_CR3:
661184865Sobrien	  val -= REG_CR;
661284865Sobrien	  break;
661384865Sobrien
661484865Sobrien	case IA64_OPND_F1:
661584865Sobrien	case IA64_OPND_F2:
661684865Sobrien	case IA64_OPND_F3:
661784865Sobrien	case IA64_OPND_F4:
661884865Sobrien	  val -= REG_FR;
661984865Sobrien	  break;
662084865Sobrien
662184865Sobrien	case IA64_OPND_P1:
662284865Sobrien	case IA64_OPND_P2:
662384865Sobrien	  val -= REG_P;
662484865Sobrien	  break;
662584865Sobrien
662684865Sobrien	case IA64_OPND_R1:
662784865Sobrien	case IA64_OPND_R2:
662884865Sobrien	case IA64_OPND_R3:
662984865Sobrien	case IA64_OPND_R3_2:
663084865Sobrien	case IA64_OPND_CPUID_R3:
663184865Sobrien	case IA64_OPND_DBR_R3:
663284865Sobrien	case IA64_OPND_DTR_R3:
663384865Sobrien	case IA64_OPND_ITR_R3:
663484865Sobrien	case IA64_OPND_IBR_R3:
663584865Sobrien	case IA64_OPND_MR3:
663684865Sobrien	case IA64_OPND_MSR_R3:
663784865Sobrien	case IA64_OPND_PKR_R3:
663884865Sobrien	case IA64_OPND_PMC_R3:
663984865Sobrien	case IA64_OPND_PMD_R3:
664084865Sobrien	case IA64_OPND_RR_R3:
664184865Sobrien	  val -= REG_GR;
664284865Sobrien	  break;
664384865Sobrien
664484865Sobrien	default:
664584865Sobrien	  break;
664684865Sobrien	}
664784865Sobrien
664884865Sobrien      odesc = elf64_ia64_operands + idesc->operands[i];
664984865Sobrien      err = (*odesc->insert) (odesc, val, &insn);
665084865Sobrien      if (err)
665184865Sobrien	as_bad_where (slot->src_file, slot->src_line,
665284865Sobrien		      "Bad operand value: %s", err);
665384865Sobrien      if (idesc->flags & IA64_OPCODE_PSEUDO)
665484865Sobrien	{
665584865Sobrien	  if ((idesc->flags & IA64_OPCODE_F2_EQ_F3)
665684865Sobrien	      && odesc == elf64_ia64_operands + IA64_OPND_F3)
665784865Sobrien	    {
665884865Sobrien	      o2desc = elf64_ia64_operands + IA64_OPND_F2;
665984865Sobrien	      (*o2desc->insert) (o2desc, val, &insn);
666084865Sobrien	    }
666184865Sobrien	  if ((idesc->flags & IA64_OPCODE_LEN_EQ_64MCNT)
666284865Sobrien	      && (odesc == elf64_ia64_operands + IA64_OPND_CPOS6a
666384865Sobrien		  || odesc == elf64_ia64_operands + IA64_OPND_POS6))
666484865Sobrien	    {
666584865Sobrien	      o2desc = elf64_ia64_operands + IA64_OPND_LEN6;
666684865Sobrien	      (*o2desc->insert) (o2desc, 64 - val, &insn);
666784865Sobrien	    }
666884865Sobrien	}
666984865Sobrien    }
667084865Sobrien  *insnp = insn;
667184865Sobrien}
667284865Sobrien
667384865Sobrienstatic void
667484865Sobrienemit_one_bundle ()
667584865Sobrien{
6676218822Sdim  int manual_bundling_off = 0, manual_bundling = 0;
667784865Sobrien  enum ia64_unit required_unit, insn_unit = 0;
667884865Sobrien  enum ia64_insn_type type[3], insn_type;
667984865Sobrien  unsigned int template, orig_template;
668084865Sobrien  bfd_vma insn[3] = { -1, -1, -1 };
668184865Sobrien  struct ia64_opcode *idesc;
668284865Sobrien  int end_of_insn_group = 0, user_template = -1;
6683218822Sdim  int n, i, j, first, curr, last_slot;
668484865Sobrien  bfd_vma t0 = 0, t1 = 0;
668584865Sobrien  struct label_fix *lfix;
6686218822Sdim  bfd_boolean mark_label;
668784865Sobrien  struct insn_fix *ifix;
668884865Sobrien  char mnemonic[16];
668984865Sobrien  fixS *fix;
669084865Sobrien  char *f;
6691218822Sdim  int addr_mod;
669284865Sobrien
669384865Sobrien  first = (md.curr_slot + NUM_SLOTS - md.num_slots_in_use) % NUM_SLOTS;
6694218822Sdim  know (first >= 0 && first < NUM_SLOTS);
669584865Sobrien  n = MIN (3, md.num_slots_in_use);
669684865Sobrien
669784865Sobrien  /* Determine template: user user_template if specified, best match
669884865Sobrien     otherwise:  */
669984865Sobrien
670084865Sobrien  if (md.slot[first].user_template >= 0)
670184865Sobrien    user_template = template = md.slot[first].user_template;
670284865Sobrien  else
670384865Sobrien    {
670484865Sobrien      /* Auto select appropriate template.  */
670584865Sobrien      memset (type, 0, sizeof (type));
670684865Sobrien      curr = first;
670784865Sobrien      for (i = 0; i < n; ++i)
670884865Sobrien	{
670984865Sobrien	  if (md.slot[curr].label_fixups && i != 0)
671084865Sobrien	    break;
671184865Sobrien	  type[i] = md.slot[curr].idesc->type;
671284865Sobrien	  curr = (curr + 1) % NUM_SLOTS;
671384865Sobrien	}
671484865Sobrien      template = best_template[type[0]][type[1]][type[2]];
671584865Sobrien    }
671684865Sobrien
671784865Sobrien  /* initialize instructions with appropriate nops:  */
671884865Sobrien  for (i = 0; i < 3; ++i)
671984865Sobrien    insn[i] = nop[ia64_templ_desc[template].exec_unit[i]];
672084865Sobrien
672184865Sobrien  f = frag_more (16);
672284865Sobrien
6723218822Sdim  /* Check to see if this bundle is at an offset that is a multiple of 16-bytes
6724218822Sdim     from the start of the frag.  */
6725218822Sdim  addr_mod = frag_now_fix () & 15;
6726218822Sdim  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
6727218822Sdim    as_bad (_("instruction address is not a multiple of 16"));
6728218822Sdim  frag_now->insn_addr = addr_mod;
6729218822Sdim  frag_now->has_code = 1;
6730218822Sdim
673184865Sobrien  /* now fill in slots with as many insns as possible:  */
673284865Sobrien  curr = first;
673384865Sobrien  idesc = md.slot[curr].idesc;
673484865Sobrien  end_of_insn_group = 0;
6735218822Sdim  last_slot = -1;
673684865Sobrien  for (i = 0; i < 3 && md.num_slots_in_use > 0; ++i)
673784865Sobrien    {
6738130561Sobrien      /* If we have unwind records, we may need to update some now.  */
6739218822Sdim      unw_rec_list *ptr = md.slot[curr].unwind_record;
6740218822Sdim      unw_rec_list *end_ptr = NULL;
6741218822Sdim
6742130561Sobrien      if (ptr)
6743130561Sobrien	{
6744130561Sobrien	  /* Find the last prologue/body record in the list for the current
6745130561Sobrien	     insn, and set the slot number for all records up to that point.
6746130561Sobrien	     This needs to be done now, because prologue/body records refer to
6747130561Sobrien	     the current point, not the point after the instruction has been
6748130561Sobrien	     issued.  This matters because there may have been nops emitted
6749130561Sobrien	     meanwhile.  Any non-prologue non-body record followed by a
6750130561Sobrien	     prologue/body record must also refer to the current point.  */
6751218822Sdim	  unw_rec_list *last_ptr;
6752218822Sdim
6753218822Sdim	  for (j = 1; end_ptr == NULL && j < md.num_slots_in_use; ++j)
6754218822Sdim	    end_ptr = md.slot[(curr + j) % NUM_SLOTS].unwind_record;
6755218822Sdim	  for (last_ptr = NULL; ptr != end_ptr; ptr = ptr->next)
6756130561Sobrien	    if (ptr->r.type == prologue || ptr->r.type == prologue_gr
6757130561Sobrien		|| ptr->r.type == body)
6758130561Sobrien	      last_ptr = ptr;
6759130561Sobrien	  if (last_ptr)
6760130561Sobrien	    {
6761130561Sobrien	      /* Make last_ptr point one after the last prologue/body
6762130561Sobrien		 record.  */
6763130561Sobrien	      last_ptr = last_ptr->next;
6764130561Sobrien	      for (ptr = md.slot[curr].unwind_record; ptr != last_ptr;
6765130561Sobrien		   ptr = ptr->next)
6766130561Sobrien		{
6767130561Sobrien		  ptr->slot_number = (unsigned long) f + i;
6768130561Sobrien		  ptr->slot_frag = frag_now;
6769130561Sobrien		}
6770130561Sobrien	      /* Remove the initialized records, so that we won't accidentally
6771130561Sobrien		 update them again if we insert a nop and continue.  */
6772130561Sobrien	      md.slot[curr].unwind_record = last_ptr;
6773130561Sobrien	    }
6774130561Sobrien	}
677584865Sobrien
6776218822Sdim      manual_bundling_off = md.slot[curr].manual_bundling_off;
6777218822Sdim      if (md.slot[curr].manual_bundling_on)
677884865Sobrien	{
6779218822Sdim	  if (curr == first)
6780218822Sdim	    manual_bundling = 1;
678184865Sobrien	  else
6782218822Sdim	  break; /* Need to start a new bundle.  */
678384865Sobrien	}
6784218822Sdim
6785218822Sdim      /* If this instruction specifies a template, then it must be the first
6786218822Sdim	 instruction of a bundle.  */
6787218822Sdim      if (curr != first && md.slot[curr].user_template >= 0)
6788218822Sdim	break;
6789218822Sdim
6790218822Sdim      if (idesc->flags & IA64_OPCODE_SLOT2)
6791218822Sdim	{
6792218822Sdim	  if (manual_bundling && !manual_bundling_off)
6793218822Sdim	    {
6794218822Sdim	      as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
6795218822Sdim			    "`%s' must be last in bundle", idesc->name);
6796218822Sdim	      if (i < 2)
6797218822Sdim		manual_bundling = -1; /* Suppress meaningless post-loop errors.  */
6798218822Sdim	    }
6799218822Sdim	  i = 2;
6800218822Sdim	}
680184865Sobrien      if (idesc->flags & IA64_OPCODE_LAST)
680284865Sobrien	{
680384865Sobrien	  int required_slot;
680484865Sobrien	  unsigned int required_template;
680584865Sobrien
680684865Sobrien	  /* If we need a stop bit after an M slot, our only choice is
680784865Sobrien	     template 5 (M;;MI).  If we need a stop bit after a B
680884865Sobrien	     slot, our only choice is to place it at the end of the
680984865Sobrien	     bundle, because the only available templates are MIB,
681084865Sobrien	     MBB, BBB, MMB, and MFB.  We don't handle anything other
681184865Sobrien	     than M and B slots because these are the only kind of
681284865Sobrien	     instructions that can have the IA64_OPCODE_LAST bit set.  */
681384865Sobrien	  required_template = template;
681484865Sobrien	  switch (idesc->type)
681584865Sobrien	    {
681684865Sobrien	    case IA64_TYPE_M:
681784865Sobrien	      required_slot = 0;
681884865Sobrien	      required_template = 5;
681984865Sobrien	      break;
682084865Sobrien
682184865Sobrien	    case IA64_TYPE_B:
682284865Sobrien	      required_slot = 2;
682384865Sobrien	      break;
682484865Sobrien
682584865Sobrien	    default:
682684865Sobrien	      as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
682784865Sobrien			    "Internal error: don't know how to force %s to end"
682884865Sobrien			    "of instruction group", idesc->name);
682984865Sobrien	      required_slot = i;
683084865Sobrien	      break;
683184865Sobrien	    }
6832218822Sdim	  if (manual_bundling
6833218822Sdim	      && (i > required_slot
6834218822Sdim		  || (required_slot == 2 && !manual_bundling_off)
6835218822Sdim		  || (user_template >= 0
6836218822Sdim		      /* Changing from MMI to M;MI is OK.  */
6837218822Sdim		      && (template ^ required_template) > 1)))
6838218822Sdim	    {
6839218822Sdim	      as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
6840218822Sdim			    "`%s' must be last in instruction group",
6841218822Sdim			    idesc->name);
6842218822Sdim	      if (i < 2 && required_slot == 2 && !manual_bundling_off)
6843218822Sdim		manual_bundling = -1; /* Suppress meaningless post-loop errors.  */
6844218822Sdim	    }
684584865Sobrien	  if (required_slot < i)
684684865Sobrien	    /* Can't fit this instruction.  */
684784865Sobrien	    break;
684884865Sobrien
684984865Sobrien	  i = required_slot;
685084865Sobrien	  if (required_template != template)
685184865Sobrien	    {
685284865Sobrien	      /* If we switch the template, we need to reset the NOPs
685384865Sobrien	         after slot i.  The slot-types of the instructions ahead
685484865Sobrien	         of i never change, so we don't need to worry about
685584865Sobrien	         changing NOPs in front of this slot.  */
685684865Sobrien	      for (j = i; j < 3; ++j)
685784865Sobrien	        insn[j] = nop[ia64_templ_desc[required_template].exec_unit[j]];
6858218822Sdim
6859218822Sdim	      /* We just picked a template that includes the stop bit in the
6860218822Sdim		 middle, so we don't need another one emitted later.  */
6861218822Sdim	      md.slot[curr].end_of_insn_group = 0;
686284865Sobrien	    }
686384865Sobrien	  template = required_template;
686484865Sobrien	}
686584865Sobrien      if (curr != first && md.slot[curr].label_fixups)
686684865Sobrien	{
6867218822Sdim	  if (manual_bundling)
6868218822Sdim	    {
6869218822Sdim	      as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
687084865Sobrien			  "Label must be first in a bundle");
6871218822Sdim	      manual_bundling = -1; /* Suppress meaningless post-loop errors.  */
6872218822Sdim	    }
687384865Sobrien	  /* This insn must go into the first slot of a bundle.  */
687484865Sobrien	  break;
687584865Sobrien	}
687684865Sobrien
687784865Sobrien      if (end_of_insn_group && md.num_slots_in_use >= 1)
687884865Sobrien	{
687984865Sobrien	  /* We need an instruction group boundary in the middle of a
688084865Sobrien	     bundle.  See if we can switch to an other template with
688184865Sobrien	     an appropriate boundary.  */
688284865Sobrien
688384865Sobrien	  orig_template = template;
688484865Sobrien	  if (i == 1 && (user_template == 4
688584865Sobrien			 || (user_template < 0
688684865Sobrien			     && (ia64_templ_desc[template].exec_unit[0]
688784865Sobrien				 == IA64_UNIT_M))))
688884865Sobrien	    {
688984865Sobrien	      template = 5;
689084865Sobrien	      end_of_insn_group = 0;
689184865Sobrien	    }
689284865Sobrien	  else if (i == 2 && (user_template == 0
689384865Sobrien			      || (user_template < 0
689484865Sobrien				  && (ia64_templ_desc[template].exec_unit[1]
689584865Sobrien				      == IA64_UNIT_I)))
689684865Sobrien		   /* This test makes sure we don't switch the template if
689784865Sobrien		      the next instruction is one that needs to be first in
689884865Sobrien		      an instruction group.  Since all those instructions are
689984865Sobrien		      in the M group, there is no way such an instruction can
690084865Sobrien		      fit in this bundle even if we switch the template.  The
690184865Sobrien		      reason we have to check for this is that otherwise we
690284865Sobrien		      may end up generating "MI;;I M.." which has the deadly
690384865Sobrien		      effect that the second M instruction is no longer the
6904218822Sdim		      first in the group! --davidm 99/12/16  */
690584865Sobrien		   && (idesc->flags & IA64_OPCODE_FIRST) == 0)
690684865Sobrien	    {
690784865Sobrien	      template = 1;
690884865Sobrien	      end_of_insn_group = 0;
690984865Sobrien	    }
6910218822Sdim	  else if (i == 1
6911218822Sdim		   && user_template == 0
6912218822Sdim		   && !(idesc->flags & IA64_OPCODE_FIRST))
6913218822Sdim	    /* Use the next slot.  */
6914218822Sdim	    continue;
691584865Sobrien	  else if (curr != first)
691684865Sobrien	    /* can't fit this insn */
691784865Sobrien	    break;
691884865Sobrien
691984865Sobrien	  if (template != orig_template)
692084865Sobrien	    /* if we switch the template, we need to reset the NOPs
692184865Sobrien	       after slot i.  The slot-types of the instructions ahead
692284865Sobrien	       of i never change, so we don't need to worry about
692384865Sobrien	       changing NOPs in front of this slot.  */
692484865Sobrien	    for (j = i; j < 3; ++j)
692584865Sobrien	      insn[j] = nop[ia64_templ_desc[template].exec_unit[j]];
692684865Sobrien	}
692784865Sobrien      required_unit = ia64_templ_desc[template].exec_unit[i];
692884865Sobrien
6929130561Sobrien      /* resolve dynamic opcodes such as "break", "hint", and "nop":  */
693084865Sobrien      if (idesc->type == IA64_TYPE_DYN)
693184865Sobrien	{
6932218822Sdim	  enum ia64_opnd opnd1, opnd2;
6933218822Sdim
693484865Sobrien	  if ((strcmp (idesc->name, "nop") == 0)
693584865Sobrien	      || (strcmp (idesc->name, "break") == 0))
693684865Sobrien	    insn_unit = required_unit;
6937218822Sdim	  else if (strcmp (idesc->name, "hint") == 0)
693884865Sobrien	    {
6939218822Sdim	      insn_unit = required_unit;
6940218822Sdim	      if (required_unit == IA64_UNIT_B)
6941218822Sdim		{
6942218822Sdim		  switch (md.hint_b)
6943218822Sdim		    {
6944218822Sdim		    case hint_b_ok:
6945218822Sdim		      break;
6946218822Sdim		    case hint_b_warning:
6947218822Sdim		      as_warn ("hint in B unit may be treated as nop");
6948218822Sdim		      break;
6949218822Sdim		    case hint_b_error:
6950218822Sdim		      /* When manual bundling is off and there is no
6951218822Sdim			 user template, we choose a different unit so
6952218822Sdim			 that hint won't go into the current slot. We
6953218822Sdim			 will fill the current bundle with nops and
6954218822Sdim			 try to put hint into the next bundle.  */
6955218822Sdim		      if (!manual_bundling && user_template < 0)
6956218822Sdim			insn_unit = IA64_UNIT_I;
6957218822Sdim		      else
6958218822Sdim			as_bad ("hint in B unit can't be used");
6959218822Sdim		      break;
6960218822Sdim		    }
6961218822Sdim		}
6962218822Sdim	    }
6963218822Sdim	  else if (strcmp (idesc->name, "chk.s") == 0
6964218822Sdim	      || strcmp (idesc->name, "mov") == 0)
6965218822Sdim	    {
696684865Sobrien	      insn_unit = IA64_UNIT_M;
6967218822Sdim	      if (required_unit == IA64_UNIT_I
6968218822Sdim		  || (required_unit == IA64_UNIT_F && template == 6))
696984865Sobrien		insn_unit = IA64_UNIT_I;
697084865Sobrien	    }
697184865Sobrien	  else
697284865Sobrien	    as_fatal ("emit_one_bundle: unexpected dynamic op");
697384865Sobrien
6974218822Sdim	  snprintf (mnemonic, sizeof (mnemonic), "%s.%c",
6975218822Sdim		    idesc->name, "?imbfxx"[insn_unit]);
6976218822Sdim	  opnd1 = idesc->operands[0];
6977218822Sdim	  opnd2 = idesc->operands[1];
697884865Sobrien	  ia64_free_opcode (idesc);
6979218822Sdim	  idesc = ia64_find_opcode (mnemonic);
6980218822Sdim	  /* moves to/from ARs have collisions */
6981218822Sdim	  if (opnd1 == IA64_OPND_AR3 || opnd2 == IA64_OPND_AR3)
6982218822Sdim	    {
6983218822Sdim	      while (idesc != NULL
6984218822Sdim		     && (idesc->operands[0] != opnd1
6985218822Sdim			 || idesc->operands[1] != opnd2))
6986218822Sdim		idesc = get_next_opcode (idesc);
6987218822Sdim	    }
6988218822Sdim	  md.slot[curr].idesc = idesc;
698984865Sobrien	}
699084865Sobrien      else
699184865Sobrien	{
699284865Sobrien	  insn_type = idesc->type;
699384865Sobrien	  insn_unit = IA64_UNIT_NIL;
699484865Sobrien	  switch (insn_type)
699584865Sobrien	    {
699684865Sobrien	    case IA64_TYPE_A:
699784865Sobrien	      if (required_unit == IA64_UNIT_I || required_unit == IA64_UNIT_M)
699884865Sobrien		insn_unit = required_unit;
699984865Sobrien	      break;
700084865Sobrien	    case IA64_TYPE_X: insn_unit = IA64_UNIT_L; break;
700184865Sobrien	    case IA64_TYPE_I: insn_unit = IA64_UNIT_I; break;
700284865Sobrien	    case IA64_TYPE_M: insn_unit = IA64_UNIT_M; break;
700384865Sobrien	    case IA64_TYPE_B: insn_unit = IA64_UNIT_B; break;
700484865Sobrien	    case IA64_TYPE_F: insn_unit = IA64_UNIT_F; break;
700584865Sobrien	    default:				       break;
700684865Sobrien	    }
700784865Sobrien	}
700884865Sobrien
700984865Sobrien      if (insn_unit != required_unit)
7010218822Sdim	continue;		/* Try next slot.  */
7011218822Sdim
7012218822Sdim      /* Now is a good time to fix up the labels for this insn.  */
7013218822Sdim      mark_label = FALSE;
7014218822Sdim      for (lfix = md.slot[curr].label_fixups; lfix; lfix = lfix->next)
701584865Sobrien	{
7016218822Sdim	  S_SET_VALUE (lfix->sym, frag_now_fix () - 16);
7017218822Sdim	  symbol_set_frag (lfix->sym, frag_now);
7018218822Sdim	  mark_label |= lfix->dw2_mark_labels;
701984865Sobrien	}
7020218822Sdim      for (lfix = md.slot[curr].tag_fixups; lfix; lfix = lfix->next)
7021218822Sdim	{
7022218822Sdim	  S_SET_VALUE (lfix->sym, frag_now_fix () - 16 + i);
7023218822Sdim	  symbol_set_frag (lfix->sym, frag_now);
7024218822Sdim	}
702584865Sobrien
7026218822Sdim      if (debug_type == DEBUG_DWARF2
7027218822Sdim	  || md.slot[curr].loc_directive_seen
7028218822Sdim	  || mark_label)
7029218822Sdim	{
7030218822Sdim	  bfd_vma addr = frag_now->fr_address + frag_now_fix () - 16 + i;
703184865Sobrien
7032218822Sdim	  md.slot[curr].loc_directive_seen = 0;
7033218822Sdim	  if (mark_label)
7034218822Sdim	    md.slot[curr].debug_line.flags |= DWARF2_FLAG_BASIC_BLOCK;
703584865Sobrien
7036218822Sdim	  dwarf2_gen_line_info (addr, &md.slot[curr].debug_line);
7037218822Sdim	}
703884865Sobrien
703984865Sobrien      build_insn (md.slot + curr, insn + i);
704084865Sobrien
7041130561Sobrien      ptr = md.slot[curr].unwind_record;
7042130561Sobrien      if (ptr)
7043130561Sobrien	{
7044130561Sobrien	  /* Set slot numbers for all remaining unwind records belonging to the
7045130561Sobrien	     current insn.  There can not be any prologue/body unwind records
7046130561Sobrien	     here.  */
7047130561Sobrien	  for (; ptr != end_ptr; ptr = ptr->next)
7048130561Sobrien	    {
7049130561Sobrien	      ptr->slot_number = (unsigned long) f + i;
7050130561Sobrien	      ptr->slot_frag = frag_now;
7051130561Sobrien	    }
7052130561Sobrien	  md.slot[curr].unwind_record = NULL;
7053130561Sobrien	}
705484865Sobrien
705584865Sobrien      if (required_unit == IA64_UNIT_L)
705684865Sobrien	{
705784865Sobrien	  know (i == 1);
705884865Sobrien	  /* skip one slot for long/X-unit instructions */
705984865Sobrien	  ++i;
706084865Sobrien	}
706184865Sobrien      --md.num_slots_in_use;
7062218822Sdim      last_slot = i;
706384865Sobrien
706484865Sobrien      for (j = 0; j < md.slot[curr].num_fixups; ++j)
706584865Sobrien	{
706684865Sobrien	  ifix = md.slot[curr].fixup + j;
706784865Sobrien	  fix = fix_new_exp (frag_now, frag_now_fix () - 16 + i, 8,
706884865Sobrien			     &ifix->expr, ifix->is_pcrel, ifix->code);
706984865Sobrien	  fix->tc_fix_data.opnd = ifix->opnd;
707084865Sobrien	  fix->fx_file = md.slot[curr].src_file;
707184865Sobrien	  fix->fx_line = md.slot[curr].src_line;
707284865Sobrien	}
707384865Sobrien
707484865Sobrien      end_of_insn_group = md.slot[curr].end_of_insn_group;
707584865Sobrien
707684865Sobrien      /* clear slot:  */
707784865Sobrien      ia64_free_opcode (md.slot[curr].idesc);
707884865Sobrien      memset (md.slot + curr, 0, sizeof (md.slot[curr]));
707984865Sobrien      md.slot[curr].user_template = -1;
708084865Sobrien
708184865Sobrien      if (manual_bundling_off)
708284865Sobrien	{
708384865Sobrien	  manual_bundling = 0;
708484865Sobrien	  break;
708584865Sobrien	}
708684865Sobrien      curr = (curr + 1) % NUM_SLOTS;
708784865Sobrien      idesc = md.slot[curr].idesc;
708884865Sobrien    }
7089218822Sdim
7090218822Sdim  /* A user template was specified, but the first following instruction did
7091218822Sdim     not fit.  This can happen with or without manual bundling.  */
7092218822Sdim  if (md.num_slots_in_use > 0 && last_slot < 0)
709384865Sobrien    {
7094218822Sdim      as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
7095218822Sdim		    "`%s' does not fit into %s template",
7096218822Sdim		    idesc->name, ia64_templ_desc[template].name);
7097218822Sdim      /* Drop first insn so we don't livelock.  */
7098218822Sdim      --md.num_slots_in_use;
7099218822Sdim      know (curr == first);
7100218822Sdim      ia64_free_opcode (md.slot[curr].idesc);
7101218822Sdim      memset (md.slot + curr, 0, sizeof (md.slot[curr]));
7102218822Sdim      md.slot[curr].user_template = -1;
7103218822Sdim    }
7104218822Sdim  else if (manual_bundling > 0)
7105218822Sdim    {
710684865Sobrien      if (md.num_slots_in_use > 0)
7107218822Sdim	{
7108218822Sdim	  if (last_slot >= 2)
7109218822Sdim	    as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
7110218822Sdim			  "`%s' does not fit into bundle", idesc->name);
7111218822Sdim	  else
7112218822Sdim	    {
7113218822Sdim	      const char *where;
7114218822Sdim
7115218822Sdim	      if (template == 2)
7116218822Sdim		where = "X slot";
7117218822Sdim	      else if (last_slot == 0)
7118218822Sdim		where = "slots 2 or 3";
7119218822Sdim	      else
7120218822Sdim		where = "slot 3";
7121218822Sdim	      as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
7122218822Sdim			    "`%s' can't go in %s of %s template",
7123218822Sdim			    idesc->name, where, ia64_templ_desc[template].name);
7124218822Sdim	    }
7125218822Sdim	}
712684865Sobrien      else
712784865Sobrien	as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
712884865Sobrien		      "Missing '}' at end of file");
712984865Sobrien    }
7130218822Sdim
713184865Sobrien  know (md.num_slots_in_use < NUM_SLOTS);
713284865Sobrien
713384865Sobrien  t0 = end_of_insn_group | (template << 1) | (insn[0] << 5) | (insn[1] << 46);
713484865Sobrien  t1 = ((insn[1] >> 18) & 0x7fffff) | (insn[2] << 23);
713584865Sobrien
713684865Sobrien  number_to_chars_littleendian (f + 0, t0, 8);
713784865Sobrien  number_to_chars_littleendian (f + 8, t1, 8);
713884865Sobrien}
713984865Sobrien
714084865Sobrienint
714184865Sobrienmd_parse_option (c, arg)
714284865Sobrien     int c;
714384865Sobrien     char *arg;
714484865Sobrien{
714589857Sobrien
714684865Sobrien  switch (c)
714784865Sobrien    {
714884865Sobrien    /* Switches from the Intel assembler.  */
714984865Sobrien    case 'm':
715084865Sobrien      if (strcmp (arg, "ilp64") == 0
715184865Sobrien	  || strcmp (arg, "lp64") == 0
715284865Sobrien	  || strcmp (arg, "p64") == 0)
715384865Sobrien	{
715484865Sobrien	  md.flags |= EF_IA_64_ABI64;
715584865Sobrien	}
715684865Sobrien      else if (strcmp (arg, "ilp32") == 0)
715784865Sobrien	{
715884865Sobrien	  md.flags &= ~EF_IA_64_ABI64;
715984865Sobrien	}
716084865Sobrien      else if (strcmp (arg, "le") == 0)
716184865Sobrien	{
716284865Sobrien	  md.flags &= ~EF_IA_64_BE;
7163218822Sdim	  default_big_endian = 0;
716484865Sobrien	}
716584865Sobrien      else if (strcmp (arg, "be") == 0)
716684865Sobrien	{
716784865Sobrien	  md.flags |= EF_IA_64_BE;
7168218822Sdim	  default_big_endian = 1;
716984865Sobrien	}
7170218822Sdim      else if (strncmp (arg, "unwind-check=", 13) == 0)
7171218822Sdim	{
7172218822Sdim	  arg += 13;
7173218822Sdim	  if (strcmp (arg, "warning") == 0)
7174218822Sdim	    md.unwind_check = unwind_check_warning;
7175218822Sdim	  else if (strcmp (arg, "error") == 0)
7176218822Sdim	    md.unwind_check = unwind_check_error;
7177218822Sdim	  else
7178218822Sdim	    return 0;
7179218822Sdim	}
7180218822Sdim      else if (strncmp (arg, "hint.b=", 7) == 0)
7181218822Sdim	{
7182218822Sdim	  arg += 7;
7183218822Sdim	  if (strcmp (arg, "ok") == 0)
7184218822Sdim	    md.hint_b = hint_b_ok;
7185218822Sdim	  else if (strcmp (arg, "warning") == 0)
7186218822Sdim	    md.hint_b = hint_b_warning;
7187218822Sdim	  else if (strcmp (arg, "error") == 0)
7188218822Sdim	    md.hint_b = hint_b_error;
7189218822Sdim	  else
7190218822Sdim	    return 0;
7191218822Sdim	}
7192218822Sdim      else if (strncmp (arg, "tune=", 5) == 0)
7193218822Sdim	{
7194218822Sdim	  arg += 5;
7195218822Sdim	  if (strcmp (arg, "itanium1") == 0)
7196218822Sdim	    md.tune = itanium1;
7197218822Sdim	  else if (strcmp (arg, "itanium2") == 0)
7198218822Sdim	    md.tune = itanium2;
7199218822Sdim	  else
7200218822Sdim	    return 0;
7201218822Sdim	}
720284865Sobrien      else
720384865Sobrien	return 0;
720484865Sobrien      break;
720584865Sobrien
720684865Sobrien    case 'N':
720784865Sobrien      if (strcmp (arg, "so") == 0)
720884865Sobrien	{
720984865Sobrien	  /* Suppress signon message.  */
721084865Sobrien	}
721184865Sobrien      else if (strcmp (arg, "pi") == 0)
721284865Sobrien	{
721384865Sobrien	  /* Reject privileged instructions.  FIXME */
721484865Sobrien	}
721584865Sobrien      else if (strcmp (arg, "us") == 0)
721684865Sobrien	{
721784865Sobrien	  /* Allow union of signed and unsigned range.  FIXME */
721884865Sobrien	}
721984865Sobrien      else if (strcmp (arg, "close_fcalls") == 0)
722084865Sobrien	{
722184865Sobrien	  /* Do not resolve global function calls.  */
722284865Sobrien	}
722384865Sobrien      else
722484865Sobrien	return 0;
722584865Sobrien      break;
722684865Sobrien
722784865Sobrien    case 'C':
722884865Sobrien      /* temp[="prefix"]  Insert temporary labels into the object file
722984865Sobrien			  symbol table prefixed by "prefix".
723084865Sobrien			  Default prefix is ":temp:".
723184865Sobrien       */
723284865Sobrien      break;
723384865Sobrien
723484865Sobrien    case 'a':
723584865Sobrien      /* indirect=<tgt>	Assume unannotated indirect branches behavior
723684865Sobrien			according to <tgt> --
723784865Sobrien			exit:	branch out from the current context (default)
723884865Sobrien			labels:	all labels in context may be branch targets
723984865Sobrien       */
724084865Sobrien      if (strncmp (arg, "indirect=", 9) != 0)
724184865Sobrien        return 0;
724284865Sobrien      break;
724384865Sobrien
724484865Sobrien    case 'x':
724584865Sobrien      /* -X conflicts with an ignored option, use -x instead */
724684865Sobrien      md.detect_dv = 1;
724784865Sobrien      if (!arg || strcmp (arg, "explicit") == 0)
724884865Sobrien	{
724984865Sobrien	  /* set default mode to explicit */
725084865Sobrien	  md.default_explicit_mode = 1;
725184865Sobrien	  break;
725284865Sobrien	}
725384865Sobrien      else if (strcmp (arg, "auto") == 0)
725484865Sobrien	{
725584865Sobrien	  md.default_explicit_mode = 0;
725684865Sobrien	}
7257218822Sdim      else if (strcmp (arg, "none") == 0)
7258218822Sdim	{
7259218822Sdim	  md.detect_dv = 0;
7260218822Sdim	}
726184865Sobrien      else if (strcmp (arg, "debug") == 0)
726284865Sobrien	{
726384865Sobrien	  md.debug_dv = 1;
726484865Sobrien	}
726584865Sobrien      else if (strcmp (arg, "debugx") == 0)
726684865Sobrien	{
726784865Sobrien	  md.default_explicit_mode = 1;
726884865Sobrien	  md.debug_dv = 1;
726984865Sobrien	}
7270218822Sdim      else if (strcmp (arg, "debugn") == 0)
7271218822Sdim	{
7272218822Sdim	  md.debug_dv = 1;
7273218822Sdim	  md.detect_dv = 0;
7274218822Sdim	}
727584865Sobrien      else
727684865Sobrien	{
727784865Sobrien	  as_bad (_("Unrecognized option '-x%s'"), arg);
727884865Sobrien	}
727984865Sobrien      break;
728084865Sobrien
728184865Sobrien    case 'S':
728284865Sobrien      /* nops		Print nops statistics.  */
728384865Sobrien      break;
728484865Sobrien
728584865Sobrien    /* GNU specific switches for gcc.  */
728684865Sobrien    case OPTION_MCONSTANT_GP:
728784865Sobrien      md.flags |= EF_IA_64_CONS_GP;
728884865Sobrien      break;
728984865Sobrien
729084865Sobrien    case OPTION_MAUTO_PIC:
729184865Sobrien      md.flags |= EF_IA_64_NOFUNCDESC_CONS_GP;
729284865Sobrien      break;
729384865Sobrien
729484865Sobrien    default:
729584865Sobrien      return 0;
729684865Sobrien    }
729784865Sobrien
729884865Sobrien  return 1;
729984865Sobrien}
730084865Sobrien
730184865Sobrienvoid
730284865Sobrienmd_show_usage (stream)
730384865Sobrien     FILE *stream;
730484865Sobrien{
730584865Sobrien  fputs (_("\
730684865SobrienIA-64 options:\n\
730792828Sobrien  --mconstant-gp	  mark output file as using the constant-GP model\n\
730892828Sobrien			  (sets ELF header flag EF_IA_64_CONS_GP)\n\
730992828Sobrien  --mauto-pic		  mark output file as using the constant-GP model\n\
731092828Sobrien			  without function descriptors (sets ELF header flag\n\
731192828Sobrien			  EF_IA_64_NOFUNCDESC_CONS_GP)\n\
731284865Sobrien  -milp32|-milp64|-mlp64|-mp64	select data model (default -mlp64)\n\
731384865Sobrien  -mle | -mbe		  select little- or big-endian byte order (default -mle)\n\
7314218822Sdim  -mtune=[itanium1|itanium2]\n\
7315218822Sdim			  tune for a specific CPU (default -mtune=itanium2)\n\
7316218822Sdim  -munwind-check=[warning|error]\n\
7317218822Sdim			  unwind directive check (default -munwind-check=warning)\n\
7318218822Sdim  -mhint.b=[ok|warning|error]\n\
7319218822Sdim			  hint.b check (default -mhint.b=error)\n\
7320218822Sdim  -x | -xexplicit	  turn on dependency violation checking\n\
7321218822Sdim  -xauto		  automagically remove dependency violations (default)\n\
7322218822Sdim  -xnone		  turn off dependency violation checking\n\
7323218822Sdim  -xdebug		  debug dependency violation checker\n\
7324218822Sdim  -xdebugn		  debug dependency violation checker but turn off\n\
7325218822Sdim			  dependency violation checking\n\
7326218822Sdim  -xdebugx		  debug dependency violation checker and turn on\n\
7327218822Sdim			  dependency violation checking\n"),
732884865Sobrien	stream);
732984865Sobrien}
733084865Sobrien
733189857Sobrienvoid
733289857Sobrienia64_after_parse_args ()
733389857Sobrien{
733489857Sobrien  if (debug_type == DEBUG_STABS)
733589857Sobrien    as_fatal (_("--gstabs is not supported for ia64"));
733689857Sobrien}
733789857Sobrien
733884865Sobrien/* Return true if TYPE fits in TEMPL at SLOT.  */
733984865Sobrien
734084865Sobrienstatic int
734184865Sobrienmatch (int templ, int type, int slot)
734284865Sobrien{
734384865Sobrien  enum ia64_unit unit;
734484865Sobrien  int result;
734584865Sobrien
734684865Sobrien  unit = ia64_templ_desc[templ].exec_unit[slot];
734784865Sobrien  switch (type)
734884865Sobrien    {
734984865Sobrien    case IA64_TYPE_DYN: result = 1; break; /* for nop and break */
735084865Sobrien    case IA64_TYPE_A:
735184865Sobrien      result = (unit == IA64_UNIT_I || unit == IA64_UNIT_M);
735284865Sobrien      break;
735384865Sobrien    case IA64_TYPE_X:	result = (unit == IA64_UNIT_L); break;
735484865Sobrien    case IA64_TYPE_I:	result = (unit == IA64_UNIT_I); break;
735584865Sobrien    case IA64_TYPE_M:	result = (unit == IA64_UNIT_M); break;
735684865Sobrien    case IA64_TYPE_B:	result = (unit == IA64_UNIT_B); break;
735784865Sobrien    case IA64_TYPE_F:	result = (unit == IA64_UNIT_F); break;
735884865Sobrien    default:		result = 0; break;
735984865Sobrien    }
736084865Sobrien  return result;
736184865Sobrien}
736284865Sobrien
7363218822Sdim/* For Itanium 1, add a bit of extra goodness if a nop of type F or B would fit
7364218822Sdim   in TEMPL at SLOT.  For Itanium 2, add a bit of extra goodness if a nop of
7365218822Sdim   type M or I would fit in TEMPL at SLOT.  */
736684865Sobrien
736784865Sobrienstatic inline int
736884865Sobrienextra_goodness (int templ, int slot)
736984865Sobrien{
7370218822Sdim  switch (md.tune)
7371218822Sdim    {
7372218822Sdim    case itanium1:
7373218822Sdim      if (slot == 1 && match (templ, IA64_TYPE_F, slot))
7374218822Sdim	return 2;
7375218822Sdim      else if (slot == 2 && match (templ, IA64_TYPE_B, slot))
7376218822Sdim	return 1;
7377218822Sdim      else
7378218822Sdim	return 0;
7379218822Sdim      break;
7380218822Sdim    case itanium2:
7381218822Sdim      if (match (templ, IA64_TYPE_M, slot)
7382218822Sdim	  || match (templ, IA64_TYPE_I, slot))
7383218822Sdim	/* Favor M- and I-unit NOPs.  We definitely want to avoid
7384218822Sdim	   F-unit and B-unit may cause split-issue or less-than-optimal
7385218822Sdim	   branch-prediction.  */
7386218822Sdim	return 2;
7387218822Sdim      else
7388218822Sdim	return 0;
7389218822Sdim      break;
7390218822Sdim    default:
7391218822Sdim      abort ();
7392218822Sdim      return 0;
7393218822Sdim    }
739484865Sobrien}
739584865Sobrien
739684865Sobrien/* This function is called once, at assembler startup time.  It sets
739784865Sobrien   up all the tables, etc. that the MD part of the assembler will need
739884865Sobrien   that can be determined before arguments are parsed.  */
739984865Sobrienvoid
740084865Sobrienmd_begin ()
740184865Sobrien{
7402218822Sdim  int i, j, k, t, goodness, best, ok;
740384865Sobrien  const char *err;
740484865Sobrien  char name[8];
740584865Sobrien
740684865Sobrien  md.auto_align = 1;
740784865Sobrien  md.explicit_mode = md.default_explicit_mode;
740884865Sobrien
740984865Sobrien  bfd_set_section_alignment (stdoutput, text_section, 4);
741084865Sobrien
7411130561Sobrien  /* Make sure function pointers get initialized.  */
7412130561Sobrien  target_big_endian = -1;
7413218822Sdim  dot_byteorder (default_big_endian);
7414130561Sobrien
7415130561Sobrien  alias_hash = hash_new ();
7416130561Sobrien  alias_name_hash = hash_new ();
7417130561Sobrien  secalias_hash = hash_new ();
7418130561Sobrien  secalias_name_hash = hash_new ();
7419130561Sobrien
7420104834Sobrien  pseudo_func[FUNC_DTP_MODULE].u.sym =
7421104834Sobrien    symbol_new (".<dtpmod>", undefined_section, FUNC_DTP_MODULE,
7422104834Sobrien		&zero_address_frag);
7423104834Sobrien
7424104834Sobrien  pseudo_func[FUNC_DTP_RELATIVE].u.sym =
7425104834Sobrien    symbol_new (".<dtprel>", undefined_section, FUNC_DTP_RELATIVE,
7426104834Sobrien		&zero_address_frag);
7427104834Sobrien
742884865Sobrien  pseudo_func[FUNC_FPTR_RELATIVE].u.sym =
742984865Sobrien    symbol_new (".<fptr>", undefined_section, FUNC_FPTR_RELATIVE,
743084865Sobrien		&zero_address_frag);
743184865Sobrien
743284865Sobrien  pseudo_func[FUNC_GP_RELATIVE].u.sym =
743384865Sobrien    symbol_new (".<gprel>", undefined_section, FUNC_GP_RELATIVE,
743484865Sobrien		&zero_address_frag);
743584865Sobrien
743684865Sobrien  pseudo_func[FUNC_LT_RELATIVE].u.sym =
743784865Sobrien    symbol_new (".<ltoff>", undefined_section, FUNC_LT_RELATIVE,
743884865Sobrien		&zero_address_frag);
743984865Sobrien
7440130561Sobrien  pseudo_func[FUNC_LT_RELATIVE_X].u.sym =
7441130561Sobrien    symbol_new (".<ltoffx>", undefined_section, FUNC_LT_RELATIVE_X,
7442130561Sobrien		&zero_address_frag);
7443130561Sobrien
744484865Sobrien  pseudo_func[FUNC_PC_RELATIVE].u.sym =
744584865Sobrien    symbol_new (".<pcrel>", undefined_section, FUNC_PC_RELATIVE,
744684865Sobrien		&zero_address_frag);
744784865Sobrien
744884865Sobrien  pseudo_func[FUNC_PLT_RELATIVE].u.sym =
744984865Sobrien    symbol_new (".<pltoff>", undefined_section, FUNC_PLT_RELATIVE,
745084865Sobrien		&zero_address_frag);
745184865Sobrien
745284865Sobrien  pseudo_func[FUNC_SEC_RELATIVE].u.sym =
745384865Sobrien    symbol_new (".<secrel>", undefined_section, FUNC_SEC_RELATIVE,
745484865Sobrien		&zero_address_frag);
745584865Sobrien
745684865Sobrien  pseudo_func[FUNC_SEG_RELATIVE].u.sym =
745784865Sobrien    symbol_new (".<segrel>", undefined_section, FUNC_SEG_RELATIVE,
745884865Sobrien		&zero_address_frag);
745984865Sobrien
7460104834Sobrien  pseudo_func[FUNC_TP_RELATIVE].u.sym =
7461104834Sobrien    symbol_new (".<tprel>", undefined_section, FUNC_TP_RELATIVE,
7462104834Sobrien		&zero_address_frag);
7463104834Sobrien
746484865Sobrien  pseudo_func[FUNC_LTV_RELATIVE].u.sym =
746584865Sobrien    symbol_new (".<ltv>", undefined_section, FUNC_LTV_RELATIVE,
746684865Sobrien		&zero_address_frag);
746784865Sobrien
746884865Sobrien  pseudo_func[FUNC_LT_FPTR_RELATIVE].u.sym =
746984865Sobrien    symbol_new (".<ltoff.fptr>", undefined_section, FUNC_LT_FPTR_RELATIVE,
747084865Sobrien		&zero_address_frag);
747184865Sobrien
7472104834Sobrien  pseudo_func[FUNC_LT_DTP_MODULE].u.sym =
7473104834Sobrien    symbol_new (".<ltoff.dtpmod>", undefined_section, FUNC_LT_DTP_MODULE,
7474104834Sobrien		&zero_address_frag);
7475104834Sobrien
7476104834Sobrien  pseudo_func[FUNC_LT_DTP_RELATIVE].u.sym =
7477104834Sobrien    symbol_new (".<ltoff.dptrel>", undefined_section, FUNC_LT_DTP_RELATIVE,
7478104834Sobrien		&zero_address_frag);
7479104834Sobrien
7480104834Sobrien  pseudo_func[FUNC_LT_TP_RELATIVE].u.sym =
7481104834Sobrien    symbol_new (".<ltoff.tprel>", undefined_section, FUNC_LT_TP_RELATIVE,
7482104834Sobrien		&zero_address_frag);
7483104834Sobrien
748489857Sobrien  pseudo_func[FUNC_IPLT_RELOC].u.sym =
748589857Sobrien    symbol_new (".<iplt>", undefined_section, FUNC_IPLT_RELOC,
748689857Sobrien		&zero_address_frag);
748789857Sobrien
7488218822Sdim if (md.tune != itanium1)
7489218822Sdim   {
7490218822Sdim     /* Convert MFI NOPs bundles into MMI NOPs bundles.  */
7491218822Sdim     le_nop[0] = 0x8;
7492218822Sdim     le_nop_stop[0] = 0x9;
7493218822Sdim   }
7494218822Sdim
749584865Sobrien  /* Compute the table of best templates.  We compute goodness as a
7496218822Sdim     base 4 value, in which each match counts for 3.  Match-failures
7497218822Sdim     result in NOPs and we use extra_goodness() to pick the execution
7498218822Sdim     units that are best suited for issuing the NOP.  */
749984865Sobrien  for (i = 0; i < IA64_NUM_TYPES; ++i)
750084865Sobrien    for (j = 0; j < IA64_NUM_TYPES; ++j)
750184865Sobrien      for (k = 0; k < IA64_NUM_TYPES; ++k)
750284865Sobrien	{
750384865Sobrien	  best = 0;
750484865Sobrien	  for (t = 0; t < NELEMS (ia64_templ_desc); ++t)
750584865Sobrien	    {
750684865Sobrien	      goodness = 0;
750784865Sobrien	      if (match (t, i, 0))
750884865Sobrien		{
750984865Sobrien		  if (match (t, j, 1))
751084865Sobrien		    {
7511218822Sdim		      if ((t == 2 && j == IA64_TYPE_X) || match (t, k, 2))
751284865Sobrien			goodness = 3 + 3 + 3;
751384865Sobrien		      else
751484865Sobrien			goodness = 3 + 3 + extra_goodness (t, 2);
751584865Sobrien		    }
751684865Sobrien		  else if (match (t, j, 2))
751784865Sobrien		    goodness = 3 + 3 + extra_goodness (t, 1);
751884865Sobrien		  else
751984865Sobrien		    {
752084865Sobrien		      goodness = 3;
752184865Sobrien		      goodness += extra_goodness (t, 1);
752284865Sobrien		      goodness += extra_goodness (t, 2);
752384865Sobrien		    }
752484865Sobrien		}
752584865Sobrien	      else if (match (t, i, 1))
752684865Sobrien		{
7527218822Sdim		  if ((t == 2 && i == IA64_TYPE_X) || match (t, j, 2))
752884865Sobrien		    goodness = 3 + 3;
752984865Sobrien		  else
753084865Sobrien		    goodness = 3 + extra_goodness (t, 2);
753184865Sobrien		}
753284865Sobrien	      else if (match (t, i, 2))
753384865Sobrien		goodness = 3 + extra_goodness (t, 1);
753484865Sobrien
753584865Sobrien	      if (goodness > best)
753684865Sobrien		{
753784865Sobrien		  best = goodness;
753884865Sobrien		  best_template[i][j][k] = t;
753984865Sobrien		}
754084865Sobrien	    }
754184865Sobrien	}
754284865Sobrien
7543218822Sdim#ifdef DEBUG_TEMPLATES
7544218822Sdim  /* For debugging changes to the best_template calculations.  We don't care
7545218822Sdim     about combinations with invalid instructions, so start the loops at 1.  */
7546218822Sdim  for (i = 0; i < IA64_NUM_TYPES; ++i)
7547218822Sdim    for (j = 0; j < IA64_NUM_TYPES; ++j)
7548218822Sdim      for (k = 0; k < IA64_NUM_TYPES; ++k)
7549218822Sdim	{
7550218822Sdim	  char type_letter[IA64_NUM_TYPES] = { 'n', 'a', 'i', 'm', 'b', 'f',
7551218822Sdim					       'x', 'd' };
7552218822Sdim	  fprintf (stderr, "%c%c%c %s\n", type_letter[i], type_letter[j],
7553218822Sdim		   type_letter[k],
7554218822Sdim		   ia64_templ_desc[best_template[i][j][k]].name);
7555218822Sdim	}
7556218822Sdim#endif
7557218822Sdim
755884865Sobrien  for (i = 0; i < NUM_SLOTS; ++i)
755984865Sobrien    md.slot[i].user_template = -1;
756084865Sobrien
756184865Sobrien  md.pseudo_hash = hash_new ();
756284865Sobrien  for (i = 0; i < NELEMS (pseudo_opcode); ++i)
756384865Sobrien    {
756484865Sobrien      err = hash_insert (md.pseudo_hash, pseudo_opcode[i].name,
756584865Sobrien			 (void *) (pseudo_opcode + i));
756684865Sobrien      if (err)
756784865Sobrien	as_fatal ("ia64.md_begin: can't hash `%s': %s",
756884865Sobrien		  pseudo_opcode[i].name, err);
756984865Sobrien    }
757084865Sobrien
757184865Sobrien  md.reg_hash = hash_new ();
757284865Sobrien  md.dynreg_hash = hash_new ();
757384865Sobrien  md.const_hash = hash_new ();
757484865Sobrien  md.entry_hash = hash_new ();
757584865Sobrien
757684865Sobrien  /* general registers:  */
7577218822Sdim  declare_register_set ("r", 128, REG_GR);
7578218822Sdim  declare_register ("gp", REG_GR +  1);
7579218822Sdim  declare_register ("sp", REG_GR + 12);
7580218822Sdim  declare_register ("tp", REG_GR + 13);
7581218822Sdim  declare_register_set ("ret", 4, REG_GR + 8);
758284865Sobrien
758384865Sobrien  /* floating point registers:  */
7584218822Sdim  declare_register_set ("f", 128, REG_FR);
7585218822Sdim  declare_register_set ("farg", 8, REG_FR + 8);
7586218822Sdim  declare_register_set ("fret", 8, REG_FR + 8);
758784865Sobrien
7588218822Sdim  /* branch registers:  */
7589218822Sdim  declare_register_set ("b", 8, REG_BR);
7590218822Sdim  declare_register ("rp", REG_BR + 0);
7591218822Sdim
7592218822Sdim  /* predicate registers:  */
7593218822Sdim  declare_register_set ("p", 64, REG_P);
7594218822Sdim  declare_register ("pr", REG_PR);
7595218822Sdim  declare_register ("pr.rot", REG_PR_ROT);
7596218822Sdim
759784865Sobrien  /* application registers:  */
7598218822Sdim  declare_register_set ("ar", 128, REG_AR);
7599218822Sdim  for (i = 0; i < NELEMS (ar); ++i)
7600218822Sdim    declare_register (ar[i].name, REG_AR + ar[i].regnum);
760184865Sobrien
760284865Sobrien  /* control registers:  */
7603218822Sdim  declare_register_set ("cr", 128, REG_CR);
7604218822Sdim  for (i = 0; i < NELEMS (cr); ++i)
7605218822Sdim    declare_register (cr[i].name, REG_CR + cr[i].regnum);
760684865Sobrien
7607218822Sdim  declare_register ("ip", REG_IP);
7608218822Sdim  declare_register ("cfm", REG_CFM);
7609218822Sdim  declare_register ("psr", REG_PSR);
7610218822Sdim  declare_register ("psr.l", REG_PSR_L);
7611218822Sdim  declare_register ("psr.um", REG_PSR_UM);
761284865Sobrien
7613218822Sdim  for (i = 0; i < NELEMS (indirect_reg); ++i)
761484865Sobrien    {
7615218822Sdim      unsigned int regnum = indirect_reg[i].regnum;
761684865Sobrien
7617218822Sdim      md.indregsym[regnum - IND_CPUID] = declare_register (indirect_reg[i].name, regnum);
761884865Sobrien    }
761984865Sobrien
762084865Sobrien  /* pseudo-registers used to specify unwind info:  */
762184865Sobrien  declare_register ("psp", REG_PSP);
762284865Sobrien
762384865Sobrien  for (i = 0; i < NELEMS (const_bits); ++i)
762484865Sobrien    {
762584865Sobrien      err = hash_insert (md.const_hash, const_bits[i].name,
762684865Sobrien			 (PTR) (const_bits + i));
762784865Sobrien      if (err)
762884865Sobrien	as_fatal ("Inserting \"%s\" into constant hash table failed: %s",
762984865Sobrien		  name, err);
763084865Sobrien    }
763184865Sobrien
763284865Sobrien  /* Set the architecture and machine depending on defaults and command line
763384865Sobrien     options.  */
763484865Sobrien  if (md.flags & EF_IA_64_ABI64)
763584865Sobrien    ok = bfd_set_arch_mach (stdoutput, bfd_arch_ia64, bfd_mach_ia64_elf64);
763684865Sobrien  else
763784865Sobrien    ok = bfd_set_arch_mach (stdoutput, bfd_arch_ia64, bfd_mach_ia64_elf32);
763884865Sobrien
763984865Sobrien  if (! ok)
764084865Sobrien     as_warn (_("Could not set architecture and machine"));
764184865Sobrien
764289857Sobrien  /* Set the pointer size and pointer shift size depending on md.flags */
764389857Sobrien
764489857Sobrien  if (md.flags & EF_IA_64_ABI64)
764589857Sobrien    {
764689857Sobrien      md.pointer_size = 8;         /* pointers are 8 bytes */
764789857Sobrien      md.pointer_size_shift = 3;   /* alignment is 8 bytes = 2^2 */
764889857Sobrien    }
764989857Sobrien  else
765089857Sobrien    {
765189857Sobrien      md.pointer_size = 4;         /* pointers are 4 bytes */
765289857Sobrien      md.pointer_size_shift = 2;   /* alignment is 4 bytes = 2^2 */
765389857Sobrien    }
765489857Sobrien
765584865Sobrien  md.mem_offset.hint = 0;
765684865Sobrien  md.path = 0;
765784865Sobrien  md.maxpaths = 0;
765884865Sobrien  md.entry_labels = NULL;
765984865Sobrien}
766084865Sobrien
7661218822Sdim/* Set the default options in md.  Cannot do this in md_begin because
7662218822Sdim   that is called after md_parse_option which is where we set the
7663218822Sdim   options in md based on command line options.  */
766484865Sobrien
766584865Sobrienvoid
766684865Sobrienia64_init (argc, argv)
766784865Sobrien     int argc ATTRIBUTE_UNUSED;
766884865Sobrien     char **argv ATTRIBUTE_UNUSED;
766984865Sobrien{
767089857Sobrien  md.flags = MD_FLAGS_DEFAULT;
7671218822Sdim  md.detect_dv = 1;
7672218822Sdim  /* FIXME: We should change it to unwind_check_error someday.  */
7673218822Sdim  md.unwind_check = unwind_check_warning;
7674218822Sdim  md.hint_b = hint_b_error;
7675218822Sdim  md.tune = itanium2;
767684865Sobrien}
767784865Sobrien
767884865Sobrien/* Return a string for the target object file format.  */
767984865Sobrien
768084865Sobrienconst char *
768184865Sobrienia64_target_format ()
768284865Sobrien{
768384865Sobrien  if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
768484865Sobrien    {
768584865Sobrien      if (md.flags & EF_IA_64_BE)
768684865Sobrien	{
768784865Sobrien	  if (md.flags & EF_IA_64_ABI64)
768889857Sobrien#if defined(TE_AIX50)
768989857Sobrien	    return "elf64-ia64-aix-big";
769089857Sobrien#elif defined(TE_HPUX)
769189857Sobrien	    return "elf64-ia64-hpux-big";
769289857Sobrien#else
769384865Sobrien	    return "elf64-ia64-big";
769489857Sobrien#endif
769584865Sobrien	  else
769689857Sobrien#if defined(TE_AIX50)
769789857Sobrien	    return "elf32-ia64-aix-big";
769889857Sobrien#elif defined(TE_HPUX)
769989857Sobrien	    return "elf32-ia64-hpux-big";
770089857Sobrien#else
770184865Sobrien	    return "elf32-ia64-big";
770289857Sobrien#endif
770384865Sobrien	}
770484865Sobrien      else
770584865Sobrien	{
770684865Sobrien	  if (md.flags & EF_IA_64_ABI64)
7707218822Sdim#if defined(TE_AIX50)
770889857Sobrien	    return "elf64-ia64-aix-little";
7709218822Sdim#elif defined(TE_FreeBSD)
7710218822Sdim	    return "elf64-ia64-freebsd";
771189857Sobrien#else
771284865Sobrien	    return "elf64-ia64-little";
771389857Sobrien#endif
771484865Sobrien	  else
771589857Sobrien#ifdef TE_AIX50
771689857Sobrien	    return "elf32-ia64-aix-little";
771789857Sobrien#else
771884865Sobrien	    return "elf32-ia64-little";
771989857Sobrien#endif
772084865Sobrien	}
772184865Sobrien    }
772284865Sobrien  else
772384865Sobrien    return "unknown-format";
772484865Sobrien}
772584865Sobrien
772684865Sobrienvoid
772784865Sobrienia64_end_of_source ()
772884865Sobrien{
772984865Sobrien  /* terminate insn group upon reaching end of file:  */
773084865Sobrien  insn_group_break (1, 0, 0);
773184865Sobrien
773284865Sobrien  /* emits slots we haven't written yet:  */
773384865Sobrien  ia64_flush_insns ();
773484865Sobrien
773584865Sobrien  bfd_set_private_flags (stdoutput, md.flags);
773684865Sobrien
773784865Sobrien  md.mem_offset.hint = 0;
773884865Sobrien}
773984865Sobrien
774084865Sobrienvoid
774184865Sobrienia64_start_line ()
774284865Sobrien{
7743218822Sdim  static int first;
7744218822Sdim
7745218822Sdim  if (!first) {
7746218822Sdim    /* Make sure we don't reference input_line_pointer[-1] when that's
7747218822Sdim       not valid.  */
7748218822Sdim    first = 1;
7749218822Sdim    return;
7750218822Sdim  }
7751218822Sdim
775284865Sobrien  if (md.qp.X_op == O_register)
775384865Sobrien    as_bad ("qualifying predicate not followed by instruction");
775484865Sobrien  md.qp.X_op = O_absent;
775584865Sobrien
775684865Sobrien  if (ignore_input ())
775784865Sobrien    return;
775884865Sobrien
775984865Sobrien  if (input_line_pointer[0] == ';' && input_line_pointer[-1] == ';')
776084865Sobrien    {
776184865Sobrien      if (md.detect_dv && !md.explicit_mode)
7762218822Sdim	{
7763218822Sdim	  static int warned;
7764218822Sdim
7765218822Sdim	  if (!warned)
7766218822Sdim	    {
7767218822Sdim	      warned = 1;
7768218822Sdim	      as_warn (_("Explicit stops are ignored in auto mode"));
7769218822Sdim	    }
7770218822Sdim	}
777184865Sobrien      else
777284865Sobrien	insn_group_break (1, 0, 0);
777384865Sobrien    }
7774218822Sdim  else if (input_line_pointer[-1] == '{')
777584865Sobrien    {
777684865Sobrien      if (md.manual_bundling)
777784865Sobrien	as_warn ("Found '{' when manual bundling is already turned on");
777884865Sobrien      else
777984865Sobrien	CURR_SLOT.manual_bundling_on = 1;
778084865Sobrien      md.manual_bundling = 1;
778184865Sobrien
778284865Sobrien      /* Bundling is only acceptable in explicit mode
778384865Sobrien	 or when in default automatic mode.  */
778484865Sobrien      if (md.detect_dv && !md.explicit_mode)
778584865Sobrien	{
778684865Sobrien	  if (!md.mode_explicitly_set
778784865Sobrien	      && !md.default_explicit_mode)
778884865Sobrien	    dot_dv_mode ('E');
778984865Sobrien	  else
779084865Sobrien	    as_warn (_("Found '{' after explicit switch to automatic mode"));
779184865Sobrien	}
7792218822Sdim    }
7793218822Sdim  else if (input_line_pointer[-1] == '}')
7794218822Sdim    {
779584865Sobrien      if (!md.manual_bundling)
779684865Sobrien	as_warn ("Found '}' when manual bundling is off");
779784865Sobrien      else
779884865Sobrien	PREV_SLOT.manual_bundling_off = 1;
779984865Sobrien      md.manual_bundling = 0;
780084865Sobrien
780184865Sobrien      /* switch back to automatic mode, if applicable */
780284865Sobrien      if (md.detect_dv
780384865Sobrien	  && md.explicit_mode
780484865Sobrien	  && !md.mode_explicitly_set
780584865Sobrien	  && !md.default_explicit_mode)
780684865Sobrien	dot_dv_mode ('A');
7807218822Sdim    }
7808218822Sdim}
780984865Sobrien
7810218822Sdim/* This is a hook for ia64_frob_label, so that it can distinguish tags from
7811218822Sdim   labels.  */
7812218822Sdimstatic int defining_tag = 0;
7813218822Sdim
7814218822Sdimint
7815218822Sdimia64_unrecognized_line (ch)
7816218822Sdim     int ch;
7817218822Sdim{
7818218822Sdim  switch (ch)
7819218822Sdim    {
7820218822Sdim    case '(':
7821218822Sdim      expression_and_evaluate (&md.qp);
7822218822Sdim      if (*input_line_pointer++ != ')')
782384865Sobrien	{
7824218822Sdim	  as_bad ("Expected ')'");
7825218822Sdim	  return 0;
782684865Sobrien	}
7827218822Sdim      if (md.qp.X_op != O_register)
7828218822Sdim	{
7829218822Sdim	  as_bad ("Qualifying predicate expected");
7830218822Sdim	  return 0;
7831218822Sdim	}
7832218822Sdim      if (md.qp.X_add_number < REG_P || md.qp.X_add_number >= REG_P + 64)
7833218822Sdim	{
7834218822Sdim	  as_bad ("Predicate register expected");
7835218822Sdim	  return 0;
7836218822Sdim	}
783784865Sobrien      return 1;
783884865Sobrien
783984865Sobrien    case '[':
784084865Sobrien      {
784184865Sobrien	char *s;
784284865Sobrien	char c;
784384865Sobrien	symbolS *tag;
784484865Sobrien	int temp;
784584865Sobrien
784684865Sobrien	if (md.qp.X_op == O_register)
784784865Sobrien	  {
784884865Sobrien	    as_bad ("Tag must come before qualifying predicate.");
784984865Sobrien	    return 0;
785084865Sobrien	  }
785184865Sobrien
785284865Sobrien	/* This implements just enough of read_a_source_file in read.c to
785384865Sobrien	   recognize labels.  */
785484865Sobrien	if (is_name_beginner (*input_line_pointer))
785584865Sobrien	  {
785684865Sobrien	    s = input_line_pointer;
785784865Sobrien	    c = get_symbol_end ();
785884865Sobrien	  }
785984865Sobrien	else if (LOCAL_LABELS_FB
786089857Sobrien		 && ISDIGIT (*input_line_pointer))
786184865Sobrien	  {
786284865Sobrien	    temp = 0;
786389857Sobrien	    while (ISDIGIT (*input_line_pointer))
786484865Sobrien	      temp = (temp * 10) + *input_line_pointer++ - '0';
786584865Sobrien	    fb_label_instance_inc (temp);
786684865Sobrien	    s = fb_label_name (temp, 0);
786784865Sobrien	    c = *input_line_pointer;
786884865Sobrien	  }
786984865Sobrien	else
787084865Sobrien	  {
787184865Sobrien	    s = NULL;
787284865Sobrien	    c = '\0';
787384865Sobrien	  }
787484865Sobrien	if (c != ':')
787584865Sobrien	  {
787684865Sobrien	    /* Put ':' back for error messages' sake.  */
787784865Sobrien	    *input_line_pointer++ = ':';
787884865Sobrien	    as_bad ("Expected ':'");
787984865Sobrien	    return 0;
788084865Sobrien	  }
788184865Sobrien
788284865Sobrien	defining_tag = 1;
788384865Sobrien	tag = colon (s);
788484865Sobrien	defining_tag = 0;
788584865Sobrien	/* Put ':' back for error messages' sake.  */
788684865Sobrien	*input_line_pointer++ = ':';
788784865Sobrien	if (*input_line_pointer++ != ']')
788884865Sobrien	  {
788984865Sobrien	    as_bad ("Expected ']'");
789084865Sobrien	    return 0;
789184865Sobrien	  }
789284865Sobrien	if (! tag)
789384865Sobrien	  {
789484865Sobrien	    as_bad ("Tag name expected");
789584865Sobrien	    return 0;
789684865Sobrien	  }
789784865Sobrien	return 1;
789884865Sobrien      }
789984865Sobrien
790084865Sobrien    default:
790184865Sobrien      break;
790284865Sobrien    }
790384865Sobrien
790484865Sobrien  /* Not a valid line.  */
790584865Sobrien  return 0;
790684865Sobrien}
790784865Sobrien
790884865Sobrienvoid
790984865Sobrienia64_frob_label (sym)
791084865Sobrien     struct symbol *sym;
791184865Sobrien{
791284865Sobrien  struct label_fix *fix;
791384865Sobrien
791484865Sobrien  /* Tags need special handling since they are not bundle breaks like
791584865Sobrien     labels.  */
791684865Sobrien  if (defining_tag)
791784865Sobrien    {
791884865Sobrien      fix = obstack_alloc (&notes, sizeof (*fix));
791984865Sobrien      fix->sym = sym;
792084865Sobrien      fix->next = CURR_SLOT.tag_fixups;
7921218822Sdim      fix->dw2_mark_labels = FALSE;
792284865Sobrien      CURR_SLOT.tag_fixups = fix;
792384865Sobrien
792484865Sobrien      return;
792584865Sobrien    }
792684865Sobrien
792784865Sobrien  if (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE)
792884865Sobrien    {
792984865Sobrien      md.last_text_seg = now_seg;
793084865Sobrien      fix = obstack_alloc (&notes, sizeof (*fix));
793184865Sobrien      fix->sym = sym;
793284865Sobrien      fix->next = CURR_SLOT.label_fixups;
7933218822Sdim      fix->dw2_mark_labels = dwarf2_loc_mark_labels;
793484865Sobrien      CURR_SLOT.label_fixups = fix;
793584865Sobrien
793684865Sobrien      /* Keep track of how many code entry points we've seen.  */
793784865Sobrien      if (md.path == md.maxpaths)
793884865Sobrien	{
793984865Sobrien	  md.maxpaths += 20;
794084865Sobrien	  md.entry_labels = (const char **)
794184865Sobrien	    xrealloc ((void *) md.entry_labels,
794284865Sobrien		      md.maxpaths * sizeof (char *));
794384865Sobrien	}
794484865Sobrien      md.entry_labels[md.path++] = S_GET_NAME (sym);
794584865Sobrien    }
794684865Sobrien}
794784865Sobrien
7948130561Sobrien#ifdef TE_HPUX
7949130561Sobrien/* The HP-UX linker will give unresolved symbol errors for symbols
7950130561Sobrien   that are declared but unused.  This routine removes declared,
7951130561Sobrien   unused symbols from an object.  */
7952130561Sobrienint
7953130561Sobrienia64_frob_symbol (sym)
7954130561Sobrien     struct symbol *sym;
7955130561Sobrien{
7956130561Sobrien  if ((S_GET_SEGMENT (sym) == &bfd_und_section && ! symbol_used_p (sym) &&
7957130561Sobrien       ELF_ST_VISIBILITY (S_GET_OTHER (sym)) == STV_DEFAULT)
7958130561Sobrien      || (S_GET_SEGMENT (sym) == &bfd_abs_section
7959130561Sobrien	  && ! S_IS_EXTERNAL (sym)))
7960130561Sobrien    return 1;
7961130561Sobrien  return 0;
7962130561Sobrien}
7963130561Sobrien#endif
7964130561Sobrien
796584865Sobrienvoid
796684865Sobrienia64_flush_pending_output ()
796784865Sobrien{
796884865Sobrien  if (!md.keep_pending_output
796984865Sobrien      && bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE)
797084865Sobrien    {
797184865Sobrien      /* ??? This causes many unnecessary stop bits to be emitted.
797284865Sobrien	 Unfortunately, it isn't clear if it is safe to remove this.  */
797384865Sobrien      insn_group_break (1, 0, 0);
797484865Sobrien      ia64_flush_insns ();
797584865Sobrien    }
797684865Sobrien}
797784865Sobrien
797884865Sobrien/* Do ia64-specific expression optimization.  All that's done here is
797984865Sobrien   to transform index expressions that are either due to the indexing
798084865Sobrien   of rotating registers or due to the indexing of indirect register
798184865Sobrien   sets.  */
798284865Sobrienint
798384865Sobrienia64_optimize_expr (l, op, r)
798484865Sobrien     expressionS *l;
798584865Sobrien     operatorT op;
798684865Sobrien     expressionS *r;
798784865Sobrien{
7988218822Sdim  if (op != O_index)
7989218822Sdim    return 0;
7990218822Sdim  resolve_expression (l);
7991218822Sdim  if (l->X_op == O_register)
7992218822Sdim    {
7993218822Sdim      unsigned num_regs = l->X_add_number >> 16;
799484865Sobrien
7995218822Sdim      resolve_expression (r);
7996218822Sdim      if (num_regs)
799784865Sobrien	{
7998218822Sdim	  /* Left side is a .rotX-allocated register.  */
7999218822Sdim	  if (r->X_op != O_constant)
800084865Sobrien	    {
8001218822Sdim	      as_bad ("Rotating register index must be a non-negative constant");
800284865Sobrien	      r->X_add_number = 0;
800384865Sobrien	    }
8004218822Sdim	  else if ((valueT) r->X_add_number >= num_regs)
8005218822Sdim	    {
8006218822Sdim	      as_bad ("Index out of range 0..%u", num_regs - 1);
8007218822Sdim	      r->X_add_number = 0;
8008218822Sdim	    }
800984865Sobrien	  l->X_add_number = (l->X_add_number & 0xffff) + r->X_add_number;
801084865Sobrien	  return 1;
801184865Sobrien	}
8012218822Sdim      else if (l->X_add_number >= IND_CPUID && l->X_add_number <= IND_RR)
801384865Sobrien	{
8014218822Sdim	  if (r->X_op != O_register
8015218822Sdim	      || r->X_add_number < REG_GR
8016218822Sdim	      || r->X_add_number > REG_GR + 127)
801784865Sobrien	    {
8018218822Sdim	      as_bad ("Indirect register index must be a general register");
8019218822Sdim	      r->X_add_number = REG_GR;
802084865Sobrien	    }
802184865Sobrien	  l->X_op = O_index;
8022218822Sdim	  l->X_op_symbol = md.indregsym[l->X_add_number - IND_CPUID];
802384865Sobrien	  l->X_add_number = r->X_add_number;
802484865Sobrien	  return 1;
802584865Sobrien	}
802684865Sobrien    }
8027218822Sdim  as_bad ("Index can only be applied to rotating or indirect registers");
8028218822Sdim  /* Fall back to some register use of which has as little as possible
8029218822Sdim     side effects, to minimize subsequent error messages.  */
8030218822Sdim  l->X_op = O_register;
8031218822Sdim  l->X_add_number = REG_GR + 3;
8032218822Sdim  return 1;
803384865Sobrien}
803484865Sobrien
803584865Sobrienint
8036218822Sdimia64_parse_name (name, e, nextcharP)
803784865Sobrien     char *name;
803884865Sobrien     expressionS *e;
8039218822Sdim     char *nextcharP;
804084865Sobrien{
804184865Sobrien  struct const_desc *cdesc;
804284865Sobrien  struct dynreg *dr = 0;
8043218822Sdim  unsigned int idx;
804484865Sobrien  struct symbol *sym;
804584865Sobrien  char *end;
804684865Sobrien
8047218822Sdim  if (*name == '@')
8048218822Sdim    {
8049218822Sdim      enum pseudo_type pseudo_type = PSEUDO_FUNC_NONE;
8050218822Sdim
8051218822Sdim      /* Find what relocation pseudo-function we're dealing with.  */
8052218822Sdim      for (idx = 0; idx < NELEMS (pseudo_func); ++idx)
8053218822Sdim	if (pseudo_func[idx].name
8054218822Sdim	    && pseudo_func[idx].name[0] == name[1]
8055218822Sdim	    && strcmp (pseudo_func[idx].name + 1, name + 2) == 0)
8056218822Sdim	  {
8057218822Sdim	    pseudo_type = pseudo_func[idx].type;
8058218822Sdim	    break;
8059218822Sdim	  }
8060218822Sdim      switch (pseudo_type)
8061218822Sdim	{
8062218822Sdim	case PSEUDO_FUNC_RELOC:
8063218822Sdim	  end = input_line_pointer;
8064218822Sdim	  if (*nextcharP != '(')
8065218822Sdim	    {
8066218822Sdim	      as_bad ("Expected '('");
8067218822Sdim	      break;
8068218822Sdim	    }
8069218822Sdim	  /* Skip '('.  */
8070218822Sdim	  ++input_line_pointer;
8071218822Sdim	  expression (e);
8072218822Sdim	  if (*input_line_pointer != ')')
8073218822Sdim	    {
8074218822Sdim	      as_bad ("Missing ')'");
8075218822Sdim	      goto done;
8076218822Sdim	    }
8077218822Sdim	  /* Skip ')'.  */
8078218822Sdim	  ++input_line_pointer;
8079218822Sdim	  if (e->X_op != O_symbol)
8080218822Sdim	    {
8081218822Sdim	      if (e->X_op != O_pseudo_fixup)
8082218822Sdim		{
8083218822Sdim		  as_bad ("Not a symbolic expression");
8084218822Sdim		  goto done;
8085218822Sdim		}
8086218822Sdim	      if (idx != FUNC_LT_RELATIVE)
8087218822Sdim		{
8088218822Sdim		  as_bad ("Illegal combination of relocation functions");
8089218822Sdim		  goto done;
8090218822Sdim		}
8091218822Sdim	      switch (S_GET_VALUE (e->X_op_symbol))
8092218822Sdim		{
8093218822Sdim		case FUNC_FPTR_RELATIVE:
8094218822Sdim		  idx = FUNC_LT_FPTR_RELATIVE; break;
8095218822Sdim		case FUNC_DTP_MODULE:
8096218822Sdim		  idx = FUNC_LT_DTP_MODULE; break;
8097218822Sdim		case FUNC_DTP_RELATIVE:
8098218822Sdim		  idx = FUNC_LT_DTP_RELATIVE; break;
8099218822Sdim		case FUNC_TP_RELATIVE:
8100218822Sdim		  idx = FUNC_LT_TP_RELATIVE; break;
8101218822Sdim		default:
8102218822Sdim		  as_bad ("Illegal combination of relocation functions");
8103218822Sdim		  goto done;
8104218822Sdim		}
8105218822Sdim	    }
8106218822Sdim	  /* Make sure gas doesn't get rid of local symbols that are used
8107218822Sdim	     in relocs.  */
8108218822Sdim	  e->X_op = O_pseudo_fixup;
8109218822Sdim	  e->X_op_symbol = pseudo_func[idx].u.sym;
8110218822Sdim	done:
8111218822Sdim	  *nextcharP = *input_line_pointer;
8112218822Sdim	  break;
8113218822Sdim
8114218822Sdim	case PSEUDO_FUNC_CONST:
8115218822Sdim	  e->X_op = O_constant;
8116218822Sdim	  e->X_add_number = pseudo_func[idx].u.ival;
8117218822Sdim	  break;
8118218822Sdim
8119218822Sdim	case PSEUDO_FUNC_REG:
8120218822Sdim	  e->X_op = O_register;
8121218822Sdim	  e->X_add_number = pseudo_func[idx].u.ival;
8122218822Sdim	  break;
8123218822Sdim
8124218822Sdim	default:
8125218822Sdim	  return 0;
8126218822Sdim	}
8127218822Sdim      return 1;
8128218822Sdim    }
8129218822Sdim
813084865Sobrien  /* first see if NAME is a known register name:  */
813184865Sobrien  sym = hash_find (md.reg_hash, name);
813284865Sobrien  if (sym)
813384865Sobrien    {
813484865Sobrien      e->X_op = O_register;
813584865Sobrien      e->X_add_number = S_GET_VALUE (sym);
813684865Sobrien      return 1;
813784865Sobrien    }
813884865Sobrien
813984865Sobrien  cdesc = hash_find (md.const_hash, name);
814084865Sobrien  if (cdesc)
814184865Sobrien    {
814284865Sobrien      e->X_op = O_constant;
814384865Sobrien      e->X_add_number = cdesc->value;
814484865Sobrien      return 1;
814584865Sobrien    }
814684865Sobrien
814784865Sobrien  /* check for inN, locN, or outN:  */
8148218822Sdim  idx = 0;
814984865Sobrien  switch (name[0])
815084865Sobrien    {
815184865Sobrien    case 'i':
815289857Sobrien      if (name[1] == 'n' && ISDIGIT (name[2]))
815384865Sobrien	{
815484865Sobrien	  dr = &md.in;
8155218822Sdim	  idx = 2;
815684865Sobrien	}
815784865Sobrien      break;
815884865Sobrien
815984865Sobrien    case 'l':
816089857Sobrien      if (name[1] == 'o' && name[2] == 'c' && ISDIGIT (name[3]))
816184865Sobrien	{
816284865Sobrien	  dr = &md.loc;
8163218822Sdim	  idx = 3;
816484865Sobrien	}
816584865Sobrien      break;
816684865Sobrien
816784865Sobrien    case 'o':
816889857Sobrien      if (name[1] == 'u' && name[2] == 't' && ISDIGIT (name[3]))
816984865Sobrien	{
817084865Sobrien	  dr = &md.out;
8171218822Sdim	  idx = 3;
817284865Sobrien	}
817384865Sobrien      break;
817484865Sobrien
817584865Sobrien    default:
817684865Sobrien      break;
817784865Sobrien    }
817884865Sobrien
8179218822Sdim  /* Ignore register numbers with leading zeroes, except zero itself.  */
8180218822Sdim  if (dr && (name[idx] != '0' || name[idx + 1] == '\0'))
818184865Sobrien    {
8182218822Sdim      unsigned long regnum;
8183218822Sdim
818484865Sobrien      /* The name is inN, locN, or outN; parse the register number.  */
8185218822Sdim      regnum = strtoul (name + idx, &end, 10);
8186218822Sdim      if (end > name + idx && *end == '\0' && regnum < 96)
818784865Sobrien	{
8188218822Sdim	  if (regnum >= dr->num_regs)
818984865Sobrien	    {
819084865Sobrien	      if (!dr->num_regs)
819184865Sobrien		as_bad ("No current frame");
819284865Sobrien	      else
819384865Sobrien		as_bad ("Register number out of range 0..%u",
819484865Sobrien			dr->num_regs - 1);
819584865Sobrien	      regnum = 0;
819684865Sobrien	    }
819784865Sobrien	  e->X_op = O_register;
819884865Sobrien	  e->X_add_number = dr->base + regnum;
819984865Sobrien	  return 1;
820084865Sobrien	}
820184865Sobrien    }
820284865Sobrien
8203218822Sdim  end = alloca (strlen (name) + 1);
8204218822Sdim  strcpy (end, name);
8205218822Sdim  name = ia64_canonicalize_symbol_name (end);
820684865Sobrien  if ((dr = hash_find (md.dynreg_hash, name)))
820784865Sobrien    {
820884865Sobrien      /* We've got ourselves the name of a rotating register set.
820984865Sobrien	 Store the base register number in the low 16 bits of
821084865Sobrien	 X_add_number and the size of the register set in the top 16
821184865Sobrien	 bits.  */
821284865Sobrien      e->X_op = O_register;
821384865Sobrien      e->X_add_number = dr->base | (dr->num_regs << 16);
821484865Sobrien      return 1;
821584865Sobrien    }
821684865Sobrien  return 0;
821784865Sobrien}
821884865Sobrien
821984865Sobrien/* Remove the '#' suffix that indicates a symbol as opposed to a register.  */
822084865Sobrien
822184865Sobrienchar *
822284865Sobrienia64_canonicalize_symbol_name (name)
822384865Sobrien     char *name;
822484865Sobrien{
8225218822Sdim  size_t len = strlen (name), full = len;
8226218822Sdim
8227218822Sdim  while (len > 0 && name[len - 1] == '#')
8228218822Sdim    --len;
8229218822Sdim  if (len <= 0)
8230218822Sdim    {
8231218822Sdim      if (full > 0)
8232218822Sdim	as_bad ("Standalone `#' is illegal");
8233218822Sdim    }
8234218822Sdim  else if (len < full - 1)
8235218822Sdim    as_warn ("Redundant `#' suffix operators");
8236218822Sdim  name[len] = '\0';
823784865Sobrien  return name;
823884865Sobrien}
823984865Sobrien
824089857Sobrien/* Return true if idesc is a conditional branch instruction.  This excludes
824189857Sobrien   the modulo scheduled branches, and br.ia.  Mod-sched branches are excluded
824289857Sobrien   because they always read/write resources regardless of the value of the
824389857Sobrien   qualifying predicate.  br.ia must always use p0, and hence is always
824489857Sobrien   taken.  Thus this function returns true for branches which can fall
824589857Sobrien   through, and which use no resources if they do fall through.  */
824684865Sobrien
824784865Sobrienstatic int
824884865Sobrienis_conditional_branch (idesc)
824984865Sobrien     struct ia64_opcode *idesc;
825084865Sobrien{
825184865Sobrien  /* br is a conditional branch.  Everything that starts with br. except
825289857Sobrien     br.ia, br.c{loop,top,exit}, and br.w{top,exit} is a conditional branch.
825389857Sobrien     Everything that starts with brl is a conditional branch.  */
825484865Sobrien  return (idesc->name[0] == 'b' && idesc->name[1] == 'r'
825584865Sobrien	  && (idesc->name[2] == '\0'
825689857Sobrien	      || (idesc->name[2] == '.' && idesc->name[3] != 'i'
825789857Sobrien		  && idesc->name[3] != 'c' && idesc->name[3] != 'w')
825889857Sobrien	      || idesc->name[2] == 'l'
825989857Sobrien	      /* br.cond, br.call, br.clr  */
826089857Sobrien	      || (idesc->name[2] == '.' && idesc->name[3] == 'c'
826189857Sobrien		  && (idesc->name[4] == 'a' || idesc->name[4] == 'o'
826289857Sobrien		      || (idesc->name[4] == 'l' && idesc->name[5] == 'r')))));
826384865Sobrien}
826484865Sobrien
826584865Sobrien/* Return whether the given opcode is a taken branch.  If there's any doubt,
826684865Sobrien   returns zero.  */
826784865Sobrien
826884865Sobrienstatic int
826984865Sobrienis_taken_branch (idesc)
827084865Sobrien     struct ia64_opcode *idesc;
827184865Sobrien{
827284865Sobrien  return ((is_conditional_branch (idesc) && CURR_SLOT.qp_regno == 0)
827384865Sobrien	  || strncmp (idesc->name, "br.ia", 5) == 0);
827484865Sobrien}
827584865Sobrien
827684865Sobrien/* Return whether the given opcode is an interruption or rfi.  If there's any
827784865Sobrien   doubt, returns zero.  */
827884865Sobrien
827984865Sobrienstatic int
828084865Sobrienis_interruption_or_rfi (idesc)
828184865Sobrien     struct ia64_opcode *idesc;
828284865Sobrien{
828384865Sobrien  if (strcmp (idesc->name, "rfi") == 0)
828484865Sobrien    return 1;
828584865Sobrien  return 0;
828684865Sobrien}
828784865Sobrien
828884865Sobrien/* Returns the index of the given dependency in the opcode's list of chks, or
828984865Sobrien   -1 if there is no dependency.  */
829084865Sobrien
829184865Sobrienstatic int
829284865Sobriendepends_on (depind, idesc)
829384865Sobrien     int depind;
829484865Sobrien     struct ia64_opcode *idesc;
829584865Sobrien{
829684865Sobrien  int i;
829784865Sobrien  const struct ia64_opcode_dependency *dep = idesc->dependencies;
829884865Sobrien  for (i = 0; i < dep->nchks; i++)
829984865Sobrien    {
830084865Sobrien      if (depind == DEP (dep->chks[i]))
830184865Sobrien	return i;
830284865Sobrien    }
830384865Sobrien  return -1;
830484865Sobrien}
830584865Sobrien
830684865Sobrien/* Determine a set of specific resources used for a particular resource
830784865Sobrien   class.  Returns the number of specific resources identified  For those
830884865Sobrien   cases which are not determinable statically, the resource returned is
830984865Sobrien   marked nonspecific.
831084865Sobrien
831184865Sobrien   Meanings of value in 'NOTE':
831284865Sobrien   1) only read/write when the register number is explicitly encoded in the
831384865Sobrien   insn.
831484865Sobrien   2) only read CFM when accessing a rotating GR, FR, or PR.  mov pr only
831584865Sobrien   accesses CFM when qualifying predicate is in the rotating region.
831684865Sobrien   3) general register value is used to specify an indirect register; not
831784865Sobrien   determinable statically.
831884865Sobrien   4) only read the given resource when bits 7:0 of the indirect index
831984865Sobrien   register value does not match the register number of the resource; not
832084865Sobrien   determinable statically.
832184865Sobrien   5) all rules are implementation specific.
832284865Sobrien   6) only when both the index specified by the reader and the index specified
832384865Sobrien   by the writer have the same value in bits 63:61; not determinable
832484865Sobrien   statically.
832584865Sobrien   7) only access the specified resource when the corresponding mask bit is
832684865Sobrien   set
832784865Sobrien   8) PSR.dfh is only read when these insns reference FR32-127.  PSR.dfl is
832884865Sobrien   only read when these insns reference FR2-31
832984865Sobrien   9) PSR.mfl is only written when these insns write FR2-31.  PSR.mfh is only
833084865Sobrien   written when these insns write FR32-127
833184865Sobrien   10) The PSR.bn bit is only accessed when one of GR16-31 is specified in the
833284865Sobrien   instruction
833384865Sobrien   11) The target predicates are written independently of PR[qp], but source
833484865Sobrien   registers are only read if PR[qp] is true.  Since the state of PR[qp]
833584865Sobrien   cannot statically be determined, all source registers are marked used.
833684865Sobrien   12) This insn only reads the specified predicate register when that
833784865Sobrien   register is the PR[qp].
833884865Sobrien   13) This reference to ld-c only applies to teh GR whose value is loaded
833984865Sobrien   with data returned from memory, not the post-incremented address register.
834084865Sobrien   14) The RSE resource includes the implementation-specific RSE internal
834184865Sobrien   state resources.  At least one (and possibly more) of these resources are
834284865Sobrien   read by each instruction listed in IC:rse-readers.  At least one (and
834384865Sobrien   possibly more) of these resources are written by each insn listed in
834484865Sobrien   IC:rse-writers.
834584865Sobrien   15+16) Represents reserved instructions, which the assembler does not
834684865Sobrien   generate.
8347218822Sdim   17) CR[TPR] has a RAW dependency only between mov-to-CR-TPR and
8348218822Sdim   mov-to-PSR-l or ssm instructions that set PSR.i, PSR.pp or PSR.up.
834984865Sobrien
835084865Sobrien   Memory resources (i.e. locations in memory) are *not* marked or tracked by
835184865Sobrien   this code; there are no dependency violations based on memory access.
835284865Sobrien*/
835384865Sobrien
835484865Sobrien#define MAX_SPECS 256
835584865Sobrien#define DV_CHK 1
835684865Sobrien#define DV_REG 0
835784865Sobrien
835884865Sobrienstatic int
835984865Sobrienspecify_resource (dep, idesc, type, specs, note, path)
836084865Sobrien     const struct ia64_dependency *dep;
836184865Sobrien     struct ia64_opcode *idesc;
836284865Sobrien     int type;                         /* is this a DV chk or a DV reg? */
836384865Sobrien     struct rsrc specs[MAX_SPECS];     /* returned specific resources */
836484865Sobrien     int note;                         /* resource note for this insn's usage */
836584865Sobrien     int path;                         /* which execution path to examine */
836684865Sobrien{
836784865Sobrien  int count = 0;
836884865Sobrien  int i;
836984865Sobrien  int rsrc_write = 0;
837084865Sobrien  struct rsrc tmpl;
837184865Sobrien
837284865Sobrien  if (dep->mode == IA64_DV_WAW
837384865Sobrien      || (dep->mode == IA64_DV_RAW && type == DV_REG)
837484865Sobrien      || (dep->mode == IA64_DV_WAR && type == DV_CHK))
837584865Sobrien    rsrc_write = 1;
837684865Sobrien
837784865Sobrien  /* template for any resources we identify */
837884865Sobrien  tmpl.dependency = dep;
837984865Sobrien  tmpl.note = note;
838084865Sobrien  tmpl.insn_srlz = tmpl.data_srlz = 0;
838184865Sobrien  tmpl.qp_regno = CURR_SLOT.qp_regno;
838284865Sobrien  tmpl.link_to_qp_branch = 1;
838384865Sobrien  tmpl.mem_offset.hint = 0;
8384218822Sdim  tmpl.mem_offset.offset = 0;
8385218822Sdim  tmpl.mem_offset.base = 0;
838684865Sobrien  tmpl.specific = 1;
8387218822Sdim  tmpl.index = -1;
838884865Sobrien  tmpl.cmp_type = CMP_NONE;
8389218822Sdim  tmpl.depind = 0;
8390218822Sdim  tmpl.file = NULL;
8391218822Sdim  tmpl.line = 0;
8392218822Sdim  tmpl.path = 0;
839384865Sobrien
839484865Sobrien#define UNHANDLED \
839584865Sobrienas_warn (_("Unhandled dependency %s for %s (%s), note %d"), \
839684865Sobriendep->name, idesc->name, (rsrc_write?"write":"read"), note)
839784865Sobrien#define KNOWN(REG) (gr_values[REG].known && gr_values[REG].path >= path)
839884865Sobrien
839984865Sobrien  /* we don't need to track these */
840084865Sobrien  if (dep->semantics == IA64_DVS_NONE)
840184865Sobrien    return 0;
840284865Sobrien
840384865Sobrien  switch (dep->specifier)
840484865Sobrien    {
840584865Sobrien    case IA64_RS_AR_K:
840684865Sobrien      if (note == 1)
840784865Sobrien	{
840884865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_AR3)
840984865Sobrien	    {
841084865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_AR;
841184865Sobrien	      if (regno >= 0 && regno <= 7)
841284865Sobrien		{
841384865Sobrien		  specs[count] = tmpl;
841484865Sobrien		  specs[count++].index = regno;
841584865Sobrien		}
841684865Sobrien	    }
841784865Sobrien	}
841884865Sobrien      else if (note == 0)
841984865Sobrien	{
842084865Sobrien	  for (i = 0; i < 8; i++)
842184865Sobrien	    {
842284865Sobrien	      specs[count] = tmpl;
842384865Sobrien	      specs[count++].index = i;
842484865Sobrien	    }
842584865Sobrien	}
842684865Sobrien      else
842784865Sobrien	{
842884865Sobrien	  UNHANDLED;
842984865Sobrien	}
843084865Sobrien      break;
843184865Sobrien
843284865Sobrien    case IA64_RS_AR_UNAT:
843384865Sobrien      /* This is a mov =AR or mov AR= instruction.  */
843484865Sobrien      if (idesc->operands[!rsrc_write] == IA64_OPND_AR3)
843584865Sobrien	{
843684865Sobrien	  int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_AR;
843784865Sobrien	  if (regno == AR_UNAT)
843884865Sobrien	    {
843984865Sobrien	      specs[count++] = tmpl;
844084865Sobrien	    }
844184865Sobrien	}
844284865Sobrien      else
844384865Sobrien	{
844484865Sobrien	  /* This is a spill/fill, or other instruction that modifies the
844584865Sobrien	     unat register.  */
844684865Sobrien
844784865Sobrien	  /* Unless we can determine the specific bits used, mark the whole
844884865Sobrien	     thing; bits 8:3 of the memory address indicate the bit used in
844984865Sobrien	     UNAT.  The .mem.offset hint may be used to eliminate a small
845084865Sobrien	     subset of conflicts.  */
845184865Sobrien	  specs[count] = tmpl;
845284865Sobrien	  if (md.mem_offset.hint)
845384865Sobrien	    {
845484865Sobrien	      if (md.debug_dv)
845584865Sobrien		fprintf (stderr, "  Using hint for spill/fill\n");
845684865Sobrien	      /* The index isn't actually used, just set it to something
845784865Sobrien		 approximating the bit index.  */
845884865Sobrien	      specs[count].index = (md.mem_offset.offset >> 3) & 0x3F;
845984865Sobrien	      specs[count].mem_offset.hint = 1;
846084865Sobrien	      specs[count].mem_offset.offset = md.mem_offset.offset;
846184865Sobrien	      specs[count++].mem_offset.base = md.mem_offset.base;
846284865Sobrien	    }
846384865Sobrien	  else
846484865Sobrien	    {
846584865Sobrien	      specs[count++].specific = 0;
846684865Sobrien	    }
846784865Sobrien	}
846884865Sobrien      break;
846984865Sobrien
847084865Sobrien    case IA64_RS_AR:
847184865Sobrien      if (note == 1)
847284865Sobrien	{
847384865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_AR3)
847484865Sobrien	    {
847584865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_AR;
847684865Sobrien	      if ((regno >= 8 && regno <= 15)
847784865Sobrien		  || (regno >= 20 && regno <= 23)
847884865Sobrien		  || (regno >= 31 && regno <= 39)
847984865Sobrien		  || (regno >= 41 && regno <= 47)
848084865Sobrien		  || (regno >= 67 && regno <= 111))
848184865Sobrien		{
848284865Sobrien		  specs[count] = tmpl;
848384865Sobrien		  specs[count++].index = regno;
848484865Sobrien		}
848584865Sobrien	    }
848684865Sobrien	}
848784865Sobrien      else
848884865Sobrien	{
848984865Sobrien	  UNHANDLED;
849084865Sobrien	}
849184865Sobrien      break;
849284865Sobrien
849384865Sobrien    case IA64_RS_ARb:
849484865Sobrien      if (note == 1)
849584865Sobrien	{
849684865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_AR3)
849784865Sobrien	    {
849884865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_AR;
849984865Sobrien	      if ((regno >= 48 && regno <= 63)
850084865Sobrien		  || (regno >= 112 && regno <= 127))
850184865Sobrien		{
850284865Sobrien		  specs[count] = tmpl;
850384865Sobrien		  specs[count++].index = regno;
850484865Sobrien		}
850584865Sobrien	    }
850684865Sobrien	}
850784865Sobrien      else if (note == 0)
850884865Sobrien	{
850984865Sobrien	  for (i = 48; i < 64; i++)
851084865Sobrien	    {
851184865Sobrien	      specs[count] = tmpl;
851284865Sobrien	      specs[count++].index = i;
851384865Sobrien	    }
851484865Sobrien	  for (i = 112; i < 128; i++)
851584865Sobrien	    {
851684865Sobrien	      specs[count] = tmpl;
851784865Sobrien	      specs[count++].index = i;
851884865Sobrien	    }
851984865Sobrien	}
852084865Sobrien      else
852184865Sobrien	{
852284865Sobrien	  UNHANDLED;
852384865Sobrien	}
852484865Sobrien      break;
852584865Sobrien
852684865Sobrien    case IA64_RS_BR:
852784865Sobrien      if (note != 1)
852884865Sobrien	{
852984865Sobrien	  UNHANDLED;
853084865Sobrien	}
853184865Sobrien      else
853284865Sobrien	{
853384865Sobrien	  if (rsrc_write)
853484865Sobrien	    {
853584865Sobrien	      for (i = 0; i < idesc->num_outputs; i++)
853684865Sobrien		if (idesc->operands[i] == IA64_OPND_B1
853784865Sobrien		    || idesc->operands[i] == IA64_OPND_B2)
853884865Sobrien		  {
853984865Sobrien		    specs[count] = tmpl;
854084865Sobrien		    specs[count++].index =
854184865Sobrien		      CURR_SLOT.opnd[i].X_add_number - REG_BR;
854284865Sobrien		  }
854384865Sobrien	    }
854484865Sobrien	  else
854584865Sobrien	    {
8546104834Sobrien	      for (i = idesc->num_outputs; i < NELEMS (idesc->operands); i++)
854784865Sobrien		if (idesc->operands[i] == IA64_OPND_B1
854884865Sobrien		    || idesc->operands[i] == IA64_OPND_B2)
854984865Sobrien		  {
855084865Sobrien		    specs[count] = tmpl;
855184865Sobrien		    specs[count++].index =
855284865Sobrien		      CURR_SLOT.opnd[i].X_add_number - REG_BR;
855384865Sobrien		  }
855484865Sobrien	    }
855584865Sobrien	}
855684865Sobrien      break;
855784865Sobrien
855884865Sobrien    case IA64_RS_CPUID: /* four or more registers */
855984865Sobrien      if (note == 3)
856084865Sobrien	{
856184865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_CPUID_R3)
856284865Sobrien	    {
856384865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_GR;
856484865Sobrien	      if (regno >= 0 && regno < NELEMS (gr_values)
856584865Sobrien		  && KNOWN (regno))
856684865Sobrien		{
856784865Sobrien		  specs[count] = tmpl;
856884865Sobrien		  specs[count++].index = gr_values[regno].value & 0xFF;
856984865Sobrien		}
857084865Sobrien	      else
857184865Sobrien		{
857284865Sobrien		  specs[count] = tmpl;
857384865Sobrien		  specs[count++].specific = 0;
857484865Sobrien		}
857584865Sobrien	    }
857684865Sobrien	}
857784865Sobrien      else
857884865Sobrien	{
857984865Sobrien	  UNHANDLED;
858084865Sobrien	}
858184865Sobrien      break;
858284865Sobrien
858384865Sobrien    case IA64_RS_DBR: /* four or more registers */
858484865Sobrien      if (note == 3)
858584865Sobrien	{
858684865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_DBR_R3)
858784865Sobrien	    {
858884865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_GR;
858984865Sobrien	      if (regno >= 0 && regno < NELEMS (gr_values)
859084865Sobrien		  && KNOWN (regno))
859184865Sobrien		{
859284865Sobrien		  specs[count] = tmpl;
859384865Sobrien		  specs[count++].index = gr_values[regno].value & 0xFF;
859484865Sobrien		}
859584865Sobrien	      else
859684865Sobrien		{
859784865Sobrien		  specs[count] = tmpl;
859884865Sobrien		  specs[count++].specific = 0;
859984865Sobrien		}
860084865Sobrien	    }
860184865Sobrien	}
860284865Sobrien      else if (note == 0 && !rsrc_write)
860384865Sobrien	{
860484865Sobrien	  specs[count] = tmpl;
860584865Sobrien	  specs[count++].specific = 0;
860684865Sobrien	}
860784865Sobrien      else
860884865Sobrien	{
860984865Sobrien	  UNHANDLED;
861084865Sobrien	}
861184865Sobrien      break;
861284865Sobrien
861384865Sobrien    case IA64_RS_IBR: /* four or more registers */
861484865Sobrien      if (note == 3)
861584865Sobrien	{
861684865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_IBR_R3)
861784865Sobrien	    {
861884865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_GR;
861984865Sobrien	      if (regno >= 0 && regno < NELEMS (gr_values)
862084865Sobrien		  && KNOWN (regno))
862184865Sobrien		{
862284865Sobrien		  specs[count] = tmpl;
862384865Sobrien		  specs[count++].index = gr_values[regno].value & 0xFF;
862484865Sobrien		}
862584865Sobrien	      else
862684865Sobrien		{
862784865Sobrien		  specs[count] = tmpl;
862884865Sobrien		  specs[count++].specific = 0;
862984865Sobrien		}
863084865Sobrien	    }
863184865Sobrien	}
863284865Sobrien      else
863384865Sobrien	{
863484865Sobrien	  UNHANDLED;
863584865Sobrien	}
863684865Sobrien      break;
863784865Sobrien
863884865Sobrien    case IA64_RS_MSR:
863984865Sobrien      if (note == 5)
864084865Sobrien	{
864184865Sobrien	  /* These are implementation specific.  Force all references to
864284865Sobrien	     conflict with all other references.  */
864384865Sobrien	  specs[count] = tmpl;
864484865Sobrien	  specs[count++].specific = 0;
864584865Sobrien	}
864684865Sobrien      else
864784865Sobrien	{
864884865Sobrien	  UNHANDLED;
864984865Sobrien	}
865084865Sobrien      break;
865184865Sobrien
865284865Sobrien    case IA64_RS_PKR: /* 16 or more registers */
865384865Sobrien      if (note == 3 || note == 4)
865484865Sobrien	{
865584865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_PKR_R3)
865684865Sobrien	    {
865784865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_GR;
865884865Sobrien	      if (regno >= 0 && regno < NELEMS (gr_values)
865984865Sobrien		  && KNOWN (regno))
866084865Sobrien		{
866184865Sobrien		  if (note == 3)
866284865Sobrien		    {
866384865Sobrien		      specs[count] = tmpl;
866484865Sobrien		      specs[count++].index = gr_values[regno].value & 0xFF;
866584865Sobrien		    }
866684865Sobrien		  else
866784865Sobrien		    for (i = 0; i < NELEMS (gr_values); i++)
866884865Sobrien		      {
866984865Sobrien			/* Uses all registers *except* the one in R3.  */
867084865Sobrien			if ((unsigned)i != (gr_values[regno].value & 0xFF))
867184865Sobrien			  {
867284865Sobrien			    specs[count] = tmpl;
867384865Sobrien			    specs[count++].index = i;
867484865Sobrien			  }
867584865Sobrien		      }
867684865Sobrien		}
867784865Sobrien	      else
867884865Sobrien		{
867984865Sobrien		  specs[count] = tmpl;
868084865Sobrien		  specs[count++].specific = 0;
868184865Sobrien		}
868284865Sobrien	    }
868384865Sobrien	}
868484865Sobrien      else if (note == 0)
868584865Sobrien	{
868684865Sobrien	  /* probe et al.  */
868784865Sobrien	  specs[count] = tmpl;
868884865Sobrien	  specs[count++].specific = 0;
868984865Sobrien	}
869084865Sobrien      break;
869184865Sobrien
869284865Sobrien    case IA64_RS_PMC: /* four or more registers */
869384865Sobrien      if (note == 3)
869484865Sobrien	{
869584865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_PMC_R3
869684865Sobrien	      || (!rsrc_write && idesc->operands[1] == IA64_OPND_PMD_R3))
869784865Sobrien
869884865Sobrien	    {
869984865Sobrien	      int index = ((idesc->operands[1] == IA64_OPND_R3 && !rsrc_write)
870084865Sobrien			   ? 1 : !rsrc_write);
870184865Sobrien	      int regno = CURR_SLOT.opnd[index].X_add_number - REG_GR;
870284865Sobrien	      if (regno >= 0 && regno < NELEMS (gr_values)
870384865Sobrien		  && KNOWN (regno))
870484865Sobrien		{
870584865Sobrien		  specs[count] = tmpl;
870684865Sobrien		  specs[count++].index = gr_values[regno].value & 0xFF;
870784865Sobrien		}
870884865Sobrien	      else
870984865Sobrien		{
871084865Sobrien		  specs[count] = tmpl;
871184865Sobrien		  specs[count++].specific = 0;
871284865Sobrien		}
871384865Sobrien	    }
871484865Sobrien	}
871584865Sobrien      else
871684865Sobrien	{
871784865Sobrien	  UNHANDLED;
871884865Sobrien	}
871984865Sobrien      break;
872084865Sobrien
872184865Sobrien    case IA64_RS_PMD: /* four or more registers */
872284865Sobrien      if (note == 3)
872384865Sobrien	{
872484865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_PMD_R3)
872584865Sobrien	    {
872684865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_GR;
872784865Sobrien	      if (regno >= 0 && regno < NELEMS (gr_values)
872884865Sobrien		  && KNOWN (regno))
872984865Sobrien		{
873084865Sobrien		  specs[count] = tmpl;
873184865Sobrien		  specs[count++].index = gr_values[regno].value & 0xFF;
873284865Sobrien		}
873384865Sobrien	      else
873484865Sobrien		{
873584865Sobrien		  specs[count] = tmpl;
873684865Sobrien		  specs[count++].specific = 0;
873784865Sobrien		}
873884865Sobrien	    }
873984865Sobrien	}
874084865Sobrien      else
874184865Sobrien	{
874284865Sobrien	  UNHANDLED;
874384865Sobrien	}
874484865Sobrien      break;
874584865Sobrien
874684865Sobrien    case IA64_RS_RR: /* eight registers */
874784865Sobrien      if (note == 6)
874884865Sobrien	{
874984865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_RR_R3)
875084865Sobrien	    {
875184865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_GR;
875284865Sobrien	      if (regno >= 0 && regno < NELEMS (gr_values)
875384865Sobrien		  && KNOWN (regno))
875484865Sobrien		{
875584865Sobrien		  specs[count] = tmpl;
875684865Sobrien		  specs[count++].index = (gr_values[regno].value >> 61) & 0x7;
875784865Sobrien		}
875884865Sobrien	      else
875984865Sobrien		{
876084865Sobrien		  specs[count] = tmpl;
876184865Sobrien		  specs[count++].specific = 0;
876284865Sobrien		}
876384865Sobrien	    }
876484865Sobrien	}
876584865Sobrien      else if (note == 0 && !rsrc_write)
876684865Sobrien	{
876784865Sobrien	  specs[count] = tmpl;
876884865Sobrien	  specs[count++].specific = 0;
876984865Sobrien	}
877084865Sobrien      else
877184865Sobrien	{
877284865Sobrien	  UNHANDLED;
877384865Sobrien	}
877484865Sobrien      break;
877584865Sobrien
877684865Sobrien    case IA64_RS_CR_IRR:
877784865Sobrien      if (note == 0)
877884865Sobrien	{
877984865Sobrien	  /* handle mov-from-CR-IVR; it's a read that writes CR[IRR] */
878084865Sobrien	  int regno = CURR_SLOT.opnd[1].X_add_number - REG_CR;
878184865Sobrien	  if (rsrc_write
878284865Sobrien	      && idesc->operands[1] == IA64_OPND_CR3
878384865Sobrien	      && regno == CR_IVR)
878484865Sobrien	    {
878584865Sobrien	      for (i = 0; i < 4; i++)
878684865Sobrien		{
878784865Sobrien		  specs[count] = tmpl;
878884865Sobrien		  specs[count++].index = CR_IRR0 + i;
878984865Sobrien		}
879084865Sobrien	    }
879184865Sobrien	}
879284865Sobrien      else if (note == 1)
879384865Sobrien	{
879484865Sobrien	  int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_CR;
879584865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_CR3
879684865Sobrien	      && regno >= CR_IRR0
879784865Sobrien	      && regno <= CR_IRR3)
879884865Sobrien	    {
879984865Sobrien	      specs[count] = tmpl;
880084865Sobrien	      specs[count++].index = regno;
880184865Sobrien	    }
880284865Sobrien	}
880384865Sobrien      else
880484865Sobrien	{
880584865Sobrien	  UNHANDLED;
880684865Sobrien	}
880784865Sobrien      break;
880884865Sobrien
880984865Sobrien    case IA64_RS_CR_LRR:
881084865Sobrien      if (note != 1)
881184865Sobrien	{
881284865Sobrien	  UNHANDLED;
881384865Sobrien	}
881484865Sobrien      else
881584865Sobrien	{
881684865Sobrien	  int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_CR;
881784865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_CR3
881884865Sobrien	      && (regno == CR_LRR0 || regno == CR_LRR1))
881984865Sobrien	    {
882084865Sobrien	      specs[count] = tmpl;
882184865Sobrien	      specs[count++].index = regno;
882284865Sobrien	    }
882384865Sobrien	}
882484865Sobrien      break;
882584865Sobrien
882684865Sobrien    case IA64_RS_CR:
882784865Sobrien      if (note == 1)
882884865Sobrien	{
882984865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_CR3)
883084865Sobrien	    {
883184865Sobrien	      specs[count] = tmpl;
883284865Sobrien	      specs[count++].index =
883384865Sobrien		CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_CR;
883484865Sobrien	    }
883584865Sobrien	}
883684865Sobrien      else
883784865Sobrien	{
883884865Sobrien	  UNHANDLED;
883984865Sobrien	}
884084865Sobrien      break;
884184865Sobrien
884284865Sobrien    case IA64_RS_FR:
884384865Sobrien    case IA64_RS_FRb:
884484865Sobrien      if (note != 1)
884584865Sobrien	{
884684865Sobrien	  UNHANDLED;
884784865Sobrien	}
884884865Sobrien      else if (rsrc_write)
884984865Sobrien	{
885084865Sobrien	  if (dep->specifier == IA64_RS_FRb
885184865Sobrien	      && idesc->operands[0] == IA64_OPND_F1)
885284865Sobrien	    {
885384865Sobrien	      specs[count] = tmpl;
885484865Sobrien	      specs[count++].index = CURR_SLOT.opnd[0].X_add_number - REG_FR;
885584865Sobrien	    }
885684865Sobrien	}
885784865Sobrien      else
885884865Sobrien	{
885984865Sobrien	  for (i = idesc->num_outputs; i < NELEMS (idesc->operands); i++)
886084865Sobrien	    {
886184865Sobrien	      if (idesc->operands[i] == IA64_OPND_F2
886284865Sobrien		  || idesc->operands[i] == IA64_OPND_F3
886384865Sobrien		  || idesc->operands[i] == IA64_OPND_F4)
886484865Sobrien		{
886584865Sobrien		  specs[count] = tmpl;
886684865Sobrien		  specs[count++].index =
886784865Sobrien		    CURR_SLOT.opnd[i].X_add_number - REG_FR;
886884865Sobrien		}
886984865Sobrien	    }
887084865Sobrien	}
887184865Sobrien      break;
887284865Sobrien
887384865Sobrien    case IA64_RS_GR:
887484865Sobrien      if (note == 13)
887584865Sobrien	{
887684865Sobrien	  /* This reference applies only to the GR whose value is loaded with
887784865Sobrien	     data returned from memory.  */
887884865Sobrien	  specs[count] = tmpl;
887984865Sobrien	  specs[count++].index = CURR_SLOT.opnd[0].X_add_number - REG_GR;
888084865Sobrien	}
888184865Sobrien      else if (note == 1)
888284865Sobrien	{
888384865Sobrien	  if (rsrc_write)
888484865Sobrien	    {
888584865Sobrien	      for (i = 0; i < idesc->num_outputs; i++)
888684865Sobrien		if (idesc->operands[i] == IA64_OPND_R1
888784865Sobrien		    || idesc->operands[i] == IA64_OPND_R2
888884865Sobrien		    || idesc->operands[i] == IA64_OPND_R3)
888984865Sobrien		  {
889084865Sobrien		    specs[count] = tmpl;
889184865Sobrien		    specs[count++].index =
889284865Sobrien		      CURR_SLOT.opnd[i].X_add_number - REG_GR;
889384865Sobrien		  }
889484865Sobrien	      if (idesc->flags & IA64_OPCODE_POSTINC)
889584865Sobrien		for (i = 0; i < NELEMS (idesc->operands); i++)
889684865Sobrien		  if (idesc->operands[i] == IA64_OPND_MR3)
889784865Sobrien		    {
889884865Sobrien		      specs[count] = tmpl;
889984865Sobrien		      specs[count++].index =
890084865Sobrien			CURR_SLOT.opnd[i].X_add_number - REG_GR;
890184865Sobrien		    }
890284865Sobrien	    }
890384865Sobrien	  else
890484865Sobrien	    {
890584865Sobrien	      /* Look for anything that reads a GR.  */
890684865Sobrien	      for (i = 0; i < NELEMS (idesc->operands); i++)
890784865Sobrien		{
890884865Sobrien		  if (idesc->operands[i] == IA64_OPND_MR3
890984865Sobrien		      || idesc->operands[i] == IA64_OPND_CPUID_R3
891084865Sobrien		      || idesc->operands[i] == IA64_OPND_DBR_R3
891184865Sobrien		      || idesc->operands[i] == IA64_OPND_IBR_R3
891284865Sobrien		      || idesc->operands[i] == IA64_OPND_MSR_R3
891384865Sobrien		      || idesc->operands[i] == IA64_OPND_PKR_R3
891484865Sobrien		      || idesc->operands[i] == IA64_OPND_PMC_R3
891584865Sobrien		      || idesc->operands[i] == IA64_OPND_PMD_R3
891684865Sobrien		      || idesc->operands[i] == IA64_OPND_RR_R3
891784865Sobrien		      || ((i >= idesc->num_outputs)
891884865Sobrien			  && (idesc->operands[i] == IA64_OPND_R1
891984865Sobrien			      || idesc->operands[i] == IA64_OPND_R2
892084865Sobrien			      || idesc->operands[i] == IA64_OPND_R3
892184865Sobrien			      /* addl source register.  */
892284865Sobrien			      || idesc->operands[i] == IA64_OPND_R3_2)))
892384865Sobrien		    {
892484865Sobrien		      specs[count] = tmpl;
892584865Sobrien		      specs[count++].index =
892684865Sobrien			CURR_SLOT.opnd[i].X_add_number - REG_GR;
892784865Sobrien		    }
892884865Sobrien		}
892984865Sobrien	    }
893084865Sobrien	}
893184865Sobrien      else
893284865Sobrien	{
893384865Sobrien	  UNHANDLED;
893484865Sobrien	}
893584865Sobrien      break;
893684865Sobrien
893784865Sobrien      /* This is the same as IA64_RS_PRr, except that the register range is
893884865Sobrien	 from 1 - 15, and there are no rotating register reads/writes here.  */
893984865Sobrien    case IA64_RS_PR:
894084865Sobrien      if (note == 0)
894184865Sobrien	{
894284865Sobrien	  for (i = 1; i < 16; i++)
894384865Sobrien	    {
894484865Sobrien	      specs[count] = tmpl;
894584865Sobrien	      specs[count++].index = i;
894684865Sobrien	    }
894784865Sobrien	}
894884865Sobrien      else if (note == 7)
894984865Sobrien	{
895084865Sobrien	  valueT mask = 0;
895184865Sobrien	  /* Mark only those registers indicated by the mask.  */
895284865Sobrien	  if (rsrc_write)
895384865Sobrien	    {
895484865Sobrien	      mask = CURR_SLOT.opnd[2].X_add_number;
895584865Sobrien	      for (i = 1; i < 16; i++)
895684865Sobrien		if (mask & ((valueT) 1 << i))
895784865Sobrien		  {
895884865Sobrien		    specs[count] = tmpl;
895984865Sobrien		    specs[count++].index = i;
896084865Sobrien		  }
896184865Sobrien	    }
896284865Sobrien	  else
896384865Sobrien	    {
896484865Sobrien	      UNHANDLED;
896584865Sobrien	    }
896684865Sobrien	}
896784865Sobrien      else if (note == 11) /* note 11 implies note 1 as well */
896884865Sobrien	{
896984865Sobrien	  if (rsrc_write)
897084865Sobrien	    {
897184865Sobrien	      for (i = 0; i < idesc->num_outputs; i++)
897284865Sobrien		{
897384865Sobrien		  if (idesc->operands[i] == IA64_OPND_P1
897484865Sobrien		      || idesc->operands[i] == IA64_OPND_P2)
897584865Sobrien		    {
897684865Sobrien		      int regno = CURR_SLOT.opnd[i].X_add_number - REG_P;
897784865Sobrien		      if (regno >= 1 && regno < 16)
897884865Sobrien			{
897984865Sobrien			  specs[count] = tmpl;
898084865Sobrien			  specs[count++].index = regno;
898184865Sobrien			}
898284865Sobrien		    }
898384865Sobrien		}
898484865Sobrien	    }
898584865Sobrien	  else
898684865Sobrien	    {
898784865Sobrien	      UNHANDLED;
898884865Sobrien	    }
898984865Sobrien	}
899084865Sobrien      else if (note == 12)
899184865Sobrien	{
899284865Sobrien	  if (CURR_SLOT.qp_regno >= 1 && CURR_SLOT.qp_regno < 16)
899384865Sobrien	    {
899484865Sobrien	      specs[count] = tmpl;
899584865Sobrien	      specs[count++].index = CURR_SLOT.qp_regno;
899684865Sobrien	    }
899784865Sobrien	}
899884865Sobrien      else if (note == 1)
899984865Sobrien	{
900084865Sobrien	  if (rsrc_write)
900184865Sobrien	    {
900284865Sobrien	      int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
900384865Sobrien	      int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
900489857Sobrien	      int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
900589857Sobrien	      int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
900684865Sobrien
900784865Sobrien	      if ((idesc->operands[0] == IA64_OPND_P1
900884865Sobrien		   || idesc->operands[0] == IA64_OPND_P2)
900984865Sobrien		  && p1 >= 1 && p1 < 16)
901084865Sobrien		{
901184865Sobrien		  specs[count] = tmpl;
901284865Sobrien		  specs[count].cmp_type =
901384865Sobrien		    (or_andcm ? CMP_OR : (and_orcm ? CMP_AND : CMP_NONE));
901484865Sobrien		  specs[count++].index = p1;
901584865Sobrien		}
901684865Sobrien	      if ((idesc->operands[1] == IA64_OPND_P1
901784865Sobrien		   || idesc->operands[1] == IA64_OPND_P2)
901884865Sobrien		  && p2 >= 1 && p2 < 16)
901984865Sobrien		{
902084865Sobrien		  specs[count] = tmpl;
902184865Sobrien		  specs[count].cmp_type =
902284865Sobrien		    (or_andcm ? CMP_AND : (and_orcm ? CMP_OR : CMP_NONE));
902384865Sobrien		  specs[count++].index = p2;
902484865Sobrien		}
902584865Sobrien	    }
902684865Sobrien	  else
902784865Sobrien	    {
902884865Sobrien	      if (CURR_SLOT.qp_regno >= 1 && CURR_SLOT.qp_regno < 16)
902984865Sobrien		{
903084865Sobrien		  specs[count] = tmpl;
903184865Sobrien		  specs[count++].index = CURR_SLOT.qp_regno;
903284865Sobrien		}
903384865Sobrien	      if (idesc->operands[1] == IA64_OPND_PR)
903484865Sobrien		{
903584865Sobrien		  for (i = 1; i < 16; i++)
903684865Sobrien		    {
903784865Sobrien		      specs[count] = tmpl;
903884865Sobrien		      specs[count++].index = i;
903984865Sobrien		    }
904084865Sobrien		}
904184865Sobrien	    }
904284865Sobrien	}
904384865Sobrien      else
904484865Sobrien	{
904584865Sobrien	  UNHANDLED;
904684865Sobrien	}
904784865Sobrien      break;
904884865Sobrien
904984865Sobrien      /* This is the general case for PRs.  IA64_RS_PR and IA64_RS_PR63 are
905084865Sobrien	 simplified cases of this.  */
905184865Sobrien    case IA64_RS_PRr:
905284865Sobrien      if (note == 0)
905384865Sobrien	{
905484865Sobrien	  for (i = 16; i < 63; i++)
905584865Sobrien	    {
905684865Sobrien	      specs[count] = tmpl;
905784865Sobrien	      specs[count++].index = i;
905884865Sobrien	    }
905984865Sobrien	}
906084865Sobrien      else if (note == 7)
906184865Sobrien	{
906284865Sobrien	  valueT mask = 0;
906384865Sobrien	  /* Mark only those registers indicated by the mask.  */
906484865Sobrien	  if (rsrc_write
906584865Sobrien	      && idesc->operands[0] == IA64_OPND_PR)
906684865Sobrien	    {
906784865Sobrien	      mask = CURR_SLOT.opnd[2].X_add_number;
9068104834Sobrien	      if (mask & ((valueT) 1 << 16))
906984865Sobrien		for (i = 16; i < 63; i++)
907084865Sobrien		  {
907184865Sobrien		    specs[count] = tmpl;
907284865Sobrien		    specs[count++].index = i;
907384865Sobrien		  }
907484865Sobrien	    }
907584865Sobrien	  else if (rsrc_write
907684865Sobrien		   && idesc->operands[0] == IA64_OPND_PR_ROT)
907784865Sobrien	    {
907884865Sobrien	      for (i = 16; i < 63; i++)
907984865Sobrien		{
908084865Sobrien		  specs[count] = tmpl;
908184865Sobrien		  specs[count++].index = i;
908284865Sobrien		}
908384865Sobrien	    }
908484865Sobrien	  else
908584865Sobrien	    {
908684865Sobrien	      UNHANDLED;
908784865Sobrien	    }
908884865Sobrien	}
908984865Sobrien      else if (note == 11) /* note 11 implies note 1 as well */
909084865Sobrien	{
909184865Sobrien	  if (rsrc_write)
909284865Sobrien	    {
909384865Sobrien	      for (i = 0; i < idesc->num_outputs; i++)
909484865Sobrien		{
909584865Sobrien		  if (idesc->operands[i] == IA64_OPND_P1
909684865Sobrien		      || idesc->operands[i] == IA64_OPND_P2)
909784865Sobrien		    {
909884865Sobrien		      int regno = CURR_SLOT.opnd[i].X_add_number - REG_P;
909984865Sobrien		      if (regno >= 16 && regno < 63)
910084865Sobrien			{
910184865Sobrien			  specs[count] = tmpl;
910284865Sobrien			  specs[count++].index = regno;
910384865Sobrien			}
910484865Sobrien		    }
910584865Sobrien		}
910684865Sobrien	    }
910784865Sobrien	  else
910884865Sobrien	    {
910984865Sobrien	      UNHANDLED;
911084865Sobrien	    }
911184865Sobrien	}
911284865Sobrien      else if (note == 12)
911384865Sobrien	{
911484865Sobrien	  if (CURR_SLOT.qp_regno >= 16 && CURR_SLOT.qp_regno < 63)
911584865Sobrien	    {
911684865Sobrien	      specs[count] = tmpl;
911784865Sobrien	      specs[count++].index = CURR_SLOT.qp_regno;
911884865Sobrien	    }
911984865Sobrien	}
912084865Sobrien      else if (note == 1)
912184865Sobrien	{
912284865Sobrien	  if (rsrc_write)
912384865Sobrien	    {
912484865Sobrien	      int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
912584865Sobrien	      int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
912689857Sobrien	      int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
912789857Sobrien	      int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
912884865Sobrien
912984865Sobrien	      if ((idesc->operands[0] == IA64_OPND_P1
913084865Sobrien		   || idesc->operands[0] == IA64_OPND_P2)
913184865Sobrien		  && p1 >= 16 && p1 < 63)
913284865Sobrien		{
913384865Sobrien		  specs[count] = tmpl;
913484865Sobrien		  specs[count].cmp_type =
913584865Sobrien		    (or_andcm ? CMP_OR : (and_orcm ? CMP_AND : CMP_NONE));
913684865Sobrien		  specs[count++].index = p1;
913784865Sobrien		}
913884865Sobrien	      if ((idesc->operands[1] == IA64_OPND_P1
913984865Sobrien		   || idesc->operands[1] == IA64_OPND_P2)
914084865Sobrien		  && p2 >= 16 && p2 < 63)
914184865Sobrien		{
914284865Sobrien		  specs[count] = tmpl;
914384865Sobrien		  specs[count].cmp_type =
914484865Sobrien		    (or_andcm ? CMP_AND : (and_orcm ? CMP_OR : CMP_NONE));
914584865Sobrien		  specs[count++].index = p2;
914684865Sobrien		}
914784865Sobrien	    }
914884865Sobrien	  else
914984865Sobrien	    {
915084865Sobrien	      if (CURR_SLOT.qp_regno >= 16 && CURR_SLOT.qp_regno < 63)
915184865Sobrien		{
915284865Sobrien		  specs[count] = tmpl;
915384865Sobrien		  specs[count++].index = CURR_SLOT.qp_regno;
915484865Sobrien		}
915584865Sobrien	      if (idesc->operands[1] == IA64_OPND_PR)
915684865Sobrien		{
915784865Sobrien		  for (i = 16; i < 63; i++)
915884865Sobrien		    {
915984865Sobrien		      specs[count] = tmpl;
916084865Sobrien		      specs[count++].index = i;
916184865Sobrien		    }
916284865Sobrien		}
916384865Sobrien	    }
916484865Sobrien	}
916584865Sobrien      else
916684865Sobrien	{
916784865Sobrien	  UNHANDLED;
916884865Sobrien	}
916984865Sobrien      break;
917084865Sobrien
917184865Sobrien    case IA64_RS_PSR:
917284865Sobrien      /* Verify that the instruction is using the PSR bit indicated in
917384865Sobrien	 dep->regindex.  */
917484865Sobrien      if (note == 0)
917584865Sobrien	{
917684865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_PSR_UM)
917784865Sobrien	    {
917884865Sobrien	      if (dep->regindex < 6)
917984865Sobrien		{
918084865Sobrien		  specs[count++] = tmpl;
918184865Sobrien		}
918284865Sobrien	    }
918384865Sobrien	  else if (idesc->operands[!rsrc_write] == IA64_OPND_PSR)
918484865Sobrien	    {
918584865Sobrien	      if (dep->regindex < 32
918684865Sobrien		  || dep->regindex == 35
918784865Sobrien		  || dep->regindex == 36
918884865Sobrien		  || (!rsrc_write && dep->regindex == PSR_CPL))
918984865Sobrien		{
919084865Sobrien		  specs[count++] = tmpl;
919184865Sobrien		}
919284865Sobrien	    }
919384865Sobrien	  else if (idesc->operands[!rsrc_write] == IA64_OPND_PSR_L)
919484865Sobrien	    {
919584865Sobrien	      if (dep->regindex < 32
919684865Sobrien		  || dep->regindex == 35
919784865Sobrien		  || dep->regindex == 36
919884865Sobrien		  || (rsrc_write && dep->regindex == PSR_CPL))
919984865Sobrien		{
920084865Sobrien		  specs[count++] = tmpl;
920184865Sobrien		}
920284865Sobrien	    }
920384865Sobrien	  else
920484865Sobrien	    {
920584865Sobrien	      /* Several PSR bits have very specific dependencies.  */
920684865Sobrien	      switch (dep->regindex)
920784865Sobrien		{
920884865Sobrien		default:
920984865Sobrien		  specs[count++] = tmpl;
921084865Sobrien		  break;
921184865Sobrien		case PSR_IC:
921284865Sobrien		  if (rsrc_write)
921384865Sobrien		    {
921484865Sobrien		      specs[count++] = tmpl;
921584865Sobrien		    }
921684865Sobrien		  else
921784865Sobrien		    {
921884865Sobrien		      /* Only certain CR accesses use PSR.ic */
921984865Sobrien		      if (idesc->operands[0] == IA64_OPND_CR3
922084865Sobrien			  || idesc->operands[1] == IA64_OPND_CR3)
922184865Sobrien			{
922284865Sobrien			  int index =
922384865Sobrien			    ((idesc->operands[0] == IA64_OPND_CR3)
922484865Sobrien			     ? 0 : 1);
922584865Sobrien			  int regno =
922684865Sobrien			    CURR_SLOT.opnd[index].X_add_number - REG_CR;
922784865Sobrien
922884865Sobrien			  switch (regno)
922984865Sobrien			    {
923084865Sobrien			    default:
923184865Sobrien			      break;
923284865Sobrien			    case CR_ITIR:
923384865Sobrien			    case CR_IFS:
923484865Sobrien			    case CR_IIM:
923584865Sobrien			    case CR_IIP:
923684865Sobrien			    case CR_IPSR:
923784865Sobrien			    case CR_ISR:
923884865Sobrien			    case CR_IFA:
923984865Sobrien			    case CR_IHA:
924084865Sobrien			    case CR_IIPA:
924184865Sobrien			      specs[count++] = tmpl;
924284865Sobrien			      break;
924384865Sobrien			    }
924484865Sobrien			}
924584865Sobrien		    }
924684865Sobrien		  break;
924784865Sobrien		case PSR_CPL:
924884865Sobrien		  if (rsrc_write)
924984865Sobrien		    {
925084865Sobrien		      specs[count++] = tmpl;
925184865Sobrien		    }
925284865Sobrien		  else
925384865Sobrien		    {
925484865Sobrien		      /* Only some AR accesses use cpl */
925584865Sobrien		      if (idesc->operands[0] == IA64_OPND_AR3
925684865Sobrien			  || idesc->operands[1] == IA64_OPND_AR3)
925784865Sobrien			{
925884865Sobrien			  int index =
925984865Sobrien			    ((idesc->operands[0] == IA64_OPND_AR3)
926084865Sobrien			     ? 0 : 1);
926184865Sobrien			  int regno =
926284865Sobrien			    CURR_SLOT.opnd[index].X_add_number - REG_AR;
926384865Sobrien
926484865Sobrien			  if (regno == AR_ITC
926584865Sobrien			      || (index == 0
926684865Sobrien				  && (regno == AR_ITC
926784865Sobrien				      || regno == AR_RSC
926884865Sobrien				      || (regno >= AR_K0
926984865Sobrien					  && regno <= AR_K7))))
927084865Sobrien			    {
927184865Sobrien			      specs[count++] = tmpl;
927284865Sobrien			    }
927384865Sobrien			}
927484865Sobrien		      else
927584865Sobrien			{
927684865Sobrien			  specs[count++] = tmpl;
927784865Sobrien			}
927884865Sobrien		      break;
927984865Sobrien		    }
928084865Sobrien		}
928184865Sobrien	    }
928284865Sobrien	}
928384865Sobrien      else if (note == 7)
928484865Sobrien	{
928584865Sobrien	  valueT mask = 0;
928684865Sobrien	  if (idesc->operands[0] == IA64_OPND_IMMU24)
928784865Sobrien	    {
928884865Sobrien	      mask = CURR_SLOT.opnd[0].X_add_number;
928984865Sobrien	    }
929084865Sobrien	  else
929184865Sobrien	    {
929284865Sobrien	      UNHANDLED;
929384865Sobrien	    }
929484865Sobrien	  if (mask & ((valueT) 1 << dep->regindex))
929584865Sobrien	    {
929684865Sobrien	      specs[count++] = tmpl;
929784865Sobrien	    }
929884865Sobrien	}
929984865Sobrien      else if (note == 8)
930084865Sobrien	{
930184865Sobrien	  int min = dep->regindex == PSR_DFL ? 2 : 32;
930284865Sobrien	  int max = dep->regindex == PSR_DFL ? 31 : 127;
930384865Sobrien	  /* dfh is read on FR32-127; dfl is read on FR2-31 */
930484865Sobrien	  for (i = 0; i < NELEMS (idesc->operands); i++)
930584865Sobrien	    {
930684865Sobrien	      if (idesc->operands[i] == IA64_OPND_F1
930784865Sobrien		  || idesc->operands[i] == IA64_OPND_F2
930884865Sobrien		  || idesc->operands[i] == IA64_OPND_F3
930984865Sobrien		  || idesc->operands[i] == IA64_OPND_F4)
931084865Sobrien		{
931184865Sobrien		  int reg = CURR_SLOT.opnd[i].X_add_number - REG_FR;
931284865Sobrien		  if (reg >= min && reg <= max)
931384865Sobrien		    {
931484865Sobrien		      specs[count++] = tmpl;
931584865Sobrien		    }
931684865Sobrien		}
931784865Sobrien	    }
931884865Sobrien	}
931984865Sobrien      else if (note == 9)
932084865Sobrien	{
932184865Sobrien	  int min = dep->regindex == PSR_MFL ? 2 : 32;
932284865Sobrien	  int max = dep->regindex == PSR_MFL ? 31 : 127;
932384865Sobrien	  /* mfh is read on writes to FR32-127; mfl is read on writes to
932484865Sobrien	     FR2-31 */
932584865Sobrien	  for (i = 0; i < idesc->num_outputs; i++)
932684865Sobrien	    {
932784865Sobrien	      if (idesc->operands[i] == IA64_OPND_F1)
932884865Sobrien		{
932984865Sobrien		  int reg = CURR_SLOT.opnd[i].X_add_number - REG_FR;
933084865Sobrien		  if (reg >= min && reg <= max)
933184865Sobrien		    {
933284865Sobrien		      specs[count++] = tmpl;
933384865Sobrien		    }
933484865Sobrien		}
933584865Sobrien	    }
933684865Sobrien	}
933784865Sobrien      else if (note == 10)
933884865Sobrien	{
933984865Sobrien	  for (i = 0; i < NELEMS (idesc->operands); i++)
934084865Sobrien	    {
934184865Sobrien	      if (idesc->operands[i] == IA64_OPND_R1
934284865Sobrien		  || idesc->operands[i] == IA64_OPND_R2
934384865Sobrien		  || idesc->operands[i] == IA64_OPND_R3)
934484865Sobrien		{
934584865Sobrien		  int regno = CURR_SLOT.opnd[i].X_add_number - REG_GR;
934684865Sobrien		  if (regno >= 16 && regno <= 31)
934784865Sobrien		    {
934884865Sobrien		      specs[count++] = tmpl;
934984865Sobrien		    }
935084865Sobrien		}
935184865Sobrien	    }
935284865Sobrien	}
935384865Sobrien      else
935484865Sobrien	{
935584865Sobrien	  UNHANDLED;
935684865Sobrien	}
935784865Sobrien      break;
935884865Sobrien
935984865Sobrien    case IA64_RS_AR_FPSR:
936084865Sobrien      if (idesc->operands[!rsrc_write] == IA64_OPND_AR3)
936184865Sobrien	{
936284865Sobrien	  int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_AR;
936384865Sobrien	  if (regno == AR_FPSR)
936484865Sobrien	    {
936584865Sobrien	      specs[count++] = tmpl;
936684865Sobrien	    }
936784865Sobrien	}
936884865Sobrien      else
936984865Sobrien	{
937084865Sobrien	  specs[count++] = tmpl;
937184865Sobrien	}
937284865Sobrien      break;
937384865Sobrien
937484865Sobrien    case IA64_RS_ARX:
937584865Sobrien      /* Handle all AR[REG] resources */
937684865Sobrien      if (note == 0 || note == 1)
937784865Sobrien	{
937884865Sobrien	  int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_AR;
937984865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_AR3
938084865Sobrien	      && regno == dep->regindex)
938184865Sobrien	    {
938284865Sobrien	      specs[count++] = tmpl;
938384865Sobrien	    }
938484865Sobrien	  /* other AR[REG] resources may be affected by AR accesses */
938584865Sobrien	  else if (idesc->operands[0] == IA64_OPND_AR3)
938684865Sobrien	    {
938784865Sobrien	      /* AR[] writes */
938884865Sobrien	      regno = CURR_SLOT.opnd[0].X_add_number - REG_AR;
938984865Sobrien	      switch (dep->regindex)
939084865Sobrien		{
939184865Sobrien		default:
939284865Sobrien		  break;
939384865Sobrien		case AR_BSP:
939484865Sobrien		case AR_RNAT:
939584865Sobrien		  if (regno == AR_BSPSTORE)
939684865Sobrien		    {
939784865Sobrien		      specs[count++] = tmpl;
939884865Sobrien		    }
939984865Sobrien		case AR_RSC:
940084865Sobrien		  if (!rsrc_write &&
940184865Sobrien		      (regno == AR_BSPSTORE
940284865Sobrien		       || regno == AR_RNAT))
940384865Sobrien		    {
940484865Sobrien		      specs[count++] = tmpl;
940584865Sobrien		    }
940684865Sobrien		  break;
940784865Sobrien		}
940884865Sobrien	    }
940984865Sobrien	  else if (idesc->operands[1] == IA64_OPND_AR3)
941084865Sobrien	    {
941184865Sobrien	      /* AR[] reads */
941284865Sobrien	      regno = CURR_SLOT.opnd[1].X_add_number - REG_AR;
941384865Sobrien	      switch (dep->regindex)
941484865Sobrien		{
941584865Sobrien		default:
941684865Sobrien		  break;
941784865Sobrien		case AR_RSC:
941884865Sobrien		  if (regno == AR_BSPSTORE || regno == AR_RNAT)
941984865Sobrien		    {
942084865Sobrien		      specs[count++] = tmpl;
942184865Sobrien		    }
942284865Sobrien		  break;
942384865Sobrien		}
942484865Sobrien	    }
942584865Sobrien	  else
942684865Sobrien	    {
942784865Sobrien	      specs[count++] = tmpl;
942884865Sobrien	    }
942984865Sobrien	}
943084865Sobrien      else
943184865Sobrien	{
943284865Sobrien	  UNHANDLED;
943384865Sobrien	}
943484865Sobrien      break;
943584865Sobrien
943684865Sobrien    case IA64_RS_CRX:
9437218822Sdim      /* Handle all CR[REG] resources.
9438218822Sdim	 ??? FIXME: The rule 17 isn't really handled correctly.   */
9439218822Sdim      if (note == 0 || note == 1 || note == 17)
944084865Sobrien	{
944184865Sobrien	  if (idesc->operands[!rsrc_write] == IA64_OPND_CR3)
944284865Sobrien	    {
944384865Sobrien	      int regno = CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_CR;
944484865Sobrien	      if (regno == dep->regindex)
944584865Sobrien		{
944684865Sobrien		  specs[count++] = tmpl;
944784865Sobrien		}
944884865Sobrien	      else if (!rsrc_write)
944984865Sobrien		{
945084865Sobrien		  /* Reads from CR[IVR] affect other resources.  */
945184865Sobrien		  if (regno == CR_IVR)
945284865Sobrien		    {
945384865Sobrien		      if ((dep->regindex >= CR_IRR0
945484865Sobrien			   && dep->regindex <= CR_IRR3)
945584865Sobrien			  || dep->regindex == CR_TPR)
945684865Sobrien			{
945784865Sobrien			  specs[count++] = tmpl;
945884865Sobrien			}
945984865Sobrien		    }
946084865Sobrien		}
946184865Sobrien	    }
946284865Sobrien	  else
946384865Sobrien	    {
946484865Sobrien	      specs[count++] = tmpl;
946584865Sobrien	    }
946684865Sobrien	}
946784865Sobrien      else
946884865Sobrien	{
946984865Sobrien	  UNHANDLED;
947084865Sobrien	}
947184865Sobrien      break;
947284865Sobrien
947384865Sobrien    case IA64_RS_INSERVICE:
947484865Sobrien      /* look for write of EOI (67) or read of IVR (65) */
947584865Sobrien      if ((idesc->operands[0] == IA64_OPND_CR3
947684865Sobrien	   && CURR_SLOT.opnd[0].X_add_number - REG_CR == CR_EOI)
947784865Sobrien	  || (idesc->operands[1] == IA64_OPND_CR3
947884865Sobrien	      && CURR_SLOT.opnd[1].X_add_number - REG_CR == CR_IVR))
947984865Sobrien	{
948084865Sobrien	  specs[count++] = tmpl;
948184865Sobrien	}
948284865Sobrien      break;
948384865Sobrien
948484865Sobrien    case IA64_RS_GR0:
948584865Sobrien      if (note == 1)
948684865Sobrien	{
948784865Sobrien	  specs[count++] = tmpl;
948884865Sobrien	}
948984865Sobrien      else
949084865Sobrien	{
949184865Sobrien	  UNHANDLED;
949284865Sobrien	}
949384865Sobrien      break;
949484865Sobrien
949584865Sobrien    case IA64_RS_CFM:
949684865Sobrien      if (note != 2)
949784865Sobrien	{
949884865Sobrien	  specs[count++] = tmpl;
949984865Sobrien	}
950084865Sobrien      else
950184865Sobrien	{
950284865Sobrien	  /* Check if any of the registers accessed are in the rotating region.
950384865Sobrien	     mov to/from pr accesses CFM only when qp_regno is in the rotating
950484865Sobrien	     region */
950584865Sobrien	  for (i = 0; i < NELEMS (idesc->operands); i++)
950684865Sobrien	    {
950784865Sobrien	      if (idesc->operands[i] == IA64_OPND_R1
950884865Sobrien		  || idesc->operands[i] == IA64_OPND_R2
950984865Sobrien		  || idesc->operands[i] == IA64_OPND_R3)
951084865Sobrien		{
951184865Sobrien		  int num = CURR_SLOT.opnd[i].X_add_number - REG_GR;
951284865Sobrien		  /* Assumes that md.rot.num_regs is always valid */
951384865Sobrien		  if (md.rot.num_regs > 0
951484865Sobrien		      && num > 31
951584865Sobrien		      && num < 31 + md.rot.num_regs)
951684865Sobrien		    {
951784865Sobrien		      specs[count] = tmpl;
951884865Sobrien		      specs[count++].specific = 0;
951984865Sobrien		    }
952084865Sobrien		}
952184865Sobrien	      else if (idesc->operands[i] == IA64_OPND_F1
952284865Sobrien		       || idesc->operands[i] == IA64_OPND_F2
952384865Sobrien		       || idesc->operands[i] == IA64_OPND_F3
952484865Sobrien		       || idesc->operands[i] == IA64_OPND_F4)
952584865Sobrien		{
952684865Sobrien		  int num = CURR_SLOT.opnd[i].X_add_number - REG_FR;
952784865Sobrien		  if (num > 31)
952884865Sobrien		    {
952984865Sobrien		      specs[count] = tmpl;
953084865Sobrien		      specs[count++].specific = 0;
953184865Sobrien		    }
953284865Sobrien		}
953384865Sobrien	      else if (idesc->operands[i] == IA64_OPND_P1
953484865Sobrien		       || idesc->operands[i] == IA64_OPND_P2)
953584865Sobrien		{
953684865Sobrien		  int num = CURR_SLOT.opnd[i].X_add_number - REG_P;
953784865Sobrien		  if (num > 15)
953884865Sobrien		    {
953984865Sobrien		      specs[count] = tmpl;
954084865Sobrien		      specs[count++].specific = 0;
954184865Sobrien		    }
954284865Sobrien		}
954384865Sobrien	    }
954484865Sobrien	  if (CURR_SLOT.qp_regno > 15)
954584865Sobrien	    {
954684865Sobrien	      specs[count] = tmpl;
954784865Sobrien	      specs[count++].specific = 0;
954884865Sobrien	    }
954984865Sobrien	}
955084865Sobrien      break;
955184865Sobrien
955284865Sobrien      /* This is the same as IA64_RS_PRr, except simplified to account for
955384865Sobrien	 the fact that there is only one register.  */
955484865Sobrien    case IA64_RS_PR63:
955584865Sobrien      if (note == 0)
955684865Sobrien	{
955784865Sobrien	  specs[count++] = tmpl;
955884865Sobrien	}
955984865Sobrien      else if (note == 7)
9560104834Sobrien	{
9561104834Sobrien	  valueT mask = 0;
9562104834Sobrien	  if (idesc->operands[2] == IA64_OPND_IMM17)
9563104834Sobrien	    mask = CURR_SLOT.opnd[2].X_add_number;
9564104834Sobrien	  if (mask & ((valueT) 1 << 63))
956584865Sobrien	    specs[count++] = tmpl;
9566104834Sobrien	}
956784865Sobrien      else if (note == 11)
956884865Sobrien	{
956984865Sobrien	  if ((idesc->operands[0] == IA64_OPND_P1
957084865Sobrien	       && CURR_SLOT.opnd[0].X_add_number - REG_P == 63)
957184865Sobrien	      || (idesc->operands[1] == IA64_OPND_P2
957284865Sobrien		  && CURR_SLOT.opnd[1].X_add_number - REG_P == 63))
957384865Sobrien	    {
957484865Sobrien	      specs[count++] = tmpl;
957584865Sobrien	    }
957684865Sobrien	}
957784865Sobrien      else if (note == 12)
957884865Sobrien	{
957984865Sobrien	  if (CURR_SLOT.qp_regno == 63)
958084865Sobrien	    {
958184865Sobrien	      specs[count++] = tmpl;
958284865Sobrien	    }
958384865Sobrien	}
958484865Sobrien      else if (note == 1)
958584865Sobrien	{
958684865Sobrien	  if (rsrc_write)
958784865Sobrien	    {
9588104834Sobrien	      int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
9589104834Sobrien	      int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
959089857Sobrien	      int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
959189857Sobrien	      int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
959284865Sobrien
959384865Sobrien	      if (p1 == 63
959484865Sobrien		  && (idesc->operands[0] == IA64_OPND_P1
959584865Sobrien		      || idesc->operands[0] == IA64_OPND_P2))
959684865Sobrien		{
9597104834Sobrien		  specs[count] = tmpl;
959884865Sobrien		  specs[count++].cmp_type =
959984865Sobrien		    (or_andcm ? CMP_OR : (and_orcm ? CMP_AND : CMP_NONE));
960084865Sobrien		}
960184865Sobrien	      if (p2 == 63
960284865Sobrien		  && (idesc->operands[1] == IA64_OPND_P1
960384865Sobrien		      || idesc->operands[1] == IA64_OPND_P2))
960484865Sobrien		{
9605104834Sobrien		  specs[count] = tmpl;
960684865Sobrien		  specs[count++].cmp_type =
960784865Sobrien		    (or_andcm ? CMP_AND : (and_orcm ? CMP_OR : CMP_NONE));
960884865Sobrien		}
960984865Sobrien	    }
961084865Sobrien	  else
961184865Sobrien	    {
961284865Sobrien	      if (CURR_SLOT.qp_regno == 63)
961384865Sobrien		{
961484865Sobrien		  specs[count++] = tmpl;
961584865Sobrien		}
961684865Sobrien	    }
961784865Sobrien	}
961884865Sobrien      else
961984865Sobrien	{
962084865Sobrien	  UNHANDLED;
962184865Sobrien	}
962284865Sobrien      break;
962384865Sobrien
962484865Sobrien    case IA64_RS_RSE:
962584865Sobrien      /* FIXME we can identify some individual RSE written resources, but RSE
962684865Sobrien	 read resources have not yet been completely identified, so for now
962784865Sobrien	 treat RSE as a single resource */
962884865Sobrien      if (strncmp (idesc->name, "mov", 3) == 0)
962984865Sobrien	{
963084865Sobrien	  if (rsrc_write)
963184865Sobrien	    {
963284865Sobrien	      if (idesc->operands[0] == IA64_OPND_AR3
963384865Sobrien		  && CURR_SLOT.opnd[0].X_add_number - REG_AR == AR_BSPSTORE)
963484865Sobrien		{
9635218822Sdim		  specs[count++] = tmpl;
963684865Sobrien		}
963784865Sobrien	    }
963884865Sobrien	  else
963984865Sobrien	    {
964084865Sobrien	      if (idesc->operands[0] == IA64_OPND_AR3)
964184865Sobrien		{
964284865Sobrien		  if (CURR_SLOT.opnd[0].X_add_number - REG_AR == AR_BSPSTORE
964384865Sobrien		      || CURR_SLOT.opnd[0].X_add_number - REG_AR == AR_RNAT)
964484865Sobrien		    {
964584865Sobrien		      specs[count++] = tmpl;
964684865Sobrien		    }
964784865Sobrien		}
964884865Sobrien	      else if (idesc->operands[1] == IA64_OPND_AR3)
964984865Sobrien		{
965084865Sobrien		  if (CURR_SLOT.opnd[1].X_add_number - REG_AR == AR_BSP
965184865Sobrien		      || CURR_SLOT.opnd[1].X_add_number - REG_AR == AR_BSPSTORE
965284865Sobrien		      || CURR_SLOT.opnd[1].X_add_number - REG_AR == AR_RNAT)
965384865Sobrien		    {
965484865Sobrien		      specs[count++] = tmpl;
965584865Sobrien		    }
965684865Sobrien		}
965784865Sobrien	    }
965884865Sobrien	}
965984865Sobrien      else
966084865Sobrien	{
966184865Sobrien	  specs[count++] = tmpl;
966284865Sobrien	}
966384865Sobrien      break;
966484865Sobrien
966584865Sobrien    case IA64_RS_ANY:
966684865Sobrien      /* FIXME -- do any of these need to be non-specific? */
966784865Sobrien      specs[count++] = tmpl;
966884865Sobrien      break;
966984865Sobrien
967084865Sobrien    default:
967184865Sobrien      as_bad (_("Unrecognized dependency specifier %d\n"), dep->specifier);
967284865Sobrien      break;
967384865Sobrien    }
967484865Sobrien
967584865Sobrien  return count;
967684865Sobrien}
967784865Sobrien
967884865Sobrien/* Clear branch flags on marked resources.  This breaks the link between the
967984865Sobrien   QP of the marking instruction and a subsequent branch on the same QP.  */
968084865Sobrien
968184865Sobrienstatic void
968284865Sobrienclear_qp_branch_flag (mask)
968384865Sobrien     valueT mask;
968484865Sobrien{
968584865Sobrien  int i;
968684865Sobrien  for (i = 0; i < regdepslen; i++)
968784865Sobrien    {
968884865Sobrien      valueT bit = ((valueT) 1 << regdeps[i].qp_regno);
968984865Sobrien      if ((bit & mask) != 0)
969084865Sobrien	{
969184865Sobrien	  regdeps[i].link_to_qp_branch = 0;
969284865Sobrien	}
969384865Sobrien    }
969484865Sobrien}
969584865Sobrien
9696130561Sobrien/* MASK contains 2 and only 2 PRs which are mutually exclusive.  Remove
9697130561Sobrien   any mutexes which contain one of the PRs and create new ones when
9698130561Sobrien   needed.  */
9699130561Sobrien
9700130561Sobrienstatic int
9701130561Sobrienupdate_qp_mutex (valueT mask)
9702130561Sobrien{
9703130561Sobrien  int i;
9704130561Sobrien  int add = 0;
9705130561Sobrien
9706130561Sobrien  i = 0;
9707130561Sobrien  while (i < qp_mutexeslen)
9708130561Sobrien    {
9709130561Sobrien      if ((qp_mutexes[i].prmask & mask) != 0)
9710130561Sobrien	{
9711130561Sobrien	  /* If it destroys and creates the same mutex, do nothing.  */
9712130561Sobrien	  if (qp_mutexes[i].prmask == mask
9713130561Sobrien	      && qp_mutexes[i].path == md.path)
9714130561Sobrien	    {
9715130561Sobrien	      i++;
9716130561Sobrien	      add = -1;
9717130561Sobrien	    }
9718130561Sobrien	  else
9719130561Sobrien	    {
9720130561Sobrien	      int keep = 0;
9721130561Sobrien
9722130561Sobrien	      if (md.debug_dv)
9723130561Sobrien		{
9724130561Sobrien		  fprintf (stderr, "  Clearing mutex relation");
9725130561Sobrien		  print_prmask (qp_mutexes[i].prmask);
9726130561Sobrien		  fprintf (stderr, "\n");
9727130561Sobrien		}
9728130561Sobrien
9729130561Sobrien	      /* Deal with the old mutex with more than 3+ PRs only if
9730130561Sobrien		 the new mutex on the same execution path with it.
9731130561Sobrien
9732130561Sobrien		 FIXME: The 3+ mutex support is incomplete.
9733130561Sobrien		 dot_pred_rel () may be a better place to fix it.  */
9734130561Sobrien	      if (qp_mutexes[i].path == md.path)
9735130561Sobrien		{
9736130561Sobrien		  /* If it is a proper subset of the mutex, create a
9737130561Sobrien		     new mutex.  */
9738130561Sobrien		  if (add == 0
9739130561Sobrien		      && (qp_mutexes[i].prmask & mask) == mask)
9740130561Sobrien		    add = 1;
9741130561Sobrien
9742130561Sobrien		  qp_mutexes[i].prmask &= ~mask;
9743130561Sobrien		  if (qp_mutexes[i].prmask & (qp_mutexes[i].prmask - 1))
9744130561Sobrien		    {
9745130561Sobrien		      /* Modify the mutex if there are more than one
9746130561Sobrien			 PR left.  */
9747130561Sobrien		      keep = 1;
9748130561Sobrien		      i++;
9749130561Sobrien		    }
9750130561Sobrien		}
9751130561Sobrien
9752130561Sobrien	      if (keep == 0)
9753130561Sobrien		/* Remove the mutex.  */
9754130561Sobrien		qp_mutexes[i] = qp_mutexes[--qp_mutexeslen];
9755130561Sobrien	    }
9756130561Sobrien	}
9757130561Sobrien      else
9758130561Sobrien	++i;
9759130561Sobrien    }
9760130561Sobrien
9761130561Sobrien  if (add == 1)
9762130561Sobrien    add_qp_mutex (mask);
9763130561Sobrien
9764130561Sobrien  return add;
9765130561Sobrien}
9766130561Sobrien
976784865Sobrien/* Remove any mutexes which contain any of the PRs indicated in the mask.
976884865Sobrien
976984865Sobrien   Any changes to a PR clears the mutex relations which include that PR.  */
977084865Sobrien
977184865Sobrienstatic void
977284865Sobrienclear_qp_mutex (mask)
977384865Sobrien     valueT mask;
977484865Sobrien{
977584865Sobrien  int i;
977684865Sobrien
977784865Sobrien  i = 0;
977884865Sobrien  while (i < qp_mutexeslen)
977984865Sobrien    {
978084865Sobrien      if ((qp_mutexes[i].prmask & mask) != 0)
978184865Sobrien	{
978284865Sobrien	  if (md.debug_dv)
978384865Sobrien	    {
978484865Sobrien	      fprintf (stderr, "  Clearing mutex relation");
978584865Sobrien	      print_prmask (qp_mutexes[i].prmask);
978684865Sobrien	      fprintf (stderr, "\n");
978784865Sobrien	    }
978884865Sobrien	  qp_mutexes[i] = qp_mutexes[--qp_mutexeslen];
978984865Sobrien	}
979084865Sobrien      else
979184865Sobrien	++i;
979284865Sobrien    }
979384865Sobrien}
979484865Sobrien
979584865Sobrien/* Clear implies relations which contain PRs in the given masks.
979684865Sobrien   P1_MASK indicates the source of the implies relation, while P2_MASK
979784865Sobrien   indicates the implied PR.  */
979884865Sobrien
979984865Sobrienstatic void
980084865Sobrienclear_qp_implies (p1_mask, p2_mask)
980184865Sobrien     valueT p1_mask;
980284865Sobrien     valueT p2_mask;
980384865Sobrien{
980484865Sobrien  int i;
980584865Sobrien
980684865Sobrien  i = 0;
980784865Sobrien  while (i < qp_implieslen)
980884865Sobrien    {
980984865Sobrien      if ((((valueT) 1 << qp_implies[i].p1) & p1_mask) != 0
981084865Sobrien	  || (((valueT) 1 << qp_implies[i].p2) & p2_mask) != 0)
981184865Sobrien	{
981284865Sobrien	  if (md.debug_dv)
981384865Sobrien	    fprintf (stderr, "Clearing implied relation PR%d->PR%d\n",
981484865Sobrien		     qp_implies[i].p1, qp_implies[i].p2);
981584865Sobrien	  qp_implies[i] = qp_implies[--qp_implieslen];
981684865Sobrien	}
981784865Sobrien      else
981884865Sobrien	++i;
981984865Sobrien    }
982084865Sobrien}
982184865Sobrien
982284865Sobrien/* Add the PRs specified to the list of implied relations.  */
982384865Sobrien
982484865Sobrienstatic void
982584865Sobrienadd_qp_imply (p1, p2)
982684865Sobrien     int p1, p2;
982784865Sobrien{
982884865Sobrien  valueT mask;
982984865Sobrien  valueT bit;
983084865Sobrien  int i;
983184865Sobrien
983284865Sobrien  /* p0 is not meaningful here.  */
983384865Sobrien  if (p1 == 0 || p2 == 0)
983484865Sobrien    abort ();
983584865Sobrien
983684865Sobrien  if (p1 == p2)
983784865Sobrien    return;
983884865Sobrien
983984865Sobrien  /* If it exists already, ignore it.  */
984084865Sobrien  for (i = 0; i < qp_implieslen; i++)
984184865Sobrien    {
984284865Sobrien      if (qp_implies[i].p1 == p1
984384865Sobrien	  && qp_implies[i].p2 == p2
984484865Sobrien	  && qp_implies[i].path == md.path
984584865Sobrien	  && !qp_implies[i].p2_branched)
984684865Sobrien	return;
984784865Sobrien    }
984884865Sobrien
984984865Sobrien  if (qp_implieslen == qp_impliestotlen)
985084865Sobrien    {
985184865Sobrien      qp_impliestotlen += 20;
985284865Sobrien      qp_implies = (struct qp_imply *)
985384865Sobrien	xrealloc ((void *) qp_implies,
985484865Sobrien		  qp_impliestotlen * sizeof (struct qp_imply));
985584865Sobrien    }
985684865Sobrien  if (md.debug_dv)
985784865Sobrien    fprintf (stderr, "  Registering PR%d implies PR%d\n", p1, p2);
985884865Sobrien  qp_implies[qp_implieslen].p1 = p1;
985984865Sobrien  qp_implies[qp_implieslen].p2 = p2;
986084865Sobrien  qp_implies[qp_implieslen].path = md.path;
986184865Sobrien  qp_implies[qp_implieslen++].p2_branched = 0;
986284865Sobrien
986384865Sobrien  /* Add in the implied transitive relations; for everything that p2 implies,
986484865Sobrien     make p1 imply that, too; for everything that implies p1, make it imply p2
986584865Sobrien     as well.  */
986684865Sobrien  for (i = 0; i < qp_implieslen; i++)
986784865Sobrien    {
986884865Sobrien      if (qp_implies[i].p1 == p2)
986984865Sobrien	add_qp_imply (p1, qp_implies[i].p2);
987084865Sobrien      if (qp_implies[i].p2 == p1)
987184865Sobrien	add_qp_imply (qp_implies[i].p1, p2);
987284865Sobrien    }
987384865Sobrien  /* Add in mutex relations implied by this implies relation; for each mutex
987484865Sobrien     relation containing p2, duplicate it and replace p2 with p1.  */
987584865Sobrien  bit = (valueT) 1 << p1;
987684865Sobrien  mask = (valueT) 1 << p2;
987784865Sobrien  for (i = 0; i < qp_mutexeslen; i++)
987884865Sobrien    {
987984865Sobrien      if (qp_mutexes[i].prmask & mask)
988084865Sobrien	add_qp_mutex ((qp_mutexes[i].prmask & ~mask) | bit);
988184865Sobrien    }
988284865Sobrien}
988384865Sobrien
988484865Sobrien/* Add the PRs specified in the mask to the mutex list; this means that only
988584865Sobrien   one of the PRs can be true at any time.  PR0 should never be included in
988684865Sobrien   the mask.  */
988784865Sobrien
988884865Sobrienstatic void
988984865Sobrienadd_qp_mutex (mask)
989084865Sobrien     valueT mask;
989184865Sobrien{
989284865Sobrien  if (mask & 0x1)
989384865Sobrien    abort ();
989484865Sobrien
989584865Sobrien  if (qp_mutexeslen == qp_mutexestotlen)
989684865Sobrien    {
989784865Sobrien      qp_mutexestotlen += 20;
989884865Sobrien      qp_mutexes = (struct qpmutex *)
989984865Sobrien	xrealloc ((void *) qp_mutexes,
990084865Sobrien		  qp_mutexestotlen * sizeof (struct qpmutex));
990184865Sobrien    }
990284865Sobrien  if (md.debug_dv)
990384865Sobrien    {
990484865Sobrien      fprintf (stderr, "  Registering mutex on");
990584865Sobrien      print_prmask (mask);
990684865Sobrien      fprintf (stderr, "\n");
990784865Sobrien    }
990884865Sobrien  qp_mutexes[qp_mutexeslen].path = md.path;
990984865Sobrien  qp_mutexes[qp_mutexeslen++].prmask = mask;
991084865Sobrien}
991184865Sobrien
991289857Sobrienstatic int
991389857Sobrienhas_suffix_p (name, suffix)
9914104834Sobrien     const char *name;
9915104834Sobrien     const char *suffix;
991689857Sobrien{
991789857Sobrien  size_t namelen = strlen (name);
991889857Sobrien  size_t sufflen = strlen (suffix);
991989857Sobrien
992089857Sobrien  if (namelen <= sufflen)
992189857Sobrien    return 0;
992289857Sobrien  return strcmp (name + namelen - sufflen, suffix) == 0;
992389857Sobrien}
992489857Sobrien
992584865Sobrienstatic void
992684865Sobrienclear_register_values ()
992784865Sobrien{
992884865Sobrien  int i;
992984865Sobrien  if (md.debug_dv)
993084865Sobrien    fprintf (stderr, "  Clearing register values\n");
993184865Sobrien  for (i = 1; i < NELEMS (gr_values); i++)
993284865Sobrien    gr_values[i].known = 0;
993384865Sobrien}
993484865Sobrien
993584865Sobrien/* Keep track of register values/changes which affect DV tracking.
993684865Sobrien
993784865Sobrien   optimization note: should add a flag to classes of insns where otherwise we
993884865Sobrien   have to examine a group of strings to identify them.  */
993984865Sobrien
994084865Sobrienstatic void
994184865Sobriennote_register_values (idesc)
994284865Sobrien     struct ia64_opcode *idesc;
994384865Sobrien{
994484865Sobrien  valueT qp_changemask = 0;
994584865Sobrien  int i;
994684865Sobrien
994784865Sobrien  /* Invalidate values for registers being written to.  */
994884865Sobrien  for (i = 0; i < idesc->num_outputs; i++)
994984865Sobrien    {
995084865Sobrien      if (idesc->operands[i] == IA64_OPND_R1
995184865Sobrien	  || idesc->operands[i] == IA64_OPND_R2
995284865Sobrien	  || idesc->operands[i] == IA64_OPND_R3)
995384865Sobrien	{
995484865Sobrien	  int regno = CURR_SLOT.opnd[i].X_add_number - REG_GR;
995584865Sobrien	  if (regno > 0 && regno < NELEMS (gr_values))
995684865Sobrien	    gr_values[regno].known = 0;
995784865Sobrien	}
995884865Sobrien      else if (idesc->operands[i] == IA64_OPND_R3_2)
995984865Sobrien	{
996084865Sobrien	  int regno = CURR_SLOT.opnd[i].X_add_number - REG_GR;
996184865Sobrien	  if (regno > 0 && regno < 4)
996284865Sobrien	    gr_values[regno].known = 0;
996384865Sobrien	}
996484865Sobrien      else if (idesc->operands[i] == IA64_OPND_P1
996584865Sobrien	       || idesc->operands[i] == IA64_OPND_P2)
996684865Sobrien	{
996784865Sobrien	  int regno = CURR_SLOT.opnd[i].X_add_number - REG_P;
996884865Sobrien	  qp_changemask |= (valueT) 1 << regno;
996984865Sobrien	}
997084865Sobrien      else if (idesc->operands[i] == IA64_OPND_PR)
997184865Sobrien	{
997284865Sobrien	  if (idesc->operands[2] & (valueT) 0x10000)
997384865Sobrien	    qp_changemask = ~(valueT) 0x1FFFF | idesc->operands[2];
997484865Sobrien	  else
997584865Sobrien	    qp_changemask = idesc->operands[2];
997684865Sobrien	  break;
997784865Sobrien	}
997884865Sobrien      else if (idesc->operands[i] == IA64_OPND_PR_ROT)
997984865Sobrien	{
998084865Sobrien	  if (idesc->operands[1] & ((valueT) 1 << 43))
9981130561Sobrien	    qp_changemask = -((valueT) 1 << 44) | idesc->operands[1];
998284865Sobrien	  else
998384865Sobrien	    qp_changemask = idesc->operands[1];
998484865Sobrien	  qp_changemask &= ~(valueT) 0xFFFF;
998584865Sobrien	  break;
998684865Sobrien	}
998784865Sobrien    }
998884865Sobrien
998984865Sobrien  /* Always clear qp branch flags on any PR change.  */
999084865Sobrien  /* FIXME there may be exceptions for certain compares.  */
999184865Sobrien  clear_qp_branch_flag (qp_changemask);
999284865Sobrien
999384865Sobrien  /* Invalidate rotating registers on insns which affect RRBs in CFM.  */
999484865Sobrien  if (idesc->flags & IA64_OPCODE_MOD_RRBS)
999584865Sobrien    {
999684865Sobrien      qp_changemask |= ~(valueT) 0xFFFF;
999784865Sobrien      if (strcmp (idesc->name, "clrrrb.pr") != 0)
999884865Sobrien	{
999984865Sobrien	  for (i = 32; i < 32 + md.rot.num_regs; i++)
1000084865Sobrien	    gr_values[i].known = 0;
1000184865Sobrien	}
1000284865Sobrien      clear_qp_mutex (qp_changemask);
1000384865Sobrien      clear_qp_implies (qp_changemask, qp_changemask);
1000484865Sobrien    }
1000584865Sobrien  /* After a call, all register values are undefined, except those marked
1000684865Sobrien     as "safe".  */
1000784865Sobrien  else if (strncmp (idesc->name, "br.call", 6) == 0
1000884865Sobrien	   || strncmp (idesc->name, "brl.call", 7) == 0)
1000984865Sobrien    {
1001084865Sobrien      /* FIXME keep GR values which are marked as "safe_across_calls"  */
1001184865Sobrien      clear_register_values ();
1001284865Sobrien      clear_qp_mutex (~qp_safe_across_calls);
1001384865Sobrien      clear_qp_implies (~qp_safe_across_calls, ~qp_safe_across_calls);
1001484865Sobrien      clear_qp_branch_flag (~qp_safe_across_calls);
1001584865Sobrien    }
1001684865Sobrien  else if (is_interruption_or_rfi (idesc)
1001784865Sobrien	   || is_taken_branch (idesc))
1001884865Sobrien    {
1001984865Sobrien      clear_register_values ();
1002084865Sobrien      clear_qp_mutex (~(valueT) 0);
1002184865Sobrien      clear_qp_implies (~(valueT) 0, ~(valueT) 0);
1002284865Sobrien    }
1002384865Sobrien  /* Look for mutex and implies relations.  */
1002484865Sobrien  else if ((idesc->operands[0] == IA64_OPND_P1
1002584865Sobrien	    || idesc->operands[0] == IA64_OPND_P2)
1002684865Sobrien	   && (idesc->operands[1] == IA64_OPND_P1
1002784865Sobrien	       || idesc->operands[1] == IA64_OPND_P2))
1002884865Sobrien    {
1002984865Sobrien      int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
1003084865Sobrien      int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
10031130561Sobrien      valueT p1mask = (p1 != 0) ? (valueT) 1 << p1 : 0;
10032130561Sobrien      valueT p2mask = (p2 != 0) ? (valueT) 1 << p2 : 0;
1003384865Sobrien
10034130561Sobrien      /* If both PRs are PR0, we can't really do anything.  */
10035130561Sobrien      if (p1 == 0 && p2 == 0)
1003684865Sobrien	{
1003784865Sobrien	  if (md.debug_dv)
1003884865Sobrien	    fprintf (stderr, "  Ignoring PRs due to inclusion of p0\n");
1003984865Sobrien	}
1004084865Sobrien      /* In general, clear mutexes and implies which include P1 or P2,
1004184865Sobrien	 with the following exceptions.  */
1004289857Sobrien      else if (has_suffix_p (idesc->name, ".or.andcm")
1004389857Sobrien	       || has_suffix_p (idesc->name, ".and.orcm"))
1004484865Sobrien	{
1004584865Sobrien	  clear_qp_implies (p2mask, p1mask);
1004684865Sobrien	}
1004789857Sobrien      else if (has_suffix_p (idesc->name, ".andcm")
1004889857Sobrien	       || has_suffix_p (idesc->name, ".and"))
1004984865Sobrien	{
1005084865Sobrien	  clear_qp_implies (0, p1mask | p2mask);
1005184865Sobrien	}
1005289857Sobrien      else if (has_suffix_p (idesc->name, ".orcm")
1005389857Sobrien	       || has_suffix_p (idesc->name, ".or"))
1005484865Sobrien	{
1005584865Sobrien	  clear_qp_mutex (p1mask | p2mask);
1005684865Sobrien	  clear_qp_implies (p1mask | p2mask, 0);
1005784865Sobrien	}
1005884865Sobrien      else
1005984865Sobrien	{
10060130561Sobrien	  int added = 0;
10061130561Sobrien
1006284865Sobrien	  clear_qp_implies (p1mask | p2mask, p1mask | p2mask);
10063130561Sobrien
10064130561Sobrien	  /* If one of the PRs is PR0, we call clear_qp_mutex.  */
10065130561Sobrien	  if (p1 == 0 || p2 == 0)
10066130561Sobrien	    clear_qp_mutex (p1mask | p2mask);
10067130561Sobrien	  else
10068130561Sobrien	    added = update_qp_mutex (p1mask | p2mask);
10069130561Sobrien
10070130561Sobrien	  if (CURR_SLOT.qp_regno == 0
10071130561Sobrien	      || has_suffix_p (idesc->name, ".unc"))
1007284865Sobrien	    {
10073130561Sobrien	      if (added == 0 && p1 && p2)
10074130561Sobrien		add_qp_mutex (p1mask | p2mask);
1007584865Sobrien	      if (CURR_SLOT.qp_regno != 0)
1007684865Sobrien		{
10077130561Sobrien		  if (p1)
10078130561Sobrien		    add_qp_imply (p1, CURR_SLOT.qp_regno);
10079130561Sobrien		  if (p2)
10080130561Sobrien		    add_qp_imply (p2, CURR_SLOT.qp_regno);
1008184865Sobrien		}
1008284865Sobrien	    }
1008384865Sobrien	}
1008484865Sobrien    }
1008584865Sobrien  /* Look for mov imm insns into GRs.  */
1008684865Sobrien  else if (idesc->operands[0] == IA64_OPND_R1
1008784865Sobrien	   && (idesc->operands[1] == IA64_OPND_IMM22
1008884865Sobrien	       || idesc->operands[1] == IA64_OPND_IMMU64)
10089218822Sdim	   && CURR_SLOT.opnd[1].X_op == O_constant
1009084865Sobrien	   && (strcmp (idesc->name, "mov") == 0
1009184865Sobrien	       || strcmp (idesc->name, "movl") == 0))
1009284865Sobrien    {
1009384865Sobrien      int regno = CURR_SLOT.opnd[0].X_add_number - REG_GR;
1009484865Sobrien      if (regno > 0 && regno < NELEMS (gr_values))
1009584865Sobrien	{
1009684865Sobrien	  gr_values[regno].known = 1;
1009784865Sobrien	  gr_values[regno].value = CURR_SLOT.opnd[1].X_add_number;
1009884865Sobrien	  gr_values[regno].path = md.path;
1009984865Sobrien	  if (md.debug_dv)
1010084865Sobrien	    {
1010184865Sobrien	      fprintf (stderr, "  Know gr%d = ", regno);
1010284865Sobrien	      fprintf_vma (stderr, gr_values[regno].value);
1010384865Sobrien	      fputs ("\n", stderr);
1010484865Sobrien	    }
1010584865Sobrien	}
1010684865Sobrien    }
10107218822Sdim  /* Look for dep.z imm insns.  */
10108218822Sdim  else if (idesc->operands[0] == IA64_OPND_R1
10109218822Sdim	   && idesc->operands[1] == IA64_OPND_IMM8
10110218822Sdim	   && strcmp (idesc->name, "dep.z") == 0)
10111218822Sdim    {
10112218822Sdim      int regno = CURR_SLOT.opnd[0].X_add_number - REG_GR;
10113218822Sdim      if (regno > 0 && regno < NELEMS (gr_values))
10114218822Sdim	{
10115218822Sdim	  valueT value = CURR_SLOT.opnd[1].X_add_number;
10116218822Sdim
10117218822Sdim	  if (CURR_SLOT.opnd[3].X_add_number < 64)
10118218822Sdim	    value &= ((valueT)1 << CURR_SLOT.opnd[3].X_add_number) - 1;
10119218822Sdim	  value <<= CURR_SLOT.opnd[2].X_add_number;
10120218822Sdim	  gr_values[regno].known = 1;
10121218822Sdim	  gr_values[regno].value = value;
10122218822Sdim	  gr_values[regno].path = md.path;
10123218822Sdim	  if (md.debug_dv)
10124218822Sdim	    {
10125218822Sdim	      fprintf (stderr, "  Know gr%d = ", regno);
10126218822Sdim	      fprintf_vma (stderr, gr_values[regno].value);
10127218822Sdim	      fputs ("\n", stderr);
10128218822Sdim	    }
10129218822Sdim	}
10130218822Sdim    }
1013184865Sobrien  else
1013284865Sobrien    {
1013384865Sobrien      clear_qp_mutex (qp_changemask);
1013484865Sobrien      clear_qp_implies (qp_changemask, qp_changemask);
1013584865Sobrien    }
1013684865Sobrien}
1013784865Sobrien
1013884865Sobrien/* Return whether the given predicate registers are currently mutex.  */
1013984865Sobrien
1014084865Sobrienstatic int
1014184865Sobrienqp_mutex (p1, p2, path)
1014284865Sobrien     int p1;
1014384865Sobrien     int p2;
1014484865Sobrien     int path;
1014584865Sobrien{
1014684865Sobrien  int i;
1014784865Sobrien  valueT mask;
1014884865Sobrien
1014984865Sobrien  if (p1 != p2)
1015084865Sobrien    {
1015184865Sobrien      mask = ((valueT) 1 << p1) | (valueT) 1 << p2;
1015284865Sobrien      for (i = 0; i < qp_mutexeslen; i++)
1015384865Sobrien	{
1015484865Sobrien	  if (qp_mutexes[i].path >= path
1015584865Sobrien	      && (qp_mutexes[i].prmask & mask) == mask)
1015684865Sobrien	    return 1;
1015784865Sobrien	}
1015884865Sobrien    }
1015984865Sobrien  return 0;
1016084865Sobrien}
1016184865Sobrien
1016284865Sobrien/* Return whether the given resource is in the given insn's list of chks
1016384865Sobrien   Return 1 if the conflict is absolutely determined, 2 if it's a potential
1016484865Sobrien   conflict.  */
1016584865Sobrien
1016684865Sobrienstatic int
1016784865Sobrienresources_match (rs, idesc, note, qp_regno, path)
1016884865Sobrien     struct rsrc *rs;
1016984865Sobrien     struct ia64_opcode *idesc;
1017084865Sobrien     int note;
1017184865Sobrien     int qp_regno;
1017284865Sobrien     int path;
1017384865Sobrien{
1017484865Sobrien  struct rsrc specs[MAX_SPECS];
1017584865Sobrien  int count;
1017684865Sobrien
1017784865Sobrien  /* If the marked resource's qp_regno and the given qp_regno are mutex,
1017884865Sobrien     we don't need to check.  One exception is note 11, which indicates that
1017984865Sobrien     target predicates are written regardless of PR[qp].  */
1018084865Sobrien  if (qp_mutex (rs->qp_regno, qp_regno, path)
1018184865Sobrien      && note != 11)
1018284865Sobrien    return 0;
1018384865Sobrien
1018484865Sobrien  count = specify_resource (rs->dependency, idesc, DV_CHK, specs, note, path);
1018584865Sobrien  while (count-- > 0)
1018684865Sobrien    {
1018784865Sobrien      /* UNAT checking is a bit more specific than other resources */
1018884865Sobrien      if (rs->dependency->specifier == IA64_RS_AR_UNAT
1018984865Sobrien	  && specs[count].mem_offset.hint
1019084865Sobrien	  && rs->mem_offset.hint)
1019184865Sobrien	{
1019284865Sobrien	  if (rs->mem_offset.base == specs[count].mem_offset.base)
1019384865Sobrien	    {
1019484865Sobrien	      if (((rs->mem_offset.offset >> 3) & 0x3F) ==
1019584865Sobrien		  ((specs[count].mem_offset.offset >> 3) & 0x3F))
1019684865Sobrien		return 1;
1019784865Sobrien	      else
1019884865Sobrien		continue;
1019984865Sobrien	    }
1020084865Sobrien	}
1020184865Sobrien
1020284865Sobrien      /* Skip apparent PR write conflicts where both writes are an AND or both
1020384865Sobrien	 writes are an OR.  */
1020484865Sobrien      if (rs->dependency->specifier == IA64_RS_PR
1020584865Sobrien	  || rs->dependency->specifier == IA64_RS_PRr
1020684865Sobrien	  || rs->dependency->specifier == IA64_RS_PR63)
1020784865Sobrien	{
1020884865Sobrien	  if (specs[count].cmp_type != CMP_NONE
1020984865Sobrien	      && specs[count].cmp_type == rs->cmp_type)
1021084865Sobrien	    {
1021184865Sobrien	      if (md.debug_dv)
1021284865Sobrien		fprintf (stderr, "  %s on parallel compare allowed (PR%d)\n",
1021384865Sobrien			 dv_mode[rs->dependency->mode],
1021484865Sobrien			 rs->dependency->specifier != IA64_RS_PR63 ?
1021584865Sobrien			 specs[count].index : 63);
1021684865Sobrien	      continue;
1021784865Sobrien	    }
1021884865Sobrien	  if (md.debug_dv)
1021984865Sobrien	    fprintf (stderr,
1022084865Sobrien		     "  %s on parallel compare conflict %s vs %s on PR%d\n",
1022184865Sobrien		     dv_mode[rs->dependency->mode],
1022284865Sobrien		     dv_cmp_type[rs->cmp_type],
1022384865Sobrien		     dv_cmp_type[specs[count].cmp_type],
1022484865Sobrien		     rs->dependency->specifier != IA64_RS_PR63 ?
1022584865Sobrien		     specs[count].index : 63);
1022684865Sobrien
1022784865Sobrien	}
1022884865Sobrien
1022984865Sobrien      /* If either resource is not specific, conservatively assume a conflict
1023084865Sobrien       */
1023184865Sobrien      if (!specs[count].specific || !rs->specific)
1023284865Sobrien	return 2;
1023384865Sobrien      else if (specs[count].index == rs->index)
1023484865Sobrien	return 1;
1023584865Sobrien    }
1023684865Sobrien
1023784865Sobrien  return 0;
1023884865Sobrien}
1023984865Sobrien
1024084865Sobrien/* Indicate an instruction group break; if INSERT_STOP is non-zero, then
1024184865Sobrien   insert a stop to create the break.  Update all resource dependencies
1024284865Sobrien   appropriately.  If QP_REGNO is non-zero, only apply the break to resources
1024384865Sobrien   which use the same QP_REGNO and have the link_to_qp_branch flag set.
1024484865Sobrien   If SAVE_CURRENT is non-zero, don't affect resources marked by the current
1024584865Sobrien   instruction.  */
1024684865Sobrien
1024784865Sobrienstatic void
1024884865Sobrieninsn_group_break (insert_stop, qp_regno, save_current)
1024984865Sobrien     int insert_stop;
1025084865Sobrien     int qp_regno;
1025184865Sobrien     int save_current;
1025284865Sobrien{
1025384865Sobrien  int i;
1025484865Sobrien
1025584865Sobrien  if (insert_stop && md.num_slots_in_use > 0)
1025684865Sobrien    PREV_SLOT.end_of_insn_group = 1;
1025784865Sobrien
1025884865Sobrien  if (md.debug_dv)
1025984865Sobrien    {
1026084865Sobrien      fprintf (stderr, "  Insn group break%s",
1026184865Sobrien	       (insert_stop ? " (w/stop)" : ""));
1026284865Sobrien      if (qp_regno != 0)
1026384865Sobrien	fprintf (stderr, " effective for QP=%d", qp_regno);
1026484865Sobrien      fprintf (stderr, "\n");
1026584865Sobrien    }
1026684865Sobrien
1026784865Sobrien  i = 0;
1026884865Sobrien  while (i < regdepslen)
1026984865Sobrien    {
1027084865Sobrien      const struct ia64_dependency *dep = regdeps[i].dependency;
1027184865Sobrien
1027284865Sobrien      if (qp_regno != 0
1027384865Sobrien	  && regdeps[i].qp_regno != qp_regno)
1027484865Sobrien	{
1027584865Sobrien	  ++i;
1027684865Sobrien	  continue;
1027784865Sobrien	}
1027884865Sobrien
1027984865Sobrien      if (save_current
1028084865Sobrien	  && CURR_SLOT.src_file == regdeps[i].file
1028184865Sobrien	  && CURR_SLOT.src_line == regdeps[i].line)
1028284865Sobrien	{
1028384865Sobrien	  ++i;
1028484865Sobrien	  continue;
1028584865Sobrien	}
1028684865Sobrien
1028784865Sobrien      /* clear dependencies which are automatically cleared by a stop, or
1028884865Sobrien	 those that have reached the appropriate state of insn serialization */
1028984865Sobrien      if (dep->semantics == IA64_DVS_IMPLIED
1029084865Sobrien	  || dep->semantics == IA64_DVS_IMPLIEDF
1029184865Sobrien	  || regdeps[i].insn_srlz == STATE_SRLZ)
1029284865Sobrien	{
1029384865Sobrien	  print_dependency ("Removing", i);
1029484865Sobrien	  regdeps[i] = regdeps[--regdepslen];
1029584865Sobrien	}
1029684865Sobrien      else
1029784865Sobrien	{
1029884865Sobrien	  if (dep->semantics == IA64_DVS_DATA
1029984865Sobrien	      || dep->semantics == IA64_DVS_INSTR
1030084865Sobrien	      || dep->semantics == IA64_DVS_SPECIFIC)
1030184865Sobrien	    {
1030284865Sobrien	      if (regdeps[i].insn_srlz == STATE_NONE)
1030384865Sobrien		regdeps[i].insn_srlz = STATE_STOP;
1030484865Sobrien	      if (regdeps[i].data_srlz == STATE_NONE)
1030584865Sobrien		regdeps[i].data_srlz = STATE_STOP;
1030684865Sobrien	    }
1030784865Sobrien	  ++i;
1030884865Sobrien	}
1030984865Sobrien    }
1031084865Sobrien}
1031184865Sobrien
1031284865Sobrien/* Add the given resource usage spec to the list of active dependencies.  */
1031384865Sobrien
1031484865Sobrienstatic void
1031584865Sobrienmark_resource (idesc, dep, spec, depind, path)
1031684865Sobrien     struct ia64_opcode *idesc ATTRIBUTE_UNUSED;
1031784865Sobrien     const struct ia64_dependency *dep ATTRIBUTE_UNUSED;
1031884865Sobrien     struct rsrc *spec;
1031984865Sobrien     int depind;
1032084865Sobrien     int path;
1032184865Sobrien{
1032284865Sobrien  if (regdepslen == regdepstotlen)
1032384865Sobrien    {
1032484865Sobrien      regdepstotlen += 20;
1032584865Sobrien      regdeps = (struct rsrc *)
1032684865Sobrien	xrealloc ((void *) regdeps,
1032784865Sobrien		  regdepstotlen * sizeof (struct rsrc));
1032884865Sobrien    }
1032984865Sobrien
1033084865Sobrien  regdeps[regdepslen] = *spec;
1033184865Sobrien  regdeps[regdepslen].depind = depind;
1033284865Sobrien  regdeps[regdepslen].path = path;
1033384865Sobrien  regdeps[regdepslen].file = CURR_SLOT.src_file;
1033484865Sobrien  regdeps[regdepslen].line = CURR_SLOT.src_line;
1033584865Sobrien
1033684865Sobrien  print_dependency ("Adding", regdepslen);
1033784865Sobrien
1033884865Sobrien  ++regdepslen;
1033984865Sobrien}
1034084865Sobrien
1034184865Sobrienstatic void
1034284865Sobrienprint_dependency (action, depind)
1034384865Sobrien     const char *action;
1034484865Sobrien     int depind;
1034584865Sobrien{
1034684865Sobrien  if (md.debug_dv)
1034784865Sobrien    {
1034884865Sobrien      fprintf (stderr, "  %s %s '%s'",
1034984865Sobrien	       action, dv_mode[(regdeps[depind].dependency)->mode],
1035084865Sobrien	       (regdeps[depind].dependency)->name);
10351218822Sdim      if (regdeps[depind].specific && regdeps[depind].index >= 0)
1035284865Sobrien	fprintf (stderr, " (%d)", regdeps[depind].index);
1035384865Sobrien      if (regdeps[depind].mem_offset.hint)
1035484865Sobrien	{
1035584865Sobrien	  fputs (" ", stderr);
1035684865Sobrien	  fprintf_vma (stderr, regdeps[depind].mem_offset.base);
1035784865Sobrien	  fputs ("+", stderr);
1035884865Sobrien	  fprintf_vma (stderr, regdeps[depind].mem_offset.offset);
1035984865Sobrien	}
1036084865Sobrien      fprintf (stderr, "\n");
1036184865Sobrien    }
1036284865Sobrien}
1036384865Sobrien
1036484865Sobrienstatic void
1036584865Sobrieninstruction_serialization ()
1036684865Sobrien{
1036784865Sobrien  int i;
1036884865Sobrien  if (md.debug_dv)
1036984865Sobrien    fprintf (stderr, "  Instruction serialization\n");
1037084865Sobrien  for (i = 0; i < regdepslen; i++)
1037184865Sobrien    if (regdeps[i].insn_srlz == STATE_STOP)
1037284865Sobrien      regdeps[i].insn_srlz = STATE_SRLZ;
1037384865Sobrien}
1037484865Sobrien
1037584865Sobrienstatic void
1037684865Sobriendata_serialization ()
1037784865Sobrien{
1037884865Sobrien  int i = 0;
1037984865Sobrien  if (md.debug_dv)
1038084865Sobrien    fprintf (stderr, "  Data serialization\n");
1038184865Sobrien  while (i < regdepslen)
1038284865Sobrien    {
1038384865Sobrien      if (regdeps[i].data_srlz == STATE_STOP
1038484865Sobrien	  /* Note: as of 991210, all "other" dependencies are cleared by a
1038584865Sobrien	     data serialization.  This might change with new tables */
1038684865Sobrien	  || (regdeps[i].dependency)->semantics == IA64_DVS_OTHER)
1038784865Sobrien	{
1038884865Sobrien	  print_dependency ("Removing", i);
1038984865Sobrien	  regdeps[i] = regdeps[--regdepslen];
1039084865Sobrien	}
1039184865Sobrien      else
1039284865Sobrien	++i;
1039384865Sobrien    }
1039484865Sobrien}
1039584865Sobrien
1039684865Sobrien/* Insert stops and serializations as needed to avoid DVs.  */
1039784865Sobrien
1039884865Sobrienstatic void
1039984865Sobrienremove_marked_resource (rs)
1040084865Sobrien     struct rsrc *rs;
1040184865Sobrien{
1040284865Sobrien  switch (rs->dependency->semantics)
1040384865Sobrien    {
1040484865Sobrien    case IA64_DVS_SPECIFIC:
1040584865Sobrien      if (md.debug_dv)
1040684865Sobrien	fprintf (stderr, "Implementation-specific, assume worst case...\n");
1040784865Sobrien      /* ...fall through...  */
1040884865Sobrien    case IA64_DVS_INSTR:
1040984865Sobrien      if (md.debug_dv)
1041084865Sobrien	fprintf (stderr, "Inserting instr serialization\n");
1041184865Sobrien      if (rs->insn_srlz < STATE_STOP)
1041284865Sobrien	insn_group_break (1, 0, 0);
1041384865Sobrien      if (rs->insn_srlz < STATE_SRLZ)
1041484865Sobrien	{
10415218822Sdim	  struct slot oldslot = CURR_SLOT;
1041684865Sobrien	  /* Manually jam a srlz.i insn into the stream */
10417218822Sdim	  memset (&CURR_SLOT, 0, sizeof (CURR_SLOT));
10418218822Sdim	  CURR_SLOT.user_template = -1;
1041984865Sobrien	  CURR_SLOT.idesc = ia64_find_opcode ("srlz.i");
1042084865Sobrien	  instruction_serialization ();
1042184865Sobrien	  md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
1042284865Sobrien	  if (++md.num_slots_in_use >= NUM_SLOTS)
1042384865Sobrien	    emit_one_bundle ();
10424218822Sdim	  CURR_SLOT = oldslot;
1042584865Sobrien	}
1042684865Sobrien      insn_group_break (1, 0, 0);
1042784865Sobrien      break;
1042884865Sobrien    case IA64_DVS_OTHER: /* as of rev2 (991220) of the DV tables, all
1042984865Sobrien			    "other" types of DV are eliminated
1043084865Sobrien			    by a data serialization */
1043184865Sobrien    case IA64_DVS_DATA:
1043284865Sobrien      if (md.debug_dv)
1043384865Sobrien	fprintf (stderr, "Inserting data serialization\n");
1043484865Sobrien      if (rs->data_srlz < STATE_STOP)
1043584865Sobrien	insn_group_break (1, 0, 0);
1043684865Sobrien      {
10437218822Sdim	struct slot oldslot = CURR_SLOT;
1043884865Sobrien	/* Manually jam a srlz.d insn into the stream */
10439218822Sdim	memset (&CURR_SLOT, 0, sizeof (CURR_SLOT));
10440218822Sdim	CURR_SLOT.user_template = -1;
1044184865Sobrien	CURR_SLOT.idesc = ia64_find_opcode ("srlz.d");
1044284865Sobrien	data_serialization ();
1044384865Sobrien	md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
1044484865Sobrien	if (++md.num_slots_in_use >= NUM_SLOTS)
1044584865Sobrien	  emit_one_bundle ();
10446218822Sdim	CURR_SLOT = oldslot;
1044784865Sobrien      }
1044884865Sobrien      break;
1044984865Sobrien    case IA64_DVS_IMPLIED:
1045084865Sobrien    case IA64_DVS_IMPLIEDF:
1045184865Sobrien      if (md.debug_dv)
1045284865Sobrien	fprintf (stderr, "Inserting stop\n");
1045384865Sobrien      insn_group_break (1, 0, 0);
1045484865Sobrien      break;
1045584865Sobrien    default:
1045684865Sobrien      break;
1045784865Sobrien    }
1045884865Sobrien}
1045984865Sobrien
1046084865Sobrien/* Check the resources used by the given opcode against the current dependency
1046184865Sobrien   list.
1046284865Sobrien
1046384865Sobrien   The check is run once for each execution path encountered.  In this case,
1046484865Sobrien   a unique execution path is the sequence of instructions following a code
1046584865Sobrien   entry point, e.g. the following has three execution paths, one starting
1046684865Sobrien   at L0, one at L1, and one at L2.
1046784865Sobrien
1046884865Sobrien   L0:     nop
1046984865Sobrien   L1:     add
1047084865Sobrien   L2:     add
1047184865Sobrien   br.ret
1047284865Sobrien*/
1047384865Sobrien
1047484865Sobrienstatic void
1047584865Sobriencheck_dependencies (idesc)
1047684865Sobrien     struct ia64_opcode *idesc;
1047784865Sobrien{
1047884865Sobrien  const struct ia64_opcode_dependency *opdeps = idesc->dependencies;
1047984865Sobrien  int path;
1048084865Sobrien  int i;
1048184865Sobrien
1048284865Sobrien  /* Note that the number of marked resources may change within the
1048384865Sobrien     loop if in auto mode.  */
1048484865Sobrien  i = 0;
1048584865Sobrien  while (i < regdepslen)
1048684865Sobrien    {
1048784865Sobrien      struct rsrc *rs = &regdeps[i];
1048884865Sobrien      const struct ia64_dependency *dep = rs->dependency;
1048984865Sobrien      int chkind;
1049084865Sobrien      int note;
1049184865Sobrien      int start_over = 0;
1049284865Sobrien
1049384865Sobrien      if (dep->semantics == IA64_DVS_NONE
1049484865Sobrien	  || (chkind = depends_on (rs->depind, idesc)) == -1)
1049584865Sobrien	{
1049684865Sobrien	  ++i;
1049784865Sobrien	  continue;
1049884865Sobrien	}
1049984865Sobrien
1050084865Sobrien      note = NOTE (opdeps->chks[chkind]);
1050184865Sobrien
1050284865Sobrien      /* Check this resource against each execution path seen thus far.  */
1050384865Sobrien      for (path = 0; path <= md.path; path++)
1050484865Sobrien	{
1050584865Sobrien	  int matchtype;
1050684865Sobrien
1050784865Sobrien	  /* If the dependency wasn't on the path being checked, ignore it.  */
1050884865Sobrien	  if (rs->path < path)
1050984865Sobrien	    continue;
1051084865Sobrien
1051184865Sobrien	  /* If the QP for this insn implies a QP which has branched, don't
1051284865Sobrien	     bother checking.  Ed. NOTE: I don't think this check is terribly
1051384865Sobrien	     useful; what's the point of generating code which will only be
1051484865Sobrien	     reached if its QP is zero?
1051584865Sobrien	     This code was specifically inserted to handle the following code,
1051684865Sobrien	     based on notes from Intel's DV checking code, where p1 implies p2.
1051784865Sobrien
1051884865Sobrien		  mov r4 = 2
1051984865Sobrien	     (p2) br.cond L
1052084865Sobrien	     (p1) mov r4 = 7
1052184865Sobrien	  */
1052284865Sobrien	  if (CURR_SLOT.qp_regno != 0)
1052384865Sobrien	    {
1052484865Sobrien	      int skip = 0;
1052584865Sobrien	      int implies;
1052684865Sobrien	      for (implies = 0; implies < qp_implieslen; implies++)
1052784865Sobrien		{
1052884865Sobrien		  if (qp_implies[implies].path >= path
1052984865Sobrien		      && qp_implies[implies].p1 == CURR_SLOT.qp_regno
1053084865Sobrien		      && qp_implies[implies].p2_branched)
1053184865Sobrien		    {
1053284865Sobrien		      skip = 1;
1053384865Sobrien		      break;
1053484865Sobrien		    }
1053584865Sobrien		}
1053684865Sobrien	      if (skip)
1053784865Sobrien		continue;
1053884865Sobrien	    }
1053984865Sobrien
1054084865Sobrien	  if ((matchtype = resources_match (rs, idesc, note,
1054184865Sobrien					    CURR_SLOT.qp_regno, path)) != 0)
1054284865Sobrien	    {
1054384865Sobrien	      char msg[1024];
1054484865Sobrien	      char pathmsg[256] = "";
1054584865Sobrien	      char indexmsg[256] = "";
1054684865Sobrien	      int certain = (matchtype == 1 && CURR_SLOT.qp_regno == 0);
1054784865Sobrien
1054884865Sobrien	      if (path != 0)
10549218822Sdim		snprintf (pathmsg, sizeof (pathmsg),
10550218822Sdim			  " when entry is at label '%s'",
1055184865Sobrien			 md.entry_labels[path - 1]);
10552218822Sdim	      if (matchtype == 1 && rs->index >= 0)
10553218822Sdim		snprintf (indexmsg, sizeof (indexmsg),
10554218822Sdim			  ", specific resource number is %d",
1055584865Sobrien			 rs->index);
10556218822Sdim	      snprintf (msg, sizeof (msg),
10557218822Sdim			"Use of '%s' %s %s dependency '%s' (%s)%s%s",
1055884865Sobrien		       idesc->name,
1055984865Sobrien		       (certain ? "violates" : "may violate"),
1056084865Sobrien		       dv_mode[dep->mode], dep->name,
1056184865Sobrien		       dv_sem[dep->semantics],
1056284865Sobrien		       pathmsg, indexmsg);
1056384865Sobrien
1056484865Sobrien	      if (md.explicit_mode)
1056584865Sobrien		{
1056684865Sobrien		  as_warn ("%s", msg);
1056784865Sobrien		  if (path < md.path)
1056884865Sobrien		    as_warn (_("Only the first path encountering the conflict "
1056984865Sobrien			       "is reported"));
1057084865Sobrien		  as_warn_where (rs->file, rs->line,
1057184865Sobrien				 _("This is the location of the "
1057284865Sobrien				   "conflicting usage"));
1057384865Sobrien		  /* Don't bother checking other paths, to avoid duplicating
1057484865Sobrien		     the same warning */
1057584865Sobrien		  break;
1057684865Sobrien		}
1057784865Sobrien	      else
1057884865Sobrien		{
1057984865Sobrien		  if (md.debug_dv)
1058084865Sobrien		    fprintf (stderr, "%s @ %s:%d\n", msg, rs->file, rs->line);
1058184865Sobrien
1058284865Sobrien		  remove_marked_resource (rs);
1058384865Sobrien
1058484865Sobrien		  /* since the set of dependencies has changed, start over */
1058584865Sobrien		  /* FIXME -- since we're removing dvs as we go, we
1058684865Sobrien		     probably don't really need to start over...  */
1058784865Sobrien		  start_over = 1;
1058884865Sobrien		  break;
1058984865Sobrien		}
1059084865Sobrien	    }
1059184865Sobrien	}
1059284865Sobrien      if (start_over)
1059384865Sobrien	i = 0;
1059484865Sobrien      else
1059584865Sobrien	++i;
1059684865Sobrien    }
1059784865Sobrien}
1059884865Sobrien
1059984865Sobrien/* Register new dependencies based on the given opcode.  */
1060084865Sobrien
1060184865Sobrienstatic void
1060284865Sobrienmark_resources (idesc)
1060384865Sobrien     struct ia64_opcode *idesc;
1060484865Sobrien{
1060584865Sobrien  int i;
1060684865Sobrien  const struct ia64_opcode_dependency *opdeps = idesc->dependencies;
1060784865Sobrien  int add_only_qp_reads = 0;
1060884865Sobrien
1060984865Sobrien  /* A conditional branch only uses its resources if it is taken; if it is
1061084865Sobrien     taken, we stop following that path.  The other branch types effectively
1061184865Sobrien     *always* write their resources.  If it's not taken, register only QP
1061284865Sobrien     reads.  */
1061384865Sobrien  if (is_conditional_branch (idesc) || is_interruption_or_rfi (idesc))
1061484865Sobrien    {
1061584865Sobrien      add_only_qp_reads = 1;
1061684865Sobrien    }
1061784865Sobrien
1061884865Sobrien  if (md.debug_dv)
1061984865Sobrien    fprintf (stderr, "Registering '%s' resource usage\n", idesc->name);
1062084865Sobrien
1062184865Sobrien  for (i = 0; i < opdeps->nregs; i++)
1062284865Sobrien    {
1062384865Sobrien      const struct ia64_dependency *dep;
1062484865Sobrien      struct rsrc specs[MAX_SPECS];
1062584865Sobrien      int note;
1062684865Sobrien      int path;
1062784865Sobrien      int count;
1062884865Sobrien
1062984865Sobrien      dep = ia64_find_dependency (opdeps->regs[i]);
1063084865Sobrien      note = NOTE (opdeps->regs[i]);
1063184865Sobrien
1063284865Sobrien      if (add_only_qp_reads
1063384865Sobrien	  && !(dep->mode == IA64_DV_WAR
1063484865Sobrien	       && (dep->specifier == IA64_RS_PR
1063584865Sobrien		   || dep->specifier == IA64_RS_PRr
1063684865Sobrien		   || dep->specifier == IA64_RS_PR63)))
1063784865Sobrien	continue;
1063884865Sobrien
1063984865Sobrien      count = specify_resource (dep, idesc, DV_REG, specs, note, md.path);
1064084865Sobrien
1064184865Sobrien      while (count-- > 0)
1064284865Sobrien	{
1064384865Sobrien	  mark_resource (idesc, dep, &specs[count],
1064484865Sobrien			 DEP (opdeps->regs[i]), md.path);
1064584865Sobrien	}
1064684865Sobrien
1064784865Sobrien      /* The execution path may affect register values, which may in turn
1064884865Sobrien	 affect which indirect-access resources are accessed.  */
1064984865Sobrien      switch (dep->specifier)
1065084865Sobrien	{
1065184865Sobrien	default:
1065284865Sobrien	  break;
1065384865Sobrien	case IA64_RS_CPUID:
1065484865Sobrien	case IA64_RS_DBR:
1065584865Sobrien	case IA64_RS_IBR:
1065684865Sobrien	case IA64_RS_MSR:
1065784865Sobrien	case IA64_RS_PKR:
1065884865Sobrien	case IA64_RS_PMC:
1065984865Sobrien	case IA64_RS_PMD:
1066084865Sobrien	case IA64_RS_RR:
1066184865Sobrien	  for (path = 0; path < md.path; path++)
1066284865Sobrien	    {
1066384865Sobrien	      count = specify_resource (dep, idesc, DV_REG, specs, note, path);
1066484865Sobrien	      while (count-- > 0)
1066584865Sobrien		mark_resource (idesc, dep, &specs[count],
1066684865Sobrien			       DEP (opdeps->regs[i]), path);
1066784865Sobrien	    }
1066884865Sobrien	  break;
1066984865Sobrien	}
1067084865Sobrien    }
1067184865Sobrien}
1067284865Sobrien
1067384865Sobrien/* Remove dependencies when they no longer apply.  */
1067484865Sobrien
1067584865Sobrienstatic void
1067684865Sobrienupdate_dependencies (idesc)
1067784865Sobrien     struct ia64_opcode *idesc;
1067884865Sobrien{
1067984865Sobrien  int i;
1068084865Sobrien
1068184865Sobrien  if (strcmp (idesc->name, "srlz.i") == 0)
1068284865Sobrien    {
1068384865Sobrien      instruction_serialization ();
1068484865Sobrien    }
1068584865Sobrien  else if (strcmp (idesc->name, "srlz.d") == 0)
1068684865Sobrien    {
1068784865Sobrien      data_serialization ();
1068884865Sobrien    }
1068984865Sobrien  else if (is_interruption_or_rfi (idesc)
1069084865Sobrien	   || is_taken_branch (idesc))
1069184865Sobrien    {
1069284865Sobrien      /* Although technically the taken branch doesn't clear dependencies
1069384865Sobrien	 which require a srlz.[id], we don't follow the branch; the next
1069484865Sobrien	 instruction is assumed to start with a clean slate.  */
1069584865Sobrien      regdepslen = 0;
1069684865Sobrien      md.path = 0;
1069784865Sobrien    }
1069884865Sobrien  else if (is_conditional_branch (idesc)
1069984865Sobrien	   && CURR_SLOT.qp_regno != 0)
1070084865Sobrien    {
1070184865Sobrien      int is_call = strstr (idesc->name, ".call") != NULL;
1070284865Sobrien
1070384865Sobrien      for (i = 0; i < qp_implieslen; i++)
1070484865Sobrien	{
1070584865Sobrien	  /* If the conditional branch's predicate is implied by the predicate
1070684865Sobrien	     in an existing dependency, remove that dependency.  */
1070784865Sobrien	  if (qp_implies[i].p2 == CURR_SLOT.qp_regno)
1070884865Sobrien	    {
1070984865Sobrien	      int depind = 0;
1071084865Sobrien	      /* Note that this implied predicate takes a branch so that if
1071184865Sobrien		 a later insn generates a DV but its predicate implies this
1071284865Sobrien		 one, we can avoid the false DV warning.  */
1071384865Sobrien	      qp_implies[i].p2_branched = 1;
1071484865Sobrien	      while (depind < regdepslen)
1071584865Sobrien		{
1071684865Sobrien		  if (regdeps[depind].qp_regno == qp_implies[i].p1)
1071784865Sobrien		    {
1071884865Sobrien		      print_dependency ("Removing", depind);
1071984865Sobrien		      regdeps[depind] = regdeps[--regdepslen];
1072084865Sobrien		    }
1072184865Sobrien		  else
1072284865Sobrien		    ++depind;
1072384865Sobrien		}
1072484865Sobrien	    }
1072584865Sobrien	}
1072684865Sobrien      /* Any marked resources which have this same predicate should be
1072784865Sobrien	 cleared, provided that the QP hasn't been modified between the
1072884865Sobrien	 marking instruction and the branch.  */
1072984865Sobrien      if (is_call)
1073084865Sobrien	{
1073184865Sobrien	  insn_group_break (0, CURR_SLOT.qp_regno, 1);
1073284865Sobrien	}
1073384865Sobrien      else
1073484865Sobrien	{
1073584865Sobrien	  i = 0;
1073684865Sobrien	  while (i < regdepslen)
1073784865Sobrien	    {
1073884865Sobrien	      if (regdeps[i].qp_regno == CURR_SLOT.qp_regno
1073984865Sobrien		  && regdeps[i].link_to_qp_branch
1074084865Sobrien		  && (regdeps[i].file != CURR_SLOT.src_file
1074184865Sobrien		      || regdeps[i].line != CURR_SLOT.src_line))
1074284865Sobrien		{
1074384865Sobrien		  /* Treat like a taken branch */
1074484865Sobrien		  print_dependency ("Removing", i);
1074584865Sobrien		  regdeps[i] = regdeps[--regdepslen];
1074684865Sobrien		}
1074784865Sobrien	      else
1074884865Sobrien		++i;
1074984865Sobrien	    }
1075084865Sobrien	}
1075184865Sobrien    }
1075284865Sobrien}
1075384865Sobrien
1075484865Sobrien/* Examine the current instruction for dependency violations.  */
1075584865Sobrien
1075684865Sobrienstatic int
1075784865Sobriencheck_dv (idesc)
1075884865Sobrien     struct ia64_opcode *idesc;
1075984865Sobrien{
1076084865Sobrien  if (md.debug_dv)
1076184865Sobrien    {
1076284865Sobrien      fprintf (stderr, "Checking %s for violations (line %d, %d/%d)\n",
1076384865Sobrien	       idesc->name, CURR_SLOT.src_line,
1076484865Sobrien	       idesc->dependencies->nchks,
1076584865Sobrien	       idesc->dependencies->nregs);
1076684865Sobrien    }
1076784865Sobrien
1076884865Sobrien  /* Look through the list of currently marked resources; if the current
1076984865Sobrien     instruction has the dependency in its chks list which uses that resource,
1077084865Sobrien     check against the specific resources used.  */
1077184865Sobrien  check_dependencies (idesc);
1077284865Sobrien
1077384865Sobrien  /* Look up the instruction's regdeps (RAW writes, WAW writes, and WAR reads),
1077484865Sobrien     then add them to the list of marked resources.  */
1077584865Sobrien  mark_resources (idesc);
1077684865Sobrien
1077784865Sobrien  /* There are several types of dependency semantics, and each has its own
1077884865Sobrien     requirements for being cleared
1077984865Sobrien
1078084865Sobrien     Instruction serialization (insns separated by interruption, rfi, or
1078184865Sobrien     writer + srlz.i + reader, all in separate groups) clears DVS_INSTR.
1078284865Sobrien
1078384865Sobrien     Data serialization (instruction serialization, or writer + srlz.d +
1078484865Sobrien     reader, where writer and srlz.d are in separate groups) clears
1078584865Sobrien     DVS_DATA. (This also clears DVS_OTHER, but that is not guaranteed to
1078684865Sobrien     always be the case).
1078784865Sobrien
1078884865Sobrien     Instruction group break (groups separated by stop, taken branch,
1078984865Sobrien     interruption or rfi) clears DVS_IMPLIED and DVS_IMPLIEDF.
1079084865Sobrien   */
1079184865Sobrien  update_dependencies (idesc);
1079284865Sobrien
1079384865Sobrien  /* Sometimes, knowing a register value allows us to avoid giving a false DV
1079484865Sobrien     warning.  Keep track of as many as possible that are useful.  */
1079584865Sobrien  note_register_values (idesc);
1079684865Sobrien
1079784865Sobrien  /* We don't need or want this anymore.  */
1079884865Sobrien  md.mem_offset.hint = 0;
1079984865Sobrien
1080084865Sobrien  return 0;
1080184865Sobrien}
1080284865Sobrien
1080384865Sobrien/* Translate one line of assembly.  Pseudo ops and labels do not show
1080484865Sobrien   here.  */
1080584865Sobrienvoid
1080684865Sobrienmd_assemble (str)
1080784865Sobrien     char *str;
1080884865Sobrien{
1080984865Sobrien  char *saved_input_line_pointer, *mnemonic;
1081084865Sobrien  const struct pseudo_opcode *pdesc;
1081184865Sobrien  struct ia64_opcode *idesc;
1081284865Sobrien  unsigned char qp_regno;
1081384865Sobrien  unsigned int flags;
1081484865Sobrien  int ch;
1081584865Sobrien
1081684865Sobrien  saved_input_line_pointer = input_line_pointer;
1081784865Sobrien  input_line_pointer = str;
1081884865Sobrien
1081984865Sobrien  /* extract the opcode (mnemonic):  */
1082084865Sobrien
1082184865Sobrien  mnemonic = input_line_pointer;
1082284865Sobrien  ch = get_symbol_end ();
1082384865Sobrien  pdesc = (struct pseudo_opcode *) hash_find (md.pseudo_hash, mnemonic);
1082484865Sobrien  if (pdesc)
1082584865Sobrien    {
1082684865Sobrien      *input_line_pointer = ch;
1082784865Sobrien      (*pdesc->handler) (pdesc->arg);
1082884865Sobrien      goto done;
1082984865Sobrien    }
1083084865Sobrien
1083184865Sobrien  /* Find the instruction descriptor matching the arguments.  */
1083284865Sobrien
1083384865Sobrien  idesc = ia64_find_opcode (mnemonic);
1083484865Sobrien  *input_line_pointer = ch;
1083584865Sobrien  if (!idesc)
1083684865Sobrien    {
1083784865Sobrien      as_bad ("Unknown opcode `%s'", mnemonic);
1083884865Sobrien      goto done;
1083984865Sobrien    }
1084084865Sobrien
1084184865Sobrien  idesc = parse_operands (idesc);
1084284865Sobrien  if (!idesc)
1084384865Sobrien    goto done;
1084484865Sobrien
1084584865Sobrien  /* Handle the dynamic ops we can handle now:  */
1084684865Sobrien  if (idesc->type == IA64_TYPE_DYN)
1084784865Sobrien    {
1084884865Sobrien      if (strcmp (idesc->name, "add") == 0)
1084984865Sobrien	{
1085084865Sobrien	  if (CURR_SLOT.opnd[2].X_op == O_register
1085184865Sobrien	      && CURR_SLOT.opnd[2].X_add_number < 4)
1085284865Sobrien	    mnemonic = "addl";
1085384865Sobrien	  else
1085484865Sobrien	    mnemonic = "adds";
1085584865Sobrien	  ia64_free_opcode (idesc);
1085684865Sobrien	  idesc = ia64_find_opcode (mnemonic);
1085784865Sobrien	}
1085884865Sobrien      else if (strcmp (idesc->name, "mov") == 0)
1085984865Sobrien	{
1086084865Sobrien	  enum ia64_opnd opnd1, opnd2;
1086184865Sobrien	  int rop;
1086284865Sobrien
1086384865Sobrien	  opnd1 = idesc->operands[0];
1086484865Sobrien	  opnd2 = idesc->operands[1];
1086584865Sobrien	  if (opnd1 == IA64_OPND_AR3)
1086684865Sobrien	    rop = 0;
1086784865Sobrien	  else if (opnd2 == IA64_OPND_AR3)
1086884865Sobrien	    rop = 1;
1086984865Sobrien	  else
1087084865Sobrien	    abort ();
10871218822Sdim	  if (CURR_SLOT.opnd[rop].X_op == O_register)
10872218822Sdim	    {
10873218822Sdim	      if (ar_is_only_in_integer_unit (CURR_SLOT.opnd[rop].X_add_number))
10874218822Sdim		mnemonic = "mov.i";
10875218822Sdim	      else if (ar_is_only_in_memory_unit (CURR_SLOT.opnd[rop].X_add_number))
10876218822Sdim		mnemonic = "mov.m";
10877218822Sdim	      else
10878218822Sdim		rop = -1;
10879218822Sdim	    }
1088084865Sobrien	  else
10881218822Sdim	    abort ();
10882218822Sdim	  if (rop >= 0)
10883218822Sdim	    {
10884218822Sdim	      ia64_free_opcode (idesc);
10885218822Sdim	      idesc = ia64_find_opcode (mnemonic);
10886218822Sdim	      while (idesc != NULL
10887218822Sdim		     && (idesc->operands[0] != opnd1
10888218822Sdim			 || idesc->operands[1] != opnd2))
10889218822Sdim		idesc = get_next_opcode (idesc);
10890218822Sdim	    }
1089184865Sobrien	}
1089284865Sobrien    }
10893218822Sdim  else if (strcmp (idesc->name, "mov.i") == 0
10894218822Sdim	   || strcmp (idesc->name, "mov.m") == 0)
10895218822Sdim    {
10896218822Sdim      enum ia64_opnd opnd1, opnd2;
10897218822Sdim      int rop;
10898218822Sdim
10899218822Sdim      opnd1 = idesc->operands[0];
10900218822Sdim      opnd2 = idesc->operands[1];
10901218822Sdim      if (opnd1 == IA64_OPND_AR3)
10902218822Sdim	rop = 0;
10903218822Sdim      else if (opnd2 == IA64_OPND_AR3)
10904218822Sdim	rop = 1;
10905218822Sdim      else
10906218822Sdim	abort ();
10907218822Sdim      if (CURR_SLOT.opnd[rop].X_op == O_register)
10908218822Sdim	{
10909218822Sdim	  char unit = 'a';
10910218822Sdim	  if (ar_is_only_in_integer_unit (CURR_SLOT.opnd[rop].X_add_number))
10911218822Sdim	    unit = 'i';
10912218822Sdim	  else if (ar_is_only_in_memory_unit (CURR_SLOT.opnd[rop].X_add_number))
10913218822Sdim	    unit = 'm';
10914218822Sdim	  if (unit != 'a' && unit != idesc->name [4])
10915218822Sdim	    as_bad ("AR %d can only be accessed by %c-unit",
10916218822Sdim		    (int) (CURR_SLOT.opnd[rop].X_add_number - REG_AR),
10917218822Sdim		    TOUPPER (unit));
10918218822Sdim	}
10919218822Sdim    }
10920218822Sdim  else if (strcmp (idesc->name, "hint.b") == 0)
10921218822Sdim    {
10922218822Sdim      switch (md.hint_b)
10923218822Sdim	{
10924218822Sdim	case hint_b_ok:
10925218822Sdim	  break;
10926218822Sdim	case hint_b_warning:
10927218822Sdim	  as_warn ("hint.b may be treated as nop");
10928218822Sdim	  break;
10929218822Sdim	case hint_b_error:
10930218822Sdim	  as_bad ("hint.b shouldn't be used");
10931218822Sdim	  break;
10932218822Sdim	}
10933218822Sdim    }
1093484865Sobrien
1093584865Sobrien  qp_regno = 0;
1093684865Sobrien  if (md.qp.X_op == O_register)
1093784865Sobrien    {
1093884865Sobrien      qp_regno = md.qp.X_add_number - REG_P;
1093984865Sobrien      md.qp.X_op = O_absent;
1094084865Sobrien    }
1094184865Sobrien
1094284865Sobrien  flags = idesc->flags;
1094384865Sobrien
1094484865Sobrien  if ((flags & IA64_OPCODE_FIRST) != 0)
10945130561Sobrien    {
10946130561Sobrien      /* The alignment frag has to end with a stop bit only if the
10947130561Sobrien	 next instruction after the alignment directive has to be
10948130561Sobrien	 the first instruction in an instruction group.  */
10949130561Sobrien      if (align_frag)
10950130561Sobrien	{
10951130561Sobrien	  while (align_frag->fr_type != rs_align_code)
10952130561Sobrien	    {
10953130561Sobrien	      align_frag = align_frag->fr_next;
10954130561Sobrien	      if (!align_frag)
10955130561Sobrien		break;
10956130561Sobrien	    }
10957130561Sobrien	  /* align_frag can be NULL if there are directives in
10958130561Sobrien	     between.  */
10959130561Sobrien	  if (align_frag && align_frag->fr_next == frag_now)
10960130561Sobrien	    align_frag->tc_frag_data = 1;
10961130561Sobrien	}
1096284865Sobrien
10963130561Sobrien      insn_group_break (1, 0, 0);
10964130561Sobrien    }
10965130561Sobrien  align_frag = NULL;
10966130561Sobrien
1096784865Sobrien  if ((flags & IA64_OPCODE_NO_PRED) != 0 && qp_regno != 0)
1096884865Sobrien    {
1096984865Sobrien      as_bad ("`%s' cannot be predicated", idesc->name);
1097084865Sobrien      goto done;
1097184865Sobrien    }
1097284865Sobrien
1097384865Sobrien  /* Build the instruction.  */
1097484865Sobrien  CURR_SLOT.qp_regno = qp_regno;
1097584865Sobrien  CURR_SLOT.idesc = idesc;
1097684865Sobrien  as_where (&CURR_SLOT.src_file, &CURR_SLOT.src_line);
1097784865Sobrien  dwarf2_where (&CURR_SLOT.debug_line);
1097884865Sobrien
10979218822Sdim  /* Add unwind entries, if there are any.  */
1098084865Sobrien  if (unwind.current_entry)
1098184865Sobrien    {
1098284865Sobrien      CURR_SLOT.unwind_record = unwind.current_entry;
1098384865Sobrien      unwind.current_entry = NULL;
1098484865Sobrien    }
10985218822Sdim  if (unwind.pending_saves)
10986218822Sdim    {
10987218822Sdim      if (unwind.pending_saves->next)
10988218822Sdim	{
10989218822Sdim	  /* Attach the next pending save to the next slot so that its
10990218822Sdim	     slot number will get set correctly.  */
10991218822Sdim	  add_unwind_entry (unwind.pending_saves->next, NOT_A_CHAR);
10992218822Sdim	  unwind.pending_saves = &unwind.pending_saves->next->r.record.p;
10993218822Sdim	}
10994218822Sdim      else
10995218822Sdim	unwind.pending_saves = NULL;
10996218822Sdim    }
10997218822Sdim  if (unwind.proc_pending.sym && S_IS_DEFINED (unwind.proc_pending.sym))
10998218822Sdim    unwind.insn = 1;
1099984865Sobrien
1100084865Sobrien  /* Check for dependency violations.  */
1100184865Sobrien  if (md.detect_dv)
1100284865Sobrien    check_dv (idesc);
1100384865Sobrien
1100484865Sobrien  md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
1100584865Sobrien  if (++md.num_slots_in_use >= NUM_SLOTS)
1100684865Sobrien    emit_one_bundle ();
1100784865Sobrien
1100884865Sobrien  if ((flags & IA64_OPCODE_LAST) != 0)
1100984865Sobrien    insn_group_break (1, 0, 0);
1101084865Sobrien
1101184865Sobrien  md.last_text_seg = now_seg;
1101284865Sobrien
1101384865Sobrien done:
1101484865Sobrien  input_line_pointer = saved_input_line_pointer;
1101584865Sobrien}
1101684865Sobrien
1101784865Sobrien/* Called when symbol NAME cannot be found in the symbol table.
1101884865Sobrien   Should be used for dynamic valued symbols only.  */
1101984865Sobrien
1102084865SobriensymbolS *
1102184865Sobrienmd_undefined_symbol (name)
1102284865Sobrien     char *name ATTRIBUTE_UNUSED;
1102384865Sobrien{
1102484865Sobrien  return 0;
1102584865Sobrien}
1102684865Sobrien
1102784865Sobrien/* Called for any expression that can not be recognized.  When the
1102884865Sobrien   function is called, `input_line_pointer' will point to the start of
1102984865Sobrien   the expression.  */
1103084865Sobrien
1103184865Sobrienvoid
1103284865Sobrienmd_operand (e)
1103384865Sobrien     expressionS *e;
1103484865Sobrien{
1103584865Sobrien  switch (*input_line_pointer)
1103684865Sobrien    {
1103784865Sobrien    case '[':
1103884865Sobrien      ++input_line_pointer;
11039218822Sdim      expression_and_evaluate (e);
1104084865Sobrien      if (*input_line_pointer != ']')
1104184865Sobrien	{
11042218822Sdim	  as_bad ("Closing bracket missing");
1104384865Sobrien	  goto err;
1104484865Sobrien	}
1104584865Sobrien      else
1104684865Sobrien	{
11047218822Sdim	  if (e->X_op != O_register
11048218822Sdim	      || e->X_add_number < REG_GR
11049218822Sdim	      || e->X_add_number > REG_GR + 127)
11050218822Sdim	    {
11051218822Sdim	      as_bad ("Index must be a general register");
11052218822Sdim	      e->X_add_number = REG_GR;
11053218822Sdim	    }
1105484865Sobrien
1105584865Sobrien	  ++input_line_pointer;
1105684865Sobrien	  e->X_op = O_index;
1105784865Sobrien	}
1105884865Sobrien      break;
1105984865Sobrien
1106084865Sobrien    default:
1106184865Sobrien      break;
1106284865Sobrien    }
1106384865Sobrien  return;
1106484865Sobrien
1106584865Sobrien err:
1106684865Sobrien  ignore_rest_of_line ();
1106784865Sobrien}
1106884865Sobrien
1106984865Sobrien/* Return 1 if it's OK to adjust a reloc by replacing the symbol with
1107084865Sobrien   a section symbol plus some offset.  For relocs involving @fptr(),
1107184865Sobrien   directives we don't want such adjustments since we need to have the
1107284865Sobrien   original symbol's name in the reloc.  */
1107384865Sobrienint
1107484865Sobrienia64_fix_adjustable (fix)
1107584865Sobrien     fixS *fix;
1107684865Sobrien{
1107784865Sobrien  /* Prevent all adjustments to global symbols */
11078218822Sdim  if (S_IS_EXTERNAL (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy))
1107984865Sobrien    return 0;
1108084865Sobrien
1108184865Sobrien  switch (fix->fx_r_type)
1108284865Sobrien    {
1108384865Sobrien    case BFD_RELOC_IA64_FPTR64I:
1108484865Sobrien    case BFD_RELOC_IA64_FPTR32MSB:
1108584865Sobrien    case BFD_RELOC_IA64_FPTR32LSB:
1108684865Sobrien    case BFD_RELOC_IA64_FPTR64MSB:
1108784865Sobrien    case BFD_RELOC_IA64_FPTR64LSB:
1108884865Sobrien    case BFD_RELOC_IA64_LTOFF_FPTR22:
1108984865Sobrien    case BFD_RELOC_IA64_LTOFF_FPTR64I:
1109084865Sobrien      return 0;
1109184865Sobrien    default:
1109284865Sobrien      break;
1109384865Sobrien    }
1109484865Sobrien
1109584865Sobrien  return 1;
1109684865Sobrien}
1109784865Sobrien
1109884865Sobrienint
1109984865Sobrienia64_force_relocation (fix)
1110084865Sobrien     fixS *fix;
1110184865Sobrien{
1110284865Sobrien  switch (fix->fx_r_type)
1110384865Sobrien    {
1110484865Sobrien    case BFD_RELOC_IA64_FPTR64I:
1110584865Sobrien    case BFD_RELOC_IA64_FPTR32MSB:
1110684865Sobrien    case BFD_RELOC_IA64_FPTR32LSB:
1110784865Sobrien    case BFD_RELOC_IA64_FPTR64MSB:
1110884865Sobrien    case BFD_RELOC_IA64_FPTR64LSB:
1110984865Sobrien
1111084865Sobrien    case BFD_RELOC_IA64_LTOFF22:
1111184865Sobrien    case BFD_RELOC_IA64_LTOFF64I:
1111284865Sobrien    case BFD_RELOC_IA64_LTOFF_FPTR22:
1111384865Sobrien    case BFD_RELOC_IA64_LTOFF_FPTR64I:
1111484865Sobrien    case BFD_RELOC_IA64_PLTOFF22:
1111584865Sobrien    case BFD_RELOC_IA64_PLTOFF64I:
1111684865Sobrien    case BFD_RELOC_IA64_PLTOFF64MSB:
1111784865Sobrien    case BFD_RELOC_IA64_PLTOFF64LSB:
11118130561Sobrien
11119130561Sobrien    case BFD_RELOC_IA64_LTOFF22X:
11120130561Sobrien    case BFD_RELOC_IA64_LDXMOV:
1112184865Sobrien      return 1;
1112284865Sobrien
1112384865Sobrien    default:
11124130561Sobrien      break;
1112584865Sobrien    }
11126130561Sobrien
11127130561Sobrien  return generic_force_reloc (fix);
1112884865Sobrien}
1112984865Sobrien
1113084865Sobrien/* Decide from what point a pc-relative relocation is relative to,
1113184865Sobrien   relative to the pc-relative fixup.  Er, relatively speaking.  */
1113284865Sobrienlong
1113384865Sobrienia64_pcrel_from_section (fix, sec)
1113484865Sobrien     fixS *fix;
1113584865Sobrien     segT sec;
1113684865Sobrien{
1113784865Sobrien  unsigned long off = fix->fx_frag->fr_address + fix->fx_where;
1113884865Sobrien
1113984865Sobrien  if (bfd_get_section_flags (stdoutput, sec) & SEC_CODE)
1114084865Sobrien    off &= ~0xfUL;
1114184865Sobrien
1114284865Sobrien  return off;
1114384865Sobrien}
1114484865Sobrien
11145130561Sobrien
11146130561Sobrien/* Used to emit section-relative relocs for the dwarf2 debug data.  */
11147130561Sobrienvoid
11148130561Sobrienia64_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
11149130561Sobrien{
11150130561Sobrien  expressionS expr;
11151130561Sobrien
11152130561Sobrien  expr.X_op = O_pseudo_fixup;
11153130561Sobrien  expr.X_op_symbol = pseudo_func[FUNC_SEC_RELATIVE].u.sym;
11154130561Sobrien  expr.X_add_number = 0;
11155130561Sobrien  expr.X_add_symbol = symbol;
11156130561Sobrien  emit_expr (&expr, size);
11157130561Sobrien}
11158130561Sobrien
1115984865Sobrien/* This is called whenever some data item (not an instruction) needs a
1116084865Sobrien   fixup.  We pick the right reloc code depending on the byteorder
1116184865Sobrien   currently in effect.  */
1116284865Sobrienvoid
1116384865Sobrienia64_cons_fix_new (f, where, nbytes, exp)
1116484865Sobrien     fragS *f;
1116584865Sobrien     int where;
1116684865Sobrien     int nbytes;
1116784865Sobrien     expressionS *exp;
1116884865Sobrien{
1116984865Sobrien  bfd_reloc_code_real_type code;
1117084865Sobrien  fixS *fix;
1117184865Sobrien
1117284865Sobrien  switch (nbytes)
1117384865Sobrien    {
1117484865Sobrien      /* There are no reloc for 8 and 16 bit quantities, but we allow
1117584865Sobrien	 them here since they will work fine as long as the expression
1117684865Sobrien	 is fully defined at the end of the pass over the source file.  */
1117784865Sobrien    case 1: code = BFD_RELOC_8; break;
1117884865Sobrien    case 2: code = BFD_RELOC_16; break;
1117984865Sobrien    case 4:
1118084865Sobrien      if (target_big_endian)
1118184865Sobrien	code = BFD_RELOC_IA64_DIR32MSB;
1118284865Sobrien      else
1118384865Sobrien	code = BFD_RELOC_IA64_DIR32LSB;
1118484865Sobrien      break;
1118584865Sobrien
1118684865Sobrien    case 8:
11187104834Sobrien      /* In 32-bit mode, data8 could mean function descriptors too.  */
1118894536Sobrien      if (exp->X_op == O_pseudo_fixup
11189104834Sobrien	  && exp->X_op_symbol
11190104834Sobrien	  && S_GET_VALUE (exp->X_op_symbol) == FUNC_IPLT_RELOC
11191104834Sobrien	  && !(md.flags & EF_IA_64_ABI64))
11192104834Sobrien	{
11193104834Sobrien	  if (target_big_endian)
11194104834Sobrien	    code = BFD_RELOC_IA64_IPLTMSB;
11195104834Sobrien	  else
11196104834Sobrien	    code = BFD_RELOC_IA64_IPLTLSB;
11197104834Sobrien	  exp->X_op = O_symbol;
11198104834Sobrien	  break;
11199104834Sobrien	}
11200104834Sobrien      else
11201104834Sobrien	{
11202104834Sobrien	  if (target_big_endian)
11203104834Sobrien	    code = BFD_RELOC_IA64_DIR64MSB;
11204104834Sobrien	  else
11205104834Sobrien	    code = BFD_RELOC_IA64_DIR64LSB;
11206104834Sobrien	  break;
11207104834Sobrien	}
1120884865Sobrien
1120989857Sobrien    case 16:
1121089857Sobrien      if (exp->X_op == O_pseudo_fixup
1121189857Sobrien	  && exp->X_op_symbol
1121289857Sobrien	  && S_GET_VALUE (exp->X_op_symbol) == FUNC_IPLT_RELOC)
1121389857Sobrien	{
1121489857Sobrien	  if (target_big_endian)
1121589857Sobrien	    code = BFD_RELOC_IA64_IPLTMSB;
1121689857Sobrien	  else
1121789857Sobrien	    code = BFD_RELOC_IA64_IPLTLSB;
1121889857Sobrien	  exp->X_op = O_symbol;
1121989857Sobrien	  break;
1122089857Sobrien	}
1122189857Sobrien      /* FALLTHRU */
1122289857Sobrien
1122384865Sobrien    default:
1122484865Sobrien      as_bad ("Unsupported fixup size %d", nbytes);
1122584865Sobrien      ignore_rest_of_line ();
1122684865Sobrien      return;
1122784865Sobrien    }
11228130561Sobrien
1122984865Sobrien  if (exp->X_op == O_pseudo_fixup)
1123084865Sobrien    {
1123184865Sobrien      exp->X_op = O_symbol;
1123284865Sobrien      code = ia64_gen_real_reloc_type (exp->X_op_symbol, code);
11233130561Sobrien      /* ??? If code unchanged, unsupported.  */
1123484865Sobrien    }
1123589857Sobrien
1123684865Sobrien  fix = fix_new_exp (f, where, nbytes, exp, 0, code);
1123784865Sobrien  /* We need to store the byte order in effect in case we're going
1123884865Sobrien     to fix an 8 or 16 bit relocation (for which there no real
11239218822Sdim     relocs available).  See md_apply_fix().  */
1124084865Sobrien  fix->tc_fix_data.bigendian = target_big_endian;
1124184865Sobrien}
1124284865Sobrien
1124384865Sobrien/* Return the actual relocation we wish to associate with the pseudo
1124484865Sobrien   reloc described by SYM and R_TYPE.  SYM should be one of the
1124584865Sobrien   symbols in the pseudo_func array, or NULL.  */
1124684865Sobrien
1124784865Sobrienstatic bfd_reloc_code_real_type
1124884865Sobrienia64_gen_real_reloc_type (sym, r_type)
1124984865Sobrien     struct symbol *sym;
1125084865Sobrien     bfd_reloc_code_real_type r_type;
1125184865Sobrien{
1125284865Sobrien  bfd_reloc_code_real_type new = 0;
11253218822Sdim  const char *type = NULL, *suffix = "";
1125484865Sobrien
1125584865Sobrien  if (sym == NULL)
1125684865Sobrien    {
1125784865Sobrien      return r_type;
1125884865Sobrien    }
1125984865Sobrien
1126084865Sobrien  switch (S_GET_VALUE (sym))
1126184865Sobrien    {
1126284865Sobrien    case FUNC_FPTR_RELATIVE:
1126384865Sobrien      switch (r_type)
1126484865Sobrien	{
1126584865Sobrien	case BFD_RELOC_IA64_IMM64:	new = BFD_RELOC_IA64_FPTR64I; break;
1126684865Sobrien	case BFD_RELOC_IA64_DIR32MSB:	new = BFD_RELOC_IA64_FPTR32MSB; break;
1126784865Sobrien	case BFD_RELOC_IA64_DIR32LSB:	new = BFD_RELOC_IA64_FPTR32LSB; break;
1126884865Sobrien	case BFD_RELOC_IA64_DIR64MSB:	new = BFD_RELOC_IA64_FPTR64MSB; break;
1126984865Sobrien	case BFD_RELOC_IA64_DIR64LSB:	new = BFD_RELOC_IA64_FPTR64LSB; break;
11270218822Sdim	default:			type = "FPTR"; break;
1127184865Sobrien	}
1127284865Sobrien      break;
1127384865Sobrien
1127484865Sobrien    case FUNC_GP_RELATIVE:
1127584865Sobrien      switch (r_type)
1127684865Sobrien	{
1127784865Sobrien	case BFD_RELOC_IA64_IMM22:	new = BFD_RELOC_IA64_GPREL22; break;
1127884865Sobrien	case BFD_RELOC_IA64_IMM64:	new = BFD_RELOC_IA64_GPREL64I; break;
1127984865Sobrien	case BFD_RELOC_IA64_DIR32MSB:	new = BFD_RELOC_IA64_GPREL32MSB; break;
1128084865Sobrien	case BFD_RELOC_IA64_DIR32LSB:	new = BFD_RELOC_IA64_GPREL32LSB; break;
1128184865Sobrien	case BFD_RELOC_IA64_DIR64MSB:	new = BFD_RELOC_IA64_GPREL64MSB; break;
1128284865Sobrien	case BFD_RELOC_IA64_DIR64LSB:	new = BFD_RELOC_IA64_GPREL64LSB; break;
11283218822Sdim	default:			type = "GPREL"; break;
1128484865Sobrien	}
1128584865Sobrien      break;
1128684865Sobrien
1128784865Sobrien    case FUNC_LT_RELATIVE:
1128884865Sobrien      switch (r_type)
1128984865Sobrien	{
1129084865Sobrien	case BFD_RELOC_IA64_IMM22:	new = BFD_RELOC_IA64_LTOFF22; break;
1129184865Sobrien	case BFD_RELOC_IA64_IMM64:	new = BFD_RELOC_IA64_LTOFF64I; break;
11292218822Sdim	default:			type = "LTOFF"; break;
1129384865Sobrien	}
1129484865Sobrien      break;
1129584865Sobrien
11296130561Sobrien    case FUNC_LT_RELATIVE_X:
11297130561Sobrien      switch (r_type)
11298130561Sobrien	{
11299130561Sobrien	case BFD_RELOC_IA64_IMM22:	new = BFD_RELOC_IA64_LTOFF22X; break;
11300218822Sdim	default:			type = "LTOFF"; suffix = "X"; break;
11301130561Sobrien	}
11302130561Sobrien      break;
11303130561Sobrien
1130484865Sobrien    case FUNC_PC_RELATIVE:
1130584865Sobrien      switch (r_type)
1130684865Sobrien	{
1130784865Sobrien	case BFD_RELOC_IA64_IMM22:	new = BFD_RELOC_IA64_PCREL22; break;
1130884865Sobrien	case BFD_RELOC_IA64_IMM64:	new = BFD_RELOC_IA64_PCREL64I; break;
1130984865Sobrien	case BFD_RELOC_IA64_DIR32MSB:	new = BFD_RELOC_IA64_PCREL32MSB; break;
1131084865Sobrien	case BFD_RELOC_IA64_DIR32LSB:	new = BFD_RELOC_IA64_PCREL32LSB; break;
1131184865Sobrien	case BFD_RELOC_IA64_DIR64MSB:	new = BFD_RELOC_IA64_PCREL64MSB; break;
1131284865Sobrien	case BFD_RELOC_IA64_DIR64LSB:	new = BFD_RELOC_IA64_PCREL64LSB; break;
11313218822Sdim	default:			type = "PCREL"; break;
1131484865Sobrien	}
1131584865Sobrien      break;
1131684865Sobrien
1131784865Sobrien    case FUNC_PLT_RELATIVE:
1131884865Sobrien      switch (r_type)
1131984865Sobrien	{
1132084865Sobrien	case BFD_RELOC_IA64_IMM22:	new = BFD_RELOC_IA64_PLTOFF22; break;
1132184865Sobrien	case BFD_RELOC_IA64_IMM64:	new = BFD_RELOC_IA64_PLTOFF64I; break;
1132284865Sobrien	case BFD_RELOC_IA64_DIR64MSB:	new = BFD_RELOC_IA64_PLTOFF64MSB;break;
1132384865Sobrien	case BFD_RELOC_IA64_DIR64LSB:	new = BFD_RELOC_IA64_PLTOFF64LSB;break;
11324218822Sdim	default:			type = "PLTOFF"; break;
1132584865Sobrien	}
1132684865Sobrien      break;
1132784865Sobrien
1132884865Sobrien    case FUNC_SEC_RELATIVE:
1132984865Sobrien      switch (r_type)
1133084865Sobrien	{
1133184865Sobrien	case BFD_RELOC_IA64_DIR32MSB:	new = BFD_RELOC_IA64_SECREL32MSB;break;
1133284865Sobrien	case BFD_RELOC_IA64_DIR32LSB:	new = BFD_RELOC_IA64_SECREL32LSB;break;
1133384865Sobrien	case BFD_RELOC_IA64_DIR64MSB:	new = BFD_RELOC_IA64_SECREL64MSB;break;
1133484865Sobrien	case BFD_RELOC_IA64_DIR64LSB:	new = BFD_RELOC_IA64_SECREL64LSB;break;
11335218822Sdim	default:			type = "SECREL"; break;
1133684865Sobrien	}
1133784865Sobrien      break;
1133884865Sobrien
1133984865Sobrien    case FUNC_SEG_RELATIVE:
1134084865Sobrien      switch (r_type)
1134184865Sobrien	{
1134284865Sobrien	case BFD_RELOC_IA64_DIR32MSB:	new = BFD_RELOC_IA64_SEGREL32MSB;break;
1134384865Sobrien	case BFD_RELOC_IA64_DIR32LSB:	new = BFD_RELOC_IA64_SEGREL32LSB;break;
1134484865Sobrien	case BFD_RELOC_IA64_DIR64MSB:	new = BFD_RELOC_IA64_SEGREL64MSB;break;
1134584865Sobrien	case BFD_RELOC_IA64_DIR64LSB:	new = BFD_RELOC_IA64_SEGREL64LSB;break;
11346218822Sdim	default:			type = "SEGREL"; break;
1134784865Sobrien	}
1134884865Sobrien      break;
1134984865Sobrien
1135084865Sobrien    case FUNC_LTV_RELATIVE:
1135184865Sobrien      switch (r_type)
1135284865Sobrien	{
1135384865Sobrien	case BFD_RELOC_IA64_DIR32MSB:	new = BFD_RELOC_IA64_LTV32MSB; break;
1135484865Sobrien	case BFD_RELOC_IA64_DIR32LSB:	new = BFD_RELOC_IA64_LTV32LSB; break;
1135584865Sobrien	case BFD_RELOC_IA64_DIR64MSB:	new = BFD_RELOC_IA64_LTV64MSB; break;
1135684865Sobrien	case BFD_RELOC_IA64_DIR64LSB:	new = BFD_RELOC_IA64_LTV64LSB; break;
11357218822Sdim	default:			type = "LTV"; break;
1135884865Sobrien	}
1135984865Sobrien      break;
1136084865Sobrien
1136184865Sobrien    case FUNC_LT_FPTR_RELATIVE:
1136284865Sobrien      switch (r_type)
1136384865Sobrien	{
1136484865Sobrien	case BFD_RELOC_IA64_IMM22:
1136584865Sobrien	  new = BFD_RELOC_IA64_LTOFF_FPTR22; break;
1136684865Sobrien	case BFD_RELOC_IA64_IMM64:
1136784865Sobrien	  new = BFD_RELOC_IA64_LTOFF_FPTR64I; break;
11368218822Sdim	case BFD_RELOC_IA64_DIR32MSB:
11369218822Sdim	  new = BFD_RELOC_IA64_LTOFF_FPTR32MSB; break;
11370218822Sdim	case BFD_RELOC_IA64_DIR32LSB:
11371218822Sdim	  new = BFD_RELOC_IA64_LTOFF_FPTR32LSB; break;
11372218822Sdim	case BFD_RELOC_IA64_DIR64MSB:
11373218822Sdim	  new = BFD_RELOC_IA64_LTOFF_FPTR64MSB; break;
11374218822Sdim	case BFD_RELOC_IA64_DIR64LSB:
11375218822Sdim	  new = BFD_RELOC_IA64_LTOFF_FPTR64LSB; break;
1137684865Sobrien	default:
11377218822Sdim	  type = "LTOFF_FPTR"; break;
1137884865Sobrien	}
1137984865Sobrien      break;
1138089857Sobrien
11381104834Sobrien    case FUNC_TP_RELATIVE:
11382104834Sobrien      switch (r_type)
11383104834Sobrien	{
11384218822Sdim	case BFD_RELOC_IA64_IMM14:      new = BFD_RELOC_IA64_TPREL14; break;
11385218822Sdim	case BFD_RELOC_IA64_IMM22:      new = BFD_RELOC_IA64_TPREL22; break;
11386218822Sdim	case BFD_RELOC_IA64_IMM64:      new = BFD_RELOC_IA64_TPREL64I; break;
11387218822Sdim	case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_TPREL64MSB; break;
11388218822Sdim	case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_TPREL64LSB; break;
11389218822Sdim	default:                        type = "TPREL"; break;
11390104834Sobrien	}
11391104834Sobrien      break;
1139289857Sobrien
11393104834Sobrien    case FUNC_LT_TP_RELATIVE:
11394104834Sobrien      switch (r_type)
11395104834Sobrien	{
11396104834Sobrien	case BFD_RELOC_IA64_IMM22:
11397104834Sobrien	  new = BFD_RELOC_IA64_LTOFF_TPREL22; break;
11398104834Sobrien	default:
11399218822Sdim	  type = "LTOFF_TPREL"; break;
11400104834Sobrien	}
11401104834Sobrien      break;
11402104834Sobrien
11403218822Sdim    case FUNC_DTP_MODULE:
11404218822Sdim      switch (r_type)
11405218822Sdim	{
11406218822Sdim	case BFD_RELOC_IA64_DIR64MSB:
11407218822Sdim	  new = BFD_RELOC_IA64_DTPMOD64MSB; break;
11408218822Sdim	case BFD_RELOC_IA64_DIR64LSB:
11409218822Sdim	  new = BFD_RELOC_IA64_DTPMOD64LSB; break;
11410218822Sdim	default:
11411218822Sdim	  type = "DTPMOD"; break;
11412218822Sdim	}
11413218822Sdim      break;
11414218822Sdim
11415104834Sobrien    case FUNC_LT_DTP_MODULE:
11416104834Sobrien      switch (r_type)
11417104834Sobrien	{
11418104834Sobrien	case BFD_RELOC_IA64_IMM22:
11419104834Sobrien	  new = BFD_RELOC_IA64_LTOFF_DTPMOD22; break;
11420104834Sobrien	default:
11421218822Sdim	  type = "LTOFF_DTPMOD"; break;
11422104834Sobrien	}
11423104834Sobrien      break;
11424104834Sobrien
11425104834Sobrien    case FUNC_DTP_RELATIVE:
11426104834Sobrien      switch (r_type)
11427104834Sobrien	{
11428218822Sdim	case BFD_RELOC_IA64_DIR32MSB:
11429218822Sdim	  new = BFD_RELOC_IA64_DTPREL32MSB; break;
11430218822Sdim	case BFD_RELOC_IA64_DIR32LSB:
11431218822Sdim	  new = BFD_RELOC_IA64_DTPREL32LSB; break;
11432130561Sobrien	case BFD_RELOC_IA64_DIR64MSB:
11433130561Sobrien	  new = BFD_RELOC_IA64_DTPREL64MSB; break;
11434130561Sobrien	case BFD_RELOC_IA64_DIR64LSB:
11435130561Sobrien	  new = BFD_RELOC_IA64_DTPREL64LSB; break;
11436104834Sobrien	case BFD_RELOC_IA64_IMM14:
11437104834Sobrien	  new = BFD_RELOC_IA64_DTPREL14; break;
11438104834Sobrien	case BFD_RELOC_IA64_IMM22:
11439104834Sobrien	  new = BFD_RELOC_IA64_DTPREL22; break;
11440104834Sobrien	case BFD_RELOC_IA64_IMM64:
11441104834Sobrien	  new = BFD_RELOC_IA64_DTPREL64I; break;
11442104834Sobrien	default:
11443218822Sdim	  type = "DTPREL"; break;
11444104834Sobrien	}
11445104834Sobrien      break;
11446104834Sobrien
11447104834Sobrien    case FUNC_LT_DTP_RELATIVE:
11448104834Sobrien      switch (r_type)
11449104834Sobrien	{
11450104834Sobrien	case BFD_RELOC_IA64_IMM22:
11451104834Sobrien	  new = BFD_RELOC_IA64_LTOFF_DTPREL22; break;
11452104834Sobrien	default:
11453218822Sdim	  type = "LTOFF_DTPREL"; break;
11454104834Sobrien	}
11455104834Sobrien      break;
11456104834Sobrien
11457104834Sobrien    case FUNC_IPLT_RELOC:
11458218822Sdim      switch (r_type)
11459218822Sdim	{
11460218822Sdim	case BFD_RELOC_IA64_IPLTMSB:    return r_type;
11461218822Sdim	case BFD_RELOC_IA64_IPLTLSB:    return r_type;
11462218822Sdim	default:                        type = "IPLT"; break;
11463218822Sdim	}
11464104834Sobrien      break;
11465104834Sobrien
1146684865Sobrien    default:
1146784865Sobrien      abort ();
1146884865Sobrien    }
11469130561Sobrien
1147084865Sobrien  if (new)
1147184865Sobrien    return new;
1147284865Sobrien  else
11473218822Sdim    {
11474218822Sdim      int width;
11475218822Sdim
11476218822Sdim      if (!type)
11477218822Sdim	abort ();
11478218822Sdim      switch (r_type)
11479218822Sdim	{
11480218822Sdim	case BFD_RELOC_IA64_DIR32MSB: width = 32; suffix = "MSB"; break;
11481218822Sdim	case BFD_RELOC_IA64_DIR32LSB: width = 32; suffix = "LSB"; break;
11482218822Sdim	case BFD_RELOC_IA64_DIR64MSB: width = 64; suffix = "MSB"; break;
11483218822Sdim	case BFD_RELOC_IA64_DIR64LSB: width = 64; suffix = "LSB"; break;
11484218822Sdim	case BFD_RELOC_UNUSED:        width = 13; break;
11485218822Sdim	case BFD_RELOC_IA64_IMM14:    width = 14; break;
11486218822Sdim	case BFD_RELOC_IA64_IMM22:    width = 22; break;
11487218822Sdim	case BFD_RELOC_IA64_IMM64:    width = 64; suffix = "I"; break;
11488218822Sdim	default:                      abort ();
11489218822Sdim	}
11490218822Sdim
11491218822Sdim      /* This should be an error, but since previously there wasn't any
11492218822Sdim	 diagnostic here, dont't make it fail because of this for now.  */
11493218822Sdim      as_warn ("Cannot express %s%d%s relocation", type, width, suffix);
11494218822Sdim      return r_type;
11495218822Sdim    }
1149684865Sobrien}
1149784865Sobrien
1149884865Sobrien/* Here is where generate the appropriate reloc for pseudo relocation
1149984865Sobrien   functions.  */
1150084865Sobrienvoid
1150184865Sobrienia64_validate_fix (fix)
1150284865Sobrien     fixS *fix;
1150384865Sobrien{
1150484865Sobrien  switch (fix->fx_r_type)
1150584865Sobrien    {
1150684865Sobrien    case BFD_RELOC_IA64_FPTR64I:
1150784865Sobrien    case BFD_RELOC_IA64_FPTR32MSB:
1150884865Sobrien    case BFD_RELOC_IA64_FPTR64LSB:
1150984865Sobrien    case BFD_RELOC_IA64_LTOFF_FPTR22:
1151084865Sobrien    case BFD_RELOC_IA64_LTOFF_FPTR64I:
1151184865Sobrien      if (fix->fx_offset != 0)
1151284865Sobrien	as_bad_where (fix->fx_file, fix->fx_line,
1151384865Sobrien		      "No addend allowed in @fptr() relocation");
1151484865Sobrien      break;
1151584865Sobrien    default:
1151684865Sobrien      break;
1151784865Sobrien    }
1151884865Sobrien}
1151984865Sobrien
1152084865Sobrienstatic void
1152184865Sobrienfix_insn (fix, odesc, value)
1152284865Sobrien     fixS *fix;
1152384865Sobrien     const struct ia64_operand *odesc;
1152484865Sobrien     valueT value;
1152584865Sobrien{
1152684865Sobrien  bfd_vma insn[3], t0, t1, control_bits;
1152784865Sobrien  const char *err;
1152884865Sobrien  char *fixpos;
1152984865Sobrien  long slot;
1153084865Sobrien
1153184865Sobrien  slot = fix->fx_where & 0x3;
1153284865Sobrien  fixpos = fix->fx_frag->fr_literal + (fix->fx_where - slot);
1153384865Sobrien
1153484865Sobrien  /* Bundles are always in little-endian byte order */
1153584865Sobrien  t0 = bfd_getl64 (fixpos);
1153684865Sobrien  t1 = bfd_getl64 (fixpos + 8);
1153784865Sobrien  control_bits = t0 & 0x1f;
1153884865Sobrien  insn[0] = (t0 >>  5) & 0x1ffffffffffLL;
1153984865Sobrien  insn[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18);
1154084865Sobrien  insn[2] = (t1 >> 23) & 0x1ffffffffffLL;
1154184865Sobrien
1154284865Sobrien  err = NULL;
1154384865Sobrien  if (odesc - elf64_ia64_operands == IA64_OPND_IMMU64)
1154484865Sobrien    {
1154584865Sobrien      insn[1] = (value >> 22) & 0x1ffffffffffLL;
1154684865Sobrien      insn[2] |= (((value & 0x7f) << 13)
1154784865Sobrien		  | (((value >> 7) & 0x1ff) << 27)
1154884865Sobrien		  | (((value >> 16) & 0x1f) << 22)
1154984865Sobrien		  | (((value >> 21) & 0x1) << 21)
1155084865Sobrien		  | (((value >> 63) & 0x1) << 36));
1155184865Sobrien    }
1155284865Sobrien  else if (odesc - elf64_ia64_operands == IA64_OPND_IMMU62)
1155384865Sobrien    {
1155484865Sobrien      if (value & ~0x3fffffffffffffffULL)
1155584865Sobrien	err = "integer operand out of range";
1155684865Sobrien      insn[1] = (value >> 21) & 0x1ffffffffffLL;
1155784865Sobrien      insn[2] |= (((value & 0xfffff) << 6) | (((value >> 20) & 0x1) << 36));
1155884865Sobrien    }
1155984865Sobrien  else if (odesc - elf64_ia64_operands == IA64_OPND_TGT64)
1156084865Sobrien    {
1156184865Sobrien      value >>= 4;
1156284865Sobrien      insn[1] = ((value >> 20) & 0x7fffffffffLL) << 2;
1156384865Sobrien      insn[2] |= ((((value >> 59) & 0x1) << 36)
1156484865Sobrien		  | (((value >> 0) & 0xfffff) << 13));
1156584865Sobrien    }
1156684865Sobrien  else
1156784865Sobrien    err = (*odesc->insert) (odesc, value, insn + slot);
1156884865Sobrien
1156984865Sobrien  if (err)
1157084865Sobrien    as_bad_where (fix->fx_file, fix->fx_line, err);
1157184865Sobrien
1157284865Sobrien  t0 = control_bits | (insn[0] << 5) | (insn[1] << 46);
1157384865Sobrien  t1 = ((insn[1] >> 18) & 0x7fffff) | (insn[2] << 23);
1157484865Sobrien  number_to_chars_littleendian (fixpos + 0, t0, 8);
1157584865Sobrien  number_to_chars_littleendian (fixpos + 8, t1, 8);
1157684865Sobrien}
1157784865Sobrien
1157884865Sobrien/* Attempt to simplify or even eliminate a fixup.  The return value is
1157984865Sobrien   ignored; perhaps it was once meaningful, but now it is historical.
1158084865Sobrien   To indicate that a fixup has been eliminated, set FIXP->FX_DONE.
1158184865Sobrien
1158284865Sobrien   If fixp->fx_addsy is non-NULL, we'll have to generate a reloc entry
1158384865Sobrien   (if possible).  */
1158489857Sobrien
1158589857Sobrienvoid
11586218822Sdimmd_apply_fix (fix, valP, seg)
1158784865Sobrien     fixS *fix;
11588104834Sobrien     valueT *valP;
1158984865Sobrien     segT seg ATTRIBUTE_UNUSED;
1159084865Sobrien{
1159184865Sobrien  char *fixpos;
11592104834Sobrien  valueT value = *valP;
1159384865Sobrien
1159484865Sobrien  fixpos = fix->fx_frag->fr_literal + fix->fx_where;
1159584865Sobrien
1159684865Sobrien  if (fix->fx_pcrel)
1159784865Sobrien    {
11598218822Sdim    switch (fix->fx_r_type)
11599218822Sdim      {
11600218822Sdim      case BFD_RELOC_IA64_PCREL21B: break;
11601218822Sdim      case BFD_RELOC_IA64_PCREL21BI: break;
11602218822Sdim      case BFD_RELOC_IA64_PCREL21F: break;
11603218822Sdim      case BFD_RELOC_IA64_PCREL21M: break;
11604218822Sdim      case BFD_RELOC_IA64_PCREL60B: break;
11605218822Sdim      case BFD_RELOC_IA64_PCREL22: break;
11606218822Sdim      case BFD_RELOC_IA64_PCREL64I: break;
11607218822Sdim      case BFD_RELOC_IA64_PCREL32MSB: break;
11608218822Sdim      case BFD_RELOC_IA64_PCREL32LSB: break;
11609218822Sdim      case BFD_RELOC_IA64_PCREL64MSB: break;
11610218822Sdim      case BFD_RELOC_IA64_PCREL64LSB: break;
11611218822Sdim      default:
11612218822Sdim	fix->fx_r_type = ia64_gen_real_reloc_type (pseudo_func[FUNC_PC_RELATIVE].u.sym,
11613218822Sdim					       fix->fx_r_type);
11614218822Sdim	break;
11615218822Sdim      }
1161684865Sobrien    }
1161784865Sobrien  if (fix->fx_addsy)
1161884865Sobrien    {
11619130561Sobrien      switch (fix->fx_r_type)
1162084865Sobrien	{
11621130561Sobrien	case BFD_RELOC_UNUSED:
1162289857Sobrien	  /* This must be a TAG13 or TAG13b operand.  There are no external
1162389857Sobrien	     relocs defined for them, so we must give an error.  */
1162484865Sobrien	  as_bad_where (fix->fx_file, fix->fx_line,
1162584865Sobrien			"%s must have a constant value",
1162684865Sobrien			elf64_ia64_operands[fix->tc_fix_data.opnd].desc);
1162789857Sobrien	  fix->fx_done = 1;
1162889857Sobrien	  return;
11629130561Sobrien
11630130561Sobrien	case BFD_RELOC_IA64_TPREL14:
11631130561Sobrien	case BFD_RELOC_IA64_TPREL22:
11632130561Sobrien	case BFD_RELOC_IA64_TPREL64I:
11633130561Sobrien	case BFD_RELOC_IA64_LTOFF_TPREL22:
11634130561Sobrien	case BFD_RELOC_IA64_LTOFF_DTPMOD22:
11635130561Sobrien	case BFD_RELOC_IA64_DTPREL14:
11636130561Sobrien	case BFD_RELOC_IA64_DTPREL22:
11637130561Sobrien	case BFD_RELOC_IA64_DTPREL64I:
11638130561Sobrien	case BFD_RELOC_IA64_LTOFF_DTPREL22:
11639130561Sobrien	  S_SET_THREAD_LOCAL (fix->fx_addsy);
11640130561Sobrien	  break;
11641130561Sobrien
11642130561Sobrien	default:
11643130561Sobrien	  break;
1164484865Sobrien	}
1164584865Sobrien    }
1164684865Sobrien  else if (fix->tc_fix_data.opnd == IA64_OPND_NIL)
1164784865Sobrien    {
1164884865Sobrien      if (fix->tc_fix_data.bigendian)
1164984865Sobrien	number_to_chars_bigendian (fixpos, value, fix->fx_size);
1165084865Sobrien      else
1165184865Sobrien	number_to_chars_littleendian (fixpos, value, fix->fx_size);
1165284865Sobrien      fix->fx_done = 1;
1165384865Sobrien    }
1165484865Sobrien  else
1165584865Sobrien    {
1165684865Sobrien      fix_insn (fix, elf64_ia64_operands + fix->tc_fix_data.opnd, value);
1165784865Sobrien      fix->fx_done = 1;
1165884865Sobrien    }
1165984865Sobrien}
1166084865Sobrien
1166184865Sobrien/* Generate the BFD reloc to be stuck in the object file from the
1166284865Sobrien   fixup used internally in the assembler.  */
1166384865Sobrien
1166484865Sobrienarelent *
1166584865Sobrientc_gen_reloc (sec, fixp)
1166684865Sobrien     asection *sec ATTRIBUTE_UNUSED;
1166784865Sobrien     fixS *fixp;
1166884865Sobrien{
1166984865Sobrien  arelent *reloc;
1167084865Sobrien
1167184865Sobrien  reloc = xmalloc (sizeof (*reloc));
1167284865Sobrien  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
1167384865Sobrien  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1167484865Sobrien  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1167584865Sobrien  reloc->addend = fixp->fx_offset;
1167684865Sobrien  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
1167784865Sobrien
1167884865Sobrien  if (!reloc->howto)
1167984865Sobrien    {
1168084865Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1168184865Sobrien		    "Cannot represent %s relocation in object file",
1168284865Sobrien		    bfd_get_reloc_code_name (fixp->fx_r_type));
1168384865Sobrien    }
1168484865Sobrien  return reloc;
1168584865Sobrien}
1168684865Sobrien
1168784865Sobrien/* Turn a string in input_line_pointer into a floating point constant
1168884865Sobrien   of type TYPE, and store the appropriate bytes in *LIT.  The number
1168984865Sobrien   of LITTLENUMS emitted is stored in *SIZE.  An error message is
1169084865Sobrien   returned, or NULL on OK.  */
1169184865Sobrien
1169284865Sobrien#define MAX_LITTLENUMS 5
1169384865Sobrien
1169484865Sobrienchar *
1169584865Sobrienmd_atof (type, lit, size)
1169684865Sobrien     int type;
1169784865Sobrien     char *lit;
1169884865Sobrien     int *size;
1169984865Sobrien{
1170084865Sobrien  LITTLENUM_TYPE words[MAX_LITTLENUMS];
1170184865Sobrien  char *t;
1170284865Sobrien  int prec;
1170384865Sobrien
1170484865Sobrien  switch (type)
1170584865Sobrien    {
1170684865Sobrien      /* IEEE floats */
1170784865Sobrien    case 'f':
1170884865Sobrien    case 'F':
1170984865Sobrien    case 's':
1171084865Sobrien    case 'S':
1171184865Sobrien      prec = 2;
1171284865Sobrien      break;
1171384865Sobrien
1171484865Sobrien    case 'd':
1171584865Sobrien    case 'D':
1171684865Sobrien    case 'r':
1171784865Sobrien    case 'R':
1171884865Sobrien      prec = 4;
1171984865Sobrien      break;
1172084865Sobrien
1172184865Sobrien    case 'x':
1172284865Sobrien    case 'X':
1172384865Sobrien    case 'p':
1172484865Sobrien    case 'P':
1172584865Sobrien      prec = 5;
1172684865Sobrien      break;
1172784865Sobrien
1172884865Sobrien    default:
1172984865Sobrien      *size = 0;
1173084865Sobrien      return "Bad call to MD_ATOF()";
1173184865Sobrien    }
1173284865Sobrien  t = atof_ieee (input_line_pointer, type, words);
1173384865Sobrien  if (t)
1173484865Sobrien    input_line_pointer = t;
1173584865Sobrien
11736130561Sobrien  (*ia64_float_to_chars) (lit, words, prec);
11737130561Sobrien
11738130561Sobrien  if (type == 'X')
1173984865Sobrien    {
11740130561Sobrien      /* It is 10 byte floating point with 6 byte padding.  */
11741130561Sobrien      memset (&lit [10], 0, 6);
11742130561Sobrien      *size = 8 * sizeof (LITTLENUM_TYPE);
1174384865Sobrien    }
11744130561Sobrien  else
11745130561Sobrien    *size = prec * sizeof (LITTLENUM_TYPE);
11746130561Sobrien
1174784865Sobrien  return 0;
1174884865Sobrien}
1174984865Sobrien
1175084865Sobrien/* Handle ia64 specific semantics of the align directive.  */
1175184865Sobrien
1175284865Sobrienvoid
1175384865Sobrienia64_md_do_align (n, fill, len, max)
1175484865Sobrien     int n ATTRIBUTE_UNUSED;
1175584865Sobrien     const char *fill ATTRIBUTE_UNUSED;
1175684865Sobrien     int len ATTRIBUTE_UNUSED;
1175784865Sobrien     int max ATTRIBUTE_UNUSED;
1175884865Sobrien{
1175984865Sobrien  if (subseg_text_p (now_seg))
1176084865Sobrien    ia64_flush_insns ();
1176184865Sobrien}
1176284865Sobrien
1176384865Sobrien/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
1176484865Sobrien   of an rs_align_code fragment.  */
1176584865Sobrien
1176684865Sobrienvoid
1176784865Sobrienia64_handle_align (fragp)
1176884865Sobrien     fragS *fragp;
1176984865Sobrien{
1177084865Sobrien  int bytes;
1177184865Sobrien  char *p;
11772130561Sobrien  const unsigned char *nop;
1177384865Sobrien
1177484865Sobrien  if (fragp->fr_type != rs_align_code)
1177584865Sobrien    return;
1177684865Sobrien
11777130561Sobrien  /* Check if this frag has to end with a stop bit.  */
11778130561Sobrien  nop = fragp->tc_frag_data ? le_nop_stop : le_nop;
11779130561Sobrien
1178084865Sobrien  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
1178184865Sobrien  p = fragp->fr_literal + fragp->fr_fix;
1178284865Sobrien
11783130561Sobrien  /* If no paddings are needed, we check if we need a stop bit.  */
11784130561Sobrien  if (!bytes && fragp->tc_frag_data)
11785130561Sobrien    {
11786130561Sobrien      if (fragp->fr_fix < 16)
11787130561Sobrien#if 1
11788130561Sobrien	/* FIXME: It won't work with
11789130561Sobrien	   .align 16
11790130561Sobrien	   alloc r32=ar.pfs,1,2,4,0
11791130561Sobrien	 */
11792130561Sobrien	;
11793130561Sobrien#else
11794130561Sobrien	as_bad_where (fragp->fr_file, fragp->fr_line,
11795130561Sobrien		      _("Can't add stop bit to mark end of instruction group"));
11796130561Sobrien#endif
11797130561Sobrien      else
11798130561Sobrien	/* Bundles are always in little-endian byte order. Make sure
11799130561Sobrien	   the previous bundle has the stop bit.  */
11800130561Sobrien	*(p - 16) |= 1;
11801130561Sobrien    }
11802130561Sobrien
1180384865Sobrien  /* Make sure we are on a 16-byte boundary, in case someone has been
1180484865Sobrien     putting data into a text section.  */
1180584865Sobrien  if (bytes & 15)
1180684865Sobrien    {
1180784865Sobrien      int fix = bytes & 15;
1180884865Sobrien      memset (p, 0, fix);
1180984865Sobrien      p += fix;
1181084865Sobrien      bytes -= fix;
1181184865Sobrien      fragp->fr_fix += fix;
1181284865Sobrien    }
1181384865Sobrien
11814130561Sobrien  /* Instruction bundles are always little-endian.  */
11815130561Sobrien  memcpy (p, nop, 16);
1181684865Sobrien  fragp->fr_var = 16;
1181784865Sobrien}
11818130561Sobrien
11819130561Sobrienstatic void
11820130561Sobrienia64_float_to_chars_bigendian (char *lit, LITTLENUM_TYPE *words,
11821130561Sobrien			       int prec)
11822130561Sobrien{
11823130561Sobrien  while (prec--)
11824130561Sobrien    {
11825130561Sobrien      number_to_chars_bigendian (lit, (long) (*words++),
11826130561Sobrien				 sizeof (LITTLENUM_TYPE));
11827130561Sobrien      lit += sizeof (LITTLENUM_TYPE);
11828130561Sobrien    }
11829130561Sobrien}
11830130561Sobrien
11831130561Sobrienstatic void
11832130561Sobrienia64_float_to_chars_littleendian (char *lit, LITTLENUM_TYPE *words,
11833130561Sobrien				  int prec)
11834130561Sobrien{
11835130561Sobrien  while (prec--)
11836130561Sobrien    {
11837130561Sobrien      number_to_chars_littleendian (lit, (long) (words[prec]),
11838130561Sobrien				    sizeof (LITTLENUM_TYPE));
11839130561Sobrien      lit += sizeof (LITTLENUM_TYPE);
11840130561Sobrien    }
11841130561Sobrien}
11842130561Sobrien
11843130561Sobrienvoid
11844130561Sobrienia64_elf_section_change_hook  (void)
11845130561Sobrien{
11846218822Sdim  if (elf_section_type (now_seg) == SHT_IA_64_UNWIND
11847218822Sdim      && elf_linked_to_section (now_seg) == NULL)
11848218822Sdim    elf_linked_to_section (now_seg) = text_section;
11849130561Sobrien  dot_byteorder (-1);
11850130561Sobrien}
11851130561Sobrien
11852130561Sobrien/* Check if a label should be made global.  */
11853130561Sobrienvoid
11854130561Sobrienia64_check_label (symbolS *label)
11855130561Sobrien{
11856130561Sobrien  if (*input_line_pointer == ':')
11857130561Sobrien    {
11858130561Sobrien      S_SET_EXTERNAL (label);
11859130561Sobrien      input_line_pointer++;
11860130561Sobrien    }
11861130561Sobrien}
11862130561Sobrien
11863130561Sobrien/* Used to remember where .alias and .secalias directives are seen. We
11864130561Sobrien   will rename symbol and section names when we are about to output
11865130561Sobrien   the relocatable file.  */
11866130561Sobrienstruct alias
11867130561Sobrien{
11868130561Sobrien  char *file;		/* The file where the directive is seen.  */
11869130561Sobrien  unsigned int line;	/* The line number the directive is at.  */
11870218822Sdim  const char *name;	/* The original name of the symbol.  */
11871130561Sobrien};
11872130561Sobrien
11873130561Sobrien/* Called for .alias and .secalias directives. If SECTION is 1, it is
11874130561Sobrien   .secalias. Otherwise, it is .alias.  */
11875130561Sobrienstatic void
11876130561Sobriendot_alias (int section)
11877130561Sobrien{
11878130561Sobrien  char *name, *alias;
11879130561Sobrien  char delim;
11880130561Sobrien  char *end_name;
11881130561Sobrien  int len;
11882130561Sobrien  const char *error_string;
11883130561Sobrien  struct alias *h;
11884130561Sobrien  const char *a;
11885130561Sobrien  struct hash_control *ahash, *nhash;
11886130561Sobrien  const char *kind;
11887130561Sobrien
11888130561Sobrien  name = input_line_pointer;
11889130561Sobrien  delim = get_symbol_end ();
11890130561Sobrien  end_name = input_line_pointer;
11891130561Sobrien  *end_name = delim;
11892130561Sobrien
11893130561Sobrien  if (name == end_name)
11894130561Sobrien    {
11895130561Sobrien      as_bad (_("expected symbol name"));
11896218822Sdim      ignore_rest_of_line ();
11897130561Sobrien      return;
11898130561Sobrien    }
11899130561Sobrien
11900130561Sobrien  SKIP_WHITESPACE ();
11901130561Sobrien
11902130561Sobrien  if (*input_line_pointer != ',')
11903130561Sobrien    {
11904130561Sobrien      *end_name = 0;
11905130561Sobrien      as_bad (_("expected comma after \"%s\""), name);
11906130561Sobrien      *end_name = delim;
11907130561Sobrien      ignore_rest_of_line ();
11908130561Sobrien      return;
11909130561Sobrien    }
11910130561Sobrien
11911130561Sobrien  input_line_pointer++;
11912130561Sobrien  *end_name = 0;
11913218822Sdim  ia64_canonicalize_symbol_name (name);
11914130561Sobrien
11915130561Sobrien  /* We call demand_copy_C_string to check if alias string is valid.
11916130561Sobrien     There should be a closing `"' and no `\0' in the string.  */
11917130561Sobrien  alias = demand_copy_C_string (&len);
11918130561Sobrien  if (alias == NULL)
11919130561Sobrien    {
11920130561Sobrien      ignore_rest_of_line ();
11921130561Sobrien      return;
11922130561Sobrien    }
11923130561Sobrien
11924130561Sobrien  /* Make a copy of name string.  */
11925130561Sobrien  len = strlen (name) + 1;
11926130561Sobrien  obstack_grow (&notes, name, len);
11927130561Sobrien  name = obstack_finish (&notes);
11928130561Sobrien
11929130561Sobrien  if (section)
11930130561Sobrien    {
11931130561Sobrien      kind = "section";
11932130561Sobrien      ahash = secalias_hash;
11933130561Sobrien      nhash = secalias_name_hash;
11934130561Sobrien    }
11935130561Sobrien  else
11936130561Sobrien    {
11937130561Sobrien      kind = "symbol";
11938130561Sobrien      ahash = alias_hash;
11939130561Sobrien      nhash = alias_name_hash;
11940130561Sobrien    }
11941130561Sobrien
11942130561Sobrien  /* Check if alias has been used before.  */
11943130561Sobrien  h = (struct alias *) hash_find (ahash, alias);
11944130561Sobrien  if (h)
11945130561Sobrien    {
11946130561Sobrien      if (strcmp (h->name, name))
11947130561Sobrien	as_bad (_("`%s' is already the alias of %s `%s'"),
11948130561Sobrien		alias, kind, h->name);
11949130561Sobrien      goto out;
11950130561Sobrien    }
11951130561Sobrien
11952130561Sobrien  /* Check if name already has an alias.  */
11953130561Sobrien  a = (const char *) hash_find (nhash, name);
11954130561Sobrien  if (a)
11955130561Sobrien    {
11956130561Sobrien      if (strcmp (a, alias))
11957130561Sobrien	as_bad (_("%s `%s' already has an alias `%s'"), kind, name, a);
11958130561Sobrien      goto out;
11959130561Sobrien    }
11960130561Sobrien
11961130561Sobrien  h = (struct alias *) xmalloc (sizeof (struct alias));
11962130561Sobrien  as_where (&h->file, &h->line);
11963130561Sobrien  h->name = name;
11964130561Sobrien
11965130561Sobrien  error_string = hash_jam (ahash, alias, (PTR) h);
11966130561Sobrien  if (error_string)
11967130561Sobrien    {
11968130561Sobrien      as_fatal (_("inserting \"%s\" into %s alias hash table failed: %s"),
11969130561Sobrien		alias, kind, error_string);
11970130561Sobrien      goto out;
11971130561Sobrien    }
11972130561Sobrien
11973130561Sobrien  error_string = hash_jam (nhash, name, (PTR) alias);
11974130561Sobrien  if (error_string)
11975130561Sobrien    {
11976130561Sobrien      as_fatal (_("inserting \"%s\" into %s name hash table failed: %s"),
11977130561Sobrien		alias, kind, error_string);
11978130561Sobrienout:
11979130561Sobrien      obstack_free (&notes, name);
11980130561Sobrien      obstack_free (&notes, alias);
11981130561Sobrien    }
11982130561Sobrien
11983130561Sobrien  demand_empty_rest_of_line ();
11984130561Sobrien}
11985130561Sobrien
11986130561Sobrien/* It renames the original symbol name to its alias.  */
11987130561Sobrienstatic void
11988130561Sobriendo_alias (const char *alias, PTR value)
11989130561Sobrien{
11990130561Sobrien  struct alias *h = (struct alias *) value;
11991130561Sobrien  symbolS *sym = symbol_find (h->name);
11992130561Sobrien
11993130561Sobrien  if (sym == NULL)
11994130561Sobrien    as_warn_where (h->file, h->line,
11995130561Sobrien		   _("symbol `%s' aliased to `%s' is not used"),
11996130561Sobrien		   h->name, alias);
11997130561Sobrien    else
11998130561Sobrien      S_SET_NAME (sym, (char *) alias);
11999130561Sobrien}
12000130561Sobrien
12001130561Sobrien/* Called from write_object_file.  */
12002130561Sobrienvoid
12003130561Sobrienia64_adjust_symtab (void)
12004130561Sobrien{
12005130561Sobrien  hash_traverse (alias_hash, do_alias);
12006130561Sobrien}
12007130561Sobrien
12008130561Sobrien/* It renames the original section name to its alias.  */
12009130561Sobrienstatic void
12010130561Sobriendo_secalias (const char *alias, PTR value)
12011130561Sobrien{
12012130561Sobrien  struct alias *h = (struct alias *) value;
12013130561Sobrien  segT sec = bfd_get_section_by_name (stdoutput, h->name);
12014130561Sobrien
12015130561Sobrien  if (sec == NULL)
12016130561Sobrien    as_warn_where (h->file, h->line,
12017130561Sobrien		   _("section `%s' aliased to `%s' is not used"),
12018130561Sobrien		   h->name, alias);
12019130561Sobrien  else
12020130561Sobrien    sec->name = alias;
12021130561Sobrien}
12022130561Sobrien
12023130561Sobrien/* Called from write_object_file.  */
12024130561Sobrienvoid
12025130561Sobrienia64_frob_file (void)
12026130561Sobrien{
12027130561Sobrien  hash_traverse (secalias_hash, do_secalias);
12028130561Sobrien}
12029