diff mbox series

[8/9] simplify ((x & M) | (y << S)) >> S

Message ID 20180808143528.82880-9-luc.vanoostenryck@gmail.com (mailing list archive)
State Rejected, archived
Headers show
Series more simplifications of bitfiled accesses | expand

Commit Message

Luc Van Oostenryck Aug. 8, 2018, 2:35 p.m. UTC
This expression is simplified into:
	 ((x >> S) & M') | (y & M'')
with M' = (M >> S) and M'' = (~0 >> S)

This is a rather complex and specialized simplification but
it is the first of a two steps process to simplify some
bitfield acceesses. More exactly, the access is the store/reload
of a bitfield which is otherwise potentially uninitialized.
The next step will be the simplification of:
	 ((((x >> S) & M') | (y & M'')) & M'''
where (M' & M''') = 0. Then the whole expression is reduced to:
	 (y & (M'' & M'''))
which doesn't use x (potentially unintialized, or simply unknown).

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 simplify.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
diff mbox series

Patch

diff --git a/simplify.c b/simplify.c
index e58c97c08..baea32378 100644
--- a/simplify.c
+++ b/simplify.c
@@ -580,11 +580,38 @@  static int simplify_or_lsr(struct instruction *insn, pseudo_t src, pseudo_t othe
 	// src->def->opcode == OP_AND
 	struct instruction *insn2 = src->def;
 	pseudo_t src2 = insn2->src2;
+	struct instruction *insn3;
 
 	if (!constant(src2))
 		return 0;
 	if ((((unsigned long long)src2->value) >> shift) == 0)
 		return replace_pseudo(insn, &insn->src1, other);
+	if (DEF_OPCODE(insn3, other) == OP_SHL && constant(insn3->src2)
+	    && insn3->src2->value == shift && nbr_users(src) == 1
+	    && nbr_users(other) == 1 && nbr_users(insn->src1) == 1) {
+		struct instruction *insn1 = insn->src1->def;
+		unsigned long long mask = insn2->src2->value;
+		unsigned size = insn->size;
+
+		// simplify ((x & M) | (y << S)) >> S
+		// into     ((x >> S) & M') | (y & M'')
+		// where M' = (M >> S) and M'' = (~0 >> S)
+
+		insn3->opcode = OP_AND;
+		insn3->src2 = value_pseudo(bits_mask(size - shift));
+
+		insn2->opcode = OP_LSR;
+		insn2->src2 = value_pseudo(shift);
+
+		insn1->opcode = OP_AND;
+		insn1->src2 = value_pseudo(mask >> shift);
+
+		insn->opcode = OP_OR;
+		use_pseudo(insn, other, &insn->src2);
+		remove_usage(other, &insn1->src2);
+
+		return REPEAT_CSE;
+	}
 	return 0;
 }