From 2a1448f2763a72c83e2ec496f78243a975b0d44e Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 8 Aug 2022 09:07:23 +0200 Subject: lto/106540 - fix LTO tree input wrt dwarf2out_register_external_die I've revisited the earlier two workarounds for dwarf2out_register_external_die getting duplicate entries. It turns out that r11-525-g03d90a20a1afcb added dref_queue pruning to lto_input_tree but decl reading uses that to stream in DECL_INITIAL even when in the middle of SCC streaming. When that SCC then gets thrown away we can end up with debug nodes registered which isn't supposed to happen. The following adjusts the DECL_INITIAL streaming to go the in-SCC way, using lto_input_tree_1, since no SCCs are expected at this point, just refs. PR lto/106540 PR lto/106334 * dwarf2out.cc (dwarf2out_register_external_die): Restore original assert. * lto-streamer-in.cc (lto_read_tree_1): Use lto_input_tree_1 to input DECL_INITIAL, avoiding to commit drefs. --- gcc/dwarf2out.cc | 7 +------ gcc/lto-streamer-in.cc | 7 +++++-- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index cfea9cf..e3920c8 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -6069,12 +6069,7 @@ dwarf2out_register_external_die (tree decl, const char *sym, if (!external_die_map) external_die_map = hash_map::create_ggc (1000); - /* When we do tree merging during WPA or with -flto-partition=none we - can end up re-using GC memory as there's currently no way to unregister - external DIEs. Ideally we'd register them only after merging finished - but allowing override here is easiest. See PR106334. */ - gcc_checking_assert (!(in_lto_p && !flag_wpa) - || !external_die_map->get (decl)); + gcc_checking_assert (!external_die_map->get (decl)); sym_off_pair p = { IDENTIFIER_POINTER (get_identifier (sym)), off }; external_die_map->put (decl, p); } diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc index fe5a4e7..a7dad70 100644 --- a/gcc/lto-streamer-in.cc +++ b/gcc/lto-streamer-in.cc @@ -1699,11 +1699,14 @@ lto_read_tree_1 (class lto_input_block *ib, class data_in *data_in, tree expr) /* Read all the pointer fields in EXPR. */ streamer_read_tree_body (ib, data_in, expr); - /* Read any LTO-specific data not read by the tree streamer. */ + /* Read any LTO-specific data not read by the tree streamer. Do not use + stream_read_tree here since that flushes the dref_queue in mids of + SCC reading. */ if (DECL_P (expr) && TREE_CODE (expr) != FUNCTION_DECL && TREE_CODE (expr) != TRANSLATION_UNIT_DECL) - DECL_INITIAL (expr) = stream_read_tree (ib, data_in); + DECL_INITIAL (expr) + = lto_input_tree_1 (ib, data_in, streamer_read_record_start (ib), 0); /* Stream references to early generated DIEs. Keep in sync with the trees handled in dwarf2out_register_external_die. */ -- cgit v1.1 From 21c7aab09805d0c8c7695c8a69c8715d673a739a Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Mon, 20 Dec 2021 20:27:33 -0800 Subject: Fix middle-end/103645: empty struct store not removed when using compound literal For compound literals empty struct stores are not removed as they go down a different path of the gimplifier; trying to optimize the init constructor. This fixes the problem by not adding the gimple assignment at the end of gimplify_init_constructor if it was an empty type. Note this updates gcc.dg/pr87052.c where we had: const char d[0] = { }; And was expecting a store to d but after this, there is no store as the decl's type is zero in size. OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. gcc/ChangeLog: PR middle-end/103645 * gimplify.cc (gimplify_init_constructor): Don't build/add gimple assignment of an empty type. gcc/testsuite/ChangeLog: * gcc.dg/pr87052.c: Update d var to expect nothing. --- gcc/gimplify.cc | 7 +++++-- gcc/testsuite/gcc.dg/pr87052.c | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 2ac7ca0..f0fbdb4 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -5488,8 +5488,11 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (ret == GS_ERROR) return GS_ERROR; /* If we have gimplified both sides of the initializer but have - not emitted an assignment, do so now. */ - if (*expr_p) + not emitted an assignment, do so now. */ + if (*expr_p + /* If the type is an empty type, we don't need to emit the + assignment. */ + && !is_empty_type (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))) { tree lhs = TREE_OPERAND (*expr_p, 0); tree rhs = TREE_OPERAND (*expr_p, 1); diff --git a/gcc/testsuite/gcc.dg/pr87052.c b/gcc/testsuite/gcc.dg/pr87052.c index 18e092c..796fe64 100644 --- a/gcc/testsuite/gcc.dg/pr87052.c +++ b/gcc/testsuite/gcc.dg/pr87052.c @@ -23,8 +23,7 @@ void test (void) const char d[0] = { }; - /* Expect the following: - d = ""; */ + /* Expect nothing. */ const char e[0] = ""; @@ -36,6 +35,7 @@ void test (void) /* { dg-final { scan-tree-dump-times "a = \"\\\\x00ab\";" 1 "gimple" } } { dg-final { scan-tree-dump-times "b = \"a\\\\x00bc\";" 1 "gimple" } } { dg-final { scan-tree-dump-times "c = \"\";" 1 "gimple" } } - { dg-final { scan-tree-dump-times "d = { *};" 1 "gimple" } } + { dg-final { scan-tree-dump-times "d = " 1 "gimple" } } + { dg-final { scan-tree-dump-times "d = {CLOBBER\\(eol\\)}" 1 "gimple" } } { dg-final { scan-tree-dump-times "e = " 1 "gimple" } } { dg-final { scan-tree-dump-times "e = {CLOBBER\\(eol\\)}" 1 "gimple" } } */ -- cgit v1.1 From 4b0253b019943abf2cc5f4db0b7ed67caedffe4a Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Mon, 8 Aug 2022 15:17:47 +0200 Subject: d: Fix ICE in in add_stack_var, at cfgexpand.cc:476 The type that triggers the ICE never got completed by the semantic analysis pass. Checking for size forces it to be done, or issue a compile-time error. PR d/106555 gcc/d/ChangeLog: * d-target.cc (Target::isReturnOnStack): Check for return type size. gcc/testsuite/ChangeLog: * gdc.dg/imports/pr106555.d: New test. * gdc.dg/pr106555.d: New test. --- gcc/d/d-target.cc | 2 ++ gcc/testsuite/gdc.dg/imports/pr106555.d | 10 ++++++++++ gcc/testsuite/gdc.dg/pr106555.d | 4 ++++ 3 files changed, 16 insertions(+) create mode 100644 gcc/testsuite/gdc.dg/imports/pr106555.d create mode 100644 gcc/testsuite/gdc.dg/pr106555.d (limited to 'gcc') diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 610be74..d4350e5 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -464,6 +464,8 @@ Target::isReturnOnStack (TypeFunction *tf, bool) return false; Type *tn = tf->next->toBasetype (); + if (tn->size () == SIZE_INVALID) + return false; return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray); } diff --git a/gcc/testsuite/gdc.dg/imports/pr106555.d b/gcc/testsuite/gdc.dg/imports/pr106555.d new file mode 100644 index 0000000..0d3ab6b --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/pr106555.d @@ -0,0 +1,10 @@ +module imports.pr106555; +struct S106555 +{ + int[] f106555; + int max106555; + this(int) + { + f106555.length = max106555; + } +} diff --git a/gcc/testsuite/gdc.dg/pr106555.d b/gcc/testsuite/gdc.dg/pr106555.d new file mode 100644 index 0000000..7b40f3c --- /dev/null +++ b/gcc/testsuite/gdc.dg/pr106555.d @@ -0,0 +1,4 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106555 +// { dg-do compile } +// { dg-additional-options "-O2" } +// { dg-additional-sources "imports/pr106555.d" } -- cgit v1.1 From 703837b2cc8ac03c53ac7cc0fb1327055acaebd2 Mon Sep 17 00:00:00 2001 From: Tom Honermann Date: Tue, 2 Aug 2022 14:36:01 -0400 Subject: C: Implement C2X N2653 char8_t and UTF-8 string literal changes This patch implements the core language and compiler dependent library changes adopted for C2X via WG14 N2653. The changes include: - Change of type for UTF-8 string literals from array of const char to array of const char8_t (unsigned char). - A new atomic_char8_t typedef. - A new ATOMIC_CHAR8_T_LOCK_FREE macro defined in terms of the existing __GCC_ATOMIC_CHAR8_T_LOCK_FREE predefined macro. gcc/ChangeLog: * ginclude/stdatomic.h (atomic_char8_t, ATOMIC_CHAR8_T_LOCK_FREE): New typedef and macro. gcc/c/ChangeLog: * c-parser.cc (c_parser_string_literal): Use char8_t as the type of CPP_UTF8STRING when char8_t support is enabled. * c-typeck.cc (digest_init): Allow initialization of an array of character type by a string literal with type array of char8_t. gcc/c-family/ChangeLog: * c-lex.cc (lex_string, lex_charconst): Use char8_t as the type of CPP_UTF8CHAR and CPP_UTF8STRING when char8_t support is enabled. * c-opts.cc (c_common_post_options): Set flag_char8_t if targeting C2x. gcc/testsuite/ChangeLog: * gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c: New test. * gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c: New test. * gcc.dg/c11-utf8str-type.c: New test. * gcc.dg/c17-utf8str-type.c: New test. * gcc.dg/c2x-utf8str-type.c: New test. * gcc.dg/c2x-utf8str.c: New test. * gcc.dg/gnu2x-utf8str-type.c: New test. * gcc.dg/gnu2x-utf8str.c: New test. --- gcc/c-family/c-lex.cc | 13 ++++--- gcc/c-family/c-opts.cc | 4 +-- gcc/c/c-parser.cc | 16 +++++++-- gcc/c/c-typeck.cc | 2 +- gcc/ginclude/stdatomic.h | 6 ++++ .../gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c | 42 ++++++++++++++++++++++ .../atomic/gnu2x-stdatomic-lockfree-char8_t.c | 5 +++ gcc/testsuite/gcc.dg/c11-utf8str-type.c | 6 ++++ gcc/testsuite/gcc.dg/c17-utf8str-type.c | 6 ++++ gcc/testsuite/gcc.dg/c2x-utf8str-type.c | 6 ++++ gcc/testsuite/gcc.dg/c2x-utf8str.c | 34 ++++++++++++++++++ gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c | 5 +++ gcc/testsuite/gcc.dg/gnu2x-utf8str.c | 34 ++++++++++++++++++ 13 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c create mode 100644 gcc/testsuite/gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c create mode 100644 gcc/testsuite/gcc.dg/c11-utf8str-type.c create mode 100644 gcc/testsuite/gcc.dg/c17-utf8str-type.c create mode 100644 gcc/testsuite/gcc.dg/c2x-utf8str-type.c create mode 100644 gcc/testsuite/gcc.dg/c2x-utf8str.c create mode 100644 gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c create mode 100644 gcc/testsuite/gcc.dg/gnu2x-utf8str.c (limited to 'gcc') diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index 8bfa4f4..0b6f94e 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -1352,7 +1352,14 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) default: case CPP_STRING: case CPP_UTF8STRING: - value = build_string (1, ""); + if (type == CPP_UTF8STRING && flag_char8_t) + { + value = build_string (TYPE_PRECISION (char8_type_node) + / TYPE_PRECISION (char_type_node), + ""); /* char8_t is 8 bits */ + } + else + value = build_string (1, ""); break; case CPP_STRING16: value = build_string (TYPE_PRECISION (char16_type_node) @@ -1425,9 +1432,7 @@ lex_charconst (const cpp_token *token) type = char16_type_node; else if (token->type == CPP_UTF8CHAR) { - if (!c_dialect_cxx ()) - type = unsigned_char_type_node; - else if (flag_char8_t) + if (flag_char8_t) type = char8_type_node; else type = char_type_node; diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 4e14636..1cf119a 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -1059,9 +1059,9 @@ c_common_post_options (const char **pfilename) if (flag_sized_deallocation == -1) flag_sized_deallocation = (cxx_dialect >= cxx14); - /* char8_t support is new in C++20. */ + /* char8_t support is implicitly enabled in C++20 and C2X. */ if (flag_char8_t == -1) - flag_char8_t = (cxx_dialect >= cxx20); + flag_char8_t = (cxx_dialect >= cxx20) || flag_isoc2x; if (flag_extern_tls_init) { diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 92049d1..fa93959 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -7447,7 +7447,14 @@ c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) default: case CPP_STRING: case CPP_UTF8STRING: - value = build_string (1, ""); + if (type == CPP_UTF8STRING && flag_char8_t) + { + value = build_string (TYPE_PRECISION (char8_type_node) + / TYPE_PRECISION (char_type_node), + ""); /* char8_t is 8 bits */ + } + else + value = build_string (1, ""); break; case CPP_STRING16: value = build_string (TYPE_PRECISION (char16_type_node) @@ -7472,9 +7479,14 @@ c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) { default: case CPP_STRING: - case CPP_UTF8STRING: TREE_TYPE (value) = char_array_type_node; break; + case CPP_UTF8STRING: + if (flag_char8_t) + TREE_TYPE (value) = char8_array_type_node; + else + TREE_TYPE (value) = char_array_type_node; + break; case CPP_STRING16: TREE_TYPE (value) = char16_array_type_node; break; diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 8514488..d37de2a 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -8056,7 +8056,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, if (char_array) { - if (typ2 != char_type_node) + if (typ2 != char_type_node && typ2 != char8_type_node) incompat_string_cst = true; } else if (!comptypes (typ1, typ2)) diff --git a/gcc/ginclude/stdatomic.h b/gcc/ginclude/stdatomic.h index bfcfdf6..9f2475b 100644 --- a/gcc/ginclude/stdatomic.h +++ b/gcc/ginclude/stdatomic.h @@ -49,6 +49,9 @@ typedef _Atomic long atomic_long; typedef _Atomic unsigned long atomic_ulong; typedef _Atomic long long atomic_llong; typedef _Atomic unsigned long long atomic_ullong; +#ifdef __CHAR8_TYPE__ +typedef _Atomic __CHAR8_TYPE__ atomic_char8_t; +#endif typedef _Atomic __CHAR16_TYPE__ atomic_char16_t; typedef _Atomic __CHAR32_TYPE__ atomic_char32_t; typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t; @@ -97,6 +100,9 @@ extern void atomic_signal_fence (memory_order); #define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE #define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +#ifdef __GCC_ATOMIC_CHAR8_T_LOCK_FREE +#define ATOMIC_CHAR8_T_LOCK_FREE __GCC_ATOMIC_CHAR8_T_LOCK_FREE +#endif #define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE #define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE #define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE diff --git a/gcc/testsuite/gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c b/gcc/testsuite/gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c new file mode 100644 index 0000000..1b692f5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c @@ -0,0 +1,42 @@ +/* Test atomic_is_lock_free for char8_t. */ +/* { dg-do run } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +#include +#include + +extern void abort (void); + +_Atomic __CHAR8_TYPE__ ac8a; +atomic_char8_t ac8t; + +#define CHECK_TYPE(MACRO, V1, V2) \ + do \ + { \ + int r1 = MACRO; \ + int r2 = atomic_is_lock_free (&V1); \ + int r3 = atomic_is_lock_free (&V2); \ + if (r1 != 0 && r1 != 1 && r1 != 2) \ + abort (); \ + if (r2 != 0 && r2 != 1) \ + abort (); \ + if (r3 != 0 && r3 != 1) \ + abort (); \ + if (r1 == 2 && r2 != 1) \ + abort (); \ + if (r1 == 2 && r3 != 1) \ + abort (); \ + if (r1 == 0 && r2 != 0) \ + abort (); \ + if (r1 == 0 && r3 != 0) \ + abort (); \ + } \ + while (0) + +int +main () +{ + CHECK_TYPE (ATOMIC_CHAR8_T_LOCK_FREE, ac8a, ac8t); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c b/gcc/testsuite/gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c new file mode 100644 index 0000000..27a3cfe --- /dev/null +++ b/gcc/testsuite/gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c @@ -0,0 +1,5 @@ +/* Test atomic_is_lock_free for char8_t with -std=gnu2x. */ +/* { dg-do run } */ +/* { dg-options "-std=gnu2x -pedantic-errors" } */ + +#include "c2x-stdatomic-lockfree-char8_t.c" diff --git a/gcc/testsuite/gcc.dg/c11-utf8str-type.c b/gcc/testsuite/gcc.dg/c11-utf8str-type.c new file mode 100644 index 0000000..8be9abb --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-utf8str-type.c @@ -0,0 +1,6 @@ +/* Test C11 UTF-8 string literal type. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11" } */ + +_Static_assert (_Generic (u8"text", char*: 1, default: 2) == 1, "UTF-8 string literals have an unexpected type"); +_Static_assert (_Generic (u8"x"[0], char: 1, default: 2) == 1, "UTF-8 string literal elements have an unexpected type"); diff --git a/gcc/testsuite/gcc.dg/c17-utf8str-type.c b/gcc/testsuite/gcc.dg/c17-utf8str-type.c new file mode 100644 index 0000000..515c6db --- /dev/null +++ b/gcc/testsuite/gcc.dg/c17-utf8str-type.c @@ -0,0 +1,6 @@ +/* Test C17 UTF-8 string literal type. */ +/* { dg-do compile } */ +/* { dg-options "-std=c17" } */ + +_Static_assert (_Generic (u8"text", char*: 1, default: 2) == 1, "UTF-8 string literals have an unexpected type"); +_Static_assert (_Generic (u8"x"[0], char: 1, default: 2) == 1, "UTF-8 string literal elements have an unexpected type"); diff --git a/gcc/testsuite/gcc.dg/c2x-utf8str-type.c b/gcc/testsuite/gcc.dg/c2x-utf8str-type.c new file mode 100644 index 0000000..ebdde97 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-utf8str-type.c @@ -0,0 +1,6 @@ +/* Test C2X UTF-8 string literal type. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +_Static_assert (_Generic (u8"text", unsigned char*: 1, default: 2) == 1, "UTF-8 string literals have an unexpected type"); +_Static_assert (_Generic (u8"x"[0], unsigned char: 1, default: 2) == 1, "UTF-8 string literal elements have an unexpected type"); diff --git a/gcc/testsuite/gcc.dg/c2x-utf8str.c b/gcc/testsuite/gcc.dg/c2x-utf8str.c new file mode 100644 index 0000000..2e4c392 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-utf8str.c @@ -0,0 +1,34 @@ +/* Test initialization by UTF-8 string literal in C2X. */ +/* { dg-do compile } */ +/* { dg-require-effective-target wchar } */ +/* { dg-options "-std=c2x" } */ + +typedef __CHAR8_TYPE__ char8_t; +typedef __CHAR16_TYPE__ char16_t; +typedef __CHAR32_TYPE__ char32_t; +typedef __WCHAR_TYPE__ wchar_t; + +/* Test that char, signed char, unsigned char, and char8_t arrays can be + initialized by a UTF-8 string literal. */ +const char cbuf1[] = u8"text"; +const char cbuf2[] = { u8"text" }; +const signed char scbuf1[] = u8"text"; +const signed char scbuf2[] = { u8"text" }; +const unsigned char ucbuf1[] = u8"text"; +const unsigned char ucbuf2[] = { u8"text" }; +const char8_t c8buf1[] = u8"text"; +const char8_t c8buf2[] = { u8"text" }; + +/* Test that a diagnostic is issued for attempted initialization of + other character types by a UTF-8 string literal. */ +const char16_t c16buf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char16_t c16buf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char32_t c32buf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char32_t c32buf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const wchar_t wbuf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const wchar_t wbuf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ + +/* Test that char8_t arrays can be initialized by an ordinary string + literal. */ +const char8_t c8buf3[] = "text"; +const char8_t c8buf4[] = { "text" }; diff --git a/gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c b/gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c new file mode 100644 index 0000000..efe16ff --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c @@ -0,0 +1,5 @@ +/* Test C2X UTF-8 string literal type with -std=gnu2x. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu2x" } */ + +#include "c2x-utf8str-type.c" diff --git a/gcc/testsuite/gcc.dg/gnu2x-utf8str.c b/gcc/testsuite/gcc.dg/gnu2x-utf8str.c new file mode 100644 index 0000000..f3719ea --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu2x-utf8str.c @@ -0,0 +1,34 @@ +/* Test initialization by UTF-8 string literal in C2X with -std=gnu2x. */ +/* { dg-do compile } */ +/* { dg-require-effective-target wchar } */ +/* { dg-options "-std=gnu2x" } */ + +typedef __CHAR8_TYPE__ char8_t; +typedef __CHAR16_TYPE__ char16_t; +typedef __CHAR32_TYPE__ char32_t; +typedef __WCHAR_TYPE__ wchar_t; + +/* Test that char, signed char, unsigned char, and char8_t arrays can be + initialized by a UTF-8 string literal. */ +const char cbuf1[] = u8"text"; +const char cbuf2[] = { u8"text" }; +const signed char scbuf1[] = u8"text"; +const signed char scbuf2[] = { u8"text" }; +const unsigned char ucbuf1[] = u8"text"; +const unsigned char ucbuf2[] = { u8"text" }; +const char8_t c8buf1[] = u8"text"; +const char8_t c8buf2[] = { u8"text" }; + +/* Test that a diagnostic is issued for attempted initialization of + other character types by a UTF-8 string literal. */ +const char16_t c16buf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char16_t c16buf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char32_t c32buf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char32_t c32buf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const wchar_t wbuf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const wchar_t wbuf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ + +/* Test that char8_t arrays can be initialized by an ordinary string + literal. */ +const char8_t c8buf3[] = "text"; +const char8_t c8buf4[] = { "text" }; -- cgit v1.1 From 053876cdbe8057210e6f4da4eec2df58f92ccd4c Mon Sep 17 00:00:00 2001 From: Tom Honermann Date: Tue, 2 Aug 2022 14:36:02 -0400 Subject: preprocessor/106426: Treat u8 character literals as unsigned in char8_t modes. This patch corrects handling of UTF-8 character literals in preprocessing directives so that they are treated as unsigned types in char8_t enabled C++ modes (C++17 with -fchar8_t or C++20 without -fno-char8_t). Previously, UTF-8 character literals were always treated as having the same type as ordinary character literals (signed or unsigned dependent on target or use of the -fsigned-char or -funsigned char options). PR preprocessor/106426 gcc/c-family/ChangeLog: * c-opts.cc (c_common_post_options): Assign cpp_opts->unsigned_utf8char subject to -fchar8_t, -fsigned-char, and/or -funsigned-char. gcc/testsuite/ChangeLog: * g++.dg/ext/char8_t-char-literal-1.C: Check signedness of u8 literals. * g++.dg/ext/char8_t-char-literal-2.C: Check signedness of u8 literals. libcpp/ChangeLog: * charset.cc (narrow_str_to_charconst): Set signedness of CPP_UTF8CHAR literals based on unsigned_utf8char. * include/cpplib.h (cpp_options): Add unsigned_utf8char. * init.cc (cpp_create_reader): Initialize unsigned_utf8char. --- gcc/c-family/c-opts.cc | 1 + gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C | 6 +++++- gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 1cf119a..9833e50 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -1062,6 +1062,7 @@ c_common_post_options (const char **pfilename) /* char8_t support is implicitly enabled in C++20 and C2X. */ if (flag_char8_t == -1) flag_char8_t = (cxx_dialect >= cxx20) || flag_isoc2x; + cpp_opts->unsigned_utf8char = flag_char8_t ? 1 : cpp_opts->unsigned_char; if (flag_extern_tls_init) { diff --git a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C index 8ed85cc..2994dd3 100644 --- a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C +++ b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C @@ -1,6 +1,6 @@ // Test that UTF-8 character literals have type char if -fchar8_t is not enabled. // { dg-do compile } -// { dg-options "-std=c++17 -fno-char8_t" } +// { dg-options "-std=c++17 -fsigned-char -fno-char8_t" } template struct is_same @@ -10,3 +10,7 @@ template { static const bool value = true; }; static_assert(is_same::value, "Error"); + +#if u8'\0' - 1 > 0 +#error "UTF-8 character literals not signed in preprocessor" +#endif diff --git a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C index 7861736..db4fe70 100644 --- a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C +++ b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C @@ -10,3 +10,7 @@ template { static const bool value = true; }; static_assert(is_same::value, "Error"); + +#if u8'\0' - 1 < 0 +#error "UTF-8 character literals not unsigned in preprocessor" +#endif -- cgit v1.1 From ef623bb58594958a7959f8f031f65a50eb0e5890 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 8 Aug 2022 15:13:51 -0400 Subject: Evaluate condition arguments with the correct type. Processing of a cond_expr requires that a range of the correct type for the operands of the cond_expr is passed in. PR tree-optimization/106556 gcc/ * gimple-range-gori.cc (gori_compute::condexpr_adjust): Use the type of the cond_expr operands being evaluted. gcc/testsuite/ * gfortran.dg/pr106556.f90: New. --- gcc/gimple-range-gori.cc | 11 ++++++----- gcc/testsuite/gfortran.dg/pr106556.f90 | 10 ++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr106556.f90 (limited to 'gcc') diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index a43e44c..8879e44 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -1398,16 +1398,17 @@ gori_compute::condexpr_adjust (vrange &r1, vrange &r2, gimple *, tree cond, } // Now solve for SSA1 or SSA2 if they are in the dependency chain. - Value_Range tmp (type); if (ssa1 && in_chain_p (ssa1, cond_name)) { - if (compute_operand_range (tmp, def_stmt, cond_true, ssa1, src)) - r1.intersect (tmp); + Value_Range tmp1 (TREE_TYPE (ssa1)); + if (compute_operand_range (tmp1, def_stmt, cond_true, ssa1, src)) + r1.intersect (tmp1); } if (ssa2 && in_chain_p (ssa2, cond_name)) { - if (compute_operand_range (tmp, def_stmt, cond_false, ssa2, src)) - r2.intersect (tmp); + Value_Range tmp2 (TREE_TYPE (ssa2)); + if (compute_operand_range (tmp2, def_stmt, cond_false, ssa2, src)) + r2.intersect (tmp2); } if (idx) { diff --git a/gcc/testsuite/gfortran.dg/pr106556.f90 b/gcc/testsuite/gfortran.dg/pr106556.f90 new file mode 100644 index 0000000..01b89a8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr106556.f90 @@ -0,0 +1,10 @@ +! { dg-do compile } +! { dg-options "-O1 -fnon-call-exceptions -ftree-loop-if-convert" } + + +program p + real :: a(2) + + a(:) = 1.0 + if (minloc (a, dim = 1).ne.1) STOP 1 +end -- cgit v1.1 From 5f17badb648980275ff4c86b0c207dbd751b00f2 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 9 Aug 2022 00:16:47 +0000 Subject: Daily bump. --- gcc/ChangeLog | 26 ++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 14 ++++++++++++++ gcc/c/ChangeLog | 8 ++++++++ gcc/d/ChangeLog | 5 +++++ gcc/testsuite/ChangeLog | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 91 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2d41c22..36879ec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2022-08-08 Andrew MacLeod + + PR tree-optimization/106556 + * gimple-range-gori.cc (gori_compute::condexpr_adjust): Use the + type of the cond_expr operands being evaluted. + +2022-08-08 Tom Honermann + + * ginclude/stdatomic.h (atomic_char8_t, + ATOMIC_CHAR8_T_LOCK_FREE): New typedef and macro. + +2022-08-08 Andrew Pinski + + PR middle-end/103645 + * gimplify.cc (gimplify_init_constructor): Don't build/add + gimple assignment of an empty type. + +2022-08-08 Richard Biener + + PR lto/106540 + PR lto/106334 + * dwarf2out.cc (dwarf2out_register_external_die): Restore + original assert. + * lto-streamer-in.cc (lto_read_tree_1): Use lto_input_tree_1 + to input DECL_INITIAL, avoiding to commit drefs. + 2022-08-07 Roger Sayle * config/i386/i386.md (*cmp_doubleword): Change predicate diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 00f22f5..8bd1173 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220808 +20220809 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 68fc6e2..63277a5 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,17 @@ +2022-08-08 Tom Honermann + + PR preprocessor/106426 + * c-opts.cc (c_common_post_options): Assign cpp_opts->unsigned_utf8char + subject to -fchar8_t, -fsigned-char, and/or -funsigned-char. + +2022-08-08 Tom Honermann + + * c-lex.cc (lex_string, lex_charconst): Use char8_t as the type + of CPP_UTF8CHAR and CPP_UTF8STRING when char8_t support is + enabled. + * c-opts.cc (c_common_post_options): Set flag_char8_t if + targeting C2x. + 2022-07-31 Lewis Hyatt PR c++/66290 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index cffb462..b5ecf92 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,11 @@ +2022-08-08 Tom Honermann + + * c-parser.cc (c_parser_string_literal): Use char8_t as the type + of CPP_UTF8STRING when char8_t support is enabled. + * c-typeck.cc (digest_init): Allow initialization of an array + of character type by a string literal with type array of + char8_t. + 2022-08-01 David Malcolm * c-typeck.cc (build_c_cast): Quote names of address spaces in diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 41e2809..0bb74b1 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,8 @@ +2022-08-08 Iain Buclaw + + PR d/106555 + * d-target.cc (Target::isReturnOnStack): Check for return type size. + 2022-08-03 Iain Buclaw * dmd/MERGE: Merge upstream dmd d7772a2369. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fee24d2..19a5303 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,40 @@ +2022-08-08 Andrew MacLeod + + PR tree-optimization/106556 + * gfortran.dg/pr106556.f90: New. + +2022-08-08 Tom Honermann + + PR preprocessor/106426 + * g++.dg/ext/char8_t-char-literal-1.C: Check signedness of u8 literals. + * g++.dg/ext/char8_t-char-literal-2.C: Check signedness of u8 literals. + +2022-08-08 Tom Honermann + + * gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c: New test. + * gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c: New test. + * gcc.dg/c11-utf8str-type.c: New test. + * gcc.dg/c17-utf8str-type.c: New test. + * gcc.dg/c2x-utf8str-type.c: New test. + * gcc.dg/c2x-utf8str.c: New test. + * gcc.dg/gnu2x-utf8str-type.c: New test. + * gcc.dg/gnu2x-utf8str.c: New test. + +2022-08-08 Iain Buclaw + + PR d/106555 + * gdc.dg/imports/pr106555.d: New test. + * gdc.dg/pr106555.d: New test. + +2022-08-08 Andrew Pinski + + * gcc.dg/pr87052.c: Update d var to expect nothing. + +2022-08-08 Andrew Pinski + + * gcc.dg/tree-ssa/pr93776.c: Moved to... + * gcc.c-torture/compile/pr93776.c: ...here. + 2022-08-07 Roger Sayle * gcc.target/i386/cmpti2.c: Add -mno-stv to dg-options. -- cgit v1.1 From 8a16b9f983824b6b9a25275cd23b6bba8c98b800 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Tue, 9 Aug 2022 07:57:40 +0200 Subject: OpenMP: Fix folding with simd's linear clause [PR106492] gcc/ChangeLog: PR middle-end/106492 * omp-low.cc (lower_rec_input_clauses): Add missing folding to data type of linear-clause list item. gcc/testsuite/ChangeLog: PR middle-end/106492 * g++.dg/gomp/pr106492.C: New test. --- gcc/omp-low.cc | 6 ++--- gcc/testsuite/g++.dg/gomp/pr106492.C | 49 ++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/pr106492.C (limited to 'gcc') diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc index d73c165..3c4b859 100644 --- a/gcc/omp-low.cc +++ b/gcc/omp-low.cc @@ -6241,10 +6241,10 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } if (POINTER_TYPE_P (TREE_TYPE (x))) - x = fold_build2 (POINTER_PLUS_EXPR, - TREE_TYPE (x), x, t); + x = fold_build_pointer_plus (x, t); else - x = fold_build2 (PLUS_EXPR, TREE_TYPE (x), x, t); + x = fold_build2 (PLUS_EXPR, TREE_TYPE (x), x, + fold_convert (TREE_TYPE (x), t)); } if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR diff --git a/gcc/testsuite/g++.dg/gomp/pr106492.C b/gcc/testsuite/g++.dg/gomp/pr106492.C new file mode 100644 index 0000000..f263bb4 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/pr106492.C @@ -0,0 +1,49 @@ +/* PR middle-end/106492 */ + +template +struct S { + T a : 12; + S () : a(0) + { +#pragma omp for simd linear(a) + for (int k = 0; k < 64; ++k) + a++; + } +}; +struct U { + int a : 12; + U () : a(0) + { +#pragma omp for simd linear(a) + for (int k = 0; k < 64; ++k) + a++; + } +}; + +S s; +U u; + + +template +struct Sptr { + T a; + Sptr (T init) : a(init) + { +#pragma omp for simd linear(a) + for (int k = 0; k < 64; ++k) + a++; + } +}; +struct Uptr { + int *a; + Uptr (int *init) : a(init) + { +#pragma omp for simd linear(a) + for (int k = 0; k < 64; ++k) + a++; + } +}; + +int i[1024]; +Sptr sptr(i); +Uptr uptr(&i[100]); -- cgit v1.1 From 409978d58dafa689c5b3f85013e2786526160f2c Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 8 Aug 2022 12:20:04 +0200 Subject: tree-optimization/106514 - add --param max-jump-thread-paths The following adds a limit for the exponential greedy search of the backwards jump threader. The idea is to limit the search space in a way that the paths considered are the same if the search were in BFS order rather than DFS. In particular it stops considering incoming edges into a block if the product of the in-degrees of blocks on the path exceeds the specified limit. When considering the low stmt copying limit of 7 (or 1 in the size optimize case) this means the degenerate case with maximum search space is a sequence of conditions with no actual code B1 |\ | empty |/ B2 |\ ... Bn |\ GIMPLE_CONDs are costed 2, an equivalent GIMPLE_SWITCH already 4, so we reach 7 already with 3 middle conditions (B1 and Bn do not count). The search space would be 2^4 == 16 to reach this. The FSM threads historically allowed for a thread length of 10 but is really looking for a single multiway branch threaded across the backedge. I've chosen the default of the new parameter to 64 which effectively limits the outdegree of the switch statement (the cases reaching the backedge) to that number (divided by 2 until I add some special pruning for FSM threads due to the loop header indegree). The testcase ssa-dom-thread-7.c requires 56 at the moment (as said, some special FSM thread pruning of considered edges would bring it down to half of that), but we now get one more threading and quite some more in later threadfull. This testcase seems to be difficult to check for expected transforms. The new testcases add the degenerate case we currently thread (without deciding whether that's a good idea ...) plus one with an approripate limit that should prevent the threading. This obsoletes the mentioned --param max-fsm-thread-length but I am not removing it as part of this patch. When the search space is limited the thread stmt size limit effectively provides max-fsm-thread-length. The param with its default does not help PR106514 enough to unleash path searching with the higher FSM stmt count limit. PR tree-optimization/106514 * params.opt (max-jump-thread-paths): New. * doc/invoke.texi (max-jump-thread-paths): Document. * tree-ssa-threadbackward.cc (back_threader::find_paths_to_names): Honor max-jump-thread-paths, take overall_path argument. (back_threader::find_paths): Pass 1 as initial overall_path. * gcc.dg/tree-ssa/ssa-thread-16.c: New testcase. * gcc.dg/tree-ssa/ssa-thread-17.c: Likewise. * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Adjust. --- gcc/doc/invoke.texi | 7 +++++++ gcc/params.opt | 4 ++++ gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c | 24 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c | 7 +++++++ gcc/tree-ssa-threadbackward.cc | 20 ++++++++++++++------ 6 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 92f7aae..f016966 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -14754,6 +14754,13 @@ optimizing. Maximum number of statements allowed in a block that needs to be duplicated when threading jumps. +@item max-jump-thread-paths +The maximum number of paths to consider when searching for jump threading +opportunities. When arriving at a block incoming edges are only considered +if the number of paths to be searched sofar multiplied by the incoming +edge degree does not exhaust the specified maximum number of paths to +consider. + @item max-fields-for-field-sensitive Maximum number of fields in a structure treated in a field sensitive manner during pointer analysis. diff --git a/gcc/params.opt b/gcc/params.opt index 2f9c9cf..1329873 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -582,6 +582,10 @@ Bound on the number of iterations the brute force # of iterations analysis algor Common Joined UInteger Var(param_max_jump_thread_duplication_stmts) Init(15) Param Optimization Maximum number of statements allowed in a block that needs to be duplicated when threading jumps. +-param=max-jump-thread-paths= +Common Joined UInteger Var(param_max_jump_thread_paths) Init(64) IntegerRange(1, 65536) Param Optimization +Search space limit for the backwards jump threader. + -param=max-last-value-rtl= Common Joined UInteger Var(param_max_last_value_rtl) Init(10000) Param Optimization The maximum number of RTL nodes that can be recorded as combiner's last value. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c index aa06db5..47b8fdf 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c @@ -11,7 +11,7 @@ to change decisions in switch expansion which in turn can expose new jump threading opportunities. Skip the later tests on aarch64. */ /* { dg-final { scan-tree-dump-not "Jumps threaded" "dom3" { target { ! aarch64*-*-* } } } } */ -/* { dg-final { scan-tree-dump "Jumps threaded: 8" "thread2" { target { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump "Jumps threaded: 9" "thread2" { target { ! aarch64*-*-* } } } } */ /* { dg-final { scan-tree-dump "Jumps threaded: 18" "thread2" { target { aarch64*-*-* } } } } */ enum STATE { diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c new file mode 100644 index 0000000..f96170b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-threadfull1-details" } */ + +int res; +void foo (int a, int b, int c, int d, int e) +{ + if (a > 100) + res = 3; + if (b != 5) + res = 5; + if (c == 29) + res = 7; + if (d < 2) + res = 9; + /* Accounting whoes makes this not catched. */ +#if 0 + if (e != 37) + res = 11; +#endif + if (a < 10) + res = 13; +} + +/* { dg-final { scan-tree-dump "SUCCESS" "threadfull1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c new file mode 100644 index 0000000..94ee666 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-threadfull1-details --param max-jump-thread-paths=15" } */ + +#include "ssa-thread-16.c" + +/* With limiting the search space we should no longer consider this path. */ +/* { dg-final { scan-tree-dump-not "SUCCESS" "threadfull1" } } */ diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc index 332a1d2..a5f8f14 100644 --- a/gcc/tree-ssa-threadbackward.cc +++ b/gcc/tree-ssa-threadbackward.cc @@ -90,7 +90,7 @@ private: bool debug_counter (); edge maybe_register_path (); void maybe_register_path_dump (edge taken_edge); - void find_paths_to_names (basic_block bb, bitmap imports); + void find_paths_to_names (basic_block bb, bitmap imports, unsigned); edge find_taken_edge (const vec &path); edge find_taken_edge_cond (const vec &path, gcond *); edge find_taken_edge_switch (const vec &path, gswitch *); @@ -337,9 +337,12 @@ back_threader::find_taken_edge_cond (const vec &path, // INTERESTING bitmap, and register any such paths. // // BB is the current path being processed. +// +// OVERALL_PATHS is the search space up to this block void -back_threader::find_paths_to_names (basic_block bb, bitmap interesting) +back_threader::find_paths_to_names (basic_block bb, bitmap interesting, + unsigned overall_paths) { if (m_visited_bbs.add (bb)) return; @@ -352,8 +355,10 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting) || maybe_register_path ())) ; - // Continue looking for ways to extend the path - else + // Continue looking for ways to extend the path but limit the + // search space along a branch + else if ((overall_paths = overall_paths * EDGE_COUNT (bb->preds)) + <= (unsigned)param_max_jump_thread_paths) { // For further greedy searching we want to remove interesting // names defined in BB but add ones on the PHI edges for the @@ -407,7 +412,7 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting) unwind.quick_push (def); } } - find_paths_to_names (e->src, new_interesting); + find_paths_to_names (e->src, new_interesting, overall_paths); // Restore new_interesting. We leave m_imports alone since // we do not prune defs in BB from it and separately keeping // track of which bits to unwind isn't worth the trouble. @@ -417,6 +422,9 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting) } } } + else if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " FAIL: Search space limit %d reached.\n", + param_max_jump_thread_paths); // Reset things to their original state. m_path.pop (); @@ -447,7 +455,7 @@ back_threader::find_paths (basic_block bb, tree name) auto_bitmap interesting; bitmap_copy (interesting, m_imports); - find_paths_to_names (bb, interesting); + find_paths_to_names (bb, interesting, 1); } } -- cgit v1.1 From c64ef5cd92c2e340caabc95f4a28c9a125e8b5b8 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 8 Aug 2022 14:04:43 +0200 Subject: Remove --param max-fsm-thread-length This removes max-fsm-thread-length which is obsoleted by max-jump-thread-paths. * doc/invoke.texi (max-fsm-thread-length): Remove. * params.opt (max-fsm-thread-length): Likewise. * tree-ssa-threadbackward.cc (back_threader_profitability::profitable_path_p): Do not check max-fsm-thread-length. --- gcc/doc/invoke.texi | 3 --- gcc/params.opt | 4 ---- gcc/tree-ssa-threadbackward.cc | 9 --------- 3 files changed, 16 deletions(-) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index f016966..58e4220 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -15262,9 +15262,6 @@ Emit instrumentation calls to __tsan_func_entry() and __tsan_func_exit(). Maximum number of instructions to copy when duplicating blocks on a finite state automaton jump thread path. -@item max-fsm-thread-length -Maximum number of basic blocks on a jump thread path. - @item threader-debug threader-debug=[none|all] Enables verbose dumping of the threader solver. diff --git a/gcc/params.opt b/gcc/params.opt index 1329873..201b5c9 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -498,10 +498,6 @@ The maximum number of nested indirect inlining performed by early inliner. Common Joined UInteger Var(param_max_fields_for_field_sensitive) Param Maximum number of fields in a structure before pointer analysis treats the structure as a single variable. --param=max-fsm-thread-length= -Common Joined UInteger Var(param_max_fsm_thread_length) Init(10) IntegerRange(1, 999999) Param Optimization -Maximum number of basic blocks on a jump thread path. - -param=max-fsm-thread-path-insns= Common Joined UInteger Var(param_max_fsm_thread_path_insns) Init(100) IntegerRange(1, 999999) Param Optimization Maximum number of instructions to copy when duplicating blocks on a finite state automaton jump thread path. diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc index a5f8f14..30047c6 100644 --- a/gcc/tree-ssa-threadbackward.cc +++ b/gcc/tree-ssa-threadbackward.cc @@ -569,15 +569,6 @@ back_threader_profitability::profitable_path_p (const vec &m_path, if (m_path.length () <= 1) return false; - if (m_path.length () > (unsigned) param_max_fsm_thread_length) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " FAIL: Jump-thread path not considered: " - "the number of basic blocks on the path " - "exceeds PARAM_MAX_FSM_THREAD_LENGTH.\n"); - return false; - } - int n_insns = 0; gimple_stmt_iterator gsi; loop_p loop = m_path[0]->loop_father; -- cgit v1.1 From 9aa08cd48490183382371bff4fd53573b5adabe8 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 2 Aug 2022 13:46:28 +0200 Subject: autopar TLC The following removes all excessive update_ssa calls from OMP expansion, thereby rewriting the atomic load and store cases to GIMPLE code generation. I don't think autopar ever exercises the atomics code though. There's not much test coverage overall so I've built SPEC 2k17 with -floop-parallelize-all -ftree-parallelize-loops=2 with and without LTO (and otherwise -Ofast plus -march=haswell) without fallout. If there's any fallout it's not OK to update SSA form for each and every OMP stmt lowered. * omp-expand.cc (expand_omp_atomic_load): Emit GIMPLE directly. Avoid update_ssa when in SSA form. (expand_omp_atomic_store): Likewise. (expand_omp_atomic_fetch_op): Avoid update_ssa when in SSA form. (expand_omp_atomic_pipeline): Likewise. (expand_omp_atomic_mutex): Likewise. * tree-parloops.cc (gen_parallel_loop): Use TODO_update_ssa_no_phi after loop_version. --- gcc/omp-expand.cc | 81 +++++++++++++++++++++++++++++++--------------------- gcc/tree-parloops.cc | 2 +- 2 files changed, 50 insertions(+), 33 deletions(-) (limited to 'gcc') diff --git a/gcc/omp-expand.cc b/gcc/omp-expand.cc index 64e6308..48fbd15 100644 --- a/gcc/omp-expand.cc +++ b/gcc/omp-expand.cc @@ -8617,7 +8617,7 @@ expand_omp_atomic_load (basic_block load_bb, tree addr, basic_block store_bb; location_t loc; gimple *stmt; - tree decl, call, type, itype; + tree decl, type, itype; gsi = gsi_last_nondebug_bb (load_bb); stmt = gsi_stmt (gsi); @@ -8637,23 +8637,33 @@ expand_omp_atomic_load (basic_block load_bb, tree addr, itype = TREE_TYPE (TREE_TYPE (decl)); enum omp_memory_order omo = gimple_omp_atomic_memory_order (stmt); - tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo)); - call = build_call_expr_loc (loc, decl, 2, addr, mo); + tree mo = build_int_cst (integer_type_node, + omp_memory_order_to_memmodel (omo)); + gcall *call = gimple_build_call (decl, 2, addr, mo); + gimple_set_location (call, loc); + gimple_set_vuse (call, gimple_vuse (stmt)); + gimple *repl; if (!useless_type_conversion_p (type, itype)) - call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call); - call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call); - - force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT); - gsi_remove (&gsi, true); + { + tree lhs = make_ssa_name (itype); + gimple_call_set_lhs (call, lhs); + gsi_insert_before (&gsi, call, GSI_SAME_STMT); + repl = gimple_build_assign (loaded_val, + build1 (VIEW_CONVERT_EXPR, type, lhs)); + gimple_set_location (repl, loc); + } + else + { + gimple_call_set_lhs (call, loaded_val); + repl = call; + } + gsi_replace (&gsi, repl, true); store_bb = single_succ (load_bb); gsi = gsi_last_nondebug_bb (store_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE); gsi_remove (&gsi, true); - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_no_phi); - return true; } @@ -8669,7 +8679,7 @@ expand_omp_atomic_store (basic_block load_bb, tree addr, basic_block store_bb = single_succ (load_bb); location_t loc; gimple *stmt; - tree decl, call, type, itype; + tree decl, type, itype; machine_mode imode; bool exchange; @@ -8710,25 +8720,36 @@ expand_omp_atomic_store (basic_block load_bb, tree addr, if (!useless_type_conversion_p (itype, type)) stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val); enum omp_memory_order omo = gimple_omp_atomic_memory_order (stmt); - tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo)); - call = build_call_expr_loc (loc, decl, 3, addr, stored_val, mo); + tree mo = build_int_cst (integer_type_node, + omp_memory_order_to_memmodel (omo)); + stored_val = force_gimple_operand_gsi (&gsi, stored_val, true, NULL_TREE, + true, GSI_SAME_STMT); + gcall *call = gimple_build_call (decl, 3, addr, stored_val, mo); + gimple_set_location (call, loc); + gimple_set_vuse (call, gimple_vuse (stmt)); + gimple_set_vdef (call, gimple_vdef (stmt)); + + gimple *repl = call; if (exchange) { if (!useless_type_conversion_p (type, itype)) - call = build1_loc (loc, VIEW_CONVERT_EXPR, type, call); - call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call); + { + tree lhs = make_ssa_name (itype); + gimple_call_set_lhs (call, lhs); + gsi_insert_before (&gsi, call, GSI_SAME_STMT); + repl = gimple_build_assign (loaded_val, + build1 (VIEW_CONVERT_EXPR, type, lhs)); + gimple_set_location (repl, loc); + } + else + gimple_call_set_lhs (call, loaded_val); } - - force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT); - gsi_remove (&gsi, true); + gsi_replace (&gsi, repl, true); /* Remove the GIMPLE_OMP_ATOMIC_LOAD that we verified above. */ gsi = gsi_last_nondebug_bb (load_bb); gsi_remove (&gsi, true); - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_no_phi); - return true; } @@ -8874,10 +8895,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb, gsi_remove (&gsi, true); if (gimple_in_ssa_p (cfun)) - { - release_defs (stmt); - update_ssa (TODO_update_ssa_no_phi); - } + release_defs (stmt); return true; } @@ -9333,16 +9351,16 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb, } /* Remove GIMPLE_OMP_ATOMIC_STORE. */ + stmt = gsi_stmt (si); gsi_remove (&si, true); + if (gimple_in_ssa_p (cfun)) + release_defs (stmt); class loop *loop = alloc_loop (); loop->header = loop_header; loop->latch = store_bb; add_loop (loop, loop_header->loop_father); - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_no_phi); - return true; } @@ -9399,15 +9417,14 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb, gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE); stmt = gimple_build_assign (unshare_expr (mem), stored_val); + gimple_set_vuse (stmt, gimple_vuse (gsi_stmt (si))); + gimple_set_vdef (stmt, gimple_vdef (gsi_stmt (si))); gsi_insert_before (&si, stmt, GSI_SAME_STMT); t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END); t = build_call_expr (t, 0); force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); gsi_remove (&si, true); - - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_no_phi); return true; } diff --git a/gcc/tree-parloops.cc b/gcc/tree-parloops.cc index 2d3aa78..b070527 100644 --- a/gcc/tree-parloops.cc +++ b/gcc/tree-parloops.cc @@ -3082,7 +3082,7 @@ gen_parallel_loop (class loop *loop, profile_probability::unlikely (), profile_probability::likely (), profile_probability::unlikely (), true); - update_ssa (TODO_update_ssa); + update_ssa (TODO_update_ssa_no_phi); free_original_copy_tables (); } -- cgit v1.1 From 4e1914625dec4aa09a5671c6294e877dbf4518f5 Mon Sep 17 00:00:00 2001 From: Andrew Stubbs Date: Fri, 15 Jul 2022 09:47:36 +0100 Subject: amdgcn: Vector procedure call ABI Adjust the (unofficial) procedure calling ABI such that vector arguments are passed in vector registers, not on the stack. Scalar arguments continue to be passed in scalar registers, making a total of 12 argument registers. The return value is also moved to a vector register (even for scalars; it would be possible to retain the scalar location, using untyped_call, but there's no obvious advantage in doing so). After this change the ABI is as follows: s0-s13 : Reserved for kernel launch parameters. s14-s15 : Frame pointer. s16-s17 : Stack pointer. s18-s19 : Link register. s20-s21 : Exec Save. s22-s23 : CC Save. s24-s25 : Scalar arguments. NO LONGER RETURN VALUE. s26-s29 : Additional scalar arguments (makes 6 total). s30-s31 : Static Chain. v0 : Prologue/epilogue scratch. v1 : Constant 0, 1, 2, 3, 4, ... 63. v2-v7 : Prologue/epilogue scratch. v8-v9 : Return value & vector arguments. NEW. v10-v13 : Additional vector arguments (makes 6 total). NEW. gcc/ChangeLog: * config/gcn/gcn.cc (gcn_function_value): Allow vector return values. (num_arg_regs): Allow vector arguments. (gcn_function_arg): Likewise. (gcn_function_arg_advance): Likewise. (gcn_arg_partial_bytes): Likewise. (gcn_return_in_memory): Likewise. (gcn_expand_epilogue): Get return value from v8. * config/gcn/gcn.h (RETURN_VALUE_REG): Set to v8. (FIRST_PARM_REG): USE FIRST_SGPR_REG for clarity. (FIRST_VPARM_REG): New. (FUNCTION_ARG_REGNO_P): Allow vector parameters. (struct gcn_args): Add vnum field. (LIBCALL_VALUE): All vector return values. * config/gcn/gcn.md (gcn_call_value): Add vector constraints. (gcn_call_value_indirect): Likewise. --- gcc/config/gcn/gcn.cc | 50 +++++++++++++++++++++++++++++--------------------- gcc/config/gcn/gcn.h | 11 +++++++---- gcc/config/gcn/gcn.md | 12 ++++++------ 3 files changed, 42 insertions(+), 31 deletions(-) (limited to 'gcc') diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index 6fc20d3..96295e2 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -2284,7 +2284,7 @@ gcn_function_value (const_tree valtype, const_tree, bool) && GET_MODE_SIZE (mode) < 4) mode = SImode; - return gen_rtx_REG (mode, SGPR_REGNO (RETURN_VALUE_REG)); + return gen_rtx_REG (mode, RETURN_VALUE_REG); } /* Implement TARGET_FUNCTION_VALUE_REGNO_P. @@ -2308,7 +2308,9 @@ num_arg_regs (const function_arg_info &arg) return 0; int size = arg.promoted_size_in_bytes (); - return (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + int regsize = UNITS_PER_WORD * (VECTOR_MODE_P (arg.mode) + ? GET_MODE_NUNITS (arg.mode) : 1); + return (size + regsize - 1) / regsize; } /* Implement TARGET_STRICT_ARGUMENT_NAMING. @@ -2358,16 +2360,16 @@ gcn_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) if (targetm.calls.must_pass_in_stack (arg)) return 0; - /* Vector parameters are not supported yet. */ - if (VECTOR_MODE_P (arg.mode)) - return 0; - - int reg_num = FIRST_PARM_REG + cum->num; + int first_reg = (VECTOR_MODE_P (arg.mode) + ? FIRST_VPARM_REG : FIRST_PARM_REG); + int cum_num = (VECTOR_MODE_P (arg.mode) + ? cum->vnum : cum->num); + int reg_num = first_reg + cum_num; int num_regs = num_arg_regs (arg); if (num_regs > 0) while (reg_num % num_regs != 0) reg_num++; - if (reg_num + num_regs <= FIRST_PARM_REG + NUM_PARM_REGS) + if (reg_num + num_regs <= first_reg + NUM_PARM_REGS) return gen_rtx_REG (arg.mode, reg_num); } else @@ -2419,11 +2421,15 @@ gcn_function_arg_advance (cumulative_args_t cum_v, if (!arg.named) return; + int first_reg = (VECTOR_MODE_P (arg.mode) + ? FIRST_VPARM_REG : FIRST_PARM_REG); + int *cum_num = (VECTOR_MODE_P (arg.mode) + ? &cum->vnum : &cum->num); int num_regs = num_arg_regs (arg); if (num_regs > 0) - while ((FIRST_PARM_REG + cum->num) % num_regs != 0) - cum->num++; - cum->num += num_regs; + while ((first_reg + *cum_num) % num_regs != 0) + (*cum_num)++; + *cum_num += num_regs; } else { @@ -2454,14 +2460,18 @@ gcn_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg) if (targetm.calls.must_pass_in_stack (arg)) return 0; - if (cum->num >= NUM_PARM_REGS) + int cum_num = (VECTOR_MODE_P (arg.mode) ? cum->vnum : cum->num); + int regsize = UNITS_PER_WORD * (VECTOR_MODE_P (arg.mode) + ? GET_MODE_NUNITS (arg.mode) : 1); + + if (cum_num >= NUM_PARM_REGS) return 0; /* If the argument fits entirely in registers, return 0. */ - if (cum->num + num_arg_regs (arg) <= NUM_PARM_REGS) + if (cum_num + num_arg_regs (arg) <= NUM_PARM_REGS) return 0; - return (NUM_PARM_REGS - cum->num) * UNITS_PER_WORD; + return (NUM_PARM_REGS - cum_num) * regsize; } /* A normal function which takes a pointer argument (to a scalar) may be @@ -2549,14 +2559,11 @@ gcn_return_in_memory (const_tree type, const_tree ARG_UNUSED (fntype)) if (AGGREGATE_TYPE_P (type)) return true; - /* Vector return values are not supported yet. */ - if (VECTOR_TYPE_P (type)) - return true; - if (mode == BLKmode) return true; - if (size > 2 * UNITS_PER_WORD) + if ((!VECTOR_TYPE_P (type) && size > 2 * UNITS_PER_WORD) + || size > 2 * UNITS_PER_WORD * 64) return true; return false; @@ -3199,9 +3206,10 @@ gcn_expand_epilogue (void) emit_move_insn (kernarg_reg, retptr_mem); rtx retval_mem = gen_rtx_MEM (SImode, kernarg_reg); + rtx scalar_retval = gen_rtx_REG (SImode, FIRST_PARM_REG); set_mem_addr_space (retval_mem, ADDR_SPACE_SCALAR_FLAT); - emit_move_insn (retval_mem, - gen_rtx_REG (SImode, SGPR_REGNO (RETURN_VALUE_REG))); + emit_move_insn (scalar_retval, gen_rtx_REG (SImode, RETURN_VALUE_REG)); + emit_move_insn (retval_mem, scalar_retval); } emit_jump_insn (gen_gcn_return ()); diff --git a/gcc/config/gcn/gcn.h b/gcc/config/gcn/gcn.h index a129760..318256c 100644 --- a/gcc/config/gcn/gcn.h +++ b/gcc/config/gcn/gcn.h @@ -138,7 +138,7 @@ #define LINK_REGNUM 18 #define EXEC_SAVE_REG 20 #define CC_SAVE_REG 22 -#define RETURN_VALUE_REG 24 /* Must be divisible by 4. */ +#define RETURN_VALUE_REG 168 /* Must be divisible by 4. */ #define STATIC_CHAIN_REGNUM 30 #define WORK_ITEM_ID_Z_REG 162 #define SOFT_ARG_REG 416 @@ -146,7 +146,8 @@ #define DWARF_LINK_REGISTER 420 #define FIRST_PSEUDO_REGISTER 421 -#define FIRST_PARM_REG 24 +#define FIRST_PARM_REG (FIRST_SGPR_REG + 24) +#define FIRST_VPARM_REG (FIRST_VGPR_REG + 8) #define NUM_PARM_REGS 6 /* There is no arg pointer. Just choose random fixed register that does @@ -164,7 +165,8 @@ #define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X))) #define CC_REGNO_P(X) ((X) == SCC_REG || (X) == VCC_REG) #define FUNCTION_ARG_REGNO_P(N) \ - ((N) >= FIRST_PARM_REG && (N) < (FIRST_PARM_REG + NUM_PARM_REGS)) + (((N) >= FIRST_PARM_REG && (N) < (FIRST_PARM_REG + NUM_PARM_REGS)) \ + || ((N) >= FIRST_VPARM_REG && (N) < (FIRST_VPARM_REG + NUM_PARM_REGS))) #define FIXED_REGISTERS { \ @@ -550,6 +552,7 @@ typedef struct gcn_args tree fntype; struct gcn_kernel_args args; int num; + int vnum; int offset; int alignment; } CUMULATIVE_ARGS; @@ -653,7 +656,7 @@ enum gcn_builtin_codes } /* This needs to match gcn_function_value. */ -#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, SGPR_REGNO (RETURN_VALUE_REG)) +#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, RETURN_VALUE_REG) /* The s_ff0 and s_flbit instructions return -1 if no input bits are set. */ #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = -1, 2) diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md index 70a769b..7805e86 100644 --- a/gcc/config/gcn/gcn.md +++ b/gcc/config/gcn/gcn.md @@ -908,11 +908,11 @@ {}) (define_insn "gcn_call_value" - [(set (match_operand 0 "register_operand" "=Sg,Sg") - (call (mem (match_operand 1 "immediate_operand" "Y,B")) + [(set (match_operand 0 "register_operand" "=Sgv,Sgv") + (call (mem (match_operand 1 "immediate_operand" " Y, B")) (match_operand 2 "const_int_operand"))) (clobber (reg:DI LR_REGNUM)) - (clobber (match_scratch:DI 3 "=&Sg,X"))] + (clobber (match_scratch:DI 3 "=&Sg, X"))] "" "@ s_getpc_b64\t%3\;s_add_u32\t%L3, %L3, %1@rel32@lo+4\;s_addc_u32\t%H3, %H3, %1@rel32@hi+4\;s_swappc_b64\ts[18:19], %3 @@ -921,11 +921,11 @@ (set_attr "length" "24")]) (define_insn "gcn_call_value_indirect" - [(set (match_operand 0 "register_operand" "=Sg") - (call (mem (match_operand:DI 1 "register_operand" "Sg")) + [(set (match_operand 0 "register_operand" "=Sgv") + (call (mem (match_operand:DI 1 "register_operand" " Sg")) (match_operand 2 "" ""))) (clobber (reg:DI LR_REGNUM)) - (clobber (match_scratch:DI 3 "=X"))] + (clobber (match_scratch:DI 3 "= X"))] "" "s_swappc_b64\ts[18:19], %1" [(set_attr "type" "sop1") -- cgit v1.1 From 04284176d549ff2565406406a6d53ab4ba8e507d Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 9 Aug 2022 12:48:14 +0200 Subject: d: Fix undefined reference to pragma(inline) symbol (PR106563) Functions that are declared `pragma(inline)' should be treated as if they are defined in every translation unit they are referenced from, regardless of visibility protection. Ensure they always get DECL_ONE_ONLY linkage, and start emitting them into other modules that import them. PR d/106563 gcc/d/ChangeLog: * decl.cc (DeclVisitor::visit (FuncDeclaration *)): Set semanticRun before generating its symbol. (function_defined_in_root_p): New function. (function_needs_inline_definition_p): New function. (maybe_build_decl_tree): New function. (get_symbol_decl): Call maybe_build_decl_tree before returning symbol. (start_function): Use function_defined_in_root_p instead of inline test for locally defined symbols. (set_linkage_for_decl): Check for inline functions before private or protected symbols. gcc/testsuite/ChangeLog: * gdc.dg/torture/torture.exp (srcdir): New proc. * gdc.dg/torture/imports/pr106563math.d: New test. * gdc.dg/torture/imports/pr106563regex.d: New test. * gdc.dg/torture/imports/pr106563uni.d: New test. * gdc.dg/torture/pr106563.d: New test. --- gcc/d/decl.cc | 121 +++++++++++++++++---- .../gdc.dg/torture/imports/pr106563math.d | 12 ++ .../gdc.dg/torture/imports/pr106563regex.d | 7 ++ gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d | 15 +++ gcc/testsuite/gdc.dg/torture/pr106563.d | 16 +++ gcc/testsuite/gdc.dg/torture/torture.exp | 9 ++ 6 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gdc.dg/torture/imports/pr106563math.d create mode 100644 gcc/testsuite/gdc.dg/torture/imports/pr106563regex.d create mode 100644 gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d create mode 100644 gcc/testsuite/gdc.dg/torture/pr106563.d (limited to 'gcc') diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 58cea4d..0131b01 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -828,6 +828,10 @@ public: if (global.errors) return; + /* Start generating code for this function. */ + gcc_assert (d->semanticRun == PASS::semantic3done); + d->semanticRun = PASS::obj; + /* Duplicated FuncDeclarations map to the same symbol. Check if this is the one declaration which will be emitted. */ tree fndecl = get_symbol_decl (d); @@ -844,10 +848,6 @@ public: if (global.params.verbose) message ("function %s", d->toPrettyChars ()); - /* Start generating code for this function. */ - gcc_assert (d->semanticRun == PASS::semantic3done); - d->semanticRun = PASS::obj; - tree old_context = start_function (d); tree parm_decl = NULL_TREE; @@ -1020,13 +1020,103 @@ build_decl_tree (Dsymbol *d) input_location = saved_location; } +/* Returns true if function FD is defined or instantiated in a root module. */ + +static bool +function_defined_in_root_p (FuncDeclaration *fd) +{ + Module *md = fd->getModule (); + if (md && md->isRoot ()) + return true; + + TemplateInstance *ti = fd->isInstantiated (); + if (ti && ti->minst && ti->minst->isRoot ()) + return true; + + return false; +} + +/* Returns true if function FD always needs to be implicitly defined, such as + it was declared `pragma(inline)'. */ + +static bool +function_needs_inline_definition_p (FuncDeclaration *fd) +{ + /* Function has already been defined. */ + if (!DECL_EXTERNAL (fd->csym)) + return false; + + /* Non-inlineable functions are always external. */ + if (DECL_UNINLINABLE (fd->csym)) + return false; + + /* No function body available for inlining. */ + if (!fd->fbody) + return false; + + /* Ignore functions that aren't decorated with `pragma(inline)'. */ + if (fd->inlining != PINLINE::always) + return false; + + /* These functions are tied to the module they are defined in. */ + if (fd->isFuncLiteralDeclaration () + || fd->isUnitTestDeclaration () + || fd->isFuncAliasDeclaration () + || fd->isInvariantDeclaration ()) + return false; + + /* Check whether function will be regularly defined later in the current + translation unit. */ + if (function_defined_in_root_p (fd)) + return false; + + /* Weak functions cannot be inlined. */ + if (lookup_attribute ("weak", DECL_ATTRIBUTES (fd->csym))) + return false; + + /* Naked functions cannot be inlined. */ + if (lookup_attribute ("naked", DECL_ATTRIBUTES (fd->csym))) + return false; + + return true; +} + +/* If the variable or function declaration in DECL needs to be defined, call + build_decl_tree on it now before returning its back-end symbol. */ + +static tree +maybe_build_decl_tree (Declaration *decl) +{ + gcc_assert (decl->csym != NULL_TREE); + + /* Still running semantic analysis on declaration, or it has already had its + code generated. */ + if (doing_semantic_analysis_p || decl->semanticRun >= PASS::obj) + return decl->csym; + + if (error_operand_p (decl->csym)) + return decl->csym; + + if (FuncDeclaration *fd = decl->isFuncDeclaration ()) + { + /* Externally defined inline functions need to be emitted. */ + if (function_needs_inline_definition_p (fd)) + { + DECL_EXTERNAL (fd->csym) = 0; + build_decl_tree (fd); + } + } + + return decl->csym; +} + /* Return the decl for the symbol, create it if it doesn't already exist. */ tree get_symbol_decl (Declaration *decl) { if (decl->csym) - return decl->csym; + return maybe_build_decl_tree (decl); /* Deal with placeholder symbols immediately: SymbolDeclaration is used as a shell around an initializer symbol. */ @@ -1404,7 +1494,7 @@ get_symbol_decl (Declaration *decl) TREE_USED (decl->csym) = 1; d_keep (decl->csym); - return decl->csym; + return maybe_build_decl_tree (decl); } /* Returns a declaration for a VAR_DECL. Used to create compiler-generated @@ -1895,15 +1985,8 @@ start_function (FuncDeclaration *fd) /* Function has been defined, check now whether we intend to send it to object file, or it really is extern. Such as inlinable functions from modules not in this compilation, or thunk aliases. */ - TemplateInstance *ti = fd->isInstantiated (); - if (ti && ti->needsCodegen ()) + if (function_defined_in_root_p (fd)) DECL_EXTERNAL (fndecl) = 0; - else - { - Module *md = fd->getModule (); - if (md && md->isRoot ()) - DECL_EXTERNAL (fndecl) = 0; - } DECL_INITIAL (fndecl) = error_mark_node; @@ -2422,16 +2505,16 @@ set_linkage_for_decl (tree decl) if (!TREE_PUBLIC (decl)) return; - /* Don't need to give private or protected symbols a special linkage. */ - if ((TREE_PRIVATE (decl) || TREE_PROTECTED (decl)) - && !DECL_INSTANTIATED (decl)) - return; - /* Functions declared as `pragma(inline, true)' can appear in multiple translation units. */ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)) return d_comdat_linkage (decl); + /* Don't need to give private or protected symbols a special linkage. */ + if ((TREE_PRIVATE (decl) || TREE_PROTECTED (decl)) + && !DECL_INSTANTIATED (decl)) + return; + /* If all instantiations must go in COMDAT, give them that linkage. This also applies to other extern declarations, so that it is possible for them to override template declarations. */ diff --git a/gcc/testsuite/gdc.dg/torture/imports/pr106563math.d b/gcc/testsuite/gdc.dg/torture/imports/pr106563math.d new file mode 100644 index 0000000..b9351ea --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/imports/pr106563math.d @@ -0,0 +1,12 @@ +module imports.pr106563math; + +T nextPow2(T)(const T val) +{ + return powIntegralImpl(val); +} + +pragma(inline, true) +T powIntegralImpl(T)(T) +{ + return 1; +} diff --git a/gcc/testsuite/gdc.dg/torture/imports/pr106563regex.d b/gcc/testsuite/gdc.dg/torture/imports/pr106563regex.d new file mode 100644 index 0000000..a2cd90c --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/imports/pr106563regex.d @@ -0,0 +1,7 @@ +module imports.pr106563regex; +import imports.pr106563uni; + +struct CharMatcher +{ + typeof(MultiArray!().length) trie; +} diff --git a/gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d b/gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d new file mode 100644 index 0000000..16e3bc8 --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d @@ -0,0 +1,15 @@ +module imports.pr106563uni; + +struct MultiArray() +{ + @property length() + { + return spaceFor!0(); + } +} + +size_t spaceFor(size_t bits)() +{ + import imports.pr106563math; + return nextPow2(bits); +} diff --git a/gcc/testsuite/gdc.dg/torture/pr106563.d b/gcc/testsuite/gdc.dg/torture/pr106563.d new file mode 100644 index 0000000..7e15442 --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/pr106563.d @@ -0,0 +1,16 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106563 +// { dg-do link } +// { dg-additional-files "imports/pr106563math.d imports/pr106563regex.d imports/pr106563uni.d" } +// { dg-additional-options "-I[srcdir] -fno-druntime" } +import imports.pr106563math; +import imports.pr106563regex; + +auto requireSize()(size_t size) +{ + return nextPow2(size); +} + +extern(C) int main() +{ + return cast(int)requireSize(0); +} diff --git a/gcc/testsuite/gdc.dg/torture/torture.exp b/gcc/testsuite/gdc.dg/torture/torture.exp index f7d00b1..d9c6a79 100644 --- a/gcc/testsuite/gdc.dg/torture/torture.exp +++ b/gcc/testsuite/gdc.dg/torture/torture.exp @@ -19,6 +19,15 @@ # Load support procs. load_lib gdc-dg.exp +# Helper function allows adding tests that use imports/*, but don't compile +# the sources in with dg-additional-sources. +global testdir +set testdir $srcdir/$subdir +proc srcdir {} { + global testdir + return $testdir +} + # The default option list can be overridden by # TORTURE_OPTIONS="{ { list1 } ... { listN } }" -- cgit v1.1