From a87819b8f1b890d36a3f05bd9de80be20e9525dd Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Tue, 25 Oct 2022 15:16:47 -0400 Subject: Check if varying may also be non-negative. When using strict enums, we can sometimes turn varying into a better range. * gimple-range-fold.cc (fold_using_range::fold_stmt): Check if stmt is non-negative and adjust the range. --- gcc/gimple-range-fold.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc') diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index f919237..a899d82 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -494,6 +494,14 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name) else if (is_a (s) && gimple_assign_rhs_code (s) == COND_EXPR) res = range_of_cond_expr (r, as_a (s), src); + // If the result is varying, check for basic nonnegativeness. + // Specifically this helps for now with strict enum in cases like + // g++.dg/warn/pr33738.C. + bool so_p; + if (res && r.varying_p () && INTEGRAL_TYPE_P (r.type ()) + && gimple_stmt_nonnegative_warnv_p (s, &so_p)) + r.set_nonnegative (r.type ()); + if (!res) { // If no name specified or range is unsupported, bail. -- cgit v1.1 From 82e629c26647313be406c41a01e6868cfad0f289 Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Wed, 26 Oct 2022 16:37:34 +0300 Subject: ipa-visibility: remove assert in TLS optimization [PR107353] When upgrading TLS access model based on optimized symbol visibility status, we attempted to assert that recomputing the model would not weaken it. It turns out that C, C++, and Fortran front-ends all can (unintentionally) assign a stronger model than what can be derived from the declaration. Let's act conservatively instead of asserting, at least as long as such pre-existing issues remain. gcc/ChangeLog: PR other/107353 * ipa-visibility.cc (function_and_variable_visibility): Conditionally upgrade TLS model instead of asserting. --- gcc/ipa-visibility.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-visibility.cc b/gcc/ipa-visibility.cc index 3ed2b7c..238f7eb 100644 --- a/gcc/ipa-visibility.cc +++ b/gcc/ipa-visibility.cc @@ -886,8 +886,12 @@ function_and_variable_visibility (bool whole_program) && vnode->ref_list.referring.length ()) { enum tls_model new_model = decl_default_tls_model (decl); - gcc_checking_assert (new_model >= decl_tls_model (decl)); - set_decl_tls_model (decl, new_model); + STATIC_ASSERT (TLS_MODEL_GLOBAL_DYNAMIC < TLS_MODEL_LOCAL_DYNAMIC); + STATIC_ASSERT (TLS_MODEL_INITIAL_EXEC < TLS_MODEL_LOCAL_EXEC); + /* We'd prefer to assert that recomputed model is not weaker than + what the front-end assigned, but cannot: see PR 107353. */ + if (new_model >= decl_tls_model (decl)) + set_decl_tls_model (decl, new_model); } } } -- cgit v1.1 From f896c13489d22b30d01257bc8316ab97b3359d1c Mon Sep 17 00:00:00 2001 From: Takayuki 'January June' Suwa Date: Wed, 26 Oct 2022 15:27:51 +0900 Subject: xtensa: Fix out-of-bounds array access in the movdi pattern The following new warnings were introduced in the commit 4f3f0296acbb ("xtensa: Prepare the transition from Reload to LRA"): gcc/config/xtensa/xtensa.md:945:26: error: array subscript 3 is above array bounds of 'rtx_def* [2]' [-Werror=array-bounds] 945 | emit_move_insn (operands[2], operands[3]); gcc/config/xtensa/xtensa.md:945:26: error: array subscript 2 is above array bounds of 'rtx_def* [2]' [-Werror=array-bounds] 945 | emit_move_insn (operands[2], operands[3]); From gcc/insn-emit.cc (generated by building): > /* ../../gcc/config/xtensa/xtensa.md:932 */ > rtx > gen_movdi (rtx operand0, > rtx operand1) > { > rtx_insn *_val = 0; > start_sequence (); > { > rtx operands[2]; // only 2 elements > operands[0] = operand0; > operands[1] = operand1; > #define FAIL return (end_sequence (), _val) > #define DONE return (_val = get_insns (), end_sequence (), _val) > #line 936 "../../gcc/config/xtensa/xtensa.md" > { > if (CONSTANT_P (operands[1])) > { > /* Split in halves if 64-bit Const-to-Reg moves > because of offering further optimization opportunities. */ > if (register_operand (operands[0], DImode)) > { > xtensa_split_DI_reg_imm (operands); // out-of-bounds! > emit_move_insn (operands[0], operands[1]); > emit_move_insn (operands[2], operands[3]); // out-of-bounds! > DONE; > } gcc/ChangeLog: * config/xtensa/xtensa.md (movdi): Copy operands[0...1] to ops[0...3] and then use the latter before calling xtensa_split_DI_reg_imm() and emitting insns. --- gcc/config/xtensa/xtensa.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 2e7f76a..de9bcbf 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -940,9 +940,10 @@ because of offering further optimization opportunities. */ if (register_operand (operands[0], DImode)) { - xtensa_split_DI_reg_imm (operands); - emit_move_insn (operands[0], operands[1]); - emit_move_insn (operands[2], operands[3]); + rtx ops[4] = { operands[0], operands[1] }; + xtensa_split_DI_reg_imm (ops); + emit_move_insn (ops[0], ops[1]); + emit_move_insn (ops[2], ops[3]); DONE; } -- cgit v1.1 From d2249cd9adf5ae638577139177a50f7e62d8abd9 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 14 Oct 2022 10:05:57 -0400 Subject: c++: Implement -Wdangling-reference [PR106393] This patch implements a new experimental warning (enabled by -Wall) to detect references bound to temporaries whose lifetime has ended. The primary motivation is the Note in : Capturing the result of std::max by reference produces a dangling reference if one of the parameters is a temporary and that parameter is returned: int n = 1; const int& r = std::max(n-1, n+1); // r is dangling That's because both temporaries for n-1 and n+1 are destroyed at the end of the full expression. With this warning enabled, you'll get: g.C:3:12: warning: possibly dangling reference to a temporary [-Wdangling-reference] 3 | const int& r = std::max(n-1, n+1); | ^ g.C:3:24: note: the temporary was destroyed at the end of the full expression 'std::max((n - 1), (n + 1))' 3 | const int& r = std::max(n-1, n+1); | ~~~~~~~~^~~~~~~~~~ The warning works by checking if a reference is initialized with a function that returns a reference, and at least one parameter of the function is a reference that is bound to a temporary. It assumes that such a function actually returns one of its arguments! (I added code to check_return_expr to suppress the warning when we've seen the definition of the function and we can say that it can return a variable with static storage duration.) It warns when the function in question is a member function, but only if the function is invoked on a temporary object, otherwise the warning would emit loads of warnings for valid code like obj.emplace({0}, 0). It does detect the dangling reference in: struct S { const S& self () { return *this; } }; const S& s = S().self(); It warns in member initializer lists as well: const int& f(const int& i) { return i; } struct S { const int &r; S() : r(f(10)) { } }; I've run the testsuite/bootstrap with the warning enabled by default. There were just a few FAILs, all of which look like genuine bugs. A bootstrap with the warning enabled by default passed as well. When testing a previous version of the patch, there were many FAILs in libstdc++'s 22_locale/; all of them because the warning triggered on const test_type& obj = std::use_facet(std::locale()); but this code looks valid -- std::use_facet doesn't return a reference to its parameter. Therefore I added a #pragma and code to suppress the warning. PR c++/106393 gcc/c-family/ChangeLog: * c.opt (Wdangling-reference): New. gcc/cp/ChangeLog: * call.cc (expr_represents_temporary_p): New, factored out of... (conv_binds_ref_to_temporary): ...here. Don't return false just because a ck_base is missing. Use expr_represents_temporary_p. (do_warn_dangling_reference): New. (maybe_warn_dangling_reference): New. (extend_ref_init_temps): Call maybe_warn_dangling_reference. * cp-tree.h: Adjust comment. * typeck.cc (check_return_expr): Suppress -Wdangling-reference warnings. gcc/ChangeLog: * doc/invoke.texi: Document -Wdangling-reference. libstdc++-v3/ChangeLog: * include/bits/locale_classes.tcc: Add #pragma to disable -Wdangling-reference with std::use_facet. gcc/testsuite/ChangeLog: * g++.dg/cpp23/elision4.C: Use -Wdangling-reference, add dg-warning. * g++.dg/cpp23/elision7.C: Likewise. * g++.dg/warn/Wdangling-pointer-2.C: Use -Wno-dangling-reference. * g++.dg/warn/Wdangling-reference1.C: New test. * g++.dg/warn/Wdangling-reference2.C: New test. * g++.dg/warn/Wdangling-reference3.C: New test. --- gcc/c-family/c.opt | 4 + gcc/cp/call.cc | 148 +++++++++++++++++++++-- gcc/cp/cp-tree.h | 4 +- gcc/cp/typeck.cc | 11 ++ gcc/doc/invoke.texi | 51 +++++++- gcc/testsuite/g++.dg/cpp23/elision4.C | 5 +- gcc/testsuite/g++.dg/cpp23/elision7.C | 3 +- gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C | 2 +- gcc/testsuite/g++.dg/warn/Wdangling-reference1.C | 144 ++++++++++++++++++++++ gcc/testsuite/g++.dg/warn/Wdangling-reference2.C | 28 +++++ gcc/testsuite/g++.dg/warn/Wdangling-reference3.C | 24 ++++ 11 files changed, 406 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference1.C create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference2.C create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference3.C (limited to 'gcc') diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 01d4807..070f85c 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -555,6 +555,10 @@ Wdangling-pointer= C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_dangling_pointer) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall, 2, 0) IntegerRange(0, 2) Warn for uses of pointers to auto variables whose lifetime has ended. +Wdangling-reference +C++ ObjC++ Var(warn_dangling_reference) Warning LangEnabledBy(C++ ObjC++, Wall) +Warn when a reference is bound to a temporary whose lifetime has ended. + Wdate-time C ObjC C++ ObjC++ CPP(warn_date_time) CppReason(CPP_W_DATE_TIME) Var(cpp_warn_date_time) Init(0) Warning Warn about __TIME__, __DATE__ and __TIMESTAMP__ usage. diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 6a34e9c..951b9fd 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -9313,6 +9313,16 @@ conv_binds_ref_to_prvalue (conversion *c) return conv_is_prvalue (next_conversion (c)); } +/* True iff EXPR represents a (subobject of a) temporary. */ + +static bool +expr_represents_temporary_p (tree expr) +{ + while (handled_component_p (expr)) + expr = TREE_OPERAND (expr, 0); + return TREE_CODE (expr) == TARGET_EXPR; +} + /* True iff C is a conversion that binds a reference to a temporary. This is a superset of conv_binds_ref_to_prvalue: here we're also interested in xvalues. */ @@ -9330,18 +9340,14 @@ conv_binds_ref_to_temporary (conversion *c) struct Derived : Base {}; const Base& b(Derived{}); where we bind 'b' to the Base subobject of a temporary object of type - Derived. The subobject is an xvalue; the whole object is a prvalue. */ - if (c->kind != ck_base) - return false; - c = next_conversion (c); - if (c->kind == ck_identity && c->u.expr) - { - tree expr = c->u.expr; - while (handled_component_p (expr)) - expr = TREE_OPERAND (expr, 0); - if (TREE_CODE (expr) == TARGET_EXPR) - return true; - } + Derived. The subobject is an xvalue; the whole object is a prvalue. + + The ck_base doesn't have to be present for cases like X{}.m. */ + if (c->kind == ck_base) + c = next_conversion (c); + if (c->kind == ck_identity && c->u.expr + && expr_represents_temporary_p (c->u.expr)) + return true; return false; } @@ -13428,6 +13434,121 @@ initialize_reference (tree type, tree expr, return expr; } +/* Helper for maybe_warn_dangling_reference to find a problematic CALL_EXPR + that initializes the LHS (and at least one of its arguments represents + a temporary, as outlined in maybe_warn_dangling_reference), or NULL_TREE + if none found. For instance: + + const S& s = S().self(); // S::self (&TARGET_EXPR <...>) + const int& r = (42, f(1)); // f(1) + const int& t = b ? f(1) : f(2); // f(1) + const int& u = b ? f(1) : f(g); // f(1) + const int& v = b ? f(g) : f(2); // f(2) + const int& w = b ? f(g) : f(g); // NULL_TREE + const int& y = (f(1), 42); // NULL_TREE + const int& z = f(f(1)); // f(f(1)) + + EXPR is the initializer. */ + +static tree +do_warn_dangling_reference (tree expr) +{ + STRIP_NOPS (expr); + switch (TREE_CODE (expr)) + { + case CALL_EXPR: + { + tree fndecl = cp_get_callee_fndecl_nofold (expr); + if (!fndecl + || warning_suppressed_p (fndecl, OPT_Wdangling_reference) + || !warning_enabled_at (DECL_SOURCE_LOCATION (fndecl), + OPT_Wdangling_reference) + /* If the function doesn't return a reference, don't warn. This + can be e.g. + const int& z = std::min({1, 2, 3, 4, 5, 6, 7}); + which doesn't dangle: std::min here returns an int. */ + || !TYPE_REF_OBJ_P (TREE_TYPE (TREE_TYPE (fndecl)))) + return NULL_TREE; + + /* Here we're looking to see if any of the arguments is a temporary + initializing a reference parameter. */ + for (int i = 0; i < call_expr_nargs (expr); ++i) + { + tree arg = CALL_EXPR_ARG (expr, i); + /* Check that this argument initializes a reference, except for + the argument initializing the object of a member function. */ + if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) + && !TYPE_REF_P (TREE_TYPE (arg))) + continue; + /* It could also be another call taking a temporary and returning + it and initializing this reference parameter. */ + if (do_warn_dangling_reference (arg)) + return expr; + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR) + arg = TREE_OPERAND (arg, 0); + if (expr_represents_temporary_p (arg)) + return expr; + /* Don't warn about member function like: + std::any a(...); + S& s = a.emplace({0}, 0); + which constructs a new object and returns a reference to it, but + we still want to detect: + struct S { const S& self () { return *this; } }; + const S& s = S().self(); + where 's' dangles. If we've gotten here, the object this function + is invoked on is not a temporary. */ + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)) + break; + } + return NULL_TREE; + } + case COMPOUND_EXPR: + return do_warn_dangling_reference (TREE_OPERAND (expr, 1)); + case COND_EXPR: + if (tree t = do_warn_dangling_reference (TREE_OPERAND (expr, 1))) + return t; + return do_warn_dangling_reference (TREE_OPERAND (expr, 2)); + case PAREN_EXPR: + return do_warn_dangling_reference (TREE_OPERAND (expr, 0)); + default: + return NULL_TREE; + } +} + +/* Implement -Wdangling-reference, to detect cases like + + int n = 1; + const int& r = std::max(n - 1, n + 1); // r is dangling + + This creates temporaries from the arguments, returns a reference to + one of the temporaries, but both temporaries are destroyed at the end + of the full expression. + + This works by checking if a reference is initialized with a function + that returns a reference, and at least one parameter of the function + is a reference that is bound to a temporary. It assumes that such a + function actually returns one of its arguments. + + DECL is the reference being initialized, INIT is the initializer. */ + +static void +maybe_warn_dangling_reference (const_tree decl, tree init) +{ + if (!warn_dangling_reference) + return; + if (!TYPE_REF_P (TREE_TYPE (decl))) + return; + if (tree call = do_warn_dangling_reference (init)) + { + auto_diagnostic_group d; + if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wdangling_reference, + "possibly dangling reference to a temporary")) + inform (EXPR_LOCATION (call), "the temporary was destroyed at " + "the end of the full expression %qE", call); + } +} + /* If *P is an xvalue expression, prevent temporary lifetime extension if it gets used to initialize a reference. */ @@ -13525,6 +13646,9 @@ extend_ref_init_temps (tree decl, tree init, vec **cleanups, tree type = TREE_TYPE (init); if (processing_template_decl) return init; + + maybe_warn_dangling_reference (decl, init); + if (TYPE_REF_P (type)) init = extend_ref_init_temps_1 (decl, init, cleanups, cond_guard); else diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 867096b..40f5bf8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -459,7 +459,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. DELETE_EXPR_USE_VEC (in DELETE_EXPR). - (TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out). ICS_ELLIPSIS_FLAG (in _CONV) DECL_INITIALIZED_P (in VAR_DECL) TYPENAME_IS_CLASS_P (in TYPENAME_TYPE) @@ -4567,6 +4566,9 @@ get_vec_init_expr (tree t) When appearing in a CONSTRUCTOR, the expression is an unconverted compound literal. + When appearing in a CALL_EXPR, it means that it is a call to + a constructor. + When appearing in a FIELD_DECL, it means that this field has been duly initialized in its constructor. */ #define TREE_HAS_CONSTRUCTOR(NODE) (TREE_LANG_FLAG_4 (NODE)) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index ab6979b..4605f73 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -11246,6 +11246,17 @@ check_return_expr (tree retval, bool *no_warning) if (processing_template_decl) return saved_retval; + /* A naive attempt to reduce the number of -Wdangling-reference false + positives: if we know that this function can return a variable with + static storage duration rather than one of its parameters, suppress + the warning. */ + if (warn_dangling_reference + && TYPE_REF_P (functype) + && bare_retval + && VAR_P (bare_retval) + && TREE_STATIC (bare_retval)) + suppress_warning (current_function_decl, OPT_Wdangling_reference); + /* Actually copy the value returned into the appropriate location. */ if (retval && retval != result) retval = cp_build_init_expr (result, retval); diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 64f77e8..9f0e546 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -249,7 +249,8 @@ in the following sections. -Wno-class-conversion -Wclass-memaccess @gol -Wcomma-subscript -Wconditionally-supported @gol -Wno-conversion-null -Wctad-maybe-unsupported @gol --Wctor-dtor-privacy -Wno-delete-incomplete @gol +-Wctor-dtor-privacy -Wdangling-reference @gol +-Wno-delete-incomplete @gol -Wdelete-non-virtual-dtor -Wno-deprecated-array-compare @gol -Wdeprecated-copy -Wdeprecated-copy-dtor @gol -Wno-deprecated-enum-enum-conversion -Wno-deprecated-enum-float-conversion @gol @@ -3627,6 +3628,54 @@ public static member functions. Also warn if there are no non-private methods, and there's at least one private member function that isn't a constructor or destructor. +@item -Wdangling-reference @r{(C++ and Objective-C++ only)} +@opindex Wdangling-reference +@opindex Wno-dangling-reference +Warn when a reference is bound to a temporary whose lifetime has ended. +For example: + +@smallexample +int n = 1; +const int& r = std::max(n - 1, n + 1); // r is dangling +@end smallexample + +In the example above, two temporaries are created, one for each +argument, and a reference to one of the temporaries is returned. +However, both temporaries are destroyed at the end of the full +expression, so the reference @code{r} is dangling. This warning +also detects dangling references in member initializer lists: + +@smallexample +const int& f(const int& i) @{ return i; @} +struct S @{ + const int &r; // r is dangling + S() : r(f(10)) @{ @} +@}; +@end smallexample + +Member functions are checked as well, but only their object argument: + +@smallexample +struct S @{ + const S& self () @{ return *this; @} +@}; +const S& s = S().self(); // s is dangling +@end smallexample + +Certain functions are safe in this respect, for example @code{std::use_facet}: +they take and return a reference, but they don't return one of its arguments, +which can fool the warning. Such functions can be excluded from the warning +by wrapping them in a @code{#pragma}: + +@smallexample +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" +const T& foo (const T&) @{ @dots{} @} +#pragma GCC diagnostic pop +@end smallexample + +This warning is enabled by @option{-Wall}. + @item -Wdelete-non-virtual-dtor @r{(C++ and Objective-C++ only)} @opindex Wdelete-non-virtual-dtor @opindex Wno-delete-non-virtual-dtor diff --git a/gcc/testsuite/g++.dg/cpp23/elision4.C b/gcc/testsuite/g++.dg/cpp23/elision4.C index c19b86b..d39053a 100644 --- a/gcc/testsuite/g++.dg/cpp23/elision4.C +++ b/gcc/testsuite/g++.dg/cpp23/elision4.C @@ -1,5 +1,6 @@ // PR c++/101165 - P2266R1 - Simpler implicit move // { dg-do compile { target c++23 } } +// { dg-options "-Wdangling-reference" } // Test from P2266R1, $ 5.2. LibreOffice OString constructor. struct X { @@ -33,6 +34,6 @@ T& temporary2(T&& x) { return static_cast(x); } void test () { - int& r1 = temporary1 (42); - int& r2 = temporary2 (42); + int& r1 = temporary1 (42); // { dg-warning "dangling reference" } + int& r2 = temporary2 (42); // { dg-warning "dangling reference" } } diff --git a/gcc/testsuite/g++.dg/cpp23/elision7.C b/gcc/testsuite/g++.dg/cpp23/elision7.C index 19fa89a..0045842 100644 --- a/gcc/testsuite/g++.dg/cpp23/elision7.C +++ b/gcc/testsuite/g++.dg/cpp23/elision7.C @@ -1,5 +1,6 @@ // PR c++/101165 - P2266R1 - Simpler implicit move // { dg-do compile { target c++23 } } +// { dg-options "-Wdangling-reference" } struct X { X (); @@ -68,5 +69,5 @@ f7 (T &&t) void do_f7 () { - const int &x = f7 (0); + const int &x = f7 (0); // { dg-warning "dangling reference" } } diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C b/gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C index 151418f..802ac9c 100644 --- a/gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C +++ b/gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C @@ -1,5 +1,5 @@ /* { dg-do compile } - { dg-options "-O1 -Wall -Wno-class-memaccess" } */ + { dg-options "-O1 -Wall -Wno-class-memaccess -Wno-dangling-reference" } */ struct A { A (); }; diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C new file mode 100644 index 0000000..97c81ee --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C @@ -0,0 +1,144 @@ +// PR c++/106393 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } + +const int& f(const int& i) { return i; } +const int& f_(const int& i) { return i; } +const int& h(int); +const int& rp(const int *); +int g; +const int& globref(const int&) { return g; } +struct X { + int* i; + operator const int&() const { return *i; } +}; +X x{&g}; + +const int& r1 = f(10); // { dg-warning "dangling reference" } +// r2 = _ZGR2r2_ = (int) *f ((const int &) &TARGET_EXPR ) + 1; (const int &) &_ZGR2r2_ +const int& r2 = f(10) + 1; +// Don't warn here, we have +// r3 = f (X::operator const int& (&x)) +const int& r3 = f(x); +// Don't warn here, because we've seen the definition of globref +// and could figure out that it may not return one of its parms. +// Questionable -- it can also hide bugs --, but it helps here. +const int& r4 = globref(1); +const int& r5 = (42, f(10)); // { dg-warning "dangling reference" } +const int& r6 = (f(10), 42); +const int& r7 = (f(10)); // { dg-warning "dangling reference" } +const int& r8 = g ? f(10) : f(9); // { dg-warning "dangling reference" } +const int& r9 = (42, g ? f(10) : f(9)); // { dg-warning "dangling reference" } +const int& r10 = (g ? f(10) : f(9), 42); +// Binds to a reference temporary for r11. No dangling reference. +const int& r11 = g ? f(10) : 9; +const int& r12 = g ? 9 : f(10); +// r12 = f (f ((const int &) &TARGET_EXPR )) +const int& r13 = f(f(1)); // { dg-warning "dangling reference" } +const int& r14 = f(f_(1)); // { dg-warning "dangling reference" } +const int& r15 = f(g ? f(1) : f(2)); // { dg-warning "dangling reference" } +const int& r16 = f(*&f(1)); // { dg-warning "dangling reference" } +const int& r17 = rp(&f(1)); +const int& r18 = rp(&f(g)); +const int& r19 = h(f(1)); +// Other forms of initializers. +const int& r20(f(10)); // { dg-warning "dangling reference" } +const int& r21(f(10)); // { dg-warning "dangling reference" } +// Returns a ref, but doesn't have a parameter of reference type. +const int& r22 = h(10); +const int& r23 = g ? h(10) : f(10); // { dg-warning "dangling reference" } +const int& r24 = g ? f(10) : h(10); // { dg-warning "dangling reference" } +const int& r25 = g ? h(10) : (1, f(10)); // { dg-warning "dangling reference" } +const int& r26 = g ? (1, f(10)) : h(10); // { dg-warning "dangling reference" } +const int& r29 = f((f_(1), 1)); // { dg-warning "dangling reference" } +const int& r30 = f((f_(1), g)); + +struct Z { + operator int() { return 42; } +}; + +const int& r27 = f(Z()); // { dg-warning "dangling reference" } +const int& r28 = f(true ? Z() : Z()); // { dg-warning "dangling reference" } + +const int& operator|(const int &, Z); +const int& r31 = 1 | Z(); // { dg-warning "dangling reference" } + +// OK: the reference is bound to the 10 so still valid at the point +// where it's copied into i1. +int i1 = f(10); + +int +test1 () +{ + const int &lr = f(10); // { dg-warning "dangling reference" } + int i2 = f(10); + return lr; +} + +struct B { }; +struct D : B { }; +struct C { + D d; +}; + +C c; +D d; + +using U = D[3]; + +const B& frotz(const D&); +const B& b1 = frotz(C{}.d); // { dg-warning "dangling reference" } +const B& b2 = frotz(D{}); // { dg-warning "dangling reference" } +const B& b3 = frotz(c.d); +const B& b4 = frotz(d); +const B& b5 = frotz(U{}[0]); // { dg-warning "dangling reference" } + +// Try returning a subobject. +const B& bar (const D& d) { return d; } +const B& b6 = bar (D{}); // { dg-warning "dangling reference" } +const B& baz (const C& c) { return c.d; } +const B& b7 = baz (C{}); // { dg-warning "dangling reference" } +const D& qux (const C& c) { return c.d; } +const D& d1 = qux (C{}); // { dg-warning "dangling reference" } + +struct E { + E(int); +}; +const E& operator*(const E&); +const E& b8 = *E(1); // { dg-warning "dangling reference" } + +struct F : virtual B { }; +struct G : virtual B { }; +struct H : F, G { }; +const B& yum (const F& f) { return f; } +const B& b9 = yum (F{}); // { dg-warning "dangling reference" } +const B& lox (const H& h) { return h; } +const B& b10 = lox (H{}); // { dg-warning "dangling reference" } + +struct S { + const int &r; // { dg-warning "dangling reference" } + S() : r(f(10)) { } // { dg-message "destroyed" } +}; + +// From cppreference. +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +int n = 1; +const int& refmax = max(n - 1, n + 1); // { dg-warning "dangling reference" } + +struct Y { + operator int&(); + operator int&&(); + const int& foo(const int&); +}; + +// x1 = Y::operator int&& (&TARGET_EXPR ) +int&& x1 = Y(); // { dg-warning "dangling reference" } +int&& x2 = Y{}; // { dg-warning "dangling reference" } +int& x3 = Y(); // { dg-warning "dangling reference" } +int& x4 = Y{}; // { dg-warning "dangling reference" } +const int& t1 = Y().foo(10); // { dg-warning "dangling reference" } diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C new file mode 100644 index 0000000..dafdb43 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C @@ -0,0 +1,28 @@ +// PR c++/106393 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } + +namespace std { +struct any {}; +template _ValueType any_cast(any &&); +template struct remove_reference { using type = _Tp; }; +template _Tp forward(typename remove_reference<_Tp>::type); +template typename remove_reference<_Tp>::type move(_Tp); +} // namespace std + +const int &r = std::any_cast(std::any()); // { dg-warning "dangling reference" } + +template struct C { + T t_; // { dg-warning "dangling reference" } + C(T); + template C(U c) : t_(std::forward(c.t_)) {} +}; +struct A {}; +struct B { + B(A); +}; +int main() { + A a; + C ca(a); + C(std::move(ca)); +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C new file mode 100644 index 0000000..4bc20c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C @@ -0,0 +1,24 @@ +// PR c++/106393 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } + +struct A { + int ar[4]; + int& operator[](int i) { return ar[i]; } +}; +const int &r = A()[2]; // { dg-warning "dangling reference" } + +struct S { + const S& self () { return *this; } +}; +const S& s = S().self(); // { dg-warning "dangling reference" } + +struct G { + const G& g() { return *this; } +}; + +struct F { + G& f(); +}; + +const G& g = F().f().g(); // { dg-warning "dangling reference" } -- cgit v1.1 From 068baae1864e2a8036beec3082d384a204e24201 Mon Sep 17 00:00:00 2001 From: David Faust Date: Mon, 24 Oct 2022 13:59:39 -0700 Subject: bpf: add preserve_field_info builtin Add BPF __builtin_preserve_field_info. This builtin is used to extract information to facilitate struct and union relocations performed by the BPF loader, especially for bitfields. The builtin has the following signature: unsigned int __builtin_preserve_field_info (EXPR, unsigned int KIND); Where EXPR is an expression accessing a field of a struct or union. Depending on KIND, different information is returned to the program. The supported values for KIND are as follows: enum { FIELD_BYTE_OFFSET = 0, FIELD_BYTE_SIZE, FIELD_EXISTENCE, FIELD_SIGNEDNESS, FIELD_LSHIFT_U64, FIELD_RSHIFT_U64 }; If -mco-re is in effect (explicitly or implicitly specified), a CO-RE relocation is added for the access in EXPR recording the relevant information according to KIND. gcc/ * config/bpf/bpf.cc: Support __builtin_preserve_field_info. (enum bpf_builtins): Add new builtin. (bpf_init_builtins): Likewise. (bpf_core_field_info): New function. (bpf_expand_builtin): Accomodate new builtin. Refactor adding new relocation to... (maybe_make_core_relo): ... here. New function. (bpf_resolve_overloaded_builtin): Accomodate new builtin. (bpf_core_newdecl): Likewise. (bpf_core_walk): Likewise. (bpf_core_is_maybe_aggregate_access): Improve logic. (struct core_walk_data): New. * config/bpf/coreout.cc (bpf_core_reloc_add): Allow adding different relocation kinds. * config/bpf/coreout.h: Analogous change. * doc/extend.texi: Document BPF __builtin_preserve_field_info. gcc/testsuite/ * gcc.target/bpf/core-builtin-fieldinfo-errors-1.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-errors-2.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-existence-1.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-offset-1.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-sign-1.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-sign-2.c: New test. * gcc.target/bpf/core-builtin-fieldinfo-size-1.c: New test. --- gcc/config/bpf/bpf.cc | 402 +++++++++++++++++---- gcc/config/bpf/coreout.cc | 5 +- gcc/config/bpf/coreout.h | 2 +- gcc/doc/extend.texi | 77 ++++ .../bpf/core-builtin-fieldinfo-errors-1.c | 23 ++ .../bpf/core-builtin-fieldinfo-errors-2.c | 23 ++ .../bpf/core-builtin-fieldinfo-existence-1.c | 34 ++ .../bpf/core-builtin-fieldinfo-lshift-1-be.c | 37 ++ .../bpf/core-builtin-fieldinfo-lshift-1-le.c | 37 ++ .../bpf/core-builtin-fieldinfo-lshift-2.c | 37 ++ .../bpf/core-builtin-fieldinfo-offset-1.c | 56 +++ .../bpf/core-builtin-fieldinfo-rshift-1.c | 36 ++ .../bpf/core-builtin-fieldinfo-rshift-2.c | 35 ++ .../gcc.target/bpf/core-builtin-fieldinfo-sign-1.c | 33 ++ .../gcc.target/bpf/core-builtin-fieldinfo-sign-2.c | 45 +++ .../gcc.target/bpf/core-builtin-fieldinfo-size-1.c | 43 +++ 16 files changed, 850 insertions(+), 75 deletions(-) create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c (limited to 'gcc') diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc index 5105565..ea8ca64 100644 --- a/gcc/config/bpf/bpf.cc +++ b/gcc/config/bpf/bpf.cc @@ -184,13 +184,13 @@ enum bpf_builtins /* Compile Once - Run Everywhere (CO-RE) support. */ BPF_BUILTIN_PRESERVE_ACCESS_INDEX, + BPF_BUILTIN_PRESERVE_FIELD_INFO, BPF_BUILTIN_MAX, }; static GTY (()) tree bpf_builtins[(int) BPF_BUILTIN_MAX]; - void bpf_register_coreattr_pass (void); /* Initialize the per-function machine status. */ @@ -966,6 +966,9 @@ bpf_init_builtins (void) def_builtin ("__builtin_preserve_access_index", BPF_BUILTIN_PRESERVE_ACCESS_INDEX, build_function_type_list (ptr_type_node, ptr_type_node, 0)); + def_builtin ("__builtin_preserve_field_info", + BPF_BUILTIN_PRESERVE_FIELD_INFO, + build_function_type_list (unsigned_type_node, ptr_type_node, unsigned_type_node, 0)); } #undef TARGET_INIT_BUILTINS @@ -975,6 +978,199 @@ static tree bpf_core_compute (tree, vec *); static int bpf_core_get_index (const tree); static bool is_attr_preserve_access (tree); +/* BPF Compile Once - Run Everywhere (CO-RE) support. Construct a CO-RE + relocation record for EXPR of kind KIND to be emitted in the .BTF.ext + section. Does nothing if we are not targetting BPF CO-RE, or if the + constructed relocation would be a no-op. */ + +static void +maybe_make_core_relo (tree expr, enum btf_core_reloc_kind kind) +{ + /* If we are not targetting BPF CO-RE, do not make a relocation. We + might not be generating any debug info at all. */ + if (!TARGET_BPF_CORE) + return; + + auto_vec accessors; + tree container = bpf_core_compute (expr, &accessors); + + /* Any valid use of the builtin must have at least one access. Otherwise, + there is nothing to record and nothing to do. This is primarily a + guard against optimizations leading to unexpected expressions in the + argument of the builtin. For example, if the builtin is used to read + a field of a structure which can be statically determined to hold a + constant value, the argument to the builtin will be optimized to that + constant. This is OK, and means the builtin call is superfluous. + e.g. + struct S foo; + foo.a = 5; + int x = __preserve_access_index (foo.a); + ... do stuff with x + 'foo.a' in the builtin argument will be optimized to '5' with -01+. + This sequence does not warrant recording a CO-RE relocation. */ + + if (accessors.length () < 1) + return; + accessors.reverse (); + + rtx_code_label *label = gen_label_rtx (); + LABEL_PRESERVE_P (label) = 1; + emit_label (label); + + /* Determine what output section this relocation will apply to. + If this function is associated with a section, use that. Otherwise, + fall back on '.text'. */ + const char * section_name; + if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) + section_name = DECL_SECTION_NAME (current_function_decl); + else + section_name = ".text"; + + /* Add the CO-RE relocation information to the BTF container. */ + bpf_core_reloc_add (TREE_TYPE (container), section_name, &accessors, label, + kind); +} + +/* Expand a call to __builtin_preserve_field_info by evaluating the requested + information about SRC according to KIND, and return a tree holding + the result. */ + +static tree +bpf_core_field_info (tree src, enum btf_core_reloc_kind kind) +{ + unsigned int result; + poly_int64 bitsize, bitpos; + tree var_off = NULL_TREE; + machine_mode mode; + int unsignedp, reversep, volatilep; + location_t loc = EXPR_LOCATION (src); + + get_inner_reference (src, &bitsize, &bitpos, &var_off, &mode, &unsignedp, + &reversep, &volatilep); + + /* Note: Use DECL_BIT_FIELD_TYPE rather than DECL_BIT_FIELD here, because it + remembers whether the field in question was originally declared as a + bitfield, regardless of how it has been optimized. */ + bool bitfieldp = (TREE_CODE (src) == COMPONENT_REF + && DECL_BIT_FIELD_TYPE (TREE_OPERAND (src, 1))); + + unsigned int align = TYPE_ALIGN (TREE_TYPE (src)); + if (TREE_CODE (src) == COMPONENT_REF) + { + tree field = TREE_OPERAND (src, 1); + if (DECL_BIT_FIELD_TYPE (field)) + align = TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)); + else + align = TYPE_ALIGN (TREE_TYPE (field)); + } + + unsigned int start_bitpos = bitpos & ~(align - 1); + unsigned int end_bitpos = start_bitpos + align; + + switch (kind) + { + case BPF_RELO_FIELD_BYTE_OFFSET: + { + if (var_off != NULL_TREE) + { + error_at (loc, "unsupported variable field offset"); + return error_mark_node; + } + + if (bitfieldp) + result = start_bitpos / 8; + else + result = bitpos / 8; + } + break; + + case BPF_RELO_FIELD_BYTE_SIZE: + { + if (mode == BLKmode && bitsize == -1) + { + error_at (loc, "unsupported variable size field access"); + return error_mark_node; + } + + if (bitfieldp) + { + /* To match LLVM behavior, byte size of bitfields is recorded as + the full size of the base type. A 3-bit bitfield of type int is + therefore recorded as having a byte size of 4 bytes. */ + result = end_bitpos - start_bitpos; + if (result & (result - 1)) + { + error_at (loc, "unsupported field expression"); + return error_mark_node; + } + result = result / 8; + } + else + result = bitsize / 8; + } + break; + + case BPF_RELO_FIELD_EXISTS: + /* The field always exists at compile time. */ + result = 1; + break; + + case BPF_RELO_FIELD_SIGNED: + result = !unsignedp; + break; + + case BPF_RELO_FIELD_LSHIFT_U64: + case BPF_RELO_FIELD_RSHIFT_U64: + { + if (mode == BLKmode && bitsize == -1) + { + error_at (loc, "unsupported variable size field access"); + return error_mark_node; + } + if (var_off != NULL_TREE) + { + error_at (loc, "unsupported variable field offset"); + return error_mark_node; + } + + if (!bitfieldp) + { + if (bitsize > 64) + { + error_at (loc, "field size too large"); + return error_mark_node; + } + result = 64 - bitsize; + break; + } + + if (end_bitpos - start_bitpos > 64) + { + error_at (loc, "field size too large"); + return error_mark_node; + } + + if (kind == BPF_RELO_FIELD_LSHIFT_U64) + { + if (TARGET_BIG_ENDIAN) + result = bitpos + 64 - start_bitpos - align; + else + result = start_bitpos + 64 - bitpos - bitsize; + } + else /* RSHIFT_U64 */ + result = 64 - bitsize; + } + break; + + default: + error ("invalid second argument to built-in function"); + return error_mark_node; + break; + } + + return build_int_cst (unsigned_type_node, result); +} + /* Expand a call to a BPF-specific built-in function that was set up with bpf_init_builtins. */ @@ -1025,17 +1221,15 @@ bpf_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, /* The result of the load is in R0. */ return gen_rtx_REG (ops[0].mode, BPF_R0); } + else if (code == -1) { - /* A resolved overloaded builtin, e.g. __bpf_preserve_access_index_si */ + /* A resolved overloaded __builtin_preserve_access_index. */ tree arg = CALL_EXPR_ARG (exp, 0); if (arg == NULL_TREE) return NULL_RTX; - auto_vec accessors; - tree container; - if (TREE_CODE (arg) == SSA_NAME) { gimple *def_stmt = SSA_NAME_DEF_STMT (arg); @@ -1049,51 +1243,42 @@ bpf_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, /* Avoid double-recording information if the argument is an access to a struct/union marked __attribute__((preserve_access_index)). This Will be handled by the attribute handling pass. */ - if (is_attr_preserve_access (arg)) - return expand_normal (arg); - - container = bpf_core_compute (arg, &accessors); - - /* Any valid use of the builtin must have at least one access. Otherwise, - there is nothing to record and nothing to do. This is primarily a - guard against optimizations leading to unexpected expressions in the - argument of the builtin. For example, if the builtin is used to read - a field of a structure which can be statically determined to hold a - constant value, the argument to the builtin will be optimized to that - constant. This is OK, and means the builtin call is superfluous. - e.g. - struct S foo; - foo.a = 5; - int x = __preserve_access_index (foo.a); - ... do stuff with x - 'foo.a' in the builtin argument will be optimized to '5' with -01+. - This sequence does not warrant recording a CO-RE relocation. */ - - if (accessors.length () < 1) - return expand_normal (arg); - - accessors.reverse (); - - container = TREE_TYPE (container); - - rtx_code_label *label = gen_label_rtx (); - LABEL_PRESERVE_P (label) = 1; - emit_label (label); - - /* Determine what output section this relocation will apply to. - If this function is associated with a section, use that. Otherwise, - fall back on '.text'. */ - const char * section_name; - if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) - section_name = DECL_SECTION_NAME (current_function_decl); + if (!is_attr_preserve_access (arg)) + maybe_make_core_relo (arg, BPF_RELO_FIELD_BYTE_OFFSET); + + return expand_normal (arg); + } + + else if (code == -2) + { + /* A resolved overloaded __builtin_preserve_field_info. */ + tree src = CALL_EXPR_ARG (exp, 0); + tree kind_tree = CALL_EXPR_ARG (exp, 1); + unsigned HOST_WIDE_INT kind_val; + if (tree_fits_uhwi_p (kind_tree)) + kind_val = tree_to_uhwi (kind_tree); else - section_name = ".text"; + error ("invalid argument to built-in function"); - /* Add the CO-RE relocation information to the BTF container. */ - bpf_core_reloc_add (container, section_name, &accessors, label); + enum btf_core_reloc_kind kind = (enum btf_core_reloc_kind) kind_val; - return expand_normal (arg); + if (TREE_CODE (src) == SSA_NAME) + { + gimple *def_stmt = SSA_NAME_DEF_STMT (src); + if (is_gimple_assign (def_stmt)) + src = gimple_assign_rhs1 (def_stmt); + } + if (TREE_CODE (src) == ADDR_EXPR) + src = TREE_OPERAND (src, 0); + + tree result = bpf_core_field_info (src, kind); + + if (result != error_mark_node) + maybe_make_core_relo (src, kind); + + return expand_normal (result); } + gcc_unreachable (); } @@ -1259,41 +1444,64 @@ bpf_core_get_index (const tree node) __builtin_preserve_access_index. */ static tree -bpf_core_newdecl (tree type) +bpf_core_newdecl (tree type, bool is_pai) { - tree rettype = build_function_type_list (type, type, NULL); + tree rettype; char name[80]; - int len = snprintf (name, sizeof (name), "%s", "__builtin_pai_"); + static unsigned long pai_count = 0; + static unsigned long pfi_count = 0; - static unsigned long cnt = 0; - len = snprintf (name + len, sizeof (name) - len, "%lu", cnt++); + if (is_pai) + { + rettype = build_function_type_list (type, type, NULL); + int len = snprintf (name, sizeof (name), "%s", "__builtin_pai_"); + len = snprintf (name + len, sizeof (name) - len, "%lu", pai_count++); + } + else + { + rettype = build_function_type_list (unsigned_type_node, type, + unsigned_type_node, NULL); + int len = snprintf (name, sizeof (name), "%s", "__builtin_pfi_"); + len = snprintf (name + len, sizeof (name) - len, "%lu", pfi_count++); + } - return add_builtin_function_ext_scope (name, rettype, -1, BUILT_IN_MD, NULL, - NULL_TREE); + return add_builtin_function_ext_scope (name, rettype, is_pai ? -1 : -2, + BUILT_IN_MD, NULL, NULL_TREE); } /* Return whether EXPR could access some aggregate data structure that BPF CO-RE support needs to know about. */ -static int +static bool bpf_core_is_maybe_aggregate_access (tree expr) { - enum tree_code code = TREE_CODE (expr); - if (code == COMPONENT_REF || code == ARRAY_REF) - return 1; - - if (code == ADDR_EXPR) + switch (TREE_CODE (expr)) + { + case COMPONENT_REF: + case BIT_FIELD_REF: + case ARRAY_REF: + case ARRAY_RANGE_REF: + return true; + case ADDR_EXPR: + case NOP_EXPR: return bpf_core_is_maybe_aggregate_access (TREE_OPERAND (expr, 0)); - - return 0; + default: + return false; + } } +struct core_walk_data { + location_t loc; + tree arg; +}; + /* Callback function used with walk_tree from bpf_resolve_overloaded_builtin. */ static tree bpf_core_walk (tree *tp, int *walk_subtrees, void *data) { - location_t loc = *((location_t *) data); + struct core_walk_data *dat = (struct core_walk_data *) data; + bool is_pai = dat->arg == NULL_TREE; /* If this is a type, don't do anything. */ if (TYPE_P (*tp)) @@ -1302,10 +1510,18 @@ bpf_core_walk (tree *tp, int *walk_subtrees, void *data) return NULL_TREE; } + /* Build a new function call to a resolved builtin for the desired operation. + If this is a preserve_field_info call, pass along the argument to the + resolved builtin call. */ if (bpf_core_is_maybe_aggregate_access (*tp)) { - tree newdecl = bpf_core_newdecl (TREE_TYPE (*tp)); - tree newcall = build_call_expr_loc (loc, newdecl, 1, *tp); + tree newdecl = bpf_core_newdecl (TREE_TYPE (*tp), is_pai); + tree newcall; + if (is_pai) + newcall = build_call_expr_loc (dat->loc, newdecl, 1, *tp); + else + newcall = build_call_expr_loc (dat->loc, newdecl, 2, *tp, dat->arg); + *tp = newcall; *walk_subtrees = 0; } @@ -1330,6 +1546,30 @@ bpf_small_register_classes_for_mode_p (machine_mode mode) #define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P \ bpf_small_register_classes_for_mode_p +/* Return whether EXPR is a valid first argument for a call to + __builtin_preserve_field_info. */ + +static bool +bpf_is_valid_preserve_field_info_arg (tree expr) +{ + switch (TREE_CODE (expr)) + { + case COMPONENT_REF: + case BIT_FIELD_REF: + case ARRAY_REF: + case ARRAY_RANGE_REF: + return true; + case NOP_EXPR: + return bpf_is_valid_preserve_field_info_arg (TREE_OPERAND (expr, 0)); + case ADDR_EXPR: + /* Do not accept ADDR_EXPRs like &foo.bar, but do accept accesses like + foo.baz where baz is an array. */ + return (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == ARRAY_TYPE); + default: + return false; + } +} + /* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN (see gccint manual section Target Macros::Misc.). We use this for the __builtin_preserve_access_index builtin for CO-RE @@ -1344,7 +1584,12 @@ bpf_small_register_classes_for_mode_p (machine_mode mode) static tree bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) { - if (DECL_MD_FUNCTION_CODE (fndecl) != BPF_BUILTIN_PRESERVE_ACCESS_INDEX) + bool is_pai = DECL_MD_FUNCTION_CODE (fndecl) + == BPF_BUILTIN_PRESERVE_ACCESS_INDEX; + bool is_pfi = DECL_MD_FUNCTION_CODE (fndecl) + == BPF_BUILTIN_PRESERVE_FIELD_INFO; + + if (!is_pai && !is_pfi) return NULL_TREE; /* We only expect one argument, but it may be an arbitrarily-complicated @@ -1352,18 +1597,26 @@ bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) vec *params = static_cast *> (arglist); unsigned n_params = params ? params->length() : 0; - if (n_params != 1) + if ((is_pai && n_params != 1) || (is_pfi && n_params != 2)) { - error_at (loc, "expected exactly 1 argument"); - return NULL_TREE; + error_at (loc, "wrong number of arguments"); + return error_mark_node; } tree param = (*params)[0]; - /* If not generating BPF_CORE information, the builtin does nothing. */ - if (!TARGET_BPF_CORE) + /* If not generating BPF_CORE information, preserve_access_index does nothing, + and simply "resolves to" the argument. */ + if (!TARGET_BPF_CORE && is_pai) return param; + if (is_pfi && !bpf_is_valid_preserve_field_info_arg (param)) + { + error_at (EXPR_LOC_OR_LOC (param, loc), + "argument is not a field access"); + return error_mark_node; + } + /* Do remove_c_maybe_const_expr for the arg. TODO: WHY do we have to do this here? Why doesn't c-typeck take care of it before or after this hook? */ @@ -1387,7 +1640,11 @@ bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) This ensures that all the relevant information remains within the expression trees the builtin finally gets. */ - walk_tree (¶m, bpf_core_walk, (void *) &loc, NULL); + struct core_walk_data data; + data.loc = loc; + data.arg = is_pai ? NULL_TREE : (*params)[1]; + + walk_tree (¶m, bpf_core_walk, (void *) &data, NULL); return param; } @@ -1524,7 +1781,8 @@ handle_attr_preserve (function *fn) emit_label (label); /* Add the CO-RE relocation information to the BTF container. */ - bpf_core_reloc_add (container, section_name, &accessors, label); + bpf_core_reloc_add (container, section_name, &accessors, label, + BPF_RELO_FIELD_BYTE_OFFSET); } } } diff --git a/gcc/config/bpf/coreout.cc b/gcc/config/bpf/coreout.cc index 8897a04..9f71040 100644 --- a/gcc/config/bpf/coreout.cc +++ b/gcc/config/bpf/coreout.cc @@ -152,7 +152,8 @@ static GTY (()) vec *bpf_core_sections; void bpf_core_reloc_add (const tree type, const char * section_name, - vec *accessors, rtx_code_label *label) + vec *accessors, rtx_code_label *label, + enum btf_core_reloc_kind kind) { char buf[40]; unsigned int i, n = 0; @@ -173,7 +174,7 @@ bpf_core_reloc_add (const tree type, const char * section_name, bpfcr->bpfcr_type = get_btf_id (ctf_lookup_tree_type (ctfc, type)); bpfcr->bpfcr_insn_label = label; - bpfcr->bpfcr_kind = BPF_RELO_FIELD_BYTE_OFFSET; + bpfcr->bpfcr_kind = kind; /* Add the CO-RE reloc to the appropriate section. */ bpf_core_section_ref sec; diff --git a/gcc/config/bpf/coreout.h b/gcc/config/bpf/coreout.h index 3c7bdfd..498853f 100644 --- a/gcc/config/bpf/coreout.h +++ b/gcc/config/bpf/coreout.h @@ -103,7 +103,7 @@ extern void btf_ext_init (void); extern void btf_ext_output (void); extern void bpf_core_reloc_add (const tree, const char *, vec *, - rtx_code_label *); + rtx_code_label *, enum btf_core_reloc_kind); extern int bpf_core_get_sou_member_index (ctf_container_ref, const tree); #ifdef __cplusplus diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index ba90bfa..77ea545 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -15755,6 +15755,83 @@ Load 32-bits from the @code{struct sk_buff} packet data pointed by the register BPF Compile Once-Run Everywhere (CO-RE) support. Instruct GCC to generate CO-RE relocation records for any accesses to aggregate data structures (struct, union, array types) in @var{expr}. This builtin is otherwise transparent, the return value is whatever @var{expr} evaluates to. It is also overloaded: @var{expr} may be of any type (not necessarily a pointer), the return type is the same. Has no effect if @code{-mco-re} is not in effect (either specified or implied). @end deftypefn +@deftypefn {Built-in Function} unsigned int __builtin_preserve_field_info (@var{expr}, unsigned int @var{kind}) +BPF Compile Once-Run Everywhere (CO-RE) support. This builtin is used to +extract information to aid in struct/union relocations. @var{expr} is +an access to a field of a struct or union. Depending on @var{kind}, different +information is returned to the program. A CO-RE relocation for the access in +@var{expr} with kind @var{kind} is recorded if @code{-mco-re} is in effect. + +The following values are supported for @var{kind}: +@table @var +@item FIELD_BYTE_OFFSET = 0 +The returned value is the offset, in bytes, of the field from the +beginning of the containing structure. For bitfields, the byte offset +of the containing word. + +@item FIELD_BYTE_SIZE = 1 +The returned value is the size, in bytes, of the field. For bitfields, +the size in bytes of the containing word. + +@item FIELD_EXISTENCE = 2 +The returned value is 1 if the field exists, 0 otherwise. Always 1 at +compile time. + +@item FIELD_SIGNEDNESS = 3 +The returned value is 1 if the field is signed, 0 otherwise. + +@item FIELD_LSHIFT_U64 = 4 +@itemx FIELD_RSHIFT_U64 = 5 +The returned value is the number of bits of left- or right-shifting +respectively needed in order to recover the original value of the field, +after it has been loaded by a read of FIELD_BYTE_SIZE bytes into an +unsigned 64-bit value. Primarily useful for reading bitfield values +from structures which may change between kernel versions. + +@end table + +Note that the return value is a constant which is known at +compile-time. If the field has a variable offset then +FIELD_BYTE_OFFSET, FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are not +supported. Similarly, if the field has a variable size then +FIELD_BYTE_SIZE, FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are not +supported. + +For example, __builtin_preserve_field_info can be used to reliably +extract bitfield values from a structure which may change between +kernel versions: + +@example +struct S +@{ + short a; + int x:7; + int y:5; +@}; + +int +read_y (struct S *arg) +@{ + unsigned long long val; + unsigned int offset = __builtin_preserve_field_info (arg->y, FIELD_BYTE_OFFSET); + unsigned int size = __builtin_presrve_field_info (arg->y, FIELD_BYTE_SIZE); + + /* Read size bytes from arg + offset into val. */ + bpf_probe_read (&val, size, arg + offset); + + val <<= __builtin_preserve_field_info (arg->y, FIELD_LSHIFT_U64); + + if (__builtin_preserve_field_info (arg->y, FIELD_SIGNEDNESS)) + val = ((long long) val >> __builtin_preserve_field_info (arg->y, FIELD_RSHIFT_U64)); + else + val >>= __builtin_preserve_field_info (arg->y, FIELD_RSHIFT_U64); + + return val; +@} + +@end example +@end deftypefn + @node FR-V Built-in Functions @subsection FR-V Built-in Functions diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c new file mode 100644 index 0000000..2c67c38 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct F { + int bar; + char c; + int baz; + int arr[]; +}; + +enum { + FIELD_BYTE_OFFSET = 0, + FIELD_BYTE_SIZE = 1, +}; + +unsigned int test (struct F *f) { + + unsigned x = __builtin_preserve_field_info (f->arr, FIELD_BYTE_SIZE); /* { dg-error "unsupported variable size field access" } */ + + unsigned y = __builtin_preserve_field_info (f->baz, 99); /* { dg-error "invalid second argument to built-in function" } */ + + return x + y; +} diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c new file mode 100644 index 0000000..31d7a03 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct F { + int bar; + char c; + int baz; +}; + +enum { + FIELD_BYTE_OFFSET = 0, + FIELD_BYTE_SIZE = 1, +}; + +int test (struct F *f) { + int a; + unsigned x = __builtin_preserve_field_info (({ a = f->bar + f->baz; }), FIELD_BYTE_OFFSET); /* { dg-error "argument is not a field access" } */ + + int b; + unsigned y = __builtin_preserve_field_info (&(f->c), FIELD_BYTE_SIZE); /* { dg-error "argument is not a field access" } */ + + return a + b + x + y; +} diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c new file mode 100644 index 0000000..c55f21a --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +enum { + FIELD_EXISTENCE = 2, +}; + +typedef unsigned uint; + +struct S { + unsigned char c; + int d; + uint u; + short ar[3]; +}; + +unsigned int foo (struct S *s) +{ + unsigned c = __builtin_preserve_field_info (s->c, FIELD_EXISTENCE); + unsigned d = __builtin_preserve_field_info (s->d, FIELD_EXISTENCE); + unsigned u = __builtin_preserve_field_info (s->u, FIELD_EXISTENCE); + unsigned ar = __builtin_preserve_field_info (s->ar[1], FIELD_EXISTENCE); + + return c + d + u + ar; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 4 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x2\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c new file mode 100644 index 0000000..dabf73d --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re -mbig-endian" } */ + +struct S { + int x1: 6; + int x2: 3; + int x3: 7; + int x4: 16; +}; + +enum { + FIELD_LSHIFT_U64 = 4, +}; + +unsigned int foo (struct S *s) +{ + /* little endian: x1=58, x2=55, x3=48, x4=32 */ + /* big endian: x1=32, x2=38, x3=41, x4=48 */ + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_LSHIFT_U64); + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_LSHIFT_U64); + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_LSHIFT_U64); + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_LSHIFT_U64); + + return x1 + x2 + x3 + x4; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],38" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],41" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c new file mode 100644 index 0000000..99e3982 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re -mlittle-endian" } */ + +struct S { + int x1: 6; + int x2: 3; + int x3: 7; + int x4: 16; +}; + +enum { + FIELD_LSHIFT_U64 = 4, +}; + +unsigned int foo (struct S *s) +{ + /* little endian: x1=58, x2=55, x3=48, x4=32 */ + /* big endian: x1=32, x2=38, x3=41, x4=48 */ + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_LSHIFT_U64); + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_LSHIFT_U64); + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_LSHIFT_U64); + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_LSHIFT_U64); + + return x1 + x2 + x3 + x4; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],58" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],55" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c new file mode 100644 index 0000000..25be969 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + char c; + short s; + int x; +}; + +union U { + struct S s[2]; + long long ll; +}; + +enum { + FIELD_LSHIFT_U64 = 4, +}; + +unsigned int foo (union U *u) +{ + /* s0s = 48, s1c = 56, ll = 0; endianness independent. */ + unsigned s0s = __builtin_preserve_field_info (u->s[0].s, FIELD_LSHIFT_U64); + unsigned s1c = __builtin_preserve_field_info (u->s[1].c, FIELD_LSHIFT_U64); + unsigned ll = __builtin_preserve_field_info (u->ll, FIELD_LSHIFT_U64); + + return s0s + s1c + ll; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],56" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0:0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c new file mode 100644 index 0000000..590eea0 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + unsigned int a1: 7; + unsigned int a2: 4; + unsigned int a3: 13; + unsigned int a4: 5; + int x; +}; + +struct T { + unsigned int y; + struct S s[2]; + char c; + char d; +}; + +enum { + FIELD_BYTE_OFFSET = 0, +}; + + +unsigned int foo (struct T *t) +{ + unsigned s0a1 = __builtin_preserve_field_info (t->s[0].a1, FIELD_BYTE_OFFSET); + unsigned s0a4 = __builtin_preserve_field_info (t->s[0].a4, FIELD_BYTE_OFFSET); + unsigned s0x = __builtin_preserve_field_info (t->s[0].x, FIELD_BYTE_OFFSET); + + unsigned s1a1 = __builtin_preserve_field_info (t->s[1].a1, FIELD_BYTE_OFFSET); + unsigned s1a4 = __builtin_preserve_field_info (t->s[1].a4, FIELD_BYTE_OFFSET); + unsigned s1x = __builtin_preserve_field_info (t->s[1].x, FIELD_BYTE_OFFSET); + + unsigned c = __builtin_preserve_field_info (t->c, FIELD_BYTE_OFFSET); + unsigned d = __builtin_preserve_field_info (t->d, FIELD_BYTE_OFFSET); + + return s0a1 + s0a4 + s0x + s1a1 + s1a4 + s1x + c + d; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],4" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],8" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],12" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],16" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],20" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],21" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:1:0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:0:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0\[\t \]+\[^\n\]*bpfcr_kind" 8 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c new file mode 100644 index 0000000..d0c75d9 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + int x1: 6; + int x2: 3; + int x3: 7; + int x4: 16; +}; + +enum { + FIELD_RSHIFT_U64 = 5, +}; + +unsigned int foo (struct S *s) +{ + /* x1=58, x2=61, x3=57, x4=48; endianness independent. */ + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_RSHIFT_U64); + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_RSHIFT_U64); + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_RSHIFT_U64); + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_RSHIFT_U64); + + return x1 + x2 + x3 + x4; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],58" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],61" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],57" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x5\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c new file mode 100644 index 0000000..a71ddc1 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + int x; + char c; +}; + +union U { + int i; + struct S s; +}; + +enum { + FIELD_RSHIFT_U64 = 5, +}; + +unsigned int foo (union U *u) +{ + /* sx = 32, sc = 56, i = 32; endianness independent. */ + unsigned sx = __builtin_preserve_field_info (u->s.x, FIELD_RSHIFT_U64); + unsigned sc = __builtin_preserve_field_info (u->s.c, FIELD_RSHIFT_U64); + unsigned i = __builtin_preserve_field_info (u->i, FIELD_RSHIFT_U64); + + return sx + sc + i; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],56" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x5\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c new file mode 100644 index 0000000..3b2081e --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +enum { + FIELD_SIGNEDNESS = 3, +}; + +typedef unsigned uint; + +struct S { + unsigned char c; + int d; + uint u; + short ar[3]; +}; + +unsigned int foo (struct S *s) +{ + unsigned d = __builtin_preserve_field_info (s->d, FIELD_SIGNEDNESS); + unsigned u = __builtin_preserve_field_info (s->u, FIELD_SIGNEDNESS); + unsigned ar = __builtin_preserve_field_info (s->ar[1], FIELD_SIGNEDNESS); + + return d + u + ar; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x3\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c new file mode 100644 index 0000000..bf18429 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +enum { + FIELD_SIGNEDNESS = 3, +}; + +enum Esig { + SA = -1, + SB, + SC, +}; + +enum Eun { + UA = 0, + UB, +}; + +struct S { + enum Esig sig : 3; + enum Eun un : 3; +}; + +union U { + int i; + struct S s; +}; + +unsigned int foo (union U *u) +{ + unsigned i = __builtin_preserve_field_info (u->i, FIELD_SIGNEDNESS); + unsigned sig = __builtin_preserve_field_info (u->s.sig, FIELD_SIGNEDNESS); + unsigned un = __builtin_preserve_field_info (u->s.un, FIELD_SIGNEDNESS); + + return i + sig + un; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "3\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c new file mode 100644 index 0000000..8747bde --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + unsigned int a1: 7; + unsigned int a2: 4; + unsigned int a3: 13; + unsigned int a4: 5; + char carr[5][3]; +}; + +enum { + FIELD_BYTE_SIZE = 1, +}; + +union U { + long long l[3]; + struct S s; +}; + +unsigned int foo (union U *u) +{ + unsigned ls = __builtin_preserve_field_info (u->l, FIELD_BYTE_SIZE); + unsigned s = __builtin_preserve_field_info (u->s, FIELD_BYTE_SIZE); + unsigned a2 = __builtin_preserve_field_info (u->s.a2, FIELD_BYTE_SIZE); + unsigned a3 = __builtin_preserve_field_info (u->s.a3, FIELD_BYTE_SIZE); + unsigned ca = __builtin_preserve_field_info (u->s.carr, FIELD_BYTE_SIZE); + + return ls + s + a2 + a3 + ca; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],24" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],20" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],4" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],15" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x1\[\t \]+\[^\n\]*bpfcr_kind" 5 } } */ -- cgit v1.1 From f7d28818179247685f3c101f9f2f16366f56309b Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Wed, 26 Oct 2022 21:00:44 +0200 Subject: Fortran: BOZ literal constants are not compatible to any type [PR103413] gcc/fortran/ChangeLog: PR fortran/103413 * symbol.cc (gfc_type_compatible): A boz-literal-constant has no type and thus is not considered compatible to any type. gcc/testsuite/ChangeLog: PR fortran/103413 * gfortran.dg/illegal_boz_arg_4.f90: New test. --- gcc/fortran/symbol.cc | 4 ++++ gcc/testsuite/gfortran.dg/illegal_boz_arg_4.f90 | 13 +++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/illegal_boz_arg_4.f90 (limited to 'gcc') diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc index 6050359..49fb378 100644 --- a/gcc/fortran/symbol.cc +++ b/gcc/fortran/symbol.cc @@ -5139,6 +5139,10 @@ gfc_type_compatible (gfc_typespec *ts1, gfc_typespec *ts2) bool is_union1 = (ts1->type == BT_UNION); bool is_union2 = (ts2->type == BT_UNION); + /* A boz-literal-constant has no type. */ + if (ts1->type == BT_BOZ || ts2->type == BT_BOZ) + return false; + if (is_class1 && ts1->u.derived->components && ((ts1->u.derived->attr.is_class diff --git a/gcc/testsuite/gfortran.dg/illegal_boz_arg_4.f90 b/gcc/testsuite/gfortran.dg/illegal_boz_arg_4.f90 new file mode 100644 index 0000000..856cfa9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/illegal_boz_arg_4.f90 @@ -0,0 +1,13 @@ +! { dg-do compile } +! { dg-options "-std=f2018" } +! PR fortran/103413 +! Contributed by G.Steinmetz + +program p + type t + class(*), allocatable :: a + end type + type(t) :: x + allocate (x%a, source=z'1') ! { dg-error "type incompatible" } + allocate (x%a, mold=z'1') ! { dg-error "type incompatible" } +end -- cgit v1.1 From 593254ae03a6c0db5946e44b2cfd90dbfc707a17 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 26 Oct 2022 16:44:23 -0400 Subject: analyzer: add sm-fd.dot Add a .dot file to document the file descriptor state machine. gcc/analyzer/ChangeLog: * sm-fd.dot: New file. Signed-off-by: David Malcolm --- gcc/analyzer/sm-fd.dot | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 gcc/analyzer/sm-fd.dot (limited to 'gcc') diff --git a/gcc/analyzer/sm-fd.dot b/gcc/analyzer/sm-fd.dot new file mode 100644 index 0000000..175daae --- /dev/null +++ b/gcc/analyzer/sm-fd.dot @@ -0,0 +1,109 @@ +/* An overview of the state machine from sm-fd.cc. + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 +. */ + +/* Keep this in-sync with sm-dot.cc */ + +digraph "fd" { + + /* STATES. */ + + /* Start state. */ + start; + + /* States representing a file descriptor that hasn't yet been + checked for validity after opening, for three different + access modes. */ + unchecked_read_write; + unchecked_read_only; + unchecked_write_only; + + /* States for representing a file descriptor that is known to be valid (>= + 0), for three different access modes. */ + valid_read_write; + valid_read_only; + valid_write_only; + + /* State for a file descriptor that is known to be invalid (< 0). */ + invalid; + + /* State for a file descriptor that has been closed. */ + closed; + + /* State for a file descriptor that we do not want to track anymore . */ + stop; + + /* TRANSITIONS. */ + + /* On "open". */ + start -> unchecked_read_only [label="on 'X = open(..., O_RDONLY);'"]; + start -> unchecked_write_only [label="on 'X = open(..., O_WRONLY);'"]; + start -> unchecked_read_write [label="on 'X = open(..., ...);'"]; + + /* On "creat". */ + start -> unchecked_write_only [label="on 'X = create(...);'"]; + + /* On "close". */ + start -> closed [label="on 'close(X);'"]; + unchecked_read_write -> closed [label="on 'close(X);'"]; + unchecked_read_only -> closed [label="on 'close(X);'"]; + unchecked_write_only -> closed [label="on 'close(X);'"]; + valid_read_write -> closed [label="on 'close(X);'"]; + valid_read_only -> closed [label="on 'close(X);'"]; + valid_write_only -> closed [label="on 'close(X);'"]; + constant_fd -> closed [label="on 'close(X);'"]; + closed -> stop [label="on 'close(X);':\nWarn('double close')"]; + + /* On "read". */ + closed -> closed [label="on 'read(X);':\nWarn('use after close')"]; + unchecked_read_write -> unchecked_read_write [label="on 'read(X);:\nWarn('use without check')'"]; + unchecked_read_only -> unchecked_read_only [label="on 'read(X);:\nWarn('use without check')'"]; + unchecked_write_only -> unchecked_write_only [label="on 'read(X);:\nWarn('use without check')'"]; + valid_write_only -> valid_write_only [label="on 'read(X);:\nWarn('access mode mismatch')'"]; + + /* On "write". */ + closed -> closed [label="on 'write(X);':\nWarn('use after close')"]; + unchecked_read_write -> unchecked_read_write [label="on 'write(X);:\nWarn('use without check')'"]; + unchecked_read_only -> unchecked_read_only [label="on 'write(X);:\nWarn('use without check')'"]; + unchecked_write_only -> unchecked_write_only [label="on 'write(X);:\nWarn('use without check')'"]; + valid_read_only -> valid_read_only [label="on 'write(X);:\nWarn('access mode mismatch')'"]; + + /* On "dup". */ + closed -> closed [label="on 'dup(X);':\nWarn('use after close')"]; + /* plus stuff for the new fd. */ + + /* On "pipe". */ + start -> valid_read_write [label="when 'pipe()' succeeds"]; + + /* on_condition. */ + unchecked_read_write -> valid_read_write [label="on 'X >= 0'"]; + unchecked_read_only -> valid_read_only [label="on 'X >= 0'"]; + unchecked_write_only -> valid_write_only [label="on 'X >= 0'"]; + unchecked_read_write -> invalid [label="on 'X < 0'"]; + unchecked_read_only -> invalid [label="on 'X < 0'"]; + unchecked_write_only -> invalid [label="on 'X < 0'"]; + + /* Leaks. */ + unchecked_read_write -> stop [label="on leak:\nWarn('leak')"]; + unchecked_read_only -> stop [label="on leak:\nWarn('leak')"]; + unchecked_write_only -> stop [label="on leak:\nWarn('leak')"]; + valid_read_write -> stop [label="on leak:\nWarn('leak')"]; + valid_read_only -> stop [label="on leak:\nWarn('leak')"]; + valid_write_only -> stop [label="on leak:\nWarn('leak')"]; +} -- cgit v1.1 From 57bbf3a403bb1e77c5081dc25d2d54e5c3d5aae4 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 26 Oct 2022 16:45:17 -0400 Subject: analyzer: fixes to file-descriptor handling gcc/analyzer/ChangeLog: * sm-fd.cc (fd_state_machine::on_open): Transition to "unchecked" when the mode is symbolic, rather than just on integer constants. (fd_state_machine::check_for_open_fd): Don't complain about unchecked values in the start state. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/fd-3.c (test_5): Expect "opened here" message even when flags are symbolic. (test_read_from_symbolic_fd): New. (test_write_to_symbolic_fd): New. Signed-off-by: David Malcolm --- gcc/analyzer/sm-fd.cc | 34 +++++++++++++++++----------------- gcc/testsuite/gcc.dg/analyzer/fd-3.c | 18 +++++++++++++++--- 2 files changed, 32 insertions(+), 20 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index 8a4c208..ae846cd 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -940,25 +940,25 @@ fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node, if (lhs) { tree arg = gimple_call_arg (call, 1); + enum access_mode mode = READ_WRITE; if (TREE_CODE (arg) == INTEGER_CST) { int flag = TREE_INT_CST_LOW (arg); - enum access_mode mode = get_access_mode_from_flag (flag); - - switch (mode) - { - case READ_ONLY: - sm_ctxt->on_transition (node, stmt, lhs, m_start, - m_unchecked_read_only); - break; - case WRITE_ONLY: - sm_ctxt->on_transition (node, stmt, lhs, m_start, - m_unchecked_write_only); - break; - default: - sm_ctxt->on_transition (node, stmt, lhs, m_start, - m_unchecked_read_write); - } + mode = get_access_mode_from_flag (flag); + } + switch (mode) + { + case READ_ONLY: + sm_ctxt->on_transition (node, stmt, lhs, m_start, + m_unchecked_read_only); + break; + case WRITE_ONLY: + sm_ctxt->on_transition (node, stmt, lhs, m_start, + m_unchecked_write_only); + break; + default: + sm_ctxt->on_transition (node, stmt, lhs, m_start, + m_unchecked_read_write); } } else @@ -1096,7 +1096,7 @@ fd_state_machine::check_for_open_fd ( else { - if (!(is_valid_fd_p (state) || (state == m_stop))) + if (!(is_valid_fd_p (state) || state == m_start || state == m_stop)) { if (!is_constant_fd_p (state)) sm_ctxt->warn ( diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-3.c b/gcc/testsuite/gcc.dg/analyzer/fd-3.c index 55e84e3..8e71b14 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-3.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-3.c @@ -50,9 +50,9 @@ test_5 (char *path, void *buf) int flags = O_RDONLY; if (some_condition()) flags |= O_NOATIME; - int fd = open (path, flags); + int fd = open (path, flags); /* { dg-message "\\(1\\) opened here" } */ read (fd, buf, 1); /* { dg-warning "'read' on possibly invalid file descriptor 'fd'" } */ - /* { dg-message "\\(1\\) 'fd' could be invalid" "" { target *-*-* } .-1 } */ + /* { dg-message "\\(2\\) 'fd' could be invalid" "" { target *-*-* } .-1 } */ close (fd); } @@ -82,4 +82,16 @@ test_7 (char *path, void *buf) } close(fd); -} \ No newline at end of file +} + +void +test_read_from_symbolic_fd (int fd, void *buf) +{ + read (fd, buf, 1); +} + +void +test_write_to_symbolic_fd (int fd, void *buf) +{ + write (fd, buf, 1); +} -- cgit v1.1 From 486a50374e7c6200c476e67ffbe13ad71ac3262a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 27 Oct 2022 00:18:35 +0000 Subject: Daily bump. --- gcc/ChangeLog | 146 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 11 ++++ gcc/c-family/ChangeLog | 5 ++ gcc/cp/ChangeLog | 13 +++++ gcc/fortran/ChangeLog | 6 ++ gcc/testsuite/ChangeLog | 74 ++++++++++++++++++++++++ 7 files changed, 256 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6b8ba1d..f9052da 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,149 @@ +2022-10-26 David Faust + + * config/bpf/bpf.cc: Support __builtin_preserve_field_info. + (enum bpf_builtins): Add new builtin. + (bpf_init_builtins): Likewise. + (bpf_core_field_info): New function. + (bpf_expand_builtin): Accomodate new builtin. Refactor adding new + relocation to... + (maybe_make_core_relo): ... here. New function. + (bpf_resolve_overloaded_builtin): Accomodate new builtin. + (bpf_core_newdecl): Likewise. + (bpf_core_walk): Likewise. + (bpf_core_is_maybe_aggregate_access): Improve logic. + (struct core_walk_data): New. + * config/bpf/coreout.cc (bpf_core_reloc_add): Allow adding different + relocation kinds. + * config/bpf/coreout.h: Analogous change. + * doc/extend.texi: Document BPF __builtin_preserve_field_info. + +2022-10-26 Marek Polacek + + PR c++/106393 + * doc/invoke.texi: Document -Wdangling-reference. + +2022-10-26 Takayuki 'January June' Suwa + + * config/xtensa/xtensa.md (movdi): + Copy operands[0...1] to ops[0...3] and then use the latter before + calling xtensa_split_DI_reg_imm() and emitting insns. + +2022-10-26 Alexander Monakov + + PR other/107353 + * ipa-visibility.cc (function_and_variable_visibility): + Conditionally upgrade TLS model instead of asserting. + +2022-10-26 Andrew MacLeod + + * gimple-range-fold.cc (fold_using_range::fold_stmt): Check if + stmt is non-negative and adjust the range. + +2022-10-26 Martin Liska + + * common/config/i386/cpuinfo.h (has_cpu_feature): Add comment. + (reset_cpu_feature): New. + (get_zhaoxin_cpu): Use reset_cpu_feature. + +2022-10-26 Ju-Zhe Zhong + + * config/riscv/riscv.cc (riscv_expand_epilogue): Fix statement. + +2022-10-26 Ju-Zhe Zhong + + PR target/107357 + * config/riscv/riscv-modes.def (VECTOR_BOOL_MODE): Set to minimum size. + (ADJUST_NUNITS): Adjust according to -march. + (ADJUST_BYTESIZE): Ditto. + * config/riscv/riscv-protos.h (riscv_v_ext_enabled_vector_mode_p): + Remove. + (riscv_v_ext_vector_mode_p): Change function implementation. + * config/riscv/riscv-vector-builtins.cc (rvv_switcher::rvv_switcher): + Change to riscv_v_ext_vector_mode_p. + (register_builtin_type): Ditto. + * config/riscv/riscv.cc (riscv_v_ext_vector_mode_p): Change to enabled + modes. + (ENTRY): Ditto. + (riscv_v_ext_enabled_vector_mode_p): Remove. + (riscv_v_adjust_nunits): New function. + (riscv_vector_mode_supported_p): Use riscv_v_ext_vector_mode_p instead. + * config/riscv/riscv.h (riscv_v_adjust_nunits): New function. + +2022-10-26 Ju-Zhe Zhong + + * config.gcc (riscv*): Add riscv-v.o to extra_objs. + * config/riscv/constraints.md (vu): New constraint. + (vi): Ditto. + (Wc0): Ditto. + (Wc1): Ditto. + * config/riscv/predicates.md (vector_length_operand): New. + (reg_or_mem_operand): Ditto. + (vector_move_operand): Ditto. + (vector_mask_operand): Ditto. + (vector_merge_operand): Ditto. + * config/riscv/riscv-protos.h (riscv_regmode_natural_size) New. + (riscv_vector::const_vec_all_same_in_range_p): Ditto. + (riscv_vector::legitimize_move): Ditto. + (tail_policy): Ditto. + (mask_policy): Ditto. + * config/riscv/riscv-v.cc: New. + * config/riscv/riscv-vector-builtins-bases.cc + (vsetvl::expand): Refactor how LMUL encoding. + * config/riscv/riscv.cc (riscv_print_operand): Update how LMUL + print and mask operand print. + (riscv_regmode_natural_size): New. + * config/riscv/riscv.h (REGMODE_NATURAL_SIZE): New. + * config/riscv/riscv.md (mode): Add vector modes. + * config/riscv/t-riscv (riscv-v.o) New. + * config/riscv/vector-iterators.md: New. + * config/riscv/vector.md (vundefined): New. + (mov): New. + (*mov): New. + (@vsetvl_no_side_effects): New. + (@pred_mov): New. + +2022-10-26 Monk Chiang + + * common/config/riscv/riscv-common.cc (riscv_ext_version_table): + Add svinval and svnapot extension. + (riscv_ext_flag_table): Ditto. + * config/riscv/riscv-opts.h (MASK_SVINVAL): New. + (MASK_SVNAPOT): Ditto. + (TARGET_SVINVAL): Ditto. + (TARGET_SVNAPOT): Ditto. + * config/riscv/riscv.opt (riscv_sv_subext): New. + +2022-10-26 Ju-Zhe Zhong + + * config/riscv/riscv-modes.def: Adjust table indentation in commnet. + +2022-10-26 Martin Liska + + * configure: Regenerate. + +2022-10-26 Aldy Hernandez + + * value-range.cc (frange::set): Use HONOR_*. + (frange::verify_range): Same. + * value-range.h (frange_val_min): Same. + (frange_val_max): Same. + +2022-10-26 Jiufu Guo + + PR target/106460 + * config/rs6000/rs6000.cc (rs6000_cannot_force_const_mem): Return true + for HIGH code rtx. + +2022-10-26 Kito Cheng + + * common/config/riscv/riscv-common.cc (riscv_ext_version_table): + Add `h`. + (riscv_supported_std_ext): Ditto. + (multi_letter_subset_rank): Remove `h`. + (riscv_subset_list::parse_std_ext): Handle `h` as single letter + extension. + (riscv_subset_list::parse): Ditto. + 2022-10-25 Eugene Rozenfeld * auto-profile.cc (get_combined_location): Include discriminator in the diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 03e9228..494f34d 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20221026 +20221027 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 733580a..6e6b056 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,14 @@ +2022-10-26 David Malcolm + + * sm-fd.cc (fd_state_machine::on_open): Transition to "unchecked" + when the mode is symbolic, rather than just on integer constants. + (fd_state_machine::check_for_open_fd): Don't complain about + unchecked values in the start state. + +2022-10-26 David Malcolm + + * sm-fd.dot: New file. + 2022-10-24 David Malcolm PR analyzer/107349 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index bb85e78..ee7b511 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2022-10-26 Marek Polacek + + PR c++/106393 + * c.opt (Wdangling-reference): New. + 2022-10-19 Joseph Myers * c-format.h (enum format_lengths): Add FMT_LEN_w8, FMT_LEN_w16, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 550515c..4a49075 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2022-10-26 Marek Polacek + + PR c++/106393 + * call.cc (expr_represents_temporary_p): New, factored out of... + (conv_binds_ref_to_temporary): ...here. Don't return false just + because a ck_base is missing. Use expr_represents_temporary_p. + (do_warn_dangling_reference): New. + (maybe_warn_dangling_reference): New. + (extend_ref_init_temps): Call maybe_warn_dangling_reference. + * cp-tree.h: Adjust comment. + * typeck.cc (check_return_expr): Suppress -Wdangling-reference + warnings. + 2022-10-25 Nathan Sidwell * parser.cc (synthesize_implicit_template_parm): Fix thinko about diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f764113..1ca82cd 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2022-10-26 Harald Anlauf + + PR fortran/103413 + * symbol.cc (gfc_type_compatible): A boz-literal-constant has no type + and thus is not considered compatible to any type. + 2022-10-21 José Rui Faustino de Sousa PR fortran/100097 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 09c4108..56ccf84 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,77 @@ +2022-10-26 David Malcolm + + * gcc.dg/analyzer/fd-3.c (test_5): Expect "opened here" message + even when flags are symbolic. + (test_read_from_symbolic_fd): New. + (test_write_to_symbolic_fd): New. + +2022-10-26 Harald Anlauf + + PR fortran/103413 + * gfortran.dg/illegal_boz_arg_4.f90: New test. + +2022-10-26 David Faust + + * gcc.target/bpf/core-builtin-fieldinfo-errors-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-errors-2.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-existence-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-offset-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-sign-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-sign-2.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-size-1.c: New test. + +2022-10-26 Marek Polacek + + PR c++/106393 + * g++.dg/cpp23/elision4.C: Use -Wdangling-reference, add dg-warning. + * g++.dg/cpp23/elision7.C: Likewise. + * g++.dg/warn/Wdangling-pointer-2.C: Use -Wno-dangling-reference. + * g++.dg/warn/Wdangling-reference1.C: New test. + * g++.dg/warn/Wdangling-reference2.C: New test. + * g++.dg/warn/Wdangling-reference3.C: New test. + +2022-10-26 Ju-Zhe Zhong + + * gcc.target/riscv/rvv/base/mov-1.c: New. + * gcc.target/riscv/rvv/base/mov-10.c: New. + * gcc.target/riscv/rvv/base/mov-11.c: New. + * gcc.target/riscv/rvv/base/mov-12.c: New. + * gcc.target/riscv/rvv/base/mov-13.c: New. + * gcc.target/riscv/rvv/base/mov-2.c: New. + * gcc.target/riscv/rvv/base/mov-3.c: New. + * gcc.target/riscv/rvv/base/mov-4.c: New. + * gcc.target/riscv/rvv/base/mov-5.c: New. + * gcc.target/riscv/rvv/base/mov-6.c: New. + * gcc.target/riscv/rvv/base/mov-7.c: New. + * gcc.target/riscv/rvv/base/mov-8.c: New. + * gcc.target/riscv/rvv/base/mov-9.c: New. + +2022-10-26 Monk Chiang + + * gcc.target/riscv/predef-24.c:New. + * gcc.target/riscv/predef-25.c:New. + +2022-10-26 Jiufu Guo + + PR target/106460 + * gcc.target/powerpc/pr106460.c: New test. + +2022-10-26 Kito Cheng + + * gcc.target/riscv/arch-18.c: New. + * gcc.target/riscv/arch-5.c: Remove test for prefixed + with `h`. + * gcc.target/riscv/predef-23.c: New. + +2022-10-26 Eugene Rozenfeld + + * lib/profopt.exp: Don't force DWARF4 for AutoFDO tests + 2022-10-25 Patrick Palka PR c++/106848 -- cgit v1.1 From e09335728d3f9bc177eac2f7dff79715e0aa67c9 Mon Sep 17 00:00:00 2001 From: Jiawei Date: Thu, 20 Oct 2022 17:32:32 +0800 Subject: RISC-V: Minimal support of z*inx extension. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minimal support of z*inx extension, include 'zfinx', 'zdinx' and 'zhinx/zhinxmin' corresponding to 'f', 'd' and 'zfh/zfhmin', the 'zdinx' will imply 'zfinx' same as 'd' imply 'f', 'zhinx' will aslo imply 'zfinx', all zfinx extension imply 'zicsr'. Co-Authored-By: Sinan Lin gcc/ChangeLog: * common/config/riscv/riscv-common.cc: New extensions. * config/riscv/arch-canonicalize: New imply relations. * config/riscv/riscv-opts.h (MASK_ZFINX): New mask. (MASK_ZDINX): Ditto. (MASK_ZHINX): Ditto. (MASK_ZHINXMIN): Ditto. (TARGET_ZFINX): New target. (TARGET_ZDINX): Ditto. (TARGET_ZHINX): Ditto. (TARGET_ZHINXMIN): Ditto. * config/riscv/riscv.opt: New target variable. --- gcc/common/config/riscv/riscv-common.cc | 18 ++++++++++++++++++ gcc/config/riscv/arch-canonicalize | 5 +++++ gcc/config/riscv/riscv-opts.h | 10 ++++++++++ gcc/config/riscv/riscv.opt | 3 +++ 4 files changed, 36 insertions(+) (limited to 'gcc') diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index bd356ce..d6404a0 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -51,6 +51,11 @@ static const riscv_implied_info_t riscv_implied_info[] = {"d", "f"}, {"f", "zicsr"}, {"d", "zicsr"}, + + {"zdinx", "zfinx"}, + {"zfinx", "zicsr"}, + {"zdinx", "zicsr"}, + {"zk", "zkn"}, {"zk", "zkr"}, {"zk", "zkt"}, @@ -99,6 +104,9 @@ static const riscv_implied_info_t riscv_implied_info[] = {"zfh", "zfhmin"}, {"zfhmin", "f"}, + + {"zhinx", "zhinxmin"}, + {"zhinxmin", "zfinx"}, {NULL, NULL} }; @@ -160,6 +168,11 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zbc", ISA_SPEC_CLASS_NONE, 1, 0}, {"zbs", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zfinx", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zdinx", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zhinx", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zhinxmin", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zbkb", ISA_SPEC_CLASS_NONE, 1, 0}, {"zbkc", ISA_SPEC_CLASS_NONE, 1, 0}, {"zbkx", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -1172,6 +1185,11 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zbc", &gcc_options::x_riscv_zb_subext, MASK_ZBC}, {"zbs", &gcc_options::x_riscv_zb_subext, MASK_ZBS}, + {"zfinx", &gcc_options::x_riscv_zinx_subext, MASK_ZFINX}, + {"zdinx", &gcc_options::x_riscv_zinx_subext, MASK_ZDINX}, + {"zhinx", &gcc_options::x_riscv_zinx_subext, MASK_ZHINX}, + {"zhinxmin", &gcc_options::x_riscv_zinx_subext, MASK_ZHINXMIN}, + {"zbkb", &gcc_options::x_riscv_zk_subext, MASK_ZBKB}, {"zbkc", &gcc_options::x_riscv_zk_subext, MASK_ZBKC}, {"zbkx", &gcc_options::x_riscv_zk_subext, MASK_ZBKX}, diff --git a/gcc/config/riscv/arch-canonicalize b/gcc/config/riscv/arch-canonicalize index fd7651a..2498db5 100755 --- a/gcc/config/riscv/arch-canonicalize +++ b/gcc/config/riscv/arch-canonicalize @@ -41,6 +41,11 @@ LONG_EXT_PREFIXES = ['z', 's', 'h', 'x'] IMPLIED_EXT = { "d" : ["f", "zicsr"], "f" : ["zicsr"], + "zdinx" : ["zfinx", "zicsr"], + "zfinx" : ["zicsr"], + "zhinx" : ["zhinxmin", "zfinx", "zicsr"], + "zhinxmin" : ["zfinx", "zicsr"], + "zk" : ["zkn", "zkr", "zkt"], "zkn" : ["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"], "zks" : ["zbkb", "zbkc", "zbkx", "zksed", "zksh"], diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 63ac56a..1dfe8c8 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -83,6 +83,16 @@ enum stack_protector_guard { #define TARGET_ZBC ((riscv_zb_subext & MASK_ZBC) != 0) #define TARGET_ZBS ((riscv_zb_subext & MASK_ZBS) != 0) +#define MASK_ZFINX (1 << 0) +#define MASK_ZDINX (1 << 1) +#define MASK_ZHINX (1 << 2) +#define MASK_ZHINXMIN (1 << 3) + +#define TARGET_ZFINX ((riscv_zinx_subext & MASK_ZFINX) != 0) +#define TARGET_ZDINX ((riscv_zinx_subext & MASK_ZDINX) != 0) +#define TARGET_ZHINX ((riscv_zinx_subext & MASK_ZHINX) != 0) +#define TARGET_ZHINXMIN ((riscv_zinx_subext & MASK_ZHINXMIN) != 0) + #define MASK_ZBKB (1 << 0) #define MASK_ZBKC (1 << 1) #define MASK_ZBKX (1 << 2) diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index 9493117..426ea95 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -207,6 +207,9 @@ TargetVariable int riscv_zb_subext TargetVariable +int riscv_zinx_subext + +TargetVariable int riscv_zk_subext TargetVariable -- cgit v1.1 From ac96e9068ce7dcaca992fde7f1551ffe8837b723 Mon Sep 17 00:00:00 2001 From: Jiawei Date: Thu, 20 Oct 2022 17:32:33 +0800 Subject: RISC-V: Target support for z*inx extension. Support 'TARGET_ZFINX' with float instruction pattern and builtin function. Reuse 'TARGET_HADR_FLOAT', 'TARGET_DOUBLE_FLOAT' and 'TARGET_ZHINX' patterns. gcc/ChangeLog: * config/riscv/iterators.md (TARGET_ZFINX):New target. (TARGET_ZDINX): Ditto. (TARGET_ZHINX): Ditto. * config/riscv/riscv-builtins.cc (AVAIL): Ditto. (riscv_atomic_assign_expand_fenv): Ditto. * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): Ditto. * config/riscv/riscv.md: Ditto. --- gcc/config/riscv/iterators.md | 6 +-- gcc/config/riscv/riscv-builtins.cc | 4 +- gcc/config/riscv/riscv-c.cc | 2 +- gcc/config/riscv/riscv.md | 78 +++++++++++++++++++------------------- 4 files changed, 46 insertions(+), 44 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md index 39dffab..50380ec 100644 --- a/gcc/config/riscv/iterators.md +++ b/gcc/config/riscv/iterators.md @@ -59,9 +59,9 @@ (define_mode_iterator ANYI [QI HI SI (DI "TARGET_64BIT")]) ;; Iterator for hardware-supported floating-point modes. -(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT") - (DF "TARGET_DOUBLE_FLOAT") - (HF "TARGET_ZFH")]) +(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT || TARGET_ZFINX") + (DF "TARGET_DOUBLE_FLOAT || TARGET_ZDINX") + (HF "TARGET_ZFH || TARGET_ZHINX")]) ;; Iterator for floating-point modes that can be loaded into X registers. (define_mode_iterator SOFTF [SF (DF "TARGET_64BIT") (HF "TARGET_ZFHMIN")]) diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index 9fa4d6c..021f6c6 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -87,7 +87,7 @@ struct riscv_builtin_description { unsigned int (*avail) (void); }; -AVAIL (hard_float, TARGET_HARD_FLOAT) +AVAIL (hard_float, TARGET_HARD_FLOAT || TARGET_ZFINX) AVAIL (clean32, TARGET_ZICBOM && !TARGET_64BIT) @@ -342,7 +342,7 @@ riscv_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, void riscv_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) { - if (!TARGET_HARD_FLOAT) + if (!(TARGET_HARD_FLOAT || TARGET_ZFINX)) return; tree frflags = GET_BUILTIN_DECL (CODE_FOR_riscv_frflags); diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index 78f6eac..826ae00 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -61,7 +61,7 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile) if (TARGET_HARD_FLOAT) builtin_define_with_int_value ("__riscv_flen", UNITS_PER_FP_REG * 8); - if (TARGET_HARD_FLOAT && TARGET_FDIV) + if ((TARGET_HARD_FLOAT || TARGET_ZFINX) && TARGET_FDIV) { builtin_define ("__riscv_fdiv"); builtin_define ("__riscv_fsqrt"); diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index ae907a7..798f737 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -441,7 +441,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (plus:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fadd.\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "")]) @@ -572,7 +572,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (minus:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fsub.\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "")]) @@ -742,7 +742,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (mult:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmul.\t%0,%1,%2" [(set_attr "type" "fmul") (set_attr "mode" "")]) @@ -1049,7 +1049,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (div:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT && TARGET_FDIV" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && TARGET_FDIV" "fdiv.\t%0,%1,%2" [(set_attr "type" "fdiv") (set_attr "mode" "")]) @@ -1064,7 +1064,7 @@ (define_insn "sqrt2" [(set (match_operand:ANYF 0 "register_operand" "=f") (sqrt:ANYF (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT && TARGET_FDIV" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && TARGET_FDIV" { return "fsqrt.\t%0,%1"; } @@ -1079,7 +1079,7 @@ (fma:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmadd.\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "")]) @@ -1090,7 +1090,7 @@ (fma:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f") (neg:ANYF (match_operand:ANYF 3 "register_operand" " f"))))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmsub.\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "")]) @@ -1102,7 +1102,7 @@ (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")) (match_operand:ANYF 2 "register_operand" " f") (neg:ANYF (match_operand:ANYF 3 "register_operand" " f"))))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fnmadd.\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "")]) @@ -1114,7 +1114,7 @@ (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")) (match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fnmsub.\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "")]) @@ -1127,7 +1127,7 @@ (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")) (match_operand:ANYF 2 "register_operand" " f") (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))] - "TARGET_HARD_FLOAT && !HONOR_SIGNED_ZEROS (mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SIGNED_ZEROS (mode)" "fmadd.\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "")]) @@ -1140,7 +1140,7 @@ (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")) (match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f"))))] - "TARGET_HARD_FLOAT && !HONOR_SIGNED_ZEROS (mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SIGNED_ZEROS (mode)" "fmsub.\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "")]) @@ -1153,7 +1153,7 @@ (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f"))))] - "TARGET_HARD_FLOAT && !HONOR_SIGNED_ZEROS (mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SIGNED_ZEROS (mode)" "fnmadd.\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "")]) @@ -1166,7 +1166,7 @@ (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f") (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))] - "TARGET_HARD_FLOAT && !HONOR_SIGNED_ZEROS (mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SIGNED_ZEROS (mode)" "fnmsub.\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "")]) @@ -1181,7 +1181,7 @@ (define_insn "abs2" [(set (match_operand:ANYF 0 "register_operand" "=f") (abs:ANYF (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fabs.\t%0,%1" [(set_attr "type" "fmove") (set_attr "mode" "")]) @@ -1191,7 +1191,7 @@ (unspec:ANYF [(match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")] UNSPEC_COPYSIGN))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fsgnj.\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "")]) @@ -1199,7 +1199,7 @@ (define_insn "neg2" [(set (match_operand:ANYF 0 "register_operand" "=f") (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fneg.\t%0,%1" [(set_attr "type" "fmove") (set_attr "mode" "")]) @@ -1216,7 +1216,7 @@ (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f")) (use (match_operand:ANYF 2 "register_operand" " f"))] UNSPEC_FMIN))] - "TARGET_HARD_FLOAT && !HONOR_SNANS (mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SNANS (mode)" "fmin.\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "")]) @@ -1226,7 +1226,7 @@ (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f")) (use (match_operand:ANYF 2 "register_operand" " f"))] UNSPEC_FMAX))] - "TARGET_HARD_FLOAT && !HONOR_SNANS (mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SNANS (mode)" "fmax.\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "")]) @@ -1235,7 +1235,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (smin:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmin.\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "")]) @@ -1244,7 +1244,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (smax:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmax.\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "")]) @@ -1305,7 +1305,7 @@ [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "register_operand" " f")))] - "TARGET_DOUBLE_FLOAT" + "TARGET_DOUBLE_FLOAT || TARGET_ZDINX" "fcvt.s.d\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF")]) @@ -1314,7 +1314,7 @@ [(set (match_operand:HF 0 "register_operand" "=f") (float_truncate:HF (match_operand:SF 1 "register_operand" " f")))] - "TARGET_ZFHMIN" + "TARGET_ZFHMIN || TARGET_ZHINXMIN" "fcvt.h.s\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "HF")]) @@ -1323,7 +1323,8 @@ [(set (match_operand:HF 0 "register_operand" "=f") (float_truncate:HF (match_operand:DF 1 "register_operand" " f")))] - "TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT" + "(TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT) || + (TARGET_ZHINXMIN && TARGET_ZDINX)" "fcvt.h.d\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "HF")]) @@ -1449,7 +1450,7 @@ [(set (match_operand:SF 0 "register_operand" "=f") (float_extend:SF (match_operand:HF 1 "register_operand" " f")))] - "TARGET_ZFHMIN" + "TARGET_ZFHMIN || TARGET_ZHINXMIN" "fcvt.s.h\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF")]) @@ -1458,7 +1459,7 @@ [(set (match_operand:DF 0 "register_operand" "=f") (float_extend:DF (match_operand:SF 1 "register_operand" " f")))] - "TARGET_DOUBLE_FLOAT" + "TARGET_DOUBLE_FLOAT || TARGET_ZDINX" "fcvt.d.s\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF")]) @@ -1467,7 +1468,8 @@ [(set (match_operand:DF 0 "register_operand" "=f") (float_extend:DF (match_operand:HF 1 "register_operand" " f")))] - "TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT" + "(TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT) || + (TARGET_ZHINXMIN && TARGET_ZDINX)" "fcvt.d.h\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF")]) @@ -1513,7 +1515,7 @@ [(set (match_operand:GPR 0 "register_operand" "=r") (fix:GPR (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.. %0,%1,rtz" [(set_attr "type" "fcvt") (set_attr "mode" "")]) @@ -1522,7 +1524,7 @@ [(set (match_operand:GPR 0 "register_operand" "=r") (unsigned_fix:GPR (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.u. %0,%1,rtz" [(set_attr "type" "fcvt") (set_attr "mode" "")]) @@ -1531,7 +1533,7 @@ [(set (match_operand:ANYF 0 "register_operand" "= f") (float:ANYF (match_operand:GPR 1 "reg_or_0_operand" " rJ")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt..\t%0,%z1" [(set_attr "type" "fcvt") (set_attr "mode" "")]) @@ -1540,7 +1542,7 @@ [(set (match_operand:ANYF 0 "register_operand" "= f") (unsigned_float:ANYF (match_operand:GPR 1 "reg_or_0_operand" " rJ")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt..u\t%0,%z1" [(set_attr "type" "fcvt") (set_attr "mode" "")]) @@ -1550,7 +1552,7 @@ (unspec:GPR [(match_operand:ANYF 1 "register_operand" " f")] RINT))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.. %0,%1," [(set_attr "type" "fcvt") (set_attr "mode" "")]) @@ -2278,7 +2280,7 @@ (match_operand:ANYF 2 "register_operand")]) (label_ref (match_operand 3 "")) (pc)))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" { riscv_expand_conditional_branch (operands[3], GET_CODE (operands[0]), operands[1], operands[2]); @@ -2367,7 +2369,7 @@ (match_operator:SI 1 "fp_scc_comparison" [(match_operand:ANYF 2 "register_operand") (match_operand:ANYF 3 "register_operand")]))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" { riscv_expand_float_scc (operands[0], GET_CODE (operands[1]), operands[2], operands[3]); @@ -2379,7 +2381,7 @@ (match_operator:X 1 "fp_native_comparison" [(match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f")]))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "f%C1.\t%0,%2,%3" [(set_attr "type" "fcmp") (set_attr "mode" "")]) @@ -2389,7 +2391,7 @@ (unspec:X [(match_operand:ANYF 1 "register_operand") (match_operand:ANYF 2 "register_operand")] QUIET_COMPARISON))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" { rtx op0 = operands[0]; rtx op1 = operands[1]; @@ -2809,19 +2811,19 @@ (define_insn "riscv_frflags" [(set (match_operand:SI 0 "register_operand" "=r") (unspec_volatile [(const_int 0)] UNSPECV_FRFLAGS))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "frflags\t%0") (define_insn "riscv_fsflags" [(unspec_volatile [(match_operand:SI 0 "csr_operand" "rK")] UNSPECV_FSFLAGS)] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fsflags\t%0") (define_insn "*riscv_fsnvsnan2" [(unspec_volatile [(match_operand:ANYF 0 "register_operand" "f") (match_operand:ANYF 1 "register_operand" "f")] UNSPECV_FSNVSNAN)] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "feq.\tzero,%0,%1" [(set_attr "type" "fcmp") (set_attr "mode" "")]) -- cgit v1.1 From 6b252dc96b52f5ab6f399c3f6b0c0b6614a36913 Mon Sep 17 00:00:00 2001 From: Jiawei Date: Thu, 20 Oct 2022 17:32:34 +0800 Subject: RISC-V: Limit regs use for z*inx extension. Limit z*inx abi support with 'ilp32','ilp32e','lp64' only. Use GPR instead FPR when 'zfinx' enable, Only use even registers in RV32 when 'zdinx' enable. Enable FLOAT16 when Zhinx/Zhinxmin enabled. Co-Authored-By: Sinan Lin gcc/ChangeLog: * config/riscv/constraints.md (TARGET_ZFINX ? GR_REGS): Set GPRS use while Zfinx is enable. * config/riscv/riscv.cc (riscv_hard_regno_mode_ok): Limit odd registers use when Zdinx enable in RV32 cases. (riscv_option_override): New target enable MASK_FDIV. (riscv_libgcc_floating_mode_supported_p): New error info when use incompatible arch&abi. (riscv_excess_precision): New target enable FLOAT16. --- gcc/config/riscv/constraints.md | 5 +++-- gcc/config/riscv/riscv.cc | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md index 951dcc5..4088c48 100644 --- a/gcc/config/riscv/constraints.md +++ b/gcc/config/riscv/constraints.md @@ -21,8 +21,9 @@ ;; Register constraints -(define_register_constraint "f" "TARGET_HARD_FLOAT ? FP_REGS : NO_REGS" - "A floating-point register (if available).") +(define_register_constraint "f" "TARGET_HARD_FLOAT ? FP_REGS : + (TARGET_ZFINX ? GR_REGS : NO_REGS)" + "A floating-point register (if available, reuse GPR as FPR when use zfinx).") (define_register_constraint "j" "SIBCALL_REGS" "@internal") diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 3d02954..77bc65b 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -5420,6 +5420,13 @@ riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode) != call_used_or_fixed_reg_p (regno + i)) return false; + /* Only use even registers in RV32 ZDINX */ + if (!TARGET_64BIT && TARGET_ZDINX){ + if (GET_MODE_CLASS (mode) == MODE_FLOAT && + GET_MODE_UNIT_SIZE (mode) == GET_MODE_SIZE (DFmode)) + return !(regno & 1); + } + return true; } @@ -5659,7 +5666,7 @@ riscv_option_override (void) error ("%<-mdiv%> requires %<-march%> to subsume the % extension"); /* Likewise floating-point division and square root. */ - if (TARGET_HARD_FLOAT && (target_flags_explicit & MASK_FDIV) == 0) + if ((TARGET_HARD_FLOAT || TARGET_ZFINX) && (target_flags_explicit & MASK_FDIV) == 0) target_flags |= MASK_FDIV; /* Handle -mtune, use -mcpu if -mtune is not given, and use default -mtune @@ -5705,6 +5712,11 @@ riscv_option_override (void) if (TARGET_RVE && riscv_abi != ABI_ILP32E) error ("rv32e requires ilp32e ABI"); + // Zfinx require abi ilp32,ilp32e or lp64. + if (TARGET_ZFINX && riscv_abi != ABI_ILP32 + && riscv_abi != ABI_LP64 && riscv_abi != ABI_ILP32E) + error ("z*inx requires ABI ilp32, ilp32e or lp64"); + /* We do not yet support ILP32 on RV64. */ if (BITS_PER_WORD != POINTER_SIZE) error ("ABI requires %<-march=rv%d%>", POINTER_SIZE); @@ -6337,7 +6349,7 @@ riscv_libgcc_floating_mode_supported_p (scalar_float_mode mode) precision of the _FloatN type; evaluate all other operations and constants to the range and precision of the semantic type; - If we have the zfh extensions then we support _Float16 in native + If we have the zfh/zhinx extensions then we support _Float16 in native precision, so we should set this to 16. */ static enum flt_eval_method riscv_excess_precision (enum excess_precision_type type) @@ -6346,8 +6358,9 @@ riscv_excess_precision (enum excess_precision_type type) { case EXCESS_PRECISION_TYPE_FAST: case EXCESS_PRECISION_TYPE_STANDARD: - return (TARGET_ZFH ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 - : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT); + return ((TARGET_ZFH || TARGET_ZHINX) + ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 + : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT); case EXCESS_PRECISION_TYPE_IMPLICIT: case EXCESS_PRECISION_TYPE_FLOAT16: return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16; -- cgit v1.1 From 27065374f172f05110b68fe1f452eed414c837bd Mon Sep 17 00:00:00 2001 From: Jiawei Date: Thu, 20 Oct 2022 17:32:35 +0800 Subject: RISC-V: Add zhinx/zhinxmin testcases. Test zhinx/zhinxmin support, same like with zfh/zfhmin testcases but use gprs and don't use fmv instruction. gcc/testsuite/ChangeLog: * gcc.target/riscv/_Float16-zhinx-1.c: New test. * gcc.target/riscv/_Float16-zhinx-2.c: New test. * gcc.target/riscv/_Float16-zhinx-3.c: New test. * gcc.target/riscv/_Float16-zhinxmin-1.c: New test. * gcc.target/riscv/_Float16-zhinxmin-2.c: New test. * gcc.target/riscv/_Float16-zhinxmin-3.c: New test. --- gcc/testsuite/gcc.target/riscv/_Float16-zhinx-1.c | 10 ++++++++++ gcc/testsuite/gcc.target/riscv/_Float16-zhinx-2.c | 9 +++++++++ gcc/testsuite/gcc.target/riscv/_Float16-zhinx-3.c | 9 +++++++++ gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-1.c | 10 ++++++++++ gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-2.c | 10 ++++++++++ gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c | 10 ++++++++++ 6 files changed, 58 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zhinx-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zhinx-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zhinx-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-1.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-1.c new file mode 100644 index 0000000..90172b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinx -mabi=lp64 -O" } */ + +_Float16 foo1 (_Float16 a, _Float16 b) +{ + return b; +} + +/* { dg-final { scan-assembler-not "fmv.h" } } */ +/* { dg-final { scan-assembler-times "mv" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-2.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-2.c new file mode 100644 index 0000000..26f0119 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinx -mabi=lp64 -O" } */ + +_Float16 foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fadd.h fa" } } */ + /* { dg-final { scan-assembler-times "fadd.h a" 1 } } */ + return a + b; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-3.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-3.c new file mode 100644 index 0000000..5739135 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-3.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinx -mabi=lp64 -O" } */ + +int foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fgt.h fa" } } */ + /* { dg-final { scan-assembler-times "fgt.h a" 1 } } */ + return a > b; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-1.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-1.c new file mode 100644 index 0000000..0070ebf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinxmin -mabi=lp64 -O" } */ + +_Float16 foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fmv.h" } } */ + /* { dg-final { scan-assembler-not "fmv.s" } } */ + /* { dg-final { scan-assembler-times "mv" 1 } } */ + return b; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-2.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-2.c new file mode 100644 index 0000000..17f45a9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinxmin -mabi=lp64 -O" } */ + +_Float16 foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fadd.h" } } */ + /* { dg-final { scan-assembler-not "fadd.s fa" } } */ + /* { dg-final { scan-assembler-times "fadd.s a" 1 } } */ + return a + b; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c new file mode 100644 index 0000000..7a43641 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */ + +int foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fgt.h" } } */ + /* { dg-final { scan-assembler-not "fgt.s fa" } } */ + /* { dg-final { scan-assembler-times "fgt.s a" 1 } } */ + return a > b; +} -- cgit v1.1 From 4e1d704243a4f3c4ded47cd0d02427bb7efef069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20SVENSSON?= Date: Tue, 25 Oct 2022 11:45:40 +0200 Subject: IRA: Make sure array is big enough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 081c96621da, the call to resize_reg_info() was moved before the call to remove_scratches() and the latter one can increase the number of regs and that would cause an out of bounds usage on the reg_renumber global array. Without this patch, the following testcase randomly fails with: during RTL pass: ira In file included from /src/gcc/testsuite/gcc.dg/compat/struct-by-value-5b_y.c:13: /src/gcc/testsuite/gcc.dg/compat/struct-by-value-5b_y.c: In function 'checkgSf13': /src/gcc/testsuite/gcc.dg/compat/fp-struct-test-by-value-y.h:28:1: internal compiler error: Segmentation fault /src/gcc/testsuite/gcc.dg/compat/struct-by-value-5b_y.c:22:1: note: in expansion of macro 'TEST' gcc/ChangeLog: * ira.cc: Resize array after reg number increased. Co-Authored-By: Yvan ROUX Signed-off-by: Torbjörn SVENSSON --- gcc/ira.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc') diff --git a/gcc/ira.cc b/gcc/ira.cc index 42c9cea..d28a67b 100644 --- a/gcc/ira.cc +++ b/gcc/ira.cc @@ -5718,6 +5718,7 @@ ira (FILE *f) regstat_free_ri (); regstat_init_n_sets_and_refs (); regstat_compute_ri (); + resize_reg_info (); }; int max_regno_before_rm = max_reg_num (); -- cgit v1.1 From bfb7994a9fb0b10767d12b8d670c081014ad8b01 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 27 Oct 2022 10:24:45 +0200 Subject: c++: Fix excess precision related ICE on invalid binop [PR107382, PR107383] The following tests ICE in the gcc_assert (common); in cp_build_binary_op. I've missed that while for * common is set always, while for +, - and / it is in some cases not. If it is not, then if (!result_type && arithmetic_types_p && (shorten || common || short_compare)) condition is false, then the following if (may_need_excess_precision && (orig_type0 != type0 || orig_type1 != type1) && build_type == NULL_TREE) would fail the assertion there and if there wouldn't be excess precision, if (code == SPACESHIP_EXPR) would be false (for SPACESHIP_EXPR we always have build_type set like for other comparisons) and then trigger if (!result_type) { if (complain & tf_error) { binary_op_rich_location richloc (location, orig_op0, orig_op1, true); error_at (&richloc, "invalid operands of types %qT and %qT to binary %qO", TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code); } return error_mark_node; } So, if result_type is NULL, we don't really need to compute semantic_result_type because nothing will use it anyway and can get fall through into the error/return error_mark_node; case. 2022-10-27 Jakub Jelinek PR c++/107382 PR c++/107383 * typeck.cc (cp_build_binary_op): Don't compute semantic_result_type if result_type is NULL. * g++.dg/diagnostic/bad-binary-ops2.C: New test. --- gcc/cp/typeck.cc | 3 ++- gcc/testsuite/g++.dg/diagnostic/bad-binary-ops2.C | 26 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/diagnostic/bad-binary-ops2.C (limited to 'gcc') diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 4605f73..2e0fd8f 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -6179,7 +6179,8 @@ cp_build_binary_op (const op_location_t &location, } if (may_need_excess_precision && (orig_type0 != type0 || orig_type1 != type1) - && build_type == NULL_TREE) + && build_type == NULL_TREE + && result_type) { gcc_assert (common); semantic_result_type = cp_common_type (orig_type0, orig_type1); diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops2.C b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops2.C new file mode 100644 index 0000000..627e8a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops2.C @@ -0,0 +1,26 @@ +// PR c++/107382 +// PR c++/107383 +// { dg-do compile } +// { dg-options "-O2 -fexcess-precision=standard" } + +void +foo () +{ + float t[2] = { 1, 2 }; + int const *s = 0; + t[1] / s; // { dg-error "invalid operands of types 'float' and 'const int\\\*' to binary 'operator/'" } +} + +void +bar () +{ + float t[2] = { 1, 2 }; + int const *s[2] = { 0, 0 }; + t[1] / s[0]; // { dg-error "invalid operands of types 'float' and 'const int\\\*' to binary 'operator/'" } +} + +void +baz (float a, int* b) +{ + a -= b; // { dg-error "invalid operands of types 'float' and 'int\\\*' to binary 'operator-'" } +} -- cgit v1.1 From be6c75547385c69706370f4e792b04295f708a5a Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 27 Oct 2022 10:29:17 +0200 Subject: lto: do not load LTO stream for aliases [PR107418] PR lto/107418 gcc/lto/ChangeLog: * lto-dump.cc (lto_main): Do not load LTO stream for aliases. --- gcc/lto/lto-dump.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/lto/lto-dump.cc b/gcc/lto/lto-dump.cc index f3d852d..cb97827 100644 --- a/gcc/lto/lto-dump.cc +++ b/gcc/lto/lto-dump.cc @@ -347,7 +347,8 @@ lto_main (void) /* Dump gimple statement statistics. */ cgraph_node *node; FOR_EACH_DEFINED_FUNCTION (node) - node->get_untransformed_body (); + if (!node->alias) + node->get_untransformed_body (); if (!GATHER_STATISTICS) warning_at (input_location, 0, "Not configured with " -- cgit v1.1 From 9119431bc1563217c7c770035b0456d1e2bc596d Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Thu, 31 Mar 2022 12:06:29 +0200 Subject: options: Clarify 'Init' option property usage for streaming optimization This clarifies commit 95db7e9afe57ca1c269d46baa2accced004e5c74 "options, lto: Optimize streaming of optimization nodes". No functional change; no change in generated files. gcc/ * optc-save-gen.awk: Clarify 'Init' option property usage for streaming optimization. --- gcc/optc-save-gen.awk | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk index 49065ce..2b8557f 100644 --- a/gcc/optc-save-gen.awk +++ b/gcc/optc-save-gen.awk @@ -1291,7 +1291,22 @@ for (i = 0; i < n_opts; i++) { var_opt_val_type[n_opt_val] = otype; var_opt_val[n_opt_val] = "x_" name; var_opt_hash[n_opt_val] = flag_set_p("Optimization", flags[i]); - var_opt_init[n_opt_val] = opt_args("Init", flags[i]); + + # If applicable, optimize streaming for the common case that + # the current value is unchanged from the 'Init' value: + # XOR-encode it so that we stream value zero. + # Not handling non-parameters as those really generally don't + # have large initializers. + # Not handling enums as we don't know if '(enum ...) 10' is + # even valid (see synthesized 'if' conditionals below). + if (flag_set_p("Param", flags[i]) \ + && !(otype ~ "^enum ")) { + # Those without 'Init' are zero-initialized and thus + # already encoded ideally. + init = opt_args("Init", flags[i]) + var_opt_optimize_init[n_opt_val] = init; + } + n_opt_val++; } } @@ -1369,9 +1384,10 @@ for (i = 0; i < n_opt_val; i++) { } else { sgn = "int"; } - if (name ~ "^x_param" && !(otype ~ "^enum ") && var_opt_init[i]) { - print " if (" var_opt_init[i] " > (" var_opt_val_type[i] ") 10)"; - print " bp_pack_var_len_" sgn " (bp, ptr->" name" ^ " var_opt_init[i] ");"; + # If applicable, encode the streamed value. + if (var_opt_optimize_init[i]) { + print " if (" var_opt_optimize_init[i] " > (" var_opt_val_type[i] ") 10)"; + print " bp_pack_var_len_" sgn " (bp, ptr->" name" ^ " var_opt_optimize_init[i] ");"; print " else"; print " bp_pack_var_len_" sgn " (bp, ptr->" name");"; } else { @@ -1405,9 +1421,10 @@ for (i = 0; i < n_opt_val; i++) { sgn = "int"; } print " ptr->" name" = (" var_opt_val_type[i] ") bp_unpack_var_len_" sgn " (bp);"; - if (name ~ "^x_param" && !(otype ~ "^enum ") && var_opt_init[i]) { - print " if (" var_opt_init[i] " > (" var_opt_val_type[i] ") 10)"; - print " ptr->" name" ^= " var_opt_init[i] ";"; + # If applicable, decode the streamed value. + if (var_opt_optimize_init[i]) { + print " if (" var_opt_optimize_init[i] " > (" var_opt_val_type[i] ") 10)"; + print " ptr->" name" ^= " var_opt_optimize_init[i] ";"; } } } -- cgit v1.1 From 2b1fb720818a85d5c893ce65d140add40debf2ff Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 25 Oct 2022 22:44:51 +0200 Subject: [PR tree-optimization/107394] Canonicalize global franges as they are read back. The problem here is that we're inlining a global range with NANs into a function that has been tagged with __attribute__((optimize ("-ffinite-math-only"))). As the global range is copied from SSA_NAME_RANGE_INFO, its NAN bits are copied, which then cause frange::verify_range() to fail a sanity check making sure no NANs creep in when !HONOR_NANS. I think what we should do is nuke the NAN bits as we're restoring the global range. For that matter, if we use the frange constructor, everything except that NAN sign will be done automatically, including dropping INFs to the min/max representable range when appropriate. PR tree-optimization/107394 gcc/ChangeLog: * value-range-storage.cc (frange_storage_slot::get_frange): Use frange constructor. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr107394.c: New test. --- gcc/testsuite/gcc.dg/tree-ssa/pr107394.c | 22 +++++++++++++++++++++ gcc/value-range-storage.cc | 33 +++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr107394.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107394.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107394.c new file mode 100644 index 0000000..0e1e5ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107394.c @@ -0,0 +1,22 @@ +// { dg-do compile } +// { dg-options "-O2" } + +static double +quux (double x) +{ + return __builtin_fabs (x); +} + +__attribute__ ((flatten, optimize ("-ffinite-math-only"))) static int +bar (int *p) +{ + *p = quux (0.0); + + return 0; +} + +void +foo (int *p) +{ + (void) bar (p); +} diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc index 6e05462..462447b 100644 --- a/gcc/value-range-storage.cc +++ b/gcc/value-range-storage.cc @@ -261,17 +261,28 @@ frange_storage_slot::get_frange (frange &r, tree type) const { gcc_checking_assert (r.supports_type_p (type)); - r.set_undefined (); - r.m_kind = m_kind; - r.m_type = type; - r.m_min = m_min; - r.m_max = m_max; - r.m_pos_nan = m_pos_nan; - r.m_neg_nan = m_neg_nan; - r.normalize_kind (); - - if (flag_checking) - r.verify_range (); + // Handle explicit NANs. + if (m_kind == VR_NAN) + { + if (HONOR_NANS (type)) + { + if (m_pos_nan && m_neg_nan) + r.set_nan (type); + else + r.set_nan (type, m_neg_nan); + } + else + r.set_undefined (); + return; + } + + // Use the constructor because it will canonicalize the range. + r = frange (type, m_min, m_max, m_kind); + + // The constructor will set the NAN bits for HONOR_NANS, but we must + // make sure to set the NAN sign if known. + if (HONOR_NANS (type) && (m_pos_nan ^ m_neg_nan) == 1) + r.update_nan (m_neg_nan); } bool -- cgit v1.1 From f95d3d5de72a1c43e8d529bad3ef59afc3214705 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 27 Oct 2022 14:20:23 +0100 Subject: aarch64: Reinstate some uses of CONSTEXPR In 9482a5e4eac8d696129ec2854b331e1bb5dbab42 I'd replaced uses of CONSTEXPR with direct uses of constexpr. However, it turns out that we still have CONSTEXPR for a reason: GCC 4.8 doesn't implement constexpr properly, and for example rejects things like: extern const int x; constexpr int x = 1; This patch partially reverts the previous one. To make things more complicated, there are still some things that need to be constexpr rather than CONSTEXPR, since they are used to initialise scalar constants. The patch therefore doesn't change anything in aarch64-feature-deps.h. gcc/ * config/aarch64/aarch64-protos.h: Replace constexpr with CONSTEXPR. * config/aarch64/aarch64-sve-builtins-base.cc: Likewise. * config/aarch64/aarch64-sve-builtins-functions.h: Likewise. * config/aarch64/aarch64-sve-builtins-shapes.cc: Likewise. * config/aarch64/aarch64-sve-builtins-sve2.cc: Likewise. * config/aarch64/aarch64-sve-builtins.cc: Likewise. * config/aarch64/aarch64.cc: Likewise. * config/aarch64/driver-aarch64.cc: Likewise --- gcc/config/aarch64/aarch64-protos.h | 6 +-- gcc/config/aarch64/aarch64-sve-builtins-base.cc | 56 +++++++++++----------- .../aarch64/aarch64-sve-builtins-functions.h | 28 +++++------ gcc/config/aarch64/aarch64-sve-builtins-shapes.cc | 8 ++-- gcc/config/aarch64/aarch64-sve-builtins-sve2.cc | 12 ++--- gcc/config/aarch64/aarch64-sve-builtins.cc | 8 ++-- gcc/config/aarch64/aarch64.cc | 2 +- gcc/config/aarch64/driver-aarch64.cc | 4 +- 8 files changed, 62 insertions(+), 62 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 1a71f02..2388205 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -254,7 +254,7 @@ typedef struct simd_vec_cost advsimd_vec_cost; /* SVE-specific extensions to the information provided by simd_vec_cost. */ struct sve_vec_cost : simd_vec_cost { - constexpr sve_vec_cost (const simd_vec_cost &base, + CONSTEXPR sve_vec_cost (const simd_vec_cost &base, unsigned int clast_cost, unsigned int fadda_f16_cost, unsigned int fadda_f32_cost, @@ -354,7 +354,7 @@ using aarch64_scalar_vec_issue_info = aarch64_base_vec_issue_info; Advanced SIMD and SVE. */ struct aarch64_simd_vec_issue_info : aarch64_base_vec_issue_info { - constexpr aarch64_simd_vec_issue_info (aarch64_base_vec_issue_info base, + CONSTEXPR aarch64_simd_vec_issue_info (aarch64_base_vec_issue_info base, unsigned int ld2_st2_general_ops, unsigned int ld3_st3_general_ops, unsigned int ld4_st4_general_ops) @@ -382,7 +382,7 @@ using aarch64_advsimd_vec_issue_info = aarch64_simd_vec_issue_info; is a concept of "predicate operations". */ struct aarch64_sve_vec_issue_info : aarch64_simd_vec_issue_info { - constexpr aarch64_sve_vec_issue_info + CONSTEXPR aarch64_sve_vec_issue_info (aarch64_simd_vec_issue_info base, unsigned int pred_ops_per_cycle, unsigned int while_pred_ops, diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc b/gcc/config/aarch64/aarch64-sve-builtins-base.cc index 23b4d42..6347407 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc @@ -177,7 +177,7 @@ public: class svac_impl : public function_base { public: - constexpr svac_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svac_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -209,7 +209,7 @@ public: class svadr_bhwd_impl : public function_base { public: - constexpr svadr_bhwd_impl (unsigned int shift) : m_shift (shift) {} + CONSTEXPR svadr_bhwd_impl (unsigned int shift) : m_shift (shift) {} rtx expand (function_expander &e) const override @@ -259,7 +259,7 @@ public: class svbrk_binary_impl : public function_base { public: - constexpr svbrk_binary_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svbrk_binary_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -275,7 +275,7 @@ public: class svbrk_unary_impl : public function_base { public: - constexpr svbrk_unary_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svbrk_unary_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -309,7 +309,7 @@ public: class svclast_impl : public quiet { public: - constexpr svclast_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svclast_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -381,7 +381,7 @@ public: class svcmp_impl : public function_base { public: - constexpr svcmp_impl (tree_code code, int unspec_for_fp) + CONSTEXPR svcmp_impl (tree_code code, int unspec_for_fp) : m_code (code), m_unspec_for_fp (unspec_for_fp) {} gimple * @@ -437,7 +437,7 @@ public: class svcmp_wide_impl : public function_base { public: - constexpr svcmp_wide_impl (tree_code code, int unspec_for_sint, + CONSTEXPR svcmp_wide_impl (tree_code code, int unspec_for_sint, int unspec_for_uint) : m_code (code), m_unspec_for_sint (unspec_for_sint), m_unspec_for_uint (unspec_for_uint) {} @@ -512,7 +512,7 @@ public: class svcnt_bhwd_impl : public function_base { public: - constexpr svcnt_bhwd_impl (machine_mode ref_mode) : m_ref_mode (ref_mode) {} + CONSTEXPR svcnt_bhwd_impl (machine_mode ref_mode) : m_ref_mode (ref_mode) {} gimple * fold (gimple_folder &f) const override @@ -949,7 +949,7 @@ public: class svext_bhw_impl : public function_base { public: - constexpr svext_bhw_impl (scalar_int_mode from_mode) + CONSTEXPR svext_bhw_impl (scalar_int_mode from_mode) : m_from_mode (from_mode) {} rtx @@ -1053,7 +1053,7 @@ public: class svlast_impl : public quiet { public: - constexpr svlast_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svlast_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -1399,7 +1399,7 @@ public: class svldxf1_impl : public full_width_access { public: - constexpr svldxf1_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svldxf1_impl (int unspec) : m_unspec (unspec) {} unsigned int call_properties (const function_instance &) const override @@ -1426,7 +1426,7 @@ public: class svldxf1_extend_impl : public extending_load { public: - constexpr svldxf1_extend_impl (type_suffix_index memory_type, int unspec) + CONSTEXPR svldxf1_extend_impl (type_suffix_index memory_type, int unspec) : extending_load (memory_type), m_unspec (unspec) {} unsigned int @@ -1616,7 +1616,7 @@ public: class svnot_impl : public rtx_code_function { public: - constexpr svnot_impl () : rtx_code_function (NOT, NOT, -1) {} + CONSTEXPR svnot_impl () : rtx_code_function (NOT, NOT, -1) {} rtx expand (function_expander &e) const override @@ -1664,7 +1664,7 @@ public: class svpfirst_svpnext_impl : public function_base { public: - constexpr svpfirst_svpnext_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svpfirst_svpnext_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -1682,7 +1682,7 @@ public: class svprf_bhwd_impl : public function_base { public: - constexpr svprf_bhwd_impl (machine_mode mode) : m_mode (mode) {} + CONSTEXPR svprf_bhwd_impl (machine_mode mode) : m_mode (mode) {} unsigned int call_properties (const function_instance &) const override @@ -1706,7 +1706,7 @@ public: class svprf_bhwd_gather_impl : public function_base { public: - constexpr svprf_bhwd_gather_impl (machine_mode mode) : m_mode (mode) {} + CONSTEXPR svprf_bhwd_gather_impl (machine_mode mode) : m_mode (mode) {} unsigned int call_properties (const function_instance &) const override @@ -1744,7 +1744,7 @@ public: class svptest_impl : public function_base { public: - constexpr svptest_impl (rtx_code compare) : m_compare (compare) {} + CONSTEXPR svptest_impl (rtx_code compare) : m_compare (compare) {} rtx expand (function_expander &e) const override @@ -1849,7 +1849,7 @@ public: class svqdec_svqinc_bhwd_impl : public function_base { public: - constexpr svqdec_svqinc_bhwd_impl (rtx_code code_for_sint, + CONSTEXPR svqdec_svqinc_bhwd_impl (rtx_code code_for_sint, rtx_code code_for_uint, scalar_int_mode elem_mode) : m_code_for_sint (code_for_sint), @@ -1896,7 +1896,7 @@ public: class svqdec_bhwd_impl : public svqdec_svqinc_bhwd_impl { public: - constexpr svqdec_bhwd_impl (scalar_int_mode elem_mode) + CONSTEXPR svqdec_bhwd_impl (scalar_int_mode elem_mode) : svqdec_svqinc_bhwd_impl (SS_MINUS, US_MINUS, elem_mode) {} }; @@ -1904,7 +1904,7 @@ public: class svqinc_bhwd_impl : public svqdec_svqinc_bhwd_impl { public: - constexpr svqinc_bhwd_impl (scalar_int_mode elem_mode) + CONSTEXPR svqinc_bhwd_impl (scalar_int_mode elem_mode) : svqdec_svqinc_bhwd_impl (SS_PLUS, US_PLUS, elem_mode) {} }; @@ -1912,7 +1912,7 @@ public: class svqdecp_svqincp_impl : public function_base { public: - constexpr svqdecp_svqincp_impl (rtx_code code_for_sint, + CONSTEXPR svqdecp_svqincp_impl (rtx_code code_for_sint, rtx_code code_for_uint) : m_code_for_sint (code_for_sint), m_code_for_uint (code_for_uint) @@ -2275,7 +2275,7 @@ public: class svsub_impl : public rtx_code_function { public: - constexpr svsub_impl () + CONSTEXPR svsub_impl () : rtx_code_function (MINUS, MINUS, UNSPEC_COND_FSUB) {} rtx @@ -2304,7 +2304,7 @@ public: class svtrn_impl : public binary_permute { public: - constexpr svtrn_impl (int base) + CONSTEXPR svtrn_impl (int base) : binary_permute (base ? UNSPEC_TRN2 : UNSPEC_TRN1), m_base (base) {} gimple * @@ -2345,7 +2345,7 @@ public: class svunpk_impl : public quiet { public: - constexpr svunpk_impl (bool high_p) : m_high_p (high_p) {} + CONSTEXPR svunpk_impl (bool high_p) : m_high_p (high_p) {} gimple * fold (gimple_folder &f) const override @@ -2387,7 +2387,7 @@ public: class svusdot_impl : public function_base { public: - constexpr svusdot_impl (bool su) : m_su (su) {} + CONSTEXPR svusdot_impl (bool su) : m_su (su) {} rtx expand (function_expander &e) const override @@ -2415,7 +2415,7 @@ private: class svuzp_impl : public binary_permute { public: - constexpr svuzp_impl (unsigned int base) + CONSTEXPR svuzp_impl (unsigned int base) : binary_permute (base ? UNSPEC_UZP2 : UNSPEC_UZP1), m_base (base) {} gimple * @@ -2438,7 +2438,7 @@ public: class svwhilelx_impl : public while_comparison { public: - constexpr svwhilelx_impl (int unspec_for_sint, int unspec_for_uint, bool eq_p) + CONSTEXPR svwhilelx_impl (int unspec_for_sint, int unspec_for_uint, bool eq_p) : while_comparison (unspec_for_sint, unspec_for_uint), m_eq_p (eq_p) {} @@ -2525,7 +2525,7 @@ public: class svzip_impl : public binary_permute { public: - constexpr svzip_impl (unsigned int base) + CONSTEXPR svzip_impl (unsigned int base) : binary_permute (base ? UNSPEC_ZIP2 : UNSPEC_ZIP1), m_base (base) {} gimple * diff --git a/gcc/config/aarch64/aarch64-sve-builtins-functions.h b/gcc/config/aarch64/aarch64-sve-builtins-functions.h index ec943c5..472e26c 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-functions.h +++ b/gcc/config/aarch64/aarch64-sve-builtins-functions.h @@ -44,7 +44,7 @@ public: class multi_vector_function : public function_base { public: - constexpr multi_vector_function (unsigned int vectors_per_tuple) + CONSTEXPR multi_vector_function (unsigned int vectors_per_tuple) : m_vectors_per_tuple (vectors_per_tuple) {} unsigned int @@ -63,7 +63,7 @@ public: class full_width_access : public multi_vector_function { public: - constexpr full_width_access (unsigned int vectors_per_tuple = 1) + CONSTEXPR full_width_access (unsigned int vectors_per_tuple = 1) : multi_vector_function (vectors_per_tuple) {} tree @@ -88,7 +88,7 @@ public: class extending_load : public function_base { public: - constexpr extending_load (type_suffix_index memory_type) + CONSTEXPR extending_load (type_suffix_index memory_type) : m_memory_type (memory_type) {} unsigned int @@ -131,7 +131,7 @@ public: class truncating_store : public function_base { public: - constexpr truncating_store (scalar_int_mode to_mode) : m_to_mode (to_mode) {} + CONSTEXPR truncating_store (scalar_int_mode to_mode) : m_to_mode (to_mode) {} unsigned int call_properties (const function_instance &) const override @@ -168,7 +168,7 @@ public: class rtx_code_function_base : public function_base { public: - constexpr rtx_code_function_base (rtx_code code_for_sint, + CONSTEXPR rtx_code_function_base (rtx_code code_for_sint, rtx_code code_for_uint, int unspec_for_fp = -1) : m_code_for_sint (code_for_sint), m_code_for_uint (code_for_uint), @@ -227,7 +227,7 @@ public: class unspec_based_function_base : public function_base { public: - constexpr unspec_based_function_base (int unspec_for_sint, + CONSTEXPR unspec_based_function_base (int unspec_for_sint, int unspec_for_uint, int unspec_for_fp) : m_unspec_for_sint (unspec_for_sint), @@ -434,7 +434,7 @@ public: class fixed_insn_function : public function_base { public: - constexpr fixed_insn_function (insn_code code) : m_code (code) {} + CONSTEXPR fixed_insn_function (insn_code code) : m_code (code) {} rtx expand (function_expander &e) const override @@ -476,7 +476,7 @@ public: class binary_permute : public permute { public: - constexpr binary_permute (int unspec) : m_unspec (unspec) {} + CONSTEXPR binary_permute (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -493,13 +493,13 @@ public: class reduction : public function_base { public: - constexpr reduction (int unspec) + CONSTEXPR reduction (int unspec) : m_unspec_for_sint (unspec), m_unspec_for_uint (unspec), m_unspec_for_fp (unspec) {} - constexpr reduction (int unspec_for_sint, int unspec_for_uint, + CONSTEXPR reduction (int unspec_for_sint, int unspec_for_uint, int unspec_for_fp) : m_unspec_for_sint (unspec_for_sint), m_unspec_for_uint (unspec_for_uint), @@ -532,7 +532,7 @@ public: class shift_wide : public function_base { public: - constexpr shift_wide (rtx_code code, int wide_unspec) + CONSTEXPR shift_wide (rtx_code code, int wide_unspec) : m_code (code), m_wide_unspec (wide_unspec) {} rtx @@ -567,7 +567,7 @@ public: class unary_count : public quiet { public: - constexpr unary_count (rtx_code code) : m_code (code) {} + CONSTEXPR unary_count (rtx_code code) : m_code (code) {} rtx expand (function_expander &e) const override @@ -590,7 +590,7 @@ public: class while_comparison : public function_base { public: - constexpr while_comparison (int unspec_for_sint, int unspec_for_uint) + CONSTEXPR while_comparison (int unspec_for_sint, int unspec_for_uint) : m_unspec_for_sint (unspec_for_sint), m_unspec_for_uint (unspec_for_uint) {} @@ -619,7 +619,7 @@ public: /* Declare the global function base NAME, creating it from an instance of class CLASS with constructor arguments ARGS. */ #define FUNCTION(NAME, CLASS, ARGS) \ - namespace { static constexpr const CLASS NAME##_obj ARGS; } \ + namespace { static CONSTEXPR const CLASS NAME##_obj ARGS; } \ namespace functions { const function_base *const NAME = &NAME##_obj; } #endif diff --git a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc index bf1d05e..8e26bd8 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc @@ -447,7 +447,7 @@ long_type_suffix (function_resolver &r, type_suffix_index type) /* Declare the function shape NAME, pointing it to an instance of class _def. */ #define SHAPE(NAME) \ - static constexpr const NAME##_def NAME##_obj; \ + static CONSTEXPR const NAME##_def NAME##_obj; \ namespace shapes { const function_shape *const NAME = &NAME##_obj; } /* Base class for functions that are not overloaded. */ @@ -587,7 +587,7 @@ struct binary_imm_long_base : public overloaded_base<0> /* Base class for inc_dec and inc_dec_pat. */ struct inc_dec_base : public overloaded_base<0> { - constexpr inc_dec_base (bool pat_p) : m_pat_p (pat_p) {} + CONSTEXPR inc_dec_base (bool pat_p) : m_pat_p (pat_p) {} /* Resolve based on the first argument only, which must be either a scalar or a vector. If it's a scalar, it must be a 32-bit or @@ -1924,7 +1924,7 @@ SHAPE (get) whose size is tied to the [bhwd] suffix of "svfoo". */ struct inc_dec_def : public inc_dec_base { - constexpr inc_dec_def () : inc_dec_base (false) {} + CONSTEXPR inc_dec_def () : inc_dec_base (false) {} void build (function_builder &b, const function_group_info &group) const override @@ -1949,7 +1949,7 @@ SHAPE (inc_dec) whose size is tied to the [bhwd] suffix of "svfoo". */ struct inc_dec_pat_def : public inc_dec_base { - constexpr inc_dec_pat_def () : inc_dec_base (true) {} + CONSTEXPR inc_dec_pat_def () : inc_dec_base (true) {} void build (function_builder &b, const function_group_info &group) const override diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc index ca8f20d..a7d7435 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc @@ -158,7 +158,7 @@ public: class svmatch_svnmatch_impl : public function_base { public: - constexpr svmatch_svnmatch_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svmatch_svnmatch_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -233,7 +233,7 @@ public: class svqrshl_impl : public unspec_based_function { public: - constexpr svqrshl_impl () + CONSTEXPR svqrshl_impl () : unspec_based_function (UNSPEC_SQRSHL, UNSPEC_UQRSHL, -1) {} gimple * @@ -267,7 +267,7 @@ public: class svqshl_impl : public unspec_based_function { public: - constexpr svqshl_impl () + CONSTEXPR svqshl_impl () : unspec_based_function (UNSPEC_SQSHL, UNSPEC_UQSHL, -1) {} gimple * @@ -303,7 +303,7 @@ public: class svrshl_impl : public unspec_based_function { public: - constexpr svrshl_impl () + CONSTEXPR svrshl_impl () : unspec_based_function (UNSPEC_SRSHL, UNSPEC_URSHL, -1) {} gimple * @@ -403,7 +403,7 @@ public: class svtbl2_impl : public quiet { public: - constexpr svtbl2_impl () : quiet (2) {} + CONSTEXPR svtbl2_impl () : quiet (2) {} rtx expand (function_expander &e) const override @@ -431,7 +431,7 @@ public: class svwhilerw_svwhilewr_impl : public full_width_access { public: - constexpr svwhilerw_svwhilewr_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svwhilerw_svwhilewr_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc index 37228f6..e168c83 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -99,7 +99,7 @@ struct registered_function_hasher : nofree_ptr_hash }; /* Information about each single-predicate or single-vector type. */ -static constexpr const vector_type_info vector_types[] = { +static CONSTEXPR const vector_type_info vector_types[] = { #define DEF_SVE_TYPE(ACLE_NAME, NCHARS, ABI_NAME, SCALAR_TYPE) \ { #ACLE_NAME, #ABI_NAME, "u" #NCHARS #ABI_NAME }, #include "aarch64-sve-builtins.def" @@ -116,7 +116,7 @@ static const char *const pred_suffixes[NUM_PREDS + 1] = { }; /* Static information about each mode_suffix_index. */ -constexpr const mode_suffix_info mode_suffixes[] = { +CONSTEXPR const mode_suffix_info mode_suffixes[] = { #define VECTOR_TYPE_none NUM_VECTOR_TYPES #define DEF_SVE_MODE(NAME, BASE, DISPLACEMENT, UNITS) \ { "_" #NAME, VECTOR_TYPE_##BASE, VECTOR_TYPE_##DISPLACEMENT, UNITS_##UNITS }, @@ -126,7 +126,7 @@ constexpr const mode_suffix_info mode_suffixes[] = { }; /* Static information about each type_suffix_index. */ -constexpr const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = { +CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = { #define DEF_SVE_TYPE_SUFFIX(NAME, ACLE_TYPE, CLASS, BITS, MODE) \ { "_" #NAME, \ VECTOR_TYPE_##ACLE_TYPE, \ @@ -522,7 +522,7 @@ static const predication_index preds_z_or_none[] = { static const predication_index preds_z[] = { PRED_z, NUM_PREDS }; /* A list of all SVE ACLE functions. */ -static constexpr const function_group_info function_groups[] = { +static CONSTEXPR const function_group_info function_groups[] = { #define DEF_SVE_FUNCTION(NAME, SHAPE, TYPES, PREDS) \ { #NAME, &functions::NAME, &shapes::SHAPE, types_##TYPES, preds_##PREDS, \ REQUIRED_EXTENSIONS | AARCH64_FL_SVE }, diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 5d1ab5a..0458c65 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -2679,7 +2679,7 @@ struct processor }; /* Architectures implementing AArch64. */ -static constexpr processor all_architectures[] = +static CONSTEXPR const processor all_architectures[] = { #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, D, E) \ {NAME, CORE, CORE, AARCH64_ARCH_##ARCH_IDENT, \ diff --git a/gcc/config/aarch64/driver-aarch64.cc b/gcc/config/aarch64/driver-aarch64.cc index 2ae47c0..a1d412c 100644 --- a/gcc/config/aarch64/driver-aarch64.cc +++ b/gcc/config/aarch64/driver-aarch64.cc @@ -64,7 +64,7 @@ struct aarch64_core_data #define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \ { CORE_NAME, #ARCH, IMP, PART, VARIANT, feature_deps::cpu_##CORE_IDENT }, -static constexpr aarch64_core_data aarch64_cpu_data[] = +static CONSTEXPR const aarch64_core_data aarch64_cpu_data[] = { #include "aarch64-cores.def" { NULL, NULL, INVALID_IMP, INVALID_CORE, ALL_VARIANTS, 0 } @@ -82,7 +82,7 @@ struct aarch64_arch_driver_info #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \ { #ARCH_IDENT + 1, NAME, feature_deps::ARCH_IDENT ().enable }, -static constexpr aarch64_arch_driver_info aarch64_arches[] = +static CONSTEXPR const aarch64_arch_driver_info aarch64_arches[] = { #include "aarch64-arches.def" {NULL, NULL, 0} -- cgit v1.1 From f7d1d7777bb86ad049f88214109fb561a741aa2c Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 24 Oct 2022 17:39:55 -0400 Subject: c++: Templated lambda mangling (Explicitly) Templated lambdas have a different signature to implicitly templated lambdas -- '[]