[gcc(refs/users/omachota/heads/rtl-ssa-dce)] rtl-ssa-dce: bug report
https://gcc.gnu.org/g:e6b162ba3f9c3b26f57e7f00dbfa8d2dc8656cf8 commit e6b162ba3f9c3b26f57e7f00dbfa8d2dc8656cf8 Author: Ondřej Machota Date: Fri Jun 20 00:01:49 2025 +0200 rtl-ssa-dce: bug report Diff: --- gcc/cse.cc | 2 +- gcc/dce.cc | 517 +++- gcc/fwprop.cc | 2 +- gcc/passes.def | 5 +- gcc/rtl-ssa/changes.cc | 24 +-- gcc/rtl-ssa/functions.h | 2 +- 6 files changed, 34 insertions(+), 518 deletions(-) diff --git a/gcc/cse.cc b/gcc/cse.cc index 9c0924d73e1d..70d5caac4cac 100644 --- a/gcc/cse.cc +++ b/gcc/cse.cc @@ -7639,7 +7639,7 @@ rest_of_handle_cse2 (void) bypassed safely. */ cse_condition_code_reg (); - // delete_trivially_dead_insns (get_insns (), max_reg_num ()); + delete_trivially_dead_insns (get_insns (), max_reg_num ()); if (tem == 2) { diff --git a/gcc/dce.cc b/gcc/dce.cc index 2a203b673f32..77ff0a4d2791 100644 --- a/gcc/dce.cc +++ b/gcc/dce.cc @@ -42,7 +42,6 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "dbgcnt.h" #include "rtl-iter.h" -#include using namespace rtl_ssa; @@ -1318,9 +1317,13 @@ public: } // namespace -// TODO: naalokovat prazdnou a pak resize -// -flto_partition=none -// -ftime_report a v build adresari zkusit insn*.cc (emit, match, recog) +rtl_opt_pass * +make_pass_fast_rtl_dce (gcc::context *ctxt) +{ + return new pass_fast_rtl_dce (ctxt); +} + +// offset_bitmap is a wrapper around sbitmap which takes care of negative indices struct offset_bitmap { private: @@ -1373,17 +1376,10 @@ private: void mark_prelive_insn (insn_info *, auto_vec &); auto_vec mark_prelive (); void mark (); - std::unordered_set propagate_dead_phis (); void reset_dead_debug_insn (insn_info *); void reset_dead_debug (); void sweep (); - void debugize_insn (insn_info *); - - void unmark_debugizable(insn_info *, sbitmap); - sbitmap find_debugizable(const std::unordered_set &); - void debugize_insns (const sbitmap); - offset_bitmap m_marked; sbitmap mm_marked_phis; }; @@ -1403,49 +1399,14 @@ rtl_ssa_dce::is_rtx_pattern_prelive (const_rtx insn) } } -// odebrat auto - bool rtl_ssa_dce::can_delete_call (const_rtx insn) { gcc_checking_assert (CALL_P (insn)); - // We cannot delete pure or const sibling calls because it is - // hard to see the result. - // if (!SIBLING_CALL_P (insn)) - // // We can delete dead const or pure calls as long as they do not - // // infinite loop. - // && (RTL_CONST_OR_PURE_CALL_P (insn) - // && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn) - - // && cfun->can_delete_dead_exceptions - // ) - // return true; - // Don't delete calls that may throw if we cannot do so. - - // pridat assert na const nebo pure - // pouzivat gcc_checking_assert(); if (cfun->can_delete_dead_exceptions) return true; - // if (!insn_nothrow_p (insn)) -// return false; return insn_nothrow_p (insn); - - // UD_DCE ignores this and works... - /* If we can't alter cfg, even when the call can't throw exceptions, it - might have EDGE_ABNORMAL_CALL edges and so we shouldn't delete such - calls. */ - // gcc_assert (CALL_P (insn)); - // if (BLOCK_FOR_INSN (insn) && BB_END (BLOCK_FOR_INSN (insn)) == insn) - // { - // edge e; - // edge_iterator ei; - - // FOR_EACH_EDGE (e, ei, BLOCK_FOR_INSN (insn)->succs) - // if ((e->flags & EDGE_ABNORMAL_CALL) != 0) - // return false; - // } - // return true; } bool @@ -1503,8 +1464,8 @@ rtl_ssa_dce::is_rtx_prelive (const_rtx insn) bool rtl_ssa_dce::is_prelive (insn_info *insn) { - // bb head and end contain artificial uses that we need to mark as prelive - // debug instructions are also prelive, however, they are not added to the + // Bb head and end contain artificial uses that we need to mark as prelive. + // Debug instructions are also prelive, however, they are not added to the // worklist if (insn->is_bb_head () || insn->is_bb_end () || insn->is_debug_insn ()) return true; @@ -1522,21 +1483,20 @@ rtl_ssa_dce::is_prelive (insn_info *insn) gcc_assert (def->is_reg ()); - // we should not delete the frame pointer because of the dward2frame pass + // We should not delete the frame pointer because of the dward2frame pass if (frame_pointer_needed && def->regno () == HARD_FRAME_POINTER_REGNUM) return true; - // skip clobbers, they are handled inside is_rtx_prelive + // Skip clobbers, they are handled inside is_rtx_prelive if (def->kind () == access_kind::CLOBBER) continue; gcc_assert (def->kind () == access_kind::SET); - // needed by gcc.c-torture/execute/pr51447.c + // Needed by gcc.c-torture/execute/pr51447.c if (HARD_REGISTER_NUM_P (def->regno ()) && global_regs[def->regno ()]) return true; - // what about reload? check cse.cc unsigned
[gcc r16-1585] [RISC-V] Force several tests to use rocket tuning
https://gcc.gnu.org/g:c59cea256ad3eaf34298bb9ce947af89bbc7331f commit r16-1585-gc59cea256ad3eaf34298bb9ce947af89bbc7331f Author: Jeff Law Date: Thu Jun 19 20:58:56 2025 -0600 [RISC-V] Force several tests to use rocket tuning My tester has been flagging these regressions since the default cost model was committed, along with several others > unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/rvv/vsetvl/avl_single-37.c -O2 scan-assembler-times \\.L[0-9]+\\:\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+add\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[a-x0-9]+\\s+\\.L[0-9]+\\: 1 > unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/rvv/vsetvl/avl_single-37.c -O2 -flto -fno-use-linker-plugin -flto-partition=none scan-assembler-times \\.L[0-9]+\\:\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+add\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[a-x0-9]+\\s+\\.L[0-9]+\\: 1 > unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/rvv/vsetvl/avl_single-37.c -O2 -flto -fuse-linker-plugin -fno-fat-lto-objects scan-assembler-times \\.L[0-9]+\\:\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+addi\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[0-9]00\\s+add\\s+\\s*[a-x0-9]+,\\s*[a-x0-9]+,\\s*[a-x0-9]+\\s+\\.L[0-9]+\\: 1 I really question the value of checking the output that precisely in these tests -- they're supposed to be checking vsetvl correctness and optimization, so the ordering and such of scalar ops shouldn't really be important at all. Regardless, since I don't know these tests at all I resisted the temptation to rip out the undesirable aspects of the test. Next up, fix the bogus scan or force the old cost model (rocket). I choose the latter as a path of least resistance and least surprise. Waiting for pre-commit CI to spin. gcc/testsuite * gcc.target/riscv/rvv/vsetvl/avl_single-37.c: Force rocket tuning. * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-17.c: Likewise. * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-18.c: Likewise. * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-19.c: Likewise. * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-20.c: Likewise. Diff: --- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-37.c| 2 +- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-17.c | 2 +- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-18.c | 2 +- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-19.c | 2 +- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-20.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-37.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-37.c index cd3e961cefe1..9bade063f17e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-37.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-37.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mrvv-vector-bits=scalable -march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */ +/* { dg-options "-mrvv-vector-bits=scalable -march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize -mtune=rocket" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-17.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-17.c index d7f6d18d1d61..321eb3b9f298 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-17.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-17.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mrvv-vector-bits=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +/* { dg-options "-mrvv-vector-bits=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize -mtune=rocket" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-18.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-18.c index 1354c5e46d02..29dcfefbd0cf 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-18.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-18.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mrvv-vector-bits=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +/* { dg-options "-mrvv-vector-bits=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize -mtune=rocket" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-19.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-19.c index 6366dd9db44f..8b6299e99d1f 100644 --- a/gcc/testsuite/gcc.
[gcc r16-1583] RISC-V: Add test for vec_duplicate + vminu.vv combine case 1 with GR2VR cost 0, 1 and 2
https://gcc.gnu.org/g:89ec7ba1b1815aa9ba68d17f01e1b5a4dc20bde5 commit r16-1583-g89ec7ba1b1815aa9ba68d17f01e1b5a4dc20bde5 Author: Pan Li Date: Thu Jun 19 10:49:07 2025 +0800 RISC-V: Add test for vec_duplicate + vminu.vv combine case 1 with GR2VR cost 0, 1 and 2 Add asm dump check test for vec_duplicate + vminu.vv combine to vminu.vx, with the GR2VR cost is 0, 1 and 2. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c: Add asm check for vminu.vx combine. * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u8.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u16.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u32.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u64.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u8.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u16.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u32.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u64.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u8.c: Ditto. Signed-off-by: Pan Li Diff: --- gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u8.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u16.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u32.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u64.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u8.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u16.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u32.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u64.c | 3 +++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u8.c | 3 +++ 12 files changed, 35 insertions(+) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c index bee4171c0b46..b62164347186 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c @@ -15,6 +15,8 @@ DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, %, rem, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_3_WRAP(T, MAX_FUNC_0_WARP(T), max, VX_BINARY_FUNC_BODY_X8) DEF_VX_BINARY_CASE_3_WRAP(T, MAX_FUNC_1_WARP(T), max, VX_BINARY_FUNC_BODY_X8) +DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8) +DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -25,3 +27,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MAX_FUNC_1_WARP(T), max, VX_BINARY_FUNC_BODY_X8) /* { dg-final { scan-assembler {vdivu.vx} } } */ /* { dg-final { scan-assembler {vremu.vx} } } */ /* { dg-final { scan-assembler {vmaxu.vx} } } */ +/* { dg-final { scan-assembler {vminu.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c index 376f1c63ff10..741a7495f136 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c @@ -15,6 +15,8 @@ DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, %, rem, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_3_WRAP(T, MAX_FUNC_0_WARP(T), max, VX_BINARY_FUNC_BODY_X4) DEF_VX_BINARY_CASE_3_WRAP(T, MAX_FUNC_1_WARP(T), max, VX_BINARY_FUNC_BODY_X4) +DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X4) +DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X4) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -25,3 +27,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MAX_FUNC_1_WARP(T), max, VX_BINARY_FUNC_BODY_X4) /* { dg-final { scan-assembler {vdivu.vx} } } */ /* { dg-final { scan-assembler {vremu.vx} } } */ /* { dg-final { scan-assembler {vmaxu.vx} } } */ +/* { dg-final { scan-assembler {vminu.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c index 034f50dfe634..70375b174734 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c @@ -15,6 +15,8 @@ DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, %, rem, VX_BINARY_BODY) DEF_VX_BINARY_CASE_3_WRAP(T, MAX_FUNC_0_WARP(T), max, VX_BINARY_FU
[gcc r16-1582] RISC-V: Add test for vec_duplicate + vminu.vv combine case 0 with GR2VR cost 0, 2 and 15
https://gcc.gnu.org/g:289220af97f712d253d0b9d649e57e7da3dd37ea commit r16-1582-g289220af97f712d253d0b9d649e57e7da3dd37ea Author: Pan Li Date: Thu Jun 19 10:47:33 2025 +0800 RISC-V: Add test for vec_duplicate + vminu.vv combine case 0 with GR2VR cost 0, 2 and 15 Add asm dump check and run test for vec_duplicate + vminu.vv combine to vminu.vx, with the GR2VR cost is 0, 2 and 15. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c: Add asm check. * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u8.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u16.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u32.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u64.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u8.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u16.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u32.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u64.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u8.c: Ditto. * gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h: Add test helper macors. * gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h: Add test data for run test. * gcc.target/riscv/rvv/autovec/vx_vf/vx_vmin-run-1-u16.c: New test. * gcc.target/riscv/rvv/autovec/vx_vf/vx_vmin-run-1-u32.c: New test. * gcc.target/riscv/rvv/autovec/vx_vf/vx_vmin-run-1-u64.c: New test. * gcc.target/riscv/rvv/autovec/vx_vf/vx_vmin-run-1-u8.c: New test. * gcc.target/riscv/rvv/autovec/vx_vf/vx_vmin-run-2-u16.c: New test. * gcc.target/riscv/rvv/autovec/vx_vf/vx_vmin-run-2-u32.c: New test. * gcc.target/riscv/rvv/autovec/vx_vf/vx_vmin-run-2-u64.c: New test. * gcc.target/riscv/rvv/autovec/vx_vf/vx_vmin-run-2-u8.c: New test. Signed-off-by: Pan Li Diff: --- .../gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u8.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u16.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u32.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u64.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u8.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u16.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u32.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u64.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u8.c | 1 + .../gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h | 14 +- .../riscv/rvv/autovec/vx_vf/vx_binary_data.h | 196 + .../riscv/rvv/autovec/vx_vf/vx_vmin-run-1-u16.c| 17 ++ .../riscv/rvv/autovec/vx_vf/vx_vmin-run-1-u32.c| 17 ++ .../riscv/rvv/autovec/vx_vf/vx_vmin-run-1-u64.c| 17 ++ .../riscv/rvv/autovec/vx_vf/vx_vmin-run-1-u8.c | 17 ++ .../riscv/rvv/autovec/vx_vf/vx_vmin-run-2-u16.c| 17 ++ .../riscv/rvv/autovec/vx_vf/vx_vmin-run-2-u32.c| 17 ++ .../riscv/rvv/autovec/vx_vf/vx_vmin-run-2-u64.c| 17 ++ .../riscv/rvv/autovec/vx_vf/vx_vmin-run-2-u8.c | 17 ++ 22 files changed, 357 insertions(+), 1 deletion(-) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c index e06829d621d5..bcfd5145d24f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c @@ -16,3 +16,4 @@ TEST_BINARY_VX_UNSIGNED_0(T) /* { dg-final { scan-assembler-times {vdivu.vx} 1 } } */ /* { dg-final { scan-assembler-times {vremu.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmaxu.vx} 2 } } */ +/* { dg-final { scan-assembler-times {vminu.vx} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c index 05fb829a87e0..b9a6a2830916 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c @@ -16,3 +16,4 @@ TEST_BINARY_VX_UNSIGNED_0(T) /* { dg-final { scan-assembler-times {vdivu.vx} 1 } } */ /* { dg-final { scan-assembler-times {vremu.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmaxu.vx} 2 } } */ +/* { dg-final { scan-assembler-times {vminu.vx} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c index 4681f36cd4b1..abb5e5e78428 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c +++ b/gcc/testsuite/gcc.target/r
[gcc r16-1581] RISC-V: Combine vec_duplicate + vminu.vv to vminu.vx on GR2VR cost
https://gcc.gnu.org/g:7ea9105f2609efe089461d7e92533324eb5b1103 commit r16-1581-g7ea9105f2609efe089461d7e92533324eb5b1103 Author: Pan Li Date: Thu Jun 19 10:44:14 2025 +0800 RISC-V: Combine vec_duplicate + vminu.vv to vminu.vx on GR2VR cost This patch would like to combine the vec_duplicate + vminu.vv to the vminu.vx. From example as below code. The related pattern will depend on the cost of vec_duplicate from GR2VR. Then the late-combine will take action if the cost of GR2VR is zero, and reject the combination if the GR2VR cost is greater than zero. Assume we have example code like below, GR2VR cost is 0. #define DEF_VX_BINARY(T, FUNC) \ void\ test_vx_binary (T * restrict out, T * restrict in, T x, unsigned n) \ { \ for (unsigned i = 0; i < n; i++) \ out[i] = FUNC (in[i], x); \ } uint32_t min(uint32 a, uint32 b) { return a > b ? b : a; } DEF_VX_BINARY(uint32_t, min) Before this patch: 10 │ test_vx_binary_or_int32_t_case_0: 11 │ beq a3,zero,.L8 12 │ vsetvli a5,zero,e32,m1,ta,ma 13 │ vmv.v.x v2,a2 14 │ sllia3,a3,32 15 │ srlia3,a3,32 16 │ .L3: 17 │ vsetvli a5,a3,e32,m1,ta,ma 18 │ vle32.v v1,0(a1) 19 │ sllia4,a5,2 20 │ sub a3,a3,a5 21 │ add a1,a1,a4 22 │ vminu.vv v1,v1,v2 23 │ vse32.v v1,0(a0) 24 │ add a0,a0,a4 25 │ bne a3,zero,.L3 After this patch: 10 │ test_vx_binary_or_int32_t_case_0: 11 │ beq a3,zero,.L8 12 │ sllia3,a3,32 13 │ srlia3,a3,32 14 │ .L3: 15 │ vsetvli a5,a3,e32,m1,ta,ma 16 │ vle32.v v1,0(a1) 17 │ sllia4,a5,2 18 │ sub a3,a3,a5 19 │ add a1,a1,a4 20 │ vminu.vx v1,v1,a2 21 │ vse32.v v1,0(a0) 22 │ add a0,a0,a4 23 │ bne a3,zero,.L3 gcc/ChangeLog: * config/riscv/riscv-v.cc (expand_vx_binary_vec_dup_vec): Add new case UMIN. (expand_vx_binary_vec_vec_dup): Ditto. * config/riscv/riscv.cc (riscv_rtx_costs): Ditto. * config/riscv/vector-iterators.md: Add new op umin. Signed-off-by: Pan Li Diff: --- gcc/config/riscv/riscv-v.cc | 2 ++ gcc/config/riscv/riscv.cc| 1 + gcc/config/riscv/vector-iterators.md | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index a903de9280ab..ac690df3688a 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -5540,6 +5540,7 @@ expand_vx_binary_vec_dup_vec (rtx op_0, rtx op_1, rtx op_2, case SMAX: case UMAX: case SMIN: +case UMIN: icode = code_for_pred_scalar (code, mode); break; case MINUS: @@ -5577,6 +5578,7 @@ expand_vx_binary_vec_vec_dup (rtx op_0, rtx op_1, rtx op_2, case SMAX: case UMAX: case SMIN: +case UMIN: icode = code_for_pred_scalar (code, mode); break; default: diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 86444b0bef8e..3c1bb74675a2 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -4012,6 +4012,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN case SMAX: case UMAX: case SMIN: + case UMIN: { rtx op; rtx op_0 = XEXP (x, 0); diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md index 6cfa9269f935..44ae79c48aa7 100644 --- a/gcc/config/riscv/vector-iterators.md +++ b/gcc/config/riscv/vector-iterators.md @@ -4042,11 +4042,11 @@ ]) (define_code_iterator any_int_binop_no_shift_v_vdup [ - plus minus and ior xor mult div udiv mod umod smax umax smin + plus minus and ior xor mult div udiv mod umod smax umax smin umin ]) (define_code_iterator any_int_binop_no_shift_vdup_v [ - plus minus and ior xor mult smax umax smin + plus minus and ior xor mult smax umax smin umin ]) (define_code_iterator any_int_unop [neg not])
[gcc r16-1584] [PATCH] RISC-V: Use builtin clz/ctz when count_leading_zeros and count_trailing_zeros is used
https://gcc.gnu.org/g:e08ef05e4da86d34223118092bbb857b8dd5d002 commit r16-1584-ge08ef05e4da86d34223118092bbb857b8dd5d002 Author: Sosutha Sethuramapandian Date: Thu Jun 19 20:53:56 2025 -0600 [PATCH] RISC-V: Use builtin clz/ctz when count_leading_zeros and count_trailing_zeros is used longlong.h for RISCV should define count_leading_zeros and count_trailing_zeros and COUNT_LEADING_ZEROS_0 when ZBB is enabled. The following patch patch fixes the bug reported in, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110181 The divdi3 on riscv32 with zbb extension generates __clz_tab instead of genearating __builtin_clzll/__builtin_clz which is not efficient since lookup table is emitted. Updating longlong.h to use this __builtin_clzll/__builtin_clz generates optimized code for the instruction. PR target/110181 include/ChangeLog * longlong.h [__riscv] (count_leading_zeros): Define. [__riscv] (count_trailing_zeros): Likewise. [__riscv] (COUNT_LEADING_ZEROS_0): Likewise. Diff: --- include/longlong.h | 14 ++ 1 file changed, 14 insertions(+) diff --git a/include/longlong.h b/include/longlong.h index 40f94243a1af..5ae250f7192d 100644 --- a/include/longlong.h +++ b/include/longlong.h @@ -1065,6 +1065,20 @@ extern UDItype __umulsidi3 (USItype, USItype); #endif #if defined(__riscv) + +#ifdef __riscv_zbb +#if W_TYPE_SIZE == 32 +#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz (X)) +#define count_trailing_zeros(COUNT, X) ((COUNT) = __builtin_ctz (X)) +#define COUNT_LEADING_ZEROS_0 32 +#endif /* W_TYPE_SIZE == 32 */ +#if W_TYPE_SIZE == 64 +#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clzll (X)) +#define count_trailing_zeros(COUNT, X) ((COUNT) = __builtin_ctzll (X)) +#define COUNT_LEADING_ZEROS_0 64 +#endif /* W_TYPE_SIZE == 64 */ +#endif /* __riscv_zbb */ + #ifdef __riscv_mul #define __umulsidi3(u,v) ((UDWtype)(UWtype)(u) * (UWtype)(v)) #define __muluw3(a, b) ((UWtype)(a) * (UWtype)(b))
[gcc(refs/users/mikael/heads/select_type_name_v01)] fortran: Mention user variable in select type temporary variable names
https://gcc.gnu.org/g:f74c501c5c7714784b9738d15687de9f0290dc8a commit f74c501c5c7714784b9738d15687de9f0290dc8a Author: Mikael Morin Date: Wed Jun 18 18:07:54 2025 +0200 fortran: Mention user variable in select type temporary variable names The temporary variables that are generated to implement select type and type is statements used to have a name depending only on the type. This could produce confusing dumps with code having multiple select type statements, as it wasn't obvious with which select type construct the variable were related. This was especially the case with nested select type statements and with select type variables having identical types (and thus identical names). This change adds one additional user-provided discriminating string in the variable names, using the value from the select type variable name or last component reference name. It's a purely convenience change, not a correctness issue. gcc/fortran/ChangeLog: * misc.cc (gfc_var_name_for_select_type_temp): New function. * gfortran.h (gfc_var_name_for_select_type_temp): Declare it. * resolve.cc (resolve_select_type): Pick a discriminating name from the select type variable reference and use it in the name of the temporary variable that is generated. * match.cc (select_type_set_tmp): Likewise. Pass the discriminating name... (select_intrinsic_set_tmp): ... to this function. Use the discriminating name likewise. Diff: --- gcc/fortran/gfortran.h | 2 ++ gcc/fortran/match.cc | 18 ++ gcc/fortran/misc.cc| 21 + gcc/fortran/resolve.cc | 19 +++ 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index f73b5f9c23f4..6848bd1762d3 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3507,6 +3507,8 @@ void gfc_done_2 (void); int get_c_kind (const char *, CInteropKind_t *); +const char * gfc_var_name_for_select_type_temp (gfc_expr *); + const char *gfc_closest_fuzzy_match (const char *, char **); inline void vec_push (char **&optr, size_t &osz, const char *elt) diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc index a99a757bede6..4631791015fa 100644 --- a/gcc/fortran/match.cc +++ b/gcc/fortran/match.cc @@ -7171,7 +7171,7 @@ select_type_push (gfc_symbol *sel) /* Set the temporary for the current intrinsic SELECT TYPE selector. */ static gfc_symtree * -select_intrinsic_set_tmp (gfc_typespec *ts) +select_intrinsic_set_tmp (gfc_typespec *ts, const char *var_name) { char name[GFC_MAX_SYMBOL_LEN]; gfc_symtree *tmp; @@ -7192,12 +7192,12 @@ select_intrinsic_set_tmp (gfc_typespec *ts) charlen = gfc_mpz_get_hwi (ts->u.cl->length->value.integer); if (ts->type != BT_CHARACTER) -sprintf (name, "__tmp_%s_%d", gfc_basic_typename (ts->type), -ts->kind); +sprintf (name, "__tmp_%s_%d_%s", gfc_basic_typename (ts->type), +ts->kind, var_name); else snprintf (name, sizeof (name), - "__tmp_%s_" HOST_WIDE_INT_PRINT_DEC "_%d", - gfc_basic_typename (ts->type), charlen, ts->kind); + "__tmp_%s_" HOST_WIDE_INT_PRINT_DEC "_%d_%s", + gfc_basic_typename (ts->type), charlen, ts->kind, var_name); gfc_get_sym_tree (name, gfc_current_ns, &tmp, false); sym = tmp->n.sym; @@ -7239,7 +7239,9 @@ select_type_set_tmp (gfc_typespec *ts) return; } - tmp = select_intrinsic_set_tmp (ts); + gfc_expr *select_type_expr = gfc_state_stack->construct->expr1; + const char *var_name = gfc_var_name_for_select_type_temp (select_type_expr); + tmp = select_intrinsic_set_tmp (ts, var_name); if (tmp == NULL) { @@ -7247,9 +7249,9 @@ select_type_set_tmp (gfc_typespec *ts) return; if (ts->type == BT_CLASS) - sprintf (name, "__tmp_class_%s", ts->u.derived->name); + sprintf (name, "__tmp_class_%s_%s", ts->u.derived->name, var_name); else - sprintf (name, "__tmp_type_%s", ts->u.derived->name); + sprintf (name, "__tmp_type_%s_%s", ts->u.derived->name, var_name); gfc_get_sym_tree (name, gfc_current_ns, &tmp, false); sym = tmp->n.sym; diff --git a/gcc/fortran/misc.cc b/gcc/fortran/misc.cc index b8bdf7578de6..23393066fc75 100644 --- a/gcc/fortran/misc.cc +++ b/gcc/fortran/misc.cc @@ -472,3 +472,24 @@ gfc_mpz_set_hwi (mpz_t rop, const HOST_WIDE_INT op) const wide_int w = wi::shwi (op, HOST_BITS_PER_WIDE_INT); wi::to_mpz (w, rop, SIGNED); } + + +/* Extract a name suitable for use in the name of the select type temporary + variable. We pick the last component name in the data reference if there + is one, otherwise the user variable name, and return the empty string by + default. */ + +const char * +gfc_var_name_for_select_type_temp (gfc_expr *e) +{ + cons
[gcc r16-1578] libgomp.texi: Document omp(x)::allocator::*, restructure memory allocator doc
https://gcc.gnu.org/g:b8617e0a241c7021f539aeca09a7c2bec02e9b39 commit r16-1578-gb8617e0a241c7021f539aeca09a7c2bec02e9b39 Author: Tobias Burnus Date: Thu Jun 19 21:06:11 2025 +0200 libgomp.texi: Document omp(x)::allocator::*, restructure memory allocator doc libgomp/ChangeLog: * libgomp.texi (omp_init_allocator): Refer to 'Memory allocation' for available memory spaces. (OMP_ALLOCATOR): Move list of traits and predefined memspaces and allocators to ... (Memory allocation): ... here. Document omp(x)::allocator::*; minor wording tweaks, be more explicit about memkind, pinned and pool_size. Co-authored-by: waffl3x Diff: --- libgomp/libgomp.texi | 181 --- 1 file changed, 113 insertions(+), 68 deletions(-) diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index 8374595bc823..9f53f167e064 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -3453,7 +3453,7 @@ traits; if an allocator that fulfills the requirements cannot be created, @code{omp_null_allocator} is returned. The predefined memory spaces and available traits can be found at -@ref{OMP_ALLOCATOR}, where the trait names have to be prefixed by +@ref{Memory allocation}, where the trait names have to be prefixed by @code{omp_atk_} (e.g. @code{omp_atk_pinned}) and the named trait values by @code{omp_atv_} (e.g. @code{omp_atv_true}); additionally, @code{omp_atv_default} may be used as trait value to specify that the default value should be used. @@ -3476,7 +3476,7 @@ may be used as trait value to specify that the default value should be used. @end multitable @item @emph{See also}: -@ref{OMP_ALLOCATOR}, @ref{Memory allocation}, @ref{omp_destroy_allocator} +@ref{Memory allocation}, @ref{OMP_ALLOCATOR}, @ref{omp_destroy_allocator} @item @emph{Reference}: @uref{https://www.openmp.org, OpenMP specification v5.0}, Section 3.7.2 @@ -4057,63 +4057,15 @@ The value can either be a predefined allocator or a predefined memory space or a predefined memory space followed by a colon and a comma-separated list of memory trait and value pairs, separated by @code{=}. +See @ref{Memory allocation} for a list of supported prefedined allocators, +memory spaces, and traits. + Note: The corresponding device environment variables are currently not supported. Therefore, the non-host @var{def-allocator-var} ICVs are always initialized to @code{omp_default_mem_alloc}. However, on all devices, the @code{omp_set_default_allocator} API routine can be used to change value. -@multitable @columnfractions .45 .45 -@headitem Predefined allocators @tab Associated predefined memory spaces -@item omp_default_mem_alloc @tab omp_default_mem_space -@item omp_large_cap_mem_alloc @tab omp_large_cap_mem_space -@item omp_const_mem_alloc @tab omp_const_mem_space -@item omp_high_bw_mem_alloc @tab omp_high_bw_mem_space -@item omp_low_lat_mem_alloc @tab omp_low_lat_mem_space -@item omp_cgroup_mem_alloc @tab omp_low_lat_mem_space (implementation defined) -@item omp_pteam_mem_alloc @tab omp_low_lat_mem_space (implementation defined) -@item omp_thread_mem_alloc @tab omp_low_lat_mem_space (implementation defined) -@item ompx_gnu_pinned_mem_alloc @tab omp_default_mem_space (GNU extension) -@end multitable - -The predefined allocators use the default values for the traits, -as listed below. Except that the last three allocators have the -@code{access} trait set to @code{cgroup}, @code{pteam}, and -@code{thread}, respectively. - -@multitable @columnfractions .25 .40 .25 -@headitem Trait @tab Allowed values @tab Default value -@item @code{sync_hint} @tab @code{contended}, @code{uncontended}, -@code{serialized}, @code{private} - @tab @code{contended} -@item @code{alignment} @tab Positive integer being a power of two - @tab 1 byte -@item @code{access}@tab @code{all}, @code{cgroup}, -@code{pteam}, @code{thread} - @tab @code{all} -@item @code{pool_size} @tab Positive integer - @tab See @ref{Memory allocation} -@item @code{fallback} @tab @code{default_mem_fb}, @code{null_fb}, -@code{abort_fb}, @code{allocator_fb} - @tab See below -@item @code{fb_data} @tab @emph{unsupported as it needs an allocator handle} - @tab (none) -@item @code{pinned}@tab @code{true}, @code{false} - @tab See below -@item @code{partition} @tab @code{environment}, @code{nearest}, -@code{blocked}, @code{interleaved} - @tab @code{environment} -@end multitable - -For the @code{fallback} trait, the default value is @code{null_fb} for the -@code{omp_default_mem_alloc} allocator and any allocator that is asso
[gcc r16-1579] libgomp/target.c: Fix buffer size for 'omp requires' diagnostic
https://gcc.gnu.org/g:8a759dbb690dbd882b4884515a57ba6f285835cc commit r16-1579-g8a759dbb690dbd882b4884515a57ba6f285835cc Author: Tobias Burnus Date: Thu Jun 19 21:16:42 2025 +0200 libgomp/target.c: Fix buffer size for 'omp requires' diagnostic One of the buffers that printed the list of set 'omp requires' requirements missed the 'self' clause addition, being potentially to short when all device-affecting clauses were passed. Solved it by moving the sizeof(" into a new '#define' just above the associated gomp_requires_to_name function. libgomp/ChangeLog: * target.c (GOMP_REQUIRES_NAME_BUF_LEN): Define. (GOMP_offload_register_ver, gomp_target_init): Use it for the char buffer size. Diff: --- libgomp/target.c | 13 +++-- 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libgomp/target.c b/libgomp/target.c index a2a4a7299e58..cda092bd044c 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -2641,6 +2641,10 @@ gomp_unload_image_from_device (struct gomp_device_descr *devicep, } } +#define GOMP_REQUIRES_NAME_BUF_LEN \ + sizeof ("unified_address, unified_shared_memory, " \ + "self_maps, reverse_offload") + static void gomp_requires_to_name (char *buf, size_t size, int requires_mask) { @@ -2689,10 +2693,8 @@ GOMP_offload_register_ver (unsigned version, const void *host_table, if (omp_req && omp_requires_mask && omp_requires_mask != omp_req) { - char buf1[sizeof ("unified_address, unified_shared_memory, " - "self_maps, reverse_offload")]; - char buf2[sizeof ("unified_address, unified_shared_memory, " - "self_maps, reverse_offload")]; + char buf1[GOMP_REQUIRES_NAME_BUF_LEN]; + char buf2[GOMP_REQUIRES_NAME_BUF_LEN]; gomp_requires_to_name (buf2, sizeof (buf2), omp_req != GOMP_REQUIRES_TARGET_USED ? omp_req : omp_requires_mask); @@ -5786,8 +5788,7 @@ gomp_target_init (void) found = true; if (found) { - char buf[sizeof ("unified_address, unified_shared_memory, " -"reverse_offload")]; + char buf[GOMP_REQUIRES_NAME_BUF_LEN]; gomp_requires_to_name (buf, sizeof (buf), omp_req); char *name = (char *) malloc (cur_len + 1); memcpy (name, cur, cur_len);
[gcc] Created branch 'mikael/heads/select_type_name_v01' in namespace 'refs/users'
The branch 'mikael/heads/select_type_name_v01' was created in namespace 'refs/users' pointing to: f74c501c5c77... fortran: Mention user variable in select type temporary var
[gcc r16-1587] or1k: Improve If-Conversion by delaying cbranch splits
https://gcc.gnu.org/g:becb0be25211ce13ca6764094052a38f14b954dd commit r16-1587-gbecb0be25211ce13ca6764094052a38f14b954dd Author: Stafford Horne Date: Thu Jun 19 12:17:20 2025 +0100 or1k: Improve If-Conversion by delaying cbranch splits When working on PR120587 I found that the ce1 pass was not able to properly optimize branches on OpenRISC. This is because of the early splitting of "compare" and "branch" instructions during the expand pass. Convert the cbranch* instructions from define_expand to define_insn_and_split. This dalays the instruction split until after the ce1 pass is done giving ce1 the best opportunity to perform the optimizations on the original form of cbranch4 instructions. gcc/ChangeLog: * config/or1k/or1k.cc (or1k_noce_conversion_profitable_p): New function. (or1k_is_cmov_insn): New function. (TARGET_NOCE_CONVERSION_PROFITABLE_P): Define macro. * config/or1k/or1k.md (cbranchsi4): Convert to insn_and_split. (cbranch4): Convert to insn_and_split. Signed-off-by: Stafford Horne Diff: --- gcc/config/or1k/or1k.cc | 57 + gcc/config/or1k/or1k.md | 32 +-- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/gcc/config/or1k/or1k.cc b/gcc/config/or1k/or1k.cc index f1c92c6bf6c9..868df676d352 100644 --- a/gcc/config/or1k/or1k.cc +++ b/gcc/config/or1k/or1k.cc @@ -1654,6 +1654,63 @@ or1k_rtx_costs (rtx x, machine_mode mode, int outer_code, int /* opno */, #undef TARGET_RTX_COSTS #define TARGET_RTX_COSTS or1k_rtx_costs +static bool +or1k_is_cmov_insn (rtx_insn *seq) +{ + rtx_insn *curr_insn = seq; + rtx set = NULL_RTX; + + /* The pattern may start with a simple set with register operands. Skip + through any of those. */ + while (curr_insn) +{ + set = single_set (curr_insn); + if (!set + || !REG_P (SET_DEST (set))) + return false; + + /* If it's not a simple reg or immediate break. */ + if (REG_P (SET_SRC (set)) || CONST_INT_P (SET_SRC (set))) + curr_insn = NEXT_INSN (curr_insn); + else + break; +} + + if (!curr_insn) +return false; + + /* The next instruction should be a compare. OpenRISC has many operators used + for comparison so skip and confirm the next is IF_THEN_ELSE. */ + curr_insn = NEXT_INSN (curr_insn); + if (!curr_insn) +return false; + + /* And the last instruction should be an IF_THEN_ELSE. */ + set = single_set (curr_insn); + if (!set + || !REG_P (SET_DEST (set)) + || GET_CODE (SET_SRC (set)) != IF_THEN_ELSE) +return false; + + return !NEXT_INSN (curr_insn); +} + +/* Implement TARGET_NOCE_CONVERSION_PROFITABLE_P. We detect if the conversion + resulted in a l.cmov instruction and if so we consider it more profitable than + branch instructions. */ + +static bool +or1k_noce_conversion_profitable_p (rtx_insn *seq, + struct noce_if_info *if_info) +{ + if (TARGET_CMOV) +return or1k_is_cmov_insn (seq); + + return default_noce_conversion_profitable_p (seq, if_info); +} + +#undef TARGET_NOCE_CONVERSION_PROFITABLE_P +#define TARGET_NOCE_CONVERSION_PROFITABLE_P or1k_noce_conversion_profitable_p /* A subroutine of the atomic operation splitters. Jump to LABEL if COND is true. Mark the jump as unlikely to be taken. */ diff --git a/gcc/config/or1k/or1k.md b/gcc/config/or1k/or1k.md index a30cc18892da..bf7125375ac4 100644 --- a/gcc/config/or1k/or1k.md +++ b/gcc/config/or1k/or1k.md @@ -609,7 +609,7 @@ ;; Branch instructions ;; - -(define_expand "cbranchsi4" +(define_insn_and_split "cbranchsi4" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" @@ -618,13 +618,27 @@ (label_ref (match_operand 3 "" "")) (pc)))] "" + "#" + "&& 1" + [(const_int 0)] { + rtx label; + + /* Generate *scc */ or1k_expand_compare (operands); + /* Generate *cbranch */ + label = gen_rtx_LABEL_REF (VOIDmode, operands[3]); + emit_jump_insn (gen_rtx_SET (pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, +operands[0], +label, +pc_rtx))); + DONE; }) ;; Support FP branching -(define_expand "cbranch4" +(define_insn_and_split "cbranch4" [(set (pc) (if_then_else (match_operator 0 "fp_comparison_operator" @@ -633,8 +647,22 @@ (label_ref (match_operand 3 "" "")) (pc)))] "TARGET_HARD_FLOAT" + "#" + "&& 1" + [(const_int 0)] { + rtx label; + + /* Generate *scc */ or1k_expand_compare (operands); + /* Generate *cbranch */ + label = gen_rtx_LABEL_REF (VOIDmode, operands[3]); + emit
[gcc r16-1586] or1k: Implement *extendbisi* to fix ICE in convert_mode_scalar [PR120587]
https://gcc.gnu.org/g:625a3807dabd5130bc6ec153d80dfbbb096d00f8 commit r16-1586-g625a3807dabd5130bc6ec153d80dfbbb096d00f8 Author: Stafford Horne Date: Wed Jun 18 21:47:03 2025 +0100 or1k: Implement *extendbisi* to fix ICE in convert_mode_scalar [PR120587] After commit 2dcc6dbd8a0 ("emit-rtl: Use simplify_subreg_regno to validate hardware subregs [PR119966]") the OpenRISC port is broken again. Add extend* iinstruction patterns for the SR_F pseudo registers to avoid having to use the subreg conversions which no longer work. gcc/ChangeLog: PR target/120587 * config/or1k/or1k.md (zero_extendbisi2_sr_f): New expand. (extendbisi2_sr_f): New expand. * config/or1k/predicates.md (sr_f_reg_operand): New predicate. Signed-off-by: Stafford Horne Diff: --- gcc/config/or1k/or1k.md | 25 + gcc/config/or1k/predicates.md | 4 2 files changed, 29 insertions(+) diff --git a/gcc/config/or1k/or1k.md b/gcc/config/or1k/or1k.md index 627e40084b34..a30cc18892da 100644 --- a/gcc/config/or1k/or1k.md +++ b/gcc/config/or1k/or1k.md @@ -515,6 +515,31 @@ (ne:SI (reg:BI SR_F_REGNUM) (const_int 0)))] "") +;; Allowing "extending" the BImode SR_F to a general register +;; avoids 'convert_mode_scalar' from trying to do subregging +;; which we don't have support for. +;; We require signed and unsigned extend instructions because +;; signed comparisons require signed extention, but for SR_F +;; it doesn't matter. + +(define_expand "zero_extendbisi2_sr_f" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:BI 1 "sr_f_reg_operand" "")))] + "" +{ + emit_insn(gen_sne_sr_f (operands[0])); + DONE; +}) + +(define_expand "extendbisi2_sr_f" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:BI 1 "sr_f_reg_operand" "")))] + "" +{ + emit_insn(gen_sne_sr_f (operands[0])); + DONE; +}) + (define_insn_and_split "*scc" [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 1 "equality_comparison_operator" diff --git a/gcc/config/or1k/predicates.md b/gcc/config/or1k/predicates.md index 144f4d7b5778..7ccfd09985dd 100644 --- a/gcc/config/or1k/predicates.md +++ b/gcc/config/or1k/predicates.md @@ -60,6 +60,10 @@ (and (match_operand 0 "register_operand") (match_test "TARGET_ROR" +(define_predicate "sr_f_reg_operand" + (and (match_operand 0 "register_operand") + (match_test "REGNO (op) == SR_F_REGNUM"))) + (define_predicate "call_insn_operand" (ior (and (match_code "symbol_ref") (match_test "!TARGET_CMODEL_LARGE"))
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Correction pr43808
https://gcc.gnu.org/g:0b3309e2a871c7fef8b668ada3fff439bb98b6a1 commit 0b3309e2a871c7fef8b668ada3fff439bb98b6a1 Author: Mikael Morin Date: Thu Jun 19 18:04:56 2025 +0200 Correction pr43808 Diff: --- gcc/fortran/trans-expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index c8a207609e4b..4cca4924871c 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -9589,8 +9589,8 @@ gfc_trans_alloc_subarray_assign (tree dest, gfc_component * cm, /* Shift the lbound and ubound of temporaries to being unity, rather than zero, based. Always calculate the offset. */ + gfc_conv_descriptor_offset_set (&block, dest, gfc_index_zero_node); offset = gfc_conv_descriptor_offset_get (dest); - gfc_add_modify (&block, offset, gfc_index_zero_node); tmp2 =gfc_create_var (gfc_array_index_type, NULL); for (n = 0; n < expr->rank; n++)
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Déplacement fonctions descripteur vers fichier séparé
https://gcc.gnu.org/g:ed2b5eb97ccdfe214b7389b9a19fd90977faf96f commit ed2b5eb97ccdfe214b7389b9a19fd90977faf96f Author: Mikael Morin Date: Wed Jun 18 17:31:23 2025 +0200 Déplacement fonctions descripteur vers fichier séparé Diff: --- gcc/fortran/Make-lang.in| 7 +- gcc/fortran/trans-array.cc | 515 +- gcc/fortran/trans-descriptor.cc | 534 gcc/fortran/trans-descriptor.h | 67 + 4 files changed, 610 insertions(+), 513 deletions(-) diff --git a/gcc/fortran/Make-lang.in b/gcc/fortran/Make-lang.in index 5b2f921bf2ef..2ddb0366e9dc 100644 --- a/gcc/fortran/Make-lang.in +++ b/gcc/fortran/Make-lang.in @@ -63,9 +63,10 @@ F95_PARSER_OBJS = fortran/arith.o fortran/array.o fortran/bbt.o \ F95_OBJS = $(F95_PARSER_OBJS) $(FORTRAN_TARGET_OBJS) \ fortran/convert.o fortran/dependency.o fortran/f95-lang.o \ fortran/trans.o fortran/trans-array.o fortran/trans-common.o \ -fortran/trans-const.o fortran/trans-decl.o fortran/trans-expr.o \ -fortran/trans-intrinsic.o fortran/trans-io.o fortran/trans-openmp.o \ -fortran/trans-stmt.o fortran/trans-types.o fortran/frontend-passes.o +fortran/trans-const.o fortran/trans-decl.o fortran/trans-descriptor.o \ +fortran/trans-expr.o fortran/trans-intrinsic.o fortran/trans-io.o \ +fortran/trans-openmp.o fortran/trans-stmt.o fortran/trans-types.o \ +fortran/frontend-passes.o fortran_OBJS = $(F95_OBJS) fortran/gfortranspec.o diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 960613167f72..8d90bec0d85f 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -92,6 +92,7 @@ along with GCC; see the file COPYING3. If not see #include "trans-array.h" #include "trans-const.h" #include "dependency.h" +#include "trans-descriptor.h" static bool gfc_get_array_constructor_size (mpz_t *, gfc_constructor_base); @@ -106,466 +107,6 @@ gfc_array_dataptr_type (tree desc) return (GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (desc))); } -/* Build expressions to access members of the CFI descriptor. */ -#define CFI_FIELD_BASE_ADDR 0 -#define CFI_FIELD_ELEM_LEN 1 -#define CFI_FIELD_VERSION 2 -#define CFI_FIELD_RANK 3 -#define CFI_FIELD_ATTRIBUTE 4 -#define CFI_FIELD_TYPE 5 -#define CFI_FIELD_DIM 6 - -#define CFI_DIM_FIELD_LOWER_BOUND 0 -#define CFI_DIM_FIELD_EXTENT 1 -#define CFI_DIM_FIELD_SM 2 - -static tree -gfc_get_cfi_descriptor_field (tree desc, unsigned field_idx) -{ - tree type = TREE_TYPE (desc); - gcc_assert (TREE_CODE (type) == RECORD_TYPE - && TYPE_FIELDS (type) - && (strcmp ("base_addr", -IDENTIFIER_POINTER (DECL_NAME (TYPE_FIELDS (type - == 0)); - tree field = gfc_advance_chain (TYPE_FIELDS (type), field_idx); - gcc_assert (field != NULL_TREE); - - return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), - desc, field, NULL_TREE); -} - -tree -gfc_get_cfi_desc_base_addr (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_BASE_ADDR); -} - -tree -gfc_get_cfi_desc_elem_len (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_ELEM_LEN); -} - -tree -gfc_get_cfi_desc_version (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_VERSION); -} - -tree -gfc_get_cfi_desc_rank (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_RANK); -} - -tree -gfc_get_cfi_desc_type (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_TYPE); -} - -tree -gfc_get_cfi_desc_attribute (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_ATTRIBUTE); -} - -static tree -gfc_get_cfi_dim_item (tree desc, tree idx, unsigned field_idx) -{ - tree tmp = gfc_get_cfi_descriptor_field (desc, CFI_FIELD_DIM); - tmp = gfc_build_array_ref (tmp, idx, NULL_TREE, true); - tree field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), field_idx); - gcc_assert (field != NULL_TREE); - return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), - tmp, field, NULL_TREE); -} - -tree -gfc_get_cfi_dim_lbound (tree desc, tree idx) -{ - return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_LOWER_BOUND); -} - -tree -gfc_get_cfi_dim_extent (tree desc, tree idx) -{ - return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_EXTENT); -} - -tree -gfc_get_cfi_dim_sm (tree desc, tree idx) -{ - return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_SM); -} - -#undef CFI_FIELD_BASE_ADDR -#undef CFI_FIELD_ELEM_LEN -#undef CFI_FIELD_VERSION -#undef CFI_FIELD_RANK -#undef CFI_FIELD_ATTRIBUTE -#undef CFI_FIELD_TYPE -#undef CFI_FIELD_DIM - -#undef CFI_DIM_FIELD_LOWER_BOUND -#undef CFI_DIM_FIELD_EXTENT -#undef CFI_DIM_FIELD_SM - -/* Build expressions to access the members of an array descriptor. - It's surprisingly easy to mess up here, so never access - an array descriptor by "brute force", always use these -
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] match: Simplify double not and double negate to a non_lvalue
https://gcc.gnu.org/g:6e0871403d43c8633375c420d177cf7817c0165a commit 6e0871403d43c8633375c420d177cf7817c0165a Author: Mikael Morin Date: Thu Jul 4 12:59:34 2024 +0200 match: Simplify double not and double negate to a non_lvalue I noticed while testing the second patch that none of the NON_LVALUE_EXPR trees I expected were generated when simplifying unary operators, whereas they were generated with binary operators. Regression tested on x86_64-linux. OK for master? -- 8< -- gcc/ChangeLog: * match.pd (`-(-X)`, `~(~X)`): Add a NON_LVALUE_EXPR wrapper to the simplification of doubled unary operators NEGATE_EXPR and BIT_NOT_EXPR. gcc/testsuite/ChangeLog: * gfortran.dg/non_lvalue_1.f90: New test. Diff: --- gcc/match.pd | 4 ++-- gcc/testsuite/gfortran.dg/non_lvalue_1.f90 | 21 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/gcc/match.pd b/gcc/match.pd index 0f53c162fce3..ad0fa8f10044 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2357,7 +2357,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* ~~x -> x */ (simplify (bit_not (bit_not @0)) - @0) + (non_lvalue @0)) /* zero_one_valued_p will match when a value is known to be either 0 or 1 including constants 0 or 1. @@ -4037,7 +4037,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (negate (nop_convert? (negate @1))) (if (!TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@1))) - (view_convert @1))) + (non_lvalue (view_convert @1 /* We can't reassociate floating-point unless -fassociative-math or fixed-point plus or minus because of saturation to +-Inf. */ diff --git a/gcc/testsuite/gfortran.dg/non_lvalue_1.f90 b/gcc/testsuite/gfortran.dg/non_lvalue_1.f90 new file mode 100644 index ..ac52b2720945 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/non_lvalue_1.f90 @@ -0,0 +1,21 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } +! +! Check the generation of NON_LVALUE_EXPR trees in cases where a unary operator expression +! simplifies to a data reference. + +! A NON_LVALUE_EXPR is generated for a double negation that simplifies to a data reference. */ +function f1 (f1_arg1) + integer, value :: f1_arg1 + integer :: f1 + f1 = -(-f1_arg1) +end function +! { dg-final { scan-tree-dump "__result_f1 = NON_LVALUE_EXPR ;" "original" } } + +! A NON_LVALUE_EXPR is generated for a double complement that simplifies to a data reference. */ +function f2 (f2_arg1) + integer, value :: f2_arg1 + integer :: f2 + f2 = not(not(f2_arg1)) +end function +! { dg-final { scan-tree-dump "__result_f2 = NON_LVALUE_EXPR ;" "original" } }
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Ajout nom de variable au variables temporaires select type
https://gcc.gnu.org/g:699bf6766a492c64d28b977c9598baf05fb30cd4 commit 699bf6766a492c64d28b977c9598baf05fb30cd4 Author: Mikael Morin Date: Wed Jun 18 18:07:54 2025 +0200 Ajout nom de variable au variables temporaires select type Diff: --- gcc/fortran/match.cc | 35 +++ gcc/fortran/resolve.cc | 27 --- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc index a99a757bede6..09082db8b24c 100644 --- a/gcc/fortran/match.cc +++ b/gcc/fortran/match.cc @@ -7171,7 +7171,7 @@ select_type_push (gfc_symbol *sel) /* Set the temporary for the current intrinsic SELECT TYPE selector. */ static gfc_symtree * -select_intrinsic_set_tmp (gfc_typespec *ts) +select_intrinsic_set_tmp (gfc_typespec *ts, const char *var_name) { char name[GFC_MAX_SYMBOL_LEN]; gfc_symtree *tmp; @@ -7192,12 +7192,12 @@ select_intrinsic_set_tmp (gfc_typespec *ts) charlen = gfc_mpz_get_hwi (ts->u.cl->length->value.integer); if (ts->type != BT_CHARACTER) -sprintf (name, "__tmp_%s_%d", gfc_basic_typename (ts->type), -ts->kind); +sprintf (name, "__tmp_%s_%d_%s", gfc_basic_typename (ts->type), +ts->kind, var_name); else snprintf (name, sizeof (name), - "__tmp_%s_" HOST_WIDE_INT_PRINT_DEC "_%d", - gfc_basic_typename (ts->type), charlen, ts->kind); + "__tmp_%s_" HOST_WIDE_INT_PRINT_DEC "_%d_%s", + gfc_basic_typename (ts->type), charlen, ts->kind, var_name); gfc_get_sym_tree (name, gfc_current_ns, &tmp, false); sym = tmp->n.sym; @@ -7222,6 +7222,22 @@ select_intrinsic_set_tmp (gfc_typespec *ts) } +static const char * +get_select_type_var_name () +{ + const char *name = ""; + gfc_expr *e = gfc_state_stack->construct->expr1; + if (e->symtree) +name = e->symtree->name; + for (gfc_ref *r = e->ref; r; r = r->next) +if (r->type == REF_COMPONENT + && strcmp (r->u.c.component->name, "_data") != 0) + name = r->u.c.component->name; + + return name; +} + + /* Set up a temporary for the current TYPE IS / CLASS IS branch . */ static void @@ -7239,7 +7255,10 @@ select_type_set_tmp (gfc_typespec *ts) return; } - tmp = select_intrinsic_set_tmp (ts); + + const char *var_name = get_select_type_var_name (); + + tmp = select_intrinsic_set_tmp (ts, var_name); if (tmp == NULL) { @@ -7247,9 +7266,9 @@ select_type_set_tmp (gfc_typespec *ts) return; if (ts->type == BT_CLASS) - sprintf (name, "__tmp_class_%s", ts->u.derived->name); + sprintf (name, "__tmp_class_%s_%s", ts->u.derived->name, var_name); else - sprintf (name, "__tmp_type_%s", ts->u.derived->name); + sprintf (name, "__tmp_type_%s_%s", ts->u.derived->name, var_name); gfc_get_sym_tree (name, gfc_current_ns, &tmp, false); sym = tmp->n.sym; diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index 5413d8f9c542..0070e8c170d2 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -10819,6 +10819,8 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns) ref = gfc_copy_ref (ref); } + gfc_expr *orig_expr1 = code->expr1; + /* Add EXEC_SELECT to switch on type. */ new_st = gfc_get_code (code->op); new_st->expr1 = code->expr1; @@ -10846,7 +10848,6 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns) for (body = code->block; body; body = body->block) { gfc_symbol *vtab; - gfc_expr *e; c = body->ext.block.case_list; /* Generate an index integer expression for address of the @@ -10854,6 +10855,7 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns) is stored in c->high and is used to resolve intrinsic cases. */ if (c->ts.type != BT_UNKNOWN) { + gfc_expr *e; if (c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS) { vtab = gfc_find_derived_vtab (c->ts.u.derived); @@ -10886,11 +10888,22 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns) when this case is actually true, so build a new ASSOCIATE that does precisely this here (instead of using the 'global' one). */ + const char * var_name = ""; + if (orig_expr1->symtree) + var_name = orig_expr1->symtree->name; + if (orig_expr1->ref) + { + for (gfc_ref *r = orig_expr1->ref; r; r = r->next) + if (r->type == REF_COMPONENT + && !(strcmp (r->u.c.component->name, "_data") == 0 +|| strcmp (r->u.c.component->name, "_vptr") == 0)) + var_name = r->u.c.component->name; + } if (c->ts.type == BT_CLASS) - sprintf (name, "__tmp_class_%s", c->ts.u.derived->name); + sprintf (name, "__tmp_class_%s_%s", c->ts.u.derived->name, var_name); else if (c->ts.type == BT_DERIVED) - sprintf (name, "__tmp_type_%s",
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Mises à jour dumps
https://gcc.gnu.org/g:4ddf60dad9d53404a18e47cd3565b3e3586a65c3 commit 4ddf60dad9d53404a18e47cd3565b3e3586a65c3 Author: Mikael Morin Date: Fri Mar 14 16:27:05 2025 +0100 Mises à jour dumps Mise à jour dump bind-c-contiguous-2.f90 Mise à jour dumps coarray_poly_*.f90 Mise à jour dump coarray_lock_7.f90 Correction dump coarray_allocate_7.f08 Mise à jour dump coarray_lib_alloc_4.f90 Mise à jour dump coarray_lib_alloc_2.f90 Mise à jour dump coarray_lib_alloc_3.f90 Mise à jour dump coarray_lib_alloc_1.f90 Mise à jour dump coarray_lib_token_4.f90 Mise à jour dump coarray_lib_token_3.f90 Mise à jour dump coarray_lib_token_2.f90 Mise à jour dump contiguous_3.f90 Diff: --- gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_allocate_7.f08 | 2 +- gcc/testsuite/gfortran.dg/coarray_lib_alloc_1.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_lib_alloc_2.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_lib_alloc_3.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_lib_alloc_4.f90 | 6 +++--- gcc/testsuite/gfortran.dg/coarray_lib_token_2.f90 | 4 ++-- gcc/testsuite/gfortran.dg/coarray_lib_token_3.f90 | 4 ++-- gcc/testsuite/gfortran.dg/coarray_lib_token_4.f90 | 6 +++--- gcc/testsuite/gfortran.dg/coarray_lock_7.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_poly_4.f90 | 2 +- gcc/testsuite/gfortran.dg/coarray_poly_5.f90 | 2 +- gcc/testsuite/gfortran.dg/coarray_poly_6.f90 | 2 +- gcc/testsuite/gfortran.dg/coarray_poly_7.f90 | 2 +- gcc/testsuite/gfortran.dg/coarray_poly_8.f90 | 2 +- gcc/testsuite/gfortran.dg/contiguous_3.f90| 4 ++-- 16 files changed, 48 insertions(+), 48 deletions(-) diff --git a/gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 b/gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 index 5b546800e7ff..243c4a57cba4 100644 --- a/gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 +++ b/gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 @@ -60,12 +60,12 @@ end ! Copy in + out -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) xx->data \\+ xx->dtype.elem_len \\* arrayidx.\[0-9\]+, _xx->base_addr \\+ shift.\[0-9\]+, xx->dtype.elem_len\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(\(void \*\) xx->data \+ xx->dtype.elem_len \* arrayidx.[0-9]+, _xx->base_addr \+ shift.[0-9]+, (?:NON_LVALUE_EXPR <)?xx->dtype.elem_len>?\);} 1 "original" } } ! { dg-final { scan-tree-dump-times "xx->data = \\(void \\* restrict\\) _xx->base_addr;" 1 "original" } } -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) xx->data \\+ xx->dtype.elem_len \\* arrayidx.\[0-9\]+, _xx->base_addr \\+ shift.\[0-9\]+, xx->dtype.elem_len\\);" 1 "original" } } -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) yy->data \\+ yy->dtype.elem_len \\* arrayidx.\[0-9\]+, _yy->base_addr \\+ shift.\[0-9\]+, yy->dtype.elem_len\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(\(void \*\) xx->data \+ xx->dtype.elem_len \* arrayidx.[0-9]+, _xx->base_addr \+ shift.[0-9]+, (?:NON_LVALUE_EXPR <)?xx->dtype.elem_len>?\);} 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(\(void \*\) yy->data \+ yy->dtype.elem_len \* arrayidx.[0-9]+, _yy->base_addr \+ shift.[0-9]+, (?:NON_LVALUE_EXPR <)?yy->dtype.elem_len>?\);} 1 "original" } } ! { dg-final { scan-tree-dump-times "yy->data = \\(void \\* restrict\\) _yy->base_addr;" 1 "original" } } -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(_yy->base_addr \\+ shift.\[0-9\]+, \\(void \\*\\) yy->data \\+ yy->dtype.elem_len \\* arrayidx.\[0-9\]+, yy->dtype.elem_len\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(_yy->base_addr \+ shift.[0-9]+, \(void \*\) yy->data \+ yy->dtype.elem_len \* arrayidx.[0-9]+, (?:NON_LVALUE_EXPR <)?yy->dtype.elem_len>?\);} 1 "original" } } ! { dg-final { scan-tree-dump-times "zz = \\(character\\(kind=1\\)\\\[0:\\\]\\\[1:zz.\[0-9\]+\\\] \\* restrict\\) _zz->base_addr;" 1 "original" } } ! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) zz \\+ _zz->elem_len \\* arrayidx.\[0-9\]+, _zz->base_addr \\+ shift.\[0-9\]+, _zz->elem_len\\);" 1 "original" } } @@ -73,10 +73,10 @@ end ! Copy in only -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) aa->data \\+ aa->dtype.elem_len \\* arrayidx.\[0-9\]+, _aa->base_addr \\+ shift.\[0-9\]+, aa->dtype.elem_len\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(\(void \*\) aa->data \+ aa->dtype.elem_len \* arrayidx.[0-9]+, _aa->base_addr \+ shift.[0-9]+, (?:NON_LVALUE_EXPR <)?aa->dtype.elem_len>?\);} 1 "original" } } ! { dg-final { scan-tree-dump-times "aa->data = \\(void \\* restrict\\) _aa->base_addr;" 1 "original" } } -
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Correction erreurs non-lvalue lhs pr113363.f90
https://gcc.gnu.org/g:8a125adccd48105286c8b19b5ddf5befd97a58be commit 8a125adccd48105286c8b19b5ddf5befd97a58be Author: Mikael Morin Date: Wed Feb 12 10:47:31 2025 +0100 Correction erreurs non-lvalue lhs pr113363.f90 Diff: --- gcc/fortran/trans-decl.cc | 21 + gcc/fortran/trans.cc | 4 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index 43bd7be54cb7..f60b6d916201 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -5142,10 +5142,23 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) if (!sym->attr.dummy || sym->attr.intent == INTENT_OUT) { /* Nullify when entering the scope. */ - tmp = fold_build2_loc (input_location, MODIFY_EXPR, -TREE_TYPE (se.expr), se.expr, -fold_convert (TREE_TYPE (se.expr), - null_pointer_node)); + if (sym->ts.type == BT_CLASS + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension)) + { + stmtblock_t nullify; + gfc_init_block (&nullify); + gfc_conv_descriptor_data_set (&nullify, descriptor, + null_pointer_node); + tmp = gfc_finish_block (&nullify); + } + else + { + tmp = fold_build2_loc (input_location, MODIFY_EXPR, +TREE_TYPE (se.expr), se.expr, +fold_convert (TREE_TYPE (se.expr), + null_pointer_node)); + } if (sym->attr.optional) { tree present = gfc_conv_expr_present (sym); diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc index fdeb1e89a765..f1966bd881f0 100644 --- a/gcc/fortran/trans.cc +++ b/gcc/fortran/trans.cc @@ -1737,7 +1737,7 @@ gfc_finalize_tree_expr (gfc_se *se, gfc_symbol *derived, gfc_call_free (data_ptr), build_empty_stmt (input_location)); gfc_add_expr_to_block (&se->loop->post, tmp); - gfc_add_modify (&se->loop->post, data_ptr, data_null); + gfc_conv_descriptor_data_set (&se->loop->post, desc, data_null); } else { @@ -1751,7 +1751,7 @@ gfc_finalize_tree_expr (gfc_se *se, gfc_symbol *derived, gfc_call_free (data_ptr), build_empty_stmt (input_location)); gfc_add_expr_to_block (&se->finalblock, tmp); - gfc_add_modify (&se->finalblock, data_ptr, data_null); + gfc_conv_descriptor_data_set (&se->finalblock, desc, data_null); } } }
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Interdiction non-lvalue as lhs
https://gcc.gnu.org/g:3ba96b08d42bab4f46bf60c3455608e098ce7919 commit 3ba96b08d42bab4f46bf60c3455608e098ce7919 Author: Mikael Morin Date: Tue Feb 11 21:34:11 2025 +0100 Interdiction non-lvalue as lhs git commit correction erreur gimplify Diff: --- gcc/gimplify.cc | 6 ++ 1 file changed, 6 insertions(+) diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 9f9ff92d0642..96e12c370802 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -7244,6 +7244,12 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR || TREE_CODE (*expr_p) == INIT_EXPR); + if (TREE_CODE (*to_p) == NON_LVALUE_EXPR) +{ + error ("non-lvalue used as lhs in %qD", *expr_p); + return GS_ERROR; +} + /* Trying to simplify a clobber using normal logic doesn't work, so handle it here. */ if (TREE_CLOBBER_P (*from_p))
[gcc] Created branch 'mikael/heads/refactor_descriptor_v06_temp' in namespace 'refs/users'
The branch 'mikael/heads/refactor_descriptor_v06_temp' was created in namespace 'refs/users' pointing to: 8a125adccd48... Correction erreurs non-lvalue lhs pr113363.f90
[gcc r16-1577] expand: Align PARM_DECLs again to at least BITS_PER_WORD if possible [PR120689]
https://gcc.gnu.org/g:14dd61736fee45b2a83502bafa1c969a2610dd1c commit r16-1577-g14dd61736fee45b2a83502bafa1c969a2610dd1c Author: Jakub Jelinek Date: Thu Jun 19 14:48:00 2025 +0200 expand: Align PARM_DECLs again to at least BITS_PER_WORD if possible [PR120689] The following testcase shows a regression caused by the r10-577 change made for cris. Before that change, the MEM holding (in this case 3 byte) struct parameter was BITS_PER_WORD aligned, now it is just BITS_PER_UNIT aligned and that causes significantly worse generated code. So, the MAX (DECL_ALIGN (parm), BITS_PER_WORD) extra alignment clearly doesn't help just STRICT_ALIGNMENT targets, but other targets as well. Of course, it isn't worth doing stack realignment in the rare case of MAX_SUPPORTED_STACK_ALIGNMENT < BITS_PER_WORD targets like cris, so the patch only bumps the alignment if it won't go the > MAX_SUPPORTED_STACK_ALIGNMENT path because of that optimization. The patch keeps the gcc 15 behavior for avr, pru, m68k and cris (at least some options for those) and restores the behavior before r10-577 on other targets. The change on the testcase on x86_64 is: bar: - movl%edi, %eax - movzbl %dil, %r8d - movl%esi, %ecx - movzbl %sil, %r10d - movl%edx, %r9d - movzbl %dl, %r11d - shrl$16, %edi - andl$65280, %ecx - shrl$16, %esi - shrl$16, %edx - andl$65280, %r9d - orq %r10, %rcx - movzbl %dl, %edx - movzbl %sil, %esi - andl$65280, %eax - movzbl %dil, %edi - salq$16, %rdx - orq %r11, %r9 - salq$16, %rsi - orq %r8, %rax - salq$16, %rdi - orq %r9, %rdx - orq %rcx, %rsi - orq %rax, %rdi jmp foo 2025-06-19 Jakub Jelinek PR target/120689 * function.cc (assign_parm_setup_block): Align parm to at least word alignment even on !STRICT_ALIGNMENT targets, as long as BITS_PER_WORD is not larger than MAX_SUPPORTED_STACK_ALIGNMENT. * gcc.target/i386/pr120689.c: New test. Diff: --- gcc/function.cc | 2 +- gcc/testsuite/gcc.target/i386/pr120689.c | 17 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/gcc/function.cc b/gcc/function.cc index a5b245a98e91..a3a74b44b916 100644 --- a/gcc/function.cc +++ b/gcc/function.cc @@ -2937,7 +2937,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all, if (stack_parm == 0) { HOST_WIDE_INT parm_align - = (STRICT_ALIGNMENT + = ((STRICT_ALIGNMENT || BITS_PER_WORD <= MAX_SUPPORTED_STACK_ALIGNMENT) ? MAX (DECL_ALIGN (parm), BITS_PER_WORD) : DECL_ALIGN (parm)); SET_DECL_ALIGN (parm, parm_align); diff --git a/gcc/testsuite/gcc.target/i386/pr120689.c b/gcc/testsuite/gcc.target/i386/pr120689.c new file mode 100644 index ..cd10cdb487df --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120689.c @@ -0,0 +1,17 @@ +/* PR target/120689 */ +/* { dg-do compile { target lp64 } } */ +/* { dg-options "-O2 -mtune=generic -fno-stack-protector -masm=att" } */ +/* { dg-final { scan-assembler-not "\t\(movzbl\|shrl\|salq\|orq\)\t" } } */ + +struct S { char a, b, c; }; + +[[gnu::noipa]] +void foo (struct S x, struct S y, struct S z) +{ +} + +void +bar (struct S x, struct S y, struct S z) +{ + [[gnu::musttail]] return foo (x, y, z); +}
[gcc] Deleted branch 'mikael/heads/refactor_descriptor_v06_temp' in namespace 'refs/users'
The branch 'mikael/heads/refactor_descriptor_v06_temp' in namespace 'refs/users' was deleted. It previously pointed to: 8a125adccd48... Correction erreurs non-lvalue lhs pr113363.f90 Diff: !!! WARNING: THE FOLLOWING COMMITS ARE NO LONGER ACCESSIBLE (LOST): --- 8a125ad... Correction erreurs non-lvalue lhs pr113363.f90 3ba96b0... Interdiction non-lvalue as lhs 4ddf60d... Mises à jour dumps ac820f7... match: Unwrap non-lvalue as unary or binary operand 6e08714... match: Simplify double not and double negate to a non_lvalu 699bf67... Ajout nom de variable au variables temporaires select type ed2b5eb... Déplacement fonctions descripteur vers fichier séparé
[gcc] Created branch 'mikael/heads/refactor_descriptor_v06_temp' in namespace 'refs/users'
The branch 'mikael/heads/refactor_descriptor_v06_temp' was created in namespace 'refs/users' pointing to: 5b84bee6dbab... suppression non_lvalue avec exact_div
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Déplacement fonctions descripteur vers fichier séparé
https://gcc.gnu.org/g:3a320d8bcfc6fe6f86172e9a779a7a9359070f29 commit 3a320d8bcfc6fe6f86172e9a779a7a9359070f29 Author: Mikael Morin Date: Wed Jun 18 17:31:23 2025 +0200 Déplacement fonctions descripteur vers fichier séparé Diff: --- gcc/fortran/Make-lang.in| 7 +- gcc/fortran/trans-array.cc | 515 +- gcc/fortran/trans-descriptor.cc | 534 gcc/fortran/trans-descriptor.h | 67 + 4 files changed, 610 insertions(+), 513 deletions(-) diff --git a/gcc/fortran/Make-lang.in b/gcc/fortran/Make-lang.in index 5b2f921bf2ef..2ddb0366e9dc 100644 --- a/gcc/fortran/Make-lang.in +++ b/gcc/fortran/Make-lang.in @@ -63,9 +63,10 @@ F95_PARSER_OBJS = fortran/arith.o fortran/array.o fortran/bbt.o \ F95_OBJS = $(F95_PARSER_OBJS) $(FORTRAN_TARGET_OBJS) \ fortran/convert.o fortran/dependency.o fortran/f95-lang.o \ fortran/trans.o fortran/trans-array.o fortran/trans-common.o \ -fortran/trans-const.o fortran/trans-decl.o fortran/trans-expr.o \ -fortran/trans-intrinsic.o fortran/trans-io.o fortran/trans-openmp.o \ -fortran/trans-stmt.o fortran/trans-types.o fortran/frontend-passes.o +fortran/trans-const.o fortran/trans-decl.o fortran/trans-descriptor.o \ +fortran/trans-expr.o fortran/trans-intrinsic.o fortran/trans-io.o \ +fortran/trans-openmp.o fortran/trans-stmt.o fortran/trans-types.o \ +fortran/frontend-passes.o fortran_OBJS = $(F95_OBJS) fortran/gfortranspec.o diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 960613167f72..8d90bec0d85f 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -92,6 +92,7 @@ along with GCC; see the file COPYING3. If not see #include "trans-array.h" #include "trans-const.h" #include "dependency.h" +#include "trans-descriptor.h" static bool gfc_get_array_constructor_size (mpz_t *, gfc_constructor_base); @@ -106,466 +107,6 @@ gfc_array_dataptr_type (tree desc) return (GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (desc))); } -/* Build expressions to access members of the CFI descriptor. */ -#define CFI_FIELD_BASE_ADDR 0 -#define CFI_FIELD_ELEM_LEN 1 -#define CFI_FIELD_VERSION 2 -#define CFI_FIELD_RANK 3 -#define CFI_FIELD_ATTRIBUTE 4 -#define CFI_FIELD_TYPE 5 -#define CFI_FIELD_DIM 6 - -#define CFI_DIM_FIELD_LOWER_BOUND 0 -#define CFI_DIM_FIELD_EXTENT 1 -#define CFI_DIM_FIELD_SM 2 - -static tree -gfc_get_cfi_descriptor_field (tree desc, unsigned field_idx) -{ - tree type = TREE_TYPE (desc); - gcc_assert (TREE_CODE (type) == RECORD_TYPE - && TYPE_FIELDS (type) - && (strcmp ("base_addr", -IDENTIFIER_POINTER (DECL_NAME (TYPE_FIELDS (type - == 0)); - tree field = gfc_advance_chain (TYPE_FIELDS (type), field_idx); - gcc_assert (field != NULL_TREE); - - return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), - desc, field, NULL_TREE); -} - -tree -gfc_get_cfi_desc_base_addr (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_BASE_ADDR); -} - -tree -gfc_get_cfi_desc_elem_len (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_ELEM_LEN); -} - -tree -gfc_get_cfi_desc_version (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_VERSION); -} - -tree -gfc_get_cfi_desc_rank (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_RANK); -} - -tree -gfc_get_cfi_desc_type (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_TYPE); -} - -tree -gfc_get_cfi_desc_attribute (tree desc) -{ - return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_ATTRIBUTE); -} - -static tree -gfc_get_cfi_dim_item (tree desc, tree idx, unsigned field_idx) -{ - tree tmp = gfc_get_cfi_descriptor_field (desc, CFI_FIELD_DIM); - tmp = gfc_build_array_ref (tmp, idx, NULL_TREE, true); - tree field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), field_idx); - gcc_assert (field != NULL_TREE); - return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), - tmp, field, NULL_TREE); -} - -tree -gfc_get_cfi_dim_lbound (tree desc, tree idx) -{ - return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_LOWER_BOUND); -} - -tree -gfc_get_cfi_dim_extent (tree desc, tree idx) -{ - return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_EXTENT); -} - -tree -gfc_get_cfi_dim_sm (tree desc, tree idx) -{ - return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_SM); -} - -#undef CFI_FIELD_BASE_ADDR -#undef CFI_FIELD_ELEM_LEN -#undef CFI_FIELD_VERSION -#undef CFI_FIELD_RANK -#undef CFI_FIELD_ATTRIBUTE -#undef CFI_FIELD_TYPE -#undef CFI_FIELD_DIM - -#undef CFI_DIM_FIELD_LOWER_BOUND -#undef CFI_DIM_FIELD_EXTENT -#undef CFI_DIM_FIELD_SM - -/* Build expressions to access the members of an array descriptor. - It's surprisingly easy to mess up here, so never access - an array descriptor by "brute force", always use these -
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] match: Simplify double not and double negate to a non_lvalue
https://gcc.gnu.org/g:8eddaa1ebb1af875b8d3a07005296fbd17620d19 commit 8eddaa1ebb1af875b8d3a07005296fbd17620d19 Author: Mikael Morin Date: Thu Jul 4 12:59:34 2024 +0200 match: Simplify double not and double negate to a non_lvalue I noticed while testing the second patch that none of the NON_LVALUE_EXPR trees I expected were generated when simplifying unary operators, whereas they were generated with binary operators. Regression tested on x86_64-linux. OK for master? -- 8< -- gcc/ChangeLog: * match.pd (`-(-X)`, `~(~X)`): Add a NON_LVALUE_EXPR wrapper to the simplification of doubled unary operators NEGATE_EXPR and BIT_NOT_EXPR. gcc/testsuite/ChangeLog: * gfortran.dg/non_lvalue_1.f90: New test. Diff: --- gcc/match.pd | 4 ++-- gcc/testsuite/gfortran.dg/non_lvalue_1.f90 | 21 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/gcc/match.pd b/gcc/match.pd index 0f53c162fce3..ad0fa8f10044 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2357,7 +2357,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* ~~x -> x */ (simplify (bit_not (bit_not @0)) - @0) + (non_lvalue @0)) /* zero_one_valued_p will match when a value is known to be either 0 or 1 including constants 0 or 1. @@ -4037,7 +4037,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (negate (nop_convert? (negate @1))) (if (!TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@1))) - (view_convert @1))) + (non_lvalue (view_convert @1 /* We can't reassociate floating-point unless -fassociative-math or fixed-point plus or minus because of saturation to +-Inf. */ diff --git a/gcc/testsuite/gfortran.dg/non_lvalue_1.f90 b/gcc/testsuite/gfortran.dg/non_lvalue_1.f90 new file mode 100644 index ..ac52b2720945 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/non_lvalue_1.f90 @@ -0,0 +1,21 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } +! +! Check the generation of NON_LVALUE_EXPR trees in cases where a unary operator expression +! simplifies to a data reference. + +! A NON_LVALUE_EXPR is generated for a double negation that simplifies to a data reference. */ +function f1 (f1_arg1) + integer, value :: f1_arg1 + integer :: f1 + f1 = -(-f1_arg1) +end function +! { dg-final { scan-tree-dump "__result_f1 = NON_LVALUE_EXPR ;" "original" } } + +! A NON_LVALUE_EXPR is generated for a double complement that simplifies to a data reference. */ +function f2 (f2_arg1) + integer, value :: f2_arg1 + integer :: f2 + f2 = not(not(f2_arg1)) +end function +! { dg-final { scan-tree-dump "__result_f2 = NON_LVALUE_EXPR ;" "original" } }
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Mises à jour dumps
https://gcc.gnu.org/g:4c3cdde3b9e8babde351aa86f7bf53b7c7dad1f3 commit 4c3cdde3b9e8babde351aa86f7bf53b7c7dad1f3 Author: Mikael Morin Date: Fri Mar 14 16:27:05 2025 +0100 Mises à jour dumps Mise à jour dump bind-c-contiguous-2.f90 Mise à jour dumps coarray_poly_*.f90 Mise à jour dump coarray_lock_7.f90 Correction dump coarray_allocate_7.f08 Mise à jour dump coarray_lib_alloc_4.f90 Mise à jour dump coarray_lib_alloc_2.f90 Mise à jour dump coarray_lib_alloc_3.f90 Mise à jour dump coarray_lib_alloc_1.f90 Mise à jour dump coarray_lib_token_4.f90 Mise à jour dump coarray_lib_token_3.f90 Mise à jour dump coarray_lib_token_2.f90 Mise à jour dump contiguous_3.f90 Correction dump coarray_poly_8 Diff: --- gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_allocate_7.f08 | 2 +- gcc/testsuite/gfortran.dg/coarray_lib_alloc_1.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_lib_alloc_2.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_lib_alloc_3.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_lib_alloc_4.f90 | 6 +++--- gcc/testsuite/gfortran.dg/coarray_lib_token_2.f90 | 4 ++-- gcc/testsuite/gfortran.dg/coarray_lib_token_3.f90 | 4 ++-- gcc/testsuite/gfortran.dg/coarray_lib_token_4.f90 | 6 +++--- gcc/testsuite/gfortran.dg/coarray_lock_7.f90 | 12 ++-- gcc/testsuite/gfortran.dg/coarray_poly_4.f90 | 2 +- gcc/testsuite/gfortran.dg/coarray_poly_5.f90 | 2 +- gcc/testsuite/gfortran.dg/coarray_poly_6.f90 | 2 +- gcc/testsuite/gfortran.dg/coarray_poly_7.f90 | 2 +- gcc/testsuite/gfortran.dg/coarray_poly_8.f90 | 2 +- gcc/testsuite/gfortran.dg/contiguous_3.f90| 4 ++-- 16 files changed, 48 insertions(+), 48 deletions(-) diff --git a/gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 b/gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 index 5b546800e7ff..243c4a57cba4 100644 --- a/gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 +++ b/gcc/testsuite/gfortran.dg/bind-c-contiguous-2.f90 @@ -60,12 +60,12 @@ end ! Copy in + out -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) xx->data \\+ xx->dtype.elem_len \\* arrayidx.\[0-9\]+, _xx->base_addr \\+ shift.\[0-9\]+, xx->dtype.elem_len\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(\(void \*\) xx->data \+ xx->dtype.elem_len \* arrayidx.[0-9]+, _xx->base_addr \+ shift.[0-9]+, (?:NON_LVALUE_EXPR <)?xx->dtype.elem_len>?\);} 1 "original" } } ! { dg-final { scan-tree-dump-times "xx->data = \\(void \\* restrict\\) _xx->base_addr;" 1 "original" } } -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) xx->data \\+ xx->dtype.elem_len \\* arrayidx.\[0-9\]+, _xx->base_addr \\+ shift.\[0-9\]+, xx->dtype.elem_len\\);" 1 "original" } } -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) yy->data \\+ yy->dtype.elem_len \\* arrayidx.\[0-9\]+, _yy->base_addr \\+ shift.\[0-9\]+, yy->dtype.elem_len\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(\(void \*\) xx->data \+ xx->dtype.elem_len \* arrayidx.[0-9]+, _xx->base_addr \+ shift.[0-9]+, (?:NON_LVALUE_EXPR <)?xx->dtype.elem_len>?\);} 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(\(void \*\) yy->data \+ yy->dtype.elem_len \* arrayidx.[0-9]+, _yy->base_addr \+ shift.[0-9]+, (?:NON_LVALUE_EXPR <)?yy->dtype.elem_len>?\);} 1 "original" } } ! { dg-final { scan-tree-dump-times "yy->data = \\(void \\* restrict\\) _yy->base_addr;" 1 "original" } } -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(_yy->base_addr \\+ shift.\[0-9\]+, \\(void \\*\\) yy->data \\+ yy->dtype.elem_len \\* arrayidx.\[0-9\]+, yy->dtype.elem_len\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(_yy->base_addr \+ shift.[0-9]+, \(void \*\) yy->data \+ yy->dtype.elem_len \* arrayidx.[0-9]+, (?:NON_LVALUE_EXPR <)?yy->dtype.elem_len>?\);} 1 "original" } } ! { dg-final { scan-tree-dump-times "zz = \\(character\\(kind=1\\)\\\[0:\\\]\\\[1:zz.\[0-9\]+\\\] \\* restrict\\) _zz->base_addr;" 1 "original" } } ! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) zz \\+ _zz->elem_len \\* arrayidx.\[0-9\]+, _zz->base_addr \\+ shift.\[0-9\]+, _zz->elem_len\\);" 1 "original" } } @@ -73,10 +73,10 @@ end ! Copy in only -! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) aa->data \\+ aa->dtype.elem_len \\* arrayidx.\[0-9\]+, _aa->base_addr \\+ shift.\[0-9\]+, aa->dtype.elem_len\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times {__builtin_memcpy \(\(void \*\) aa->data \+ aa->dtype.elem_len \* arrayidx.[0-9]+, _aa->base_addr \+ shift.[0-9]+, (?:NON_LVALUE_EXPR <)?aa->dtype.elem_len>?\);} 1 "original" } } ! { dg-final { scan-tree-dump-times "aa->data = \\(void \\* restrict
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Ajout nom de variable au variables temporaires select type
https://gcc.gnu.org/g:7a9396443bd81b27d61a99eefe1a29f832fc1434 commit 7a9396443bd81b27d61a99eefe1a29f832fc1434 Author: Mikael Morin Date: Wed Jun 18 18:07:54 2025 +0200 Ajout nom de variable au variables temporaires select type Diff: --- gcc/fortran/match.cc | 35 +++ gcc/fortran/resolve.cc | 27 --- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc index a99a757bede6..09082db8b24c 100644 --- a/gcc/fortran/match.cc +++ b/gcc/fortran/match.cc @@ -7171,7 +7171,7 @@ select_type_push (gfc_symbol *sel) /* Set the temporary for the current intrinsic SELECT TYPE selector. */ static gfc_symtree * -select_intrinsic_set_tmp (gfc_typespec *ts) +select_intrinsic_set_tmp (gfc_typespec *ts, const char *var_name) { char name[GFC_MAX_SYMBOL_LEN]; gfc_symtree *tmp; @@ -7192,12 +7192,12 @@ select_intrinsic_set_tmp (gfc_typespec *ts) charlen = gfc_mpz_get_hwi (ts->u.cl->length->value.integer); if (ts->type != BT_CHARACTER) -sprintf (name, "__tmp_%s_%d", gfc_basic_typename (ts->type), -ts->kind); +sprintf (name, "__tmp_%s_%d_%s", gfc_basic_typename (ts->type), +ts->kind, var_name); else snprintf (name, sizeof (name), - "__tmp_%s_" HOST_WIDE_INT_PRINT_DEC "_%d", - gfc_basic_typename (ts->type), charlen, ts->kind); + "__tmp_%s_" HOST_WIDE_INT_PRINT_DEC "_%d_%s", + gfc_basic_typename (ts->type), charlen, ts->kind, var_name); gfc_get_sym_tree (name, gfc_current_ns, &tmp, false); sym = tmp->n.sym; @@ -7222,6 +7222,22 @@ select_intrinsic_set_tmp (gfc_typespec *ts) } +static const char * +get_select_type_var_name () +{ + const char *name = ""; + gfc_expr *e = gfc_state_stack->construct->expr1; + if (e->symtree) +name = e->symtree->name; + for (gfc_ref *r = e->ref; r; r = r->next) +if (r->type == REF_COMPONENT + && strcmp (r->u.c.component->name, "_data") != 0) + name = r->u.c.component->name; + + return name; +} + + /* Set up a temporary for the current TYPE IS / CLASS IS branch . */ static void @@ -7239,7 +7255,10 @@ select_type_set_tmp (gfc_typespec *ts) return; } - tmp = select_intrinsic_set_tmp (ts); + + const char *var_name = get_select_type_var_name (); + + tmp = select_intrinsic_set_tmp (ts, var_name); if (tmp == NULL) { @@ -7247,9 +7266,9 @@ select_type_set_tmp (gfc_typespec *ts) return; if (ts->type == BT_CLASS) - sprintf (name, "__tmp_class_%s", ts->u.derived->name); + sprintf (name, "__tmp_class_%s_%s", ts->u.derived->name, var_name); else - sprintf (name, "__tmp_type_%s", ts->u.derived->name); + sprintf (name, "__tmp_type_%s_%s", ts->u.derived->name, var_name); gfc_get_sym_tree (name, gfc_current_ns, &tmp, false); sym = tmp->n.sym; diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index 5413d8f9c542..0070e8c170d2 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -10819,6 +10819,8 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns) ref = gfc_copy_ref (ref); } + gfc_expr *orig_expr1 = code->expr1; + /* Add EXEC_SELECT to switch on type. */ new_st = gfc_get_code (code->op); new_st->expr1 = code->expr1; @@ -10846,7 +10848,6 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns) for (body = code->block; body; body = body->block) { gfc_symbol *vtab; - gfc_expr *e; c = body->ext.block.case_list; /* Generate an index integer expression for address of the @@ -10854,6 +10855,7 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns) is stored in c->high and is used to resolve intrinsic cases. */ if (c->ts.type != BT_UNKNOWN) { + gfc_expr *e; if (c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS) { vtab = gfc_find_derived_vtab (c->ts.u.derived); @@ -10886,11 +10888,22 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns) when this case is actually true, so build a new ASSOCIATE that does precisely this here (instead of using the 'global' one). */ + const char * var_name = ""; + if (orig_expr1->symtree) + var_name = orig_expr1->symtree->name; + if (orig_expr1->ref) + { + for (gfc_ref *r = orig_expr1->ref; r; r = r->next) + if (r->type == REF_COMPONENT + && !(strcmp (r->u.c.component->name, "_data") == 0 +|| strcmp (r->u.c.component->name, "_vptr") == 0)) + var_name = r->u.c.component->name; + } if (c->ts.type == BT_CLASS) - sprintf (name, "__tmp_class_%s", c->ts.u.derived->name); + sprintf (name, "__tmp_class_%s_%s", c->ts.u.derived->name, var_name); else if (c->ts.type == BT_DERIVED) - sprintf (name, "__tmp_type_%s",
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] match: Unwrap non-lvalue as unary or binary operand
https://gcc.gnu.org/g:15ec2edeff225cf62195b1610031f3834e01028a commit 15ec2edeff225cf62195b1610031f3834e01028a Author: Mikael Morin Date: Thu Jul 4 15:24:36 2024 +0200 match: Unwrap non-lvalue as unary or binary operand This avoids most of the testsuite dump pattern updates with a patch generating more NON_LVALUE_EXPR trees that I plan to post later. Regression tested on x86_64-linux. OK for master? -- 8< -- gcc/ChangeLog: * match.pd (`op (non_lvalue X) Y`, `op X (non_lvalue Y)`, `op (non_lvalue X)`): New simplifications, unwrap NON_LVALUE_EXPR trees when they are used as operand of a unary or binary operator. gcc/testsuite/ChangeLog: * gfortran.dg/non_lvalue_2.f90: New test. Diff: --- gcc/match.pd | 12 gcc/testsuite/gfortran.dg/non_lvalue_2.f90 | 44 ++ 2 files changed, 56 insertions(+) diff --git a/gcc/match.pd b/gcc/match.pd index ad0fa8f10044..02a08530c5ea 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -281,6 +281,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (outer_op @0 @2) @3)) +/* Remove superfluous NON_LVALUE_EXPR in unary operators. */ +(for op (UNCOND_UNARY) + (simplify (op (non_lvalue @0)) + (op @0))) + +/* Remove superfluous NON_LVALUE_EXPR in binary operators. */ +(for op (UNCOND_BINARY tcc_comparison) + (simplify (op (non_lvalue @0) @1) + (op @0 @1)) + (simplify (op @0 (non_lvalue @1)) + (op @0 @1))) + /* Simplify x - x. This is unsafe for certain floats even in non-IEEE formats. In IEEE, it is unsafe because it does wrong for NaNs. diff --git a/gcc/testsuite/gfortran.dg/non_lvalue_2.f90 b/gcc/testsuite/gfortran.dg/non_lvalue_2.f90 new file mode 100644 index ..8c3197eab1f0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/non_lvalue_2.f90 @@ -0,0 +1,44 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } +! +! Check the removal of NON_LVALUE_EXPR if they are used in a non-lvalue context + +! The NON_LVALUE_EXPR is dropped if it's part (left operand) of a bigger expression +function f1 (f1_arg1, f1_arg2) + integer, value :: f1_arg1, f1_arg2 + integer :: f1 + f1 = (f1_arg1 + 0) + f1_arg2 +end function +! { dg-final { scan-tree-dump "__result_f1 = f1_arg1 \\+ f1_arg2;" "original" } } + +! The NON_LVALUE_EXPR is dropped if it's part (right operand) of a bigger expression +function f2 (f2_arg1, f2_arg2) + integer, value :: f2_arg1, f2_arg2 + integer :: f2 + f2 = f2_arg1 + (f2_arg2 + 0) +end function +! { dg-final { scan-tree-dump "__result_f2 = f2_arg1 \\+ f2_arg2;" "original" } } + +! The NON_LVALUE_EXPR is dropped if it's part (left operand) of a binary logical operator +function f3 (f3_arg1) + integer, value :: f3_arg1 + logical :: f3 + f3 = (f3_arg1 + 0) > 0 +end function +! { dg-final { scan-tree-dump "__result_f3 = f3_arg1 > 0;" "original" } } + +! The NON_LVALUE_EXPR is dropped if it's part (right operand) of a binary logical operator +function f4 (f4_arg1, f4_arg2) + integer, value :: f4_arg1, f4_arg2 + logical :: f4 + f4 = f4_arg1 > (f4_arg2 + 0) +end function +! { dg-final { scan-tree-dump "__result_f4 = f4_arg1 > f4_arg2;" "original" } } + +! The NON_LVALUE_EXPR is dropped if it's part of a unary operator +function f5 (f5_arg1) + integer, value :: f5_arg1 + integer :: f5 + f5 = -(not(not(f5_arg1))) +end function +! { dg-final { scan-tree-dump "__result_f5 = -f5_arg1;" "original" } }
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Correction régression assumed_type_13
https://gcc.gnu.org/g:96bc4d896ff7545bbbe64cd07e48b75f84a99638 commit 96bc4d896ff7545bbbe64cd07e48b75f84a99638 Author: Mikael Morin Date: Mon May 19 15:06:55 2025 +0200 Correction régression assumed_type_13 Diff: --- gcc/match.pd | 18 -- 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/gcc/match.pd b/gcc/match.pd index eaaf4bc2b331..8c6936b2c04c 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -848,13 +848,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (switch (if (cst1 == cst2) @0) (if (wi::multiple_of_p (cst1, cst2, TYPE_SIGN (type))) - (mul @0 { wide_int_to_tree (type, - wi::div_trunc (cst1, cst2, -TYPE_SIGN (type))); })) + (with + {wide_int simplified = wi::div_trunc (cst1, cst2, TYPE_SIGN (type)); +if (mul == LSHIFT_EXPR) + simplified = wi::shwi (wi::exact_log2 (simplified), +TYPE_PRECISION (type));} + (mul @0 { wide_int_to_tree (type, simplified); }))) (if (wi::multiple_of_p (cst2, cst1, TYPE_SIGN (type))) - (div @0 { wide_int_to_tree (type, - wi::div_trunc (cst2, cst1, -TYPE_SIGN (type))); }))) + (with + {wide_int simplified = wi::div_trunc (cst2, cst1, TYPE_SIGN (type)); +if (div == RSHIFT_EXPR) + simplified = wi::shwi (wi::exact_log2 (simplified), +TYPE_PRECISION (type));} + (div @0 { wide_int_to_tree (type, simplified); } /* If ARG1 is a constant, we can convert this to a multiply by the
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Correction régression reassoc_6
https://gcc.gnu.org/g:06c7b25288b006c1cbec648e82ad1c79da79ee24 commit 06c7b25288b006c1cbec648e82ad1c79da79ee24 Author: Mikael Morin Date: Thu May 8 21:42:53 2025 +0200 Correction régression reassoc_6 Diff: --- gcc/match.pd | 24 1 file changed, 24 insertions(+) diff --git a/gcc/match.pd b/gcc/match.pd index 02a08530c5ea..eaaf4bc2b331 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -832,6 +832,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (rshift (convert @0) { build_int_cst (integer_type_node, wi::exact_log2 (wi::to_wide (@2))); } +(for div (trunc_div ceil_div floor_div round_div exact_div rshift) + (for mul (mult lshift) + (simplify (div (mul @0 INTEGER_CST@1) INTEGER_CST@2) + (with +{wide_int cst1, cst2; + if (mul == LSHIFT_EXPR) + cst1 = wi::lshift (wi::one (TYPE_PRECISION (type)), wi::to_wide (@1)); + else + cst1 = wi::to_wide (@1); + if (div == RSHIFT_EXPR) + cst2 = wi::lshift (wi::one (TYPE_PRECISION (type)), wi::to_wide (@2)); + else + cst2 = wi::to_wide (@2);} +(switch + (if (cst1 == cst2) @0) + (if (wi::multiple_of_p (cst1, cst2, TYPE_SIGN (type))) + (mul @0 { wide_int_to_tree (type, + wi::div_trunc (cst1, cst2, +TYPE_SIGN (type))); })) + (if (wi::multiple_of_p (cst2, cst1, TYPE_SIGN (type))) + (div @0 { wide_int_to_tree (type, + wi::div_trunc (cst2, cst1, +TYPE_SIGN (type))); }))) + /* If ARG1 is a constant, we can convert this to a multiply by the reciprocal. This does not have the same rounding properties,
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Correction erreurs non-lvalue lhs pr113363.f90
https://gcc.gnu.org/g:46fce2adb08aab59bc1eadd889889be8409c8fd8 commit 46fce2adb08aab59bc1eadd889889be8409c8fd8 Author: Mikael Morin Date: Wed Feb 12 10:47:31 2025 +0100 Correction erreurs non-lvalue lhs pr113363.f90 Diff: --- gcc/fortran/trans-decl.cc | 21 + gcc/fortran/trans.cc | 4 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index 43bd7be54cb7..f60b6d916201 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -5142,10 +5142,23 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) if (!sym->attr.dummy || sym->attr.intent == INTENT_OUT) { /* Nullify when entering the scope. */ - tmp = fold_build2_loc (input_location, MODIFY_EXPR, -TREE_TYPE (se.expr), se.expr, -fold_convert (TREE_TYPE (se.expr), - null_pointer_node)); + if (sym->ts.type == BT_CLASS + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension)) + { + stmtblock_t nullify; + gfc_init_block (&nullify); + gfc_conv_descriptor_data_set (&nullify, descriptor, + null_pointer_node); + tmp = gfc_finish_block (&nullify); + } + else + { + tmp = fold_build2_loc (input_location, MODIFY_EXPR, +TREE_TYPE (se.expr), se.expr, +fold_convert (TREE_TYPE (se.expr), + null_pointer_node)); + } if (sym->attr.optional) { tree present = gfc_conv_expr_present (sym); diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc index fdeb1e89a765..f1966bd881f0 100644 --- a/gcc/fortran/trans.cc +++ b/gcc/fortran/trans.cc @@ -1737,7 +1737,7 @@ gfc_finalize_tree_expr (gfc_se *se, gfc_symbol *derived, gfc_call_free (data_ptr), build_empty_stmt (input_location)); gfc_add_expr_to_block (&se->loop->post, tmp); - gfc_add_modify (&se->loop->post, data_ptr, data_null); + gfc_conv_descriptor_data_set (&se->loop->post, desc, data_null); } else { @@ -1751,7 +1751,7 @@ gfc_finalize_tree_expr (gfc_se *se, gfc_symbol *derived, gfc_call_free (data_ptr), build_empty_stmt (input_location)); gfc_add_expr_to_block (&se->finalblock, tmp); - gfc_add_modify (&se->finalblock, data_ptr, data_null); + gfc_conv_descriptor_data_set (&se->finalblock, desc, data_null); } } }
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Ajout non_lvalue getters.
https://gcc.gnu.org/g:be9181018e6b8c3b751665d4213448cfaecf5d09 commit be9181018e6b8c3b751665d4213448cfaecf5d09 Author: Mikael Morin Date: Thu Jun 19 17:22:05 2025 +0200 Ajout non_lvalue getters. Diff: --- gcc/fortran/trans-descriptor.cc | 38 +++--- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/gcc/fortran/trans-descriptor.cc b/gcc/fortran/trans-descriptor.cc index 30093a74ae58..3d14581e3958 100644 --- a/gcc/fortran/trans-descriptor.cc +++ b/gcc/fortran/trans-descriptor.cc @@ -176,6 +176,13 @@ gfc_get_descriptor_field (tree desc, unsigned field_idx) desc, field, NULL_TREE); } + +static tree +get_descriptor_data (tree desc) +{ + return gfc_get_descriptor_field (desc, DATA_FIELD); +} + /* This provides READ-ONLY access to the data field. The field itself doesn't have the proper type. */ @@ -183,11 +190,12 @@ tree gfc_conv_descriptor_data_get (tree desc) { tree type = TREE_TYPE (desc); - if (TREE_CODE (type) == REFERENCE_TYPE) -gcc_unreachable (); + gcc_assert (TREE_CODE (type) != REFERENCE_TYPE); - tree field = gfc_get_descriptor_field (desc, DATA_FIELD); - return fold_convert (GFC_TYPE_ARRAY_DATAPTR_TYPE (type), field); + tree field = get_descriptor_data (desc); + tree target_type = GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (desc)); + tree t = fold_convert (target_type, field); + return non_lvalue_loc (input_location, t); } /* This provides WRITE access to the data field. @@ -227,7 +235,7 @@ gfc_conv_descriptor_offset (tree desc) tree gfc_conv_descriptor_offset_get (tree desc) { - return gfc_conv_descriptor_offset (desc); + return non_lvalue_loc (input_location, gfc_conv_descriptor_offset (desc)); } void @@ -258,7 +266,7 @@ gfc_conv_descriptor_span (tree desc) tree gfc_conv_descriptor_span_get (tree desc) { - return gfc_conv_descriptor_span (desc); + return non_lvalue_loc (input_location, gfc_conv_descriptor_span (desc)); } void @@ -391,7 +399,7 @@ gfc_conv_descriptor_subfield (tree desc, tree dim, unsigned field_idx) } static tree -gfc_conv_descriptor_stride (tree desc, tree dim) +get_descriptor_stride (tree desc, tree dim) { tree field = gfc_conv_descriptor_subfield (desc, dim, STRIDE_SUBFIELD); gcc_assert (TREE_TYPE (field) == gfc_array_index_type); @@ -412,19 +420,19 @@ gfc_conv_descriptor_stride_get (tree desc, tree dim) || GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_POINTER_CONT)) return gfc_index_one_node; - return gfc_conv_descriptor_stride (desc, dim); + return non_lvalue_loc (input_location, get_descriptor_stride (desc, dim)); } void gfc_conv_descriptor_stride_set (stmtblock_t *block, tree desc, tree dim, tree value) { - tree t = gfc_conv_descriptor_stride (desc, dim); + tree t = get_descriptor_stride (desc, dim); gfc_add_modify (block, t, fold_convert (TREE_TYPE (t), value)); } static tree -gfc_conv_descriptor_lbound (tree desc, tree dim) +get_descriptor_lbound (tree desc, tree dim) { tree field = gfc_conv_descriptor_subfield (desc, dim, LBOUND_SUBFIELD); gcc_assert (TREE_TYPE (field) == gfc_array_index_type); @@ -434,19 +442,19 @@ gfc_conv_descriptor_lbound (tree desc, tree dim) tree gfc_conv_descriptor_lbound_get (tree desc, tree dim) { - return gfc_conv_descriptor_lbound (desc, dim); + return non_lvalue_loc (input_location, get_descriptor_lbound (desc, dim)); } void gfc_conv_descriptor_lbound_set (stmtblock_t *block, tree desc, tree dim, tree value) { - tree t = gfc_conv_descriptor_lbound (desc, dim); + tree t = get_descriptor_lbound (desc, dim); gfc_add_modify (block, t, fold_convert (TREE_TYPE (t), value)); } static tree -gfc_conv_descriptor_ubound (tree desc, tree dim) +get_descriptor_ubound (tree desc, tree dim) { tree field = gfc_conv_descriptor_subfield (desc, dim, UBOUND_SUBFIELD); gcc_assert (TREE_TYPE (field) == gfc_array_index_type); @@ -456,14 +464,14 @@ gfc_conv_descriptor_ubound (tree desc, tree dim) tree gfc_conv_descriptor_ubound_get (tree desc, tree dim) { - return gfc_conv_descriptor_ubound (desc, dim); + return non_lvalue_loc (input_location, get_descriptor_ubound (desc, dim)); } void gfc_conv_descriptor_ubound_set (stmtblock_t *block, tree desc, tree dim, tree value) { - tree t = gfc_conv_descriptor_ubound (desc, dim); + tree t = get_descriptor_ubound (desc, dim); gfc_add_modify (block, t, fold_convert (TREE_TYPE (t), value)); }
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] suppression non_lvalue avec exact_div
https://gcc.gnu.org/g:5b84bee6dbab8dddf45598ccdce9ba88162801c6 commit 5b84bee6dbab8dddf45598ccdce9ba88162801c6 Author: Mikael Morin Date: Thu Jun 5 17:11:35 2025 +0200 suppression non_lvalue avec exact_div Diff: --- gcc/match.pd | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gcc/match.pd b/gcc/match.pd index 8c6936b2c04c..4cb9cdd6668f 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -114,6 +114,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) IFN_COND_LEN_FMIN IFN_COND_LEN_FMAX IFN_COND_LEN_COPYSIGN IFN_COND_LEN_AND IFN_COND_LEN_IOR IFN_COND_LEN_XOR IFN_COND_LEN_SHL IFN_COND_LEN_SHR) +/* Binary operators without corresponding conditional operator. */ +(define_operator_list EXTRA_BINARY + ceil_div ceil_mod + floor_div floor_mod + round_div round_mod + exact_div) /* Same for ternary operations. */ (define_operator_list UNCOND_TERNARY @@ -287,7 +293,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (op @0))) /* Remove superfluous NON_LVALUE_EXPR in binary operators. */ -(for op (UNCOND_BINARY tcc_comparison) +(for op (UNCOND_BINARY EXTRA_BINARY tcc_comparison) (simplify (op (non_lvalue @0) @1) (op @0 @1)) (simplify (op @0 (non_lvalue @1))
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] Interdiction non-lvalue as lhs
https://gcc.gnu.org/g:995814a46a94819e460b89b250c661240e51fa44 commit 995814a46a94819e460b89b250c661240e51fa44 Author: Mikael Morin Date: Tue Feb 11 21:34:11 2025 +0100 Interdiction non-lvalue as lhs git commit correction erreur gimplify Diff: --- gcc/gimplify.cc | 6 ++ 1 file changed, 6 insertions(+) diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 9f9ff92d0642..96e12c370802 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -7244,6 +7244,12 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR || TREE_CODE (*expr_p) == INIT_EXPR); + if (TREE_CODE (*to_p) == NON_LVALUE_EXPR) +{ + error ("non-lvalue used as lhs in %qD", *expr_p); + return GS_ERROR; +} + /* Trying to simplify a clobber using normal logic doesn't work, so handle it here. */ if (TREE_CLOBBER_P (*from_p))
[gcc(refs/users/mikael/heads/refactor_descriptor_v06_temp)] match: Unwrap non-lvalue as unary or binary operand
https://gcc.gnu.org/g:ac820f788376d056b9547cb28feb10cd680b0b5c commit ac820f788376d056b9547cb28feb10cd680b0b5c Author: Mikael Morin Date: Thu Jul 4 15:24:36 2024 +0200 match: Unwrap non-lvalue as unary or binary operand This avoids most of the testsuite dump pattern updates with a patch generating more NON_LVALUE_EXPR trees that I plan to post later. Regression tested on x86_64-linux. OK for master? -- 8< -- gcc/ChangeLog: * match.pd (`op (non_lvalue X) Y`, `op X (non_lvalue Y)`, `op (non_lvalue X)`): New simplifications, unwrap NON_LVALUE_EXPR trees when they are used as operand of a unary or binary operator. gcc/testsuite/ChangeLog: * gfortran.dg/non_lvalue_2.f90: New test. Diff: --- gcc/match.pd | 12 gcc/testsuite/gfortran.dg/non_lvalue_2.f90 | 44 ++ 2 files changed, 56 insertions(+) diff --git a/gcc/match.pd b/gcc/match.pd index ad0fa8f10044..02a08530c5ea 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -281,6 +281,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (outer_op @0 @2) @3)) +/* Remove superfluous NON_LVALUE_EXPR in unary operators. */ +(for op (UNCOND_UNARY) + (simplify (op (non_lvalue @0)) + (op @0))) + +/* Remove superfluous NON_LVALUE_EXPR in binary operators. */ +(for op (UNCOND_BINARY tcc_comparison) + (simplify (op (non_lvalue @0) @1) + (op @0 @1)) + (simplify (op @0 (non_lvalue @1)) + (op @0 @1))) + /* Simplify x - x. This is unsafe for certain floats even in non-IEEE formats. In IEEE, it is unsafe because it does wrong for NaNs. diff --git a/gcc/testsuite/gfortran.dg/non_lvalue_2.f90 b/gcc/testsuite/gfortran.dg/non_lvalue_2.f90 new file mode 100644 index ..8c3197eab1f0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/non_lvalue_2.f90 @@ -0,0 +1,44 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } +! +! Check the removal of NON_LVALUE_EXPR if they are used in a non-lvalue context + +! The NON_LVALUE_EXPR is dropped if it's part (left operand) of a bigger expression +function f1 (f1_arg1, f1_arg2) + integer, value :: f1_arg1, f1_arg2 + integer :: f1 + f1 = (f1_arg1 + 0) + f1_arg2 +end function +! { dg-final { scan-tree-dump "__result_f1 = f1_arg1 \\+ f1_arg2;" "original" } } + +! The NON_LVALUE_EXPR is dropped if it's part (right operand) of a bigger expression +function f2 (f2_arg1, f2_arg2) + integer, value :: f2_arg1, f2_arg2 + integer :: f2 + f2 = f2_arg1 + (f2_arg2 + 0) +end function +! { dg-final { scan-tree-dump "__result_f2 = f2_arg1 \\+ f2_arg2;" "original" } } + +! The NON_LVALUE_EXPR is dropped if it's part (left operand) of a binary logical operator +function f3 (f3_arg1) + integer, value :: f3_arg1 + logical :: f3 + f3 = (f3_arg1 + 0) > 0 +end function +! { dg-final { scan-tree-dump "__result_f3 = f3_arg1 > 0;" "original" } } + +! The NON_LVALUE_EXPR is dropped if it's part (right operand) of a binary logical operator +function f4 (f4_arg1, f4_arg2) + integer, value :: f4_arg1, f4_arg2 + logical :: f4 + f4 = f4_arg1 > (f4_arg2 + 0) +end function +! { dg-final { scan-tree-dump "__result_f4 = f4_arg1 > f4_arg2;" "original" } } + +! The NON_LVALUE_EXPR is dropped if it's part of a unary operator +function f5 (f5_arg1) + integer, value :: f5_arg1 + integer :: f5 + f5 = -(not(not(f5_arg1))) +end function +! { dg-final { scan-tree-dump "__result_f5 = -f5_arg1;" "original" } }
[gcc r16-1573] RISC-V: Add generic tune as default.
https://gcc.gnu.org/g:20f593018519fec1602dc39c08ba2e674a2d8a1c commit r16-1573-g20f593018519fec1602dc39c08ba2e674a2d8a1c Author: Dongyan Chen Date: Wed Jun 18 19:47:28 2025 +0800 RISC-V: Add generic tune as default. According to the discussion in https://gcc.gnu.org/pipermail/gcc-patches/2025-June/686893.html, by creating a -mtune=generic may be a good idea to slove the question regarding the branch cost. Changes for v2: - Delete the code about -mcpu=generic. gcc/ChangeLog: * config/riscv/riscv-cores.def (RISCV_TUNE): Add "generic" tune. * config/riscv/riscv.cc: Add generic_tune_info. * config/riscv/riscv.h (RISCV_TUNE_STRING_DEFAULT): Change default tune. gcc/testsuite/ChangeLog: * gcc.target/riscv/zicond-primitiveSemantics_compare_reg_reg_return_reg_reg.c: New test. Diff: --- gcc/config/riscv/riscv-cores.def | 1 + gcc/config/riscv/riscv.cc | 23 ++ gcc/config/riscv/riscv.h | 2 +- ...itiveSemantics_compare_reg_reg_return_reg_reg.c | 21 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def index cff7c77a0bd7..2096c0095d4e 100644 --- a/gcc/config/riscv/riscv-cores.def +++ b/gcc/config/riscv/riscv-cores.def @@ -33,6 +33,7 @@ #define RISCV_TUNE(TUNE_NAME, PIPELINE_MODEL, TUNE_INFO) #endif +RISCV_TUNE("generic", generic, generic_tune_info) RISCV_TUNE("rocket", generic, rocket_tune_info) RISCV_TUNE("sifive-3-series", generic, rocket_tune_info) RISCV_TUNE("sifive-5-series", generic, rocket_tune_info) diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 5fa84e0466da..86444b0bef8e 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -450,6 +450,29 @@ static const struct cpu_vector_cost generic_vector_cost = { &rvv_regmove_vector_cost, /* regmove */ }; +/* Costs to use when optimizing for generic. */ +static const struct riscv_tune_param generic_tune_info = { + {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_mul */ + {COSTS_N_INSNS (20), COSTS_N_INSNS (20)},/* fp_div */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ + {COSTS_N_INSNS (33), COSTS_N_INSNS (65)},/* int_div */ + 1, /* issue_rate */ + 4, /* branch_cost */ + 5, /* memory_cost */ + 8, /* fmv_cost */ + true,/* slow_unaligned_access */ + false, /* vector_unaligned_access */ + false, /* use_divmod_expansion */ + false, /* overlap_op_by_pieces */ + false, /* speculative_sched_vsetvl */ + RISCV_FUSE_NOTHING, /* fusible_ops */ + NULL,/* vector cost */ + NULL,/* function_align */ + NULL,/* jump_align */ + NULL,/* loop_align */ +}; + /* Costs to use when optimizing for rocket. */ static const struct riscv_tune_param rocket_tune_info = { {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */ diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 2759a4cb1c9f..45fa521f219f 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see #endif #ifndef RISCV_TUNE_STRING_DEFAULT -#define RISCV_TUNE_STRING_DEFAULT "rocket" +#define RISCV_TUNE_STRING_DEFAULT "generic" #endif extern const char *riscv_expand_arch (int argc, const char **argv); diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_reg_return_reg_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_reg_return_reg_reg.c new file mode 100644 index ..1ad1b77a2e65 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_reg_return_reg_reg.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicond -mabi=lp64d -mtune=generic" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f -mtune=generic" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" "-O3" } } */ + +#define N 1 + +int primitiveSemantics_compare_reg_reg_return_reg_reg_00(int *a, int min_v) +{ + int last = 0; + + for (int i = 0; i < N; i++) + { +if (a[i] < min_v) + last = a[i]; + } + return last; +} + +/* { dg-fin
[gcc] Created branch 'omachota/heads/rtl-ssa-dce-wdebug' in namespace 'refs/users'
The branch 'omachota/heads/rtl-ssa-dce-wdebug' was created in namespace 'refs/users' pointing to: a260eca5... rtl-ssa-dce: fix index out of range when debugizing
[gcc r16-1576] fortran: Statically initialize length of SAVEd character arrays
https://gcc.gnu.org/g:95cc39dd47419d0544a0e1b32292ba250155a112 commit r16-1576-g95cc39dd47419d0544a0e1b32292ba250155a112 Author: Mikael Morin Date: Wed Jun 18 22:11:43 2025 +0200 fortran: Statically initialize length of SAVEd character arrays PR fortran/120713 gcc/fortran/ChangeLog: * trans-array.cc (gfc_trans_deferred_array): Statically initialize deferred length variable for SAVEd character arrays. gcc/testsuite/ChangeLog: * gfortran.dg/save_alloc_character_1.f90: New test. Diff: --- gcc/fortran/trans-array.cc | 12 +-- .../gfortran.dg/save_alloc_character_1.f90 | 23 ++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 960613167f72..3d274439895d 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -12067,8 +12067,16 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block) && !INTEGER_CST_P (sym->ts.u.cl->backend_decl)) { if (sym->ts.deferred && !sym->ts.u.cl->length && !sym->attr.dummy) - gfc_add_modify (&init, sym->ts.u.cl->backend_decl, - build_zero_cst (TREE_TYPE (sym->ts.u.cl->backend_decl))); + { + tree len_expr = sym->ts.u.cl->backend_decl; + tree init_val = build_zero_cst (TREE_TYPE (len_expr)); + if (VAR_P (len_expr) + && sym->attr.save + && !DECL_INITIAL (len_expr)) + DECL_INITIAL (len_expr) = init_val; + else + gfc_add_modify (&init, len_expr, init_val); + } gfc_conv_string_length (sym->ts.u.cl, NULL, &init); gfc_trans_vla_type_sizes (sym, &init); diff --git a/gcc/testsuite/gfortran.dg/save_alloc_character_1.f90 b/gcc/testsuite/gfortran.dg/save_alloc_character_1.f90 new file mode 100644 index ..e26919f83bea --- /dev/null +++ b/gcc/testsuite/gfortran.dg/save_alloc_character_1.f90 @@ -0,0 +1,23 @@ +! { dg-do run } +! +! PR fortran/120713 +! Check that the length variable of SAVEd allocatable character arrays are +! not initialized at function entry. + +program p + implicit none + call s(1) + call s(2) +contains + subroutine s(i) +integer, intent(in) :: i +character(len=:), allocatable, save :: a(:) +integer :: j +if (i == 1) then + allocate(a, source= [ ('x' // achar(ichar('0') + j), j=1,7) ]) +else + if (len(a) /= 2) error stop 1 + if (any(a /= ['x1','x2','x3','x4','x5','x6','x7'])) error stop 2 +end if + end subroutine s +end program p
[gcc r16-1574] install.texi: Note that Texinfo < v7.1 may throw incorrect warnings.
https://gcc.gnu.org/g:48c52af0cd85a2e702ff90c7ba6b70daf7f4b171 commit r16-1574-g48c52af0cd85a2e702ff90c7ba6b70daf7f4b171 Author: Georg-Johann Lay Date: Wed Jun 18 18:55:02 2025 +0200 install.texi: Note that Texinfo < v7.1 may throw incorrect warnings. PR other/115893 gcc/ * doc/install.texi (Prerequisites): Note that Texinfo older than v7.1 may throw incorrect build warnings, cf. https://lists.nongnu.org/archive/html/help-texinfo/2023-11/msg4.html Diff: --- gcc/doc/install.texi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 34e35a2dd52b..80ee2cd6ebad 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -631,6 +631,9 @@ building the documentation without error, but you may still want to install a newer release to get the best appearance and usability of the generated manuals. +Also note that Texinfo older than version 7.1 may throw incorrect build +warnings, though the generated documentation is correct. + @item @TeX{} (any working version) Necessary for running @command{texi2dvi} and @command{texi2pdf}, which
[gcc r16-1575] x86: Enable *mov_(and|or) only for -Oz
https://gcc.gnu.org/g:4c80062d7b8c272e2e193b8074a8440dbb4fe588 commit r16-1575-g4c80062d7b8c272e2e193b8074a8440dbb4fe588 Author: H.J. Lu Date: Sun May 25 07:40:29 2025 +0800 x86: Enable *mov_(and|or) only for -Oz commit ef26c151c14a87177d46fd3d725e7f82e040e89f Author: Roger Sayle Date: Thu Dec 23 12:33:07 2021 + x86: PR target/103773: Fix wrong-code with -Oz from pop to memory. added "*mov_and" and extended "*mov_or" to transform "mov $0,mem" to the shorter "and $0,mem" and "mov $-1,mem" to the shorter "or $-1,mem" for -Oz. But the new pattern: (define_insn "*mov_and" [(set (match_operand:SWI248 0 "memory_operand" "=m") (match_operand:SWI248 1 "const0_operand")) (clobber (reg:CC FLAGS_REG))] "reload_completed" "and{}\t{%1, %0|%0, %1}" [(set_attr "type" "alu1") (set_attr "mode" "") (set_attr "length_immediate" "1")]) and the extended pattern: (define_insn "*mov_or" [(set (match_operand:SWI248 0 "nonimmediate_operand" "=rm") (match_operand:SWI248 1 "constm1_operand")) (clobber (reg:CC FLAGS_REG))] "reload_completed" "or{}\t{%1, %0|%0, %1}" [(set_attr "type" "alu1") (set_attr "mode" "") (set_attr "length_immediate" "1")]) aren't guarded for -Oz. As a result, "and $0,mem" and "or $-1,mem" are generated without -Oz. 1. Change *mov_and" to define_insn_and_split and split it to "mov $0,mem" if not -Oz. 2. Change "*mov_or" to define_insn_and_split and split it to "mov $-1,mem" if not -Oz. 3. Don't transform "mov $-1,reg" to "push $-1; pop reg" for -Oz since it should be transformed to "or $-1,reg". gcc/ PR target/120427 * config/i386/i386.md (*mov_and): Changed to define_insn_and_split. Split it to "mov $0,mem" if not -Oz. (*mov_or): Changed to define_insn_and_split. Split it to "mov $-1,mem" if not -Oz. (peephole2): Don't transform "mov $-1,reg" to "push $-1; pop reg" for -Oz since it will be transformed to "or $-1,reg". gcc/testsuite/ PR target/120427 * gcc.target/i386/cold-attribute-4.c: Compile with -Oz. * gcc.target/i386/pr120427-1.c: New test. * gcc.target/i386/pr120427-2.c: Likewise. * gcc.target/i386/pr120427-3.c: Likewise. * gcc.target/i386/pr120427-4.c: Likewise. Signed-off-by: H.J. Lu Diff: --- gcc/config/i386/i386.md | 15 ++-- gcc/testsuite/gcc.target/i386/cold-attribute-4.c | 2 +- gcc/testsuite/gcc.target/i386/pr120427-1.c | 28 +++ gcc/testsuite/gcc.target/i386/pr120427-2.c | 28 +++ gcc/testsuite/gcc.target/i386/pr120427-3.c | 45 gcc/testsuite/gcc.target/i386/pr120427-4.c | 6 6 files changed, 121 insertions(+), 3 deletions(-) diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 6bd557431f5c..423ef48e518f 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -2438,22 +2438,32 @@ (set_attr "mode" "SI") (set_attr "length_immediate" "0")]) -(define_insn "*mov_and" +;; Generate shorter "and $0,mem" for -Oz. Split it to "mov $0,mem" +;; otherwise. +(define_insn_and_split "*mov_and" [(set (match_operand:SWI248 0 "memory_operand" "=m") (match_operand:SWI248 1 "const0_operand")) (clobber (reg:CC FLAGS_REG))] "reload_completed" "and{}\t{%1, %0|%0, %1}" + "&& !(optimize_insn_for_size_p () && optimize_size > 1)" + [(set (match_dup 0) (match_dup 1))] + "" [(set_attr "type" "alu1") (set_attr "mode" "") (set_attr "length_immediate" "1")]) -(define_insn "*mov_or" +;; Generate shorter "or $-1,mem" for -Oz. Split it to "mov $-1,mem" +;; otherwise. +(define_insn_and_split "*mov_or" [(set (match_operand:SWI248 0 "nonimmediate_operand" "=rm") (match_operand:SWI248 1 "constm1_operand")) (clobber (reg:CC FLAGS_REG))] "reload_completed" "or{}\t{%1, %0|%0, %1}" + "&& !(optimize_insn_for_size_p () && optimize_size > 1)" + [(set (match_dup 0) (match_dup 1))] + "" [(set_attr "type" "alu1") (set_attr "mode" "") (set_attr "length_immediate" "1")]) @@ -2958,6 +2968,7 @@ (match_operand:SWI248 1 "const_int_operand"))] "optimize_insn_for_size_p () && optimize_size > 1 && operands[1] != const0_rtx + && operands[1] != constm1_rtx && IN_RANGE (INTVAL (operands[1]), -128, 127) && !ix86_red_zone_used && REGNO (operands[0]) != SP_REG" diff --git a/gcc/testsuite/gcc.target/i386/cold-attribute-4.c b/gcc/testsuite/gcc.target/i386/cold-attribute-4.c index 37a41e954daf..e0808c539051 100644 --- a/gcc/testsuite/gcc.target/i386/cold-attribute-4.c +++ b/gcc/testsuite/gcc.target/i386/cold-attribute-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2
[gcc r16-1572] dfp: Further decimal_real_to_integer fixes [PR120631]
https://gcc.gnu.org/g:e2eb9da5546b5e2fccb86586cda3beee8f69f5c9 commit r16-1572-ge2eb9da5546b5e2fccb86586cda3beee8f69f5c9 Author: Jakub Jelinek Date: Thu Jun 19 08:57:27 2025 +0200 dfp: Further decimal_real_to_integer fixes [PR120631] Unfortunately, the following further testcase shows that there aren't problems only with very large precisions and large exponents, but pretty much anything larger than 64-bits. After all, before _BitInt support dfp didn't even have {,unsigned }__int128 <-> _Decimal{32,64,128,64x} support, and the testcase again shows some of the conversions yielding zeros. While the pr120631.c test worked even without the earlier patch. So, this patch assumes 64-bit precision at most is ok and for anything larger it just uses exponent 0 and multiplies afterwards. 2025-06-19 Jakub Jelinek PR middle-end/120631 * dfp.cc (decimal_real_to_integer): Use result multiplication not just when precision > 128 and dn.exponent > 19, but when precision > 64 and dn.exponent > 0. * gcc.dg/dfp/bitint-10.c: New test. * gcc.dg/dfp/pr120631.c: New test. Diff: --- gcc/dfp.cc | 46 +++-- gcc/testsuite/gcc.dg/dfp/bitint-10.c | 49 gcc/testsuite/gcc.dg/dfp/pr120631.c | 25 ++ 3 files changed, 112 insertions(+), 8 deletions(-) diff --git a/gcc/dfp.cc b/gcc/dfp.cc index 4011a95db4af..74e964214b5c 100644 --- a/gcc/dfp.cc +++ b/gcc/dfp.cc @@ -625,14 +625,14 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) set.traps = 0; set.round = DEC_ROUND_DOWN; decimal128ToNumber ((const decimal128 *) r->sig, &dn); - if (precision > 128 && decNumberIsFinite (&dn) && dn.exponent > 19) + if (precision > 64 && decNumberIsFinite (&dn) && dn.exponent > 0) { /* libdecNumber doesn't really handle too large integers. So when precision is large and exponent as well, trim the exponent and adjust the resulting wide_int by multiplying -it multiple times with 10^19. */ - scale = dn.exponent / 19; - dn.exponent %= 19; +it multiple times with powers of ten. */ + scale = dn.exponent; + dn.exponent = 0; } decNumberToIntegralValue (&dn2, &dn, &set); @@ -649,13 +649,42 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) *fail = true; if (scale && !failp) { - wide_int wm = wi::uhwi (HOST_WIDE_INT_UC (1000), - w.get_precision ()); bool isneg = wi::neg_p (w); if (isneg) w = -w; enum wi::overflow_type ovf = wi::OVF_NONE; - do + unsigned HOST_WIDE_INT pow10s[] = { + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + }; + int s = scale % 19; + if (s) + { + wide_int wm = wi::uhwi (pow10s[s - 1], w.get_precision ()); + w = wi::umul (w, wm, &ovf); + if (ovf) + scale = 0; + } + scale /= 19; + wide_int wm = wi::uhwi (pow10s[18], w.get_precision ()); + while (scale) { if (scale & 1) { @@ -667,8 +696,9 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) if (!scale) break; wm = wi::umul (wm, wm, &ovf); + if (ovf) + break; } - while (!ovf); if (ovf) { *fail = true; diff --git a/gcc/testsuite/gcc.dg/dfp/bitint-10.c b/gcc/testsuite/gcc.dg/dfp/bitint-10.c new file mode 100644 index ..b48f0ea6c277 --- /dev/null +++ b/gcc/testsuite/gcc.dg/dfp/bitint-10.c @@ -0,0 +1,49 @@ +/* PR middle-end/120631 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-O2" } */ + +#if __BITINT_MAXWIDTH__ >= 128 +_Decimal128 a = 1234567891357924680123456789000.0dl; +_BitInt(128) b = 1234567891357924680123456789000wb; +_Decimal64 c = 12345678913579.0dd; +_BitInt(127) d = 12345678913579wb; +#endif +#if __BITINT_MAXWIDTH__ >= 256 +_Decimal128 m = 1234567891357924680123456789000
[gcc r15-9847] dfp, real: Fix up FLOAT_EXPR/FIX_TRUNC_EXPR constant folding between dfp and large _BitInt [PR120631
https://gcc.gnu.org/g:b89ee9e63ce7dff24dfab95f8df123e71629f5ff commit r15-9847-gb89ee9e63ce7dff24dfab95f8df123e71629f5ff Author: Jakub Jelinek Date: Wed Jun 18 08:07:22 2025 +0200 dfp, real: Fix up FLOAT_EXPR/FIX_TRUNC_EXPR constant folding between dfp and large _BitInt [PR120631] The following testcase shows that while at runtime we handle conversions between _Decimal{64,128} and large _BitInt correctly, at compile time we mishandle them in both directions, in one direction we end up in ICE in decimal_from_integer callee because the char buffer is too short for the needed number of decimal digits, in the conversion of dfp to large _BitInt we return 0 in the wide_int. The following patch fixes the ICE by using larger buffer (XALLOCAVEC allocated, it will be never larger than 65536 / 3 bytes) in the larger _BitInt case, and the other direction by setting exponent to exp % 19 and instead multiplying the result by needed powers of 10^19 (10^19 chosen as largest power of ten that can fit into UHWI). 2025-06-18 Jakub Jelinek PR middle-end/120631 * real.cc (decimal_from_integer): Add digits argument, if larger than 256, use XALLOCAVEC allocated buffer. (real_from_integer): Pass val_in's precision divided by 3 to decimal_from_integer. * dfp.cc (decimal_real_to_integer): For precision > 128 if finite and exponent is large, decrease exponent and multiply resulting wide_int by powers of 10^19. * gcc.dg/dfp/bitint-9.c: New test. (cherry picked from commit f3002d664d1137844c714645a841a48ab57d0eaa) Diff: --- gcc/dfp.cc | 49 - gcc/real.cc | 21 gcc/testsuite/gcc.dg/dfp/bitint-9.c | 29 ++ 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/gcc/dfp.cc b/gcc/dfp.cc index 5c2bf1ae0686..4011a95db4af 100644 --- a/gcc/dfp.cc +++ b/gcc/dfp.cc @@ -619,11 +619,21 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) decNumber dn, dn2, dn3; REAL_VALUE_TYPE to; char string[256]; + int scale = 0; decContextDefault (&set, DEC_INIT_DECIMAL128); set.traps = 0; set.round = DEC_ROUND_DOWN; decimal128ToNumber ((const decimal128 *) r->sig, &dn); + if (precision > 128 && decNumberIsFinite (&dn) && dn.exponent > 19) +{ + /* libdecNumber doesn't really handle too large integers. +So when precision is large and exponent as well, trim the +exponent and adjust the resulting wide_int by multiplying +it multiple times with 10^19. */ + scale = dn.exponent / 19; + dn.exponent %= 19; +} decNumberToIntegralValue (&dn2, &dn, &set); decNumberZero (&dn3); @@ -633,7 +643,44 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) function. */ decNumberToString (&dn, string); real_from_string (&to, string); - return real_to_integer (&to, fail, precision); + bool failp = false; + wide_int w = real_to_integer (&to, &failp, precision); + if (failp) +*fail = true; + if (scale && !failp) +{ + wide_int wm = wi::uhwi (HOST_WIDE_INT_UC (1000), + w.get_precision ()); + bool isneg = wi::neg_p (w); + if (isneg) + w = -w; + enum wi::overflow_type ovf = wi::OVF_NONE; + do + { + if (scale & 1) + { + w = wi::umul (w, wm, &ovf); + if (ovf) + break; + } + scale >>= 1; + if (!scale) + break; + wm = wi::umul (wm, wm, &ovf); + } + while (!ovf); + if (ovf) + { + *fail = true; + if (isneg) + return wi::set_bit_in_zero (precision - 1, precision); + else + return ~wi::set_bit_in_zero (precision - 1, precision); + } + if (isneg) + w = -w; +} + return w; } /* Perform the decimal floating point operation described by CODE. diff --git a/gcc/real.cc b/gcc/real.cc index 95a933220b5d..1f987d48889f 100644 --- a/gcc/real.cc +++ b/gcc/real.cc @@ -101,7 +101,7 @@ static int do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int); static void do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *); -static void decimal_from_integer (REAL_VALUE_TYPE *); +static void decimal_from_integer (REAL_VALUE_TYPE *, int); static void decimal_integer_string (char *, const REAL_VALUE_TYPE *, size_t); @@ -2309,7 +2309,9 @@ real_from_integer (REAL_VALUE_TYPE *r, format_helper fmt, } if (fmt.decimal_p ()) -decimal_from_integer (r); +/* We need at most one decimal digits for each 3 bits of input +
[gcc r15-9848] dfp: Further decimal_real_to_integer fixes [PR120631]
https://gcc.gnu.org/g:5e570c3303ae36757aa5340ac60d562562052fc9 commit r15-9848-g5e570c3303ae36757aa5340ac60d562562052fc9 Author: Jakub Jelinek Date: Thu Jun 19 08:57:27 2025 +0200 dfp: Further decimal_real_to_integer fixes [PR120631] Unfortunately, the following further testcase shows that there aren't problems only with very large precisions and large exponents, but pretty much anything larger than 64-bits. After all, before _BitInt support dfp didn't even have {,unsigned }__int128 <-> _Decimal{32,64,128,64x} support, and the testcase again shows some of the conversions yielding zeros. While the pr120631.c test worked even without the earlier patch. So, this patch assumes 64-bit precision at most is ok and for anything larger it just uses exponent 0 and multiplies afterwards. 2025-06-19 Jakub Jelinek PR middle-end/120631 * dfp.cc (decimal_real_to_integer): Use result multiplication not just when precision > 128 and dn.exponent > 19, but when precision > 64 and dn.exponent > 0. * gcc.dg/dfp/bitint-10.c: New test. * gcc.dg/dfp/pr120631.c: New test. (cherry picked from commit e2eb9da5546b5e2fccb86586cda3beee8f69f5c9) Diff: --- gcc/dfp.cc | 46 +++-- gcc/testsuite/gcc.dg/dfp/bitint-10.c | 49 gcc/testsuite/gcc.dg/dfp/pr120631.c | 25 ++ 3 files changed, 112 insertions(+), 8 deletions(-) diff --git a/gcc/dfp.cc b/gcc/dfp.cc index 4011a95db4af..74e964214b5c 100644 --- a/gcc/dfp.cc +++ b/gcc/dfp.cc @@ -625,14 +625,14 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) set.traps = 0; set.round = DEC_ROUND_DOWN; decimal128ToNumber ((const decimal128 *) r->sig, &dn); - if (precision > 128 && decNumberIsFinite (&dn) && dn.exponent > 19) + if (precision > 64 && decNumberIsFinite (&dn) && dn.exponent > 0) { /* libdecNumber doesn't really handle too large integers. So when precision is large and exponent as well, trim the exponent and adjust the resulting wide_int by multiplying -it multiple times with 10^19. */ - scale = dn.exponent / 19; - dn.exponent %= 19; +it multiple times with powers of ten. */ + scale = dn.exponent; + dn.exponent = 0; } decNumberToIntegralValue (&dn2, &dn, &set); @@ -649,13 +649,42 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) *fail = true; if (scale && !failp) { - wide_int wm = wi::uhwi (HOST_WIDE_INT_UC (1000), - w.get_precision ()); bool isneg = wi::neg_p (w); if (isneg) w = -w; enum wi::overflow_type ovf = wi::OVF_NONE; - do + unsigned HOST_WIDE_INT pow10s[] = { + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + }; + int s = scale % 19; + if (s) + { + wide_int wm = wi::uhwi (pow10s[s - 1], w.get_precision ()); + w = wi::umul (w, wm, &ovf); + if (ovf) + scale = 0; + } + scale /= 19; + wide_int wm = wi::uhwi (pow10s[18], w.get_precision ()); + while (scale) { if (scale & 1) { @@ -667,8 +696,9 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) if (!scale) break; wm = wi::umul (wm, wm, &ovf); + if (ovf) + break; } - while (!ovf); if (ovf) { *fail = true; diff --git a/gcc/testsuite/gcc.dg/dfp/bitint-10.c b/gcc/testsuite/gcc.dg/dfp/bitint-10.c new file mode 100644 index ..b48f0ea6c277 --- /dev/null +++ b/gcc/testsuite/gcc.dg/dfp/bitint-10.c @@ -0,0 +1,49 @@ +/* PR middle-end/120631 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-O2" } */ + +#if __BITINT_MAXWIDTH__ >= 128 +_Decimal128 a = 1234567891357924680123456789000.0dl; +_BitInt(128) b = 1234567891357924680123456789000wb; +_Decimal64 c = 12345678913579.0dd; +_BitInt(127) d = 12345678913579wb; +#endif +#if __BITINT_MAXWIDTH_
[gcc r14-11853] dfp: Further decimal_real_to_integer fixes [PR120631]
https://gcc.gnu.org/g:e3cf9e55e394de211617333bbc3419c248d3e6b6 commit r14-11853-ge3cf9e55e394de211617333bbc3419c248d3e6b6 Author: Jakub Jelinek Date: Thu Jun 19 08:57:27 2025 +0200 dfp: Further decimal_real_to_integer fixes [PR120631] Unfortunately, the following further testcase shows that there aren't problems only with very large precisions and large exponents, but pretty much anything larger than 64-bits. After all, before _BitInt support dfp didn't even have {,unsigned }__int128 <-> _Decimal{32,64,128,64x} support, and the testcase again shows some of the conversions yielding zeros. While the pr120631.c test worked even without the earlier patch. So, this patch assumes 64-bit precision at most is ok and for anything larger it just uses exponent 0 and multiplies afterwards. 2025-06-19 Jakub Jelinek PR middle-end/120631 * dfp.cc (decimal_real_to_integer): Use result multiplication not just when precision > 128 and dn.exponent > 19, but when precision > 64 and dn.exponent > 0. * gcc.dg/dfp/bitint-10.c: New test. * gcc.dg/dfp/pr120631.c: New test. (cherry picked from commit e2eb9da5546b5e2fccb86586cda3beee8f69f5c9) Diff: --- gcc/dfp.cc | 46 +++-- gcc/testsuite/gcc.dg/dfp/bitint-10.c | 49 gcc/testsuite/gcc.dg/dfp/pr120631.c | 25 ++ 3 files changed, 112 insertions(+), 8 deletions(-) diff --git a/gcc/dfp.cc b/gcc/dfp.cc index ebd98974523a..592693bd99c5 100644 --- a/gcc/dfp.cc +++ b/gcc/dfp.cc @@ -625,14 +625,14 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) set.traps = 0; set.round = DEC_ROUND_DOWN; decimal128ToNumber ((const decimal128 *) r->sig, &dn); - if (precision > 128 && decNumberIsFinite (&dn) && dn.exponent > 19) + if (precision > 64 && decNumberIsFinite (&dn) && dn.exponent > 0) { /* libdecNumber doesn't really handle too large integers. So when precision is large and exponent as well, trim the exponent and adjust the resulting wide_int by multiplying -it multiple times with 10^19. */ - scale = dn.exponent / 19; - dn.exponent %= 19; +it multiple times with powers of ten. */ + scale = dn.exponent; + dn.exponent = 0; } decNumberToIntegralValue (&dn2, &dn, &set); @@ -649,13 +649,42 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) *fail = true; if (scale && !failp) { - wide_int wm = wi::uhwi (HOST_WIDE_INT_UC (1000), - w.get_precision ()); bool isneg = wi::neg_p (w); if (isneg) w = -w; enum wi::overflow_type ovf = wi::OVF_NONE; - do + unsigned HOST_WIDE_INT pow10s[] = { + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + HOST_WIDE_INT_UC (1), + HOST_WIDE_INT_UC (10), + HOST_WIDE_INT_UC (100), + HOST_WIDE_INT_UC (1000), + }; + int s = scale % 19; + if (s) + { + wide_int wm = wi::uhwi (pow10s[s - 1], w.get_precision ()); + w = wi::umul (w, wm, &ovf); + if (ovf) + scale = 0; + } + scale /= 19; + wide_int wm = wi::uhwi (pow10s[18], w.get_precision ()); + while (scale) { if (scale & 1) { @@ -667,8 +696,9 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) if (!scale) break; wm = wi::umul (wm, wm, &ovf); + if (ovf) + break; } - while (!ovf); if (ovf) { *fail = true; diff --git a/gcc/testsuite/gcc.dg/dfp/bitint-10.c b/gcc/testsuite/gcc.dg/dfp/bitint-10.c new file mode 100644 index ..b48f0ea6c277 --- /dev/null +++ b/gcc/testsuite/gcc.dg/dfp/bitint-10.c @@ -0,0 +1,49 @@ +/* PR middle-end/120631 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-O2" } */ + +#if __BITINT_MAXWIDTH__ >= 128 +_Decimal128 a = 1234567891357924680123456789000.0dl; +_BitInt(128) b = 1234567891357924680123456789000wb; +_Decimal64 c = 12345678913579.0dd; +_BitInt(127) d = 12345678913579wb; +#endif +#if __BITINT_MAXWIDTH
[gcc r14-11852] dfp, real: Fix up FLOAT_EXPR/FIX_TRUNC_EXPR constant folding between dfp and large _BitInt [PR120631
https://gcc.gnu.org/g:153160c3f59c01ab864726abce66b4c3a0f2d909 commit r14-11852-g153160c3f59c01ab864726abce66b4c3a0f2d909 Author: Jakub Jelinek Date: Wed Jun 18 08:07:22 2025 +0200 dfp, real: Fix up FLOAT_EXPR/FIX_TRUNC_EXPR constant folding between dfp and large _BitInt [PR120631] The following testcase shows that while at runtime we handle conversions between _Decimal{64,128} and large _BitInt correctly, at compile time we mishandle them in both directions, in one direction we end up in ICE in decimal_from_integer callee because the char buffer is too short for the needed number of decimal digits, in the conversion of dfp to large _BitInt we return 0 in the wide_int. The following patch fixes the ICE by using larger buffer (XALLOCAVEC allocated, it will be never larger than 65536 / 3 bytes) in the larger _BitInt case, and the other direction by setting exponent to exp % 19 and instead multiplying the result by needed powers of 10^19 (10^19 chosen as largest power of ten that can fit into UHWI). 2025-06-18 Jakub Jelinek PR middle-end/120631 * real.cc (decimal_from_integer): Add digits argument, if larger than 256, use XALLOCAVEC allocated buffer. (real_from_integer): Pass val_in's precision divided by 3 to decimal_from_integer. * dfp.cc (decimal_real_to_integer): For precision > 128 if finite and exponent is large, decrease exponent and multiply resulting wide_int by powers of 10^19. * gcc.dg/dfp/bitint-9.c: New test. (cherry picked from commit f3002d664d1137844c714645a841a48ab57d0eaa) Diff: --- gcc/dfp.cc | 49 - gcc/real.cc | 21 gcc/testsuite/gcc.dg/dfp/bitint-9.c | 29 ++ 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/gcc/dfp.cc b/gcc/dfp.cc index 98437c6777a6..ebd98974523a 100644 --- a/gcc/dfp.cc +++ b/gcc/dfp.cc @@ -619,11 +619,21 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) decNumber dn, dn2, dn3; REAL_VALUE_TYPE to; char string[256]; + int scale = 0; decContextDefault (&set, DEC_INIT_DECIMAL128); set.traps = 0; set.round = DEC_ROUND_DOWN; decimal128ToNumber ((const decimal128 *) r->sig, &dn); + if (precision > 128 && decNumberIsFinite (&dn) && dn.exponent > 19) +{ + /* libdecNumber doesn't really handle too large integers. +So when precision is large and exponent as well, trim the +exponent and adjust the resulting wide_int by multiplying +it multiple times with 10^19. */ + scale = dn.exponent / 19; + dn.exponent %= 19; +} decNumberToIntegralValue (&dn2, &dn, &set); decNumberZero (&dn3); @@ -633,7 +643,44 @@ decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision) function. */ decNumberToString (&dn, string); real_from_string (&to, string); - return real_to_integer (&to, fail, precision); + bool failp = false; + wide_int w = real_to_integer (&to, &failp, precision); + if (failp) +*fail = true; + if (scale && !failp) +{ + wide_int wm = wi::uhwi (HOST_WIDE_INT_UC (1000), + w.get_precision ()); + bool isneg = wi::neg_p (w); + if (isneg) + w = -w; + enum wi::overflow_type ovf = wi::OVF_NONE; + do + { + if (scale & 1) + { + w = wi::umul (w, wm, &ovf); + if (ovf) + break; + } + scale >>= 1; + if (!scale) + break; + wm = wi::umul (wm, wm, &ovf); + } + while (!ovf); + if (ovf) + { + *fail = true; + if (isneg) + return wi::set_bit_in_zero (precision - 1, precision); + else + return ~wi::set_bit_in_zero (precision - 1, precision); + } + if (isneg) + w = -w; +} + return w; } /* Perform the decimal floating point operation described by CODE. diff --git a/gcc/real.cc b/gcc/real.cc index 4d88a416cb75..87ec92d17786 100644 --- a/gcc/real.cc +++ b/gcc/real.cc @@ -101,7 +101,7 @@ static int do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int); static void do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *); -static void decimal_from_integer (REAL_VALUE_TYPE *); +static void decimal_from_integer (REAL_VALUE_TYPE *, int); static void decimal_integer_string (char *, const REAL_VALUE_TYPE *, size_t); @@ -2309,7 +2309,9 @@ real_from_integer (REAL_VALUE_TYPE *r, format_helper fmt, } if (fmt.decimal_p ()) -decimal_from_integer (r); +/* We need at most one decimal digits for each 3 bits of input +