From b0f02eeb906b6351099ac97066ef74b6167d9ecb Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 14 Jul 2022 12:15:35 +0200 Subject: Fix ICE on view conversion between struct and integer This happens from prepare_gimple_addressable for the variable to be marked with DECL_NOT_GIMPLE_REG_P when its initialization is gimplified, so it's apparently just a matter of setting the flag earlier. gcc/ * gimplify.cc (lookup_tmp_var): Add NOT_GIMPLE_REG boolean parameter and set DECL_NOT_GIMPLE_REG_P on the variable according to it. (internal_get_tmp_var): Add NOT_GIMPLE_REG boolean parameter and pass it in the call to lookup_tmp_var. (get_formal_tmp_var): Pass false in the call to lookup_tmp_var. (get_initialized_tmp_var): Likewise. (prepare_gimple_addressable): Call internal_get_tmp_var instead of get_initialized_tmp_var with NOT_GIMPLE_REG set to true. gcc/testsuite/ * gnat.dg/opt98.ads, gnat.dg/opt98.adb: New test. --- gcc/gimplify.cc | 29 ++++++++++++++++------------- gcc/testsuite/gnat.dg/opt98.adb | 14 ++++++++++++++ gcc/testsuite/gnat.dg/opt98.ads | 19 +++++++++++++++++++ 3 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/opt98.adb create mode 100644 gcc/testsuite/gnat.dg/opt98.ads (limited to 'gcc') diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 04990ad..2ac7ca0 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -573,20 +573,26 @@ create_tmp_from_val (tree val) } /* Create a temporary to hold the value of VAL. If IS_FORMAL, try to reuse - an existing expression temporary. */ + an existing expression temporary. If NOT_GIMPLE_REG, mark it as such. */ static tree -lookup_tmp_var (tree val, bool is_formal) +lookup_tmp_var (tree val, bool is_formal, bool not_gimple_reg) { tree ret; + /* We cannot mark a formal temporary with DECL_NOT_GIMPLE_REG_P. */ + gcc_assert (!is_formal || !not_gimple_reg); + /* If not optimizing, never really reuse a temporary. local-alloc won't allocate any variable that is used in more than one basic block, which means it will go into memory, causing much extra work in reload and final and poorer code generation, outweighing the extra memory allocation here. */ if (!optimize || !is_formal || TREE_SIDE_EFFECTS (val)) - ret = create_tmp_from_val (val); + { + ret = create_tmp_from_val (val); + DECL_NOT_GIMPLE_REG_P (ret) = not_gimple_reg; + } else { elt_t elt, *elt_p; @@ -617,7 +623,7 @@ lookup_tmp_var (tree val, bool is_formal) static tree internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p, - bool is_formal, bool allow_ssa) + bool is_formal, bool allow_ssa, bool not_gimple_reg) { tree t, mod; @@ -639,7 +645,7 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p, } } else - t = lookup_tmp_var (val, is_formal); + t = lookup_tmp_var (val, is_formal, not_gimple_reg); mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val)); @@ -667,7 +673,7 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p, tree get_formal_tmp_var (tree val, gimple_seq *pre_p) { - return internal_get_tmp_var (val, pre_p, NULL, true, true); + return internal_get_tmp_var (val, pre_p, NULL, true, true, false); } /* Return a temporary variable initialized with VAL. PRE_P and POST_P @@ -678,7 +684,7 @@ get_initialized_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p /* = NULL */, bool allow_ssa /* = true */) { - return internal_get_tmp_var (val, pre_p, post_p, false, allow_ssa); + return internal_get_tmp_var (val, pre_p, post_p, false, allow_ssa, false); } /* Declare all the variables in VARS in SCOPE. If DEBUG_INFO is true, @@ -4574,13 +4580,10 @@ prepare_gimple_addressable (tree *expr_p, gimple_seq *seq_p) { while (handled_component_p (*expr_p)) expr_p = &TREE_OPERAND (*expr_p, 0); + + /* Do not allow an SSA name as the temporary. */ if (is_gimple_reg (*expr_p)) - { - /* Do not allow an SSA name as the temporary. */ - tree var = get_initialized_tmp_var (*expr_p, seq_p, NULL, false); - DECL_NOT_GIMPLE_REG_P (var) = 1; - *expr_p = var; - } + *expr_p = internal_get_tmp_var (*expr_p, seq_p, NULL, false, false, true); } /* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with diff --git a/gcc/testsuite/gnat.dg/opt98.adb b/gcc/testsuite/gnat.dg/opt98.adb new file mode 100644 index 0000000..6d42338 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt98.adb @@ -0,0 +1,14 @@ +-- { dg-do compile } +-- { dg-options "-O -gnatws" } + +package body Opt98 is + + function Func return Rec is + R :Rec; + begin + A := To_Address ((I => 0)); + R := To_Rec (A); + return R; + end; + +end Opt98; diff --git a/gcc/testsuite/gnat.dg/opt98.ads b/gcc/testsuite/gnat.dg/opt98.ads new file mode 100644 index 0000000..fcc70577 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt98.ads @@ -0,0 +1,19 @@ +with Ada.Unchecked_Conversion; +with System; + +package Opt98 is + + type Rec is record + I : Integer; + end record; + + function To_Address is new Ada.Unchecked_Conversion (Rec, System.Address); + + function To_Rec is new Ada.Unchecked_Conversion (System.Address, Rec); + + A : System.Address with Atomic; + + function Func return Rec; + +end Opt98; + -- cgit v1.1 From b4f81085d1ef5776be30f95c102ec67daf03c35c Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 13 Jul 2022 12:28:11 +0100 Subject: jit: Make recording::memento non-copyable gcc/jit/ChangeLog: * jit-recording.h (recording::memento): Define copy constructor and copy assignment operator as deleted. (recording::string): Likewise. (recording::string::c_str): Add const qualifier. --- gcc/jit/jit-recording.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 0dfb42f..8610ea9 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -405,6 +405,9 @@ public: virtual void write_reproducer (reproducer &r) = 0; virtual location *dyn_cast_location () { return NULL; } + memento (const memento&) = delete; + memento& operator= (const memento&) = delete; + protected: memento (context *ctxt) : m_ctxt (ctxt), @@ -436,13 +439,16 @@ public: string (context *ctxt, const char *text, bool escaped); ~string (); - const char *c_str () { return m_buffer; } + const char *c_str () const { return m_buffer; } static string * from_printf (context *ctxt, const char *fmt, ...) GNU_PRINTF(2, 3); void replay_into (replayer *) final override {} + string (const string&) = delete; + string& operator= (const string&) = delete; + private: string * make_debug_string () final override; void write_reproducer (reproducer &r) final override; -- cgit v1.1 From 748f8a8b145dde59c7b63aa68b5a59515b7efc49 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Thu, 14 Jul 2022 22:24:55 +0200 Subject: Fortran: error recovery for bad initializers of implied-shape arrays [PR106209] gcc/fortran/ChangeLog: PR fortran/106209 * decl.cc (add_init_expr_to_sym): Handle bad initializers for implied-shape arrays. gcc/testsuite/ChangeLog: PR fortran/106209 * gfortran.dg/pr106209.f90: New test. Co-authored-by: Steven G. Kargl --- gcc/fortran/decl.cc | 15 +++++++++++++-- gcc/testsuite/gfortran.dg/pr106209.f90 | 9 +++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr106209.f90 (limited to 'gcc') diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc index 339f8b1..b640051 100644 --- a/gcc/fortran/decl.cc +++ b/gcc/fortran/decl.cc @@ -2129,10 +2129,21 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus) /* The shape may be NULL for EXPR_ARRAY, set it. */ if (init->shape == NULL) { - gcc_assert (init->expr_type == EXPR_ARRAY); + if (init->expr_type != EXPR_ARRAY) + { + gfc_error ("Bad shape of initializer at %L", &init->where); + return false; + } + init->shape = gfc_get_shape (1); if (!gfc_array_size (init, &init->shape[0])) - gfc_internal_error ("gfc_array_size failed"); + { + gfc_error ("Cannot determine shape of initializer at %L", + &init->where); + free (init->shape); + init->shape = NULL; + return false; + } } for (dim = 0; dim < sym->as->rank; ++dim) diff --git a/gcc/testsuite/gfortran.dg/pr106209.f90 b/gcc/testsuite/gfortran.dg/pr106209.f90 new file mode 100644 index 0000000..44f9233 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr106209.f90 @@ -0,0 +1,9 @@ +! { dg-do compile } +! PR fortran/106209 - ICE in add_init_expr_to_sym +! Contributed by G.Steinmetz + +program p + integer, parameter :: a(:) = 0 ! { dg-error "of deferred shape" } + integer, parameter :: b(*) = a ! { dg-error "Bad shape of initializer" } + integer, parameter :: c(*) = [a] ! { dg-error "Cannot determine shape" } +end -- cgit v1.1 From c6cf555a88f8ffb8ec85c2b94fe656ab217260ea Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 17 Jun 2022 07:33:06 -0700 Subject: Simplify memchr with small constant strings When memchr is applied on a constant string of no more than the bytes of a word, simplify memchr by checking each byte in the constant string. int f (int a) { return __builtin_memchr ("AE", a, 2) != 0; } is simplified to int f (int a) { return ((char) a == 'A' || (char) a == 'E') != 0; } gcc/ PR tree-optimization/103798 * tree-ssa-forwprop.cc: Include "tree-ssa-strlen.h". (simplify_builtin_call): Inline memchr with constant strings of no more than the bytes of a word. * tree-ssa-strlen.cc (use_in_zero_equality): Make it global. * tree-ssa-strlen.h (use_in_zero_equality): New. gcc/testsuite/ PR tree-optimization/103798 * c-c++-common/pr103798-1.c: New test. * c-c++-common/pr103798-2.c: Likewise. * c-c++-common/pr103798-3.c: Likewise. * c-c++-common/pr103798-4.c: Likewise. * c-c++-common/pr103798-5.c: Likewise. * c-c++-common/pr103798-6.c: Likewise. * c-c++-common/pr103798-7.c: Likewise. * c-c++-common/pr103798-8.c: Likewise. * c-c++-common/pr103798-9.c: Likewise. * c-c++-common/pr103798-10.c: Likewise. --- gcc/testsuite/c-c++-common/pr103798-1.c | 28 +++++++++++++ gcc/testsuite/c-c++-common/pr103798-10.c | 10 +++++ gcc/testsuite/c-c++-common/pr103798-2.c | 30 +++++++++++++ gcc/testsuite/c-c++-common/pr103798-3.c | 28 +++++++++++++ gcc/testsuite/c-c++-common/pr103798-4.c | 28 +++++++++++++ gcc/testsuite/c-c++-common/pr103798-5.c | 26 ++++++++++++ gcc/testsuite/c-c++-common/pr103798-6.c | 27 ++++++++++++ gcc/testsuite/c-c++-common/pr103798-7.c | 27 ++++++++++++ gcc/testsuite/c-c++-common/pr103798-8.c | 27 ++++++++++++ gcc/testsuite/c-c++-common/pr103798-9.c | 10 +++++ gcc/tree-ssa-forwprop.cc | 72 ++++++++++++++++++++++++++++++++ gcc/tree-ssa-strlen.cc | 4 +- gcc/tree-ssa-strlen.h | 2 + 13 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/pr103798-1.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-10.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-2.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-3.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-4.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-5.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-6.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-7.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-8.c create mode 100644 gcc/testsuite/c-c++-common/pr103798-9.c (limited to 'gcc') diff --git a/gcc/testsuite/c-c++-common/pr103798-1.c b/gcc/testsuite/c-c++-common/pr103798-1.c new file mode 100644 index 0000000..cd3edf5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-1.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */ + +__attribute__ ((weak)) +int +f (char a) +{ + return __builtin_memchr ("a", a, 1) == 0; +} + +__attribute__ ((weak)) +int +g (char a) +{ + return a != 'a'; +} + +int +main () +{ + for (int i = 0; i < 255; i++) + if (f (i) != g (i)) + __builtin_abort (); + + return 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-10.c b/gcc/testsuite/c-c++-common/pr103798-10.c new file mode 100644 index 0000000..4677e95 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-10.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -fdump-tree-optimized -save-temps" } */ + +int +f (char a) +{ + return __builtin_memchr ("ac", a, 1) == 0; +} + +/* { dg-final { scan-assembler "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-2.c b/gcc/testsuite/c-c++-common/pr103798-2.c new file mode 100644 index 0000000..e7e99c3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-2.c @@ -0,0 +1,30 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */ + +#include + +__attribute__ ((weak)) +int +f (int a) +{ + return memchr ("aE", a, 2) != NULL; +} + +__attribute__ ((weak)) +int +g (char a) +{ + return a == 'a' || a == 'E'; +} + +int +main () +{ + for (int i = 0; i < 255; i++) + if (f (i + 256) != g (i + 256)) + __builtin_abort (); + + return 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-3.c b/gcc/testsuite/c-c++-common/pr103798-3.c new file mode 100644 index 0000000..ddcedc7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-3.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */ + +__attribute__ ((weak)) +int +f (char a) +{ + return __builtin_memchr ("aEgZ", a, 3) == 0; +} + +__attribute__ ((weak)) +int +g (char a) +{ + return a != 'a' && a != 'E' && a != 'g'; +} + +int +main () +{ + for (int i = 0; i < 255; i++) + if (f (i) != g (i)) + __builtin_abort (); + + return 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-4.c b/gcc/testsuite/c-c++-common/pr103798-4.c new file mode 100644 index 0000000..00e8302 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-4.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */ + +__attribute__ ((weak)) +int +f (char a) +{ + return __builtin_memchr ("aEgi", a, 4) != 0; +} + +__attribute__ ((weak)) +int +g (char a) +{ + return a == 'a' || a == 'E' || a == 'g' || a == 'i'; +} + +int +main () +{ + for (int i = 0; i < 255; i++) + if (f (i) != g (i)) + __builtin_abort (); + + return 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-5.c b/gcc/testsuite/c-c++-common/pr103798-5.c new file mode 100644 index 0000000..0d6487a --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-5.c @@ -0,0 +1,26 @@ +/* { dg-do run { target int128 } } */ +/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */ + +__attribute__ ((weak)) +int f(char a) +{ + return __builtin_memchr ("aEgiH", a, 5) == 0; +} + +__attribute__ ((weak)) +int g(char a) +{ + return a != 'a' && a != 'E' && a != 'g' && a != 'i' && a != 'H'; +} + +int +main () +{ + for (int i = 0; i < 255; i++) + if (f (i) != g (i)) + __builtin_abort (); + + return 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-6.c b/gcc/testsuite/c-c++-common/pr103798-6.c new file mode 100644 index 0000000..5ccb5ee --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-6.c @@ -0,0 +1,27 @@ +/* { dg-do run { target int128 } } */ +/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */ + +__attribute__ ((weak)) +int f(char a) +{ + return __builtin_memchr ("aEgiHx", a, 6) != 0; +} + +__attribute__ ((weak)) +int g(char a) +{ + return (a == 'a' || a == 'E' || a == 'g' || a == 'i' || a == 'H' + || a == 'x'); +} + +int +main () +{ + for (int i = 0; i < 255; i++) + if (f (i) != g (i)) + __builtin_abort (); + + return 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-7.c b/gcc/testsuite/c-c++-common/pr103798-7.c new file mode 100644 index 0000000..40fd382 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-7.c @@ -0,0 +1,27 @@ +/* { dg-do run { target int128 } } */ +/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */ + +__attribute__ ((weak)) +int f(char a) +{ + return __builtin_memchr ("aEgiHjZ", a, 7) == 0; +} + +__attribute__ ((weak)) +int g(char a) +{ + return (a != 'a' && a != 'E' && a != 'g' && a != 'i' && a != 'H' + && a != 'j' && a != 'Z'); +} + +int +main () +{ + for (int i = 0; i < 255; i++) + if (f (i) != g (i)) + __builtin_abort (); + + return 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-8.c b/gcc/testsuite/c-c++-common/pr103798-8.c new file mode 100644 index 0000000..0841b18 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-8.c @@ -0,0 +1,27 @@ +/* { dg-do run { target int128 } } */ +/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */ + +__attribute__ ((weak)) +int f(int a) +{ + return __builtin_memchr ("aEgiHx19ABC", a, 8) != 0; +} + +__attribute__ ((weak)) +int g(char a) +{ + return (a == 'a' || a == 'E' || a == 'g' || a == 'i' || a == 'H' + || a == 'x' || a == '1' || a == '9'); +} + +int +main () +{ + for (int i = 0; i < 255; i++) + if (f (i + 256) != g (i + 256)) + __builtin_abort (); + + return 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/testsuite/c-c++-common/pr103798-9.c b/gcc/testsuite/c-c++-common/pr103798-9.c new file mode 100644 index 0000000..c5f0f94 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr103798-9.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -fdump-tree-optimized -save-temps" } */ + +int +f (char a) +{ + return __builtin_memchr ("a", a, 1) == 0; +} + +/* { dg-final { scan-assembler-not "memchr" } } */ diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index 69567ab..fdc4bc8 100644 --- a/gcc/tree-ssa-forwprop.cc +++ b/gcc/tree-ssa-forwprop.cc @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-dfa.h" #include "tree-ssa-propagate.h" #include "tree-ssa-dom.h" +#include "tree-ssa-strlen.h" #include "builtins.h" #include "tree-cfgcleanup.h" #include "cfganal.h" @@ -1177,6 +1178,15 @@ constant_pointer_difference (tree p1, tree p2) memcpy (p, "abcd ", 7); call if the latter can be stored by pieces during expansion. + Optimize + memchr ("abcd", a, 4) == 0; + or + memchr ("abcd", a, 4) != 0; + to + (a == 'a' || a == 'b' || a == 'c' || a == 'd') == 0 + or + (a == 'a' || a == 'b' || a == 'c' || a == 'd') != 0 + Also canonicalize __atomic_fetch_op (p, x, y) op x to __atomic_op_fetch (p, x, y) or __atomic_op_fetch (p, x, y) iop x @@ -1193,8 +1203,70 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2) return false; stmt1 = SSA_NAME_DEF_STMT (vuse); + tree res; + switch (DECL_FUNCTION_CODE (callee2)) { + case BUILT_IN_MEMCHR: + if (gimple_call_num_args (stmt2) == 3 + && (res = gimple_call_lhs (stmt2)) != nullptr + && use_in_zero_equality (res) != nullptr + && CHAR_BIT == 8 + && BITS_PER_UNIT == 8) + { + tree ptr = gimple_call_arg (stmt2, 0); + if (TREE_CODE (ptr) != ADDR_EXPR + || TREE_CODE (TREE_OPERAND (ptr, 0)) != STRING_CST) + break; + unsigned HOST_WIDE_INT slen + = TREE_STRING_LENGTH (TREE_OPERAND (ptr, 0)); + /* It must be a non-empty string constant. */ + if (slen < 2) + break; + /* For -Os, only simplify strings with a single character. */ + if (!optimize_bb_for_speed_p (gimple_bb (stmt2)) + && slen > 2) + break; + tree size = gimple_call_arg (stmt2, 2); + /* Size must be a constant which is <= UNITS_PER_WORD and + <= the string length. */ + if (TREE_CODE (size) != INTEGER_CST || integer_zerop (size)) + break; + + if (!tree_fits_uhwi_p (size)) + break; + + unsigned HOST_WIDE_INT sz = tree_to_uhwi (size); + if (sz > UNITS_PER_WORD || sz >= slen) + break; + + tree ch = gimple_call_arg (stmt2, 1); + location_t loc = gimple_location (stmt2); + if (!useless_type_conversion_p (char_type_node, + TREE_TYPE (ch))) + ch = fold_convert_loc (loc, char_type_node, ch); + const char *p = TREE_STRING_POINTER (TREE_OPERAND (ptr, 0)); + unsigned int isize = sz; + tree *op = XALLOCAVEC (tree, isize); + for (unsigned int i = 0; i < isize; i++) + { + op[i] = build_int_cst (char_type_node, p[i]); + op[i] = fold_build2_loc (loc, EQ_EXPR, boolean_type_node, + op[i], ch); + } + for (unsigned int i = isize - 1; i >= 1; i--) + op[i - 1] = fold_convert_loc (loc, boolean_type_node, + fold_build2_loc (loc, + BIT_IOR_EXPR, + boolean_type_node, + op[i - 1], + op[i])); + res = fold_convert_loc (loc, TREE_TYPE (res), op[0]); + gimplify_and_update_call_from_tree (gsi_p, res); + return true; + } + break; + case BUILT_IN_MEMSET: if (gimple_call_num_args (stmt2) != 3 || gimple_call_lhs (stmt2) diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc index 7b3e389..5afbae1 100644 --- a/gcc/tree-ssa-strlen.cc +++ b/gcc/tree-ssa-strlen.cc @@ -3913,8 +3913,8 @@ strlen_pass::handle_builtin_memset (bool *zero_write) nonnull if and only RES is used in such expressions exclusively and in none other. */ -static gimple * -use_in_zero_equality (tree res, bool exclusive = true) +gimple * +use_in_zero_equality (tree res, bool exclusive) { gimple *first_use = NULL; diff --git a/gcc/tree-ssa-strlen.h b/gcc/tree-ssa-strlen.h index 8d15545..fdb4d9d 100644 --- a/gcc/tree-ssa-strlen.h +++ b/gcc/tree-ssa-strlen.h @@ -35,6 +35,8 @@ struct c_strlen_data; extern void get_range_strlen_dynamic (tree, gimple *, c_strlen_data *, pointer_query &); +extern gimple *use_in_zero_equality (tree, bool = true); + /* APIs internal to strlen pass. Defined in gimple-ssa-sprintf.cc. */ extern bool handle_printf_call (gimple_stmt_iterator *, pointer_query &); -- cgit v1.1 From e0e07bc7624776f9369cf0c73e2a3cf42cd2ce97 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 15 Jul 2022 00:16:22 +0000 Subject: Daily bump. --- gcc/ChangeLog | 36 ++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/fortran/ChangeLog | 7 +++++++ gcc/jit/ChangeLog | 7 +++++++ gcc/testsuite/ChangeLog | 29 +++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b759cf4..323b46f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,39 @@ +2022-07-14 H.J. Lu + + PR tree-optimization/103798 + * tree-ssa-forwprop.cc: Include "tree-ssa-strlen.h". + (simplify_builtin_call): Inline memchr with constant strings of + no more than the bytes of a word. + * tree-ssa-strlen.cc (use_in_zero_equality): Make it global. + * tree-ssa-strlen.h (use_in_zero_equality): New. + +2022-07-14 Eric Botcazou + + * gimplify.cc (lookup_tmp_var): Add NOT_GIMPLE_REG boolean parameter + and set DECL_NOT_GIMPLE_REG_P on the variable according to it. + (internal_get_tmp_var): Add NOT_GIMPLE_REG boolean parameter and + pass it in the call to lookup_tmp_var. + (get_formal_tmp_var): Pass false in the call to lookup_tmp_var. + (get_initialized_tmp_var): Likewise. + (prepare_gimple_addressable): Call internal_get_tmp_var instead of + get_initialized_tmp_var with NOT_GIMPLE_REG set to true. + +2022-07-14 Martin Liska + + * doc/gimple.texi: Close properly a deftypefn. + +2022-07-14 Martin Liska + + * doc/gimple.texi: Close properly a deftypefn. + +2022-07-14 Takayuki 'January June' Suwa + + * config/xtensa/xtensa.md: + In FP constant synthesis split pattern, subcontract to + avoid_constant_pool_reference() as in the case of integer, + because it can handle well too. And cast to int32_t before + calling xtensa_constantsynth() in order to ignore upper 32-bit. + 2022-07-13 Aldy Hernandez * range-op.cc (operator_lt::fold_range): Use nonzero bits. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 56754ca..5d08726 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220714 +20220715 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f13ce09..f02b65f 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,10 @@ +2022-07-14 Harald Anlauf + Steven G. Kargl + + PR fortran/106209 + * decl.cc (add_init_expr_to_sym): Handle bad initializers for + implied-shape arrays. + 2022-07-12 Harald Anlauf PR fortran/106049 diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index d16b573..581f682 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,10 @@ +2022-07-14 Jonathan Wakely + + * jit-recording.h (recording::memento): Define copy constructor + and copy assignment operator as deleted. + (recording::string): Likewise. + (recording::string::c_str): Add const qualifier. + 2022-06-29 Antoni Boucher PR jit/105812 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 97b9f5f..cfdf646 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,32 @@ +2022-07-14 H.J. Lu + + PR tree-optimization/103798 + * c-c++-common/pr103798-1.c: New test. + * c-c++-common/pr103798-2.c: Likewise. + * c-c++-common/pr103798-3.c: Likewise. + * c-c++-common/pr103798-4.c: Likewise. + * c-c++-common/pr103798-5.c: Likewise. + * c-c++-common/pr103798-6.c: Likewise. + * c-c++-common/pr103798-7.c: Likewise. + * c-c++-common/pr103798-8.c: Likewise. + * c-c++-common/pr103798-9.c: Likewise. + * c-c++-common/pr103798-10.c: Likewise. + +2022-07-14 Harald Anlauf + Steven G. Kargl + + PR fortran/106209 + * gfortran.dg/pr106209.f90: New test. + +2022-07-14 Eric Botcazou + + * gnat.dg/opt98.ads, gnat.dg/opt98.adb: New test. + +2022-07-14 Takayuki 'January June' Suwa + + * gcc.target/xtensa/constsynth_double.c: + Modify in order to catch the issue. + 2022-07-13 Patrick Palka PR c++/105912 -- cgit v1.1 From 4cbebddc2ce1e88216fec6aa89d111d8596bd34c Mon Sep 17 00:00:00 2001 From: Prathamesh Kulkarni Date: Fri, 15 Jul 2022 06:26:50 +0530 Subject: [aarch64] Use op_mode instead of vmode in aarch64_vectorize_vec_perm_const. gcc/ChangeLog: * config/aarch64/aarch64.cc (aarch64_vectorize_vec_perm_const): Use op_mode instead of vmode in calls to force_reg for op0 and op1. --- gcc/config/aarch64/aarch64.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 25f4cbb..303814b 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -24129,11 +24129,11 @@ aarch64_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, d.op_mode = op_mode; d.op_vec_flags = aarch64_classify_vector_mode (d.op_mode); d.target = target; - d.op0 = op0 ? force_reg (vmode, op0) : NULL_RTX; + d.op0 = op0 ? force_reg (op_mode, op0) : NULL_RTX; if (op0 == op1) d.op1 = d.op0; else - d.op1 = op1 ? force_reg (vmode, op1) : NULL_RTX; + d.op1 = op1 ? force_reg (op_mode, op1) : NULL_RTX; d.testing_p = !target; if (!d.testing_p) -- cgit v1.1 From ae69e6f61b93dcb5b1e7ef609431f100c1b9b2e5 Mon Sep 17 00:00:00 2001 From: konglin1 Date: Fri, 15 Jul 2022 10:29:27 +0800 Subject: i386: Fix _mm_[u]comixx_{ss,sd} codegen and add PF result. [PR106113] gcc/ChangeLog: PR target/106113 * config/i386/i386-builtin.def (BDESC): Fix [u]comi{ss,sd} comparison due to intrinsics changed over time. * config/i386/i386-expand.cc (ix86_ssecom_setcc): Add unordered check and mode for sse comi codegen. (ix86_expand_sse_comi): Add unordered check and check a different CCmode. (ix86_expand_sse_comi_round):Extract unordered check and mode part in ix86_ssecom_setcc. gcc/testsuite/ChangeLog: PR target/106113 * gcc.target/i386/avx-vcomisd-pr106113-2.c: New test. * gcc.target/i386/avx-vcomiss-pr106113-2.c: Ditto. * gcc.target/i386/avx-vucomisd-pr106113-2.c: Ditto. * gcc.target/i386/avx-vucomiss-pr106113-2.c: Ditto. * gcc.target/i386/sse-comiss-pr106113-1.c: Ditto. * gcc.target/i386/sse-comiss-pr106113-2.c: Ditto. * gcc.target/i386/sse-ucomiss-pr106113-1.c: Ditto. * gcc.target/i386/sse-ucomiss-pr106113-2.c: Ditto. * gcc.target/i386/sse2-comisd-pr106113-1.c: Ditto. * gcc.target/i386/sse2-comisd-pr106113-2.c: Ditto. * gcc.target/i386/sse2-ucomisd-pr106113-1.c: Ditto. * gcc.target/i386/sse2-ucomisd-pr106113-2.c: Ditto. --- gcc/config/i386/i386-builtin.def | 32 ++--- gcc/config/i386/i386-expand.cc | 140 +++++++++++++-------- .../gcc.target/i386/avx-vcomisd-pr106113-2.c | 8 ++ .../gcc.target/i386/avx-vcomiss-pr106113-2.c | 8 ++ .../gcc.target/i386/avx-vucomisd-pr106113-2.c | 8 ++ .../gcc.target/i386/avx-vucomiss-pr106113-2.c | 8 ++ .../gcc.target/i386/sse-comiss-pr106113-1.c | 19 +++ .../gcc.target/i386/sse-comiss-pr106113-2.c | 59 +++++++++ .../gcc.target/i386/sse-ucomiss-pr106113-1.c | 19 +++ .../gcc.target/i386/sse-ucomiss-pr106113-2.c | 59 +++++++++ .../gcc.target/i386/sse2-comisd-pr106113-1.c | 19 +++ .../gcc.target/i386/sse2-comisd-pr106113-2.c | 59 +++++++++ .../gcc.target/i386/sse2-ucomisd-pr106113-1.c | 19 +++ .../gcc.target/i386/sse2-ucomisd-pr106113-2.c | 59 +++++++++ 14 files changed, 450 insertions(+), 66 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/avx-vcomisd-pr106113-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vcomiss-pr106113-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vucomisd-pr106113-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vucomiss-pr106113-2.c create mode 100644 gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-1.c create mode 100644 gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-2.c create mode 100644 gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-1.c create mode 100644 gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-2.c create mode 100644 gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-1.c create mode 100644 gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-2.c create mode 100644 gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-1.c create mode 100644 gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-2.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-builtin.def b/gcc/config/i386/i386-builtin.def index fd16093..acb7e8c 100644 --- a/gcc/config/i386/i386-builtin.def +++ b/gcc/config/i386/i386-builtin.def @@ -35,30 +35,30 @@ IX86_BUILTIN__BDESC_##NEXT_KIND##_FIRST - 1. */ BDESC_FIRST (comi, COMI, - OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comieq", IX86_BUILTIN_COMIEQSS, UNEQ, 0) -BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comilt", IX86_BUILTIN_COMILTSS, UNLT, 0) -BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comile", IX86_BUILTIN_COMILESS, UNLE, 0) + OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comieq", IX86_BUILTIN_COMIEQSS, EQ, 0) +BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comilt", IX86_BUILTIN_COMILTSS, LT, 0) +BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comile", IX86_BUILTIN_COMILESS, LE, 0) BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comigt", IX86_BUILTIN_COMIGTSS, GT, 0) BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comige", IX86_BUILTIN_COMIGESS, GE, 0) -BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comineq", IX86_BUILTIN_COMINEQSS, LTGT, 0) -BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomieq", IX86_BUILTIN_UCOMIEQSS, UNEQ, 0) -BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomilt", IX86_BUILTIN_UCOMILTSS, UNLT, 0) -BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomile", IX86_BUILTIN_UCOMILESS, UNLE, 0) +BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comineq", IX86_BUILTIN_COMINEQSS, NE, 0) +BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomieq", IX86_BUILTIN_UCOMIEQSS, EQ, 0) +BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomilt", IX86_BUILTIN_UCOMILTSS, LT, 0) +BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomile", IX86_BUILTIN_UCOMILESS, LE, 0) BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomigt", IX86_BUILTIN_UCOMIGTSS, GT, 0) BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomige", IX86_BUILTIN_UCOMIGESS, GE, 0) -BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomineq", IX86_BUILTIN_UCOMINEQSS, LTGT, 0) -BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdeq", IX86_BUILTIN_COMIEQSD, UNEQ, 0) -BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdlt", IX86_BUILTIN_COMILTSD, UNLT, 0) -BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdle", IX86_BUILTIN_COMILESD, UNLE, 0) +BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomineq", IX86_BUILTIN_UCOMINEQSS, NE, 0) +BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdeq", IX86_BUILTIN_COMIEQSD, EQ, 0) +BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdlt", IX86_BUILTIN_COMILTSD, LT, 0) +BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdle", IX86_BUILTIN_COMILESD, LE, 0) BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdgt", IX86_BUILTIN_COMIGTSD, GT, 0) BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdge", IX86_BUILTIN_COMIGESD, GE, 0) -BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdneq", IX86_BUILTIN_COMINEQSD, LTGT, 0) -BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdeq", IX86_BUILTIN_UCOMIEQSD, UNEQ, 0) -BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdlt", IX86_BUILTIN_UCOMILTSD, UNLT, 0) -BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdle", IX86_BUILTIN_UCOMILESD, UNLE, 0) +BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdneq", IX86_BUILTIN_COMINEQSD, NE, 0) +BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdeq", IX86_BUILTIN_UCOMIEQSD, EQ, 0) +BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdlt", IX86_BUILTIN_UCOMILTSD, LT, 0) +BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdle", IX86_BUILTIN_UCOMILESD, LE, 0) BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdgt", IX86_BUILTIN_UCOMIGTSD, GT, 0) BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdge", IX86_BUILTIN_UCOMIGESD, GE, 0) -BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdneq", IX86_BUILTIN_UCOMINEQSD, LTGT, 0) +BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdneq", IX86_BUILTIN_UCOMINEQSD, NE, 0) BDESC_END (COMI, PCMPESTR) diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 6a3fcde..40f821e 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -9770,47 +9770,121 @@ ix86_expand_sse_compare (const struct builtin_description *d, return target; } +/* Subroutine of ix86_sse_comi and ix86_sse_comi_round to take care of + * ordered EQ or unordered NE, generate PF jump. */ + +static rtx +ix86_ssecom_setcc (const enum rtx_code comparison, + bool check_unordered, machine_mode mode, + rtx set_dst, rtx target) +{ + + rtx_code_label *label = NULL; + + /* NB: For ordered EQ or unordered NE, check ZF alone isn't sufficient + with NAN operands. */ + if (check_unordered) + { + gcc_assert (comparison == EQ || comparison == NE); + + rtx flag = gen_rtx_REG (CCFPmode, FLAGS_REG); + label = gen_label_rtx (); + rtx tmp = gen_rtx_fmt_ee (UNORDERED, VOIDmode, flag, const0_rtx); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + emit_jump_insn (gen_rtx_SET (pc_rtx, tmp)); + } + + /* NB: Set CCFPmode and check a different CCmode which is in subset + of CCFPmode. */ + if (GET_MODE (set_dst) != mode) + { + gcc_assert (mode == CCAmode || mode == CCCmode + || mode == CCOmode || mode == CCPmode + || mode == CCSmode || mode == CCZmode); + set_dst = gen_rtx_REG (mode, FLAGS_REG); + } + + emit_insn (gen_rtx_SET (gen_rtx_STRICT_LOW_PART (VOIDmode, target), + gen_rtx_fmt_ee (comparison, QImode, + set_dst, + const0_rtx))); + + if (label) + emit_label (label); + + return SUBREG_REG (target); +} + /* Subroutine of ix86_expand_builtin to take care of comi insns. */ static rtx ix86_expand_sse_comi (const struct builtin_description *d, tree exp, rtx target) { - rtx pat; + rtx pat, set_dst; tree arg0 = CALL_EXPR_ARG (exp, 0); tree arg1 = CALL_EXPR_ARG (exp, 1); rtx op0 = expand_normal (arg0); rtx op1 = expand_normal (arg1); - machine_mode mode0 = insn_data[d->icode].operand[0].mode; - machine_mode mode1 = insn_data[d->icode].operand[1].mode; - enum rtx_code comparison = d->comparison; + enum insn_code icode = d->icode; + const struct insn_data_d *insn_p = &insn_data[icode]; + machine_mode mode0 = insn_p->operand[0].mode; + machine_mode mode1 = insn_p->operand[1].mode; if (VECTOR_MODE_P (mode0)) op0 = safe_vector_operand (op0, mode0); if (VECTOR_MODE_P (mode1)) op1 = safe_vector_operand (op1, mode1); + enum rtx_code comparison = d->comparison; + rtx const_val = const0_rtx; + + bool check_unordered = false; + machine_mode mode = CCFPmode; + switch (comparison) + { + case LE: /* -> GE */ + case LT: /* -> GT */ + std::swap (op0, op1); + comparison = swap_condition (comparison); + /* FALLTHRU */ + case GT: + case GE: + break; + case EQ: + check_unordered = true; + mode = CCZmode; + break; + case NE: + check_unordered = true; + mode = CCZmode; + const_val = const1_rtx; + break; + default: + gcc_unreachable (); + } + target = gen_reg_rtx (SImode); - emit_move_insn (target, const0_rtx); + emit_move_insn (target, const_val); target = gen_rtx_SUBREG (QImode, target, 0); if ((optimize && !register_operand (op0, mode0)) - || !insn_data[d->icode].operand[0].predicate (op0, mode0)) + || !insn_p->operand[0].predicate (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); if ((optimize && !register_operand (op1, mode1)) - || !insn_data[d->icode].operand[1].predicate (op1, mode1)) + || !insn_p->operand[1].predicate (op1, mode1)) op1 = copy_to_mode_reg (mode1, op1); - pat = GEN_FCN (d->icode) (op0, op1); + pat = GEN_FCN (icode) (op0, op1); if (! pat) return 0; - emit_insn (pat); - emit_insn (gen_rtx_SET (gen_rtx_STRICT_LOW_PART (VOIDmode, target), - gen_rtx_fmt_ee (comparison, QImode, - SET_DEST (pat), - const0_rtx))); - return SUBREG_REG (target); + set_dst = SET_DEST (pat); + emit_insn (pat); + return ix86_ssecom_setcc (comparison, check_unordered, mode, + set_dst, target); } /* Subroutines of ix86_expand_args_builtin to take care of round insns. */ @@ -11410,42 +11484,8 @@ ix86_expand_sse_comi_round (const struct builtin_description *d, emit_insn (pat); - rtx_code_label *label = NULL; - - /* NB: For ordered EQ or unordered NE, check ZF alone isn't sufficient - with NAN operands. */ - if (check_unordered) - { - gcc_assert (comparison == EQ || comparison == NE); - - rtx flag = gen_rtx_REG (CCFPmode, FLAGS_REG); - label = gen_label_rtx (); - rtx tmp = gen_rtx_fmt_ee (UNORDERED, VOIDmode, flag, const0_rtx); - tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, - gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx); - emit_jump_insn (gen_rtx_SET (pc_rtx, tmp)); - } - - /* NB: Set CCFPmode and check a different CCmode which is in subset - of CCFPmode. */ - if (GET_MODE (set_dst) != mode) - { - gcc_assert (mode == CCAmode || mode == CCCmode - || mode == CCOmode || mode == CCPmode - || mode == CCSmode || mode == CCZmode); - set_dst = gen_rtx_REG (mode, FLAGS_REG); - } - - emit_insn (gen_rtx_SET (gen_rtx_STRICT_LOW_PART (VOIDmode, target), - gen_rtx_fmt_ee (comparison, QImode, - set_dst, - const0_rtx))); - - if (label) - emit_label (label); - - return SUBREG_REG (target); + return ix86_ssecom_setcc (comparison, check_unordered, mode, + set_dst, target); } static rtx diff --git a/gcc/testsuite/gcc.target/i386/avx-vcomisd-pr106113-2.c b/gcc/testsuite/gcc.target/i386/avx-vcomisd-pr106113-2.c new file mode 100644 index 0000000..9025b1b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vcomisd-pr106113-2.c @@ -0,0 +1,8 @@ +/* { dg-do run } */ +/* { dg-require-effective-target avx } */ +/* { dg-options "-O2 -mavx" } */ + +#define CHECK_H "avx-check.h" +#define TEST avx_test + +#include "sse2-comisd-pr106113-2.c" diff --git a/gcc/testsuite/gcc.target/i386/avx-vcomiss-pr106113-2.c b/gcc/testsuite/gcc.target/i386/avx-vcomiss-pr106113-2.c new file mode 100644 index 0000000..dc0bf51 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vcomiss-pr106113-2.c @@ -0,0 +1,8 @@ +/* { dg-do run } */ +/* { dg-require-effective-target avx } */ +/* { dg-options "-O2 -mavx" } */ + +#define CHECK_H "avx-check.h" +#define TEST avx_test + +#include "sse-comiss-pr106113-2.c" diff --git a/gcc/testsuite/gcc.target/i386/avx-vucomisd-pr106113-2.c b/gcc/testsuite/gcc.target/i386/avx-vucomisd-pr106113-2.c new file mode 100644 index 0000000..3b0c5db --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vucomisd-pr106113-2.c @@ -0,0 +1,8 @@ +/* { dg-do run } */ +/* { dg-require-effective-target avx } */ +/* { dg-options "-O2 -mavx" } */ + +#define CHECK_H "avx-check.h" +#define TEST avx_test + +#include "sse2-ucomisd-pr106113-2.c" diff --git a/gcc/testsuite/gcc.target/i386/avx-vucomiss-pr106113-2.c b/gcc/testsuite/gcc.target/i386/avx-vucomiss-pr106113-2.c new file mode 100644 index 0000000..d67e4ad --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vucomiss-pr106113-2.c @@ -0,0 +1,8 @@ +/* { dg-do run } */ +/* { dg-require-effective-target avx } */ +/* { dg-options "-O2 -mavx" } */ + +#define CHECK_H "avx-check.h" +#define TEST avx_test + +#include "sse-ucomiss-pr106113-2.c" diff --git a/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-1.c b/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-1.c new file mode 100644 index 0000000..9562102 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-msse -O2" } */ +/* { dg-final { scan-assembler-times "comiss\[ \\t\]+\[^\n\]*\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 6 } } */ +/* { dg-final { scan-assembler-times "jp" 2 } } */ +#include + +volatile __m128 x1, x2; +volatile int res; + +void extern +sse_comi_test (void) +{ + res = _mm_comieq_ss (x1, x2); + res = _mm_comilt_ss (x1, x2); + res = _mm_comile_ss (x1, x2); + res = _mm_comigt_ss (x1, x2); + res = _mm_comige_ss (x1, x2); + res = _mm_comineq_ss (x1, x2); +} diff --git a/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-2.c b/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-2.c new file mode 100644 index 0000000..a90f333 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-2.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msse" } */ +/* { dg-require-effective-target sse } */ + +#ifndef CHECK_H +#define CHECK_H "sse-check.h" +#endif + +#ifndef TEST +#define TEST sse_test +#endif + +#include CHECK_H + +#include + +#define CMP(PRED, EXP) \ + res = _mm_comi##PRED##_ss (__A, __B); \ + if (res != EXP) \ + abort (); +static void +__attribute__((noinline, unused)) +do_check (float s1, float s2) +{ + __m128 __A = _mm_load_ss (&s1); + __m128 __B = _mm_load_ss (&s2); + int res; + + CMP (eq, (!__builtin_isunordered (s1, s2) && s1 == s2)); + CMP (ge, (!__builtin_isunordered (s1, s2) && s1 >= s2)); + CMP (gt, (!__builtin_isunordered (s1, s2) && s1 > s2)); + CMP (lt, (!__builtin_isunordered (s1, s2) && s1 < s2)); + CMP (le, (!__builtin_isunordered (s1, s2) && s1 <= s2)); + CMP (neq, (__builtin_isunordered (s1, s2) || s1 != s2)); +} + +static void +TEST (void) +{ + struct + { + float x1; + float x2; + } + inputs[] = + { + { 4.3, 2.18 }, + { -4.3, 3.18 }, + { __builtin_nanf (""), -5.8 }, + { -4.8, __builtin_nansf ("") }, + { 3.8, __builtin_nansf ("") }, + { 4.2, 4.2 }, + { __builtin_nanf (""), __builtin_nansf ("") }, + }; + int i; + + for (i = 0; i < sizeof (inputs) / sizeof (inputs[0]); i++) + do_check (inputs[i].x1, inputs[i].x2); +} diff --git a/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-1.c b/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-1.c new file mode 100644 index 0000000..e337e11 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-msse -O2" } */ +/* { dg-final { scan-assembler-times "ucomiss\[ \\t\]+\[^\n\]*\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 6 } } */ +/* { dg-final { scan-assembler-times "jp" 2 } } */ +#include + +volatile __m128 x1, x2; +volatile int res; + +void extern +sse_ucomi_test (void) +{ + res = _mm_ucomieq_ss (x1, x2); + res = _mm_ucomilt_ss (x1, x2); + res = _mm_ucomile_ss (x1, x2); + res = _mm_ucomigt_ss (x1, x2); + res = _mm_ucomige_ss (x1, x2); + res = _mm_ucomineq_ss (x1, x2); +} diff --git a/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-2.c b/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-2.c new file mode 100644 index 0000000..37d8450 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-2.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msse" } */ +/* { dg-require-effective-target sse } */ + +#ifndef CHECK_H +#define CHECK_H "sse-check.h" +#endif + +#ifndef TEST +#define TEST sse_test +#endif + +#include CHECK_H + +#include + +#define CMP(PRED, EXP) \ + res = _mm_ucomi##PRED##_ss (__A, __B); \ + if (res != EXP) \ + abort (); +static void +__attribute__((noinline, unused)) +do_check (float s1, float s2) +{ + __m128 __A = _mm_load_ss (&s1); + __m128 __B = _mm_load_ss (&s2); + int res; + + CMP (eq, (!__builtin_isunordered (s1, s2) && s1 == s2)); + CMP (ge, (!__builtin_isunordered (s1, s2) && s1 >= s2)); + CMP (gt, (!__builtin_isunordered (s1, s2) && s1 > s2)); + CMP (lt, (!__builtin_isunordered (s1, s2) && s1 < s2)); + CMP (le, (!__builtin_isunordered (s1, s2) && s1 <= s2)); + CMP (neq, (__builtin_isunordered (s1, s2) || s1 != s2)); +} + +static void +TEST (void) +{ + struct + { + float x1; + float x2; + } + inputs[] = + { + { 4.3, 2.18 }, + { -4.3, 3.18 }, + { __builtin_nanf (""), -5.8 }, + { -4.8, __builtin_nansf ("") }, + { 3.8, __builtin_nansf ("") }, + { 4.2, 4.2 }, + { __builtin_nanf (""), __builtin_nansf ("") }, + }; + int i; + + for (i = 0; i < sizeof (inputs) / sizeof (inputs[0]); i++) + do_check (inputs[i].x1, inputs[i].x2); +} diff --git a/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-1.c b/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-1.c new file mode 100644 index 0000000..6268977 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2" } */ +/* { dg-final { scan-assembler-times "comisd\[ \\t\]+\[^\n\]*\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 6 } } */ +/* { dg-final { scan-assembler-times "jp" 2 } } */ +#include + +volatile __m128d x1, x2; +volatile int res; + +void extern +sse2_comisd_test (void) +{ + res = _mm_comieq_sd (x1, x2); + res = _mm_comilt_sd (x1, x2); + res = _mm_comile_sd (x1, x2); + res = _mm_comigt_sd (x1, x2); + res = _mm_comige_sd (x1, x2); + res = _mm_comineq_sd (x1, x2); +} diff --git a/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-2.c b/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-2.c new file mode 100644 index 0000000..f49771c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-2.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msse2" } */ +/* { dg-require-effective-target sse2 } */ + +#ifndef CHECK_H +#define CHECK_H "sse2-check.h" +#endif + +#ifndef TEST +#define TEST sse2_test +#endif + +#include CHECK_H + +#include + +#define CMP(PRED, EXP) \ + res = _mm_comi##PRED##_sd (__A, __B); \ + if (res != EXP) \ + abort (); +static void +__attribute__((noinline, unused)) +do_check (double s1, double s2) +{ + __m128d __A = _mm_load_sd (&s1); + __m128d __B = _mm_load_sd (&s2); + int res; + + CMP (eq, (!__builtin_isunordered (s1, s2) && s1 == s2)); + CMP (ge, (!__builtin_isunordered (s1, s2) && s1 >= s2)); + CMP (gt, (!__builtin_isunordered (s1, s2) && s1 > s2)); + CMP (lt, (!__builtin_isunordered (s1, s2) && s1 < s2)); + CMP (le, (!__builtin_isunordered (s1, s2) && s1 <= s2)); + CMP (neq, (__builtin_isunordered (s1, s2) || s1 != s2)); +} + +static void +TEST (void) +{ + struct + { + double x1; + double x2; + } + inputs[] = + { + { 4.3, 2.18 }, + { -4.3, 3.18 }, + { __builtin_nan (""), -5.8 }, + { -4.8, __builtin_nans ("") }, + { 3.8, __builtin_nans ("") }, + { 4.2, 4.2 }, + { __builtin_nan (""), __builtin_nans ("") }, + }; + int i; + + for (i = 0; i < sizeof (inputs) / sizeof (inputs[0]); i++) + do_check (inputs[i].x1, inputs[i].x2); +} diff --git a/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-1.c b/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-1.c new file mode 100644 index 0000000..e64c0ac --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2" } */ +/* { dg-final { scan-assembler-times "ucomisd\[ \\t\]+\[^\n\]*\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 6 } } */ +/* { dg-final { scan-assembler-times "jp" 2 } } */ +#include + +volatile __m128d x1, x2; +volatile int res; + +void extern +sse2_ucomisd_test (void) +{ + res = _mm_ucomieq_sd (x1, x2); + res = _mm_ucomilt_sd (x1, x2); + res = _mm_ucomile_sd (x1, x2); + res = _mm_ucomigt_sd (x1, x2); + res = _mm_ucomige_sd (x1, x2); + res = _mm_ucomineq_sd (x1, x2); +} diff --git a/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-2.c b/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-2.c new file mode 100644 index 0000000..606a897 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-2.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msse2" } */ +/* { dg-require-effective-target sse2 } */ + +#ifndef CHECK_H +#define CHECK_H "sse2-check.h" +#endif + +#ifndef TEST +#define TEST sse2_test +#endif + +#include CHECK_H + +#include + +#define CMP(PRED, EXP) \ + res = _mm_ucomi##PRED##_sd (__A, __B); \ + if (res != EXP) \ + abort (); +static void +__attribute__((noinline, unused)) +do_check (double s1, double s2) +{ + __m128d __A = _mm_load_sd (&s1); + __m128d __B = _mm_load_sd (&s2); + int res; + + CMP (eq, (!__builtin_isunordered (s1, s2) && s1 == s2)); + CMP (ge, (!__builtin_isunordered (s1, s2) && s1 >= s2)); + CMP (gt, (!__builtin_isunordered (s1, s2) && s1 > s2)); + CMP (lt, (!__builtin_isunordered (s1, s2) && s1 < s2)); + CMP (le, (!__builtin_isunordered (s1, s2) && s1 <= s2)); + CMP (neq, (__builtin_isunordered (s1, s2) || s1 != s2)); +} + +static void +TEST (void) +{ + struct + { + double x1; + double x2; + } + inputs[] = + { + { 4.3, 2.18 }, + { -4.3, 3.18 }, + { __builtin_nan (""), -5.8 }, + { -4.8, __builtin_nans ("") }, + { 3.8, __builtin_nans ("") }, + { 4.2, 4.2 }, + { __builtin_nan (""), __builtin_nans ("") }, + }; + int i; + + for (i = 0; i < sizeof (inputs) / sizeof (inputs[0]); i++) + do_check (inputs[i].x1, inputs[i].x2); +} -- cgit v1.1 From f858fe7a8b250995bc5b0d18720a2ceb6815622d Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 13 Jul 2022 11:58:05 +0100 Subject: libcpp: Improve encapsulation of label_text This adjusts the API of label_text so that the data members are private and cannot be modified by callers. Add accessors for them instead, and make the accessors const-correct. Also rename moved_from () to the more idiomatic release (). Also remove the unused take_or_copy () member function which has confusing ownership semantics. gcc/analyzer/ChangeLog: * call-info.cc (call_info::print): Adjust to new label_text API. * checker-path.cc (checker_event::dump): Likewise. (region_creation_event::get_desc): Likewise. (state_change_event::get_desc): Likewise. (superedge_event::should_filter_p): Likewise. (start_cfg_edge_event::get_desc): Likewise. (call_event::get_desc): Likewise. (return_event::get_desc): Likewise. (warning_event::get_desc): Likewise. (checker_path::dump): Likewise. (checker_path::debug): Likewise. * diagnostic-manager.cc (diagnostic_manager::prune_for_sm_diagnostic): Likewise. (diagnostic_manager::prune_interproc_events): Likewise. * engine.cc (feasibility_state::maybe_update_for_edge): Likewise. * program-state.cc (sm_state_map::to_json): Likewise. * region-model-impl-calls.cc (region_model::impl_call_analyzer_describe): Likewise. (region_model::impl_call_analyzer_dump_capacity): Likewise. * region.cc (region::to_json): Likewise. * sm-malloc.cc (inform_nonnull_attribute): Likewise. * store.cc (binding_map::to_json): Likewise. (store::to_json): Likewise. * supergraph.cc (superedge::dump): Likewise. * svalue.cc (svalue::to_json): Likewise. gcc/c-family/ChangeLog: * c-format.cc (class range_label_for_format_type_mismatch): Adjust to new label_text API. gcc/ChangeLog: * diagnostic-format-json.cc (json_from_location_range): Adjust to new label_text API. * diagnostic-format-sarif.cc (sarif_builder::make_location_object): Likewise. * diagnostic-show-locus.cc (struct pod_label_text): Likewise. (layout::print_any_labels): Likewise. * tree-diagnostic-path.cc (class path_label): Likewise. (struct event_range): Likewise. (default_tree_diagnostic_path_printer): Likewise. (default_tree_make_json_for_path): Likewise. libcpp/ChangeLog: * include/line-map.h (label_text::take_or_copy): Remove. (label_text::moved_from): Rename to release. (label_text::m_buffer, label_text::m_owned): Make private. (label_text::get, label_text::is_owned): New accessors. --- gcc/analyzer/call-info.cc | 2 +- gcc/analyzer/checker-path.cc | 46 ++++++++++++++++----------------- gcc/analyzer/diagnostic-manager.cc | 20 +++++++------- gcc/analyzer/engine.cc | 2 +- gcc/analyzer/program-state.cc | 2 +- gcc/analyzer/region-model-impl-calls.cc | 4 +-- gcc/analyzer/region.cc | 2 +- gcc/analyzer/sm-malloc.cc | 10 +++---- gcc/analyzer/store.cc | 6 ++--- gcc/analyzer/supergraph.cc | 4 +-- gcc/analyzer/svalue.cc | 2 +- gcc/c-family/c-format.cc | 4 +-- gcc/diagnostic-format-json.cc | 4 +-- gcc/diagnostic-format-sarif.cc | 2 +- gcc/diagnostic-show-locus.cc | 7 ++--- gcc/tree-diagnostic-path.cc | 16 ++++++------ 16 files changed, 67 insertions(+), 66 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc index e1142d7..efc070b 100644 --- a/gcc/analyzer/call-info.cc +++ b/gcc/analyzer/call-info.cc @@ -75,7 +75,7 @@ void call_info::print (pretty_printer *pp) const { label_text desc (get_desc (pp_show_color (pp))); - pp_string (pp, desc.m_buffer); + pp_string (pp, desc.get ()); } /* Implementation of custom_edge_info::add_events_to_path vfunc for diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc index 211cf3e..273f40d 100644 --- a/gcc/analyzer/checker-path.cc +++ b/gcc/analyzer/checker-path.cc @@ -195,7 +195,7 @@ checker_event::dump (pretty_printer *pp) const { label_text event_desc (get_desc (false)); pp_printf (pp, "\"%s\" (depth %i", - event_desc.m_buffer, m_effective_depth); + event_desc.get (), m_effective_depth); if (m_effective_depth != m_original_depth) pp_printf (pp, " corrected from %i", @@ -307,7 +307,7 @@ region_creation_event::get_desc (bool can_colorize) const label_text custom_desc = m_pending_diagnostic->describe_region_creation_event (evdesc::region_creation (can_colorize, m_reg)); - if (custom_desc.m_buffer) + if (custom_desc.get ()) return custom_desc; } @@ -390,7 +390,7 @@ state_change_event::get_desc (bool can_colorize) const = m_pending_diagnostic->describe_state_change (evdesc::state_change (can_colorize, var, origin, m_from, m_to, m_emission_id, *this)); - if (custom_desc.m_buffer) + if (custom_desc.get ()) { if (flag_analyzer_verbose_state_changes) { @@ -404,7 +404,7 @@ state_change_event::get_desc (bool can_colorize) const return make_label_text (can_colorize, "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)", - custom_desc.m_buffer, + custom_desc.get (), var, m_from->get_name (), m_to->get_name (), @@ -414,7 +414,7 @@ state_change_event::get_desc (bool can_colorize) const return make_label_text (can_colorize, "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)", - custom_desc.m_buffer, + custom_desc.get (), var, m_from->get_name (), m_to->get_name (), @@ -435,16 +435,16 @@ state_change_event::get_desc (bool can_colorize) const return make_label_text (can_colorize, "state of %qs: %qs -> %qs (origin: %qs)", - sval_desc.m_buffer, + sval_desc.get (), m_from->get_name (), m_to->get_name (), - origin_desc.m_buffer); + origin_desc.get ()); } else return make_label_text (can_colorize, "state of %qs: %qs -> %qs (NULL origin)", - sval_desc.m_buffer, + sval_desc.get (), m_from->get_name (), m_to->get_name ()); } @@ -509,8 +509,8 @@ superedge_event::should_filter_p (int verbosity) const /* Filter events with empty descriptions. This ought to filter FALLTHRU, but retain true/false/switch edges. */ label_text desc = get_desc (false); - gcc_assert (desc.m_buffer); - if (desc.m_buffer[0] == '\0') + gcc_assert (desc.get ()); + if (desc.get ()[0] == '\0') return true; } } @@ -597,28 +597,28 @@ start_cfg_edge_event::get_desc (bool can_colorize) const label_text edge_desc (m_sedge->get_description (user_facing)); if (user_facing) { - if (edge_desc.m_buffer && strlen (edge_desc.m_buffer) > 0) + if (edge_desc.get () && strlen (edge_desc.get ()) > 0) { label_text cond_desc = maybe_describe_condition (can_colorize); label_text result; - if (cond_desc.m_buffer) + if (cond_desc.get ()) return make_label_text (can_colorize, "following %qs branch (%s)...", - edge_desc.m_buffer, cond_desc.m_buffer); + edge_desc.get (), cond_desc.get ()); else return make_label_text (can_colorize, "following %qs branch...", - edge_desc.m_buffer); + edge_desc.get ()); } else return label_text::borrow (""); } else { - if (strlen (edge_desc.m_buffer) > 0) + if (strlen (edge_desc.get ()) > 0) return make_label_text (can_colorize, "taking %qs edge SN:%i -> SN:%i", - edge_desc.m_buffer, + edge_desc.get (), m_sedge->m_src->m_index, m_sedge->m_dest->m_index); else @@ -798,7 +798,7 @@ call_event::get_desc (bool can_colorize) const m_dest_snode->m_fun->decl, var, m_critical_state)); - if (custom_desc.m_buffer) + if (custom_desc.get ()) return custom_desc; } @@ -878,7 +878,7 @@ return_event::get_desc (bool can_colorize) const m_dest_snode->m_fun->decl, m_src_snode->m_fun->decl, m_critical_state)); - if (custom_desc.m_buffer) + if (custom_desc.get ()) return custom_desc; } return make_label_text (can_colorize, @@ -1105,19 +1105,19 @@ warning_event::get_desc (bool can_colorize) const label_text ev_desc = m_pending_diagnostic->describe_final_event (evdesc::final_event (can_colorize, var, m_state)); - if (ev_desc.m_buffer) + if (ev_desc.get ()) { if (m_sm && flag_analyzer_verbose_state_changes) { if (var) return make_label_text (can_colorize, "%s (%qE is in state %qs)", - ev_desc.m_buffer, + ev_desc.get (), var, m_state->get_name ()); else return make_label_text (can_colorize, "%s (in global state %qs)", - ev_desc.m_buffer, + ev_desc.get (), m_state->get_name ()); } else @@ -1163,7 +1163,7 @@ checker_path::dump (pretty_printer *pp) const if (i > 0) pp_string (pp, ", "); label_text event_desc (e->get_desc (false)); - pp_printf (pp, "\"%s\"", event_desc.m_buffer); + pp_printf (pp, "\"%s\"", event_desc.get ()); } pp_character (pp, ']'); } @@ -1203,7 +1203,7 @@ checker_path::debug () const "[%i]: %s \"%s\"\n", i, event_kind_to_string (m_events[i]->m_kind), - event_desc.m_buffer); + event_desc.get ()); } } diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 083f66b..fded828 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -2297,7 +2297,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, label_text sval_desc = sval->get_desc (); log ("considering event %i (%s), with sval: %qs, state: %qs", idx, event_kind_to_string (base_event->m_kind), - sval_desc.m_buffer, state->get_name ()); + sval_desc.get (), state->get_name ()); } else log ("considering event %i (%s), with global state: %qs", @@ -2363,8 +2363,8 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, = state_change->m_origin->get_desc (); log ("event %i:" " switching var of interest from %qs to %qs", - idx, sval_desc.m_buffer, - origin_sval_desc.m_buffer); + idx, sval_desc.get (), + origin_sval_desc.get ()); } sval = state_change->m_origin; } @@ -2386,12 +2386,12 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, label_text sval_desc = sval->get_desc (); log ("filtering event %i:" " state change to %qs unrelated to %qs", - idx, change_sval_desc.m_buffer, - sval_desc.m_buffer); + idx, change_sval_desc.get (), + sval_desc.get ()); } else log ("filtering event %i: state change to %qs", - idx, change_sval_desc.m_buffer); + idx, change_sval_desc.get ()); } else log ("filtering event %i: global state change", idx); @@ -2460,7 +2460,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, log ("event %i:" " recording critical state for %qs at call" " from %qE in callee to %qE in caller", - idx, sval_desc.m_buffer, callee_var, caller_var); + idx, sval_desc.get (), callee_var, caller_var); } if (expr.param_p ()) event->record_critical_state (caller_var, state); @@ -2503,7 +2503,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, log ("event %i:" " recording critical state for %qs at return" " from %qE in caller to %qE in callee", - idx, sval_desc.m_buffer, callee_var, callee_var); + idx, sval_desc.get (), callee_var, callee_var); } if (expr.return_value_p ()) event->record_critical_state (callee_var, state); @@ -2586,7 +2586,7 @@ diagnostic_manager::prune_interproc_events (checker_path *path) const (path->get_checker_event (idx)->get_desc (false)); log ("filtering events %i-%i:" " irrelevant call/entry/return: %s", - idx, idx + 2, desc.m_buffer); + idx, idx + 2, desc.get ()); } path->delete_event (idx + 2); path->delete_event (idx + 1); @@ -2608,7 +2608,7 @@ diagnostic_manager::prune_interproc_events (checker_path *path) const (path->get_checker_event (idx)->get_desc (false)); log ("filtering events %i-%i:" " irrelevant call/return: %s", - idx, idx + 1, desc.m_buffer); + idx, idx + 1, desc.get ()); } path->delete_event (idx + 1); path->delete_event (idx); diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 888123f..9ffcc41 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -4590,7 +4590,7 @@ feasibility_state::maybe_update_for_edge (logger *logger, logger->log (" sedge: SN:%i -> SN:%i %s", sedge->m_src->m_index, sedge->m_dest->m_index, - desc.m_buffer); + desc.get ()); } const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt (); diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index 90a56e3..f0f4046 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -300,7 +300,7 @@ sm_state_map::to_json () const entry_t e = (*iter).second; label_text sval_desc = sval->get_desc (); - map_obj->set (sval_desc.m_buffer, e.m_state->to_json ()); + map_obj->set (sval_desc.get (), e.m_state->to_json ()); /* This doesn't yet JSONify e.m_origin. */ } diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 55d6fa7..8c38e92 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -255,7 +255,7 @@ region_model::impl_call_analyzer_describe (const gcall *call, const svalue *sval = get_rvalue (t_val, ctxt); bool simple = zerop (t_verbosity); label_text desc = sval->get_desc (simple); - warning_at (call->location, 0, "svalue: %qs", desc.m_buffer); + warning_at (call->location, 0, "svalue: %qs", desc.get ()); } /* Handle a call to "__analyzer_dump_capacity". @@ -274,7 +274,7 @@ region_model::impl_call_analyzer_dump_capacity (const gcall *call, const region *base_reg = reg->get_base_region (); const svalue *capacity = get_capacity (base_reg); label_text desc = capacity->get_desc (true); - warning_at (call->location, 0, "capacity: %qs", desc.m_buffer); + warning_at (call->location, 0, "capacity: %qs", desc.get ()); } /* Compare D1 and D2 using their names, and then IDs to order them. */ diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc index 5b00e6a..a8d1ae9 100644 --- a/gcc/analyzer/region.cc +++ b/gcc/analyzer/region.cc @@ -589,7 +589,7 @@ json::value * region::to_json () const { label_text desc = get_desc (true); - json::value *reg_js = new json::string (desc.m_buffer); + json::value *reg_js = new json::string (desc.get ()); return reg_js; } diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc index 553fcd8..608aceb 100644 --- a/gcc/analyzer/sm-malloc.cc +++ b/gcc/analyzer/sm-malloc.cc @@ -1007,7 +1007,7 @@ inform_nonnull_attribute (tree fndecl, int arg_idx) label_text arg_desc = describe_argument_index (fndecl, arg_idx); inform (DECL_SOURCE_LOCATION (fndecl), "argument %s of %qD must be non-null", - arg_desc.m_buffer, fndecl); + arg_desc.get (), fndecl); /* Ideally we would use the location of the parm and underline the attribute also - but we don't have the location_t values at this point in the middle-end. @@ -1065,12 +1065,12 @@ public: if (m_origin_of_unchecked_event.known_p ()) result = ev.formatted_print ("argument %s (%qE) from %@ could be NULL" " where non-null expected", - arg_desc.m_buffer, ev.m_expr, + arg_desc.get (), ev.m_expr, &m_origin_of_unchecked_event); else result = ev.formatted_print ("argument %s (%qE) could be NULL" " where non-null expected", - arg_desc.m_buffer, ev.m_expr); + arg_desc.get (), ev.m_expr); return result; } @@ -1173,11 +1173,11 @@ public: label_text result; if (zerop (ev.m_expr)) result = ev.formatted_print ("argument %s NULL where non-null expected", - arg_desc.m_buffer); + arg_desc.get ()); else result = ev.formatted_print ("argument %s (%qE) NULL" " where non-null expected", - arg_desc.m_buffer, ev.m_expr); + arg_desc.get (), ev.m_expr); return result; } diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index d558d47..06151d8 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -675,7 +675,7 @@ binding_map::to_json () const { const svalue *value = *const_cast (m_map).get (key); label_text key_desc = key->get_desc (); - map_obj->set (key_desc.m_buffer, value->to_json ()); + map_obj->set (key_desc.get (), value->to_json ()); } return map_obj; @@ -2402,11 +2402,11 @@ store::to_json () const binding_cluster *cluster = *const_cast (m_cluster_map).get (base_reg); label_text base_reg_desc = base_reg->get_desc (); - clusters_in_parent_reg_obj->set (base_reg_desc.m_buffer, + clusters_in_parent_reg_obj->set (base_reg_desc.get (), cluster->to_json ()); } label_text parent_reg_desc = parent_reg->get_desc (); - store_obj->set (parent_reg_desc.m_buffer, clusters_in_parent_reg_obj); + store_obj->set (parent_reg_desc.get (), clusters_in_parent_reg_obj); } store_obj->set ("called_unknown_fn", new json::literal (m_called_unknown_fn)); diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index 52b48524..01e30f7 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -855,10 +855,10 @@ superedge::dump (pretty_printer *pp) const { pp_printf (pp, "edge: SN: %i -> SN: %i", m_src->m_index, m_dest->m_index); label_text desc (get_description (false)); - if (strlen (desc.m_buffer) > 0) + if (strlen (desc.get ()) > 0) { pp_space (pp); - pp_string (pp, desc.m_buffer); + pp_string (pp, desc.get ()); } } diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index 78a6eef..f5a5f1c 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -96,7 +96,7 @@ json::value * svalue::to_json () const { label_text desc = get_desc (true); - json::value *sval_js = new json::string (desc.m_buffer); + json::value *sval_js = new json::string (desc.get ()); return sval_js; } diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc index 2faed0c..68b94da 100644 --- a/gcc/c-family/c-format.cc +++ b/gcc/c-family/c-format.cc @@ -4617,14 +4617,14 @@ class range_label_for_format_type_mismatch label_text get_text (unsigned range_idx) const final override { label_text text = range_label_for_type_mismatch::get_text (range_idx); - if (text.m_buffer == NULL) + if (text.get () == NULL) return text; indirection_suffix suffix (m_pointer_count); char *p = (char *) alloca (suffix.get_buffer_size ()); suffix.fill_buffer (p); - char *result = concat (text.m_buffer, p, NULL); + char *result = concat (text.get (), p, NULL); return label_text::take (result); } diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc index 872c67e..baadc4b2 100644 --- a/gcc/diagnostic-format-json.cc +++ b/gcc/diagnostic-format-json.cc @@ -102,8 +102,8 @@ json_from_location_range (diagnostic_context *context, if (loc_range->m_label) { label_text text (loc_range->m_label->get_text (range_idx)); - if (text.m_buffer) - result->set ("label", new json::string (text.m_buffer)); + if (text.get ()) + result->set ("label", new json::string (text.get ())); } return result; diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index 1e4ebc8..fc28d16 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -582,7 +582,7 @@ sarif_builder::make_location_object (const diagnostic_event &event) /* "message" property (SARIF v2.1.0 section 3.28.5). */ label_text ev_desc = event.get_desc (false); - json::object *message_obj = make_message_object (ev_desc.m_buffer); + json::object *message_obj = make_message_object (ev_desc.get ()); location_obj->set ("message", message_obj); return location_obj; diff --git a/gcc/diagnostic-show-locus.cc b/gcc/diagnostic-show-locus.cc index 08dab20..9d430b5 100644 --- a/gcc/diagnostic-show-locus.cc +++ b/gcc/diagnostic-show-locus.cc @@ -1877,9 +1877,10 @@ struct pod_label_text {} pod_label_text (label_text &&other) - : m_buffer (other.m_buffer), m_caller_owned (other.m_owned) + : m_buffer (const_cast (other.get ())), + m_caller_owned (other.is_owner ()) { - other.moved_from (); + other.release (); } void maybe_free () @@ -1963,7 +1964,7 @@ layout::print_any_labels (linenum_type row) /* Allow for labels that return NULL from their get_text implementation (so e.g. such labels can control their own visibility). */ - if (text.m_buffer == NULL) + if (text.get () == NULL) continue; labels.safe_push (line_label (m_policy, i, disp_col, std::move (text))); diff --git a/gcc/tree-diagnostic-path.cc b/gcc/tree-diagnostic-path.cc index 2f297fa..6612b61 100644 --- a/gcc/tree-diagnostic-path.cc +++ b/gcc/tree-diagnostic-path.cc @@ -61,11 +61,11 @@ class path_label : public range_label is special-cased for diagnostic paths. */ bool colorize = pp_show_color (global_dc->printer); label_text event_text (event.get_desc (colorize)); - gcc_assert (event_text.m_buffer); + gcc_assert (event_text.get ()); pretty_printer pp; pp_show_color (&pp) = pp_show_color (global_dc->printer); diagnostic_event_id_t event_id (event_idx); - pp_printf (&pp, "%@ %s", &event_id, event_text.m_buffer); + pp_printf (&pp, "%@ %s", &event_id, event_text.get ()); label_text result = label_text::take (xstrdup (pp_formatted_text (&pp))); return result; } @@ -173,7 +173,7 @@ struct event_range diagnostic_event_id_t event_id (i); label_text event_text (iter_event.get_desc (true)); pretty_printer *pp = dc->printer; - pp_printf (pp, " %@: %s", &event_id, event_text.m_buffer); + pp_printf (pp, " %@: %s", &event_id, event_text.get ()); pp_newline (pp); } return; @@ -459,7 +459,7 @@ default_tree_diagnostic_path_printer (diagnostic_context *context, { const diagnostic_event &event = path->get_event (i); label_text event_text (event.get_desc (false)); - gcc_assert (event_text.m_buffer); + gcc_assert (event_text.get ()); diagnostic_event_id_t event_id (i); if (context->show_path_depths) { @@ -471,17 +471,17 @@ default_tree_diagnostic_path_printer (diagnostic_context *context, if (fndecl) inform (event.get_location (), "%@ %s (fndecl %qD, depth %i)", - &event_id, event_text.m_buffer, + &event_id, event_text.get (), fndecl, stack_depth); else inform (event.get_location (), "%@ %s (depth %i)", - &event_id, event_text.m_buffer, + &event_id, event_text.get (), stack_depth); } else inform (event.get_location (), - "%@ %s", &event_id, event_text.m_buffer); + "%@ %s", &event_id, event_text.get ()); } } break; @@ -519,7 +519,7 @@ default_tree_make_json_for_path (diagnostic_context *context, json_from_expanded_location (context, event.get_location ())); label_text event_text (event.get_desc (false)); - event_obj->set ("description", new json::string (event_text.m_buffer)); + event_obj->set ("description", new json::string (event_text.get ())); if (tree fndecl = event.get_fndecl ()) { const char *function -- cgit v1.1 From 91a7f30662cd8da14f0ae5eec1ce13aa29f1817c Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 14 Jul 2022 19:01:34 +0200 Subject: Implement visitor pattern for vrange. We frequently do operations on the various (upcoming) range types. The cascading if/switch statements of is_a<> are getting annoying and repetitive. The classic visitor pattern provides a clean way to implement classes handling various range types without the need for endless conditionals. It also helps us keep polluting the vrange API with functionality that should frankly live elsewhere. In a follow-up patch I will add pretty printing facilities for vrange and unify them with the dumping code. This is a prime candidate for the pattern, as the code isn't performance sensitive. Other instances (?? the dispatch code in range-ops ??) may still benefit from the hand coded conditionals, since they elide vtables in favor of the discriminator bit in vrange. Tested on x86-64 Linux. gcc/ChangeLog: * value-range.cc (irange::accept): New. (unsupported_range::accept): New. * value-range.h (class vrange_visitor): New. (class vrange): Add accept method. (class unsupported_range): Same. (class Value_Range): Same. --- gcc/value-range.cc | 12 ++++++++++++ gcc/value-range.h | 11 +++++++++++ 2 files changed, 23 insertions(+) (limited to 'gcc') diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 528ed54..8e6ec4c 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -30,6 +30,18 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "gimple-range.h" +void +irange::accept (const vrange_visitor &v) const +{ + v.visit (*this); +} + +void +unsupported_range::accept (const vrange_visitor &v) const +{ + v.visit (*this); +} + // Convenience function only available for integers and pointers. wide_int diff --git a/gcc/value-range.h b/gcc/value-range.h index 0e34118..a7da8c5 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -73,6 +73,7 @@ class vrange template friend bool is_a (vrange &); friend class Value_Range; public: + virtual void accept (const class vrange_visitor &v) const = 0; virtual void set (tree, tree, value_range_kind = VR_RANGE); virtual tree type () const; virtual bool supports_type_p (tree type) const; @@ -149,6 +150,7 @@ public: // Misc methods. virtual bool fits_p (const vrange &r) const override; virtual void dump (FILE * = stderr) const override; + virtual void accept (const vrange_visitor &v) const override; // Nonzero masks. wide_int get_nonzero_bits () const; @@ -251,6 +253,7 @@ class unsupported_range : public vrange public: unsupported_range (); virtual void dump (FILE *) const override; + virtual void accept (const vrange_visitor &v) const override; }; // is_a<> and as_a<> implementation for vrange. @@ -298,6 +301,13 @@ is_a (vrange &v) return v.m_discriminator == VR_IRANGE; } +class vrange_visitor +{ +public: + virtual void visit (const irange &) const { } + virtual void visit (const unsupported_range &) const { } +}; + // This is a special int_range<1> with only one pair, plus // VR_ANTI_RANGE magic to describe slightly more than can be described // in one pair. It is described in the code as a "legacy range" (as @@ -348,6 +358,7 @@ public: bool zero_p () const { return m_vrange->zero_p (); } wide_int lower_bound () const; // For irange/prange compatability. wide_int upper_bound () const; // For irange/prange compatability. + void accept (const vrange_visitor &v) const { m_vrange->accept (v); } private: void init (tree type); unsupported_range m_unsupported; -- cgit v1.1 From 64864aa9e6ea347a4f9c7027941be898ce993f85 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 14 Jul 2022 19:04:09 +0200 Subject: Convert vrange dumping facilities to pretty_printer. We need to dump global ranges from the gimple pretty printer code, but all the vrange dumping facilities work with FILE handles. This patch converts all the dumping methods to work with pretty printers, and provides a wrapper so the FILE * methods continue to work for debugging. I also cleaned up the code a bit. Tested on x86-64 Linux. gcc/ChangeLog: * Makefile.in (OBJS): Add value-range-pretty-print.o. * pretty-print.h (pp_vrange): New. * value-range.cc (vrange::dump): Call pp version. (unsupported_range::dump): Move to its own file. (dump_bound_with_infinite_markers): Same. (irange::dump): Same. (irange::dump_bitmasks): Same. (vrange::debug): Remove. * value-range.h: Remove virtual designation for dump methods. Remove dump_bitmasks method. * value-range-pretty-print.cc: New file. * value-range-pretty-print.h: New file. --- gcc/Makefile.in | 1 + gcc/pretty-print.h | 7 +++ gcc/value-range-pretty-print.cc | 111 +++++++++++++++++++++++++++++++++++++++ gcc/value-range-pretty-print.h | 37 +++++++++++++ gcc/value-range.cc | 113 +++++----------------------------------- gcc/value-range.h | 8 +-- 6 files changed, 172 insertions(+), 105 deletions(-) create mode 100644 gcc/value-range-pretty-print.cc create mode 100644 gcc/value-range-pretty-print.h (limited to 'gcc') diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 3ae2370..001506f 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1711,6 +1711,7 @@ OBJS = \ value-query.o \ value-range.o \ value-range-equiv.o \ + value-range-pretty-print.o \ value-range-storage.o \ value-relation.o \ value-prof.o \ diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h index fc58844..d810e57 100644 --- a/gcc/pretty-print.h +++ b/gcc/pretty-print.h @@ -340,6 +340,13 @@ pp_get_prefix (const pretty_printer *pp) { return pp->prefix; } pp_string (PP, pp_buffer (PP)->digit_buffer); \ } \ while (0) +#define pp_vrange(PP, R) \ + do \ + { \ + vrange_printer vrange_pp (PP); \ + (R)->accept (vrange_pp); \ + } \ + while (0) #define pp_double(PP, F) pp_scalar (PP, "%f", F) #define pp_pointer(PP, P) pp_scalar (PP, "%p", P) diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc new file mode 100644 index 0000000..b795e92 --- /dev/null +++ b/gcc/value-range-pretty-print.cc @@ -0,0 +1,111 @@ +/* Pretty print support for value ranges. + Copyright (C) 2019-2022 Free Software Foundation, Inc. + Contributed by Aldy Hernandez . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" +#include "tree-pretty-print.h" +#include "fold-const.h" +#include "gimple-range.h" +#include "value-range-pretty-print.h" + +void +vrange_printer::visit (const unsupported_range &r) const +{ + pp_string (pp, "[unsupported_range] "); + if (r.undefined_p ()) + { + pp_string (pp, "UNDEFINED"); + return; + } + if (r.varying_p ()) + { + pp_string (pp, "VARYING"); + return; + } + gcc_unreachable (); +} + +void +vrange_printer::visit (const irange &r) const +{ + pp_string (pp, "[irange] "); + if (r.undefined_p ()) + { + pp_string (pp, "UNDEFINED"); + return; + } + dump_generic_node (pp, r.type (), 0, TDF_NONE, false); + pp_character (pp, ' '); + if (r.varying_p ()) + { + pp_string (pp, "VARYING"); + return; + } + for (unsigned i = 0; i < r.num_pairs (); ++i) + { + tree lb = wide_int_to_tree (r.type (), r.lower_bound (i)); + tree ub = wide_int_to_tree (r.type (), r.upper_bound (i)); + pp_character (pp, '['); + print_irange_bound (lb); + pp_string (pp, ", "); + print_irange_bound (ub); + pp_character (pp, ']'); + } + print_irange_bitmasks (r); +} + +void +vrange_printer::print_irange_bound (tree bound) const +{ + tree type = TREE_TYPE (bound); + wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + + if (INTEGRAL_TYPE_P (type) + && !TYPE_UNSIGNED (type) + && TREE_CODE (bound) == INTEGER_CST + && wi::to_wide (bound) == type_min + && TYPE_PRECISION (type) != 1) + pp_string (pp, "-INF"); + else if (TREE_CODE (bound) == INTEGER_CST + && wi::to_wide (bound) == type_max + && TYPE_PRECISION (type) != 1) + pp_string (pp, "+INF"); + else + dump_generic_node (pp, bound, 0, TDF_NONE, false); +} + +void +vrange_printer::print_irange_bitmasks (const irange &r) const +{ + wide_int nz = r.get_nonzero_bits (); + if (nz == -1) + return; + + pp_string (pp, " NONZERO "); + char buf[WIDE_INT_PRINT_BUFFER_SIZE]; + print_hex (nz, buf); + pp_string (pp, buf); +} diff --git a/gcc/value-range-pretty-print.h b/gcc/value-range-pretty-print.h new file mode 100644 index 0000000..6d2fb74 --- /dev/null +++ b/gcc/value-range-pretty-print.h @@ -0,0 +1,37 @@ +/* Pretty print support for value ranges. + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by Aldy Hernandez . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_VALUE_RANGE_PRETTY_H +#define GCC_VALUE_RANGE_PRETTY_H + +class vrange_printer : public vrange_visitor +{ +public: + vrange_printer (pretty_printer *pp_) : pp (pp_) { } + void visit (const unsupported_range &) const override; + void visit (const irange &) const override; +private: + void print_irange_bound (tree bound) const; + void print_irange_bitmasks (const irange &) const; + + pretty_printer *pp; +}; + +#endif // GCC_VALUE_RANGE_PRETTY_H diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 8e6ec4c..525e192 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "ssa.h" #include "tree-pretty-print.h" +#include "value-range-pretty-print.h" #include "fold-const.h" #include "gimple-range.h" @@ -212,6 +213,19 @@ vrange::operator== (const vrange &src) const gcc_unreachable (); } +// Wrapper for vrange_printer to dump a range to a file. + +void +vrange::dump (FILE *file) const +{ + pretty_printer buffer; + pp_needs_newline (&buffer) = true; + buffer.buffer->stream = file; + vrange_printer vrange_pp (&buffer); + this->accept (vrange_pp); + pp_flush (&buffer); +} + bool irange::supports_type_p (tree type) const { @@ -238,23 +252,6 @@ unsupported_range::unsupported_range () set_undefined (); } -void -unsupported_range::dump (FILE *file) const -{ - fprintf (file, "[unsupported_range] "); - if (undefined_p ()) - { - fprintf (file, "UNDEFINED"); - return; - } - if (varying_p ()) - { - fprintf (file, "VARYING"); - return; - } - gcc_unreachable (); -} - // Here we copy between any two irange's. The ranges can be legacy or // multi-ranges, and copying between any combination works correctly. @@ -2461,88 +2458,6 @@ irange::union_nonzero_bits (const irange &r) return false; } -static void -dump_bound_with_infinite_markers (FILE *file, tree bound) -{ - tree type = TREE_TYPE (bound); - wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); - wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); - - if (INTEGRAL_TYPE_P (type) - && !TYPE_UNSIGNED (type) - && TREE_CODE (bound) == INTEGER_CST - && wi::to_wide (bound) == type_min - && TYPE_PRECISION (type) != 1) - fprintf (file, "-INF"); - else if (TREE_CODE (bound) == INTEGER_CST - && wi::to_wide (bound) == type_max - && TYPE_PRECISION (type) != 1) - fprintf (file, "+INF"); - else - print_generic_expr (file, bound); -} - -void -irange::dump (FILE *file) const -{ - fprintf (file, "[irange] "); - if (undefined_p ()) - { - fprintf (file, "UNDEFINED"); - return; - } - print_generic_expr (file, type ()); - fprintf (file, " "); - if (varying_p ()) - { - fprintf (file, "VARYING"); - dump_bitmasks (file); - return; - } - if (legacy_mode_p ()) - { - fprintf (file, "%s[", (m_kind == VR_ANTI_RANGE) ? "~" : ""); - dump_bound_with_infinite_markers (file, min ()); - fprintf (file, ", "); - dump_bound_with_infinite_markers (file, max ()); - fprintf (file, "]"); - dump_bitmasks (file); - return; - } - for (unsigned i = 0; i < m_num_ranges; ++i) - { - tree lb = m_base[i * 2]; - tree ub = m_base[i * 2 + 1]; - fprintf (file, "["); - dump_bound_with_infinite_markers (file, lb); - fprintf (file, ", "); - dump_bound_with_infinite_markers (file, ub); - fprintf (file, "]"); - } - dump_bitmasks (file); -} - -void -irange::dump_bitmasks (FILE *file) const -{ - if (m_nonzero_mask) - { - wide_int nz = get_nonzero_bits (); - if (nz != -1) - { - fprintf (file, " NONZERO "); - print_hex (nz, file); - } - } -} - -void -vrange::debug () const -{ - dump (stderr); - fprintf (stderr, "\n"); -} - void dump_value_range (FILE *file, const vrange *vr) { diff --git a/gcc/value-range.h b/gcc/value-range.h index a7da8c5..4af92fd 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -79,7 +79,6 @@ public: virtual bool supports_type_p (tree type) const; virtual void set_varying (tree type); virtual void set_undefined (); - virtual void dump (FILE * = stderr) const = 0; virtual bool union_ (const vrange &); virtual bool intersect (const vrange &); virtual bool singleton_p (tree *result = NULL) const; @@ -96,9 +95,9 @@ public: vrange& operator= (const vrange &); bool operator== (const vrange &) const; bool operator!= (const vrange &r) const { return !(*this == r); } + void dump (FILE *) const; enum value_range_kind kind () const; // DEPRECATED - void debug () const; protected: ENUM_BITFIELD(value_range_kind) m_kind : 8; @@ -149,7 +148,6 @@ public: // Misc methods. virtual bool fits_p (const vrange &r) const override; - virtual void dump (FILE * = stderr) const override; virtual void accept (const vrange_visitor &v) const override; // Nonzero masks. @@ -206,7 +204,6 @@ private: void set_nonzero_bits (tree mask); bool intersect_nonzero_bits (const irange &r); bool union_nonzero_bits (const irange &r); - void dump_bitmasks (FILE *) const; bool intersect (const wide_int& lb, const wide_int& ub); unsigned char m_num_ranges; @@ -252,7 +249,6 @@ class unsupported_range : public vrange { public: unsupported_range (); - virtual void dump (FILE *) const override; virtual void accept (const vrange_visitor &v) const override; }; @@ -339,7 +335,7 @@ public: bool operator!= (const Value_Range &r) const; operator vrange &(); operator const vrange &() const; - void dump (FILE *out = stderr) const; + void dump (FILE *) const; static bool supports_type_p (tree type); // Convenience methods for vrange compatability. -- cgit v1.1 From 3aab916f4ff9b41222273e712e1d435013ac8150 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 14 Jul 2022 19:06:57 +0200 Subject: Use pp_vrange for ranges in dump_ssaname_info. This changes the ad-hoc dumping of ranges in the gimple pretty printer to use the pp_vrange utility function, which has the benefit of handling all range types going forward and unifying the dumping code. Instead of: # RANGE [0, 51] NONZERO 0x3f # RANGE ~[5, 10] we would now get: # RANGE [irange] long unsigned int [0, 51] NONZERO 0x3f # RANGE [irange] int [-MIN, 4][11, MAX] Tested on x86-64 Linux. gcc/ChangeLog: * gimple-pretty-print.cc (dump_ssaname_info): Use pp_vrange. --- gcc/gimple-pretty-print.cc | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc index ebd87b2..f18baec 100644 --- a/gcc/gimple-pretty-print.cc +++ b/gcc/gimple-pretty-print.cc @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "ssa.h" #include "cgraph.h" #include "gimple-pretty-print.h" +#include "value-range-pretty-print.h" #include "internal-fn.h" #include "tree-eh.h" #include "gimple-iterator.h" @@ -2335,35 +2336,10 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc) if (!POINTER_TYPE_P (TREE_TYPE (node)) && SSA_NAME_RANGE_INFO (node)) { - wide_int min, max, nonzero_bits; - value_range r; - + Value_Range r (TREE_TYPE (node)); get_global_range_query ()->range_of_expr (r, node); - value_range_kind range_type = r.kind (); - if (!r.undefined_p ()) - { - min = wi::to_wide (r.min ()); - max = wi::to_wide (r.max ()); - } - - // FIXME: Use irange::dump() instead. - if (range_type == VR_VARYING) - pp_printf (buffer, "# RANGE VR_VARYING"); - else if (range_type == VR_RANGE || range_type == VR_ANTI_RANGE) - { - pp_printf (buffer, "# RANGE "); - pp_printf (buffer, "%s[", range_type == VR_RANGE ? "" : "~"); - pp_wide_int (buffer, min, TYPE_SIGN (TREE_TYPE (node))); - pp_printf (buffer, ", "); - pp_wide_int (buffer, max, TYPE_SIGN (TREE_TYPE (node))); - pp_printf (buffer, "]"); - } - nonzero_bits = get_nonzero_bits (node); - if (nonzero_bits != -1) - { - pp_string (buffer, " NONZERO "); - pp_wide_int (buffer, nonzero_bits, UNSIGNED); - } + pp_string (buffer, "# RANGE "); + pp_vrange (buffer, &r); newline_and_indent (buffer, spc); } } -- cgit v1.1 From 2fd215b03e88baae4e047dcb8dac5daa145dc3b4 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Fri, 15 Jul 2022 14:39:28 +0100 Subject: PR target/106278: Keep REG_EQUAL notes consistent during TImode STV on x86_64. This patch resolves PR target/106278 a regression on x86_64 caused by my recent TImode STV improvements. Now that TImode STV can handle comparisons such as "(set (regs:CC) (compare:CC (reg:TI) ...))" the convert_insn method sensibly checks that the mode of the SET_DEST is TImode before setting it to V1TImode [to avoid V1TImode appearing on the hard reg CC_FLAGS. Hence the current code looks like: if (GET_MODE (dst) == TImode) { tmp = find_reg_equal_equiv_note (insn); if (tmp && GET_MODE (XEXP (tmp, 0)) == TImode) PUT_MODE (XEXP (tmp, 0), V1TImode); PUT_MODE (dst, V1TImode); fix_debug_reg_uses (dst); } break; which checks GET_MODE (dst) before calling PUT_MODE, and when a change is made updating the REG_EQUAL_NOTE tmp if it exists. The logical flaw (oversight) is that due to RTL sharing, the destination of this set may already have been updated to V1TImode, as this chain is being converted, but we still need to update any REG_EQUAL_NOTE that still has TImode. Hence the correct code is actually: if (GET_MODE (dst) == TImode) { PUT_MODE (dst, V1TImode); fix_debug_reg_uses (dst); } if (GET_MODE (dst) == V1TImode) { tmp = find_reg_equal_equiv_note (insn); if (tmp && GET_MODE (XEXP (tmp, 0)) == TImode) PUT_MODE (XEXP (tmp, 0), V1TImode); } break; While fixing this behavior, I noticed I had some indentation whitespace issues and some vestigial dead code in this function/method that I've taken the liberty of cleaning up (as obvious) in this patch. 2022-07-15 Roger Sayle gcc/ChangeLog PR target/106278 * config/i386/i386-features.cc (general_scalar_chain::convert_insn): Fix indentation whitespace. (timode_scalar_chain::fix_debug_reg_uses): Likewise. (timode_scalar_chain::convert_insn): Delete dead code. Update TImode REG_EQUAL_NOTE even if the SET_DEST is already V1TI. Fix indentation whitespace. (convertible_comparison_p): Likewise. (timode_scalar_to_vector_candidate_p): Likewise. gcc/testsuite/ChangeLog * gcc.dg/pr106278.c: New test case. --- gcc/config/i386/i386-features.cc | 34 ++++++++++++++++------------------ gcc/testsuite/gcc.dg/pr106278.c | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr106278.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc index f1b03c3..813b203 100644 --- a/gcc/config/i386/i386-features.cc +++ b/gcc/config/i386/i386-features.cc @@ -1054,13 +1054,13 @@ general_scalar_chain::convert_insn (rtx_insn *insn) else if (REG_P (dst) && GET_MODE (dst) == smode) { /* Replace the definition with a SUBREG to the definition we - use inside the chain. */ + use inside the chain. */ rtx *vdef = defs_map.get (dst); if (vdef) dst = *vdef; dst = gen_rtx_SUBREG (vmode, dst, 0); /* IRA doesn't like to have REG_EQUAL/EQUIV notes when the SET_DEST - is a non-REG_P. So kill those off. */ + is a non-REG_P. So kill those off. */ rtx note = find_reg_equal_equiv_note (insn); if (note) remove_note (insn, note); @@ -1246,7 +1246,7 @@ timode_scalar_chain::fix_debug_reg_uses (rtx reg) { rtx_insn *insn = DF_REF_INSN (ref); /* Make sure the next ref is for a different instruction, - so that we're not affected by the rescan. */ + so that we're not affected by the rescan. */ next = DF_REF_NEXT_REG (ref); while (next && DF_REF_INSN (next) == insn) next = DF_REF_NEXT_REG (next); @@ -1336,21 +1336,19 @@ timode_scalar_chain::convert_insn (rtx_insn *insn) rtx dst = SET_DEST (def_set); rtx tmp; - if (MEM_P (dst) && !REG_P (src)) - { - /* There are no scalar integer instructions and therefore - temporary register usage is required. */ - } switch (GET_CODE (dst)) { case REG: if (GET_MODE (dst) == TImode) { + PUT_MODE (dst, V1TImode); + fix_debug_reg_uses (dst); + } + if (GET_MODE (dst) == V1TImode) + { tmp = find_reg_equal_equiv_note (insn); if (tmp && GET_MODE (XEXP (tmp, 0)) == TImode) PUT_MODE (XEXP (tmp, 0), V1TImode); - PUT_MODE (dst, V1TImode); - fix_debug_reg_uses (dst); } break; case MEM: @@ -1410,8 +1408,8 @@ timode_scalar_chain::convert_insn (rtx_insn *insn) if (MEM_P (dst)) { tmp = gen_reg_rtx (V1TImode); - emit_insn_before (gen_rtx_SET (tmp, src), insn); - src = tmp; + emit_insn_before (gen_rtx_SET (tmp, src), insn); + src = tmp; } break; @@ -1434,8 +1432,8 @@ timode_scalar_chain::convert_insn (rtx_insn *insn) if (MEM_P (dst)) { tmp = gen_reg_rtx (V1TImode); - emit_insn_before (gen_rtx_SET (tmp, src), insn); - src = tmp; + emit_insn_before (gen_rtx_SET (tmp, src), insn); + src = tmp; } break; @@ -1448,8 +1446,8 @@ timode_scalar_chain::convert_insn (rtx_insn *insn) if (MEM_P (dst)) { tmp = gen_reg_rtx (V1TImode); - emit_insn_before (gen_rtx_SET (tmp, src), insn); - src = tmp; + emit_insn_before (gen_rtx_SET (tmp, src), insn); + src = tmp; } break; @@ -1585,7 +1583,7 @@ convertible_comparison_p (rtx_insn *insn, enum machine_mode mode) /* *cmp_doubleword. */ if ((CONST_INT_P (op1) || ((REG_P (op1) || MEM_P (op1)) - && GET_MODE (op1) == mode)) + && GET_MODE (op1) == mode)) && (CONST_INT_P (op2) || ((REG_P (op2) || MEM_P (op2)) && GET_MODE (op2) == mode))) @@ -1745,7 +1743,7 @@ timode_scalar_to_vector_candidate_p (rtx_insn *insn) if (GET_MODE (dst) != TImode || (GET_MODE (src) != TImode - && !CONST_SCALAR_INT_P (src))) + && !CONST_SCALAR_INT_P (src))) return false; if (!REG_P (dst) && !MEM_P (dst)) diff --git a/gcc/testsuite/gcc.dg/pr106278.c b/gcc/testsuite/gcc.dg/pr106278.c new file mode 100644 index 0000000..ab312b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr106278.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +void __assert_fail(); +struct a { + int b; + int c; + int d; + int : 2; +}; +int e, f; +struct a g, i; +const struct a h; +int main() { + struct a j; + g = h; + if (e) + __assert_fail(); + if (f) + j = h; + i = j; + return 0; +} -- cgit v1.1 From 5ba864c5d11a1c20891a1e054cb7814ec23de5c9 Mon Sep 17 00:00:00 2001 From: Andrew Carlotti Date: Fri, 15 Jul 2022 15:25:53 +0100 Subject: aarch64: Add V1DI mode We already have a V1DF mode, so this makes the vector modes more consistent. Additionally, this allows us to recognise uint64x1_t and int64x1_t types given only the mode and type qualifiers (e.g. in aarch64_lookup_simd_builtin_type). gcc/ChangeLog: * config/aarch64/aarch64-builtins.cc (v1di_UP): Add V1DI mode to _UP macros. * config/aarch64/aarch64-modes.def (VECTOR_MODE): Add V1DI mode. * config/aarch64/aarch64-simd-builtin-types.def: Use V1DI mode. * config/aarch64/aarch64-simd.md (vec_extractv2dfv1df): Replace with... (vec_extract): ...this. * config/aarch64/aarch64.cc (aarch64_classify_vector_mode): Add V1DI mode. * config/aarch64/iterators.md (VQ_2E, V1HALF, V1half): New. (nunits): Add V1DI mode. --- gcc/config/aarch64/aarch64-builtins.cc | 1 + gcc/config/aarch64/aarch64-modes.def | 1 + gcc/config/aarch64/aarch64-simd-builtin-types.def | 6 +++--- gcc/config/aarch64/aarch64-simd.md | 14 +++++++------- gcc/config/aarch64/aarch64.cc | 2 +- gcc/config/aarch64/iterators.md | 14 ++++++++++++-- 6 files changed, 25 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc index 4621c6d..7371460 100644 --- a/gcc/config/aarch64/aarch64-builtins.cc +++ b/gcc/config/aarch64/aarch64-builtins.cc @@ -55,6 +55,7 @@ #define v2si_UP E_V2SImode #define v2sf_UP E_V2SFmode #define v1df_UP E_V1DFmode +#define v1di_UP E_V1DImode #define di_UP E_DImode #define df_UP E_DFmode #define v16qi_UP E_V16QImode diff --git a/gcc/config/aarch64/aarch64-modes.def b/gcc/config/aarch64/aarch64-modes.def index 8f39922..d3c9b74 100644 --- a/gcc/config/aarch64/aarch64-modes.def +++ b/gcc/config/aarch64/aarch64-modes.def @@ -70,6 +70,7 @@ VECTOR_MODES (INT, 8); /* V8QI V4HI V2SI. */ VECTOR_MODES (INT, 16); /* V16QI V8HI V4SI V2DI. */ VECTOR_MODES (FLOAT, 8); /* V2SF. */ VECTOR_MODES (FLOAT, 16); /* V4SF V2DF. */ +VECTOR_MODE (INT, DI, 1); /* V1DI. */ VECTOR_MODE (FLOAT, DF, 1); /* V1DF. */ VECTOR_MODE (FLOAT, HF, 2); /* V2HF. */ diff --git a/gcc/config/aarch64/aarch64-simd-builtin-types.def b/gcc/config/aarch64/aarch64-simd-builtin-types.def index 248e51e..4054558 100644 --- a/gcc/config/aarch64/aarch64-simd-builtin-types.def +++ b/gcc/config/aarch64/aarch64-simd-builtin-types.def @@ -24,7 +24,7 @@ ENTRY (Int16x8_t, V8HI, none, 11) ENTRY (Int32x2_t, V2SI, none, 11) ENTRY (Int32x4_t, V4SI, none, 11) - ENTRY (Int64x1_t, DI, none, 11) + ENTRY (Int64x1_t, V1DI, none, 11) ENTRY (Int64x2_t, V2DI, none, 11) ENTRY (Uint8x8_t, V8QI, unsigned, 11) ENTRY (Uint8x16_t, V16QI, unsigned, 12) @@ -32,7 +32,7 @@ ENTRY (Uint16x8_t, V8HI, unsigned, 12) ENTRY (Uint32x2_t, V2SI, unsigned, 12) ENTRY (Uint32x4_t, V4SI, unsigned, 12) - ENTRY (Uint64x1_t, DI, unsigned, 12) + ENTRY (Uint64x1_t, V1DI, unsigned, 12) ENTRY (Uint64x2_t, V2DI, unsigned, 12) ENTRY (Poly8_t, QI, poly, 9) ENTRY (Poly16_t, HI, poly, 10) @@ -42,7 +42,7 @@ ENTRY (Poly8x16_t, V16QI, poly, 12) ENTRY (Poly16x4_t, V4HI, poly, 12) ENTRY (Poly16x8_t, V8HI, poly, 12) - ENTRY (Poly64x1_t, DI, poly, 12) + ENTRY (Poly64x1_t, V1DI, poly, 12) ENTRY (Poly64x2_t, V2DI, poly, 12) ENTRY (Float16x4_t, V4HF, none, 13) ENTRY (Float16x8_t, V8HF, none, 13) diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index a00e1c6..587a45d 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -8026,16 +8026,16 @@ }) ;; Extract a single-element 64-bit vector from one half of a 128-bit vector. -(define_expand "vec_extractv2dfv1df" - [(match_operand:V1DF 0 "register_operand") - (match_operand:V2DF 1 "register_operand") +(define_expand "vec_extract" + [(match_operand: 0 "register_operand") + (match_operand:VQ_2E 1 "register_operand") (match_operand 2 "immediate_operand")] "TARGET_SIMD" { - /* V1DF is rarely used by other patterns, so it should be better to hide - it in a subreg destination of a normal DF op. */ - rtx scalar0 = gen_lowpart (DFmode, operands[0]); - emit_insn (gen_vec_extractv2dfdf (scalar0, operands[1], operands[2])); + /* V1DI and V1DF are rarely used by other patterns, so it should be better + to hide it in a subreg destination of a normal DI or DF op. */ + rtx scalar0 = gen_lowpart (mode, operands[0]); + emit_insn (gen_vec_extract (scalar0, operands[1], operands[2])); DONE; }) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 303814b..1a514c1 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -3552,7 +3552,7 @@ aarch64_classify_vector_mode (machine_mode mode) case E_V8QImode: case E_V4HImode: case E_V2SImode: - /* ...E_V1DImode doesn't exist. */ + case E_V1DImode: case E_V4HFmode: case E_V4BFmode: case E_V2SFmode: diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index 1be6a91..0dd9dc6 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -135,6 +135,9 @@ ;; VQ without 2 element modes. (define_mode_iterator VQ_NO2E [V16QI V8HI V4SI V8HF V4SF V8BF]) +;; 2 element quad vector modes. +(define_mode_iterator VQ_2E [V2DI V2DF]) + ;; BFmode vector modes. (define_mode_iterator VBF [V4BF V8BF]) @@ -1067,12 +1070,13 @@ (define_mode_attr nunits [(V8QI "8") (V16QI "16") (V4HI "4") (V8HI "8") (V2SI "2") (V4SI "4") - (V2DI "2") (V8DI "8") + (V1DI "1") (V2DI "2") (V4HF "4") (V8HF "8") (V4BF "4") (V8BF "8") (V2SF "2") (V4SF "4") (V1DF "1") (V2DF "2") - (DI "1") (DF "1")]) + (DI "1") (DF "1") + (V8DI "8")]) ;; Map a mode to the number of bits in it, if the size of the mode ;; is constant. @@ -1442,6 +1446,12 @@ (V2DI "di") (V2SF "sf") (V4SF "v2sf") (V2DF "df")]) +;; Single-element half modes of quad vector modes. +(define_mode_attr V1HALF [(V2DI "V1DI") (V2DF "V1DF")]) + +;; Single-element half modes of quad vector modes, in lower-case +(define_mode_attr V1half [(V2DI "v1di") (V2DF "v1df")]) + ;; Double modes of vector modes. (define_mode_attr VDBL [(V8QI "V16QI") (V4HI "V8HI") (V4HF "V8HF") (V4BF "V8BF") -- cgit v1.1 From 91259dd850bcbf4c0b5bdcd8304d67b883b73cc0 Mon Sep 17 00:00:00 2001 From: Andrew Carlotti Date: Fri, 15 Jul 2022 15:27:33 +0100 Subject: aarch64: Remove qualifier_internal This has been unused since 2014, so there's no reason to retain it. gcc/ChangeLog: * config/aarch64/aarch64-builtins.cc (enum aarch64_type_qualifiers): Remove qualifier_internal. (aarch64_init_simd_builtin_functions): Remove qualifier_internal check. --- gcc/config/aarch64/aarch64-builtins.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc index 7371460..69f1e4e 100644 --- a/gcc/config/aarch64/aarch64-builtins.cc +++ b/gcc/config/aarch64/aarch64-builtins.cc @@ -145,9 +145,7 @@ enum aarch64_type_qualifiers qualifier_maybe_immediate = 0x10, /* 1 << 4 */ /* void foo (...). */ qualifier_void = 0x20, /* 1 << 5 */ - /* Some patterns may have internal operands, this qualifier is an - instruction to the initialisation code to skip this operand. */ - qualifier_internal = 0x40, /* 1 << 6 */ + /* 1 << 6 is now unused */ /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum rather than using the type of the operand. */ qualifier_map_mode = 0x80, /* 1 << 7 */ @@ -1207,10 +1205,6 @@ aarch64_init_simd_builtin_functions (bool called_from_pragma) else type_signature[op_num] = 's'; - /* Skip an internal operand for vget_{low, high}. */ - if (qualifiers & qualifier_internal) - continue; - /* Some builtins have different user-facing types for certain arguments, encoded in d->mode. */ if (qualifiers & qualifier_map_mode) -- cgit v1.1 From 5054bc001d9b66fe68d938790f08f48621c6b976 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 15 Jul 2022 08:02:13 -0700 Subject: go: fix f(g()) where g returns zero-sized type Test case is https://go.dev/cl/417481. Fixes golang/go#23868 * go-gcc.cc (Gcc_backend::call_expression): Handle a void argument, as for f(g()) where g returns a zero-sized type. --- gcc/go/go-gcc.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc') diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index f3de7a8..7b4b2ad 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -2112,6 +2112,19 @@ Gcc_backend::call_expression(Bfunction*, // containing fcn for call args[i] = fn_args.at(i)->get_tree(); if (args[i] == error_mark_node) return this->error_expression(); + if (TREE_TYPE(args[i]) == void_type_node) + { + // This can happen for a case like f(g()) where g returns a + // zero-sized type, because in that case we've changed g to + // return void. + tree t = TYPE_ARG_TYPES(TREE_TYPE(TREE_TYPE(fn))); + for (size_t j = 0; j < i; ++j) + t = TREE_CHAIN(t); + tree arg_type = TREE_TYPE(TREE_VALUE(t)); + args[i] = fold_build2_loc(EXPR_LOCATION(args[i]), COMPOUND_EXPR, + arg_type, args[i], + build_zero_cst(arg_type)); + } } tree fndecl = fn; -- cgit v1.1 From b1d07b50d43e954b0c6a2b85079ce0fdf5e77ec5 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 15 Jul 2022 11:28:34 -0400 Subject: analyzer: documentation nits relating to new fd warnings gcc/ChangeLog: * doc/invoke.texi (Static Analyzer Options): Add the new fd warnings to the initial gccoptlist, and to the list of those disabled by -fanalyzer-checker=taint. Signed-off-by: David Malcolm --- gcc/doc/invoke.texi | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d5ff101..84d6f0f 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -446,6 +446,11 @@ Objective-C and Objective-C++ Dialects}. -Wno-analyzer-double-fclose @gol -Wno-analyzer-double-free @gol -Wno-analyzer-exposure-through-output-file @gol +-Wno-analyzer-fd-access-mode-mismatch @gol +-Wno-analyzer-fd-double-close @gol +-Wno-analyzer-fd-leak @gol +-Wno-analyzer-fd-use-after-close @gol +-Wno-analyzer-fd-use-without-check @gol -Wno-analyzer-file-leak @gol -Wno-analyzer-free-of-non-heap @gol -Wno-analyzer-malloc-leak @gol @@ -10231,6 +10236,11 @@ following warnings from @option{-fanalyzer}: -Wanalyzer-double-fclose @gol -Wanalyzer-double-free @gol -Wanalyzer-exposure-through-output-file @gol +-Wanalyzer-fd-access-mode-mismatch @gol +-Wanalyzer-fd-double-close @gol +-Wanalyzer-fd-leak @gol +-Wanalyzer-fd-use-after-close @gol +-Wanalyzer-fd-use-without-check @gol -Wanalyzer-file-leak @gol -Wanalyzer-free-of-non-heap @gol -Wanalyzer-malloc-leak @gol -- cgit v1.1 From 0a8edfbd37d399d1103d86e134ba0a92f8c873c3 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 15 Jul 2022 11:28:34 -0400 Subject: analyzer: fix taint false positive on optimized range checks [PR106284] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR analyzer/106284 reports a false positive from -Wanalyzer-tainted-array-index seen on the Linux kernel with a version of my patches from: https://gcc.gnu.org/pipermail/gcc-patches/2021-November/584372.html in drivers/usb/class/usblp.c in function ‘usblp_set_protocol’ handling usblp_ioctl on IOCNR_SET_PROTOCOL, which has: | 1337 | if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) | | ~ | | | | | (15) following ‘false’ branch... |...... | 1341 | if (usblp->intf->num_altsetting > 1) { | | ~~~~~~~~~~~~ | | | | | | | (16) ...to here | | (17) following ‘true’ branch... | 1342 | alts = usblp->protocol[protocol].alt_setting; | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (18) ...to here | | (19) use of attacker-controlled value ‘arg’ in array lookup without bounds checking where "arg" is "protocol" (albeit from the caller frame, the ioctl callback), and is clearly checked at (15). The root cause is that at -O1 and above fold-const's build_range-check can optimize range checks (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low) and thus into a single check: (unsigned)(c - low) <= (unsigned)(high-low). I initially attempted to fix this by detecting such conditions in region_model::on_condition, and calling on_condition for both of the implied conditions. This turned out not to work since the current sm_context framework doesn't support applying two conditions simultaneously: it led to a transition from the old state to has_lb, then a transition from the old state *again* to has_ub, thus leaving the new state as has_ub, rather than the stop state. Instead, this patch fixes things by special-casing it within taint_state_machine::on_condition. gcc/analyzer/ChangeLog: PR analyzer/106284 * sm-taint.cc (taint_state_machine::on_condition): Handle range checks optimized by build_range_check. gcc/testsuite/ChangeLog: PR analyzer/106284 * gcc.dg/analyzer/torture/taint-read-index-2.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/sm-taint.cc | 42 ++++++++++++++++ .../gcc.dg/analyzer/torture/taint-read-index-2.c | 56 ++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c (limited to 'gcc') diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc index 4075cf6..2de9284 100644 --- a/gcc/analyzer/sm-taint.cc +++ b/gcc/analyzer/sm-taint.cc @@ -848,6 +848,48 @@ taint_state_machine::on_condition (sm_context *sm_ctxt, case LE_EXPR: case LT_EXPR: { + /* Detect where build_range_check has optimized + (c>=low) && (c<=high) + into + (c-low>=0) && (c-low<=high-low) + and thus into: + (unsigned)(c - low) <= (unsigned)(high-low). */ + if (const binop_svalue *binop_sval + = lhs->dyn_cast_binop_svalue ()) + { + const svalue *inner_lhs = binop_sval->get_arg0 (); + enum tree_code inner_op = binop_sval->get_op (); + const svalue *inner_rhs = binop_sval->get_arg1 (); + if (const svalue *before_cast = inner_lhs->maybe_undo_cast ()) + inner_lhs = before_cast; + if (tree outer_rhs_cst = rhs->maybe_get_constant ()) + if (tree inner_rhs_cst = inner_rhs->maybe_get_constant ()) + if (inner_op == PLUS_EXPR + && TREE_CODE (inner_rhs_cst) == INTEGER_CST + && TREE_CODE (outer_rhs_cst) == INTEGER_CST + && TYPE_UNSIGNED (TREE_TYPE (inner_rhs_cst)) + && TYPE_UNSIGNED (TREE_TYPE (outer_rhs_cst))) + { + /* We have + (unsigned)(INNER_LHS + CST_A) get_state (stmt, inner_lhs); + if (old_state == m_tainted + || old_state == m_has_lb + || old_state == m_has_ub) + sm_ctxt->set_next_state (stmt, inner_lhs, m_stop); + return; + } + } + sm_ctxt->on_transition (node, stmt, lhs, m_tainted, m_has_ub); sm_ctxt->on_transition (node, stmt, lhs, m_has_lb, diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c b/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c new file mode 100644 index 0000000..6a4ebdb --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c @@ -0,0 +1,56 @@ +// TODO: remove need for the taint option: +/* { dg-additional-options "-fanalyzer-checker=taint" } */ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */ + +#define LOWER_LIMIT 5 +#define UPPER_LIMIT 20 + +static int arr[UPPER_LIMIT]; + +static int +called_by_test_1 (int iarg) +{ + return arr[iarg]; /* { dg-warning "without bounds checking" } */ +} + +int __attribute__((tainted_args)) +test_1 (unsigned long ularg) +{ + return called_by_test_1 (ularg); +} + +static int +called_by_test_2 (int iarg) +{ + if (iarg < LOWER_LIMIT || iarg > UPPER_LIMIT) + return 0; + return arr[iarg]; /* { dg-bogus "bounds checking" } */ +} + +int __attribute__((tainted_args)) +test_2 (unsigned long ularg) +{ + return called_by_test_2 (ularg); +} + +int __attribute__((tainted_args)) +test_3 (int iarg) +{ + if (iarg < LOWER_LIMIT || iarg > UPPER_LIMIT) + return 0; + return arr[iarg]; /* { dg-bogus "bounds checking" } */ +} + +static int +called_by_test_4 (int iarg) +{ + if (iarg < LOWER_LIMIT || iarg > UPPER_LIMIT) + return 0; + return arr[iarg]; /* { dg-bogus "bounds checking" } */ +} + +int __attribute__((tainted_args)) +test_4 (unsigned uarg) +{ + return called_by_test_4 (uarg); +} -- cgit v1.1 From 9a15d3beace26d68561cb3481b70b0bbcb122ca5 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 29 Jun 2022 19:00:54 -0400 Subject: c++: Add __reference_con{struc,ver}ts_from_temporary [PR104477] This patch implements C++23 P2255R2, which adds two new type traits to detect reference binding to a temporary. They can be used to detect code like std::tuple t("meow"); which is incorrect because it always creates a dangling reference, because the std::string temporary is created inside the selected constructor of std::tuple, and not outside it. There are two new compiler builtins, __reference_constructs_from_temporary and __reference_converts_from_temporary. The former is used to simulate direct- and the latter copy-initialization context. But I had a hard time finding a test where there's actually a difference. Under DR 2267, both of these are invalid: struct A { } a; struct B { explicit B(const A&); }; const B &b1{a}; const B &b2(a); so I had to peruse [over.match.ref], and eventually realized that the difference can be seen here: struct G { operator int(); // #1 explicit operator int&&(); // #2 }; int&& r1(G{}); // use #2 (no temporary) int&& r2 = G{}; // use #1 (a temporary is created to be bound to int&&) The implementation itself was rather straightforward because we already have the conv_binds_ref_to_prvalue function. The main function here is ref_xes_from_temporary. I've changed the return type of ref_conv_binds_directly to tristate, because previously the function didn't distinguish between an invalid conversion and one that binds to a prvalue. Since it no longer returns a bool, I removed the _p suffix. The patch also adds the relevant class and variable templates to . PR c++/104477 gcc/c-family/ChangeLog: * c-common.cc (c_common_reswords): Add __reference_constructs_from_temporary and __reference_converts_from_temporary. * c-common.h (enum rid): Add RID_REF_CONSTRUCTS_FROM_TEMPORARY and RID_REF_CONVERTS_FROM_TEMPORARY. gcc/cp/ChangeLog: * call.cc (ref_conv_binds_directly_p): Rename to ... (ref_conv_binds_directly): ... this. Add a new bool parameter. Change the return type to tristate. * constraint.cc (diagnose_trait_expr): Handle CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY. * cp-tree.h: Include "tristate.h". (enum cp_trait_kind): Add CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY. (ref_conv_binds_directly_p): Rename to ... (ref_conv_binds_directly): ... this. (ref_xes_from_temporary): Declare. * cxx-pretty-print.cc (pp_cxx_trait_expression): Handle CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY. * method.cc (ref_xes_from_temporary): New. * parser.cc (cp_parser_primary_expression): Handle RID_REF_CONSTRUCTS_FROM_TEMPORARY and RID_REF_CONVERTS_FROM_TEMPORARY. (cp_parser_trait_expr): Likewise. (warn_for_range_copy): Adjust to call ref_conv_binds_directly. * semantics.cc (trait_expr_value): Handle CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY. (finish_trait_expr): Likewise. libstdc++-v3/ChangeLog: * include/std/type_traits (reference_constructs_from_temporary, reference_converts_from_temporary): New class templates. (reference_constructs_from_temporary_v, reference_converts_from_temporary_v): New variable templates. (__cpp_lib_reference_from_temporary): Define for C++23. * include/std/version (__cpp_lib_reference_from_temporary): Define for C++23. * testsuite/20_util/variable_templates_for_traits.cc: Test reference_constructs_from_temporary_v and reference_converts_from_temporary_v. * testsuite/20_util/reference_from_temporary/value.cc: New test. * testsuite/20_util/reference_from_temporary/value2.cc: New test. * testsuite/20_util/reference_from_temporary/version.cc: New test. gcc/testsuite/ChangeLog: * g++.dg/ext/reference_constructs_from_temporary1.C: New test. * g++.dg/ext/reference_converts_from_temporary1.C: New test. --- gcc/c-family/c-common.cc | 4 + gcc/c-family/c-common.h | 2 + gcc/cp/call.cc | 20 +- gcc/cp/constraint.cc | 8 + gcc/cp/cp-tree.h | 8 +- gcc/cp/cxx-pretty-print.cc | 6 + gcc/cp/method.cc | 25 +++ gcc/cp/parser.cc | 36 ++-- gcc/cp/semantics.cc | 8 + .../ext/reference_constructs_from_temporary1.C | 214 +++++++++++++++++++++ .../ext/reference_converts_from_temporary1.C | 214 +++++++++++++++++++++ 11 files changed, 523 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C create mode 100644 gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C (limited to 'gcc') diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 1b8e73f..655c3ae 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -537,6 +537,10 @@ const struct c_common_resword c_common_reswords[] = { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY }, + { "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY, + D_CXXONLY }, + { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, + D_CXXONLY }, /* C++ transactional memory. */ { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index c090084..f906439 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -184,6 +184,8 @@ enum rid RID_IS_UNION, RID_UNDERLYING_TYPE, RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, + RID_REF_CONSTRUCTS_FROM_TEMPORARY, + RID_REF_CONVERTS_FROM_TEMPORARY, /* C++11 */ RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT, diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index fc98552..191c68c 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -9109,21 +9109,27 @@ conv_binds_ref_to_prvalue (conversion *c) return conv_is_prvalue (next_conversion (c)); } -/* True iff converting EXPR to a reference type TYPE does not involve - creating a temporary. */ +/* Return tristate::TS_TRUE if converting EXPR to a reference type TYPE does + not involve creating a temporary. Return tristate::TS_FALSE if converting + EXPR to a reference type TYPE binds the reference to a temporary. If the + conversion is invalid or bad, return tristate::TS_UNKNOWN. DIRECT_INIT_P + says whether the conversion should be done in direct- or copy-initialization + context. */ -bool -ref_conv_binds_directly_p (tree type, tree expr) +tristate +ref_conv_binds_directly (tree type, tree expr, bool direct_init_p /*= false*/) { gcc_assert (TYPE_REF_P (type)); /* Get the high-water mark for the CONVERSION_OBSTACK. */ void *p = conversion_obstack_alloc (0); + const int flags = direct_init_p ? LOOKUP_NORMAL : LOOKUP_IMPLICIT; conversion *conv = implicit_conversion (type, TREE_TYPE (expr), expr, - /*c_cast_p=*/false, - LOOKUP_IMPLICIT, tf_none); - bool ret = conv && !conv->bad_p && !conv_binds_ref_to_prvalue (conv); + /*c_cast_p=*/false, flags, tf_none); + tristate ret (tristate::TS_UNKNOWN); + if (conv && !conv->bad_p) + ret = tristate (!conv_binds_ref_to_prvalue (conv)); /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index f2137eb..568318f 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3697,6 +3697,14 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: inform (loc, " %qT does not have unique object representations", t1); break; + case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: + inform (loc, " %qT is not a reference that binds to a temporary " + "object of type %qT (direct-initialization)", t1, t2); + break; + case CPTK_REF_CONVERTS_FROM_TEMPORARY: + inform (loc, " %qT is not a reference that binds to a temporary " + "object of type %qT (copy-initialization)", t1, t2); + break; case CPTK_BASES: case CPTK_DIRECT_BASES: case CPTK_UNDERLYING_TYPE: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bec98aa..cf51c39 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "hard-reg-set.h" #include "function.h" +#include "tristate.h" /* In order for the format checking to accept the C++ front end diagnostic framework extensions, you must include this file before @@ -1397,7 +1398,9 @@ enum cp_trait_kind CPTK_IS_ASSIGNABLE, CPTK_IS_CONSTRUCTIBLE, CPTK_IS_NOTHROW_ASSIGNABLE, - CPTK_IS_NOTHROW_CONSTRUCTIBLE + CPTK_IS_NOTHROW_CONSTRUCTIBLE, + CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, + CPTK_REF_CONVERTS_FROM_TEMPORARY }; /* The types that we are processing. */ @@ -6520,7 +6523,7 @@ extern bool sufficient_parms_p (const_tree); extern tree type_decays_to (tree); extern tree extract_call_expr (tree); extern tree build_trivial_dtor_call (tree, bool = false); -extern bool ref_conv_binds_directly_p (tree, tree); +extern tristate ref_conv_binds_directly (tree, tree, bool = false); extern tree build_user_type_conversion (tree, tree, int, tsubst_flags_t); extern tree build_new_function_call (tree, vec **, @@ -7105,6 +7108,7 @@ extern tree forward_parm (tree); extern bool is_trivially_xible (enum tree_code, tree, tree); extern bool is_nothrow_xible (enum tree_code, tree, tree); extern bool is_xible (enum tree_code, tree, tree); +extern bool ref_xes_from_temporary (tree, tree, bool); extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error); extern bool maybe_explain_implicit_delete (tree); extern void explain_implicit_non_constexpr (tree); diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index 7e4db2e..4459083 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -2696,6 +2696,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) case CPTK_IS_NOTHROW_CONSTRUCTIBLE: pp_cxx_ws_string (pp, "__is_nothrow_constructible"); break; + case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: + pp_cxx_ws_string (pp, "__reference_constructs_from_temporary"); + break; + case CPTK_REF_CONVERTS_FROM_TEMPORARY: + pp_cxx_ws_string (pp, "__reference_converts_from_temporary"); + break; default: gcc_unreachable (); diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 0dffd64..f2050f6 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2211,6 +2211,31 @@ is_xible (enum tree_code code, tree to, tree from) return !!expr; } +/* Return true iff conjunction_v, is_constructible> is + true, and the initialization + T t(VAL); // DIRECT_INIT_P + or + T t = VAL; // !DIRECT_INIT_P + binds t to a temporary object whose lifetime is extended. + VAL is defined in [meta.unary.prop]: + -- If T is a reference or function type, VAL is an expression with the + same type and value category as declval(). + -- Otherwise, VAL is a prvalue that initially has type T. */ + +bool +ref_xes_from_temporary (tree to, tree from, bool direct_init_p) +{ + /* Check is_reference. */ + if (!TYPE_REF_P (to)) + return false; + /* We don't check is_constructible: if T isn't constructible + from U, we won't be able to create a conversion. */ + tree val = build_stub_object (from); + if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE) + val = CLASS_TYPE_P (from) ? force_rvalue (val, tf_none) : rvalue (val); + return ref_conv_binds_directly (to, val, direct_init_p).is_false (); +} + /* Categorize various special_function_kinds. */ #define SFK_CTOR_P(sfk) \ ((sfk) >= sfk_constructor && (sfk) <= sfk_move_constructor) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index bf9ea36..4f67441 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -5917,6 +5917,8 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_CONSTRUCTIBLE: case RID_IS_NOTHROW_ASSIGNABLE: case RID_IS_NOTHROW_CONSTRUCTIBLE: + case RID_REF_CONSTRUCTS_FROM_TEMPORARY: + case RID_REF_CONVERTS_FROM_TEMPORARY: return cp_parser_trait_expr (parser, token->keyword); // C++ concepts @@ -10988,6 +10990,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE; variadic = true; break; + case RID_REF_CONSTRUCTS_FROM_TEMPORARY: + kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY; + binary = true; + break; + case RID_REF_CONVERTS_FROM_TEMPORARY: + kind = CPTK_REF_CONVERTS_FROM_TEMPORARY; + binary = true; + break; default: gcc_unreachable (); } @@ -13811,7 +13821,7 @@ warn_for_range_copy (tree decl, tree expr) if (TYPE_REF_P (type)) { - if (glvalue_p (expr) && !ref_conv_binds_directly_p (type, expr)) + if (glvalue_p (expr) && ref_conv_binds_directly (type, expr).is_false ()) { auto_diagnostic_group d; if (warning_at (loc, OPT_Wrange_loop_construct, @@ -13839,20 +13849,20 @@ warn_for_range_copy (tree decl, tree expr) && trivially_copyable_p (type))) return; + /* If we can initialize a reference directly, suggest that to avoid the + copy. */ tree rtype = cp_build_reference_type (type, /*rval*/false); - /* If we could initialize the reference directly, it wouldn't involve any - copies. */ - if (!ref_conv_binds_directly_p (rtype, expr)) - return; - - auto_diagnostic_group d; - if (warning_at (loc, OPT_Wrange_loop_construct, - "loop variable %qD creates a copy from type %qT", - decl, type)) + if (ref_conv_binds_directly (rtype, expr).is_true ()) { - gcc_rich_location richloc (loc); - richloc.add_fixit_insert_before ("&"); - inform (&richloc, "use reference type to prevent copying"); + auto_diagnostic_group d; + if (warning_at (loc, OPT_Wrange_loop_construct, + "loop variable %qD creates a copy from type %qT", + decl, type)) + { + gcc_rich_location richloc (loc); + richloc.add_fixit_insert_before ("&"); + inform (&richloc, "use reference type to prevent copying"); + } } } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 2344b5e..96037c2 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -12007,6 +12007,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_NOTHROW_CONSTRUCTIBLE: return is_nothrow_xible (INIT_EXPR, type1, type2); + case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: + return ref_xes_from_temporary (type1, type2, /*direct_init=*/true); + + case CPTK_REF_CONVERTS_FROM_TEMPORARY: + return ref_xes_from_temporary (type1, type2, /*direct_init=*/false); + default: gcc_unreachable (); return false; @@ -12088,6 +12094,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE: case CPTK_IS_NOTHROW_ASSIGNABLE: case CPTK_IS_NOTHROW_CONSTRUCTIBLE: + case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: + case CPTK_REF_CONVERTS_FROM_TEMPORARY: if (!check_trait_type (type1) || !check_trait_type (type2)) return error_mark_node; diff --git a/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C b/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C new file mode 100644 index 0000000..76de905 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C @@ -0,0 +1,214 @@ +// P2255R2 +// PR c++/104477 +// { dg-do compile { target c++11 } } + +#define SA(X) static_assert((X),#X) + +struct A { A(); }; +struct B { operator A(); }; +struct C { explicit C(); }; +struct D { explicit operator A(); }; +struct E { explicit operator A&(); }; +struct F { explicit operator A&&(); }; +// Could use a class template with explicit(bool), but then this would need +// C++20. +struct G { + operator int(); + explicit operator int&&(); +}; +struct G2 { + explicit operator int(); + operator int&&(); +}; +struct H { + operator int(); + explicit operator int&(); +}; +struct H2 { + explicit operator int(); + operator int&(); +}; + +struct Base { }; +struct Der : Base { }; + +template +struct morph { + mutable T val{}; + operator RT() const { return static_cast(val); } +}; + +template using id = T; + +// Built-in types. +SA(!__reference_constructs_from_temporary(int, int)); +SA(!__reference_constructs_from_temporary(int&, void)); +SA(!__reference_constructs_from_temporary(int&, const void)); +SA(!__reference_constructs_from_temporary(int&, volatile void)); +SA(!__reference_constructs_from_temporary(int&, const volatile void)); +SA(!__reference_constructs_from_temporary(void, void)); +SA(!__reference_constructs_from_temporary(void, int)); +SA(!__reference_constructs_from_temporary(int&, int)); +SA(!__reference_constructs_from_temporary(int&, int&)); +SA(!__reference_constructs_from_temporary(int&, int&&)); +SA(!__reference_constructs_from_temporary(int&, long)); +// non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'long' +SA(!__reference_constructs_from_temporary(int&, long&)); +SA(!__reference_constructs_from_temporary(int&, long&&)); +SA( __reference_constructs_from_temporary(const int&, int)); +SA(!__reference_constructs_from_temporary(const int&, int&)); +SA(!__reference_constructs_from_temporary(const int&, const int&)); +SA(!__reference_constructs_from_temporary(const int&, int&&)); +SA( __reference_constructs_from_temporary(const int&, long)); +SA( __reference_constructs_from_temporary(const int&, long&)); +SA( __reference_constructs_from_temporary(const int&, long&&)); +SA( __reference_constructs_from_temporary(int&&, int)); +SA(!__reference_constructs_from_temporary(int&&, int&)); +SA(!__reference_constructs_from_temporary(int&&, int&&)); +SA( __reference_constructs_from_temporary(int&&, long)); +SA( __reference_constructs_from_temporary(int&&, long&)); +SA( __reference_constructs_from_temporary(int&&, long&&)); +SA(!__reference_constructs_from_temporary(unsigned int&, double)); +SA(!__reference_constructs_from_temporary(volatile int&, int)); +SA(!__reference_constructs_from_temporary(const volatile int&, int)); +SA(!__reference_constructs_from_temporary(volatile int&, int&)); +SA(!__reference_constructs_from_temporary(const volatile int&, int&)); +SA(!__reference_constructs_from_temporary(volatile int&, int&&)); +SA(!__reference_constructs_from_temporary(const volatile int&, int&&)); + +// Classes. +SA(!__reference_constructs_from_temporary(A, A)); +// A& r(A{}); doesn't construct. +SA(!__reference_constructs_from_temporary(A&, A)); +SA(!__reference_constructs_from_temporary(A&, A&)); +SA(!__reference_constructs_from_temporary(A&, A&&)); +// Here we get const struct A & r = (const struct A &) &D.2414; +SA( __reference_constructs_from_temporary(const A&, A)); +SA(!__reference_constructs_from_temporary(const A&, A&)); +SA(!__reference_constructs_from_temporary(const A&, const A&)); +SA(!__reference_constructs_from_temporary(const A&, A&&)); +// Here we get struct A & r = (struct A &) &D.2439; +SA( __reference_constructs_from_temporary(A&&, A)); +SA(!__reference_constructs_from_temporary(A&&, A&)); +SA(!__reference_constructs_from_temporary(A&&, const A&)); +SA(!__reference_constructs_from_temporary(A&&, A&&)); + +SA(!__reference_constructs_from_temporary(A, B)); +SA(!__reference_constructs_from_temporary(A&, B)); +SA(!__reference_constructs_from_temporary(A&, B&)); +SA(!__reference_constructs_from_temporary(A&, const B&)); +SA(!__reference_constructs_from_temporary(A&, B&&)); +SA( __reference_constructs_from_temporary(const A&, B)); +SA( __reference_constructs_from_temporary(const A&, B&)); +// Doesn't construct, so it's false. +SA(!__reference_constructs_from_temporary(const A&, const B&)); +SA( __reference_constructs_from_temporary(const A&, B&&)); +SA( __reference_constructs_from_temporary(A&&, B)); +SA( __reference_constructs_from_temporary(A&&, B&)); +SA(!__reference_constructs_from_temporary(A&&, const B&)); +SA( __reference_constructs_from_temporary(A&&, B&&)); + +SA(!__reference_constructs_from_temporary(const A&, C)); +SA(!__reference_constructs_from_temporary(const A&, C&)); + +// Doesn't construct, so it's false. +SA(!__reference_constructs_from_temporary(int&, morph)); +// Here we get +// const int & r2 = D.2580 = morph::operator int +// (&TARGET_EXPR ); (const int &) &D.2580; +SA( __reference_constructs_from_temporary(const int&, morph)); +SA(!__reference_constructs_from_temporary(int&, morph)); +SA(!__reference_constructs_from_temporary(int&, morph)); +SA(!__reference_constructs_from_temporary(int&, morph)); +SA( __reference_constructs_from_temporary(const int&, morph)); + +// These are like const C& c(cref); so the explicit ctor C isn't a problem +// even in copy-init context. const C& r = {}; would be a different story. +SA(!__reference_constructs_from_temporary(C, C)); +SA(!__reference_constructs_from_temporary(C&, C)); +SA(!__reference_constructs_from_temporary(C&, C&)); +SA(!__reference_constructs_from_temporary(C&, C&&)); +SA( __reference_constructs_from_temporary(const C&, C)); +SA(!__reference_constructs_from_temporary(const C&, C&)); +SA(!__reference_constructs_from_temporary(const C&, const C&)); +SA(!__reference_constructs_from_temporary(const C&, C&&)); +SA( __reference_constructs_from_temporary(C&&, C)); +SA(!__reference_constructs_from_temporary(C&&, C&)); +SA(!__reference_constructs_from_temporary(C&&, const C&)); +SA(!__reference_constructs_from_temporary(C&&, C&&)); + +// These are all false ultimately because of CWG 2267, which we implement. +SA(!__reference_constructs_from_temporary(A, D)); +SA(!__reference_constructs_from_temporary(A&, D)); +SA(!__reference_constructs_from_temporary(A&, D&)); +SA(!__reference_constructs_from_temporary(A&, const D&)); +SA(!__reference_constructs_from_temporary(A&, D&&)); +SA(!__reference_constructs_from_temporary(const A&, D)); +SA(!__reference_constructs_from_temporary(const A&, D&)); +SA(!__reference_constructs_from_temporary(const A&, const D&)); +SA(!__reference_constructs_from_temporary(const A&, D&&)); +SA(!__reference_constructs_from_temporary(A&&, D)); +SA(!__reference_constructs_from_temporary(A&&, D&)); +SA(!__reference_constructs_from_temporary(A&&, const D&)); +SA(!__reference_constructs_from_temporary(A&&, D&&)); + +SA(!__reference_constructs_from_temporary(A, E)); +/* A& a1(E{}); compiles, but A& a2 = E{}; doesn't. + With the former, we get A& a = E::operator A& (&TARGET_EXPR ) + so we're not binding the reference to a temporary, although there is + a temporary involved. So the result is false in both copy- and direct- + init, albeit for different reasons! */ +SA(!__reference_constructs_from_temporary(A&, E)); +// A& a = E::operator A& ((struct E *) r)); copy-init doesn't compile. +SA(!__reference_constructs_from_temporary(A&, E&)); +SA(!__reference_constructs_from_temporary(A&, const E&)); +SA(!__reference_constructs_from_temporary(A&, E&&)); +// direct-init: +// const A& a = (const struct A &) E::operator A& (&TARGET_EXPR ) +SA(!__reference_constructs_from_temporary(const A&, E)); +SA(!__reference_constructs_from_temporary(const A&, E&)); +SA(!__reference_constructs_from_temporary(const A&, const E&)); +SA(!__reference_constructs_from_temporary(const A&, E&&)); +SA(!__reference_constructs_from_temporary(A&&, E)); +SA(!__reference_constructs_from_temporary(A&&, E&)); +SA(!__reference_constructs_from_temporary(A&&, const E&)); +SA(!__reference_constructs_from_temporary(A&&, E&&)); + +SA(!__reference_constructs_from_temporary(A, F)); +// A& a1(F{}); and A& a2 = F{}; both invalid. +SA(!__reference_constructs_from_temporary(A&, F)); +SA(!__reference_constructs_from_temporary(A&, F&)); +SA(!__reference_constructs_from_temporary(A&, const F&)); +SA(!__reference_constructs_from_temporary(A&, F&&)); +SA(!__reference_constructs_from_temporary(const A&, F)); +SA(!__reference_constructs_from_temporary(const A&, F&)); +SA(!__reference_constructs_from_temporary(const A&, const F&)); +SA(!__reference_constructs_from_temporary(const A&, F&&)); +SA(!__reference_constructs_from_temporary(A&&, F)); +SA(!__reference_constructs_from_temporary(A&&, F&)); +SA(!__reference_constructs_from_temporary(A&&, const F&)); +SA(!__reference_constructs_from_temporary(A&&, F&&)); + +/* This is where _converts_ and _constructs_ will differ: + in direct-init we use G::operator int&& (no temporary), + but in copy-init we use G::operator int, where a temporary is created + to be bound to int&&. */ +SA(!__reference_constructs_from_temporary(int&&, G)); +// Similar to the previous one. +SA(!__reference_constructs_from_temporary(const int&, H)); +/* And here I've switched the explicit-ness. In both copy- and direct-init + we call operator int&, so no temporary. */ +SA(!__reference_constructs_from_temporary(int&&, G2)); +SA(!__reference_constructs_from_temporary(const int&, H2)); + +SA(!__reference_constructs_from_temporary(const Base&, Der)); + +// This fails because std::is_constructible_v> is false. +SA(!__reference_constructs_from_temporary(int&&, id)); + +// Arrays. +SA(!__reference_constructs_from_temporary(int, int[])); +SA(!__reference_constructs_from_temporary(int[], int[])); +SA(!__reference_constructs_from_temporary(int&, int[])); +SA(!__reference_constructs_from_temporary(int&&, int[])); +SA(!__reference_constructs_from_temporary(const int&, int[])); diff --git a/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C b/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C new file mode 100644 index 0000000..90196c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C @@ -0,0 +1,214 @@ +// P2255R2 +// PR c++/104477 +// { dg-do compile { target c++11 } } + +#define SA(X) static_assert((X),#X) + +struct A { A(); }; +struct B { operator A(); }; +struct C { explicit C(); }; +struct D { explicit operator A(); }; +struct E { explicit operator A&(); }; +struct F { explicit operator A&&(); }; +// Could use a class template with explicit(bool), but then this would need +// C++20. +struct G { + operator int(); + explicit operator int&&(); +}; +struct G2 { + explicit operator int(); + operator int&&(); +}; +struct H { + operator int(); + explicit operator int&(); +}; +struct H2 { + explicit operator int(); + operator int&(); +}; + +struct Base { }; +struct Der : Base { }; + +template +struct morph { + mutable T val{}; + operator RT() const { return static_cast(val); } +}; + +template using id = T; + +// Built-in types. +SA(!__reference_converts_from_temporary(int, int)); +SA(!__reference_converts_from_temporary(int&, void)); +SA(!__reference_converts_from_temporary(int&, const void)); +SA(!__reference_converts_from_temporary(int&, volatile void)); +SA(!__reference_converts_from_temporary(int&, const volatile void)); +SA(!__reference_converts_from_temporary(void, void)); +SA(!__reference_converts_from_temporary(void, int)); +SA(!__reference_converts_from_temporary(int&, int)); +SA(!__reference_converts_from_temporary(int&, int&)); +SA(!__reference_converts_from_temporary(int&, int&&)); +SA(!__reference_converts_from_temporary(int&, long)); +// non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'long' +SA(!__reference_converts_from_temporary(int&, long&)); +SA(!__reference_converts_from_temporary(int&, long&&)); +SA( __reference_converts_from_temporary(const int&, int)); +SA(!__reference_converts_from_temporary(const int&, int&)); +SA(!__reference_converts_from_temporary(const int&, const int&)); +SA(!__reference_converts_from_temporary(const int&, int&&)); +SA( __reference_converts_from_temporary(const int&, long)); +SA( __reference_converts_from_temporary(const int&, long&)); +SA( __reference_converts_from_temporary(const int&, long&&)); +SA( __reference_converts_from_temporary(int&&, int)); +SA(!__reference_converts_from_temporary(int&&, int&)); +SA(!__reference_converts_from_temporary(int&&, int&&)); +SA( __reference_converts_from_temporary(int&&, long)); +SA( __reference_converts_from_temporary(int&&, long&)); +SA( __reference_converts_from_temporary(int&&, long&&)); +SA(!__reference_converts_from_temporary(unsigned int&, double)); +SA(!__reference_converts_from_temporary(volatile int&, int)); +SA(!__reference_converts_from_temporary(const volatile int&, int)); +SA(!__reference_converts_from_temporary(volatile int&, int&)); +SA(!__reference_converts_from_temporary(const volatile int&, int&)); +SA(!__reference_converts_from_temporary(volatile int&, int&&)); +SA(!__reference_converts_from_temporary(const volatile int&, int&&)); + +// Classes. +SA(!__reference_converts_from_temporary(A, A)); +// A& r(A{}); doesn't construct. +SA(!__reference_converts_from_temporary(A&, A)); +SA(!__reference_converts_from_temporary(A&, A&)); +SA(!__reference_converts_from_temporary(A&, A&&)); +// Here we get const struct A & r = (const struct A &) &D.2414; +SA( __reference_converts_from_temporary(const A&, A)); +SA(!__reference_converts_from_temporary(const A&, A&)); +SA(!__reference_converts_from_temporary(const A&, const A&)); +SA(!__reference_converts_from_temporary(const A&, A&&)); +// Here we get struct A & r = (struct A &) &D.2439; +SA( __reference_converts_from_temporary(A&&, A)); +SA(!__reference_converts_from_temporary(A&&, A&)); +SA(!__reference_converts_from_temporary(A&&, const A&)); +SA(!__reference_converts_from_temporary(A&&, A&&)); + +SA(!__reference_converts_from_temporary(A, B)); +SA(!__reference_converts_from_temporary(A&, B)); +SA(!__reference_converts_from_temporary(A&, B&)); +SA(!__reference_converts_from_temporary(A&, const B&)); +SA(!__reference_converts_from_temporary(A&, B&&)); +SA( __reference_converts_from_temporary(const A&, B)); +SA( __reference_converts_from_temporary(const A&, B&)); +// Doesn't construct, so it's false. +SA(!__reference_converts_from_temporary(const A&, const B&)); +SA( __reference_converts_from_temporary(const A&, B&&)); +SA( __reference_converts_from_temporary(A&&, B)); +SA( __reference_converts_from_temporary(A&&, B&)); +SA(!__reference_converts_from_temporary(A&&, const B&)); +SA( __reference_converts_from_temporary(A&&, B&&)); + +SA(!__reference_converts_from_temporary(const A&, C)); +SA(!__reference_converts_from_temporary(const A&, C&)); + +// Doesn't construct, so it's false. +SA(!__reference_converts_from_temporary(int&, morph)); +// Here we get +// const int & r2 = D.2580 = morph::operator int +// (&TARGET_EXPR ); (const int &) &D.2580; +SA( __reference_converts_from_temporary(const int&, morph)); +SA(!__reference_converts_from_temporary(int&, morph)); +SA(!__reference_converts_from_temporary(int&, morph)); +SA(!__reference_converts_from_temporary(int&, morph)); +SA( __reference_converts_from_temporary(const int&, morph)); + +// These are like const C& c(cref); so the explicit ctor C isn't a problem +// even in copy-init context. const C& r = {}; would be a different story. +SA(!__reference_converts_from_temporary(C, C)); +SA(!__reference_converts_from_temporary(C&, C)); +SA(!__reference_converts_from_temporary(C&, C&)); +SA(!__reference_converts_from_temporary(C&, C&&)); +SA( __reference_converts_from_temporary(const C&, C)); +SA(!__reference_converts_from_temporary(const C&, C&)); +SA(!__reference_converts_from_temporary(const C&, const C&)); +SA(!__reference_converts_from_temporary(const C&, C&&)); +SA( __reference_converts_from_temporary(C&&, C)); +SA(!__reference_converts_from_temporary(C&&, C&)); +SA(!__reference_converts_from_temporary(C&&, const C&)); +SA(!__reference_converts_from_temporary(C&&, C&&)); + +// These are all false ultimately because of CWG 2267, which we implement. +SA(!__reference_converts_from_temporary(A, D)); +SA(!__reference_converts_from_temporary(A&, D)); +SA(!__reference_converts_from_temporary(A&, D&)); +SA(!__reference_converts_from_temporary(A&, const D&)); +SA(!__reference_converts_from_temporary(A&, D&&)); +SA(!__reference_converts_from_temporary(const A&, D)); +SA(!__reference_converts_from_temporary(const A&, D&)); +SA(!__reference_converts_from_temporary(const A&, const D&)); +SA(!__reference_converts_from_temporary(const A&, D&&)); +SA(!__reference_converts_from_temporary(A&&, D)); +SA(!__reference_converts_from_temporary(A&&, D&)); +SA(!__reference_converts_from_temporary(A&&, const D&)); +SA(!__reference_converts_from_temporary(A&&, D&&)); + +SA(!__reference_converts_from_temporary(A, E)); +/* A& a1(E{}); compiles, but A& a2 = E{}; doesn't. + With the former, we get A& a = E::operator A& (&TARGET_EXPR ) + so we're not binding the reference to a temporary, although there is + a temporary involved. So the result is false in both copy- and direct- + init, albeit for different reasons! */ +SA(!__reference_converts_from_temporary(A&, E)); +// A& a = E::operator A& ((struct E *) r)); copy-init doesn't compile. +SA(!__reference_converts_from_temporary(A&, E&)); +SA(!__reference_converts_from_temporary(A&, const E&)); +SA(!__reference_converts_from_temporary(A&, E&&)); +// direct-init: +// const A& a = (const struct A &) E::operator A& (&TARGET_EXPR ) +SA(!__reference_converts_from_temporary(const A&, E)); +SA(!__reference_converts_from_temporary(const A&, E&)); +SA(!__reference_converts_from_temporary(const A&, const E&)); +SA(!__reference_converts_from_temporary(const A&, E&&)); +SA(!__reference_converts_from_temporary(A&&, E)); +SA(!__reference_converts_from_temporary(A&&, E&)); +SA(!__reference_converts_from_temporary(A&&, const E&)); +SA(!__reference_converts_from_temporary(A&&, E&&)); + +SA(!__reference_converts_from_temporary(A, F)); +// A& a1(F{}); and A& a2 = F{}; both invalid. +SA(!__reference_converts_from_temporary(A&, F)); +SA(!__reference_converts_from_temporary(A&, F&)); +SA(!__reference_converts_from_temporary(A&, const F&)); +SA(!__reference_converts_from_temporary(A&, F&&)); +SA(!__reference_converts_from_temporary(const A&, F)); +SA(!__reference_converts_from_temporary(const A&, F&)); +SA(!__reference_converts_from_temporary(const A&, const F&)); +SA(!__reference_converts_from_temporary(const A&, F&&)); +SA(!__reference_converts_from_temporary(A&&, F)); +SA(!__reference_converts_from_temporary(A&&, F&)); +SA(!__reference_converts_from_temporary(A&&, const F&)); +SA(!__reference_converts_from_temporary(A&&, F&&)); + +/* This is where _converts_ and _constructs_ will differ: + in direct-init we use G::operator int&& (no temporary), + but in copy-init we use G::operator int, where a temporary is created + to be bound to int&&. */ +SA( __reference_converts_from_temporary(int&&, G)); +// Similar to the previous one. +SA( __reference_converts_from_temporary(const int&, H)); +/* And here I've switched the explicit-ness. In both copy- and direct-init + we call operator int&, so no temporary. */ +SA(!__reference_converts_from_temporary(int&&, G2)); +SA(!__reference_converts_from_temporary(const int&, H2)); + +SA(!__reference_converts_from_temporary(const Base&, Der)); + +// This fails because std::is_constructible_v> is false. +SA(!__reference_converts_from_temporary(int&&, id)); + +// Arrays. +SA(!__reference_converts_from_temporary(int, int[])); +SA(!__reference_converts_from_temporary(int[], int[])); +SA(!__reference_converts_from_temporary(int&, int[])); +SA(!__reference_converts_from_temporary(int&&, int[])); +SA(!__reference_converts_from_temporary(const int&, int[])); -- cgit v1.1 From 517fb1a78102df43f052c6934c27dd51d786aff7 Mon Sep 17 00:00:00 2001 From: Steve Kargl Date: Fri, 15 Jul 2022 22:07:15 +0200 Subject: Fortran: do not generate conflicting results under -ff2c [PR104313] gcc/fortran/ChangeLog: PR fortran/104313 * trans-decl.cc (gfc_generate_return): Do not generate conflicting fake results for functions with no result variable under -ff2c. gcc/testsuite/ChangeLog: PR fortran/104313 * gfortran.dg/pr104313.f: New test. --- gcc/fortran/trans-decl.cc | 2 +- gcc/testsuite/gfortran.dg/pr104313.f | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/pr104313.f (limited to 'gcc') diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index 6493cc2..908a4c6 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -6474,7 +6474,7 @@ gfc_generate_return (void) NULL_TREE, and a 'return' is generated without a variable. The following generates a 'return __result_XXX' where XXX is the function name. */ - if (sym == sym->result && sym->attr.function) + if (sym == sym->result && sym->attr.function && !flag_f2c) { result = gfc_get_fake_result_decl (sym, 0); result = fold_build2_loc (input_location, MODIFY_EXPR, diff --git a/gcc/testsuite/gfortran.dg/pr104313.f b/gcc/testsuite/gfortran.dg/pr104313.f new file mode 100644 index 0000000..89c8947 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr104313.f @@ -0,0 +1,11 @@ +! { dg-do compile } +! { dg-additional-options "-ff2c -fdump-tree-original" } +! +! PR fortran/104313 - ICE verify_gimple failed with -ff2c +! Contributed by G.Steinmetz + + function f(a) + return + end + +! { dg-final { scan-tree-dump-times "return" 1 "original" } } -- cgit v1.1 From fd3d25d6df1cbd385d2834ff3059dfb6905dd75c Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Fri, 15 Jul 2022 22:48:56 +0100 Subject: PR target/106273: Add earlyclobber to *andn3_doubleword_bmi on x86_64. This patch resolves PR target/106273 which is a wrong code regression caused by the recent reorganization to split doubleword operations after reload on x86. For the failing test case, the constraints on the andnti3_doubleword_bmi pattern allow reload to allocate the output and operand in overlapping but non-identical registers, i.e. (insn 45 44 66 2 (parallel [ (set (reg/v:TI 5 di [orig:96 i ] [96]) (and:TI (not:TI (reg:TI 39 r11 [orig:83 _2 ] [83])) (reg/v:TI 4 si [orig:100 i ] [100]))) (clobber (reg:CC 17 flags)) ]) "pr106273.c":13:5 562 {*andnti3_doubleword_bmi} where the output is in registers 5 and 6, and the second operand is registers 4 and 5, which then leads to the incorrect split: (insn 113 44 114 2 (parallel [ (set (reg:DI 5 di [orig:96 i ] [96]) (and:DI (not:DI (reg:DI 39 r11 [orig:83 _2 ] [83])) (reg:DI 4 si [orig:100 i ] [100]))) (clobber (reg:CC 17 flags)) ]) "pr106273.c":13:5 566 {*andndi_1} (insn 114 113 66 2 (parallel [ (set (reg:DI 6 bp [ i+8 ]) (and:DI (not:DI (reg:DI 40 r12 [ _2+8 ])) (reg:DI 5 di [ i+8 ]))) (clobber (reg:CC 17 flags)) ]) "pr106273.c":13:5 566 {*andndi_1} [Notice that reg:DI 5 is set in the first instruction, but assumed to have its original value in the second]. My first thought was that this could be fixed by swapping the order of the split instructions (which works in this case), but in the general case, it's impossible to handle (set (reg:TI x) (op (reg:TI x+1) (reg:TI x-1)). Hence for correctness this pattern needs an earlyclobber "=&r", but we can also allow cases where the output is the same as one of the operands (using constraint "0"). The other binary logic operations (AND, IOR, XOR) are unaffected as they constrain the output to match the first operand, but BMI's andn is a three-operand instruction which can lead to the overlapping cases described above. 2022-07-15 Roger Sayle gcc/ChangeLog PR target/106273 * config/i386/i386.md (*andn3_doubleword_bmi): Update the constraints to reflect the output is earlyclobber, unless it is the same register (pair) as one of the operands. gcc/testsuite/ChangeLog PR target/106273 * gcc.target/i386/pr106273.c: New test case. --- gcc/config/i386/i386.md | 6 +++--- gcc/testsuite/gcc.target/i386/pr106273.c | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr106273.c (limited to 'gcc') diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index bf29f444..31637bd 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -10423,10 +10423,10 @@ }) (define_insn_and_split "*andn3_doubleword_bmi" - [(set (match_operand: 0 "register_operand" "=r") + [(set (match_operand: 0 "register_operand" "=&r,r,r") (and: - (not: (match_operand: 1 "register_operand" "r")) - (match_operand: 2 "nonimmediate_operand" "ro"))) + (not: (match_operand: 1 "register_operand" "r,0,r")) + (match_operand: 2 "nonimmediate_operand" "ro,ro,0"))) (clobber (reg:CC FLAGS_REG))] "TARGET_BMI" "#" diff --git a/gcc/testsuite/gcc.target/i386/pr106273.c b/gcc/testsuite/gcc.target/i386/pr106273.c new file mode 100644 index 0000000..0f42213 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106273.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-Og -march=cascadelake" } */ +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long long u64; + +u8 g; + +void +foo (__int128 i, u8 *r) +{ + u16 a = __builtin_sub_overflow_p (0, i * g, 0); + i ^= g & i; + u64 s = (i >> 64) + i; + *r = ((union { u16 a; u8 b[2]; }) a).b[1] + s; +} + +int +bar (void) +{ + u8 x; + foo (5, &x); + if (x != 5) + __builtin_abort (); + return 0; +} +/* { dg-final { scan-assembler-not "andn\[ \\t\]+%rdi, %r11, %rdi" } } */ -- cgit v1.1 From 2582080f19e8fe9c1204dfb6fecf744311f00777 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 14 Jul 2022 10:31:21 -0700 Subject: x86: Disable sibcall if indirect_return attribute doesn't match When shadow stack is enabled, function with indirect_return attribute may return via indirect jump. In this case, we need to disable sibcall if caller doesn't have indirect_return attribute and indirect branch tracking is enabled since compiler won't generate ENDBR when calling the caller. gcc/ PR target/85620 * config/i386/i386.cc (ix86_function_ok_for_sibcall): Return false if callee has indirect_return attribute and caller doesn't. gcc/testsuite/ PR target/85620 * gcc.target/i386/pr85620-2.c: Updated. * gcc.target/i386/pr85620-5.c: New test. * gcc.target/i386/pr85620-6.c: Likewise. * gcc.target/i386/pr85620-7.c: Likewise. --- gcc/config/i386/i386.cc | 10 ++++++++++ gcc/testsuite/gcc.target/i386/pr85620-2.c | 3 ++- gcc/testsuite/gcc.target/i386/pr85620-5.c | 13 +++++++++++++ gcc/testsuite/gcc.target/i386/pr85620-6.c | 14 ++++++++++++++ gcc/testsuite/gcc.target/i386/pr85620-7.c | 14 ++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr85620-5.c create mode 100644 gcc/testsuite/gcc.target/i386/pr85620-6.c create mode 100644 gcc/testsuite/gcc.target/i386/pr85620-7.c (limited to 'gcc') diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 3a3c729..e03f86d 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -1024,6 +1024,16 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) return false; } + /* Disable sibcall if callee has indirect_return attribute and + caller doesn't since callee will return to the caller's caller + via an indirect jump. */ + if (((flag_cf_protection & (CF_RETURN | CF_BRANCH)) + == (CF_RETURN | CF_BRANCH)) + && lookup_attribute ("indirect_return", TYPE_ATTRIBUTES (type)) + && !lookup_attribute ("indirect_return", + TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl)))) + return false; + /* Otherwise okay. That also includes certain types of indirect calls. */ return true; } diff --git a/gcc/testsuite/gcc.target/i386/pr85620-2.c b/gcc/testsuite/gcc.target/i386/pr85620-2.c index b2e680f..14ce0ff 100644 --- a/gcc/testsuite/gcc.target/i386/pr85620-2.c +++ b/gcc/testsuite/gcc.target/i386/pr85620-2.c @@ -1,6 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fcf-protection" } */ -/* { dg-final { scan-assembler-times {\mendbr} 1 } } */ +/* { dg-final { scan-assembler-times {\mendbr} 2 } } */ +/* { dg-final { scan-assembler-not "jmp" } } */ struct ucontext; diff --git a/gcc/testsuite/gcc.target/i386/pr85620-5.c b/gcc/testsuite/gcc.target/i386/pr85620-5.c new file mode 100644 index 0000000..0453770 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr85620-5.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcf-protection" } */ +/* { dg-final { scan-assembler-not "jmp" } } */ + +struct ucontext; + +extern int (*bar) (struct ucontext *) __attribute__((__indirect_return__)); + +int +foo (struct ucontext *oucp) +{ + return bar (oucp); +} diff --git a/gcc/testsuite/gcc.target/i386/pr85620-6.c b/gcc/testsuite/gcc.target/i386/pr85620-6.c new file mode 100644 index 0000000..0b6a64e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr85620-6.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcf-protection" } */ +/* { dg-final { scan-assembler "jmp" } } */ + +struct ucontext; + +extern int bar (struct ucontext *) __attribute__((__indirect_return__)); + +__attribute__((__indirect_return__)) +int +foo (struct ucontext *oucp) +{ + return bar (oucp); +} diff --git a/gcc/testsuite/gcc.target/i386/pr85620-7.c b/gcc/testsuite/gcc.target/i386/pr85620-7.c new file mode 100644 index 0000000..fa62d56 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr85620-7.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcf-protection" } */ +/* { dg-final { scan-assembler "jmp" } } */ + +struct ucontext; + +extern int (*bar) (struct ucontext *) __attribute__((__indirect_return__)); +extern int foo (struct ucontext *) __attribute__((__indirect_return__)); + +int +foo (struct ucontext *oucp) +{ + return bar (oucp); +} -- cgit v1.1 From bdc7b765f8728cbb769fe1eeef773eda15578aee Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 16 Jul 2022 00:16:30 +0000 Subject: Daily bump. --- gcc/ChangeLog | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 34 +++++++++++++++ gcc/c-family/ChangeLog | 14 ++++++ gcc/cp/ChangeLog | 25 +++++++++++ gcc/fortran/ChangeLog | 6 +++ gcc/go/ChangeLog | 5 +++ gcc/testsuite/ChangeLog | 49 +++++++++++++++++++++ 8 files changed, 245 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 323b46f..dc8d2e7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,114 @@ +2022-07-15 H.J. Lu + + PR target/85620 + * config/i386/i386.cc (ix86_function_ok_for_sibcall): Return + false if callee has indirect_return attribute and caller + doesn't. + +2022-07-15 Roger Sayle + + PR target/106273 + * config/i386/i386.md (*andn3_doubleword_bmi): Update the + constraints to reflect the output is earlyclobber, unless it is + the same register (pair) as one of the operands. + +2022-07-15 David Malcolm + + * doc/invoke.texi (Static Analyzer Options): Add the new fd + warnings to the initial gccoptlist, and to the list of those + disabled by -fanalyzer-checker=taint. + +2022-07-15 Andrew Carlotti + + * config/aarch64/aarch64-builtins.cc + (enum aarch64_type_qualifiers): Remove qualifier_internal. + (aarch64_init_simd_builtin_functions): Remove qualifier_internal check. + +2022-07-15 Andrew Carlotti + + * config/aarch64/aarch64-builtins.cc + (v1di_UP): Add V1DI mode to _UP macros. + * config/aarch64/aarch64-modes.def (VECTOR_MODE): Add V1DI mode. + * config/aarch64/aarch64-simd-builtin-types.def: Use V1DI mode. + * config/aarch64/aarch64-simd.md + (vec_extractv2dfv1df): Replace with... + (vec_extract): ...this. + * config/aarch64/aarch64.cc + (aarch64_classify_vector_mode): Add V1DI mode. + * config/aarch64/iterators.md + (VQ_2E, V1HALF, V1half): New. + (nunits): Add V1DI mode. + +2022-07-15 Roger Sayle + + PR target/106278 + * config/i386/i386-features.cc (general_scalar_chain::convert_insn): + Fix indentation whitespace. + (timode_scalar_chain::fix_debug_reg_uses): Likewise. + (timode_scalar_chain::convert_insn): Delete dead code. + Update TImode REG_EQUAL_NOTE even if the SET_DEST is already V1TI. + Fix indentation whitespace. + (convertible_comparison_p): Likewise. + (timode_scalar_to_vector_candidate_p): Likewise. + +2022-07-15 Aldy Hernandez + + * gimple-pretty-print.cc (dump_ssaname_info): Use pp_vrange. + +2022-07-15 Aldy Hernandez + + * Makefile.in (OBJS): Add value-range-pretty-print.o. + * pretty-print.h (pp_vrange): New. + * value-range.cc (vrange::dump): Call pp version. + (unsupported_range::dump): Move to its own file. + (dump_bound_with_infinite_markers): Same. + (irange::dump): Same. + (irange::dump_bitmasks): Same. + (vrange::debug): Remove. + * value-range.h: Remove virtual designation for dump methods. + Remove dump_bitmasks method. + * value-range-pretty-print.cc: New file. + * value-range-pretty-print.h: New file. + +2022-07-15 Aldy Hernandez + + * value-range.cc (irange::accept): New. + (unsupported_range::accept): New. + * value-range.h (class vrange_visitor): New. + (class vrange): Add accept method. + (class unsupported_range): Same. + (class Value_Range): Same. + +2022-07-15 Jonathan Wakely + + * diagnostic-format-json.cc (json_from_location_range): Adjust + to new label_text API. + * diagnostic-format-sarif.cc (sarif_builder::make_location_object): + Likewise. + * diagnostic-show-locus.cc (struct pod_label_text): Likewise. + (layout::print_any_labels): Likewise. + * tree-diagnostic-path.cc (class path_label): Likewise. + (struct event_range): Likewise. + (default_tree_diagnostic_path_printer): Likewise. + (default_tree_make_json_for_path): Likewise. + +2022-07-15 konglin1 + + PR target/106113 + * config/i386/i386-builtin.def (BDESC): Fix [u]comi{ss,sd} + comparison due to intrinsics changed over time. + * config/i386/i386-expand.cc (ix86_ssecom_setcc): + Add unordered check and mode for sse comi codegen. + (ix86_expand_sse_comi): Add unordered check and check a different + CCmode. + (ix86_expand_sse_comi_round):Extract unordered check and mode part + in ix86_ssecom_setcc. + +2022-07-15 Prathamesh Kulkarni + + * config/aarch64/aarch64.cc (aarch64_vectorize_vec_perm_const): Use + op_mode instead of vmode in calls to force_reg for op0 and op1. + 2022-07-14 H.J. Lu PR tree-optimization/103798 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 5d08726..cedfb43 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220715 +20220716 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 06d8454..4f010eb 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,37 @@ +2022-07-15 David Malcolm + + PR analyzer/106284 + * sm-taint.cc (taint_state_machine::on_condition): Handle range + checks optimized by build_range_check. + +2022-07-15 Jonathan Wakely + + * call-info.cc (call_info::print): Adjust to new label_text API. + * checker-path.cc (checker_event::dump): Likewise. + (region_creation_event::get_desc): Likewise. + (state_change_event::get_desc): Likewise. + (superedge_event::should_filter_p): Likewise. + (start_cfg_edge_event::get_desc): Likewise. + (call_event::get_desc): Likewise. + (return_event::get_desc): Likewise. + (warning_event::get_desc): Likewise. + (checker_path::dump): Likewise. + (checker_path::debug): Likewise. + * diagnostic-manager.cc (diagnostic_manager::prune_for_sm_diagnostic): + Likewise. + (diagnostic_manager::prune_interproc_events): Likewise. + * engine.cc (feasibility_state::maybe_update_for_edge): + Likewise. + * program-state.cc (sm_state_map::to_json): Likewise. + * region-model-impl-calls.cc (region_model::impl_call_analyzer_describe): Likewise. + (region_model::impl_call_analyzer_dump_capacity): Likewise. + * region.cc (region::to_json): Likewise. + * sm-malloc.cc (inform_nonnull_attribute): Likewise. + * store.cc (binding_map::to_json): Likewise. + (store::to_json): Likewise. + * supergraph.cc (superedge::dump): Likewise. + * svalue.cc (svalue::to_json): Likewise. + 2022-07-07 David Malcolm * checker-path.cc (start_cfg_edge_event::get_desc): Update for diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index d46eb18..ade553f 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,17 @@ +2022-07-15 Marek Polacek + + PR c++/104477 + * c-common.cc (c_common_reswords): Add + __reference_constructs_from_temporary and + __reference_converts_from_temporary. + * c-common.h (enum rid): Add RID_REF_CONSTRUCTS_FROM_TEMPORARY and + RID_REF_CONVERTS_FROM_TEMPORARY. + +2022-07-15 Jonathan Wakely + + * c-format.cc (class range_label_for_format_type_mismatch): + Adjust to new label_text API. + 2022-07-11 Lewis Hyatt PR preprocessor/106252 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index aa317e8..ce6f8ea 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2022-07-15 Marek Polacek + + PR c++/104477 + * call.cc (ref_conv_binds_directly_p): Rename to ... + (ref_conv_binds_directly): ... this. Add a new bool parameter. Change + the return type to tristate. + * constraint.cc (diagnose_trait_expr): Handle + CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY. + * cp-tree.h: Include "tristate.h". + (enum cp_trait_kind): Add CPTK_REF_CONSTRUCTS_FROM_TEMPORARY + and CPTK_REF_CONVERTS_FROM_TEMPORARY. + (ref_conv_binds_directly_p): Rename to ... + (ref_conv_binds_directly): ... this. + (ref_xes_from_temporary): Declare. + * cxx-pretty-print.cc (pp_cxx_trait_expression): Handle + CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY. + * method.cc (ref_xes_from_temporary): New. + * parser.cc (cp_parser_primary_expression): Handle + RID_REF_CONSTRUCTS_FROM_TEMPORARY and RID_REF_CONVERTS_FROM_TEMPORARY. + (cp_parser_trait_expr): Likewise. + (warn_for_range_copy): Adjust to call ref_conv_binds_directly. + * semantics.cc (trait_expr_value): Handle + CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY. + (finish_trait_expr): Likewise. + 2022-07-13 Patrick Palka PR c++/105912 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f02b65f..cfe1e6d 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2022-07-15 Steve Kargl + + PR fortran/104313 + * trans-decl.cc (gfc_generate_return): Do not generate conflicting + fake results for functions with no result variable under -ff2c. + 2022-07-14 Harald Anlauf Steven G. Kargl diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 5fdf423..6ad883f 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +2022-07-15 Ian Lance Taylor + + * go-gcc.cc (Gcc_backend::call_expression): Handle a void + argument, as for f(g()) where g returns a zero-sized type. + 2022-06-02 David Malcolm * go-lang.cc (go_get_sarif_source_language): New. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cfdf646..cc8ea71 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,52 @@ +2022-07-15 H.J. Lu + + PR target/85620 + * gcc.target/i386/pr85620-2.c: Updated. + * gcc.target/i386/pr85620-5.c: New test. + * gcc.target/i386/pr85620-6.c: Likewise. + * gcc.target/i386/pr85620-7.c: Likewise. + +2022-07-15 Roger Sayle + + PR target/106273 + * gcc.target/i386/pr106273.c: New test case. + +2022-07-15 Steve Kargl + + PR fortran/104313 + * gfortran.dg/pr104313.f: New test. + +2022-07-15 Marek Polacek + + PR c++/104477 + * g++.dg/ext/reference_constructs_from_temporary1.C: New test. + * g++.dg/ext/reference_converts_from_temporary1.C: New test. + +2022-07-15 David Malcolm + + PR analyzer/106284 + * gcc.dg/analyzer/torture/taint-read-index-2.c: New test. + +2022-07-15 Roger Sayle + + * gcc.dg/pr106278.c: New test case. + +2022-07-15 konglin1 + + PR target/106113 + * gcc.target/i386/avx-vcomisd-pr106113-2.c: New test. + * gcc.target/i386/avx-vcomiss-pr106113-2.c: Ditto. + * gcc.target/i386/avx-vucomisd-pr106113-2.c: Ditto. + * gcc.target/i386/avx-vucomiss-pr106113-2.c: Ditto. + * gcc.target/i386/sse-comiss-pr106113-1.c: Ditto. + * gcc.target/i386/sse-comiss-pr106113-2.c: Ditto. + * gcc.target/i386/sse-ucomiss-pr106113-1.c: Ditto. + * gcc.target/i386/sse-ucomiss-pr106113-2.c: Ditto. + * gcc.target/i386/sse2-comisd-pr106113-1.c: Ditto. + * gcc.target/i386/sse2-comisd-pr106113-2.c: Ditto. + * gcc.target/i386/sse2-ucomisd-pr106113-1.c: Ditto. + * gcc.target/i386/sse2-ucomisd-pr106113-2.c: Ditto. + 2022-07-14 H.J. Lu PR tree-optimization/103798 -- cgit v1.1 From 1884f8978237b15013576a720bcb32e7c5647574 Mon Sep 17 00:00:00 2001 From: Takayuki 'January June' Suwa Date: Fri, 15 Jul 2022 19:50:52 +0900 Subject: xtensa: constantsynth: Make try to find shorter instruction This patch allows the constant synthesis to choose shorter instruction if possible. /* example */ int test(void) { return 128 << 8; } ;; before test: movi a2, 0x100 addmi a2, a2, 0x7f00 ret.n ;; after test: movi.n a2, 1 slli a2, a2, 15 ret.n When the Code Density Option is configured, the latter is one byte smaller than the former. gcc/ChangeLog: * config/xtensa/xtensa.cc (xtensa_emit_constantsynth): Remove. (xtensa_constantsynth_2insn): Change to try all three synthetic methods and to use the one that fits the immediate value of the seed into a Narrow Move Immediate instruction "MOVI.N" when the Code Density Option is configured. --- gcc/config/xtensa/xtensa.cc | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'gcc') diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 13f2b2b..9433745 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -1035,35 +1035,35 @@ xtensa_split_operand_pair (rtx operands[4], machine_mode mode) load-immediate / arithmetic ones, instead of a L32R instruction (plus a constant in litpool). */ -static void -xtensa_emit_constantsynth (rtx dst, enum rtx_code code, - HOST_WIDE_INT imm0, HOST_WIDE_INT imm1, - rtx (*gen_op)(rtx, HOST_WIDE_INT), - HOST_WIDE_INT imm2) -{ - gcc_assert (REG_P (dst)); - emit_move_insn (dst, GEN_INT (imm0)); - emit_move_insn (dst, gen_rtx_fmt_ee (code, SImode, - dst, GEN_INT (imm1))); - if (gen_op) - emit_move_insn (dst, gen_op (dst, imm2)); -} - static int xtensa_constantsynth_2insn (rtx dst, HOST_WIDE_INT srcval, rtx (*gen_op)(rtx, HOST_WIDE_INT), HOST_WIDE_INT op_imm) { - int shift = exact_log2 (srcval + 1); + HOST_WIDE_INT imm = INT_MAX; + rtx x = NULL_RTX; + int shift; + gcc_assert (REG_P (dst)); + + shift = exact_log2 (srcval + 1); if (IN_RANGE (shift, 1, 31)) { - xtensa_emit_constantsynth (dst, LSHIFTRT, -1, 32 - shift, - gen_op, op_imm); - return 1; + imm = -1; + x = gen_lshrsi3 (dst, dst, GEN_INT (32 - shift)); } - if (IN_RANGE (srcval, (-2048 - 32768), (2047 + 32512))) + + shift = ctz_hwi (srcval); + if ((!x || (TARGET_DENSITY && ! IN_RANGE (imm, -32, 95))) + && xtensa_simm12b (srcval >> shift)) + { + imm = srcval >> shift; + x = gen_ashlsi3 (dst, dst, GEN_INT (shift)); + } + + if ((!x || (TARGET_DENSITY && ! IN_RANGE (imm, -32, 95))) + && IN_RANGE (srcval, (-2048 - 32768), (2047 + 32512))) { HOST_WIDE_INT imm0, imm1; @@ -1076,19 +1076,19 @@ xtensa_constantsynth_2insn (rtx dst, HOST_WIDE_INT srcval, imm0 = srcval - imm1; if (TARGET_DENSITY && imm1 < 32512 && IN_RANGE (imm0, 224, 255)) imm0 -= 256, imm1 += 256; - xtensa_emit_constantsynth (dst, PLUS, imm0, imm1, gen_op, op_imm); - return 1; + imm = imm0; + x = gen_addsi3 (dst, dst, GEN_INT (imm1)); } - shift = ctz_hwi (srcval); - if (xtensa_simm12b (srcval >> shift)) - { - xtensa_emit_constantsynth (dst, ASHIFT, srcval >> shift, shift, - gen_op, op_imm); - return 1; - } + if (!x) + return 0; - return 0; + emit_move_insn (dst, GEN_INT (imm)); + emit_insn (x); + if (gen_op) + emit_move_insn (dst, gen_op (dst, op_imm)); + + return 1; } static rtx -- cgit v1.1 From d6d8e6a7e1379f9dfdf2f39efcc82d9185cca6d0 Mon Sep 17 00:00:00 2001 From: Takayuki 'January June' Suwa Date: Fri, 15 Jul 2022 19:51:40 +0900 Subject: xtensa: Optimize "bitwise AND with imm1" followed by "branch if (not) equal to imm2" This patch enhances the effectiveness of the previously posted one: "xtensa: Optimize bitwise AND operation with some specific forms of constants". /* example */ extern void foo(int); void test(int a) { if ((a & (-1U << 8)) == (128 << 8)) /* 0 or one of "b4const" */ foo(a); } ;; before .global test test: movi a3, -0x100 movi.n a4, 1 and a3, a2, a3 slli a4, a4, 15 bne a3, a4, .L3 j.l foo, a9 .L1: ret.n ;; after .global test test: srli a3, a2, 8 bnei a3, 128, .L1 j.l foo, a9 .L1: ret.n gcc/ChangeLog: * config/xtensa/xtensa.md (*masktrue_const_pow2_minus_one, *masktrue_const_negative_pow2, *masktrue_const_shifted_mask): If the immediate for bitwise AND is represented as '-(1 << N)', decrease the lower bound of N from 12 to 1. And the other immediate for conditional branch is now no longer limited to zero, but also one of some positive integers. Finally, remove the checks of some conditions, because the comparison expressions that don't satisfy such checks are determined as compile-time constants and thus will be optimized away before RTL expansion. --- gcc/config/xtensa/xtensa.md | 73 +++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 29 deletions(-) (limited to 'gcc') diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 6a58d3e..c02f1a5 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -1716,63 +1716,78 @@ (define_insn_and_split "*masktrue_const_pow2_minus_one" [(set (pc) - (if_then_else (match_operator 3 "boolean_operator" + (if_then_else (match_operator 4 "boolean_operator" [(and:SI (match_operand:SI 0 "register_operand" "r") (match_operand:SI 1 "const_int_operand" "i")) - (const_int 0)]) - (label_ref (match_operand 2 "" "")) + (match_operand:SI 2 "const_int_operand" "i")]) + (label_ref (match_operand 3 "" "")) (pc)))] - "IN_RANGE (exact_log2 (INTVAL (operands[1]) + 1), 17, 31)" + "IN_RANGE (exact_log2 (INTVAL (operands[1]) + 1), 17, 31) + /* && (~INTVAL (operands[1]) & INTVAL (operands[2])) == 0 // can be omitted */ + && xtensa_b4const_or_zero (INTVAL (operands[2]) << (32 - floor_log2 (INTVAL (operands[1]) + 1)))" "#" "&& can_create_pseudo_p ()" - [(set (match_dup 4) + [(set (match_dup 5) (ashift:SI (match_dup 0) (match_dup 1))) (set (pc) - (if_then_else (match_op_dup 3 - [(match_dup 4) - (const_int 0)]) - (label_ref (match_dup 2)) + (if_then_else (match_op_dup 4 + [(match_dup 5) + (match_dup 2)]) + (label_ref (match_dup 3)) (pc)))] { - operands[1] = GEN_INT (32 - floor_log2 (INTVAL (operands[1]) + 1)); - operands[4] = gen_reg_rtx (SImode); + int shift = 32 - floor_log2 (INTVAL (operands[1]) + 1); + operands[1] = GEN_INT (shift); + operands[2] = GEN_INT (INTVAL (operands[2]) << shift); + operands[5] = gen_reg_rtx (SImode); } [(set_attr "type" "jump") (set_attr "mode" "none") (set (attr "length") - (if_then_else (match_test "TARGET_DENSITY - && INTVAL (operands[1]) == 0x7FFFFFFF") - (const_int 5) - (const_int 6)))]) + (if_then_else (match_test "(TARGET_DENSITY && INTVAL (operands[1]) == 0x7FFFFFFF) + && INTVAL (operands[2]) == 0") + (const_int 4) + (if_then_else (match_test "TARGET_DENSITY + && (INTVAL (operands[1]) == 0x7FFFFFFF + || INTVAL (operands[2]) == 0)") + (const_int 5) + (const_int 6))))]) (define_insn_and_split "*masktrue_const_negative_pow2" [(set (pc) - (if_then_else (match_operator 3 "boolean_operator" + (if_then_else (match_operator 4 "boolean_operator" [(and:SI (match_operand:SI 0 "register_operand" "r") (match_operand:SI 1 "const_int_operand" "i")) - (const_int 0)]) - (label_ref (match_operand 2 "" "")) + (match_operand:SI 2 "const_int_operand" "i")]) + (label_ref (match_operand 3 "" "")) (pc)))] - "IN_RANGE (exact_log2 (-INTVAL (operands[1])), 12, 30)" + "IN_RANGE (exact_log2 (-INTVAL (operands[1])), 1, 30) + /* && (~INTVAL (operands[1]) & INTVAL (operands[2])) == 0 // can be omitted */ + && xtensa_b4const_or_zero (INTVAL (operands[2]) >> floor_log2 (-INTVAL (operands[1])))" "#" "&& can_create_pseudo_p ()" - [(set (match_dup 4) + [(set (match_dup 5) (lshiftrt:SI (match_dup 0) (match_dup 1))) (set (pc) - (if_then_else (match_op_dup 3 - [(match_dup 4) - (const_int 0)]) - (label_ref (match_dup 2)) + (if_then_else (match_op_dup 4 + [(match_dup 5) + (match_dup 2)]) + (label_ref (match_dup 3)) (pc)))] { - operands[1] = GEN_INT (floor_log2 (-INTVAL (operands[1]))); - operands[4] = gen_reg_rtx (SImode); + int shift = floor_log2 (-INTVAL (operands[1])); + operands[1] = GEN_INT (shift); + operands[2] = GEN_INT (INTVAL (operands[2]) >> shift); + operands[5] = gen_reg_rtx (SImode); } [(set_attr "type" "jump") (set_attr "mode" "none") - (set_attr "length" "6")]) + (set (attr "length") + (if_then_else (match_test "TARGET_DENSITY && INTVAL (operands[2]) == 0") + (const_int 5) + (const_int 6)))]) (define_insn_and_split "*masktrue_const_shifted_mask" [(set (pc) @@ -1782,8 +1797,8 @@ (match_operand:SI 2 "const_int_operand" "i")]) (label_ref (match_operand 3 "" "")) (pc)))] - "(INTVAL (operands[2]) & ((1 << ctz_hwi (INTVAL (operands[1]))) - 1)) == 0 - && xtensa_b4const_or_zero ((uint32_t)INTVAL (operands[2]) >> ctz_hwi (INTVAL (operands[1])))" + "/* (INTVAL (operands[2]) & ((1 << ctz_hwi (INTVAL (operands[1]))) - 1)) == 0 // can be omitted + && */ xtensa_b4const_or_zero ((uint32_t)INTVAL (operands[2]) >> ctz_hwi (INTVAL (operands[1])))" "#" "&& can_create_pseudo_p ()" [(set (match_dup 6) -- cgit v1.1 From 2b5baaef0b6e4d1d8e36cda091be26649163ffdb Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 16 Jul 2022 16:29:38 -0700 Subject: go: fix f().x where f returns zero-sized type Test case is https://go.dev/cl/417874. Fixes golang/go#23870 * go-gcc.cc (Gcc_backend::struct_field_expression): Handle a void expression, as for f().x where f returns a zero-sized type. --- gcc/go/go-gcc.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gcc') diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 7b4b2ad..1ba7206 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -1707,6 +1707,13 @@ Gcc_backend::struct_field_expression(Bexpression* bstruct, size_t index, if (struct_tree == error_mark_node || TREE_TYPE(struct_tree) == error_mark_node) return this->error_expression(); + + // A function call that returns a zero-sized object will have been + // changed to return void. A zero-sized object can have a + // (zero-sized) field, so support that case. + if (TREE_TYPE(struct_tree) == void_type_node) + return bstruct; + gcc_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE); tree field = TYPE_FIELDS(TREE_TYPE(struct_tree)); if (field == NULL_TREE) -- cgit v1.1 From 7bcd7f47359b903bf7a193b95d4450d9d69c60ba Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 17 Jul 2022 00:16:23 +0000 Subject: Daily bump. --- gcc/ChangeLog | 21 +++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/go/ChangeLog | 5 +++++ 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dc8d2e7..994875f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2022-07-16 Takayuki 'January June' Suwa + + * config/xtensa/xtensa.md + (*masktrue_const_pow2_minus_one, *masktrue_const_negative_pow2, + *masktrue_const_shifted_mask): If the immediate for bitwise AND is + represented as '-(1 << N)', decrease the lower bound of N from 12 + to 1. And the other immediate for conditional branch is now no + longer limited to zero, but also one of some positive integers. + Finally, remove the checks of some conditions, because the comparison + expressions that don't satisfy such checks are determined as + compile-time constants and thus will be optimized away before + RTL expansion. + +2022-07-16 Takayuki 'January June' Suwa + + * config/xtensa/xtensa.cc (xtensa_emit_constantsynth): Remove. + (xtensa_constantsynth_2insn): Change to try all three synthetic + methods and to use the one that fits the immediate value of + the seed into a Narrow Move Immediate instruction "MOVI.N" + when the Code Density Option is configured. + 2022-07-15 H.J. Lu PR target/85620 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index cedfb43..19c3fb7 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220716 +20220717 diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 6ad883f..5dbcb29 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +2022-07-16 Ian Lance Taylor + + * go-gcc.cc (Gcc_backend::struct_field_expression): Handle a void + expression, as for f().x where f returns a zero-sized type. + 2022-07-15 Ian Lance Taylor * go-gcc.cc (Gcc_backend::call_expression): Handle a void -- cgit v1.1 From 6d7071776e039d9eedf468636dcd942cb4621199 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 18 Jul 2022 00:16:24 +0000 Subject: Daily bump. --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 19c3fb7..2ac5479 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220717 +20220718 -- cgit v1.1 From f9da2663f500f473f6ae309e3349a65e6f02001b Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Mon, 18 Jul 2022 07:36:13 +0100 Subject: Add UNSPEC_MASKOP to kupck instructions in sse.md on x86. This AVX512 specific patch to sse.md is split out from an earlier patch: https://gcc.gnu.org/pipermail/gcc-patches/2022-June/596199.html The new splitters proposed in that patch interfere with AVX512's kunpckdq instruction which is defined as identical RTL, DW:DI = (HI:SI<<32)|zero_extend(LO:SI). To distinguish these, and avoid AVX512 mask registers accidentally being (ab)used by reload to perform SImode scalar shifts, this patch adds the explicit (unspec UNSPEC_MASKOP) to the unpack mask operations, which matches what sse.md does for the other mask specific (logic) operations. 2022-07-18 Roger Sayle gcc/ChangeLog * config/i386/sse.md (kunpckhi): Add UNSPEC_MASKOP unspec. (kunpcksi): Likewise, add UNSPEC_MASKOP unspec. (kunpckdi): Likewise, add UNSPEC_MASKOP unspec. (vec_pack_trunc_qi): Update to specify the now required UNSPEC_MASKOP unspec. (vec_pack_trunc_): Likewise. --- gcc/config/i386/sse.md | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index a755d72..14d12d1 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -2068,7 +2068,8 @@ (ashift:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "k")) (const_int 8)) - (zero_extend:HI (match_operand:QI 2 "register_operand" "k"))))] + (zero_extend:HI (match_operand:QI 2 "register_operand" "k")))) + (unspec [(const_int 0)] UNSPEC_MASKOP)] "TARGET_AVX512F" "kunpckbw\t{%2, %1, %0|%0, %1, %2}" [(set_attr "mode" "HI") @@ -2081,7 +2082,8 @@ (ashift:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "k")) (const_int 16)) - (zero_extend:SI (match_operand:HI 2 "register_operand" "k"))))] + (zero_extend:SI (match_operand:HI 2 "register_operand" "k")))) + (unspec [(const_int 0)] UNSPEC_MASKOP)] "TARGET_AVX512BW" "kunpckwd\t{%2, %1, %0|%0, %1, %2}" [(set_attr "mode" "SI")]) @@ -2092,7 +2094,8 @@ (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "k")) (const_int 32)) - (zero_extend:DI (match_operand:SI 2 "register_operand" "k"))))] + (zero_extend:DI (match_operand:SI 2 "register_operand" "k")))) + (unspec [(const_int 0)] UNSPEC_MASKOP)] "TARGET_AVX512BW" "kunpckdq\t{%2, %1, %0|%0, %1, %2}" [(set_attr "mode" "DI")]) @@ -17419,21 +17422,26 @@ }) (define_expand "vec_pack_trunc_qi" - [(set (match_operand:HI 0 "register_operand") - (ior:HI (ashift:HI (zero_extend:HI (match_operand:QI 2 "register_operand")) - (const_int 8)) - (zero_extend:HI (match_operand:QI 1 "register_operand"))))] + [(parallel + [(set (match_operand:HI 0 "register_operand") + (ior:HI + (ashift:HI (zero_extend:HI (match_operand:QI 2 "register_operand")) + (const_int 8)) + (zero_extend:HI (match_operand:QI 1 "register_operand")))) + (unspec [(const_int 0)] UNSPEC_MASKOP)])] "TARGET_AVX512F") (define_expand "vec_pack_trunc_" - [(set (match_operand: 0 "register_operand") - (ior: - (ashift: + [(parallel + [(set (match_operand: 0 "register_operand") + (ior: + (ashift: + (zero_extend: + (match_operand:SWI24 2 "register_operand")) + (match_dup 3)) (zero_extend: - (match_operand:SWI24 2 "register_operand")) - (match_dup 3)) - (zero_extend: - (match_operand:SWI24 1 "register_operand"))))] + (match_operand:SWI24 1 "register_operand")))) + (unspec [(const_int 0)] UNSPEC_MASKOP)])] "TARGET_AVX512BW" { operands[3] = GEN_INT (GET_MODE_BITSIZE (mode)); -- cgit v1.1 From 43c2505b31adfdef2214318484aaae987fd9e1e0 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Mon, 18 Jul 2022 07:41:36 +0100 Subject: Fix issue with x86_64_const_vector_operand predicate on x86. This patch fixes (what I believe is) a latent bug in i386.md's x86_64_const_vector_operand define_predicate. According to the documentation, when a predicate is called with rtx operand OP and machine_mode operand MODE, we can't shouldn't assume that the MODE is (or has been checked to be) GET_MODE (OP). The failure mode is that recog can call x86_64_const_vector_operand on an arbitrary CONST_VECTOR passing a MODE of V2QI_mode, but when the CONST_VECTOR is in fact V1TImode, it's unsafe to directly call ix86_convert_const_vector_to_integer, which assumes that the CONST_VECTOR contains CONST_INTs when it actually contains CONST_WIDE_INTs. The checks in this define_predicate need to be testing OP's mode, and ideally confirming that this matches the passed in/specified MODE. This bug is currently latent, but adding an innocent/unrelated define_insn, such as "(set (reg:CCC FLAGS_REG) (const_int 0))" to i386.md can occasionally change the order in which genrecog generates its tests, then ICEing during bootstrap due to V1TI CONST_VECTORs. 2022-07-18 Roger Sayle gcc/ChangeLog * config/i386/predicates.md (x86_64_const_vector_operand): Check the operand's mode matches the specified mode argument. --- gcc/config/i386/predicates.md | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc') diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index c71c453..42053ea 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1199,6 +1199,10 @@ (define_predicate "x86_64_const_vector_operand" (match_code "const_vector") { + if (mode == VOIDmode) + mode = GET_MODE (op); + else if (GET_MODE (op) != mode) + return false; if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) return false; HOST_WIDE_INT val = ix86_convert_const_vector_to_integer (op, mode); -- cgit v1.1 From 2907bfc3412dd8aef6c6acc17f2152a4e0ac4979 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Mon, 18 Jul 2022 07:44:38 +0100 Subject: PR target/106231: Optimize (any_extend:DI (ctz:SI ...)) on x86_64. This patch resolves PR target/106231 by providing insns that recognize (zero_extend:DI (ctz:SI ...)) and (sign_extend:DI (ctz:SI ...)). The result of ctz:SI is always between 0 and 32 (or undefined), so sign_extension is the same as zero_extension, and the result is already extended in the destination register. Things are a little complicated, because the existing implementation of *ctzsi2 handles multiple cases, including false dependencies, which we continue to support in this patch. 2022-07-18 Roger Sayle gcc/ChangeLog PR target/106231 * config/i386/i386.md (*ctzsidi2_ext): New insn_and_split to recognize any_extend:DI of ctz:SI which is implicitly extended. (*ctzsidi2_ext_falsedep): New define_insn to model a DImode extended ctz:SI that has preceding xor to break false dependency. gcc/testsuite/ChangeLog PR target/106231 * gcc.target/i386/pr106231-1.c: New test case. * gcc.target/i386/pr106231-2.c: New test case. --- gcc/config/i386/i386.md | 60 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr106231-1.c | 8 ++++ gcc/testsuite/gcc.target/i386/pr106231-2.c | 8 ++++ 3 files changed, 76 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr106231-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr106231-2.c (limited to 'gcc') diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 31637bd..9aaeb69 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -16431,6 +16431,66 @@ (set_attr "prefix_rep" "1") (set_attr "mode" "SI")]) +(define_insn_and_split "*ctzsidi2_ext" + [(set (match_operand:DI 0 "register_operand" "=r") + (any_extend:DI + (ctz:SI + (match_operand:SI 1 "nonimmediate_operand" "rm")))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT" +{ + if (TARGET_BMI) + return "tzcnt{l}\t{%1, %k0|%k0, %1}"; + else if (TARGET_CPU_P (GENERIC) + && !optimize_function_for_size_p (cfun)) + /* tzcnt expands to 'rep bsf' and we can use it even if !TARGET_BMI. */ + return "rep%; bsf{l}\t{%1, %k0|%k0, %1}"; + return "bsf{l}\t{%1, %k0|%k0, %1}"; +} + "(TARGET_BMI || TARGET_CPU_P (GENERIC)) + && TARGET_AVOID_FALSE_DEP_FOR_BMI && epilogue_completed + && optimize_function_for_speed_p (cfun) + && !reg_mentioned_p (operands[0], operands[1])" + [(parallel + [(set (match_dup 0) + (any_extend:DI (ctz:SI (match_dup 1)))) + (unspec [(match_dup 0)] UNSPEC_INSN_FALSE_DEP) + (clobber (reg:CC FLAGS_REG))])] + "ix86_expand_clear (operands[0]);" + [(set_attr "type" "alu1") + (set_attr "prefix_0f" "1") + (set (attr "prefix_rep") + (if_then_else + (ior (match_test "TARGET_BMI") + (and (not (match_test "optimize_function_for_size_p (cfun)")) + (match_test "TARGET_CPU_P (GENERIC)"))) + (const_string "1") + (const_string "0"))) + (set_attr "mode" "SI")]) + +(define_insn "*ctzsidi2_ext_falsedep" + [(set (match_operand:DI 0 "register_operand" "=r") + (any_extend:DI + (ctz:SI + (match_operand:SI 1 "nonimmediate_operand" "rm")))) + (unspec [(match_operand:DI 2 "register_operand" "0")] + UNSPEC_INSN_FALSE_DEP) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT" +{ + if (TARGET_BMI) + return "tzcnt{l}\t{%1, %k0|%k0, %1}"; + else if (TARGET_CPU_P (GENERIC)) + /* tzcnt expands to 'rep bsf' and we can use it even if !TARGET_BMI. */ + return "rep%; bsf{l}\t{%1, %k0|%k0, %1}"; + else + gcc_unreachable (); +} + [(set_attr "type" "alu1") + (set_attr "prefix_0f" "1") + (set_attr "prefix_rep" "1") + (set_attr "mode" "SI")]) + (define_insn "bsr_rex64" [(set (reg:CCZ FLAGS_REG) (compare:CCZ (match_operand:DI 1 "nonimmediate_operand" "rm") diff --git a/gcc/testsuite/gcc.target/i386/pr106231-1.c b/gcc/testsuite/gcc.target/i386/pr106231-1.c new file mode 100644 index 0000000..d17297f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106231-1.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -mtune=generic" } */ +long long +foo(long long x, unsigned bits) +{ + return x + (unsigned) __builtin_ctz(bits); +} +/* { dg-final { scan-assembler-not "cltq" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr106231-2.c b/gcc/testsuite/gcc.target/i386/pr106231-2.c new file mode 100644 index 0000000..fd3a8e3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106231-2.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -mtune=ivybridge" } */ +long long +foo(long long x, unsigned bits) +{ + return x + (unsigned) __builtin_ctz(bits); +} +/* { dg-final { scan-assembler-not "cltq" } } */ -- cgit v1.1