aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/s390
diff options
context:
space:
mode:
authorIlya Leoshkevich <iii@linux.ibm.com>2021-06-07 13:44:15 +0200
committerIlya Leoshkevich <iii@linux.ibm.com>2021-07-16 12:51:42 +0200
commit0990d93dd8a4268bff5bbe48aa26748cf63201c7 (patch)
tree0501bb3f68bbb3c83e743c49a9e5616f4f2a97d8 /gcc/config/s390
parentdf0d7486ec9bca8a77ca106d9fbb60f819dd9cec (diff)
downloadgcc-0990d93dd8a4268bff5bbe48aa26748cf63201c7.zip
gcc-0990d93dd8a4268bff5bbe48aa26748cf63201c7.tar.gz
gcc-0990d93dd8a4268bff5bbe48aa26748cf63201c7.tar.bz2
IBM Z: Use @PLT symbols for local functions in 64-bit mode
This helps with generating code for kernel hotpatches, which contain individual functions and are loaded more than 2G away from vmlinux. This should not create performance regressions for the normal use cases, because for local functions ld replaces @PLT calls with direct calls. gcc/ChangeLog: * config/s390/predicates.md (bras_sym_operand): Accept all functions in 64-bit mode, use UNSPEC_PLT31. (larl_operand): Use UNSPEC_PLT31. * config/s390/s390.c (s390_loadrelative_operand_p): Likewise. (legitimize_pic_address): Likewise. (s390_emit_tls_call_insn): Mark __tls_get_offset as function, use UNSPEC_PLT31. (s390_delegitimize_address): Use UNSPEC_PLT31. (s390_output_addr_const_extra): Likewise. (print_operand): Add @PLT to TLS calls, handle %K. (s390_function_profiler): Mark __fentry__/_mcount as function, use %K, use UNSPEC_PLT31. (s390_output_mi_thunk): Use only UNSPEC_GOT, use %K. (s390_emit_call): Use UNSPEC_PLT31. (s390_emit_tpf_eh_return): Mark __tpf_eh_return as function. * config/s390/s390.md (UNSPEC_PLT31): Rename from UNSPEC_PLT. (*movdi_64): Use %K. (reload_base_64): Likewise. (*sibcall_brc): Likewise. (*sibcall_brcl): Likewise. (*sibcall_value_brc): Likewise. (*sibcall_value_brcl): Likewise. (*bras): Likewise. (*brasl): Likewise. (*bras_r): Likewise. (*brasl_r): Likewise. (*bras_tls): Likewise. (*brasl_tls): Likewise. (main_base_64): Likewise. (reload_base_64): Likewise. (@split_stack_call<mode>): Likewise. gcc/testsuite/ChangeLog: * g++.dg/ext/visibility/noPLT.C: Skip on s390x. * g++.target/s390/mi-thunk.C: New test. * gcc.target/s390/nodatarel-1.c: Move foostatic to the new tests. * gcc.target/s390/pr80080-4.c: Allow @PLT suffix. * gcc.target/s390/risbg-ll-3.c: Likewise. * gcc.target/s390/call.h: Common code for the new tests. * gcc.target/s390/call-z10-pic-nodatarel.c: New test. * gcc.target/s390/call-z10-pic.c: New test. * gcc.target/s390/call-z10.c: New test. * gcc.target/s390/call-z9-pic-nodatarel.c: New test. * gcc.target/s390/call-z9-pic.c: New test. * gcc.target/s390/call-z9.c: New test. * gcc.target/s390/mfentry-m64-pic.c: New test. * gcc.target/s390/tls.h: Common code for the new TLS tests. * gcc.target/s390/tls-pic.c: New test. * gcc.target/s390/tls.c: New test.
Diffstat (limited to 'gcc/config/s390')
-rw-r--r--gcc/config/s390/predicates.md9
-rw-r--r--gcc/config/s390/s390.c81
-rw-r--r--gcc/config/s390/s390.md32
3 files changed, 79 insertions, 43 deletions
diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
index 15093cb..99c343a 100644
--- a/gcc/config/s390/predicates.md
+++ b/gcc/config/s390/predicates.md
@@ -101,10 +101,13 @@
(define_special_predicate "bras_sym_operand"
(ior (and (match_code "symbol_ref")
- (match_test "!flag_pic || SYMBOL_REF_LOCAL_P (op)"))
+ (ior (match_test "!flag_pic")
+ (match_test "SYMBOL_REF_LOCAL_P (op)")
+ (and (match_test "TARGET_64BIT")
+ (match_test "SYMBOL_REF_FUNCTION_P (op)"))))
(and (match_code "const")
(and (match_test "GET_CODE (XEXP (op, 0)) == UNSPEC")
- (match_test "XINT (XEXP (op, 0), 1) == UNSPEC_PLT")))))
+ (match_test "XINT (XEXP (op, 0), 1) == UNSPEC_PLT31")))))
;; Return true if OP is a PLUS that is not a legitimate
;; operand for the LA instruction.
@@ -197,7 +200,7 @@
&& XINT (op, 1) == UNSPEC_GOTENT)
return true;
if (GET_CODE (op) == UNSPEC
- && XINT (op, 1) == UNSPEC_PLT)
+ && XINT (op, 1) == UNSPEC_PLT31)
return true;
if (GET_CODE (op) == UNSPEC
&& XINT (op, 1) == UNSPEC_INDNTPOFF)
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 800e0ab..b1d3b99 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -3291,7 +3291,7 @@ s390_loadrelative_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend)
if (GET_CODE (addr) == SYMBOL_REF
|| (GET_CODE (addr) == UNSPEC
&& (XINT (addr, 1) == UNSPEC_GOTENT
- || XINT (addr, 1) == UNSPEC_PLT)))
+ || XINT (addr, 1) == UNSPEC_PLT31)))
{
if (symref)
*symref = addr;
@@ -4964,7 +4964,7 @@ legitimize_pic_address (rtx orig, rtx reg)
|| (SYMBOL_REF_P (addr) && s390_rel_address_ok_p (addr))
|| (GET_CODE (addr) == UNSPEC &&
(XINT (addr, 1) == UNSPEC_GOTENT
- || XINT (addr, 1) == UNSPEC_PLT)))
+ || XINT (addr, 1) == UNSPEC_PLT31)))
&& GET_CODE (addend) == CONST_INT)
{
/* This can be locally addressed. */
@@ -5125,7 +5125,7 @@ legitimize_pic_address (rtx orig, rtx reg)
/* For @PLT larl is used. This is handled like local
symbol refs. */
- case UNSPEC_PLT:
+ case UNSPEC_PLT31:
gcc_unreachable ();
break;
@@ -5191,7 +5191,10 @@ s390_emit_tls_call_insn (rtx result_reg, rtx tls_call)
emit_insn (s390_load_got ());
if (!s390_tls_symbol)
- s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
+ {
+ s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
+ SYMBOL_REF_FLAGS (s390_tls_symbol) |= SYMBOL_FLAG_FUNCTION;
+ }
insn = s390_emit_call (s390_tls_symbol, tls_call, result_reg,
gen_rtx_REG (Pmode, RETURN_REGNUM));
@@ -7596,7 +7599,7 @@ s390_delegitimize_address (rtx orig_x)
y = XEXP (x, 0);
if (GET_CODE (y) == UNSPEC
&& (XINT (y, 1) == UNSPEC_GOTENT
- || XINT (y, 1) == UNSPEC_PLT))
+ || XINT (y, 1) == UNSPEC_PLT31))
y = XVECEXP (y, 0, 0);
else
return orig_x;
@@ -7849,7 +7852,7 @@ s390_output_addr_const_extra (FILE *file, rtx x)
output_addr_const (file, XVECEXP (x, 0, 0));
fprintf (file, "@GOTOFF");
return true;
- case UNSPEC_PLT:
+ case UNSPEC_PLT31:
output_addr_const (file, XVECEXP (x, 0, 0));
fprintf (file, "@PLT");
return true;
@@ -7943,6 +7946,7 @@ print_operand_address (FILE *file, rtx addr)
'E': print opcode suffix for branch on index instruction.
'G': print the size of the operand in bytes.
'J': print tls_load/tls_gdcall/tls_ldcall suffix
+ 'K': print @PLT suffix for call targets and load address values.
'M': print the second word of a TImode operand.
'N': print the second word of a DImode operand.
'O': print only the displacement of a memory reference or address.
@@ -8129,6 +8133,29 @@ print_operand (FILE *file, rtx x, int code)
case 'Y':
print_shift_count_operand (file, x);
return;
+
+ case 'K':
+ /* Append @PLT to both local and non-local symbols in order to support
+ Linux Kernel livepatching: patches contain individual functions and
+ are loaded further than 2G away from vmlinux, and therefore they must
+ call even static functions via PLT. ld will optimize @PLT away for
+ normal code, and keep it for patches.
+
+ Do not indiscriminately add @PLT in 31-bit mode due to the %r12
+ restriction, use UNSPEC_PLT31 instead.
+
+ @PLT only makes sense for functions, data is taken care of by
+ -mno-pic-data-is-text-relative.
+
+ Adding @PLT interferes with handling of weak symbols in non-PIC code,
+ since their addresses are loaded with larl, which then always produces
+ a non-NULL result, so skip them here as well. */
+ if (TARGET_64BIT
+ && GET_CODE (x) == SYMBOL_REF
+ && SYMBOL_REF_FUNCTION_P (x)
+ && !(SYMBOL_REF_WEAK (x) && !flag_pic))
+ fprintf (file, "@PLT");
+ return;
}
switch (GET_CODE (x))
@@ -13125,9 +13152,10 @@ s390_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
op[3] = GEN_INT (UNITS_PER_LONG);
op[2] = gen_rtx_SYMBOL_REF (Pmode, flag_fentry ? "__fentry__" : "_mcount");
- if (flag_pic)
+ SYMBOL_REF_FLAGS (op[2]) |= SYMBOL_FLAG_FUNCTION;
+ if (flag_pic && !TARGET_64BIT)
{
- op[2] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[2]), UNSPEC_PLT);
+ op[2] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[2]), UNSPEC_PLT31);
op[2] = gen_rtx_CONST (Pmode, op[2]);
}
@@ -13142,7 +13170,7 @@ s390_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
warning (OPT_Wcannot_profile, "nested functions cannot be profiled "
"with %<-mfentry%> on s390");
else
- output_asm_insn ("brasl\t0,%2", op);
+ output_asm_insn ("brasl\t0,%2%K2", op);
}
else if (TARGET_64BIT)
{
@@ -13154,7 +13182,7 @@ s390_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
output_asm_insn ("stg\t%0,%1", op);
if (flag_dwarf2_cfi_asm)
output_asm_insn (".cfi_rel_offset\t%0,%3", op);
- output_asm_insn ("brasl\t%0,%2", op);
+ output_asm_insn ("brasl\t%0,%2%K2", op);
output_asm_insn ("lg\t%0,%1", op);
if (flag_dwarf2_cfi_asm)
output_asm_insn (".cfi_restore\t%0", op);
@@ -13170,7 +13198,7 @@ s390_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
output_asm_insn ("st\t%0,%1", op);
if (flag_dwarf2_cfi_asm)
output_asm_insn (".cfi_rel_offset\t%0,%3", op);
- output_asm_insn ("brasl\t%0,%2", op);
+ output_asm_insn ("brasl\t%0,%2%K2", op);
output_asm_insn ("l\t%0,%1", op);
if (flag_dwarf2_cfi_asm)
output_asm_insn (".cfi_restore\t%0", op);
@@ -13246,9 +13274,11 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
if (flag_pic && !SYMBOL_REF_LOCAL_P (op[0]))
{
nonlocal = 1;
- op[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[0]),
- TARGET_64BIT ? UNSPEC_PLT : UNSPEC_GOT);
- op[0] = gen_rtx_CONST (Pmode, op[0]);
+ if (!TARGET_64BIT)
+ {
+ op[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[0]), UNSPEC_GOT);
+ op[0] = gen_rtx_CONST (Pmode, op[0]);
+ }
}
/* Operand 1 is the 'this' pointer. */
@@ -13338,7 +13368,7 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
}
/* Jump to target. */
- output_asm_insn ("jg\t%0", op);
+ output_asm_insn ("jg\t%0%K0", op);
/* Output literal pool if required. */
if (op[5])
@@ -13729,7 +13759,7 @@ rtx_insn *
s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg,
rtx retaddr_reg)
{
- bool plt_call = false;
+ bool plt31_call_p = false;
rtx_insn *insn;
rtx vec[4] = { NULL_RTX };
int elts = 0;
@@ -13744,15 +13774,15 @@ s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg,
{
/* When calling a global routine in PIC mode, we must
replace the symbol itself with the PLT stub. */
- if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location))
+ if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location) && !TARGET_64BIT)
{
- if (TARGET_64BIT || retaddr_reg != NULL_RTX)
+ if (retaddr_reg != NULL_RTX)
{
addr_location = gen_rtx_UNSPEC (Pmode,
gen_rtvec (1, addr_location),
- UNSPEC_PLT);
+ UNSPEC_PLT31);
addr_location = gen_rtx_CONST (Pmode, addr_location);
- plt_call = true;
+ plt31_call_p = true;
}
else
/* For -fpic code the PLT entries might use r12 which is
@@ -13773,7 +13803,7 @@ s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg,
register 1. */
if (retaddr_reg == NULL_RTX
&& GET_CODE (addr_location) != SYMBOL_REF
- && !plt_call)
+ && !plt31_call_p)
{
emit_move_insn (gen_rtx_REG (Pmode, SIBCALL_REGNUM), addr_location);
addr_location = gen_rtx_REG (Pmode, SIBCALL_REGNUM);
@@ -13781,7 +13811,7 @@ s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg,
if (TARGET_INDIRECT_BRANCH_NOBP_CALL
&& GET_CODE (addr_location) != SYMBOL_REF
- && !plt_call)
+ && !plt31_call_p)
{
/* Indirect branch thunks require the target to be a single GPR. */
addr_location = force_reg (Pmode, addr_location);
@@ -13833,7 +13863,7 @@ s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg,
insn = emit_call_insn (*call);
/* 31-bit PLT stubs and tls calls use the GOT register implicitly. */
- if ((!TARGET_64BIT && plt_call) || tls_call != NULL_RTX)
+ if (plt31_call_p || tls_call != NULL_RTX)
{
/* s390_function_ok_for_sibcall should
have denied sibcalls in this case. */
@@ -13889,7 +13919,10 @@ s390_emit_tpf_eh_return (rtx target)
rtx reg, orig_ra;
if (!s390_tpf_eh_return_symbol)
- s390_tpf_eh_return_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tpf_eh_return");
+ {
+ s390_tpf_eh_return_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tpf_eh_return");
+ SYMBOL_REF_FLAGS (s390_tpf_eh_return_symbol) |= SYMBOL_FLAG_FUNCTION;
+ }
reg = gen_rtx_REG (Pmode, 2);
orig_ra = gen_rtx_REG (Pmode, 3);
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 0c5b4dc..8ad21b0 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -79,7 +79,7 @@
UNSPEC_GOTENT
UNSPEC_GOT
UNSPEC_GOTOFF
- UNSPEC_PLT
+ UNSPEC_PLT31
UNSPEC_PLTOFF
; Literal pool
@@ -1906,7 +1906,7 @@
vlgvg\t%0,%v1,0
vleg\t%v0,%1,0
vsteg\t%v1,%0,0
- larl\t%0,%1"
+ larl\t%0,%1%K1"
[(set_attr "op_type" "RI,RI,RI,RI,RI,RIL,RIL,RIL,RRE,RRE,RRE,RXY,RIL,RRE,RXY,
RXY,RR,RX,RXY,RX,RXY,RIL,SIL,*,*,RS,RS,VRI,VRR,VRS,VRS,
VRX,VRX,RIL")
@@ -2180,7 +2180,7 @@
(match_operand:SI 1 "larl_operand" "X"))]
"!TARGET_64BIT
&& !FP_REG_P (operands[0])"
- "larl\t%0,%1"
+ "larl\t%0,%1%K1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")
(set_attr "z10prop" "z10_fwd_A1")
@@ -10373,7 +10373,7 @@
[(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
(match_operand 1 "const_int_operand" "n"))]
"SIBLING_CALL_P (insn) && TARGET_SMALL_EXEC"
- "j\t%0"
+ "j\t%0%K0"
[(set_attr "op_type" "RI")
(set_attr "type" "branch")])
@@ -10381,7 +10381,7 @@
[(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
(match_operand 1 "const_int_operand" "n"))]
"SIBLING_CALL_P (insn)"
- "jg\t%0"
+ "jg\t%0%K0"
[(set_attr "op_type" "RIL")
(set_attr "type" "branch")])
@@ -10434,7 +10434,7 @@
(call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
(match_operand 2 "const_int_operand" "n")))]
"SIBLING_CALL_P (insn) && TARGET_SMALL_EXEC"
- "j\t%1"
+ "j\t%1%K1"
[(set_attr "op_type" "RI")
(set_attr "type" "branch")])
@@ -10443,7 +10443,7 @@
(call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
(match_operand 2 "const_int_operand" "n")))]
"SIBLING_CALL_P (insn)"
- "jg\t%1"
+ "jg\t%1%K1"
[(set_attr "op_type" "RIL")
(set_attr "type" "branch")])
@@ -10470,7 +10470,7 @@
"!SIBLING_CALL_P (insn)
&& TARGET_SMALL_EXEC
&& GET_MODE (operands[2]) == Pmode"
- "bras\t%2,%0"
+ "bras\t%2,%0%K0"
[(set_attr "op_type" "RI")
(set_attr "type" "jsr")
(set_attr "z196prop" "z196_cracked")])
@@ -10482,7 +10482,7 @@
"!SIBLING_CALL_P (insn)
&& GET_MODE (operands[2]) == Pmode"
- "brasl\t%2,%0"
+ "brasl\t%2,%0%K0"
[(set_attr "op_type" "RIL")
(set_attr "type" "jsr")
(set_attr "z196prop" "z196_cracked")
@@ -10576,7 +10576,7 @@
"!SIBLING_CALL_P (insn)
&& TARGET_SMALL_EXEC
&& GET_MODE (operands[3]) == Pmode"
- "bras\t%3,%1"
+ "bras\t%3,%1%K1"
[(set_attr "op_type" "RI")
(set_attr "type" "jsr")
(set_attr "z196prop" "z196_cracked")])
@@ -10589,7 +10589,7 @@
"!SIBLING_CALL_P (insn)
&& GET_MODE (operands[3]) == Pmode"
- "brasl\t%3,%1"
+ "brasl\t%3,%1%K1"
[(set_attr "op_type" "RIL")
(set_attr "type" "jsr")
(set_attr "z196prop" "z196_cracked")
@@ -10720,7 +10720,7 @@
"!SIBLING_CALL_P (insn)
&& TARGET_SMALL_EXEC
&& GET_MODE (operands[3]) == Pmode"
- "bras\t%3,%1%J4"
+ "bras\t%3,%1%K1%J4"
[(set_attr "op_type" "RI")
(set_attr "type" "jsr")
(set_attr "z196prop" "z196_cracked")])
@@ -10734,7 +10734,7 @@
"!SIBLING_CALL_P (insn)
&& GET_MODE (operands[3]) == Pmode"
- "brasl\t%3,%1%J4"
+ "brasl\t%3,%1%K1%J4"
[(set_attr "op_type" "RIL")
(set_attr "type" "jsr")
(set_attr "z196prop" "z196_cracked")
@@ -11343,7 +11343,7 @@
[(set (match_operand 0 "register_operand" "=a")
(unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))]
"GET_MODE (operands[0]) == Pmode"
- "larl\t%0,%1"
+ "larl\t%0,%1%K1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")
(set_attr "z10prop" "z10_fwd_A1")
@@ -11363,7 +11363,7 @@
[(set (match_operand 0 "register_operand" "=a")
(unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_RELOAD_BASE))]
"GET_MODE (operands[0]) == Pmode"
- "larl\t%0,%1"
+ "larl\t%0,%1%K1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")
(set_attr "z10prop" "z10_fwd_A1")])
@@ -12220,7 +12220,7 @@
""
{
s390_output_split_stack_data (operands[1], operands[2], operands[3], operands[4]);
- return "jg\t%0";
+ return "jg\t%0%K0";
}
[(set_attr "op_type" "RIL")
(set_attr "type" "branch")])