aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--simplify.c11
-rw-r--r--validation/optim/muldiv-minus-one.c13
2 files changed, 24 insertions, 0 deletions
diff --git a/simplify.c b/simplify.c
index ed6cc41b..e529cee3 100644
--- a/simplify.c
+++ b/simplify.c
@@ -339,6 +339,9 @@ static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long val
static int simplify_mul_div(struct instruction *insn, long long value)
{
+ unsigned long long sbit = 1ULL << (insn->size - 1);
+ unsigned long long bits = sbit | (sbit - 1);
+
if (value == 1)
return replace_with_pseudo(insn, insn->src1);
@@ -347,6 +350,14 @@ static int simplify_mul_div(struct instruction *insn, long long value)
case OP_MULU:
if (value == 0)
return replace_with_pseudo(insn, insn->src2);
+ if (!(value & sbit)) // positive
+ break;
+
+ value |= ~bits;
+ if (value == -1) {
+ insn->opcode = OP_NEG;
+ return REPEAT_CSE;
+ }
}
return 0;
diff --git a/validation/optim/muldiv-minus-one.c b/validation/optim/muldiv-minus-one.c
new file mode 100644
index 00000000..729b7344
--- /dev/null
+++ b/validation/optim/muldiv-minus-one.c
@@ -0,0 +1,13 @@
+typedef unsigned int u32;
+
+int smulm1(int a) { return a * -1; }
+u32 umulm1(u32 a) { return a * (u32) -1; }
+
+/*
+ * check-name: muldiv-minus-one
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: mul[us]\\.
+ * check-output-contains: neg\\.
+ */