Expressions involving equality testing against zero are ubiquitious and can often be simplified with previous comparisons. For example, when using test-linearize on the following code: _Bool foo(int a) { return !(a < 3); } the following was emitted: setlt.32 %r2 <- %arg1, $3 seteq.32 %r3 <- %r2, $0 setne.1 %r4 <- %r3, $0 ret.1 %r4 but this can be simplified into: setge.1 %r4 <- %arg1, $3 ret.1 %r4 Implement this simplification and add associated test cases. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- simplify.c | 65 ++++++++++++++++++++++++++++++++++++++++++ validation/optim/setcc-setcc.c | 19 ++++++++++++ validation/optim/setcc-seteq.c | 13 +++++++++ validation/optim/setcc-setne.c | 13 +++++++++ 4 files changed, 110 insertions(+) create mode 100644 validation/optim/setcc-setcc.c create mode 100644 validation/optim/setcc-seteq.c create mode 100644 validation/optim/setcc-setne.c diff --git a/simplify.c b/simplify.c index b29b3ebb..d076ebb5 100644 --- a/simplify.c +++ b/simplify.c @@ -310,6 +310,67 @@ static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long val return 0; } +static int compare_opcode(int opcode, int inverse) +{ + if (!inverse) + return opcode; + + switch (opcode) { + case OP_SET_EQ: return OP_SET_NE; + case OP_SET_NE: return OP_SET_EQ; + + case OP_SET_LT: return OP_SET_GE; + case OP_SET_LE: return OP_SET_GT; + case OP_SET_GT: return OP_SET_LE; + case OP_SET_GE: return OP_SET_LT; + + case OP_SET_A: return OP_SET_BE; + case OP_SET_AE: return OP_SET_B; + case OP_SET_B: return OP_SET_AE; + case OP_SET_BE: return OP_SET_A; + + default: + return opcode; + } +} + +static int simplify_seteq_setne(struct instruction *insn, long long value) +{ + struct instruction *def = insn->src1->def; + pseudo_t src1, src2; + int inverse; + int opcode; + + if (value != 0 && value != 1) + return 0; + + if (!def) + return 0; + + inverse = (insn->opcode == OP_SET_NE) == value; + opcode = def->opcode; + switch (opcode) { + case OP_BINCMP ... OP_BINCMP_END: + // Convert: + // setcc.n %t <- %a, %b + // setne.m %r <- %t, $0 + // into: + // setcc.n %t <- %a, %b + // setcc.m %r <- %a, $b + // and similar for setne/eq ... 0/1 + src1 = def->src1; + src2 = def->src2; + remove_usage(insn->src1, &insn->src1); + insn->opcode = compare_opcode(opcode, inverse); + use_pseudo(insn, src1, &insn->src1); + use_pseudo(insn, src2, &insn->src2); + return REPEAT_CSE; + + default: + return 0; + } +} + static int simplify_constant_rightside(struct instruction *insn) { long long value = insn->src2->value; @@ -342,6 +403,10 @@ static int simplify_constant_rightside(struct instruction *insn) if (!value) return replace_with_pseudo(insn, insn->src2); return 0; + + case OP_SET_NE: + case OP_SET_EQ: + return simplify_seteq_setne(insn, value); } return 0; } diff --git a/validation/optim/setcc-setcc.c b/validation/optim/setcc-setcc.c new file mode 100644 index 00000000..fac7520e --- /dev/null +++ b/validation/optim/setcc-setcc.c @@ -0,0 +1,19 @@ +static _Bool blt(int a, int b) { return (a < b); } +static _Bool bnge(int a, int b) { return !(a >= b); } +static _Bool bgt(int a, int b) { return (a > b); } +static _Bool bnle(int a, int b) { return !(a <= b); } +static _Bool ble(int a, int b) { return (a <= b); } +static _Bool bngt(int a, int b) { return !(a > b); } +static _Bool bge(int a, int b) { return (a >= b); } +static _Bool bnlt(int a, int b) { return !(a < b); } + +/* + * check-name: optim/setcc-setcc + * check-command: test-linearize $file + * check-output-ignore + * + * check-output-excludes: set..\\.32 + * check-output-excludes: setne\\.1 + * check-output-excludes: seteq\\.1 + * check-output-contains: set[gt][te]\\.1 + */ diff --git a/validation/optim/setcc-seteq.c b/validation/optim/setcc-seteq.c new file mode 100644 index 00000000..d8765fe1 --- /dev/null +++ b/validation/optim/setcc-seteq.c @@ -0,0 +1,13 @@ +static _Bool beq0(int a) { return (a == 0); } +static _Bool bnotneq0(int a) { return !(a != 0); } +static _Bool bnot(int a) { return !a; } + +/* + * check-name: optim/setcc-seteq + * check-command: test-linearize $file + * check-output-ignore + * + * check-output-excludes: set..\\.32 + * check-output-excludes: setne\\.1 + * check-output-contains: seteq\\.1 + */ diff --git a/validation/optim/setcc-setne.c b/validation/optim/setcc-setne.c new file mode 100644 index 00000000..f982eb34 --- /dev/null +++ b/validation/optim/setcc-setne.c @@ -0,0 +1,13 @@ +static _Bool bnoteq0(int a) { return !(a == 0); } +static _Bool bne0(int a) { return (a != 0); } +static _Bool bnotnot(int a) { return !!a; } + +/* + * check-name: optim/setcc-setne + * check-command: test-linearize $file + * check-output-ignore + * + * check-output-excludes: set..\\.32 + * check-output-excludes: seteq\\.1 + * check-output-contains: setne\\.1 + */ -- 2.10.2 -- 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