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, ®, 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, ®, 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, ®, 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 (¬es, sizeof (*dr)); 486984865Sobrien memset (*drpp, 0, sizeof (*dr)); 487084865Sobrien } 487184865Sobrien 4872218822Sdim name = obstack_alloc (¬es, 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 (¬es, 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(¬es, 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 (®); 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 (¬es, 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 (¬es, 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 (¬es, 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 = ®deps[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 (¬es, name, len); 11927130561Sobrien name = obstack_finish (¬es); 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 (¬es, name); 11980130561Sobrien obstack_free (¬es, 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