diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.md')
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 161 |
1 files changed, 135 insertions, 26 deletions
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 2c0b0491abe..15426d96f63 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -1672,7 +1672,7 @@ (const_int 0))) (set (match_operand:P 0 "gpc_reg_operand" "") (neg:P (match_dup 1)))] - "TARGET_32BIT && reload_completed" + "reload_completed" [(set (match_dup 0) (neg:P (match_dup 1))) (set (match_dup 2) @@ -7360,26 +7360,6 @@ ;; Now define ways of moving data around. -;; Elf specific ways of loading addresses for non-PIC code. -;; The output of this could be r0, but we make a very strong -;; preference for a base register because it will usually -;; be needed there. -(define_insn "elf_high" - [(set (match_operand:SI 0 "gpc_reg_operand" "=b*r") - (high:SI (match_operand 1 "" "")))] - "TARGET_ELF && ! TARGET_64BIT" - "{liu|lis} %0,%1@ha") - -(define_insn "elf_low" - [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") - (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b,!*r") - (match_operand 2 "" "")))] - "TARGET_ELF && ! TARGET_64BIT" - "@ - {cal|la} %0,%2@l(%1) - {ai|addic} %0,%1,%K2") - - ;; Set up a register with a value from the GOT table (define_expand "movsi_got" @@ -9810,7 +9790,8 @@ [(set (match_operand:SI 0 "register_operand" "=l") (match_operand:SI 1 "immediate_operand" "s")) (use (unspec [(match_dup 1)] UNSPEC_TOC))] - "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2" + "TARGET_ELF && DEFAULT_ABI != ABI_AIX + && (flag_pic == 2 || (flag_pic && TARGET_SECURE_PLT))" "bcl 20,31,%1\\n%1:" [(set_attr "type" "branch") (set_attr "length" "4")]) @@ -9833,6 +9814,22 @@ "{l|lwz} %0,%2-%3(%1)" [(set_attr "type" "load")]) +(define_insn "load_toc_v4_PIC_3b" + [(set (match_operand:SI 0 "gpc_reg_operand" "=b") + (plus:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (high:SI + (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s") + (match_operand:SI 3 "symbol_ref_operand" "s")))))] + "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic" + "{cau|addis} %0,%1,%2-%3@ha") + +(define_insn "load_toc_v4_PIC_3c" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b") + (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s") + (match_operand:SI 3 "symbol_ref_operand" "s"))))] + "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic" + "{cal|addi} %0,%1,%2-%3@l") ;; If the TOC is shared over a translation unit, as happens with all ;; the kinds of PIC that we support, we need to restore the TOC @@ -9867,6 +9864,25 @@ rs6000_emit_load_toc_table (FALSE); DONE; }") + +;; Elf specific ways of loading addresses for non-PIC code. +;; The output of this could be r0, but we make a very strong +;; preference for a base register because it will usually +;; be needed there. +(define_insn "elf_high" + [(set (match_operand:SI 0 "gpc_reg_operand" "=b*r") + (high:SI (match_operand 1 "" "")))] + "TARGET_ELF && ! TARGET_64BIT" + "{liu|lis} %0,%1@ha") + +(define_insn "elf_low" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b,!*r") + (match_operand 2 "" "")))] + "TARGET_ELF && ! TARGET_64BIT" + "@ + {cal|la} %0,%2@l(%1) + {ai|addic} %0,%1,%K2") ;; A function pointer under AIX is a pointer to a data area whose first word ;; contains the actual address of the function, whose second word contains a @@ -9983,6 +9999,25 @@ operands[0] = XEXP (operands[0], 0); + if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT + && flag_pic + && GET_CODE (operands[0]) == SYMBOL_REF + && !SYMBOL_REF_LOCAL_P (operands[0])) + { + rtx call; + rtvec tmp; + + tmp = gen_rtvec (3, + gen_rtx_CALL (VOIDmode, + gen_rtx_MEM (SImode, operands[0]), + operands[1]), + gen_rtx_USE (VOIDmode, operands[2]), + gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode))); + call = emit_call_insn (gen_rtx_PARALLEL (VOIDmode, tmp)); + use_reg (&CALL_INSN_FUNCTION_USAGE (call), pic_offset_table_rtx); + DONE; + } + if (GET_CODE (operands[0]) != SYMBOL_REF || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[0])) || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0)) @@ -10034,6 +10069,28 @@ operands[1] = XEXP (operands[1], 0); + if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT + && flag_pic + && GET_CODE (operands[1]) == SYMBOL_REF + && !SYMBOL_REF_LOCAL_P (operands[1])) + { + rtx call; + rtvec tmp; + + tmp = gen_rtvec (3, + gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_CALL (VOIDmode, + gen_rtx_MEM (SImode, + operands[1]), + operands[2])), + gen_rtx_USE (VOIDmode, operands[3]), + gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode))); + call = emit_call_insn (gen_rtx_PARALLEL (VOIDmode, tmp)); + use_reg (&CALL_INSN_FUNCTION_USAGE (call), pic_offset_table_rtx); + DONE; + } + if (GET_CODE (operands[1]) != SYMBOL_REF || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[1])) || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0)) @@ -10307,7 +10364,18 @@ #if TARGET_MACHO return output_call(insn, operands, 0, 2); #else - return (DEFAULT_ABI == ABI_V4 && flag_pic) ? "bl %z0@plt" : "bl %z0"; + if (DEFAULT_ABI == ABI_V4 && flag_pic) + { + if (TARGET_SECURE_PLT && flag_pic == 2) + /* The magic 32768 offset here and in the other sysv call insns + corresponds to the offset of r30 in .got2, as given by LCTOC1. + See sysv4.h:toc_section. */ + return "bl %z0+32768@plt"; + else + return "bl %z0@plt"; + } + else + return "bl %z0"; #endif } [(set_attr "type" "branch,branch") @@ -10352,7 +10420,15 @@ #if TARGET_MACHO return output_call(insn, operands, 1, 3); #else - return (DEFAULT_ABI == ABI_V4 && flag_pic) ? "bl %z1@plt" : "bl %z1"; + if (DEFAULT_ABI == ABI_V4 && flag_pic) + { + if (TARGET_SECURE_PLT && flag_pic == 2) + return "bl %z1+32768@plt"; + else + return "bl %z1@plt"; + } + else + return "bl %z1"; #endif } [(set_attr "type" "branch,branch") @@ -10567,7 +10643,15 @@ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) output_asm_insn (\"creqv 6,6,6\", operands); - return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z0@plt\" : \"b %z0\"; + if (DEFAULT_ABI == ABI_V4 && flag_pic) + { + if (TARGET_SECURE_PLT && flag_pic == 2) + return \"b %z0+32768@plt\"; + else + return \"b %z0@plt\"; + } + else + return \"b %z0\"; }" [(set_attr "type" "branch,branch") (set_attr "length" "4,8")]) @@ -10613,7 +10697,15 @@ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) output_asm_insn (\"creqv 6,6,6\", operands); - return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z1@plt\" : \"b %z1\"; + if (DEFAULT_ABI == ABI_V4 && flag_pic) + { + if (TARGET_SECURE_PLT && flag_pic == 2) + return \"b %z1+32768@plt\"; + else + return \"b %z1@plt\"; + } + else + return \"b %z1\"; }" [(set_attr "type" "branch,branch") (set_attr "length" "4,8")]) @@ -14776,6 +14868,23 @@ "<larx> %3,%y0\n\t%q4 %2,%1,%3\n\t<stcx> %2,%y0\n\tbne- $-12" [(set_attr "length" "16")]) +; This pattern could also take immediate values of operand 1, +; since the non-NOT version of the operator is used; but this is not +; very useful, since in practice operand 1 is a full 32-bit value. +; Likewise, operand 5 is in practice either <= 2^16 or it is a register. +(define_insn "*sync_boolcshort_internal" + [(set (match_operand:SI 2 "gpc_reg_operand" "=&r") + (match_operator:SI 4 "boolean_operator" + [(xor:SI (match_operand:SI 0 "memory_operand" "+Z") + (match_operand:SI 5 "logical_operand" "rK")) + (match_operand:SI 1 "gpc_reg_operand" "r")])) + (set (match_operand:SI 3 "gpc_reg_operand" "=&b") (match_dup 0)) + (set (match_dup 0) (unspec:SI [(match_dup 4)] UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 6 "=&x"))] + "TARGET_POWERPC" + "lwarx %3,%y0\n\txor%I2 %2,%3,%5\n\t%q4 %2,%2,%1\n\tstwcx. %2,%y0\n\tbne- $-16" + [(set_attr "length" "20")]) + (define_insn "*sync_boolc<mode>_internal2" [(set (match_operand:GPR 2 "gpc_reg_operand" "=&r") (match_operator:GPR 4 "boolean_operator" |