+/* Return the next non-empty frag. */
+
+static fragS *
+i386_next_non_empty_frag (fragS *fragP)
+{
+ /* There may be a frag with a ".fill 0" when there is no room in
+ the current frag for frag_grow in output_insn. */
+ for (fragP = fragP->fr_next;
+ (fragP != NULL
+ && fragP->fr_type == rs_fill
+ && fragP->fr_fix == 0);
+ fragP = fragP->fr_next)
+ ;
+ return fragP;
+}
+
+/* Return the next jcc frag after BRANCH_PADDING. */
+
+static fragS *
+i386_next_jcc_frag (fragS *fragP)
+{
+ if (!fragP)
+ return NULL;
+
+ if (fragP->fr_type == rs_machine_dependent
+ && (TYPE_FROM_RELAX_STATE (fragP->fr_subtype)
+ == BRANCH_PADDING))
+ {
+ fragP = i386_next_non_empty_frag (fragP);
+ if (fragP->fr_type != rs_machine_dependent)
+ return NULL;
+ if (TYPE_FROM_RELAX_STATE (fragP->fr_subtype) == COND_JUMP)
+ return fragP;
+ }
+
+ return NULL;
+}
+
+/* Classify BRANCH_PADDING, BRANCH_PREFIX and FUSED_JCC_PADDING frags. */
+
+static void
+i386_classify_machine_dependent_frag (fragS *fragP)
+{
+ fragS *cmp_fragP;
+ fragS *pad_fragP;
+ fragS *branch_fragP;
+ fragS *next_fragP;
+ unsigned int max_prefix_length;
+
+ if (fragP->tc_frag_data.classified)
+ return;
+
+ /* First scan for BRANCH_PADDING and FUSED_JCC_PADDING. Convert
+ FUSED_JCC_PADDING and merge BRANCH_PADDING. */
+ for (next_fragP = fragP;
+ next_fragP != NULL;
+ next_fragP = next_fragP->fr_next)
+ {
+ next_fragP->tc_frag_data.classified = 1;
+ if (next_fragP->fr_type == rs_machine_dependent)
+ switch (TYPE_FROM_RELAX_STATE (next_fragP->fr_subtype))
+ {
+ case BRANCH_PADDING:
+ /* The BRANCH_PADDING frag must be followed by a branch
+ frag. */
+ branch_fragP = i386_next_non_empty_frag (next_fragP);
+ next_fragP->tc_frag_data.u.branch_fragP = branch_fragP;
+ break;
+ case FUSED_JCC_PADDING:
+ /* Check if this is a fused jcc:
+ FUSED_JCC_PADDING
+ CMP like instruction
+ BRANCH_PADDING
+ COND_JUMP
+ */
+ cmp_fragP = i386_next_non_empty_frag (next_fragP);
+ pad_fragP = i386_next_non_empty_frag (cmp_fragP);
+ branch_fragP = i386_next_jcc_frag (pad_fragP);
+ if (branch_fragP)
+ {
+ /* The BRANCH_PADDING frag is merged with the
+ FUSED_JCC_PADDING frag. */
+ next_fragP->tc_frag_data.u.branch_fragP = branch_fragP;
+ /* CMP like instruction size. */
+ next_fragP->tc_frag_data.cmp_size = cmp_fragP->fr_fix;
+ frag_wane (pad_fragP);
+ /* Skip to branch_fragP. */
+ next_fragP = branch_fragP;
+ }
+ else if (next_fragP->tc_frag_data.max_prefix_length)
+ {
+ /* Turn FUSED_JCC_PADDING into BRANCH_PREFIX if it isn't
+ a fused jcc. */
+ next_fragP->fr_subtype
+ = ENCODE_RELAX_STATE (BRANCH_PREFIX, 0);
+ next_fragP->tc_frag_data.max_bytes
+ = next_fragP->tc_frag_data.max_prefix_length;
+ /* This will be updated in the BRANCH_PREFIX scan. */
+ next_fragP->tc_frag_data.max_prefix_length = 0;
+ }
+ else
+ frag_wane (next_fragP);
+ break;
+ }
+ }
+
+ /* Stop if there is no BRANCH_PREFIX. */
+ if (!align_branch_prefix_size)
+ return;
+
+ /* Scan for BRANCH_PREFIX. */
+ for (; fragP != NULL; fragP = fragP->fr_next)
+ {
+ if (fragP->fr_type != rs_machine_dependent
+ || (TYPE_FROM_RELAX_STATE (fragP->fr_subtype)
+ != BRANCH_PREFIX))
+ continue;
+
+ /* Count all BRANCH_PREFIX frags before BRANCH_PADDING and
+ COND_JUMP_PREFIX. */
+ max_prefix_length = 0;
+ for (next_fragP = fragP;
+ next_fragP != NULL;
+ next_fragP = next_fragP->fr_next)
+ {
+ if (next_fragP->fr_type == rs_fill)
+ /* Skip rs_fill frags. */
+ continue;
+ else if (next_fragP->fr_type != rs_machine_dependent)
+ /* Stop for all other frags. */
+ break;
+
+ /* rs_machine_dependent frags. */
+ if (TYPE_FROM_RELAX_STATE (next_fragP->fr_subtype)
+ == BRANCH_PREFIX)
+ {
+ /* Count BRANCH_PREFIX frags. */
+ if (max_prefix_length >= MAX_FUSED_JCC_PADDING_SIZE)
+ {
+ max_prefix_length = MAX_FUSED_JCC_PADDING_SIZE;
+ frag_wane (next_fragP);
+ }
+ else
+ max_prefix_length
+ += next_fragP->tc_frag_data.max_bytes;
+ }
+ else if ((TYPE_FROM_RELAX_STATE (next_fragP->fr_subtype)
+ == BRANCH_PADDING)
+ || (TYPE_FROM_RELAX_STATE (next_fragP->fr_subtype)
+ == FUSED_JCC_PADDING))
+ {
+ /* Stop at BRANCH_PADDING and FUSED_JCC_PADDING. */
+ fragP->tc_frag_data.u.padding_fragP = next_fragP;
+ break;
+ }
+ else
+ /* Stop for other rs_machine_dependent frags. */
+ break;
+ }
+
+ fragP->tc_frag_data.max_prefix_length = max_prefix_length;
+
+ /* Skip to the next frag. */
+ fragP = next_fragP;
+ }
+}
+
+/* Compute padding size for
+
+ FUSED_JCC_PADDING
+ CMP like instruction
+ BRANCH_PADDING
+ COND_JUMP/UNCOND_JUMP
+
+ or
+
+ BRANCH_PADDING
+ COND_JUMP/UNCOND_JUMP
+ */
+
+static int
+i386_branch_padding_size (fragS *fragP, offsetT address)
+{
+ unsigned int offset, size, padding_size;
+ fragS *branch_fragP = fragP->tc_frag_data.u.branch_fragP;
+
+ /* The start address of the BRANCH_PADDING or FUSED_JCC_PADDING frag. */
+ if (!address)
+ address = fragP->fr_address;
+ address += fragP->fr_fix;
+
+ /* CMP like instrunction size. */
+ size = fragP->tc_frag_data.cmp_size;
+
+ /* The base size of the branch frag. */
+ size += branch_fragP->fr_fix;
+
+ /* Add opcode and displacement bytes for the rs_machine_dependent
+ branch frag. */
+ if (branch_fragP->fr_type == rs_machine_dependent)
+ size += md_relax_table[branch_fragP->fr_subtype].rlx_length;
+
+ /* Check if branch is within boundary and doesn't end at the last
+ byte. */
+ offset = address & ((1U << align_branch_power) - 1);
+ if ((offset + size) >= (1U << align_branch_power))
+ /* Padding needed to avoid crossing boundary. */
+ padding_size = (1U << align_branch_power) - offset;
+ else
+ /* No padding needed. */
+ padding_size = 0;
+
+ /* The return value may be saved in tc_frag_data.length which is
+ unsigned byte. */
+ if (!fits_in_unsigned_byte (padding_size))
+ abort ();
+
+ return padding_size;
+}
+
+/* i386_generic_table_relax_frag()
+
+ Handle BRANCH_PADDING, BRANCH_PREFIX and FUSED_JCC_PADDING frags to
+ grow/shrink padding to align branch frags. Hand others to
+ relax_frag(). */
+
+long
+i386_generic_table_relax_frag (segT segment, fragS *fragP, long stretch)
+{
+ if (TYPE_FROM_RELAX_STATE (fragP->fr_subtype) == BRANCH_PADDING
+ || TYPE_FROM_RELAX_STATE (fragP->fr_subtype) == FUSED_JCC_PADDING)
+ {
+ long padding_size = i386_branch_padding_size (fragP, 0);
+ long grow = padding_size - fragP->tc_frag_data.length;
+
+ /* When the BRANCH_PREFIX frag is used, the computed address
+ must match the actual address and there should be no padding. */
+ if (fragP->tc_frag_data.padding_address
+ && (fragP->tc_frag_data.padding_address != fragP->fr_address
+ || padding_size))
+ abort ();
+
+ /* Update the padding size. */
+ if (grow)
+ fragP->tc_frag_data.length = padding_size;
+
+ return grow;
+ }
+ else if (TYPE_FROM_RELAX_STATE (fragP->fr_subtype) == BRANCH_PREFIX)
+ {
+ fragS *padding_fragP, *next_fragP;
+ long padding_size, left_size, last_size;
+
+ padding_fragP = fragP->tc_frag_data.u.padding_fragP;
+ if (!padding_fragP)
+ /* Use the padding set by the leading BRANCH_PREFIX frag. */
+ return (fragP->tc_frag_data.length
+ - fragP->tc_frag_data.last_length);
+
+ /* Compute the relative address of the padding frag in the very
+ first time where the BRANCH_PREFIX frag sizes are zero. */
+ if (!fragP->tc_frag_data.padding_address)
+ fragP->tc_frag_data.padding_address
+ = padding_fragP->fr_address - (fragP->fr_address - stretch);
+
+ /* First update the last length from the previous interation. */
+ left_size = fragP->tc_frag_data.prefix_length;
+ for (next_fragP = fragP;
+ next_fragP != padding_fragP;
+ next_fragP = next_fragP->fr_next)
+ if (next_fragP->fr_type == rs_machine_dependent
+ && (TYPE_FROM_RELAX_STATE (next_fragP->fr_subtype)
+ == BRANCH_PREFIX))
+ {
+ if (left_size)
+ {
+ int max = next_fragP->tc_frag_data.max_bytes;
+ if (max)
+ {
+ int size;
+ if (max > left_size)
+ size = left_size;
+ else
+ size = max;
+ left_size -= size;
+ next_fragP->tc_frag_data.last_length = size;
+ }
+ }
+ else
+ next_fragP->tc_frag_data.last_length = 0;
+ }
+
+ /* Check the padding size for the padding frag. */
+ padding_size = i386_branch_padding_size
+ (padding_fragP, (fragP->fr_address
+ + fragP->tc_frag_data.padding_address));
+
+ last_size = fragP->tc_frag_data.prefix_length;
+ /* Check if there is change from the last interation. */
+ if (padding_size == last_size)
+ {
+ /* Update the expected address of the padding frag. */
+ padding_fragP->tc_frag_data.padding_address
+ = (fragP->fr_address + padding_size
+ + fragP->tc_frag_data.padding_address);
+ return 0;
+ }
+
+ if (padding_size > fragP->tc_frag_data.max_prefix_length)
+ {
+ /* No padding if there is no sufficient room. Clear the
+ expected address of the padding frag. */
+ padding_fragP->tc_frag_data.padding_address = 0;
+ padding_size = 0;
+ }
+ else
+ /* Store the expected address of the padding frag. */
+ padding_fragP->tc_frag_data.padding_address
+ = (fragP->fr_address + padding_size
+ + fragP->tc_frag_data.padding_address);
+
+ fragP->tc_frag_data.prefix_length = padding_size;
+
+ /* Update the length for the current interation. */
+ left_size = padding_size;
+ for (next_fragP = fragP;
+ next_fragP != padding_fragP;
+ next_fragP = next_fragP->fr_next)
+ if (next_fragP->fr_type == rs_machine_dependent
+ && (TYPE_FROM_RELAX_STATE (next_fragP->fr_subtype)
+ == BRANCH_PREFIX))
+ {
+ if (left_size)
+ {
+ int max = next_fragP->tc_frag_data.max_bytes;
+ if (max)
+ {
+ int size;
+ if (max > left_size)
+ size = left_size;
+ else
+ size = max;
+ left_size -= size;
+ next_fragP->tc_frag_data.length = size;
+ }
+ }
+ else
+ next_fragP->tc_frag_data.length = 0;
+ }
+
+ return (fragP->tc_frag_data.length
+ - fragP->tc_frag_data.last_length);
+ }
+ return relax_frag (segment, fragP, stretch);
+}
+