diff options
| -rw-r--r-- | evaluate.c | 86 | ||||
| -rw-r--r-- | expand.c | 3 | ||||
| -rw-r--r-- | expression.h | 6 | ||||
| -rw-r--r-- | inline.c | 7 | ||||
| -rw-r--r-- | linearize.c | 22 | ||||
| -rw-r--r-- | linearize.h | 5 | ||||
| -rw-r--r-- | show-parse.c | 10 |
7 files changed, 129 insertions, 10 deletions
@@ -1063,11 +1063,57 @@ static struct symbol *degenerate(struct expression *expr) base = ctype->ctype.base_type; /* * Arrays degenerate into pointers to the entries, while - * functions degenerate into pointers to themselves + * functions degenerate into pointers to themselves. + * If array was part of non-lvalue compound, we create a copy + * of that compound first and then act as if we were dealing with + * the corresponding field in there. */ switch (base->type) { - case SYM_FN: case SYM_ARRAY: + if (expr->type == EXPR_SLICE) { + struct symbol *a = alloc_symbol(expr->pos, SYM_NODE); + struct expression *e0, *e1, *e2, *e3, *e4; + + a->ctype.base_type = expr->base->ctype; + a->bit_size = expr->base->ctype->bit_size; + a->array_size = expr->base->ctype->array_size; + + e0 = alloc_expression(expr->pos, EXPR_SYMBOL); + e0->symbol = a; + e0->ctype = &lazy_ptr_ctype; + + e1 = alloc_expression(expr->pos, EXPR_PREOP); + e1->unop = e0; + e1->op = '*'; + e1->ctype = expr->base->ctype; /* XXX */ + + e2 = alloc_expression(expr->pos, EXPR_ASSIGNMENT); + e2->left = e1; + e2->right = expr->base; + e2->op = '='; + e2->ctype = expr->base->ctype; + + if (expr->r_bitpos) { + e3 = alloc_expression(expr->pos, EXPR_BINOP); + e3->op = '+'; + e3->left = e0; + e3->right = alloc_const_expression(expr->pos, + expr->r_bitpos >> 3); + e3->ctype = &lazy_ptr_ctype; + } else { + e3 = e0; + } + + e4 = alloc_expression(expr->pos, EXPR_COMMA); + e4->left = e2; + e4->right = e3; + e4->ctype = &lazy_ptr_ctype; + + expr->unop = e4; + expr->type = EXPR_PREOP; + expr->op = '*'; + } + case SYM_FN: if (expr->op != '*' || expr->type != EXPR_PREOP) { warn(expr->pos, "strange non-value function or array"); return NULL; @@ -1338,12 +1384,6 @@ static struct symbol *evaluate_member_dereference(struct expression *expr) address_space |= ctype->ctype.as; mod |= ctype->ctype.modifiers; } - if (!lvalue_expression(deref)) { - warn(deref->pos, "expected lvalue for member dereference"); - return NULL; - } - deref = deref->unop; - expr->deref = deref; if (!ctype || (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION)) { warn(expr->pos, "expected structure or union"); return NULL; @@ -1368,9 +1408,32 @@ static struct symbol *evaluate_member_dereference(struct expression *expr) * the "parent" type. */ member = convert_to_as_mod(member, address_space, mod); - add = evaluate_offset(deref, offset); - ctype = member->ctype.base_type; + + if (!lvalue_expression(deref)) { + if (deref->type != EXPR_SLICE) { + expr->base = deref; + expr->r_bitpos = 0; + } else { + expr->base = deref->base; + expr->r_bitpos = deref->r_bitpos; + } + expr->r_bitpos += offset << 3; + expr->type = EXPR_SLICE; + if (ctype->type == SYM_BITFIELD) { + expr->r_bitpos += member->bit_offset; + expr->r_nrbits = member->fieldwidth; + } else { + expr->r_nrbits = member->bit_size; + } + expr->ctype = member; + return member; + } + + deref = deref->unop; + expr->deref = deref; + + add = evaluate_offset(deref, offset); if (ctype->type == SYM_BITFIELD) { expr->type = EXPR_BITFIELD; expr->bitpos = member->bit_offset; @@ -1886,6 +1949,9 @@ struct symbol *evaluate_expression(struct expression *expr) case EXPR_POS: warn(expr->pos, "internal front-end error: initializer in expression"); return NULL; + case EXPR_SLICE: + warn(expr->pos, "internal front-end error: SLICE re-evaluated"); + return NULL; } return NULL; } @@ -754,6 +754,9 @@ static int expand_expression(struct expression *expr) case EXPR_INDEX: return UNSAFE; + case EXPR_SLICE: + return expand_expression(expr->base) + 1; + case EXPR_POS: return expand_expression(expr->init_expr); diff --git a/expression.h b/expression.h index d03cdc35..4c10db8e 100644 --- a/expression.h +++ b/expression.h @@ -40,6 +40,7 @@ enum expression_type { EXPR_INDEX, // index in initializer EXPR_POS, // position in initializer EXPR_FVALUE, + EXPR_SLICE, }; struct expression { @@ -78,6 +79,11 @@ struct expression { struct expression *deref; struct ident *member; }; + // EXPR_SLICE + struct /* slice */ { + struct expression *base; + unsigned r_bitpos, r_nrbits; + }; // EXPR_CAST and EXPR_SIZEOF struct /* cast_arg */ { struct symbol *cast_type; @@ -91,6 +91,13 @@ static struct expression * copy_expression(struct expression *expr) break; } + case EXPR_SLICE: { + struct expression *base = copy_expression(expr->base); + expr = dup_expression(expr); + expr->base = base; + break; + } + /* Binops: copy left/right expressions */ case EXPR_BINOP: case EXPR_COMMA: diff --git a/linearize.c b/linearize.c index b8c2dbce..22e3fbe7 100644 --- a/linearize.c +++ b/linearize.c @@ -190,6 +190,12 @@ static void show_instruction(struct instruction *insn) break; } + case OP_SLICE: + printf("\t%%r%d <- slice %%r%d, %d, %d\n", + insn->target->nr, + insn->base->nr, insn->from, insn->len); + break; + case OP_BINCMP ... OP_BINCMP_END: { static const char *opname[] = { [OP_SET_EQ - OP_BINCMP] = "seteq", @@ -477,6 +483,19 @@ static pseudo_t add_uniop(struct entrypoint *ep, struct expression *expr, int op return new; } +static pseudo_t linearize_slice(struct entrypoint *ep, struct expression *expr) +{ + pseudo_t pre = linearize_expression(ep, expr->base); + pseudo_t new = alloc_pseudo(); + struct instruction *insn = alloc_instruction(OP_SLICE, expr->ctype); + insn->target = new; + insn->base = pre; + insn->from = expr->r_bitpos; + insn->len = expr->r_nrbits; + add_one_insn(ep, expr->pos, insn); + return new; +} + static pseudo_t linearize_regular_preop(struct entrypoint *ep, struct expression *expr) { pseudo_t pre = linearize_expression(ep, expr->unop); @@ -803,6 +822,9 @@ pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr) case EXPR_BITFIELD: return linearize_access(ep, expr); + case EXPR_SLICE: + return linearize_slice(ep, expr); + default: warn(expr->pos, "unknown expression (%d %d)", expr->type, expr->op); return VOID; diff --git a/linearize.h b/linearize.h index ada834ad..003cf7f7 100644 --- a/linearize.h +++ b/linearize.h @@ -51,6 +51,10 @@ struct instruction { struct /* binops */ { pseudo_t src1, src2; }; + struct /* slice */ { + pseudo_t base; + unsigned from, len; + }; struct /* multijump */ { int begin, end; }; @@ -131,6 +135,7 @@ enum opcode { OP_CALL, OP_VANEXT, OP_VAARG, + OP_SLICE, }; struct basic_block_list; diff --git a/show-parse.c b/show-parse.c index ab49d517..5161c78a 100644 --- a/show-parse.c +++ b/show-parse.c @@ -632,6 +632,14 @@ static int show_binop(struct expression *expr) return new; } +static int show_slice(struct expression *expr) +{ + int target = show_expression(expr->base); + int new = new_pseudo(); + printf("\tslice.%d\t\tv%d,v%d,%d\n", expr->r_nrbits, target, new, expr->r_bitpos); + return new; +} + static int show_regular_preop(struct expression *expr) { int target = show_expression(expr->unop); @@ -993,6 +1001,8 @@ int show_expression(struct expression *expr) return show_statement_expr(expr); case EXPR_LABEL: return show_label_expr(expr); + case EXPR_SLICE: + return show_slice(expr); // None of these should exist as direct expressions: they are only // valid as sub-expressions of initializers. |
