From efdba735bef6fc3c86df8e37bdfd17525f32ca8c Mon Sep 17 00:00:00 2001 From: Stuart Hastings Date: Fri, 5 Dec 2003 00:44:57 +0000 Subject: [PATCH] 2003-12-04 Stuart Hastings * rs6000.c (output_call, macho_branch_islands, add_compiler_branch_island, no_previous_def, get_previous_label) Revisions of xx_stub functions for branch islands, add -fPIC support for Darwin. * rs6000-protos.h (output_call) Prototype. * rs6000.md Use output_call. * invoke.texi Explain Darwin semantics of -longcall. * testsuite/gcc.dg/darwin-abi-1.c Revise testcase for -longcall/jbsr. From-SVN: r74302 --- gcc/ChangeLog | 11 ++ gcc/config/rs6000/rs6000-protos.h | 4 + gcc/config/rs6000/rs6000.c | 196 ++++++++++++++++++++++-------------- gcc/config/rs6000/rs6000.md | 24 +++-- gcc/doc/invoke.texi | 4 + gcc/testsuite/gcc.dg/darwin-abi-1.c | 2 +- 6 files changed, 158 insertions(+), 83 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f85c136..428e954 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2003-12-04 Stuart Hastings + + * rs6000.c (output_call, macho_branch_islands, + add_compiler_branch_island, no_previous_def, get_previous_label) + Revisions of xx_stub functions for branch islands, + add -fPIC support for Darwin. + * rs6000-protos.h (output_call) Prototype. + * rs6000.md Use output_call. + * invoke.texi Explain Darwin semantics of -longcall. + * testsuite/gcc.dg/darwin-abi-1.c Revise testcase for -longcall/jbsr. + 2003-12-04 Richard Henderson * config/i386/i386.md (addqi3_carry): Use q not r constraints. diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index ed13c34..57fca19 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -201,4 +201,8 @@ extern int rs6000_tls_symbol_ref (rtx, enum machine_mode); extern void rs6000_pragma_longcall (struct cpp_reader *); extern void rs6000_cpu_cpp_builtins (struct cpp_reader *); +#if TARGET_MACHO +char *output_call (rtx, rtx *, int, int); +#endif + #endif /* rs6000-protos.h */ diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 8a7e0e6..cc62bc5 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -399,6 +399,13 @@ static void rs6000_move_block_from_reg(int regno, rtx x, int nregs); static void setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int); +#if TARGET_MACHO +static void macho_branch_islands (void); +static void add_compiler_branch_island (tree, tree, int); +static int no_previous_def (tree function_name); +static tree get_prev_label (tree function_name); +#endif + static tree rs6000_build_builtin_va_list (void); /* Hash table stuff for keeping track of TOC entries. */ @@ -12432,7 +12439,8 @@ rs6000_output_function_epilogue (FILE *file, } } -#if TARGET_OBJECT_FORMAT == OBJECT_MACHO +#if TARGET_MACHO + macho_branch_islands (); /* Mach-O doesn't support labels at the end of objects, so if it looks like we might want one, insert a NOP. */ { @@ -14719,83 +14727,118 @@ symbolic_operand (rtx op) } #endif -#ifdef RS6000_LONG_BRANCH +#if TARGET_MACHO -static tree stub_list = 0; +static tree branch_island_list = 0; -/* ADD_COMPILER_STUB adds the compiler generated stub for handling - procedure calls to the linked list. */ +/* Remember to generate a branch island for far calls to the given + function. */ -void -add_compiler_stub (tree label_name, tree function_name, int line_number) +static void +add_compiler_branch_island (tree label_name, tree function_name, int line_number) { - tree stub = build_tree_list (function_name, label_name); - TREE_TYPE (stub) = build_int_2 (line_number, 0); - TREE_CHAIN (stub) = stub_list; - stub_list = stub; + tree branch_island = build_tree_list (function_name, label_name); + TREE_TYPE (branch_island) = build_int_2 (line_number, 0); + TREE_CHAIN (branch_island) = branch_island_list; + branch_island_list = branch_island; } -#define STUB_LABEL_NAME(STUB) TREE_VALUE (STUB) -#define STUB_FUNCTION_NAME(STUB) TREE_PURPOSE (STUB) -#define STUB_LINE_NUMBER(STUB) TREE_INT_CST_LOW (TREE_TYPE (STUB)) - -/* OUTPUT_COMPILER_STUB outputs the compiler generated stub for - handling procedure calls from the linked list and initializes the - linked list. */ - -void -output_compiler_stub (void) -{ - char tmp_buf[256]; - char label_buf[256]; - tree stub; +#define BRANCH_ISLAND_LABEL_NAME(BRANCH_ISLAND) TREE_VALUE (BRANCH_ISLAND) +#define BRANCH_ISLAND_FUNCTION_NAME(BRANCH_ISLAND) TREE_PURPOSE (BRANCH_ISLAND) +#define BRANCH_ISLAND_LINE_NUMBER(BRANCH_ISLAND) \ + TREE_INT_CST_LOW (TREE_TYPE (BRANCH_ISLAND)) - if (!flag_pic) - for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) - { - fprintf (asm_out_file, - "%s:\n", IDENTIFIER_POINTER(STUB_LABEL_NAME(stub))); +/* Generate far-jump branch islands for everything on the + branch_island_list. Invoked immediately after the last instruction + of the epilogue has been emitted; the branch-islands must be + appended to, and contiguous with, the function body. Mach-O stubs + are generated in machopic_output_stub(). */ +static void +macho_branch_islands (void) +{ + char tmp_buf[512]; + tree branch_island; + + for (branch_island = branch_island_list; + branch_island; + branch_island = TREE_CHAIN (branch_island)) + { + const char *label = + IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island)); + const char *name = + darwin_strip_name_encoding ( + IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island))); + char name_buf[512]; + /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF(). */ + if (name[0] == '*' || name[0] == '&') + strcpy (name_buf, name+1); + else + { + name_buf[0] = '_'; + strcpy (name_buf+1, name); + } + strcpy (tmp_buf, "\n"); + strcat (tmp_buf, label); #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) - if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) - fprintf (asm_out_file, "\t.stabd 68,0,%d\n", STUB_LINE_NUMBER(stub)); + if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + fprintf (asm_out_file, "\t.stabd 68,0,%lu\n", + BRANCH_ISLAND_LINE_NUMBER(branch_island)); #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ - - if (IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))[0] == '*') - strcpy (label_buf, - IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))+1); - else - { - label_buf[0] = '_'; - strcpy (label_buf+1, - IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))); - } - - strcpy (tmp_buf, "lis r12,hi16("); - strcat (tmp_buf, label_buf); - strcat (tmp_buf, ")\n\tori r12,r12,lo16("); - strcat (tmp_buf, label_buf); - strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr"); - output_asm_insn (tmp_buf, 0); - + if (flag_pic) + { + strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,"); + strcat (tmp_buf, label); + strcat (tmp_buf, "_pic\n"); + strcat (tmp_buf, label); + strcat (tmp_buf, "_pic:\n\tmflr r11\n"); + + strcat (tmp_buf, "\taddis r11,r11,ha16("); + strcat (tmp_buf, name_buf); + strcat (tmp_buf, " - "); + strcat (tmp_buf, label); + strcat (tmp_buf, "_pic)\n"); + + strcat (tmp_buf, "\tmtlr r0\n"); + + strcat (tmp_buf, "\taddi r12,r11,lo16("); + strcat (tmp_buf, name_buf); + strcat (tmp_buf, " - "); + strcat (tmp_buf, label); + strcat (tmp_buf, "_pic)\n"); + + strcat (tmp_buf, "\tmtctr r12\n\tbctr\n"); + } + else + { + strcat (tmp_buf, ":\nlis r12,hi16("); + strcat (tmp_buf, name_buf); + strcat (tmp_buf, ")\n\tori r12,r12,lo16("); + strcat (tmp_buf, name_buf); + strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr"); + } + output_asm_insn (tmp_buf, 0); #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) - if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) - fprintf(asm_out_file, "\t.stabd 68,0,%d\n", STUB_LINE_NUMBER (stub)); + if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + fprintf(asm_out_file, "\t.stabd 68,0,%lu\n", + BRANCH_ISLAND_LINE_NUMBER (branch_island)); #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ - } + } - stub_list = 0; + branch_island_list = 0; } /* NO_PREVIOUS_DEF checks in the link list whether the function name is already there or not. */ -int +static int no_previous_def (tree function_name) { - tree stub; - for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) - if (function_name == STUB_FUNCTION_NAME (stub)) + tree branch_island; + for (branch_island = branch_island_list; + branch_island; + branch_island = TREE_CHAIN (branch_island)) + if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island)) return 0; return 1; } @@ -14803,13 +14846,15 @@ no_previous_def (tree function_name) /* GET_PREV_LABEL gets the label name from the previous definition of the function. */ -tree +static tree get_prev_label (tree function_name) { - tree stub; - for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) - if (function_name == STUB_FUNCTION_NAME (stub)) - return STUB_LABEL_NAME (stub); + tree branch_island; + for (branch_island = branch_island_list; + branch_island; + branch_island = TREE_CHAIN (branch_island)) + if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island)) + return BRANCH_ISLAND_LABEL_NAME (branch_island); return 0; } @@ -14819,13 +14864,14 @@ get_prev_label (tree function_name) CALL_DEST is the routine we are calling. */ char * -output_call (rtx insn, rtx call_dest, int operand_number) +output_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operand_number) { static char buf[256]; - if (GET_CODE (call_dest) == SYMBOL_REF && TARGET_LONG_BRANCH && !flag_pic) + if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF + && (INTVAL (operands[cookie_operand_number]) & CALL_LONG)) { tree labelname; - tree funname = get_identifier (XSTR (call_dest, 0)); + tree funname = get_identifier (XSTR (operands[dest_operand_number], 0)); if (no_previous_def (funname)) { @@ -14839,23 +14885,25 @@ output_call (rtx insn, rtx call_dest, int operand_number) for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn)); if (insn) line_number = NOTE_LINE_NUMBER (insn); - add_compiler_stub (labelname, funname, line_number); + add_compiler_branch_island (labelname, funname, line_number); } else labelname = get_prev_label (funname); + /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl' + instruction will reach 'foo', otherwise link as 'bl L42'". + "L42" should be a 'branch island', that will do a far jump to + 'foo'. Branch islands are generated in + macho_branch_islands(). */ sprintf (buf, "jbsr %%z%d,%.246s", - operand_number, IDENTIFIER_POINTER (labelname)); - return buf; + dest_operand_number, IDENTIFIER_POINTER (labelname)); } else - { - sprintf (buf, "bl %%z%d", operand_number); - return buf; - } + sprintf (buf, "bl %%z%d", dest_operand_number); + return buf; } -#endif /* RS6000_LONG_BRANCH */ +#endif /* TARGET_MACHO */ /* Generate PIC and indirect symbol stubs. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 5c2beea..14a42c9 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -10273,7 +10273,7 @@ if (GET_CODE (operands[0]) != SYMBOL_REF || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[0])) - || (INTVAL (operands[2]) & CALL_LONG) != 0) + || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0)) { if (INTVAL (operands[2]) & CALL_LONG) operands[0] = rs6000_longcall_ref (operands[0]); @@ -10321,7 +10321,7 @@ if (GET_CODE (operands[1]) != SYMBOL_REF || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[1])) - || (INTVAL (operands[3]) & CALL_LONG) != 0) + || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0)) { if (INTVAL (operands[3]) & CALL_LONG) operands[1] = rs6000_longcall_ref (operands[1]); @@ -10576,9 +10576,9 @@ (match_operand 1 "" "g,g")) (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] - "(DEFAULT_ABI == ABI_V4 - || DEFAULT_ABI == ABI_DARWIN) - && (INTVAL (operands[2]) & CALL_LONG) == 0" + "(DEFAULT_ABI == ABI_DARWIN + || (DEFAULT_ABI == ABI_V4 + && (INTVAL (operands[2]) & CALL_LONG) == 0))" { if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) output_asm_insn ("crxor 6,6,6", operands); @@ -10586,7 +10586,11 @@ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) output_asm_insn ("creqv 6,6,6", operands); +#ifdef TARGET_MACHO + return output_call(insn, operands, 0, 2); +#else return (DEFAULT_ABI == ABI_V4 && flag_pic) ? "bl %z0@plt" : "bl %z0"; +#endif } [(set_attr "type" "branch,branch") (set_attr "length" "4,8")]) @@ -10617,9 +10621,9 @@ (match_operand 2 "" "g,g"))) (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] - "(DEFAULT_ABI == ABI_V4 - || DEFAULT_ABI == ABI_DARWIN) - && (INTVAL (operands[3]) & CALL_LONG) == 0" + "(DEFAULT_ABI == ABI_DARWIN + || (DEFAULT_ABI == ABI_V4 + && (INTVAL (operands[3]) & CALL_LONG) == 0))" { if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) output_asm_insn ("crxor 6,6,6", operands); @@ -10627,7 +10631,11 @@ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) output_asm_insn ("creqv 6,6,6", operands); +#ifdef TARGET_MACHO + return output_call(insn, operands, 1, 3); +#else return (DEFAULT_ABI == ABI_V4 && flag_pic) ? "bl %z1@plt" : "bl %z1"; +#endif } [(set_attr "type" "branch,branch") (set_attr "length" "4,8")]) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index a195d08..d8e63fb 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -7784,6 +7784,10 @@ generate slower code. As of this writing, the AIX linker can do this, as can the GNU linker for PowerPC/64. It is planned to add this feature to the GNU linker for 32-bit PowerPC systems as well. +On Mach-O (Darwin) systems, this option directs the compiler emit to +the glue for every direct call, and the Darwin linker decides whether +to use or discard it. + In the future, we may cause GCC to ignore all longcall specifications when the linker is known to generate glue. diff --git a/gcc/testsuite/gcc.dg/darwin-abi-1.c b/gcc/testsuite/gcc.dg/darwin-abi-1.c index c7c0288..3b13c62 100644 --- a/gcc/testsuite/gcc.dg/darwin-abi-1.c +++ b/gcc/testsuite/gcc.dg/darwin-abi-1.c @@ -1,6 +1,6 @@ /* { dg-do compile { target powerpc*-*-darwin* } } */ /* { dg-options "-O" } */ -/* { dg-final { scan-assembler "li r3,12345\n\tbl " } } */ +/* { dg-final { scan-assembler "li r3,12345\n\t(bl|jbsr) " } } */ /* Check that zero-size structures don't affect parameter passing. */ -- 2.7.4