diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-11-07 01:09:07 +0100 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-11-07 12:08:31 +0100 |
| commit | 7ccaa8a6e88a02e05cb37adc2658071947e9331c (patch) | |
| tree | c7d272aee4287fe23fdf22da603e6fa2b124eb8e /simplify.c | |
| parent | e58ddb5678f2fb1843c6871399509eacf9cc1371 (diff) | |
| download | sparse-dev-7ccaa8a6e88a02e05cb37adc2658071947e9331c.tar.gz | |
select: simplify SEL(SEL(x, C, 0), y, z) --> SEL(x, y, z) and its dual
If the condition of a select is also a select but with constant
operands, some simplification can be done:
* if the second operand is 0, the original condition can be used,
* idem if the first operand is 0s but the operand must be swapped.
Originally-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Diffstat (limited to 'simplify.c')
| -rw-r--r-- | simplify.c | 20 |
1 files changed, 20 insertions, 0 deletions
@@ -1748,6 +1748,7 @@ static int simplify_cast(struct instruction *insn) static int simplify_select(struct instruction *insn) { pseudo_t cond, src1, src2; + struct instruction *def; cond = insn->src1; src1 = insn->src2; @@ -1782,6 +1783,25 @@ static int simplify_select(struct instruction *insn) kill_use(&insn->src3); return replace_with_value(insn, 0); } + + switch (DEF_OPCODE(def, cond)) { + case OP_SEL: + if (constant(def->src2) && constant(def->src3)) { + // Is the def of the conditional another select? + // And if that one results in a "zero or not", use the + // original conditional instead. + // SEL(SEL(x, C, 0), y, z) --> SEL(x, y, z) + // SEL(SEL(x, 0, C), y, z) --> SEL(x, z, y) + if (!def->src3->value) { + return replace_pseudo(insn, &insn->cond, def->cond); + } + if (!def->src2->value) { + switch_pseudo(insn, &insn->src2, insn, &insn->src3); + return replace_pseudo(insn, &insn->cond, def->cond); + } + } + break; + } return 0; } |
