code.c (14264B)
1 static char sccsid[] = "@(#) ./cc2/arch/qbe/code.c"; 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #include <cstd.h> 8 #include "arch.h" 9 #include "../../../inc/scc.h" 10 #include "../../cc2.h" 11 12 #define ADDR_LEN (INTIDENTSIZ+64) 13 14 static void binary(void), unary(void), store(void), jmp(void), ret(void), 15 branch(void), call(void), ecall(void), param(void), 16 asalloc(void), form2local(void), ldir(void), vastart(void), 17 vaarg(void); 18 19 static struct opdata { 20 void (*fun)(void); 21 char *txt; 22 char letter; 23 } optbl [] = { 24 [ASLDSB] = {.fun = unary, .txt = "loadsb", .letter = 'w'}, 25 [ASLDUB] = {.fun = unary, .txt = "loadub", .letter = 'w'}, 26 [ASLDSH] = {.fun = unary, .txt = "loadsh", .letter = 'w'}, 27 [ASLDUH] = {.fun = unary, .txt = "loaduh", .letter = 'w'}, 28 [ASLDSW] = {.fun = unary, .txt = "loadsw", .letter = 'w'}, 29 [ASLDUW] = {.fun = unary, .txt = "loaduw", .letter = 'w'}, 30 [ASLDL] = {.fun = unary, .txt = "loadl", .letter = 'l'}, 31 [ASLDS] = {.fun = unary, .txt = "loads", .letter = 's'}, 32 [ASLDD] = {.fun = unary, .txt = "loadd", .letter = 'd'}, 33 34 [ASCOPYB] = {.fun = unary, .txt = "copy", .letter = 'b'}, 35 [ASCOPYH] = {.fun = unary, .txt = "copy", .letter = 'h'}, 36 [ASCOPYW] = {.fun = unary, .txt = "copy", .letter = 'w'}, 37 [ASCOPYL] = {.fun = unary, .txt = "copy", .letter = 'l'}, 38 [ASCOPYS] = {.fun = unary, .txt = "copy", .letter = 's'}, 39 [ASCOPYD] = {.fun = unary, .txt = "copy", .letter = 'd'}, 40 41 [ASSTB] = {.fun = store, .txt = "store", .letter = 'b'}, 42 [ASSTH] = {.fun = store, .txt = "store", .letter = 'h'}, 43 [ASSTW] = {.fun = store, .txt = "store", .letter = 'w'}, 44 [ASSTL] = {.fun = store, .txt = "store", .letter = 'l'}, 45 [ASSTM] = {.fun = ldir}, 46 [ASSTS] = {.fun = store, .txt = "store", .letter = 's'}, 47 [ASSTD] = {.fun = store, .txt = "store", .letter = 'd'}, 48 49 [ASADDW] = {.fun = binary, .txt = "add", .letter = 'w'}, 50 [ASSUBW] = {.fun = binary, .txt = "sub", .letter = 'w'}, 51 [ASMULW] = {.fun = binary, .txt = "mul", .letter = 'w'}, 52 [ASMODW] = {.fun = binary, .txt = "rem", .letter = 'w'}, 53 [ASUMODW] = {.fun = binary, .txt = "urem", .letter = 'w'}, 54 [ASDIVW] = {.fun = binary, .txt = "div", .letter = 'w'}, 55 [ASUDIVW] = {.fun = binary, .txt = "udiv", .letter = 'w'}, 56 [ASSHLW] = {.fun = binary, .txt = "shl", .letter = 'w'}, 57 [ASSHRW] = {.fun = binary, .txt = "sar", .letter = 'w'}, 58 [ASUSHRW] = {.fun = binary, .txt = "shr", .letter = 'w'}, 59 [ASLTW] = {.fun = binary, .txt = "csltw", .letter = 'w'}, 60 [ASULTW] = {.fun = binary, .txt = "cultw", .letter = 'w'}, 61 [ASGTW] = {.fun = binary, .txt = "csgtw", .letter = 'w'}, 62 [ASUGTW] = {.fun = binary, .txt = "cugtw", .letter = 'w'}, 63 [ASLEW] = {.fun = binary, .txt = "cslew", .letter = 'w'}, 64 [ASULEW] = {.fun = binary, .txt = "culew", .letter = 'w'}, 65 [ASGEW] = {.fun = binary, .txt = "csgew", .letter = 'w'}, 66 [ASUGEW] = {.fun = binary, .txt = "cugew", .letter = 'w'}, 67 [ASEQW] = {.fun = binary, .txt = "ceqw", .letter = 'w'}, 68 [ASNEW] = {.fun = binary, .txt = "cnew", .letter = 'w'}, 69 [ASBANDW] = {.fun = binary, .txt = "and", .letter = 'w'}, 70 [ASBORW] = {.fun = binary, .txt = "or", .letter = 'w'}, 71 [ASBXORW] = {.fun = binary, .txt = "xor", .letter = 'w'}, 72 73 [ASADDL] = {.fun = binary, .txt = "add", .letter = 'l'}, 74 [ASSUBL] = {.fun = binary, .txt = "sub", .letter = 'l'}, 75 [ASMULL] = {.fun = binary, .txt = "mul", .letter = 'l'}, 76 [ASMODL] = {.fun = binary, .txt = "rem", .letter = 'l'}, 77 [ASUMODL] = {.fun = binary, .txt = "urem", .letter = 'l'}, 78 [ASDIVL] = {.fun = binary, .txt = "div", .letter = 'l'}, 79 [ASUDIVL] = {.fun = binary, .txt = "udiv", .letter = 'l'}, 80 [ASSHLL] = {.fun = binary, .txt = "shl", .letter = 'l'}, 81 [ASSHRL] = {.fun = binary, .txt = "sar", .letter = 'l'}, 82 [ASUSHRL] = {.fun = binary, .txt = "shr", .letter = 'l'}, 83 [ASLTL] = {.fun = binary, .txt = "csltl", .letter = 'w'}, 84 [ASULTL] = {.fun = binary, .txt = "cultl", .letter = 'w'}, 85 [ASGTL] = {.fun = binary, .txt = "csgtl", .letter = 'w'}, 86 [ASUGTL] = {.fun = binary, .txt = "cugtl", .letter = 'w'}, 87 [ASLEL] = {.fun = binary, .txt = "cslel", .letter = 'w'}, 88 [ASULEL] = {.fun = binary, .txt = "culel", .letter = 'w'}, 89 [ASGEL] = {.fun = binary, .txt = "csgel", .letter = 'w'}, 90 [ASUGEL] = {.fun = binary, .txt = "cugel", .letter = 'w'}, 91 [ASEQL] = {.fun = binary, .txt = "ceql", .letter = 'w'}, 92 [ASNEL] = {.fun = binary, .txt = "cnel", .letter = 'w'}, 93 [ASBANDL] = {.fun = binary, .txt = "and", .letter = 'l'}, 94 [ASBORL] = {.fun = binary, .txt = "or", .letter = 'l'}, 95 [ASBXORL] = {.fun = binary, .txt = "xor", .letter = 'l'}, 96 97 [ASADDS] = {.fun = binary, .txt = "add", .letter = 's'}, 98 [ASSUBS] = {.fun = binary, .txt = "sub", .letter = 's'}, 99 [ASMULS] = {.fun = binary, .txt = "mul", .letter = 's'}, 100 [ASDIVS] = {.fun = binary, .txt = "div", .letter = 's'}, 101 [ASLTS] = {.fun = binary, .txt = "clts", .letter = 'w'}, 102 [ASGTS] = {.fun = binary, .txt = "cgts", .letter = 'w'}, 103 [ASLES] = {.fun = binary, .txt = "cles", .letter = 'w'}, 104 [ASGES] = {.fun = binary, .txt = "cges", .letter = 'w'}, 105 [ASEQS] = {.fun = binary, .txt = "ceqs", .letter = 'w'}, 106 [ASNES] = {.fun = binary, .txt = "cnes", .letter = 'w'}, 107 108 [ASADDD] = {.fun = binary, .txt = "add", .letter = 'd'}, 109 [ASSUBD] = {.fun = binary, .txt = "sub", .letter = 'd'}, 110 [ASMULD] = {.fun = binary, .txt = "mul", .letter = 'd'}, 111 [ASDIVD] = {.fun = binary, .txt = "div", .letter = 'd'}, 112 [ASLTD] = {.fun = binary, .txt = "cltd", .letter = 'w'}, 113 [ASGTD] = {.fun = binary, .txt = "cgtd", .letter = 'w'}, 114 [ASLED] = {.fun = binary, .txt = "cled", .letter = 'w'}, 115 [ASGED] = {.fun = binary, .txt = "cged", .letter = 'w'}, 116 [ASEQD] = {.fun = binary, .txt = "ceqd", .letter = 'w'}, 117 [ASNED] = {.fun = binary, .txt = "cned", .letter = 'w'}, 118 119 [ASEXTBW] = {.fun = unary, .txt = "extsb", .letter = 'w'}, 120 [ASUEXTBW]= {.fun = unary, .txt = "extub", .letter = 'w'}, 121 [ASEXTBL] = {.fun = unary, .txt = "extsb", .letter = 'l'}, 122 [ASUEXTBL]= {.fun = unary, .txt = "extub", .letter = 'l'}, 123 [ASEXTHW] = {.fun = unary, .txt = "extsh", .letter = 'w'}, 124 [ASUEXTHW]= {.fun = unary, .txt = "extuh", .letter = 'w'}, 125 [ASEXTWL] = {.fun = unary, .txt = "extsw", .letter = 'l'}, 126 [ASUEXTWL]= {.fun = unary, .txt = "extuw", .letter = 'l'}, 127 128 [ASSTOL] = {.fun = unary, .txt = "stosi", .letter = 'l'}, 129 [ASSTOW] = {.fun = unary, .txt = "stosi", .letter = 'w'}, 130 [ASDTOL] = {.fun = unary, .txt = "dtosi", .letter = 'l'}, 131 [ASDTOW] = {.fun = unary, .txt = "dtosi", .letter = 'w'}, 132 133 [ASSWTOD] = {.fun = unary, .txt = "swtof", .letter = 'd'}, 134 [ASSWTOS] = {.fun = unary, .txt = "swtof", .letter = 's'}, 135 [ASSLTOD] = {.fun = unary, .txt = "sltof", .letter = 'd'}, 136 [ASSLTOS] = {.fun = unary, .txt = "sltof", .letter = 's'}, 137 138 [ASEXTS] = {.fun = unary, .txt = "exts", .letter = 'd'}, 139 [ASTRUNCD] = {.fun = unary, .txt = "truncd", .letter = 's'}, 140 141 [ASBRANCH] = {.fun = branch}, 142 [ASJMP] = {.fun = jmp}, 143 [ASRET] = {.fun = ret}, 144 [ASCALL] = {.fun = call}, 145 [ASCALLE] = {.fun = ecall, .txt = ")"}, 146 [ASCALLEX] = {.fun = ecall, .txt = ", ...)"}, 147 [ASPAR] = {.fun = param, .txt = "%s %s, "}, 148 [ASPARE] = {.fun = param, .txt = "%s %s"}, 149 [ASALLOC] = {.fun = asalloc}, 150 [ASFORM] = {.fun = form2local}, 151 152 [ASVSTAR] = {.fun = vastart}, 153 [ASVARG] = {.fun = vaarg}, 154 }; 155 156 static char buff[ADDR_LEN]; 157 /* 158 * : is for user-defined Aggregate Types 159 * $ is for globals (represented by a pointer) 160 * % is for function-scope temporaries 161 * @ is for block labels 162 */ 163 static char 164 sigil(Symbol *sym) 165 { 166 switch (sym->kind) { 167 case SEXTRN: 168 case SGLOB: 169 case SPRIV: 170 case SLOCAL: 171 return '$'; 172 case SAUTO: 173 case STMP: 174 return '%'; 175 case SLABEL: 176 return '@'; 177 default: 178 abort(); 179 } 180 } 181 182 static char * 183 symname(Symbol *sym) 184 { 185 char c = sigil(sym); 186 187 if (sym->name) { 188 switch (sym->kind) { 189 case SEXTRN: 190 case SGLOB: 191 sprintf(buff, "%c%s", c, sym->name); 192 return buff; 193 case SLOCAL: 194 case SPRIV: 195 case SAUTO: 196 sprintf(buff, "%c%s.%u", c, sym->name, sym->id); 197 return buff; 198 default: 199 abort(); 200 } 201 } 202 sprintf(buff, "%c.%u", c, sym->numid); 203 204 return buff; 205 } 206 207 static void 208 emitconst(Node *np) 209 { 210 switch (np->type.size) { 211 case 1: 212 printf("%d", (int) np->u.i & 0xFF); 213 break; 214 case 2: 215 printf("%d", (int) np->u.i & 0xFFFF); 216 break; 217 case 4: 218 printf("%ld", (long) np->u.i & 0xFFFFFFFF); 219 break; 220 case 8: 221 printf("%lld", (long long) np->u.i); 222 break; 223 default: 224 abort(); 225 } 226 } 227 228 static void 229 emittree(Node *np) 230 { 231 if (!np) 232 return; 233 234 switch (np->op) { 235 case OSTRING: 236 printf("\"%s\"", np->u.s); 237 free(np->u.s); 238 np->u.s = NULL; 239 break; 240 case OCONST: 241 emitconst(np); 242 break; 243 case OADDR: 244 emittree(np->left); 245 break; 246 case OMEM: 247 fputs(symname(np->u.sym), stdout); 248 break; 249 default: 250 emittree(np->left); 251 printf(" %c ", np->op); 252 emittree(np->right); 253 break; 254 } 255 } 256 257 static char * 258 size2asm(Type *tp) 259 { 260 if (tp->flags & STRF) { 261 return "b"; 262 } else if (tp->flags & INTF) { 263 switch (tp->size) { 264 case 1: 265 return "b"; 266 case 2: 267 return "h"; 268 case 4: 269 return "w"; 270 case 8: 271 return "l"; 272 } 273 } else if (tp->flags & FLOATF) { 274 if (tp->size == 4) 275 return "s"; 276 else if (tp->size == 8) 277 return "d"; 278 } 279 abort(); 280 } 281 282 void 283 defglobal(Symbol *sym) 284 { 285 if (sym->kind == SEXTRN) 286 return; 287 if (sym->kind == SGLOB) 288 fputs("export ", stdout); 289 printf("data %s = {\n", symname(sym)); 290 if (sym->type.flags & INITF) 291 return; 292 printf("\tz\t%lu\n}\n", sym->type.size); 293 } 294 295 void 296 defpar(Symbol *sym) 297 { 298 sym->type.flags |= PARF; 299 } 300 301 void 302 defvar(Symbol *sym) 303 { 304 if (sym->kind == SREG) 305 sym->kind = SAUTO; 306 } 307 308 void 309 data(Node *np) 310 { 311 printf("\t%s\t", size2asm(&np->type)); 312 emittree(np); 313 putchar(','); 314 putchar('\n'); 315 } 316 317 static char * 318 size2stack(Type *tp) 319 { 320 if (tp->flags & INTF) { 321 switch (tp->size) { 322 case 1: 323 case 2: 324 case 4: 325 return "w"; 326 case 8: 327 return "l"; 328 } 329 } else if (tp->flags & FLOATF) { 330 if (tp->size == 4) 331 return "s"; 332 else if (tp->size == 8) 333 return "d"; 334 } else if (tp->size == 0) { 335 return "w"; 336 } 337 abort(); 338 } 339 340 void 341 writeout(void) 342 { 343 Symbol *p; 344 Type *tp; 345 char *sep, *name; 346 int haslabel = 0; 347 348 if (!curfun) 349 return; 350 if (curfun->kind == SGLOB) 351 fputs("export ", stdout); 352 printf("function %s %s(", size2stack(&curfun->rtype), symname(curfun)); 353 354 /* declare formal parameters */ 355 for (sep = "", p = locals; p; p = p->next, sep = ",") { 356 if ((p->type.flags & PARF) == 0) 357 break; 358 printf("%s%s %s.val", sep, size2stack(&p->type), symname(p)); 359 } 360 printf("%s)\n{\n", (curfun->type.flags&ELLIPS) ? ", ..." : ""); 361 362 /* emit assembler instructions */ 363 for (pc = prog; pc; pc = pc->next) { 364 if (pc->label) { 365 haslabel = 1; 366 printf("%s\n", symname(pc->label)); 367 } 368 if (!pc->op) 369 continue; 370 if (pc->flags&BBENTRY && !haslabel) 371 printf("%s\n", symname(newlabel())); 372 (*optbl[pc->op].fun)(); 373 if (!pc->label) 374 haslabel = 0; 375 } 376 377 puts("}"); 378 } 379 380 static char * 381 addr2txt(Addr *a) 382 { 383 switch (a->kind) { 384 case SCONST: 385 sprintf(buff, "%llu", (unsigned long long) a->u.i); 386 return buff; 387 case SAUTO: 388 case SLABEL: 389 case STMP: 390 case SGLOB: 391 case SEXTRN: 392 case SPRIV: 393 case SLOCAL: 394 return symname(a->u.sym); 395 default: 396 abort(); 397 } 398 } 399 400 static void 401 binary(void) 402 { 403 struct opdata *p = &optbl[pc->op]; 404 char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN]; 405 406 strcpy(to, addr2txt(&pc->to)); 407 strcpy(from1, addr2txt(&pc->from1)); 408 strcpy(from2, addr2txt(&pc->from2)); 409 printf("\t%s =%c\t%s\t%s,%s\n", to, p->letter, p->txt, from1, from2); 410 } 411 412 static void 413 ldir(void) 414 { 415 struct opdata *p = &optbl[pc->op]; 416 char to[ADDR_LEN], from[ADDR_LEN]; 417 /* TODO: what type do we use for the size? */ 418 419 /* TODO: it is pending */ 420 } 421 422 static void 423 store(void) 424 { 425 struct opdata *p = &optbl[pc->op]; 426 char to[ADDR_LEN], from[ADDR_LEN]; 427 428 strcpy(to, addr2txt(&pc->to)); 429 strcpy(from, addr2txt(&pc->from1)); 430 printf("\t\t%s%c\t%s,%s\n", p->txt, p->letter, from, to); 431 } 432 433 static void 434 unary(void) 435 { 436 struct opdata *p = &optbl[pc->op]; 437 char to[ADDR_LEN], from[ADDR_LEN]; 438 439 strcpy(to, addr2txt(&pc->to)); 440 strcpy(from, addr2txt(&pc->from1)); 441 printf("\t%s =%c\t%s\t%s\n", to, p->letter, p->txt, from); 442 } 443 444 static void 445 call(void) 446 { 447 struct opdata *p = &optbl[pc->op]; 448 char to[ADDR_LEN], from[ADDR_LEN]; 449 Symbol *sym = pc->to.u.sym; 450 451 strcpy(to, addr2txt(&pc->to)); 452 strcpy(from, addr2txt(&pc->from1)); 453 printf("\t%s =%s\tcall\t%s(", 454 to, size2stack(&sym->type), from); 455 } 456 457 static void 458 param(void) 459 { 460 Symbol *sym = pc->from2.u.sym; 461 462 printf(optbl[pc->op].txt, 463 size2stack(&sym->type), addr2txt(&pc->from1)); 464 } 465 466 static void 467 ecall(void) 468 { 469 struct opdata *p = &optbl[pc->op]; 470 471 puts(p->txt); 472 } 473 474 static void 475 ret(void) 476 { 477 if (pc->from1.kind == SNONE) 478 puts("\t\tret"); 479 else 480 printf("\t\tret\t%s\n", addr2txt(&pc->from1)); 481 } 482 483 static void 484 jmp(void) 485 { 486 printf("\t\tjmp\t%s\n", addr2txt(&pc->from1)); 487 } 488 489 static void 490 branch(void) 491 { 492 char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN]; 493 494 strcpy(to, addr2txt(&pc->to)); 495 strcpy(from1, addr2txt(&pc->from1)); 496 strcpy(from2, addr2txt(&pc->from2)); 497 printf("\t\tjnz\t%s,%s,%s\n", to, from1, from2); 498 } 499 500 static void 501 vastart(void) 502 { 503 printf("\t\tvastart %s\n", addr2txt(&pc->from1)); 504 } 505 506 static void 507 vaarg(void) 508 { 509 Symbol *sym = pc->to.u.sym; 510 Type *tp = &sym->type; 511 char to[ADDR_LEN], from[ADDR_LEN]; 512 513 strcpy(to, addr2txt(&pc->to)); 514 strcpy(from, addr2txt(&pc->from1)); 515 printf("\t\t%s =%s vaarg %s\n", to, size2asm(tp), from); 516 } 517 518 static void 519 asalloc(void) 520 { 521 Symbol *sym = pc->to.u.sym; 522 Type *tp = &sym->type; 523 extern Type ptrtype; 524 525 printf("\t%s =%s\talloc%lu\t%lu\n", 526 symname(sym), size2asm(&ptrtype), tp->align+3 & ~3, tp->size); 527 } 528 529 static void 530 form2local(void) 531 { 532 Symbol *sym = pc->to.u.sym; 533 Type *tp = &sym->type; 534 char *name = symname(sym); 535 536 printf("\t\tstore%s\t%s.val,%s\n", size2asm(tp), name, name); 537 } 538 539 void 540 endinit(void) 541 { 542 puts("}"); 543 } 544 545 void 546 getbblocks(void) 547 { 548 Inst *i; 549 550 if (!prog) 551 return; 552 553 prog->flags |= BBENTRY; 554 for (pc = prog; pc; pc = pc->next) { 555 switch (pc->op) { 556 case ASBRANCH: 557 i = pc->from2.u.sym->u.inst; 558 i->flags |= BBENTRY; 559 case ASJMP: 560 i = pc->from1.u.sym->u.inst; 561 i->flags |= BBENTRY; 562 case ASRET: 563 if (pc->next) 564 pc->next->flags |= BBENTRY; 565 break; 566 } 567 } 568 }