diff options
-rw-r--r-- | linearize.c | 26 | ||||
-rw-r--r-- | linearize.h | 1 | ||||
-rw-r--r-- | liveness.c | 1 | ||||
-rw-r--r-- | simplify.c | 19 |
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, @@ -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; @@ -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); |