Subversion r263265 (Git commit
77e0a97acf7b00c1e68e4738fdf275a4cffc2e50)
"[nvptx] Ignore c++ exceptions", originally had set 'UI_TARGET', but as part of
Subversion r263287 (Git commit
d989dba8ef02c2406b7c9e62b352197dffc6b880)
"[c++] Don't emit exception tables for UI_NONE", then switched to 'UI_NONE'.
I understand the intention of using 'UI_NONE' like this, and it happens to work
in a lot of cases, but there are ICEs elsewhere: code paths where we run into
'internal compiler error: in get_personality_function, at expr.cc:13512':
13494 /* Extracts the personality function of DECL and returns the corresponding
13495 libfunc. */
13496
13497 rtx
13498 get_personality_function (tree decl)
13499 {
13500 tree personality = DECL_FUNCTION_PERSONALITY (decl);
13501 enum eh_personality_kind pk;
13502
13503 pk = function_needs_eh_personality (DECL_STRUCT_FUNCTION (decl));
13504 if (pk == eh_personality_none)
13505 return NULL;
13506
13507 if (!personality
13508 && pk == eh_personality_any)
13509 personality = lang_hooks.eh_personality ();
13510
13511 if (pk == eh_personality_lang)
13512 gcc_assert (personality != NULL_TREE);
13513
13514 return XEXP (DECL_RTL (personality), 0);
13515 }
..., where 'lang_hooks.eh_personality ()' ends up calling
'gcc/expr.cc:build_personality_function', and we 'return NULL;' for 'UI_NONE':
13448 /* Build a decl for a personality function given a language prefix. */
13449
13450 tree
13451 build_personality_function (const char *lang)
13452 {
13453 const char *unwind_and_version;
13454 tree decl, type;
13455 char *name;
13456
13457 switch (targetm_common.except_unwind_info (&global_options))
13458 {
13459 case UI_NONE:
13460 return NULL;
[...]
(Comparing to nvptx' current use of 'UI_NONE', this problem (ICEs mentioned
above) is way more prevalent for GCN.)
The GCC internals documentation indeed states, 'gcc/doc/tm.texi':
@deftypefn {Common Target Hook} {enum unwind_info_type} TARGET_EXCEPT_UNWIND_INFO (struct gcc_options *@var{opts})
This hook defines the mechanism that will be used for exception handling
by the target. If the target has ABI specified unwind tables, the hook
should return @code{UI_TARGET}. If the target is to use the
@code{setjmp}/@code{longjmp}-based exception handling scheme, the hook
should return @code{UI_SJLJ}. If the target supports DWARF 2 frame unwind
information, the hook should return @code{UI_DWARF2}.
A target may, if exceptions are disabled, choose to return @code{UI_NONE}.
This may end up simplifying other parts of target-specific code. [...]
Here, note: "if exceptions are disabled" (meaning: '-fno-exceptions' etc.) may
"return @code{UI_NONE}". That's what other back ends do with code like:
/* For simplicity elsewhere in this file, indicate that all unwind
info is disabled if we're not emitting unwind tables. */
if (!opts->x_flag_exceptions && !opts->x_flag_unwind_tables)
return UI_NONE;
else
return UI_TARGET;
The corresponding "simplifying other parts of target-specific code"/
"simplicity elsewhere" would then be the early returns from
'TARGET_ASM_UNWIND_EMIT', 'ARM_OUTPUT_FN_UNWIND', etc. for
'TARGET_EXCEPT_UNWIND_INFO != UI_TARGET' (that is, for 'UI_NONE').
From the documentation (and implementation), however, it does *not* follow that
if a target doesn't implement support for exception handling, it may just set
'UI_NONE' for 'TARGET_EXCEPT_UNWIND_INFO'.
Therefore, switch (back) to 'UI_TARGET', implementing some basic support for
'exception_section': discard (via a PTX comment block) whatever GCC writes into
it.
With that, all these 'internal compiler error: in get_personality_function'
test cases turn into PASS, or UNSUPPORTED ('exception handling not supported'),
or re-classify into a few other, already known issues.
(In case that use of 'UI_NONE' like originally intended really makes sense, and
is preferable over this 'UI_TARGET' solution, then more work will be necessary
for implementing the missing parts, where 'UI_NONE' currently isn't handled.)
PR target/86660
gcc/
* common/config/nvptx/nvptx-common.cc (nvptx_except_unwind_info):
'return UI_TARGET;'.
* config/nvptx/nvptx.cc (nvptx_assemble_integer): Handle
'exception_section'.
(nvptx_output_section_asm_op, nvptx_asm_init_sections): New
functions.
(TARGET_ASM_INIT_SECTIONS): '#define'.
* config/nvptx/nvptx.h (TEXT_SECTION_ASM_OP, DATA_SECTION_ASM_OP):
Don't '#define'.
(ASM_OUTPUT_DWARF_DELTA): '#define'.
enum unwind_info_type
nvptx_except_unwind_info (struct gcc_options *opts ATTRIBUTE_UNUSED)
{
- return UI_NONE;
+ return UI_TARGET;
}
#undef TARGET_HAVE_NAMED_SECTIONS
static bool
nvptx_assemble_integer (rtx x, unsigned int size, int ARG_UNUSED (aligned_p))
{
+ if (in_section == exception_section)
+ {
+ gcc_checking_assert (!init_frag.active);
+ /* Just use the default machinery; it's not getting used, anyway. */
+ return default_assemble_integer (x, size, aligned_p);
+ }
+
gcc_checking_assert (init_frag.active);
HOST_WIDE_INT val = 0;
}
}
+/* Fake "sections support", just for 'exception_section'. */
+
+static void
+nvptx_output_section_asm_op (const char *directive)
+{
+ static char prev_section = '?';
+
+ gcc_checking_assert (directive[1] == '\0');
+ const char new_section = directive[0];
+ gcc_checking_assert (new_section != prev_section);
+ switch (new_section)
+ {
+ case 'T':
+ case 'D':
+ if (prev_section == 'E')
+ /* We're leaving the 'exception_section'. End the comment block. */
+ fprintf (asm_out_file, "\tEND '.gcc_except_table' */\n");
+ break;
+ case 'E':
+ /* We're entering the 'exception_section'. Put into a comment block
+ whatever GCC decides to emit. We assume:
+ - No nested comment blocks.
+ - Going to leave 'exception_section' before end of file.
+ Should any of these ever get violated, this will result in PTX-level
+ syntax errors. */
+ fprintf (asm_out_file, "\t/* BEGIN '.gcc_except_table'\n");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ prev_section = new_section;
+}
+
+static void
+nvptx_asm_init_sections (void)
+{
+ /* Like '#define TEXT_SECTION_ASM_OP ""', just with different 'callback'. */
+ text_section = get_unnamed_section (SECTION_CODE,
+ nvptx_output_section_asm_op, "T");
+ /* Like '#define DATA_SECTION_ASM_OP ""', just with different 'callback'. */
+ data_section = get_unnamed_section (SECTION_WRITE,
+ nvptx_output_section_asm_op, "D");
+ /* In order to later be able to recognize the 'exception_section', we set it
+ up here, instead of letting 'gcc/except.cc:switch_to_exception_section'
+ pick the 'data_section'. */
+ exception_section = get_unnamed_section (0,
+ nvptx_output_section_asm_op, "E");
+}
+
/* Implement TARGET_ASM_FILE_START. Write the kinds of things ptxas expects
at the start of a file. */
#undef TARGET_END_CALL_ARGS
#define TARGET_END_CALL_ARGS nvptx_end_call_args
+#undef TARGET_ASM_INIT_SECTIONS
+#define TARGET_ASM_INIT_SECTIONS nvptx_asm_init_sections
#undef TARGET_ASM_FILE_START
#define TARGET_ASM_FILE_START nvptx_file_start
#undef TARGET_ASM_FILE_END
#define DEBUGGER_REGNO(N) N
-#define TEXT_SECTION_ASM_OP ""
-#define DATA_SECTION_ASM_OP ""
-
#undef ASM_GENERATE_INTERNAL_LABEL
#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \
do \
Tell it to instead link against the innocuous libgcc. */
#define LIBSTDCXX "gcc"
+/* The default doesn't fly ('internal compiler error: in simplify_subreg' when
+ 'dw2_assemble_integer' -> 'assemble_integer' attempts to simplify
+ '(minus:DI (symbol_ref:DI ("$LEHB0")) (symbol_ref:DI ("$LFB3")))', for
+ example. Just emit something; it's not getting used, anyway. */
+#define ASM_OUTPUT_DWARF_DELTA(STREAM, SIZE, LABEL1, LABEL2) \
+ do \
+ { \
+ fprintf (STREAM, "%s[%d]: ", targetm.asm_out.byte_op, SIZE); \
+ const char *label1 = LABEL1; \
+ assemble_name_raw (STREAM, label1 ? label1 : "*nil"); \
+ fprintf (STREAM, " - "); \
+ const char *label2 = LABEL2; \
+ assemble_name_raw (STREAM, label2 ? label2 : "*nil"); \
+ } \
+ while (0)
+
#endif /* GCC_NVPTX_H */