Print this page
11972 resync smatch


 176                         struct storage *op1;
 177                         struct storage *op2;
 178                 };
 179 
 180                 /* stuff for C strings */
 181                 struct {
 182                         struct string *string;
 183                         int label;
 184                 };
 185         };
 186 };
 187 
 188 
 189 static struct function *current_func = NULL;
 190 static struct textbuf *unit_post_text = NULL;
 191 static const char *current_section;
 192 
 193 static void emit_comment(const char * fmt, ...) FORMAT_ATTR(1);
 194 static void emit_move(struct storage *src, struct storage *dest,
 195                       struct symbol *ctype, const char *comment);
 196 static int type_is_signed(struct symbol *sym);
 197 static struct storage *x86_address_gen(struct expression *expr);
 198 static struct storage *x86_symbol_expr(struct symbol *sym);
 199 static void x86_symbol(struct symbol *sym);
 200 static struct storage *x86_statement(struct statement *stmt);
 201 static struct storage *x86_expression(struct expression *expr);
 202 
 203 enum registers {
 204         NOREG,
 205          AL,  DL,  CL,  BL,  AH,  DH,  CH,  BH, // 8-bit
 206          AX,  DX,  CX,  BX,  SI,  DI,  BP,  SP, // 16-bit
 207         EAX, EDX, ECX, EBX, ESI, EDI, EBP, ESP, // 32-bit
 208         EAX_EDX, ECX_EBX, ESI_EDI,              // 64-bit
 209 };
 210 
 211 /* This works on regno's, reg_info's and hardreg_storage's */
 212 #define byte_reg(reg) ((reg) - 16)
 213 #define highbyte_reg(reg) ((reg)-12)
 214 #define word_reg(reg) ((reg)-8)
 215 
 216 #define REGINFO(nr, str, conflicts...)  [nr] = { .name = str, .aliases = { nr , conflicts } }


 435 }
 436 
 437 static const char *stor_op_name(struct storage *s)
 438 {
 439         static char name[32];
 440 
 441         switch (s->type) {
 442         case STOR_PSEUDO:
 443                 strcpy(name, pretty_offset((int) pseudo_offset(s)));
 444                 break;
 445         case STOR_ARG:
 446                 strcpy(name, pretty_offset((int) arg_offset(s)));
 447                 break;
 448         case STOR_SYM:
 449                 strcpy(name, show_ident(s->sym->ident));
 450                 break;
 451         case STOR_REG:
 452                 strcpy(name, s->reg->name);
 453                 break;
 454         case STOR_VALUE:
 455                 sprintf(name, "$%Ld", s->value);
 456                 break;
 457         case STOR_LABEL:
 458                 sprintf(name, "%s.L%d", s->flags & STOR_LABEL_VAL ? "$" : "",
 459                         s->label);
 460                 break;
 461         case STOR_LABELSYM:
 462                 sprintf(name, "%s.LS%p", s->flags & STOR_LABEL_VAL ? "$" : "",
 463                         s->labelsym);
 464                 break;
 465         }
 466 
 467         return name;
 468 }
 469 
 470 static struct atom *new_atom(enum atom_type type)
 471 {
 472         struct atom *atom;
 473 
 474         atom = calloc(1, sizeof(*atom));        /* TODO: chunked alloc */
 475         if (!atom)


 920 
 921         assert(expr->type == EXPR_VALUE);
 922 
 923         if (expr->value == 0ULL) {
 924                 printf("\t.zero\t%d\n", bit_size / 8);
 925                 return;
 926         }
 927 
 928         ll = (long long) expr->value;
 929 
 930         switch (bit_size) {
 931         case 8:         type = "byte";  ll = (char) ll; break;
 932         case 16:        type = "value"; ll = (short) ll; break;
 933         case 32:        type = "long";  ll = (int) ll; break;
 934         case 64:        type = "quad";  break;
 935         default:        type = NULL;    break;
 936         }
 937 
 938         assert(type != NULL);
 939 
 940         printf("\t.%s\t%Ld\n", type, ll);
 941 }
 942 
 943 static void emit_global_noinit(const char *name, unsigned long modifiers,
 944                                unsigned long alignment, unsigned int byte_size)
 945 {
 946         char s[64];
 947 
 948         if (modifiers & MOD_STATIC) {
 949                 sprintf(s, "\t.local\t%s\n", name);
 950                 textbuf_push(&unit_post_text, s);
 951         }
 952         if (alignment)
 953                 sprintf(s, "\t.comm\t%s,%d,%lu\n", name, byte_size, alignment);
 954         else
 955                 sprintf(s, "\t.comm\t%s,%d\n", name, byte_size);
 956         textbuf_push(&unit_post_text, s);
 957 }
 958 
 959 static int ea_current, ea_last;
 960 


1146         case 32: c = 'l'; break;
1147         case 64: c = 'q'; break;
1148         default: abort(); break;
1149         }
1150 
1151         sprintf(opbits_str, "%s%c", insn, c);
1152 
1153         return opbits_str;
1154 }
1155 
1156 static void emit_move(struct storage *src, struct storage *dest,
1157                       struct symbol *ctype, const char *comment)
1158 {
1159         unsigned int bits;
1160         unsigned int is_signed;
1161         unsigned int is_dest = (src->type == STOR_REG);
1162         const char *opname;
1163 
1164         if (ctype) {
1165                 bits = ctype->bit_size;
1166                 is_signed = type_is_signed(ctype);
1167         } else {
1168                 bits = 32;
1169                 is_signed = 0;
1170         }
1171 
1172         /*
1173          * Are we moving from a register to a register?
1174          * Make the new reg to be the "cache".
1175          */
1176         if ((dest->type == STOR_REG) && (src->type == STOR_REG)) {
1177                 struct storage *backing;
1178 
1179 reg_reg_move:
1180                 if (dest == src)
1181                         return;
1182 
1183                 backing = src->reg->contains;
1184                 if (backing) {
1185                         /* Is it still valid? */
1186                         if (backing->reg != src->reg)


1338         put_reg(eax_edx);
1339         emit_comment("end DIVIDE");
1340         return new;
1341 }
1342 
1343 static struct storage *emit_binop(struct expression *expr)
1344 {
1345         struct storage *left = x86_expression(expr->left);
1346         struct storage *right = x86_expression(expr->right);
1347         struct storage *new;
1348         struct storage *dest, *src;
1349         const char *opname = NULL;
1350         const char *suffix = NULL;
1351         char opstr[16];
1352         int is_signed;
1353 
1354         /* Divides have special register constraints */
1355         if ((expr->op == '/') || (expr->op == '%'))
1356                 return emit_divide(expr, left, right);
1357 
1358         is_signed = type_is_signed(expr->ctype);
1359 
1360         switch (expr->op) {
1361         case '+':
1362                 opname = "add";
1363                 break;
1364         case '-':
1365                 opname = "sub";
1366                 break;
1367         case '&':
1368                 opname = "and";
1369                 break;
1370         case '|':
1371                 opname = "or";
1372                 break;
1373         case '^':
1374                 opname = "xor";
1375                 break;
1376         case SPECIAL_LEFTSHIFT:
1377                 opname = "shl";
1378                 break;


1538         struct function *f = current_func;
1539         struct expression *expr = stmt->ret_value;
1540         struct storage *val = NULL, *jmplbl;
1541 
1542         if (expr && expr->ctype) {
1543                 val = x86_expression(expr);
1544                 assert(val != NULL);
1545                 emit_move(val, REG_EAX, expr->ctype, "return");
1546         }
1547 
1548         jmplbl = new_storage(STOR_LABEL);
1549         jmplbl->flags |= STOR_WANTS_FREE;
1550         jmplbl->label = f->ret_target;
1551         insn("jmp", jmplbl, NULL, NULL);
1552 
1553         return val;
1554 }
1555 
1556 static struct storage *emit_conditional_expr(struct expression *expr)
1557 {
1558         struct storage *cond, *true = NULL, *false = NULL;
1559         struct storage *new = stack_alloc(expr->ctype->bit_size / 8);
1560         int target_false, cond_end;
1561 
1562         /* evaluate conditional */
1563         cond = x86_expression(expr->conditional);
1564         target_false = emit_conditional_test(cond);
1565 
1566         /* handle if-true part of the expression */
1567         true = x86_expression(expr->cond_true);
1568 
1569         emit_copy(new, true, expr->ctype);
1570 
1571         cond_end = emit_conditional_end(target_false);
1572 
1573         /* handle if-false part of the expression */
1574         false = x86_expression(expr->cond_false);
1575 
1576         emit_copy(new, false, expr->ctype);
1577 
1578         /* end of conditional; jump target for if-true branch */
1579         emit_label(cond_end, "end conditional");
1580 
1581         return new;
1582 }
1583 
1584 static struct storage *emit_select_expr(struct expression *expr)
1585 {
1586         struct storage *cond = x86_expression(expr->conditional);
1587         struct storage *true = x86_expression(expr->cond_true);
1588         struct storage *false = x86_expression(expr->cond_false);
1589         struct storage *reg_cond, *reg_true, *reg_false;
1590         struct storage *new = stack_alloc(4);
1591 
1592         emit_comment("begin SELECT");
1593         reg_cond = get_reg_value(cond, get_regclass(expr->conditional));
1594         reg_true = get_reg_value(true, get_regclass(expr));
1595         reg_false = get_reg_value(false, get_regclass(expr));
1596 
1597         /*
1598          * Do the actual select: check the conditional for zero,
1599          * move false over true if zero
1600          */ 
1601         insn("test", reg_cond, reg_cond, NULL);
1602         insn("cmovz", reg_false, reg_true, NULL);
1603 
1604         /* Store it back */
1605         emit_move(reg_true, new, expr->ctype, NULL);
1606         put_reg(reg_cond);
1607         put_reg(reg_true);
1608         put_reg(reg_false);
1609         emit_comment("end SELECT");
1610         return new;
1611 }
1612 
1613 static struct storage *emit_symbol_expr_init(struct symbol *sym)
1614 {
1615         struct expression *expr = sym->initializer;


2219          * '*' is an lvalue access, and is fundamentally different
2220          * from an arithmetic operation. Maybe it should have an
2221          * expression type of its own..
2222          */
2223         if (expr->op == '*')
2224                 return x86_access(expr);
2225         if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
2226                 return emit_inc_dec(expr, 0);
2227         return emit_regular_preop(expr);
2228 }
2229 
2230 static struct storage *x86_symbol_expr(struct symbol *sym)
2231 {
2232         struct storage *new = stack_alloc(4);
2233 
2234         if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
2235                 printf("\tmovi.%d\t\tv%d,$%s\n", bits_in_pointer, new->pseudo, show_ident(sym->ident));
2236                 return new;
2237         }
2238         if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
2239                 printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, sym->value);
2240                 return new;
2241         }
2242         printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym);
2243         return new;
2244 }
2245 
2246 static void x86_symbol_init(struct symbol *sym)
2247 {
2248         struct symbol_private *priv = sym->aux;
2249         struct expression *expr = sym->initializer;
2250         struct storage *new;
2251 
2252         if (expr)
2253                 new = x86_expression(expr);
2254         else
2255                 new = stack_alloc(sym->bit_size / 8);
2256 
2257         if (!priv) {
2258                 priv = calloc(1, sizeof(*priv));
2259                 sym->aux = priv;
2260                 /* FIXME: leak! we don't free... */
2261                 /* (well, we don't free symbols either) */
2262         }
2263 
2264         priv->addr = new;
2265 }
2266 
2267 static int type_is_signed(struct symbol *sym)
2268 {
2269         if (sym->type == SYM_NODE)
2270                 sym = sym->ctype.base_type;
2271         if (sym->type == SYM_PTR)
2272                 return 0;
2273         return !(sym->ctype.modifiers & MOD_UNSIGNED);
2274 }
2275 
2276 static struct storage *x86_label_expr(struct expression *expr)
2277 {
2278         struct storage *new = stack_alloc(4);
2279         printf("\tmovi.%d\t\tv%d,.L%p\n", bits_in_pointer, new->pseudo, expr->label_symbol);
2280         return new;
2281 }
2282 
2283 static struct storage *x86_statement_expr(struct expression *expr)
2284 {
2285         return x86_statement(expr->statement);
2286 }
2287 
2288 static int x86_position_expr(struct expression *expr, struct symbol *base)
2289 {
2290         struct storage *new = x86_expression(expr->init_expr);
2291         struct symbol *ctype = expr->init_expr->ctype;
2292 
2293         printf("\tinsert v%d at [%d:%d] of %s\n", new->pseudo,
2294                 expr->init_offset, ctype->bit_offset,
2295                 show_ident(base->ident));




 176                         struct storage *op1;
 177                         struct storage *op2;
 178                 };
 179 
 180                 /* stuff for C strings */
 181                 struct {
 182                         struct string *string;
 183                         int label;
 184                 };
 185         };
 186 };
 187 
 188 
 189 static struct function *current_func = NULL;
 190 static struct textbuf *unit_post_text = NULL;
 191 static const char *current_section;
 192 
 193 static void emit_comment(const char * fmt, ...) FORMAT_ATTR(1);
 194 static void emit_move(struct storage *src, struct storage *dest,
 195                       struct symbol *ctype, const char *comment);

 196 static struct storage *x86_address_gen(struct expression *expr);
 197 static struct storage *x86_symbol_expr(struct symbol *sym);
 198 static void x86_symbol(struct symbol *sym);
 199 static struct storage *x86_statement(struct statement *stmt);
 200 static struct storage *x86_expression(struct expression *expr);
 201 
 202 enum registers {
 203         NOREG,
 204          AL,  DL,  CL,  BL,  AH,  DH,  CH,  BH, // 8-bit
 205          AX,  DX,  CX,  BX,  SI,  DI,  BP,  SP, // 16-bit
 206         EAX, EDX, ECX, EBX, ESI, EDI, EBP, ESP, // 32-bit
 207         EAX_EDX, ECX_EBX, ESI_EDI,              // 64-bit
 208 };
 209 
 210 /* This works on regno's, reg_info's and hardreg_storage's */
 211 #define byte_reg(reg) ((reg) - 16)
 212 #define highbyte_reg(reg) ((reg)-12)
 213 #define word_reg(reg) ((reg)-8)
 214 
 215 #define REGINFO(nr, str, conflicts...)  [nr] = { .name = str, .aliases = { nr , conflicts } }


 434 }
 435 
 436 static const char *stor_op_name(struct storage *s)
 437 {
 438         static char name[32];
 439 
 440         switch (s->type) {
 441         case STOR_PSEUDO:
 442                 strcpy(name, pretty_offset((int) pseudo_offset(s)));
 443                 break;
 444         case STOR_ARG:
 445                 strcpy(name, pretty_offset((int) arg_offset(s)));
 446                 break;
 447         case STOR_SYM:
 448                 strcpy(name, show_ident(s->sym->ident));
 449                 break;
 450         case STOR_REG:
 451                 strcpy(name, s->reg->name);
 452                 break;
 453         case STOR_VALUE:
 454                 sprintf(name, "$%lld", s->value);
 455                 break;
 456         case STOR_LABEL:
 457                 sprintf(name, "%s.L%d", s->flags & STOR_LABEL_VAL ? "$" : "",
 458                         s->label);
 459                 break;
 460         case STOR_LABELSYM:
 461                 sprintf(name, "%s.LS%p", s->flags & STOR_LABEL_VAL ? "$" : "",
 462                         s->labelsym);
 463                 break;
 464         }
 465 
 466         return name;
 467 }
 468 
 469 static struct atom *new_atom(enum atom_type type)
 470 {
 471         struct atom *atom;
 472 
 473         atom = calloc(1, sizeof(*atom));        /* TODO: chunked alloc */
 474         if (!atom)


 919 
 920         assert(expr->type == EXPR_VALUE);
 921 
 922         if (expr->value == 0ULL) {
 923                 printf("\t.zero\t%d\n", bit_size / 8);
 924                 return;
 925         }
 926 
 927         ll = (long long) expr->value;
 928 
 929         switch (bit_size) {
 930         case 8:         type = "byte";  ll = (char) ll; break;
 931         case 16:        type = "value"; ll = (short) ll; break;
 932         case 32:        type = "long";  ll = (int) ll; break;
 933         case 64:        type = "quad";  break;
 934         default:        type = NULL;    break;
 935         }
 936 
 937         assert(type != NULL);
 938 
 939         printf("\t.%s\t%lld\n", type, ll);
 940 }
 941 
 942 static void emit_global_noinit(const char *name, unsigned long modifiers,
 943                                unsigned long alignment, unsigned int byte_size)
 944 {
 945         char s[64];
 946 
 947         if (modifiers & MOD_STATIC) {
 948                 sprintf(s, "\t.local\t%s\n", name);
 949                 textbuf_push(&unit_post_text, s);
 950         }
 951         if (alignment)
 952                 sprintf(s, "\t.comm\t%s,%d,%lu\n", name, byte_size, alignment);
 953         else
 954                 sprintf(s, "\t.comm\t%s,%d\n", name, byte_size);
 955         textbuf_push(&unit_post_text, s);
 956 }
 957 
 958 static int ea_current, ea_last;
 959 


1145         case 32: c = 'l'; break;
1146         case 64: c = 'q'; break;
1147         default: abort(); break;
1148         }
1149 
1150         sprintf(opbits_str, "%s%c", insn, c);
1151 
1152         return opbits_str;
1153 }
1154 
1155 static void emit_move(struct storage *src, struct storage *dest,
1156                       struct symbol *ctype, const char *comment)
1157 {
1158         unsigned int bits;
1159         unsigned int is_signed;
1160         unsigned int is_dest = (src->type == STOR_REG);
1161         const char *opname;
1162 
1163         if (ctype) {
1164                 bits = ctype->bit_size;
1165                 is_signed = is_signed_type(ctype);
1166         } else {
1167                 bits = 32;
1168                 is_signed = 0;
1169         }
1170 
1171         /*
1172          * Are we moving from a register to a register?
1173          * Make the new reg to be the "cache".
1174          */
1175         if ((dest->type == STOR_REG) && (src->type == STOR_REG)) {
1176                 struct storage *backing;
1177 
1178 reg_reg_move:
1179                 if (dest == src)
1180                         return;
1181 
1182                 backing = src->reg->contains;
1183                 if (backing) {
1184                         /* Is it still valid? */
1185                         if (backing->reg != src->reg)


1337         put_reg(eax_edx);
1338         emit_comment("end DIVIDE");
1339         return new;
1340 }
1341 
1342 static struct storage *emit_binop(struct expression *expr)
1343 {
1344         struct storage *left = x86_expression(expr->left);
1345         struct storage *right = x86_expression(expr->right);
1346         struct storage *new;
1347         struct storage *dest, *src;
1348         const char *opname = NULL;
1349         const char *suffix = NULL;
1350         char opstr[16];
1351         int is_signed;
1352 
1353         /* Divides have special register constraints */
1354         if ((expr->op == '/') || (expr->op == '%'))
1355                 return emit_divide(expr, left, right);
1356 
1357         is_signed = is_signed_type(expr->ctype);
1358 
1359         switch (expr->op) {
1360         case '+':
1361                 opname = "add";
1362                 break;
1363         case '-':
1364                 opname = "sub";
1365                 break;
1366         case '&':
1367                 opname = "and";
1368                 break;
1369         case '|':
1370                 opname = "or";
1371                 break;
1372         case '^':
1373                 opname = "xor";
1374                 break;
1375         case SPECIAL_LEFTSHIFT:
1376                 opname = "shl";
1377                 break;


1537         struct function *f = current_func;
1538         struct expression *expr = stmt->ret_value;
1539         struct storage *val = NULL, *jmplbl;
1540 
1541         if (expr && expr->ctype) {
1542                 val = x86_expression(expr);
1543                 assert(val != NULL);
1544                 emit_move(val, REG_EAX, expr->ctype, "return");
1545         }
1546 
1547         jmplbl = new_storage(STOR_LABEL);
1548         jmplbl->flags |= STOR_WANTS_FREE;
1549         jmplbl->label = f->ret_target;
1550         insn("jmp", jmplbl, NULL, NULL);
1551 
1552         return val;
1553 }
1554 
1555 static struct storage *emit_conditional_expr(struct expression *expr)
1556 {
1557         struct storage *cond, *stot = NULL, *stof = NULL;
1558         struct storage *new = stack_alloc(expr->ctype->bit_size / 8);
1559         int target_false, cond_end;
1560 
1561         /* evaluate conditional */
1562         cond = x86_expression(expr->conditional);
1563         target_false = emit_conditional_test(cond);
1564 
1565         /* handle if-true part of the expression */
1566         stot = x86_expression(expr->cond_true);
1567 
1568         emit_copy(new, stot, expr->ctype);
1569 
1570         cond_end = emit_conditional_end(target_false);
1571 
1572         /* handle if-false part of the expression */
1573         stof = x86_expression(expr->cond_false);
1574 
1575         emit_copy(new, stof, expr->ctype);
1576 
1577         /* end of conditional; jump target for if-true branch */
1578         emit_label(cond_end, "end conditional");
1579 
1580         return new;
1581 }
1582 
1583 static struct storage *emit_select_expr(struct expression *expr)
1584 {
1585         struct storage *cond = x86_expression(expr->conditional);
1586         struct storage *stot = x86_expression(expr->cond_true);
1587         struct storage *stof = x86_expression(expr->cond_false);
1588         struct storage *reg_cond, *reg_true, *reg_false;
1589         struct storage *new = stack_alloc(4);
1590 
1591         emit_comment("begin SELECT");
1592         reg_cond = get_reg_value(cond, get_regclass(expr->conditional));
1593         reg_true = get_reg_value(stot, get_regclass(expr));
1594         reg_false = get_reg_value(stof, get_regclass(expr));
1595 
1596         /*
1597          * Do the actual select: check the conditional for zero,
1598          * move false over true if zero
1599          */ 
1600         insn("test", reg_cond, reg_cond, NULL);
1601         insn("cmovz", reg_false, reg_true, NULL);
1602 
1603         /* Store it back */
1604         emit_move(reg_true, new, expr->ctype, NULL);
1605         put_reg(reg_cond);
1606         put_reg(reg_true);
1607         put_reg(reg_false);
1608         emit_comment("end SELECT");
1609         return new;
1610 }
1611 
1612 static struct storage *emit_symbol_expr_init(struct symbol *sym)
1613 {
1614         struct expression *expr = sym->initializer;


2218          * '*' is an lvalue access, and is fundamentally different
2219          * from an arithmetic operation. Maybe it should have an
2220          * expression type of its own..
2221          */
2222         if (expr->op == '*')
2223                 return x86_access(expr);
2224         if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
2225                 return emit_inc_dec(expr, 0);
2226         return emit_regular_preop(expr);
2227 }
2228 
2229 static struct storage *x86_symbol_expr(struct symbol *sym)
2230 {
2231         struct storage *new = stack_alloc(4);
2232 
2233         if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
2234                 printf("\tmovi.%d\t\tv%d,$%s\n", bits_in_pointer, new->pseudo, show_ident(sym->ident));
2235                 return new;
2236         }
2237         if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
2238                 printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, 0LL);
2239                 return new;
2240         }
2241         printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym);
2242         return new;
2243 }
2244 
2245 static void x86_symbol_init(struct symbol *sym)
2246 {
2247         struct symbol_private *priv = sym->aux;
2248         struct expression *expr = sym->initializer;
2249         struct storage *new;
2250 
2251         if (expr)
2252                 new = x86_expression(expr);
2253         else
2254                 new = stack_alloc(sym->bit_size / 8);
2255 
2256         if (!priv) {
2257                 priv = calloc(1, sizeof(*priv));
2258                 sym->aux = priv;
2259                 /* FIXME: leak! we don't free... */
2260                 /* (well, we don't free symbols either) */
2261         }
2262 
2263         priv->addr = new;
2264 }
2265 









2266 static struct storage *x86_label_expr(struct expression *expr)
2267 {
2268         struct storage *new = stack_alloc(4);
2269         printf("\tmovi.%d\t\tv%d,.L%p\n", bits_in_pointer, new->pseudo, expr->label_symbol);
2270         return new;
2271 }
2272 
2273 static struct storage *x86_statement_expr(struct expression *expr)
2274 {
2275         return x86_statement(expr->statement);
2276 }
2277 
2278 static int x86_position_expr(struct expression *expr, struct symbol *base)
2279 {
2280         struct storage *new = x86_expression(expr->init_expr);
2281         struct symbol *ctype = expr->init_expr->ctype;
2282 
2283         printf("\tinsert v%d at [%d:%d] of %s\n", new->pseudo,
2284                 expr->init_offset, ctype->bit_offset,
2285                 show_ident(base->ident));