On Wed, 3 Dec 2025, Jakub Jelinek wrote:
> Hi!
>
> In r14-8302 I've changed switchconv to narrow the CONSTRUCTOR indexes and
> the runtime SSA_NAME indexing into the arrays to at most sizetype for
> types wider than that (__int128, large _BitInt, for -m32 long long too).
> The switchconv partitioning ensures that one partition isn't larger than
> that and having CONSTRUCTOR with _BitInt(1024) indexes was causing all kinds
> of problems.
>
> Unfortunately, as the following testcase shows, while doing that is
> desirable, the later gen_inbound_check call uses the lhs of m_arr_ref_first
> statement to determine the type and value that should be compared for the
> inbound check (against the highest possible bound cast to the lhs type).
> So the PR113491 r14-8302 change broke those inbound checks, instead of
> being done in unsigned type corresponding to the precision of the switch
> expression they are now sometimes done using sizetype. That is of course
> wrong.
>
> So the following patch fixes it by doing the tidx computation in steps,
> one is the utype subtraction, which has m_arr_ref_first as the last
> instruction, and then if needed there is a cast to sizetype if utype is
> wider than that. When gen_inbound_check is called, it adds the inbound
> check after the m_arr_ref_first instruction and the additional cast is
> then inside of the guarded block.
>
> So e.g. in bar for -m32 this patch changes:
> unsigned char bar (long long int val)
> {
> unsigned char result;
> - sizetype _7;
> + sizetype _6;
> + long long unsigned int _7;
>
> <bb 2> :
> - _7 = (sizetype) val_3(D);
> + _7 = (long long unsigned int) val_3(D);
> if (_7 <= 2)
> goto <bb 4>; [INV]
> else
> goto <bb 3>; [INV]
>
> <bb 3> :
> <L7>:
> - result_5 = 1;
> + result_4 = 1;
> goto <bb 5>; [100.00%]
>
> <bb 4> :
> <L8>:
> - result_6 = CSWTCH.2[_7];
> + _6 = (sizetype) _7;
> + result_5 = CSWTCH.2[_6];
>
> <bb 5> :
> - # result_1 = PHI <result_6(4), result_5(3)>
> + # result_1 = PHI <result_5(4), result_4(3)>
> <L9>:
> <L6>:
> return result_1;
>
> }
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/15/14?
OK.
Richard.
> 2025-12-03 Jakub Jelinek <[email protected]>
>
> PR tree-optimization/122943
> * tree-switch-conversion.cc (switch_conversion::build_arrays):
> Always gimplify subtraction in utype without cast to tidxtype
> and set m_arr_ref_first to the last stmt of that. Remove unneeded
> update_stmt call. If tidxtype is not utype, append after that stmt
> cast to tidxtype and set tidx to the lhs of that cast.
>
> * gcc.c-torture/execute/pr122943.c: New test.
>
> --- gcc/tree-switch-conversion.cc.jj 2025-10-13 09:46:21.492084794 +0200
> +++ gcc/tree-switch-conversion.cc 2025-12-02 12:08:50.996922750 +0100
> @@ -1074,7 +1074,7 @@ void
> switch_conversion::build_arrays ()
> {
> tree arr_index_type;
> - tree tidx, sub, utype, tidxtype;
> + tree tidx, uidx, sub, utype, tidxtype;
> gimple *stmt;
> gimple_stmt_iterator gsi;
> gphi_iterator gpi;
> @@ -1099,19 +1099,25 @@ switch_conversion::build_arrays ()
> tidxtype = utype;
>
> arr_index_type = build_index_type (m_range_size);
> - tidx = make_ssa_name (tidxtype);
> + uidx = make_ssa_name (utype);
> sub = fold_build2_loc (loc, MINUS_EXPR, utype,
> fold_convert_loc (loc, utype, m_index_expr),
> fold_convert_loc (loc, utype, m_range_min));
> - sub = fold_convert (tidxtype, sub);
> sub = force_gimple_operand_gsi (&gsi, sub,
> false, NULL, true, GSI_SAME_STMT);
> - stmt = gimple_build_assign (tidx, sub);
> + stmt = gimple_build_assign (uidx, sub);
>
> gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
> - update_stmt (stmt);
> m_arr_ref_first = stmt;
>
> + tidx = uidx;
> + if (tidxtype != utype)
> + {
> + tidx = make_ssa_name (tidxtype);
> + stmt = gimple_build_assign (tidx, NOP_EXPR, uidx);
> + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
> + }
> +
> for (gpi = gsi_start_phis (m_final_bb), i = 0;
> !gsi_end_p (gpi); gsi_next (&gpi))
> {
> --- gcc/testsuite/gcc.c-torture/execute/pr122943.c.jj 2025-12-02
> 12:40:44.922903448 +0100
> +++ gcc/testsuite/gcc.c-torture/execute/pr122943.c 2025-12-02
> 12:41:33.026073520 +0100
> @@ -0,0 +1,130 @@
> +/* PR tree-optimization/122943 */
> +
> +__attribute__((noipa)) unsigned char
> +foo (long long val)
> +{
> + unsigned char result = 0;
> + switch (val)
> + {
> + case 0: result = 1; break;
> + case 1: result = 2; break;
> + case 2: result = 3; break;
> + default: break;
> + }
> + return result;
> +}
> +
> +__attribute__((noipa)) unsigned char
> +bar (long long val)
> +{
> + unsigned char result = 1;
> + switch (val)
> + {
> + case 0: result = 8; break;
> + case 1: result = 31; break;
> + case 2: result = 72; break;
> + default: break;
> + }
> + return result;
> +}
> +
> +#ifdef __SIZEOF_INT128__
> +__attribute__((noipa)) unsigned char
> +baz (__int128 val)
> +{
> + unsigned char result = 0;
> + switch (val)
> + {
> + case 0: result = 1; break;
> + case 1: result = 2; break;
> + case 2: result = 3; break;
> + default: break;
> + }
> + return result;
> +}
> +
> +__attribute__((noipa)) unsigned char
> +qux (__int128 val)
> +{
> + unsigned char result = 1;
> + switch (val)
> + {
> + case 0: result = 8; break;
> + case 1: result = 31; break;
> + case 2: result = 72; break;
> + default: break;
> + }
> + return result;
> +}
> +#endif
> +
> +int
> +main ()
> +{
> + if (foo (-1) != 0)
> + __builtin_abort ();
> + if (foo (0) != 1)
> + __builtin_abort ();
> + if (foo (1) != 2)
> + __builtin_abort ();
> + if (foo (2) != 3)
> + __builtin_abort ();
> + if (foo (3) != 0)
> + __builtin_abort ();
> + if (foo (-__LONG_LONG_MAX__ - 1) != 0)
> + __builtin_abort ();
> + if (foo (-__LONG_LONG_MAX__) != 0)
> + __builtin_abort ();
> + if (foo (-__LONG_LONG_MAX__ + 1) != 0)
> + __builtin_abort ();
> + if (bar (-1) != 1)
> + __builtin_abort ();
> + if (bar (0) != 8)
> + __builtin_abort ();
> + if (bar (1) != 31)
> + __builtin_abort ();
> + if (bar (2) != 72)
> + __builtin_abort ();
> + if (bar (3) != 1)
> + __builtin_abort ();
> + if (bar (-__LONG_LONG_MAX__ - 1) != 1)
> + __builtin_abort ();
> + if (bar (-__LONG_LONG_MAX__) != 1)
> + __builtin_abort ();
> + if (bar (-__LONG_LONG_MAX__ + 1) != 1)
> + __builtin_abort ();
> +#ifdef __SIZEOF_INT128__
> + if (baz (-1) != 0)
> + __builtin_abort ();
> + if (baz (0) != 1)
> + __builtin_abort ();
> + if (baz (1) != 2)
> + __builtin_abort ();
> + if (baz (2) != 3)
> + __builtin_abort ();
> + if (baz (3) != 0)
> + __builtin_abort ();
> + if (baz (((__int128) 1) << 64) != 0)
> + __builtin_abort ();
> + if (baz ((((__int128) 1) << 64) + 1) != 0)
> + __builtin_abort ();
> + if (baz ((((__int128) 1) << 64) + 2) != 0)
> + __builtin_abort ();
> + if (qux (-1) != 1)
> + __builtin_abort ();
> + if (qux (0) != 8)
> + __builtin_abort ();
> + if (qux (1) != 31)
> + __builtin_abort ();
> + if (qux (2) != 72)
> + __builtin_abort ();
> + if (qux (3) != 1)
> + __builtin_abort ();
> + if (qux (((__int128) 1) << 64) != 1)
> + __builtin_abort ();
> + if (qux ((((__int128) 1) << 64) + 1) != 1)
> + __builtin_abort ();
> + if (qux ((((__int128) 1) << 64) + 2) != 1)
> + __builtin_abort ();
> +#endif
> +}
>
> Jakub
>
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)