aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linearize.c26
-rw-r--r--linearize.h1
-rw-r--r--liveness.c1
-rw-r--r--simplify.c19
4 files changed, 46 insertions, 1 deletions
diff --git a/linearize.c b/linearize.c
index 1ef5fa3..42ff7f4 100644
--- a/linearize.c
+++ b/linearize.c
@@ -211,6 +211,7 @@ static const char* opcodes[] = {
[OP_PHI] = "phi",
[OP_PHISOURCE] = "phisrc",
[OP_CAST] = "cast",
+ [OP_PTRCAST] = "ptrcast",
[OP_CALL] = "call",
[OP_VANEXT] = "va_next",
[OP_VAARG] = "va_arg",
@@ -367,6 +368,7 @@ void show_instruction(struct instruction *insn)
break;
}
case OP_CAST:
+ case OP_PTRCAST:
buf += sprintf(buf, "%s <- (%d) %s", show_pseudo(insn->target), insn->orig_type->bit_size, show_pseudo(insn->src));
break;
case OP_BINARY ... OP_BINARY_END:
@@ -1305,6 +1307,27 @@ static pseudo_t linearize_logical_branch(struct entrypoint *ep, struct expressio
return VOID;
}
+/*
+ * Casts to pointers are "less safe" than other casts, since
+ * they imply type-unsafe accesses. "void *" is a special
+ * case, since you can't access through it anyway without another
+ * cast.
+ */
+static struct instruction *alloc_cast_instruction(struct symbol *ctype)
+{
+ int opcode = OP_CAST;
+ struct symbol *base = ctype;
+
+ if (base->type == SYM_NODE)
+ base = base->ctype.base_type;
+ if (base->type == SYM_PTR) {
+ base = base->ctype.base_type;
+ if (base != &void_ctype)
+ opcode = OP_PTRCAST;
+ }
+ return alloc_typed_instruction(opcode, ctype);
+}
+
pseudo_t linearize_cast(struct entrypoint *ep, struct expression *expr)
{
pseudo_t src, result;
@@ -1315,7 +1338,8 @@ pseudo_t linearize_cast(struct entrypoint *ep, struct expression *expr)
return VOID;
if (expr->ctype->bit_size < 0)
return VOID;
- insn = alloc_typed_instruction(OP_CAST, expr->ctype);
+
+ insn = alloc_cast_instruction(expr->ctype);
result = alloc_pseudo(insn);
insn->target = result;
insn->orig_type = expr->cast_expression->ctype;
diff --git a/linearize.h b/linearize.h
index 0db5a43..c1ba1b8 100644
--- a/linearize.h
+++ b/linearize.h
@@ -151,6 +151,7 @@ enum opcode {
OP_PHI,
OP_PHISOURCE,
OP_CAST,
+ OP_PTRCAST,
OP_CALL,
OP_VANEXT,
OP_VAARG,
diff --git a/liveness.c b/liveness.c
index 8bd7ab7..1f1559c 100644
--- a/liveness.c
+++ b/liveness.c
@@ -147,6 +147,7 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction *
break;
case OP_CAST:
+ case OP_PTRCAST:
USES(src); DEFINES(target);
break;
diff --git a/simplify.c b/simplify.c
index 8a8d450..3dbd511 100644
--- a/simplify.c
+++ b/simplify.c
@@ -454,6 +454,22 @@ offset:
return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
}
+static int simplify_cast(struct instruction *insn)
+{
+ int orig_size;
+
+ if (dead_insn(insn, &insn->src, NULL))
+ return REPEAT_CSE;
+ if (insn->opcode == OP_PTRCAST)
+ return 0;
+ orig_size = insn->orig_type ? insn->orig_type->bit_size : 0;
+ if (orig_size < 0)
+ orig_size = 0;
+ if (insn->size != orig_size)
+ return 0;
+ return replace_with_pseudo(insn, insn->src);
+}
+
int simplify_instruction(struct instruction *insn)
{
pseudo_t cond;
@@ -476,6 +492,9 @@ int simplify_instruction(struct instruction *insn)
if (dead_insn(insn, NULL, NULL))
return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
break;
+ case OP_PTRCAST:
+ case OP_CAST:
+ return simplify_cast(insn);
case OP_PHI:
if (dead_insn(insn, NULL, NULL)) {
clear_phi(insn);