A shift of a shift (of the same kind) is equivalent to a single shitf with a count equal to the sum of the two initial counts. In addition: * for LSRs & SHLs, if the sum is >= to the instruction size, then the result is zero. * for ASRs, if the sum is >= to the instruction size, then the result is the same as a shift of a count of size - 1. Implement these simplifications if both shift counts are in range. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- simplify.c | 37 +++++++- validation/optim/lsr-asr.c | 46 ++++++++++ validation/optim/shift-shift.c | 149 +++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 validation/optim/lsr-asr.c create mode 100644 validation/optim/shift-shift.c diff --git a/simplify.c b/simplify.c index 014466889..7475d9e6c 100644 --- a/simplify.c +++ b/simplify.c @@ -577,7 +577,10 @@ static long long check_shift_count(struct instruction *insn, unsigned long long static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value) { + struct instruction *def; + unsigned long long nval; unsigned int size; + pseudo_t src2; if (!value) return replace_with_pseudo(insn, pseudo); @@ -590,15 +593,47 @@ static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long v case OP_ASR: if (value >= size) return 0; + switch(DEF_OPCODE(def, pseudo)) { + case OP_ASR: + src2 = def->src2; + if (src2->type != PSEUDO_VAL) + break; + nval = src2->value; + if (nval > insn->size) + break; + value += nval; + if (value >= size) + value = size - 1; + goto new_value; + } break; case OP_LSR: size = operand_size(insn, pseudo); /* fall through */ case OP_SHL: if (value >= size) - return replace_with_pseudo(insn, value_pseudo(0)); + goto zero; + if (DEF_OPCODE(def, pseudo) == insn->opcode) { + src2 = def->src2; + if (src2->type != PSEUDO_VAL) + break; + nval = src2->value; + if (nval > insn->size) + break; + value += nval; + goto new_value; + } + break; } return 0; + +new_value: + if (value < size) { + insn->src2 = value_pseudo(value); + return replace_pseudo(insn, &insn->src1, pseudo->def->src1); + } +zero: + return replace_with_pseudo(insn, value_pseudo(0)); } static int simplify_mul_div(struct instruction *insn, long long value) diff --git a/validation/optim/lsr-asr.c b/validation/optim/lsr-asr.c new file mode 100644 index 000000000..2e4f8323f --- /dev/null +++ b/validation/optim/lsr-asr.c @@ -0,0 +1,46 @@ +int lsrasr0(unsigned int x) +{ + return ((int) (x >> 15)) >> 15; +} + +int lsrasr1(unsigned int x) +{ + return ((int) (x >> 16)) >> 15; +} + +int lsrasr2(unsigned int x) +{ + return ((int) (x >> 16)) >> 16; +} + +/* + * check-name: lsr-asr + * check-command: test-linearize -Wno-decl $file + * + * check-output-start +lsrasr0: +.L0: + <entry-point> + lsr.32 %r2 <- %arg1, $15 + asr.32 %r3 <- %r2, $15 + ret.32 %r3 + + +lsrasr1: +.L2: + <entry-point> + lsr.32 %r6 <- %arg1, $16 + asr.32 %r7 <- %r6, $15 + ret.32 %r7 + + +lsrasr2: +.L4: + <entry-point> + lsr.32 %r10 <- %arg1, $16 + asr.32 %r11 <- %r10, $16 + ret.32 %r11 + + + * check-output-end + */ diff --git a/validation/optim/shift-shift.c b/validation/optim/shift-shift.c new file mode 100644 index 000000000..12a4b7d4c --- /dev/null +++ b/validation/optim/shift-shift.c @@ -0,0 +1,149 @@ +unsigned int shl0(unsigned int x) +{ + return x << 15 << 15; +} + +unsigned int shl1(unsigned int x) +{ + return x << 16 << 15; +} + +unsigned int shl2(unsigned int x) +{ + return x << 16 << 16; +} + +unsigned int shl3(unsigned int x) +{ + return x << 12 << 10 << 10; +} + + +unsigned int lsr0(unsigned int x) +{ + return x >> 15 >> 15; +} + +unsigned int lsr1(unsigned int x) +{ + return x >> 16 >> 15; +} + +unsigned int lsr2(unsigned int x) +{ + return x >> 16 >> 16; +} + +unsigned int lsr3(unsigned int x) +{ + return x >> 12 >> 10 >> 10; +} + + +int asr0(int x) +{ + return x >> 15 >> 15; +} + +int asr1(int x) +{ + return x >> 16 >> 15; +} + +int asr2(int x) +{ + return x >> 16 >> 16; +} + +int asr3(int x) +{ + return x >> 12 >> 10 >> 10; +} + +/* + * check-name: shift-shift + * check-command: test-linearize -Wno-decl $file + * + * check-output-start +shl0: +.L0: + <entry-point> + shl.32 %r3 <- %arg1, $30 + ret.32 %r3 + + +shl1: +.L2: + <entry-point> + shl.32 %r7 <- %arg1, $31 + ret.32 %r7 + + +shl2: +.L4: + <entry-point> + ret.32 $0 + + +shl3: +.L6: + <entry-point> + ret.32 $0 + + +lsr0: +.L8: + <entry-point> + lsr.32 %r20 <- %arg1, $30 + ret.32 %r20 + + +lsr1: +.L10: + <entry-point> + lsr.32 %r24 <- %arg1, $31 + ret.32 %r24 + + +lsr2: +.L12: + <entry-point> + ret.32 $0 + + +lsr3: +.L14: + <entry-point> + ret.32 $0 + + +asr0: +.L16: + <entry-point> + asr.32 %r37 <- %arg1, $30 + ret.32 %r37 + + +asr1: +.L18: + <entry-point> + asr.32 %r41 <- %arg1, $31 + ret.32 %r41 + + +asr2: +.L20: + <entry-point> + asr.32 %r45 <- %arg1, $31 + ret.32 %r45 + + +asr3: +.L22: + <entry-point> + asr.32 %r50 <- %arg1, $31 + ret.32 %r50 + + + * check-output-end + */ -- 2.18.0 -- To unsubscribe from this list: send the line "unsubscribe linux-sparse" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html