From: Kito Cheng <kito.ch...@gmail.com> Kito Cheng <kito.ch...@gmail.com> Shiva Chen <shiva0...@gmail.com>
ChangeLog: gcc/ * config/nds32/nds32-md-auxiliary.c (nds32_split_ashiftdi3): Fix wrong code gen with large shift amount. gcc/testsuite/ * gcc.target/nds32/ashiftdi3.c: New. --- gcc/config/nds32/nds32-md-auxiliary.c | 21 ++++++++++++++------- gcc/testsuite/gcc.target/nds32/ashiftdi3.c | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.target/nds32/ashiftdi3.c diff --git a/gcc/config/nds32/nds32-md-auxiliary.c b/gcc/config/nds32/nds32-md-auxiliary.c index 35fcc64..eadd841 100644 --- a/gcc/config/nds32/nds32-md-auxiliary.c +++ b/gcc/config/nds32/nds32-md-auxiliary.c @@ -3304,15 +3304,22 @@ nds32_split_ashiftdi3 (rtx dst, rtx src, rtx shiftamount) ext_start = gen_reg_rtx (SImode); /* - if (shiftamount < 32) + # In fact, we want to check shift amonut is great than or equal 32, + # but in some corner case, the shift amount might be very large value, + # however we've defined SHIFT_COUNT_TRUNCATED, so GCC think we've + # handle that correctly without any truncate. + # so check the the condition of (shiftamount & 32) is most + # safe way to do. + if (shiftamount & 32) + dst_low_part = 0 + dst_high_part = src_low_part << shiftamount & 0x1f + else dst_low_part = src_low_part << shiftamout dst_high_part = wext (src, 32 - shiftamount) # wext can't handle wext (src, 32) since it's only take rb[0:4] # for extract. dst_high_part = shiftamount == 0 ? src_high_part : dst_high_part - else - dst_low_part = 0 - dst_high_part = src_low_part << shiftamount & 0x1f + */ emit_insn (gen_subsi3 (ext_start, @@ -3331,11 +3338,11 @@ nds32_split_ashiftdi3 (rtx dst, rtx src, rtx shiftamount) emit_insn (gen_ashlsi3 (dst_high_part_g32, src_low_part, new_shift_amout)); - emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32))); + emit_insn (gen_andsi3 (select_reg, shiftamount, GEN_INT (32))); - emit_insn (gen_cmovnsi (dst_low_part, select_reg, + emit_insn (gen_cmovzsi (dst_low_part, select_reg, dst_low_part_l32, dst_low_part_g32)); - emit_insn (gen_cmovnsi (dst_high_part, select_reg, + emit_insn (gen_cmovzsi (dst_high_part, select_reg, dst_high_part_l32, dst_high_part_g32)); } } diff --git a/gcc/testsuite/gcc.target/nds32/ashiftdi3.c b/gcc/testsuite/gcc.target/nds32/ashiftdi3.c new file mode 100644 index 0000000..e3faff5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/ashiftdi3.c @@ -0,0 +1,23 @@ +/* { dg-options "-mext-dsp" { target nds32 } } */ + +#include<stdio.h> +extern void abort (void); + +unsigned long long int ull; + +unsigned long long int __attribute__ ((noinline)) +foo (unsigned long long int a, unsigned long long int b) +{ + return a << b; +} + +int +main (void) +{ + unsigned long long shiftamt = 0x45806aca; + ull = foo(0xfffffffff, shiftamt); + if (ull != 70368744176640) + abort (); + + return 0; +} -- 1.8.3.1