diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2017-08-14 06:21:08 +0200 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-06-23 07:46:40 +0200 |
| commit | d0694a238744b642714e7cd226193dd1365176d0 (patch) | |
| tree | 7983d57729f63b9c6d561d8404ebb9fc8777ddf3 | |
| parent | 295c51a487f524a83590dc1bc80a275851ffd2fd (diff) | |
| download | sparse-dev-d0694a238744b642714e7cd226193dd1365176d0.tar.gz | |
cast: prepare finer grained cast instructions
As a first step, add a small function which classify values into
'machine type:
- signed integer
- unsigned integer
- pointer
- floats
and use this to select the appropriate instruction.
Note: this is a preparatory patch and should not yet introduce
any changes in the generated IR.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
| -rw-r--r-- | linearize.c | 78 |
1 files changed, 63 insertions, 15 deletions
diff --git a/linearize.c b/linearize.c index faec8c9d..a69b8f71 100644 --- a/linearize.c +++ b/linearize.c @@ -1155,28 +1155,75 @@ static pseudo_t linearize_postop(struct entrypoint *ep, struct expression *expr) * case, since you can't access through it anyway without another * cast. */ -static struct instruction *alloc_cast_instruction(struct symbol *src, struct symbol *ctype) +enum mtype { + MTYPE_UINT, + MTYPE_SINT, + MTYPE_PTR, + MTYPE_FLOAT, + MTYPE_BAD, +}; + +static enum mtype get_mtype(struct symbol *s) +{ + int sign = (s->ctype.modifiers & MOD_SIGNED) ? 1 : 0; + +retry: switch (s->type) { + case SYM_NODE: + s = s->ctype.base_type; + goto retry; + case SYM_PTR: + if (s->ctype.base_type == &void_ctype) + // handle void pointer like an uint + goto case_int; + return MTYPE_PTR; + case SYM_BITFIELD: + case SYM_RESTRICT: + case SYM_FOULED: + case SYM_ENUM: + s = s->ctype.base_type; + /* fall-through */ + case_int: + return sign ? MTYPE_SINT : MTYPE_UINT; + case SYM_BASETYPE: + if (s->ctype.base_type == &fp_type) + return MTYPE_FLOAT; + if (s->ctype.base_type == &int_type) + goto case_int; + /* fall-through */ + default: + return MTYPE_BAD; + } +} + +static int get_cast_opcode(struct symbol *dst, struct symbol *src) { - int opcode = OP_CAST; - struct symbol *base = ctype; + enum mtype stype = get_mtype(src); + enum mtype dtype = get_mtype(dst); - if (src->ctype.modifiers & MOD_SIGNED) - opcode = OP_SCAST; - 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; - } else if (base->ctype.base_type == &fp_type) - opcode = OP_FPCAST; - return alloc_typed_instruction(opcode, ctype); + switch (dtype) { + case MTYPE_FLOAT: + return OP_FPCAST; + case MTYPE_PTR: + return OP_PTRCAST; + case MTYPE_UINT: + case MTYPE_SINT: + switch (stype) { + case MTYPE_SINT: + return OP_SCAST; + default: + break; + } + /* fall through */ + default: + return OP_CAST; + } } static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol *from, struct symbol *to) { pseudo_t result; struct instruction *insn; + int opcode; if (src == VOID) return VOID; @@ -1184,7 +1231,8 @@ static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol * return VOID; if (from->bit_size < 0 || to->bit_size < 0) return VOID; - insn = alloc_cast_instruction(from, to); + opcode = get_cast_opcode(to, from); + insn = alloc_typed_instruction(opcode, to); result = alloc_pseudo(insn); insn->target = result; insn->orig_type = from; |
