diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b3f874ba9ca..0c81a1077af 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,28 @@ 2019-10-23 Michael Meissner + * 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_64bit): Set max_prefixed_insns and num_insns. + (movtd_64bit_nodm): Set max_prefixed_insns and num_insns. + (mov_ppc64): Set max_prefixed_insns and num_insns. + * config/rs6000/vsx.md: (vsx_mov_64bit): Set + max_prefixed_insns and num_insns. + * config/rs6000/rs6000.md (mov_64bit_dm): Reformat. (movtd_64bit_nodm): Reformat. (mov_32bit): Reformat. diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 08dd88c3e4d..6b27d73023a 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -194,6 +194,7 @@ extern bool prefixed_store_p (rtx_insn *); 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. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 5876714d562..13992217fd6 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -21076,14 +21076,32 @@ rs6000_insn_cost (rtx_insn *insn, bool speed) 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) @@ -25087,6 +25105,37 @@ rs6000_asm_output_opcode (FILE *stream) 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; +} + #ifdef HAVE_GAS_HIDDEN # define USE_HIDDEN_LINKONCE 1 diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 27373c55ad6..a4ad3f8fc3e 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1847,9 +1847,19 @@ extern scalar_int_mode rs6000_pmode; /* 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. */ + to express in the length attribute. -/* #define ADJUST_INSN_LENGTH(X,LENGTH) */ + 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 diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 60b8b8ce568..a3c909fabfb 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -285,20 +285,24 @@ (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)) +;; 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)) -;; 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"))) +;; 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. @@ -7766,7 +7770,9 @@ 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") @@ -7781,7 +7787,9 @@ 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_32bit" [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,d,Y,r,r") @@ -8990,7 +8998,8 @@ 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") diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index 3cc1277aaee..a0b2e7b1fc0 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -1149,6 +1149,14 @@ "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, *, *,