This is patch #18, it finaly adds prefixed instruction support for the scalar types. There are some things I need to check out for for vector types and 128-bit floating point, so those are not enabled for now.
The earlier patch that changed the length of many of the load/stores to '*' means that this patch can be somewhat smaller. The three main insns patched are the movsi, movdi, and add<mode> insns to add an alternative to load up or add 34 bit integer constants. These changes come from my private internal branch that has been stable for some time, adapted to the current trunk. As I post this patch, it has not been go through the full bootstrap procedure, but I have checked it without doing the bootstrap before committing the patch. Assuming the bootstrap and make check run without regressions, can I check this into the FSF trunk? This is a series of separate patches to add functionality to the PowerPC backend to support future processors. Here is a high level summary of the patches: * Patches 1-8, have already been applied * Patch 9 has been rewritten in patches 12-13 * Patch 10 is withdrawn for now * Patch 11 adds DS offset mode to rs6000.c's reg_addr * Patch 12 adds a new enumeration for instruction format * Patch 13 adds support for matching prefixed insns * Patch 14 adds pc-relative support to load up addresses * Patch 15 renamed some functions to be smaller * Patch 16 updated a comment and moved a predicate * Patch 17 adds the prefixed RTL attribute & emitting 'p' before prefixed * Patch 18 adds prefixed support for scalar types * Patch 19 uses a separate 'future' cost structure * Patch 20 clones power9.md for initial scheduling on future.md. The following patches have not yet been written, but I expect them to be: * Patch 21 finish prefixed insn support for vectors & 128-bit int/floats * Patch 22 enable pc-relative by default * Patch 23 add pcrel linker optimization * Patch 24 new tests 2019-07-25 Michael Meissner <meiss...@linux.ibm.com> * config/rs6000/predicates.md (add_operand): Add support for PADDI. (non_add_cint_operand): Add support for PADDI. * config/rs6000/rs6000.c (struct rs6000_reg_addr): Add field to say whether a mode supports using prefixed memory instructions. (mode_supports_prefixed_address_p): Make static inline. Use the prefixed_memory_p field in reg_addr to say whether a give mode supports prefixed memory instructions. (rs6000_hard_regno_mode_ok_uncached): Allow for larger vector types in the future. (rs6000_debug_print_mode): If -mdebug=reg, print which modes support prefixed addressing. (rs6000_setup_reg_addr_masks): Mark all scalar types that support offset addressing to be able support prefixed addressing. (num_insns_constant_gpr): Use SIGNED_16BIT_OFFSET_P macro. If we support prefixed memory instructions, know that we can load up 34-bit constants directly in one instruction. (quad_address_p): Allow for larger vector types in the future. (mem_operand_gpr): Use SIGNED_16BIT_FFSET_EXTRA_P macro. (mem_operand_ds_form): Use SIGNED_16BIT_FFSET_EXTRA_P macro. (rs6000_legitimate_offset_address_p): Add support for larger offsets if we have prefixed addressing. (rs6000_legitimate_address_p): Add support for prefixed addresses. Do not allow update forms of addressing if the offset is larger than 16 bits, since prefixed memory instructions don't have update addressing formats. (rs6000_mode_dependent_address): Add support for 34 bit offsets if we have prefixed addressing. (rs6000_rtx_costs): Allow adds with 34-bit values which show up if we have prefixed addressing. (rs6000_num_insns): New function. (rs6000_insn_cost): When using the instruction length, count prefixed instructions as one instruction instead of three. * config/rs6000/rs6000.md (add<mode>, GPR iterator): Add support for the PADDI instruction if we have prefixed addressing. (movsi_internal1): Add support to load up 16 bit constants directly if have prefixed addressing. (movsi splitter): Don't split if we have prefixed addressing. (movdi_internal64): Add support to load up 34 bit constants if we have prefixed addressing. (movdi splitter): Add comment. (stack_protect_setdi): Add support for either address being a prefixed address. (stack_protect_testdi): Add support for either address being a prefixed address. Index: gcc/config/rs6000/predicates.md =================================================================== --- gcc/config/rs6000/predicates.md (revision 273813) +++ gcc/config/rs6000/predicates.md (working copy) @@ -839,7 +839,8 @@ (define_special_predicate "indexed_addre (define_predicate "add_operand" (if_then_else (match_code "const_int") (match_test "satisfies_constraint_I (op) - || satisfies_constraint_L (op)") + || satisfies_constraint_L (op) + || satisfies_constraint_eI (op)") (match_operand 0 "gpc_reg_operand"))) ;; Return 1 if the operand is either a non-special register, or 0, or -1. @@ -852,7 +853,8 @@ (define_predicate "adde_operand" (define_predicate "non_add_cint_operand" (and (match_code "const_int") (match_test "!satisfies_constraint_I (op) - && !satisfies_constraint_L (op)"))) + && !satisfies_constraint_L (op) + && !satisfies_constraint_eI (op)"))) ;; Return 1 if the operand is a constant that can be used as the operand ;; of an AND, OR or XOR. Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 273813) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -373,6 +373,7 @@ struct rs6000_reg_addr { enum INSN_FORM default_insn_form; /* Default format for offsets. */ addr_mask_type addr_mask[(int)N_RELOAD_REG]; /* Valid address masks. */ bool scalar_in_vmx_p; /* Scalar value can go in VMX. */ + bool prefixed_memory_p; /* We can use prefixed memory. */ }; static struct rs6000_reg_addr reg_addr[NUM_MACHINE_MODES]; @@ -415,12 +416,13 @@ mode_supports_dq_form (machine_mode mode register, but we are not using it as part of a memory operation. As modes add support for prefixed memory, they will be added here. */ -static bool +static inline bool mode_supports_prefixed_address_p (machine_mode mode) { - return mode == VOIDmode; + return reg_addr[mode].prefixed_memory_p; } + /* Given that there exists at least one variable that is set (produced) by OUT_INSN and read (consumed) by IN_INSN, return true iff IN_INSN represents one or more memory store operations and none of @@ -1838,7 +1840,7 @@ rs6000_hard_regno_mode_ok_uncached (int if (ALTIVEC_REGNO_P (regno)) { - if (GET_MODE_SIZE (mode) != 16 && !reg_addr[mode].scalar_in_vmx_p) + if (GET_MODE_SIZE (mode) < 16 && !reg_addr[mode].scalar_in_vmx_p) return 0; return ALTIVEC_REGNO_P (last_regno); @@ -2162,6 +2164,14 @@ rs6000_debug_print_mode (ssize_t m) break; } + if (reg_addr[m].prefixed_memory_p) + { + fprintf (stderr, "%*s prefix", spaces, ""); + spaces = 0; + } + else + spaces += sizeof (" prefix") - 1; + if ((reg_addr[m].reload_store != CODE_FOR_nothing) || (reg_addr[m].reload_load != CODE_FOR_nothing)) { @@ -2777,6 +2787,16 @@ rs6000_setup_reg_addr_masks (void) default_mask = reg_addr[m].addr_mask[RELOAD_REG_GPR]; reg_addr[m].default_insn_form = addr_mask_to_insn_form (default_mask); + + /* Set the prefixed memory support for any scalar mode that has offset + addressing and is held in a single register in its default + register. */ + + const addr_mask_type omask = (RELOAD_REG_VALID | RELOAD_REG_OFFSET); + + if (TARGET_PREFIXED_ADDR && msize <= 8 + && (default_mask & (omask | RELOAD_REG_MULTIPLE)) == omask) + reg_addr[m].prefixed_memory_p = true; } } @@ -5627,7 +5647,7 @@ static int num_insns_constant_gpr (HOST_WIDE_INT value) { /* signed constant loadable with addi */ - if (((unsigned HOST_WIDE_INT) value + 0x8000) < 0x10000) + if (SIGNED_16BIT_OFFSET_P (value)) return 1; /* constant loadable with addis */ @@ -5635,6 +5655,10 @@ num_insns_constant_gpr (HOST_WIDE_INT va && (value >> 31 == -1 || value >> 31 == 0)) return 1; + /* PADDI can support up to 34 bit signed integers. */ + else if (TARGET_PREFIXED_ADDR && SIGNED_34BIT_OFFSET_P (value)) + return 1; + else if (TARGET_POWERPC64) { HOST_WIDE_INT low = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000; @@ -7347,7 +7371,8 @@ quad_address_p (rtx addr, machine_mode m | ADDR_VALIDATE_PCREL_LOCAL); rtx op0, op1; - if (GET_MODE_SIZE (mode) != 16) + + if (GET_MODE_SIZE (mode) < 16) return false; if (legitimate_indirect_address_p (addr, strict)) @@ -7496,7 +7521,7 @@ mem_operand_gpr (rtx op, machine_mode mo causes a wrap, so test only the low 16 bits. */ offset = ((offset & 0xffff) ^ 0x8000) - 0x8000; - return offset + 0x8000 < 0x10000u - extra; + return SIGNED_16BIT_OFFSET_EXTRA_P (offset, extra); } /* As above, but for DS-FORM VSX insns. Unlike mem_operand_gpr, @@ -7539,7 +7564,7 @@ mem_operand_ds_form (rtx op, machine_mod causes a wrap, so test only the low 16 bits. */ offset = ((offset & 0xffff) ^ 0x8000) - 0x8000; - return offset + 0x8000 < 0x10000u - extra; + return SIGNED_16BIT_OFFSET_EXTRA_P (offset, extra); } /* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address_p. */ @@ -7888,8 +7913,10 @@ rs6000_legitimate_offset_address_p (mach break; } - offset += 0x8000; - return offset < 0x10000 - extra; + if (TARGET_PREFIXED_ADDR) + return SIGNED_34BIT_OFFSET_EXTRA_P (offset, extra); + else + return SIGNED_16BIT_OFFSET_EXTRA_P (offset, extra); } bool @@ -8786,6 +8813,10 @@ rs6000_legitimate_address_p (machine_mod && mode_supports_pre_incdec_p (mode) && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict)) return 1; + /* Handle prefixed addresses (pc-relative or 34-bit offset). */ + if (prefixed_addr_mode_p (x, mode)) + return 1; + /* Handle restricted vector d-form offsets in ISA 3.0. */ if (quad_offset_p) { @@ -8836,11 +8867,13 @@ rs6000_legitimate_address_p (machine_mod && !avoiding_indexed_address_p (mode) && legitimate_indexed_address_p (x, reg_ok_strict)) return 1; + /* There is no prefixed version of the load/store with update. */ if (TARGET_UPDATE && GET_CODE (x) == PRE_MODIFY && mode_supports_pre_modify_p (mode) && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict) - && (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1), - reg_ok_strict, false) + && ((rs6000_legitimate_offset_address_p (mode, XEXP (x, 1), + reg_ok_strict, false) + && !prefixed_addr_mode_p (XEXP (x, 1), mode)) || (!avoiding_indexed_address_p (mode) && legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict))) && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0))) @@ -8906,8 +8939,12 @@ rs6000_mode_dependent_address (const_rtx && XEXP (addr, 0) != arg_pointer_rtx && CONST_INT_P (XEXP (addr, 1))) { - unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1)); - return val + 0x8000 >= 0x10000 - (TARGET_POWERPC64 ? 8 : 12); + HOST_WIDE_INT val = INTVAL (XEXP (addr, 1)); + HOST_WIDE_INT extra = TARGET_POWERPC64 ? 8 : 12; + if (TARGET_PREFIXED_ADDR) + return !SIGNED_34BIT_OFFSET_EXTRA_P (val, extra); + else + return !SIGNED_16BIT_OFFSET_EXTRA_P (val, extra); } break; @@ -20890,7 +20927,8 @@ rs6000_rtx_costs (rtx x, machine_mode mo || outer_code == PLUS || outer_code == MINUS) && (satisfies_constraint_I (x) - || satisfies_constraint_L (x))) + || satisfies_constraint_L (x) + || satisfies_constraint_eI (x))) || (outer_code == AND && (satisfies_constraint_K (x) || (mode == SImode @@ -21270,6 +21308,42 @@ rs6000_debug_rtx_costs (rtx x, machine_m return ret; } +/* How many real instructions are generated for this insn? This is slightly + different from the length attribute, in that the length attribute counts the + number of bytes. With prefixed instructions, we don't want to count a + prefixed instruction (length 12 bytes including possible NOP) as taking 3 + instructions, but just one. */ + +static int +rs6000_num_insns (rtx_insn *insn) +{ + /* Try to figure it out based on the length and whether there are prefixed + instructions. While prefixed instructions are only 8 bytes, we have to + use 12 as the size of the first prefixed instruction in case the + instruction needs to be aligned. Back to back prefixed instructions would + only take 20 bytes, since it is guaranteed that one of the prefixed + instructions does not need the alignment. */ + int length = get_attr_length (insn); + + if (length >= 12 && TARGET_PREFIXED_ADDR + && get_attr_prefixed (insn) == PREFIXED_YES) + { + /* Single prefixed instruction. */ + if (length == 12) + return 1; + + /* A normal instruction and a prefixed instruction (16) or two back + to back prefixed instructions (20). */ + if (length == 16 || length == 20) + return 2; + + /* Guess for larger instruction sizes. */ + return 2 + (length - 20) / 4; + } + + return length / 4; +} + static int rs6000_insn_cost (rtx_insn *insn, bool speed) { @@ -21283,7 +21357,7 @@ rs6000_insn_cost (rtx_insn *insn, bool s if (cost > 0) return cost; - int n = get_attr_length (insn) / 4; + int n = rs6000_num_insns (insn); enum attr_type type = get_attr_type (insn); switch (type) Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 273813) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -1765,15 +1765,17 @@ (define_expand "add<mode>3" }) (define_insn "*add<mode>3" - [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r") - (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b") - (match_operand:GPR 2 "add_operand" "r,I,L")))] + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r,r") + (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b,b") + (match_operand:GPR 2 "add_operand" "r,I,L,eI")))] "" "@ add %0,%1,%2 addi %0,%1,%2 - addis %0,%1,%v2" - [(set_attr "type" "add")]) + addis %0,%1,%v2 + addi %0,%1,%2" + [(set_attr "type" "add") + (set_attr "isa" "*,*,*,fut")]) (define_insn "*addsi3_high" [(set (match_operand:SI 0 "gpc_reg_operand" "=b") @@ -6913,22 +6915,22 @@ (define_insn "movsi_low" ;; MR LA LWZ LFIWZX LXSIWZX ;; STW STFIWX STXSIWX LI LIS -;; # XXLOR XXSPLTIB 0 XXSPLTIB -1 VSPLTISW -;; XXLXOR 0 XXLORC -1 P9 const MTVSRWZ MFVSRWZ -;; MF%1 MT%0 NOP +;; PLI # XXLOR XXSPLTIB 0 XXSPLTIB -1 +;; VSPLTISW XXLXOR 0 XXLORC -1 P9 const MTVSRWZ +;; MFVSRWZ MF%1 MT%0 NOP (define_insn "*movsi_internal1" [(set (match_operand:SI 0 "nonimmediate_operand" "=r, r, r, d, v, m, Z, Z, r, r, - r, wa, wa, wa, v, - wa, v, v, wa, r, - r, *h, *h") + r, r, wa, wa, wa, + v, wa, v, v, wa, + r, r, *h, *h") (match_operand:SI 1 "input_operand" "r, U, m, Z, Z, r, d, v, I, L, - n, wa, O, wM, wB, - O, wM, wS, r, wa, - *h, r, 0"))] + eI, n, wa, O, wM, + wB, O, wM, wS, r, + wa, *h, r, 0"))] "gpc_reg_operand (operands[0], SImode) || gpc_reg_operand (operands[1], SImode)" "@ @@ -6942,6 +6944,7 @@ (define_insn "*movsi_internal1" stxsiwx %x1,%y0 li %0,%1 lis %0,%v1 + li %0,%1 # xxlor %x0,%x1,%x1 xxspltib %x0,0 @@ -6958,21 +6961,21 @@ (define_insn "*movsi_internal1" [(set_attr "type" "*, *, load, fpload, fpload, store, fpstore, fpstore, *, *, - *, veclogical, vecsimple, vecsimple, vecsimple, - veclogical, veclogical, vecsimple, mffgpr, mftgpr, - *, *, *") + *, *, veclogical, vecsimple, vecsimple, + vecsimple, veclogical, veclogical, vecsimple, mffgpr, + mftgpr, *, *, *") (set_attr "length" "*, *, *, *, *, *, *, *, *, *, - 8, *, *, *, *, - *, *, 8, *, *, - *, *, *") + *, 8, *, *, *, + *, *, *, 8, *, + *, *, *, *") (set_attr "isa" "*, *, *, p8v, p8v, *, p8v, p8v, *, *, - *, p8v, p9v, p9v, p8v, - p9v, p8v, p9v, p8v, p8v, - *, *, *")]) + fut, *, p8v, p9v, p9v, + p8v, p9v, p8v, p9v, p8v, + p8v, *, *, *")]) ;; Like movsi, but adjust a SF value to be used in a SI context, i.e. ;; (set (reg:SI ...) (subreg:SI (reg:SF ...) 0)) @@ -7117,14 +7120,15 @@ (define_insn "*movsi_from_df" "xscvdpsp %x0,%x1" [(set_attr "type" "fp")]) -;; Split a load of a large constant into the appropriate two-insn -;; sequence. +;; Split a load of a large constant into the appropriate two-insn sequence. On +;; systems that support PADDI (PLI), we can use PLI to load any 32-bit constant +;; in one instruction. (define_split [(set (match_operand:SI 0 "gpc_reg_operand") (match_operand:SI 1 "const_int_operand"))] "(unsigned HOST_WIDE_INT) (INTVAL (operands[1]) + 0x8000) >= 0x10000 - && (INTVAL (operands[1]) & 0xffff) != 0" + && (INTVAL (operands[1]) & 0xffff) != 0 && !TARGET_PREFIXED_ADDR" [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) @@ -8797,24 +8801,24 @@ (define_split [(pc)] { rs6000_split_multireg_move (operands[0], operands[1]); DONE; }) -;; GPR store GPR load GPR move GPR li GPR lis GPR # -;; FPR store FPR load FPR move AVX store AVX store AVX load -;; AVX load VSX move P9 0 P9 -1 AVX 0/-1 VSX 0 -;; VSX -1 P9 const AVX const From SPR To SPR SPR<->SPR -;; VSX->GPR GPR->VSX +;; GPR store GPR load GPR move GPR li GPR lis GPR pli +;; GPR # FPR store FPR load FPR move AVX store AVX store +;; AVX load AVX load VSX move P9 0 P9 -1 AVX 0/-1 +;; VSX 0 VSX -1 P9 const AVX const From SPR To SPR +;; SPR<->SPR VSX->GPR GPR->VSX (define_insn "*movdi_internal64" [(set (match_operand:DI 0 "nonimmediate_operand" "=YZ, r, r, r, r, r, - m, ^d, ^d, wY, Z, $v, - $v, ^wa, wa, wa, v, wa, - wa, v, v, r, *h, *h, - ?r, ?wa") + r, m, ^d, ^d, wY, Z, + $v, $v, ^wa, wa, wa, v, + wa, wa, v, v, r, *h, + *h, ?r, ?wa") (match_operand:DI 1 "input_operand" - "r, YZ, r, I, L, nF, - ^d, m, ^d, ^v, $v, wY, - Z, ^wa, Oj, wM, OjwM, Oj, - wM, wS, wB, *h, r, 0, - wa, r"))] + "r, YZ, r, I, L, eI, + nF, ^d, m, ^d, ^v, $v, + wY, Z, ^wa, Oj, wM, OjwM, + Oj, wM, wS, wB, *h, r, + 0, wa, r"))] "TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode) || gpc_reg_operand (operands[1], DImode))" @@ -8824,6 +8828,7 @@ (define_insn "*movdi_internal64" mr %0,%1 li %0,%1 lis %0,%v1 + li %0,%1 # stfd%U0%X0 %1,%0 lfd%U1%X1 %0,%1 @@ -8847,26 +8852,28 @@ (define_insn "*movdi_internal64" mtvsrd %x0,%1" [(set_attr "type" "store, load, *, *, *, *, - fpstore, fpload, fpsimple, fpstore, fpstore, fpload, - fpload, veclogical, vecsimple, vecsimple, vecsimple, veclogical, - veclogical, vecsimple, vecsimple, mfjmpr, mtjmpr, *, - mftgpr, mffgpr") + *, fpstore, fpload, fpsimple, fpstore, fpstore, + fpload, fpload, veclogical,vecsimple, vecsimple, vecsimple, + veclogical, veclogical, vecsimple, vecsimple, mfjmpr, mtjmpr, + *, mftgpr, mffgpr") (set_attr "size" "64") (set_attr "length" - "*, *, *, *, *, 20, - *, *, *, *, *, *, + "*, *, *, *, *, *, + 20, *, *, *, *, *, *, *, *, *, *, *, - *, 8, *, *, *, *, - *, *") + *, *, 8, *, *, *, + *, *, *") (set_attr "isa" - "*, *, *, *, *, *, - *, *, *, p9v, p7v, p9v, - p7v, *, p9v, p9v, p7v, *, - *, p7v, p7v, *, *, *, - p8v, p8v")]) + "*, *, *, *, *, fut, + *, *, *, *, p9v, p7v, + p9v, p7v, *, p9v, p9v, p7v, + *, *, p7v, p7v, *, *, + *, p8v, p8v")]) ; Some DImode loads are best done as a load of -1 followed by a mask -; instruction. +; instruction. On systems that support the PADDI (PLI) instruction, +; num_insns_constant returns 1, so these splitter would not be used for things +; that be loaded with PLI. (define_split [(set (match_operand:DI 0 "int_reg_operand_not_pseudo") (match_operand:DI 1 "const_int_operand"))] @@ -11498,14 +11505,42 @@ (define_insn "stack_protect_setsi" [(set_attr "type" "three") (set_attr "length" "12")]) +;; We can't use the prefixed attribute here because there are two memory +;; instructions, and we can't split the insn due to the fact that this +;; operation needs to be done in one piece. (define_insn "stack_protect_setdi" [(set (match_operand:DI 0 "memory_operand" "=Y") (unspec:DI [(match_operand:DI 1 "memory_operand" "Y")] UNSPEC_SP_SET)) (set (match_scratch:DI 2 "=&r") (const_int 0))] "TARGET_64BIT" - "ld%U1%X1 %2,%1\;std%U0%X0 %2,%0\;li %2,0" +{ + if (prefixed_mem_operand (operands[1], DImode)) + output_asm_insn ("pld %2,%1", operands); + else + output_asm_insn ("ld%U1%X1 %2,%1", operands); + + if (prefixed_mem_operand (operands[0], DImode)) + output_asm_insn ("pstd %2,%0", operands); + else + output_asm_insn ("std%U0%X0 %2,%0", operands); + + return "li %2,0"; +} [(set_attr "type" "three") - (set_attr "length" "12")]) + + ;; Back to back prefixed memory instructions take 20 bytes (8 bytes for each + ;; prefixed instruction + 4 bytes for the possible NOP). + (set_attr "prefixed" "no") + (set (attr "length") + (cond [(and (match_operand 0 "prefixed_mem_operand") + (match_operand 1 "prefixed_mem_operand")) + (const_string "24") + + (ior (match_operand 0 "prefixed_mem_operand") + (match_operand 1 "prefixed_mem_operand")) + (const_string "20")] + + (const_string "12")))]) (define_expand "stack_protect_test" [(match_operand 0 "memory_operand") @@ -11544,6 +11579,9 @@ (define_insn "stack_protect_testsi" lwz%U1%X1 %3,%1\;lwz%U2%X2 %4,%2\;cmplw %0,%3,%4\;li %3,0\;li %4,0" [(set_attr "length" "16,20")]) +;; We can't use the prefixed attribute here because there are two memory +;; instructions, and we can't split the insn due to the fact that this +;; operation needs to be done in one piece. (define_insn "stack_protect_testdi" [(set (match_operand:CCEQ 0 "cc_reg_operand" "=x,?y") (unspec:CCEQ [(match_operand:DI 1 "memory_operand" "Y,Y") @@ -11552,10 +11590,43 @@ (define_insn "stack_protect_testdi" (set (match_scratch:DI 4 "=r,r") (const_int 0)) (clobber (match_scratch:DI 3 "=&r,&r"))] "TARGET_64BIT" - "@ - ld%U1%X1 %3,%1\;ld%U2%X2 %4,%2\;xor. %3,%3,%4\;li %4,0 - ld%U1%X1 %3,%1\;ld%U2%X2 %4,%2\;cmpld %0,%3,%4\;li %3,0\;li %4,0" - [(set_attr "length" "16,20")]) +{ + if (prefixed_mem_operand (operands[1], DImode)) + output_asm_insn ("pld %3,%1", operands); + else + output_asm_insn ("ld%U1%X1 %3,%1", operands); + + if (prefixed_mem_operand (operands[2], DImode)) + output_asm_insn ("pld %4,%2", operands); + else + output_asm_insn ("ld%U2%X2 %4,%2", operands); + + if (which_alternative == 0) + output_asm_insn ("xor. %3,%3,%4", operands); + else + output_asm_insn ("cmpld %0,%3,%4\;li %3,0", operands); + + return "li %4,0"; +} + ;; Back to back prefixed memory instructions take 20 bytes (8 bytes for each + ;; prefixed instruction + 4 bytes for the possible NOP). + [(set (attr "length") + (cond [(and (match_operand 1 "prefixed_mem_operand") + (match_operand 2 "prefixed_mem_operand")) + (if_then_else (eq_attr "alternative" "0") + (const_string "28") + (const_string "32")) + + (ior (match_operand 1 "prefixed_mem_operand") + (match_operand 2 "prefixed_mem_operand")) + (if_then_else (eq_attr "alternative" "0") + (const_string "20") + (const_string "24"))] + + (if_then_else (eq_attr "alternative" "0") + (const_string "16") + (const_string "20")))) + (set_attr "prefixed" "no")]) ;; Here are the actual compare insns. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.ibm.com, phone: +1 (978) 899-4797