aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--linearize.c6
-rw-r--r--linearize.h2
-rw-r--r--simplify.c53
-rw-r--r--sparse-llvm.c75
-rw-r--r--validation/optim/simplify-neg-add-cte.c11
-rw-r--r--validation/optim/simplify-neg-not.c9
-rw-r--r--validation/optim/simplify-neg-sub.c9
-rw-r--r--validation/optim/simplify-not-add-cte.c11
-rw-r--r--validation/optim/simplify-not-neg.c9
-rw-r--r--validation/optim/simplify-not-sub-cte.c11
-rw-r--r--validation/optim/simplify-not-xor-cte.c11
11 files changed, 152 insertions, 55 deletions
diff --git a/linearize.c b/linearize.c
index 1081bda8..b7da35fa 100644
--- a/linearize.c
+++ b/linearize.c
@@ -426,10 +426,10 @@ const char *show_instruction(struct instruction *insn)
break;
}
case OP_LOAD:
- buf += sprintf(buf, "%s <- %d[%s]", show_pseudo(insn->target), insn->offset, show_pseudo(insn->src));
+ buf += sprintf(buf, "%s <- %lld[%s]", show_pseudo(insn->target), insn->offset, show_pseudo(insn->src));
break;
case OP_STORE:
- buf += sprintf(buf, "%s -> %d[%s]", show_pseudo(insn->target), insn->offset, show_pseudo(insn->src));
+ buf += sprintf(buf, "%s -> %lld[%s]", show_pseudo(insn->target), insn->offset, show_pseudo(insn->src));
break;
case OP_INLINED_CALL:
case OP_CALL: {
@@ -925,7 +925,7 @@ struct access_data {
struct symbol *type; // ctype
struct symbol *btype; // base type of bitfields
pseudo_t address; // pseudo containing address ..
- unsigned int offset; // byte offset
+ long long offset; // byte offset
};
static int linearize_simple_address(struct entrypoint *ep,
diff --git a/linearize.h b/linearize.h
index 76efd0b4..d8cbc3f3 100644
--- a/linearize.h
+++ b/linearize.h
@@ -117,7 +117,7 @@ struct instruction {
};
struct /* memops */ {
pseudo_t addr; /* alias .src */
- unsigned int offset;
+ long long offset;
unsigned int is_volatile:1;
};
struct /* binops and sel */ {
diff --git a/simplify.c b/simplify.c
index 96cd73a0..7588e420 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1481,21 +1481,64 @@ static int simplify_constant_unop(struct instruction *insn)
static int simplify_unop(struct instruction *insn)
{
+ struct instruction *def;
+ pseudo_t src = insn->src;
+
if (dead_insn(insn, &insn->src1, NULL, NULL))
return REPEAT_CSE;
- if (constant(insn->src1))
+ if (constant(src))
return simplify_constant_unop(insn);
switch (insn->opcode) {
- struct instruction *def;
-
case OP_NOT:
- if (DEF_OPCODE(def, insn->src) == OP_NOT)
+ switch (DEF_OPCODE(def, src)) {
+ case OP_ADD:
+ if (!constant(def->src2))
+ break;
+ insn->opcode = OP_SUB; // ~(x + C) --> ~C - x
+ src = eval_unop(OP_NOT, insn->size, def->src2);
+ use_pseudo(insn, def->src1, &insn->src2);
+ return replace_pseudo(insn, &insn->src1, src);
+ case OP_NEG:
+ insn->opcode = OP_SUB; // ~(-x) --> x - 1
+ insn->src2 = value_pseudo(1);
+ return replace_pseudo(insn, &insn->src1, def->src);
+ case OP_NOT: // ~(~x) --> x
return replace_with_pseudo(insn, def->src);
+ case OP_SUB:
+ if (!constant(def->src1))
+ break;
+ insn->opcode = OP_ADD; // ~(C - x) --> x + ~C
+ insn->src2 = eval_unop(OP_NOT, insn->size, def->src1);
+ return replace_pseudo(insn, &insn->src1, def->src2);
+ case OP_XOR:
+ if (!constant(def->src2))
+ break;
+ insn->opcode = OP_XOR; // ~(x ^ C) --> x ^ ~C
+ insn->src2 = eval_unop(OP_NOT, insn->size, def->src2);
+ return replace_pseudo(insn, &insn->src1, def->src1);
+ }
break;
case OP_NEG:
- if (DEF_OPCODE(def, insn->src) == OP_NEG)
+ switch (DEF_OPCODE(def, src)) {
+ case OP_ADD:
+ if (!constant(def->src2))
+ break;
+ insn->opcode = OP_SUB; // -(x + C) --> (-C - x)
+ src = eval_unop(OP_NEG, insn->size, def->src2);
+ use_pseudo(insn, def->src1, &insn->src2);
+ return replace_pseudo(insn, &insn->src1, src);
+ case OP_NEG: // -(-x) --> x
return replace_with_pseudo(insn, def->src);
+ case OP_NOT:
+ insn->opcode = OP_ADD; // -(~x) --> x + 1
+ insn->src2 = value_pseudo(1);
+ return replace_pseudo(insn, &insn->src1, def->src);
+ case OP_SUB:
+ insn->opcode = OP_SUB; // -(x - y) --> y - x
+ use_pseudo(insn, def->src1, &insn->src2);
+ return replace_pseudo(insn, &insn->src1, def->src2);
+ }
break;
default:
return 0;
diff --git a/sparse-llvm.c b/sparse-llvm.c
index c7a9fbb7..c984dc87 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -826,37 +826,14 @@ static void output_op_call(struct function *fn, struct instruction *insn)
static void output_op_phisrc(struct function *fn, struct instruction *insn)
{
- LLVMValueRef v;
- struct instruction *phi;
-
- assert(insn->target->priv == NULL);
-
- /* target = src */
- v = get_operand(fn, insn->type, insn->phi_src);
-
- FOR_EACH_PTR(insn->phi_users, phi) {
- LLVMValueRef load, ptr;
-
- assert(phi->opcode == OP_PHI);
- /* phi must be load from alloca */
- load = phi->target->priv;
- assert(LLVMGetInstructionOpcode(load) == LLVMLoad);
- ptr = LLVMGetOperand(load, 0);
- /* store v to alloca */
- LLVMBuildStore(fn->builder, v, ptr);
- } END_FOR_EACH_PTR(phi);
+ insn->src->priv = get_operand(fn, insn->type, insn->src);
}
static void output_op_phi(struct function *fn, struct instruction *insn)
{
- LLVMValueRef load = insn->target->priv;
-
- /* forward load */
- assert(LLVMGetInstructionOpcode(load) == LLVMLoad);
- /* forward load has no parent block */
- assert(!LLVMGetInstructionParent(load));
- /* finalize load in current block */
- LLVMInsertIntoBuilder(fn->builder, load);
+ LLVMTypeRef dst_type = insn_symbol_type(insn);
+
+ insn->target->priv = LLVMBuildPhi(fn->builder, dst_type, "");
}
static void output_op_ptrcast(struct function *fn, struct instruction *insn)
@@ -1161,30 +1138,11 @@ static void output_fn(LLVMModuleRef module, struct entrypoint *ep)
static int nr_bb;
LLVMBasicBlockRef bbr;
char bbname[32];
- struct instruction *insn;
sprintf(bbname, "L%d", nr_bb++);
bbr = LLVMAppendBasicBlock(function.fn, bbname);
bb->priv = bbr;
-
- /* allocate alloca for each phi */
- FOR_EACH_PTR(bb->insns, insn) {
- LLVMBasicBlockRef entrybbr;
- LLVMTypeRef phi_type;
- LLVMValueRef ptr;
-
- if (!insn->bb || insn->opcode != OP_PHI)
- continue;
- /* insert alloca into entry block */
- entrybbr = LLVMGetEntryBasicBlock(function.fn);
- LLVMPositionBuilderAtEnd(function.builder, entrybbr);
- phi_type = insn_symbol_type(insn);
- ptr = LLVMBuildAlloca(function.builder, phi_type, "");
- /* emit forward load for phi */
- LLVMClearInsertionPosition(function.builder);
- insn->target->priv = LLVMBuildLoad(function.builder, ptr, "phi");
- } END_FOR_EACH_PTR(insn);
}
END_FOR_EACH_PTR(bb);
@@ -1194,6 +1152,31 @@ static void output_fn(LLVMModuleRef module, struct entrypoint *ep)
output_bb(&function, bb);
}
END_FOR_EACH_PTR(bb);
+
+ FOR_EACH_PTR(ep->bbs, bb) { // complete the OP_PHIs
+ struct instruction *insn;
+
+ FOR_EACH_PTR(bb->insns, insn) {
+ pseudo_t phi;
+
+ if (!insn->bb || insn->opcode != OP_PHI)
+ continue;
+
+ FOR_EACH_PTR(insn->phi_list, phi) {
+ struct instruction *phisrc;
+ LLVMBasicBlockRef bref;
+ LLVMValueRef vref;
+
+ if (phi == VOID)
+ continue;
+
+ phisrc = phi->def;
+ bref = phisrc->bb->priv;
+ vref = phisrc->src->priv;
+ LLVMAddIncoming(insn->target->priv, &vref, &bref, 1);
+ } END_FOR_EACH_PTR(phi);
+ } END_FOR_EACH_PTR(insn);
+ } END_FOR_EACH_PTR(bb);
}
static LLVMValueRef output_data(LLVMModuleRef module, struct symbol *sym)
diff --git a/validation/optim/simplify-neg-add-cte.c b/validation/optim/simplify-neg-add-cte.c
new file mode 100644
index 00000000..a02c474f
--- /dev/null
+++ b/validation/optim/simplify-neg-add-cte.c
@@ -0,0 +1,11 @@
+#define C 3
+
+int foo(int x) { return -(x + C) == (-3 - x); }
+
+/*
+ * check-name: simplify-neg-add-cte
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
diff --git a/validation/optim/simplify-neg-not.c b/validation/optim/simplify-neg-not.c
new file mode 100644
index 00000000..e92352cf
--- /dev/null
+++ b/validation/optim/simplify-neg-not.c
@@ -0,0 +1,9 @@
+int foo(int x) { return -(~x) == x + 1; }
+
+/*
+ * check-name: simplify-neg-not
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
diff --git a/validation/optim/simplify-neg-sub.c b/validation/optim/simplify-neg-sub.c
new file mode 100644
index 00000000..9a824f09
--- /dev/null
+++ b/validation/optim/simplify-neg-sub.c
@@ -0,0 +1,9 @@
+int foo(int x, int y) { return -(x - y) == (y - x); }
+
+/*
+ * check-name: simplify-neg-sub
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
diff --git a/validation/optim/simplify-not-add-cte.c b/validation/optim/simplify-not-add-cte.c
new file mode 100644
index 00000000..6594012b
--- /dev/null
+++ b/validation/optim/simplify-not-add-cte.c
@@ -0,0 +1,11 @@
+#define C 3
+
+int foo(int x) { return ~(x + C) == (~C - x); }
+
+/*
+ * check-name: simplify-not-add-cte
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
diff --git a/validation/optim/simplify-not-neg.c b/validation/optim/simplify-not-neg.c
new file mode 100644
index 00000000..3fd8400d
--- /dev/null
+++ b/validation/optim/simplify-not-neg.c
@@ -0,0 +1,9 @@
+int foo(int x) { return ~(-x) == (x - 1); }
+
+/*
+ * check-name: simplify-not-neg
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
diff --git a/validation/optim/simplify-not-sub-cte.c b/validation/optim/simplify-not-sub-cte.c
new file mode 100644
index 00000000..1ea73ece
--- /dev/null
+++ b/validation/optim/simplify-not-sub-cte.c
@@ -0,0 +1,11 @@
+#define C 3
+
+int foo(int x) { return ~(C - x) == (x + ~C); }
+
+/*
+ * check-name: simplify-not-sub-cte
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
diff --git a/validation/optim/simplify-not-xor-cte.c b/validation/optim/simplify-not-xor-cte.c
new file mode 100644
index 00000000..c3c803b3
--- /dev/null
+++ b/validation/optim/simplify-not-xor-cte.c
@@ -0,0 +1,11 @@
+#define C 3
+
+int foo(int x) { return ~(x ^ C) == (x ^ ~C); }
+
+/*
+ * check-name: simplify-not-xor-cte
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */