emit.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. #include "all.h"
  2. #define CMP(X) \
  3. X(Ciule, "be") \
  4. X(Ciult, "b") \
  5. X(Cisle, "le") \
  6. X(Cislt, "l") \
  7. X(Cisgt, "g") \
  8. X(Cisge, "ge") \
  9. X(Ciugt, "a") \
  10. X(Ciuge, "ae") \
  11. X(Cieq, "z") \
  12. X(Cine, "nz") \
  13. X(NCmpI+Cfle, "be") \
  14. X(NCmpI+Cflt, "b") \
  15. X(NCmpI+Cfgt, "a") \
  16. X(NCmpI+Cfge, "ae") \
  17. X(NCmpI+Cfeq, "z") \
  18. X(NCmpI+Cfne, "nz") \
  19. X(NCmpI+Cfo, "np") \
  20. X(NCmpI+Cfuo, "p")
  21. enum {
  22. SLong = 0,
  23. SWord = 1,
  24. SShort = 2,
  25. SByte = 3,
  26. Ki = -1, /* matches Kw and Kl */
  27. Ka = -2, /* matches all classes */
  28. };
  29. /* Instruction format strings:
  30. *
  31. * if the format string starts with -, the instruction
  32. * is assumed to be 3-address and is put in 2-address
  33. * mode using an extra mov if necessary
  34. *
  35. * if the format string starts with +, the same as the
  36. * above applies, but commutativity is also assumed
  37. *
  38. * %k is used to set the class of the instruction,
  39. * it'll expand to "l", "q", "ss", "sd", depending
  40. * on the instruction class
  41. * %0 designates the first argument
  42. * %1 designates the second argument
  43. * %= designates the result
  44. *
  45. * if %k is not used, a prefix to 0, 1, or = must be
  46. * added, it can be:
  47. * M - memory reference
  48. * L - long (64 bits)
  49. * W - word (32 bits)
  50. * H - short (16 bits)
  51. * B - byte (8 bits)
  52. * S - single precision float
  53. * D - double precision float
  54. */
  55. static struct {
  56. short op;
  57. short cls;
  58. char *fmt;
  59. } omap[] = {
  60. { Oadd, Ka, "+add%k %1, %=" },
  61. { Osub, Ka, "-sub%k %1, %=" },
  62. { Oand, Ki, "+and%k %1, %=" },
  63. { Oor, Ki, "+or%k %1, %=" },
  64. { Oxor, Ki, "+xor%k %1, %=" },
  65. { Osar, Ki, "-sar%k %B1, %=" },
  66. { Oshr, Ki, "-shr%k %B1, %=" },
  67. { Oshl, Ki, "-shl%k %B1, %=" },
  68. { Omul, Ki, "+imul%k %1, %=" },
  69. { Omul, Ks, "+mulss %1, %=" },
  70. { Omul, Kd, "+mulsd %1, %=" },
  71. { Odiv, Ka, "-div%k %1, %=" },
  72. { Ostorel, Ka, "movq %L0, %M1" },
  73. { Ostorew, Ka, "movl %W0, %M1" },
  74. { Ostoreh, Ka, "movw %H0, %M1" },
  75. { Ostoreb, Ka, "movb %B0, %M1" },
  76. { Ostores, Ka, "movss %S0, %M1" },
  77. { Ostored, Ka, "movsd %D0, %M1" },
  78. { Oload, Ka, "mov%k %M0, %=" },
  79. { Oloadsw, Kl, "movslq %M0, %L=" },
  80. { Oloadsw, Kw, "movl %M0, %W=" },
  81. { Oloaduw, Ki, "movl %M0, %W=" },
  82. { Oloadsh, Ki, "movsw%k %M0, %=" },
  83. { Oloaduh, Ki, "movzw%k %M0, %=" },
  84. { Oloadsb, Ki, "movsb%k %M0, %=" },
  85. { Oloadub, Ki, "movzb%k %M0, %=" },
  86. { Oextsw, Kl, "movslq %W0, %L=" },
  87. { Oextuw, Kl, "movl %W0, %W=" },
  88. { Oextsh, Ki, "movsw%k %H0, %=" },
  89. { Oextuh, Ki, "movzw%k %H0, %=" },
  90. { Oextsb, Ki, "movsb%k %B0, %=" },
  91. { Oextub, Ki, "movzb%k %B0, %=" },
  92. { Oexts, Kd, "cvtss2sd %0, %=" },
  93. { Otruncd, Ks, "cvtsd2ss %0, %=" },
  94. { Ostosi, Ki, "cvttss2si%k %0, %=" },
  95. { Odtosi, Ki, "cvttsd2si%k %0, %=" },
  96. { Oswtof, Ka, "cvtsi2%k %W0, %=" },
  97. { Osltof, Ka, "cvtsi2%k %L0, %=" },
  98. { Ocast, Ki, "movq %D0, %L=" },
  99. { Ocast, Ka, "movq %L0, %D=" },
  100. { Oaddr, Ki, "lea%k %M0, %=" },
  101. { Oswap, Ki, "xchg%k %0, %1" },
  102. { Osign, Kl, "cqto" },
  103. { Osign, Kw, "cltd" },
  104. { Oxdiv, Ki, "div%k %0" },
  105. { Oxidiv, Ki, "idiv%k %0" },
  106. { Oxcmp, Ks, "ucomiss %S0, %S1" },
  107. { Oxcmp, Kd, "ucomisd %D0, %D1" },
  108. { Oxcmp, Ki, "cmp%k %0, %1" },
  109. { Oxtest, Ki, "test%k %0, %1" },
  110. #define X(c, s) \
  111. { Oflag+c, Ki, "set" s " %B=\n\tmovzb%k %B=, %=" },
  112. CMP(X)
  113. #undef X
  114. { NOp, 0, 0 }
  115. };
  116. static char *rname[][4] = {
  117. [RAX] = {"rax", "eax", "ax", "al"},
  118. [RBX] = {"rbx", "ebx", "bx", "bl"},
  119. [RCX] = {"rcx", "ecx", "cx", "cl"},
  120. [RDX] = {"rdx", "edx", "dx", "dl"},
  121. [RSI] = {"rsi", "esi", "si", "sil"},
  122. [RDI] = {"rdi", "edi", "di", "dil"},
  123. [RBP] = {"rbp", "ebp", "bp", "bpl"},
  124. [RSP] = {"rsp", "esp", "sp", "spl"},
  125. [R8 ] = {"r8" , "r8d", "r8w", "r8b"},
  126. [R9 ] = {"r9" , "r9d", "r9w", "r9b"},
  127. [R10] = {"r10", "r10d", "r10w", "r10b"},
  128. [R11] = {"r11", "r11d", "r11w", "r11b"},
  129. [R12] = {"r12", "r12d", "r12w", "r12b"},
  130. [R13] = {"r13", "r13d", "r13w", "r13b"},
  131. [R14] = {"r14", "r14d", "r14w", "r14b"},
  132. [R15] = {"r15", "r15d", "r15w", "r15b"},
  133. };
  134. static int
  135. slot(Ref r, Fn *fn)
  136. {
  137. int s;
  138. s = rsval(r);
  139. assert(s <= fn->slot);
  140. /* specific to NAlign == 3 */
  141. if (s < 0)
  142. return -4 * s;
  143. else if (fn->vararg)
  144. return -176 + -4 * (fn->slot - s);
  145. else
  146. return -4 * (fn->slot - s);
  147. }
  148. static void
  149. emitcon(Con *con, FILE *f)
  150. {
  151. char *p, *l;
  152. switch (con->type) {
  153. case CAddr:
  154. l = str(con->sym.id);
  155. p = l[0] == '"' ? "" : T.assym;
  156. if (con->sym.type == SThr) {
  157. if (T.apple)
  158. fprintf(f, "%s%s@TLVP", p, l);
  159. else
  160. fprintf(f, "%%fs:%s%s@tpoff", p, l);
  161. } else
  162. fprintf(f, "%s%s", p, l);
  163. if (con->bits.i)
  164. fprintf(f, "%+"PRId64, con->bits.i);
  165. break;
  166. case CBits:
  167. fprintf(f, "%"PRId64, con->bits.i);
  168. break;
  169. default:
  170. die("unreachable");
  171. }
  172. }
  173. static char *
  174. regtoa(int reg, int sz)
  175. {
  176. static char buf[6];
  177. assert(reg <= XMM15);
  178. if (reg >= XMM0) {
  179. sprintf(buf, "xmm%d", reg-XMM0);
  180. return buf;
  181. } else
  182. return rname[reg][sz];
  183. }
  184. static Ref
  185. getarg(char c, Ins *i)
  186. {
  187. switch (c) {
  188. case '0':
  189. return i->arg[0];
  190. case '1':
  191. return i->arg[1];
  192. case '=':
  193. return i->to;
  194. default:
  195. die("invalid arg letter %c", c);
  196. }
  197. }
  198. static void emitins(Ins, Fn *, FILE *);
  199. static void
  200. emitcopy(Ref r1, Ref r2, int k, Fn *fn, FILE *f)
  201. {
  202. Ins icp;
  203. icp.op = Ocopy;
  204. icp.arg[0] = r2;
  205. icp.to = r1;
  206. icp.cls = k;
  207. emitins(icp, fn, f);
  208. }
  209. static void
  210. emitf(char *s, Ins *i, Fn *fn, FILE *f)
  211. {
  212. static char clstoa[][3] = {"l", "q", "ss", "sd"};
  213. char c;
  214. int sz;
  215. Ref ref;
  216. Mem *m;
  217. Con off;
  218. switch (*s) {
  219. case '+':
  220. if (req(i->arg[1], i->to)) {
  221. ref = i->arg[0];
  222. i->arg[0] = i->arg[1];
  223. i->arg[1] = ref;
  224. }
  225. /* fall through */
  226. case '-':
  227. assert((!req(i->arg[1], i->to) || req(i->arg[0], i->to)) &&
  228. "cannot convert to 2-address");
  229. emitcopy(i->to, i->arg[0], i->cls, fn, f);
  230. s++;
  231. break;
  232. }
  233. fputc('\t', f);
  234. Next:
  235. while ((c = *s++) != '%')
  236. if (!c) {
  237. fputc('\n', f);
  238. return;
  239. } else
  240. fputc(c, f);
  241. switch ((c = *s++)) {
  242. case '%':
  243. fputc('%', f);
  244. break;
  245. case 'k':
  246. fputs(clstoa[i->cls], f);
  247. break;
  248. case '0':
  249. case '1':
  250. case '=':
  251. sz = KWIDE(i->cls) ? SLong : SWord;
  252. s--;
  253. goto Ref;
  254. case 'D':
  255. case 'S':
  256. sz = SLong; /* does not matter for floats */
  257. Ref:
  258. c = *s++;
  259. ref = getarg(c, i);
  260. switch (rtype(ref)) {
  261. case RTmp:
  262. assert(isreg(ref));
  263. fprintf(f, "%%%s", regtoa(ref.val, sz));
  264. break;
  265. case RSlot:
  266. fprintf(f, "%d(%%rbp)", slot(ref, fn));
  267. break;
  268. case RMem:
  269. Mem:
  270. m = &fn->mem[ref.val];
  271. if (rtype(m->base) == RSlot) {
  272. off.type = CBits;
  273. off.bits.i = slot(m->base, fn);
  274. addcon(&m->offset, &off, 1);
  275. m->base = TMP(RBP);
  276. }
  277. if (m->offset.type != CUndef)
  278. emitcon(&m->offset, f);
  279. fputc('(', f);
  280. if (!req(m->base, R))
  281. fprintf(f, "%%%s", regtoa(m->base.val, SLong));
  282. else if (m->offset.type == CAddr)
  283. fprintf(f, "%%rip");
  284. if (!req(m->index, R))
  285. fprintf(f, ", %%%s, %d",
  286. regtoa(m->index.val, SLong),
  287. m->scale
  288. );
  289. fputc(')', f);
  290. break;
  291. case RCon:
  292. fputc('$', f);
  293. emitcon(&fn->con[ref.val], f);
  294. break;
  295. default:
  296. die("unreachable");
  297. }
  298. break;
  299. case 'L':
  300. sz = SLong;
  301. goto Ref;
  302. case 'W':
  303. sz = SWord;
  304. goto Ref;
  305. case 'H':
  306. sz = SShort;
  307. goto Ref;
  308. case 'B':
  309. sz = SByte;
  310. goto Ref;
  311. case 'M':
  312. c = *s++;
  313. ref = getarg(c, i);
  314. switch (rtype(ref)) {
  315. case RMem:
  316. goto Mem;
  317. case RSlot:
  318. fprintf(f, "%d(%%rbp)", slot(ref, fn));
  319. break;
  320. case RCon:
  321. off = fn->con[ref.val];
  322. emitcon(&off, f);
  323. if (off.type == CAddr)
  324. if (off.sym.type != SThr || T.apple)
  325. fprintf(f, "(%%rip)");
  326. break;
  327. case RTmp:
  328. assert(isreg(ref));
  329. fprintf(f, "(%%%s)", regtoa(ref.val, SLong));
  330. break;
  331. default:
  332. die("unreachable");
  333. }
  334. break;
  335. default:
  336. die("invalid format specifier %%%c", c);
  337. }
  338. goto Next;
  339. }
  340. static void *negmask[4] = {
  341. [Ks] = (uint32_t[4]){ 0x80000000 },
  342. [Kd] = (uint64_t[2]){ 0x8000000000000000 },
  343. };
  344. static void
  345. emitins(Ins i, Fn *fn, FILE *f)
  346. {
  347. Ref r;
  348. int64_t val;
  349. int o, t0;
  350. Ins ineg;
  351. Con *con;
  352. char *sym;
  353. switch (i.op) {
  354. default:
  355. Table:
  356. /* most instructions are just pulled out of
  357. * the table omap[], some special cases are
  358. * detailed below */
  359. for (o=0;; o++) {
  360. /* this linear search should really be a binary
  361. * search */
  362. if (omap[o].op == NOp)
  363. die("no match for %s(%c)",
  364. optab[i.op].name, "wlsd"[i.cls]);
  365. if (omap[o].op == i.op)
  366. if (omap[o].cls == i.cls
  367. || (omap[o].cls == Ki && KBASE(i.cls) == 0)
  368. || (omap[o].cls == Ka))
  369. break;
  370. }
  371. emitf(omap[o].fmt, &i, fn, f);
  372. break;
  373. case Onop:
  374. /* just do nothing for nops, they are inserted
  375. * by some passes */
  376. break;
  377. case Omul:
  378. /* here, we try to use the 3-addresss form
  379. * of multiplication when possible */
  380. if (rtype(i.arg[1]) == RCon) {
  381. r = i.arg[0];
  382. i.arg[0] = i.arg[1];
  383. i.arg[1] = r;
  384. }
  385. if (KBASE(i.cls) == 0 /* only available for ints */
  386. && rtype(i.arg[0]) == RCon
  387. && rtype(i.arg[1]) == RTmp) {
  388. emitf("imul%k %0, %1, %=", &i, fn, f);
  389. break;
  390. }
  391. goto Table;
  392. case Osub:
  393. /* we have to use the negation trick to handle
  394. * some 3-address subtractions */
  395. if (req(i.to, i.arg[1]) && !req(i.arg[0], i.to)) {
  396. ineg = (Ins){Oneg, i.cls, i.to, {i.to}};
  397. emitins(ineg, fn, f);
  398. emitf("add%k %0, %=", &i, fn, f);
  399. break;
  400. }
  401. goto Table;
  402. case Oneg:
  403. if (!req(i.to, i.arg[0]))
  404. emitf("mov%k %0, %=", &i, fn, f);
  405. if (KBASE(i.cls) == 0)
  406. emitf("neg%k %=", &i, fn, f);
  407. else
  408. fprintf(f,
  409. "\txorp%c %sfp%d(%%rip), %%%s\n",
  410. "xxsd"[i.cls],
  411. T.asloc,
  412. stashbits(negmask[i.cls], 16),
  413. regtoa(i.to.val, SLong)
  414. );
  415. break;
  416. case Odiv:
  417. /* use xmm15 to adjust the instruction when the
  418. * conversion to 2-address in emitf() would fail */
  419. if (req(i.to, i.arg[1])) {
  420. i.arg[1] = TMP(XMM0+15);
  421. emitf("mov%k %=, %1", &i, fn, f);
  422. emitf("mov%k %0, %=", &i, fn, f);
  423. i.arg[0] = i.to;
  424. }
  425. goto Table;
  426. case Ocopy:
  427. /* copies are used for many things; see my note
  428. * to understand how to load big constants:
  429. * https://c9x.me/notes/2015-09-19.html */
  430. assert(rtype(i.to) != RMem);
  431. if (req(i.to, R) || req(i.arg[0], R))
  432. break;
  433. if (req(i.to, i.arg[0]))
  434. break;
  435. t0 = rtype(i.arg[0]);
  436. if (i.cls == Kl
  437. && t0 == RCon
  438. && fn->con[i.arg[0].val].type == CBits) {
  439. val = fn->con[i.arg[0].val].bits.i;
  440. if (isreg(i.to))
  441. if (val >= 0 && val <= UINT32_MAX) {
  442. emitf("movl %W0, %W=", &i, fn, f);
  443. break;
  444. }
  445. if (rtype(i.to) == RSlot)
  446. if (val < INT32_MIN || val > INT32_MAX) {
  447. emitf("movl %0, %=", &i, fn, f);
  448. emitf("movl %0>>32, 4+%=", &i, fn, f);
  449. break;
  450. }
  451. }
  452. if (isreg(i.to)
  453. && t0 == RCon
  454. && fn->con[i.arg[0].val].type == CAddr) {
  455. emitf("lea%k %M0, %=", &i, fn, f);
  456. break;
  457. }
  458. if (rtype(i.to) == RSlot
  459. && (t0 == RSlot || t0 == RMem)) {
  460. i.cls = KWIDE(i.cls) ? Kd : Ks;
  461. i.arg[1] = TMP(XMM0+15);
  462. emitf("mov%k %0, %1", &i, fn, f);
  463. emitf("mov%k %1, %=", &i, fn, f);
  464. break;
  465. }
  466. /* conveniently, the assembler knows if it
  467. * should use movabsq when reading movq */
  468. emitf("mov%k %0, %=", &i, fn, f);
  469. break;
  470. case Oaddr:
  471. if (!T.apple
  472. && rtype(i.arg[0]) == RCon
  473. && fn->con[i.arg[0].val].sym.type == SThr) {
  474. /* derive the symbol address from the TCB
  475. * address at offset 0 of %fs */
  476. assert(isreg(i.to));
  477. con = &fn->con[i.arg[0].val];
  478. sym = str(con->sym.id);
  479. emitf("movq %%fs:0, %L=", &i, fn, f);
  480. fprintf(f, "\tleaq %s%s@tpoff",
  481. sym[0] == '"' ? "" : T.assym, sym);
  482. if (con->bits.i)
  483. fprintf(f, "%+"PRId64, con->bits.i);
  484. fprintf(f, "(%%%s), %%%s\n",
  485. regtoa(i.to.val, SLong),
  486. regtoa(i.to.val, SLong));
  487. break;
  488. }
  489. goto Table;
  490. case Ocall:
  491. /* calls simply have a weird syntax in AT&T
  492. * assembly... */
  493. switch (rtype(i.arg[0])) {
  494. case RCon:
  495. fprintf(f, "\tcallq ");
  496. emitcon(&fn->con[i.arg[0].val], f);
  497. fprintf(f, "\n");
  498. break;
  499. case RTmp:
  500. emitf("callq *%L0", &i, fn, f);
  501. break;
  502. default:
  503. die("invalid call argument");
  504. }
  505. break;
  506. case Osalloc:
  507. /* there is no good reason why this is here
  508. * maybe we should split Osalloc in 2 different
  509. * instructions depending on the result
  510. */
  511. emitf("subq %L0, %%rsp", &i, fn, f);
  512. if (!req(i.to, R))
  513. emitcopy(i.to, TMP(RSP), Kl, fn, f);
  514. break;
  515. case Oswap:
  516. if (KBASE(i.cls) == 0)
  517. goto Table;
  518. /* for floats, there is no swap instruction
  519. * so we use xmm15 as a temporary
  520. */
  521. emitcopy(TMP(XMM0+15), i.arg[0], i.cls, fn, f);
  522. emitcopy(i.arg[0], i.arg[1], i.cls, fn, f);
  523. emitcopy(i.arg[1], TMP(XMM0+15), i.cls, fn, f);
  524. break;
  525. case Odbgloc:
  526. emitdbgloc(i.arg[0].val, i.arg[1].val, f);
  527. break;
  528. }
  529. }
  530. static uint64_t
  531. framesz(Fn *fn)
  532. {
  533. uint64_t i, o, f;
  534. /* specific to NAlign == 3 */
  535. for (i=0, o=0; i<NCLR; i++)
  536. o ^= 1 & (fn->reg >> amd64_sysv_rclob[i]);
  537. f = fn->slot;
  538. f = (f + 3) & -4;
  539. return 4*f + 8*o + 176*fn->vararg;
  540. }
  541. void
  542. amd64_emitfn(Fn *fn, FILE *f)
  543. {
  544. static char *ctoa[] = {
  545. #define X(c, s) [c] = s,
  546. CMP(X)
  547. #undef X
  548. };
  549. static int id0;
  550. Blk *b, *s;
  551. Ins *i, itmp;
  552. int *r, c, o, n, lbl;
  553. uint64_t fs;
  554. emitfnlnk(fn->name, &fn->lnk, f);
  555. fputs("\tpushq %rbp\n\tmovq %rsp, %rbp\n", f);
  556. fs = framesz(fn);
  557. if (fs)
  558. fprintf(f, "\tsubq $%"PRIu64", %%rsp\n", fs);
  559. if (fn->vararg) {
  560. o = -176;
  561. for (r=amd64_sysv_rsave; r<&amd64_sysv_rsave[6]; r++, o+=8)
  562. fprintf(f, "\tmovq %%%s, %d(%%rbp)\n", rname[*r][0], o);
  563. for (n=0; n<8; ++n, o+=16)
  564. fprintf(f, "\tmovaps %%xmm%d, %d(%%rbp)\n", n, o);
  565. }
  566. for (r=amd64_sysv_rclob; r<&amd64_sysv_rclob[NCLR]; r++)
  567. if (fn->reg & BIT(*r)) {
  568. itmp.arg[0] = TMP(*r);
  569. emitf("pushq %L0", &itmp, fn, f);
  570. fs += 8;
  571. }
  572. for (lbl=0, b=fn->start; b; b=b->link) {
  573. if (lbl || b->npred > 1)
  574. fprintf(f, "%sbb%d:\n", T.asloc, id0+b->id);
  575. for (i=b->ins; i!=&b->ins[b->nins]; i++)
  576. emitins(*i, fn, f);
  577. lbl = 1;
  578. switch (b->jmp.type) {
  579. case Jhlt:
  580. fprintf(f, "\tud2\n");
  581. break;
  582. case Jret0:
  583. if (fn->dynalloc)
  584. fprintf(f,
  585. "\tmovq %%rbp, %%rsp\n"
  586. "\tsubq $%"PRIu64", %%rsp\n",
  587. fs
  588. );
  589. for (r=&amd64_sysv_rclob[NCLR]; r>amd64_sysv_rclob;)
  590. if (fn->reg & BIT(*--r)) {
  591. itmp.arg[0] = TMP(*r);
  592. emitf("popq %L0", &itmp, fn, f);
  593. }
  594. fprintf(f,
  595. "\tleave\n"
  596. "\tret\n"
  597. );
  598. break;
  599. case Jjmp:
  600. Jmp:
  601. if (b->s1 != b->link)
  602. fprintf(f, "\tjmp %sbb%d\n",
  603. T.asloc, id0+b->s1->id);
  604. else
  605. lbl = 0;
  606. break;
  607. default:
  608. c = b->jmp.type - Jjf;
  609. if (0 <= c && c <= NCmp) {
  610. if (b->link == b->s2) {
  611. s = b->s1;
  612. b->s1 = b->s2;
  613. b->s2 = s;
  614. } else
  615. c = cmpneg(c);
  616. fprintf(f, "\tj%s %sbb%d\n", ctoa[c],
  617. T.asloc, id0+b->s2->id);
  618. goto Jmp;
  619. }
  620. die("unhandled jump %d", b->jmp.type);
  621. }
  622. }
  623. id0 += fn->nblk;
  624. if (!T.apple)
  625. elf_emitfnfin(fn->name, f);
  626. }