2019-10-23 Michael Meissner <meissner@linux.ibm.com>
+ * config/rs6000/rs6000-protos.h (rs6000_adjust_insn_length): New
+ declaration.
+ * config/rs6000/rs6000.c (rs6000_insn_cost): Use num_insns insn
+ attribute if it exists, rather than the insn size. If we use the
+ insn size, adjust the size to remove the extra size that prefixed
+ instructions take.
+ (rs6000_adjust_insn_length): New function.
+ * config/rs6000/rs6000.h (ADJUST_INSN_LENGTH): New target hook to
+ update the instruction sized if prefixed instructions are used.
+ * config/rs6000/rs6000.md (prefixed_length attribute): Delete.
+ (non_prefixed_length attribute): Delete.
+ (num_insns attribute): New insn attribute to return the number of
+ instructions.
+ (max_prefixed_insns attribute): New insn attribute to return the
+ maximum number of prefixed instructions in an insn.
+ (length attribute): Do not adjust for prefix instructions here,
+ punt to ADJUST_INSN_LENGTH.
+ (mov<mode>_64bit): Set max_prefixed_insns and num_insns.
+ (movtd_64bit_nodm): Set max_prefixed_insns and num_insns.
+ (mov<mode>_ppc64): Set max_prefixed_insns and num_insns.
+ * config/rs6000/vsx.md: (vsx_mov<mode>_64bit): Set
+ max_prefixed_insns and num_insns.
+
* config/rs6000/rs6000.md (mov<mode>_64bit_dm): Reformat.
(movtd_64bit_nodm): Reformat.
(mov<mode>_32bit): Reformat.
extern bool prefixed_paddi_p (rtx_insn *);
extern void rs6000_asm_output_opcode (FILE *);
extern void rs6000_final_prescan_insn (rtx_insn *, rtx [], int);
+extern int rs6000_adjust_insn_length (rtx_insn *, int);
/* Return true if the address can be used for a prefixed load, store, or add
immediate instructions that cannot be used with a non-prefixed instruction.
if (recog_memoized (insn) < 0)
return 0;
+ /* If we are optimizing for size, just use the length. */
if (!speed)
return get_attr_length (insn);
+ /* Use the cost if provided. */
int cost = get_attr_cost (insn);
if (cost > 0)
return cost;
- int n = get_attr_length (insn) / 4;
+ /* If the insn tells us how many insns there are, use that. Otherwise use
+ the length/4. Adjust the insn length to remove the extra size that
+ prefixed instructions take. */
+ int n = get_attr_num_insns (insn);
+ if (n == 0)
+ {
+ int length = get_attr_length (insn);
+ if (get_attr_prefixed (insn) == PREFIXED_YES)
+ {
+ int adjust = 0;
+ ADJUST_INSN_LENGTH (insn, adjust);
+ length -= adjust;
+ }
+
+ n = length / 4;
+ }
+
enum attr_type type = get_attr_type (insn);
switch (type)
return;
}
+/* Adjust the length of an INSN. LENGTH is the currently-computed length and
+ should be adjusted to reflect any required changes. This macro is used when
+ there is some systematic length adjustment required that would be difficult
+ to express in the length attribute.
+
+ In the PowerPC, we use this to adjust the length of an instruction if one or
+ more prefixed instructions are generated, using the attribute
+ num_prefixed_insns. A prefixed instruction is 8 bytes instead of 4, but the
+ hardware requires that a prefied instruciton does not cross a 64-byte
+ boundary. This means the compiler has to assume the length of the first
+ prefixed instruction is 12 bytes instead of 8 bytes. Since the length is
+ already set for the non-prefixed instruction, we just need to udpate for the
+ difference. */
+
+int
+rs6000_adjust_insn_length (rtx_insn *insn, int length)
+{
+ if (TARGET_PREFIXED_ADDR && NONJUMP_INSN_P (insn))
+ {
+ rtx pattern = PATTERN (insn);
+ if (GET_CODE (pattern) != USE && GET_CODE (pattern) != CLOBBER
+ && get_attr_prefixed (insn) == PREFIXED_YES)
+ {
+ int num_prefixed = get_attr_max_prefixed_insns (insn);
+ length += 4 * (num_prefixed + 1);
+ }
+ }
+
+ return length;
+}
+
\f
#ifdef HAVE_GAS_HIDDEN
# define USE_HIDDEN_LINKONCE 1
/* Adjust the length of an INSN. LENGTH is the currently-computed length and
should be adjusted to reflect any required changes. This macro is used when
there is some systematic length adjustment required that would be difficult
- to express in the length attribute. */
-
-/* #define ADJUST_INSN_LENGTH(X,LENGTH) */
+ to express in the length attribute.
+
+ In the PowerPC, we use this to adjust the length of an instruction if one or
+ more prefixed instructions are generated, using the attribute
+ num_prefixed_insns. A prefixed instruction is 8 bytes instead of 4, but the
+ hardware requires that a prefied instruciton does not cross a 64-byte
+ boundary. This means the compiler has to assume the length of the first
+ prefixed instruction is 12 bytes instead of 8 bytes. Since the length is
+ already set for the non-prefixed instruction, we just need to udpate for the
+ difference. */
+
+#define ADJUST_INSN_LENGTH(INSN,LENGTH) \
+ (LENGTH) = rs6000_adjust_insn_length ((INSN), (LENGTH))
/* Given a comparison code (EQ, NE, etc.) and the first operand of a
COMPARE, return the mode to be used for the comparison. For
(const_string "no")))
-;; Length in bytes of instructions that use prefixed addressing and length in
-;; bytes of instructions that does not use prefixed addressing. This allows
-;; both lengths to be defined as constants, and the length attribute can pick
-;; the size as appropriate.
-(define_attr "prefixed_length" "" (const_int 12))
-(define_attr "non_prefixed_length" "" (const_int 4))
-
-;; Length of the instruction (in bytes). Prefixed insns are 8 bytes, but the
-;; assembler might issue need to issue a NOP so that the prefixed instruction
-;; does not cross a cache boundary, which makes them possibly 12 bytes.
-(define_attr "length" ""
- (if_then_else (eq_attr "prefixed" "yes")
- (attr "prefixed_length")
- (attr "non_prefixed_length")))
+;; Return the number of real hardware instructions in a combined insn. If it
+;; is 0, just use the length / 4.
+(define_attr "num_insns" "" (const_int 0))
+
+;; If an insn is prefixed, return the maximum number of prefixed instructions
+;; in the insn. The macro ADJUST_INSN_LENGTH uses this number to adjust the
+;; insn length.
+(define_attr "max_prefixed_insns" "" (const_int 1))
+
+;; Length of the instruction (in bytes). This length does not consider the
+;; length for prefixed instructions. The macro ADJUST_INSN_LENGTH will adjust
+;; the length if there are prefixed instructions.
+;;
+;; While it might be tempting to use num_insns to calculate the length, it can
+;; be problematical unless all insn lengths are adjusted to use num_insns
+;; (i.e. if num_insns is 0, it will get the length, which in turn will get
+;; num_insns and recurse).
+(define_attr "length" "" (const_int 4))
;; Processor type -- this attribute must exactly match the processor_type
;; enumeration in rs6000-opts.h.
DONE;
}
[(set_attr "length" "8")
- (set_attr "isa" "*,*,*,*,*,*,*,*,p8v,p8v")])
+ (set_attr "isa" "*,*,*,*,*,*,*,*,p8v,p8v")
+ (set_attr "max_prefixed_insns" "2")
+ (set_attr "num_insns" "2")])
(define_insn_and_split "*movtd_64bit_nodm"
[(set (match_operand:TD 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
rs6000_split_multireg_move (operands[0], operands[1]);
DONE;
}
- [(set_attr "length" "8,8,8,12,12,8")])
+ [(set_attr "length" "8,8,8,12,12,8")
+ (set_attr "max_prefixed_insns" "2")
+ (set_attr "num_insns" "2,2,2,3,3,2")])
(define_insn_and_split "*mov<mode>_32bit"
[(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,d,Y,r,r")
return rs6000_output_move_128bit (operands);
}
[(set_attr "type" "store,store,load,load,*,*")
- (set_attr "length" "8")])
+ (set_attr "length" "8")
+ (set_attr "max_prefixed_insns" "2")])
(define_split
[(set (match_operand:TI2 0 "int_reg_operand")
"vecstore, vecload, vecsimple, mffgpr, mftgpr, load,
store, load, store, *, vecsimple, vecsimple,
vecsimple, *, *, vecstore, vecload")
+ (set_attr "num_insns"
+ "*, *, *, 2, *, 2,
+ 2, 2, 2, 2, *, *,
+ *, 5, 2, *, *")
+ (set_attr "max_prefixed_insns"
+ "*, *, *, *, *, 2,
+ 2, 2, 2, 2, *, *,
+ *, *, *, *, *")
(set_attr "length"
"*, *, *, 8, *, 8,
8, 8, 8, 8, *, *,