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));
|