A logical shift right followed by a sign extension is equivalent to an arithmetic shift. Teach this to sparse. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- simplify.c | 13 ++++++++++++- validation/optim/lsr-to-asr.c | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 validation/optim/lsr-to-asr.c diff --git a/simplify.c b/simplify.c index 1e7648486c49..3d398292f172 100644 --- a/simplify.c +++ b/simplify.c @@ -2066,7 +2066,7 @@ static int simplify_memop(struct instruction *insn) static int simplify_cast(struct instruction *insn) { unsigned long long mask; - struct instruction *def; + struct instruction *def, *def2; pseudo_t src = insn->src; pseudo_t val; int osize; @@ -2163,6 +2163,17 @@ static int simplify_cast(struct instruction *insn) case OP_TRUNC: insn->orig_type = def->orig_type; return replace_pseudo(insn, &insn->src1, def->src); + case OP_SEXT: + if (size != def->orig_type->bit_size) + break; + if (DEF_OPCODE(def2, def->src) != OP_LSR) + break; + if (def2->src2 != value_pseudo(size - def->size)) + break; + // SEXT(TRUNC(LSR(x, N))) --> ASR(x, N) + insn->opcode = OP_ASR; + insn->src2 = def2->src2; + return replace_pseudo(insn, &insn->src1, def2->src1); case OP_ZEXT: if (size != def->orig_type->bit_size) break; diff --git a/validation/optim/lsr-to-asr.c b/validation/optim/lsr-to-asr.c new file mode 100644 index 000000000000..269277396429 --- /dev/null +++ b/validation/optim/lsr-to-asr.c @@ -0,0 +1,27 @@ +int lsr_to_asr24(int x) +{ + return ((signed char)(((unsigned)x) >> 24)) == (x >> 24); +} + + +struct s { + int :30; + signed int f:2; +}; + +int lsr_to_asr30(int a) +{ + union { + int i; + struct s s; + } u = { .i = a }; + return u.s.f == (a >> 30); +} + +/* + * check-name: lsr-to-asr + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-returns: 1 + */ -- 2.30.0