[PATCH 2/3] shift: simplify LSR(LSR(x,N),N') & friends

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux