diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 2f8d391579a..58060b8600c 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -2605,41 +2605,64 @@ riscv_legitimize_move (machine_mode mode, rtx dest, rtx src) unsigned int nunits = vmode_size > mode_size ? vmode_size / mode_size : 1; scalar_mode smode = as_a (mode); unsigned int index = SUBREG_BYTE (src).to_constant () / mode_size; - unsigned int num = smode == DImode && !TARGET_VECTOR_ELEN_64 ? 2 : 1; + unsigned int num = known_eq (GET_MODE_SIZE (smode), 8) + && !TARGET_VECTOR_ELEN_64 ? 2 : 1; + bool need_int_reg_p = false; if (num == 2) { /* If we want to extract 64bit value but ELEN < 64, we use RVV vector mode with EEW = 32 to extract the highpart and lowpart. */ + need_int_reg_p = smode == DFmode; smode = SImode; nunits = nunits * 2; } - vmode = riscv_vector::get_vector_mode (smode, nunits).require (); - rtx v = gen_lowpart (vmode, SUBREG_REG (src)); - for (unsigned int i = 0; i < num; i++) + if (riscv_vector::get_vector_mode (smode, nunits).exists (&vmode)) { - rtx result; - if (num == 1) - result = dest; - else if (i == 0) - result = gen_lowpart (smode, dest); - else - result = gen_reg_rtx (smode); - riscv_vector::emit_vec_extract (result, v, index + i); + rtx v = gen_lowpart (vmode, SUBREG_REG (src)); + rtx int_reg = dest; - if (i == 1) + if (need_int_reg_p) { - rtx tmp - = expand_binop (Pmode, ashl_optab, gen_lowpart (Pmode, result), - gen_int_mode (32, Pmode), NULL_RTX, 0, - OPTAB_DIRECT); - rtx tmp2 = expand_binop (Pmode, ior_optab, tmp, dest, NULL_RTX, 0, - OPTAB_DIRECT); - emit_move_insn (dest, tmp2); + int_reg = gen_reg_rtx (DImode); + emit_move_insn (int_reg, gen_lowpart (GET_MODE (int_reg), dest)); } + + for (unsigned int i = 0; i < num; i++) + { + rtx result; + if (num == 1) + result = int_reg; + else if (i == 0) + result = gen_lowpart (smode, int_reg); + else + result = gen_reg_rtx (smode); + + riscv_vector::emit_vec_extract (result, v, index + i); + + if (i == 1) + { + rtx tmp = expand_binop (Pmode, ashl_optab, + gen_lowpart (Pmode, result), + gen_int_mode (32, Pmode), NULL_RTX, 0, + OPTAB_DIRECT); + rtx tmp2 = expand_binop (Pmode, ior_optab, tmp, int_reg, + NULL_RTX, 0, + OPTAB_DIRECT); + emit_move_insn (int_reg, tmp2); + } + } + + if (need_int_reg_p) + emit_move_insn (dest, gen_lowpart (GET_MODE (dest), int_reg)); + else + emit_move_insn (dest, int_reg); } + else + gcc_unreachable (); + return true; } /* Expand diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr112743-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr112743-2.c new file mode 100644 index 00000000000..fdb35fd70f2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr112743-2.c @@ -0,0 +1,52 @@ +/* Test that we do not have ice when compile */ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zve32f_zvfh_zfh -mabi=lp64 -O2" } */ + +#include + +union double_union +{ + double d; + __uint32_t i[2]; +}; + +#define word0(x) (x.i[1]) +#define word1(x) (x.i[0]) + +#define P 53 +#define Exp_shift 20 +#define Exp_msk1 ((__uint32_t)0x100000L) +#define Exp_mask ((__uint32_t)0x7ff00000L) + +double ulp (double _x) +{ + union double_union x, a; + register int L; + + x.d = _x; + L = (word0 (x) & Exp_mask) - (P - 1) * Exp_msk1; + + if (L > 0) + { + L |= Exp_msk1 >> 4; + word0 (a) = L; + word1 (a) = 0; + } + else + { + L = -L >> Exp_shift; + if (L < Exp_shift) + { + word0 (a) = 0x80000 >> L; + word1 (a) = 0; + } + else + { + word0 (a) = 0; + L -= Exp_shift; + word1 (a) = L >= 31 ? 1 : 1 << (31 - L); + } + } + + return a.d; +}