aboutsummaryrefslogtreecommitdiffhomepage
path: root/x86_64/emit.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-12-16 19:23:33 +0100
committerlemon <lsof@mailbox.org>2025-12-16 19:23:33 +0100
commit842f49f34464440abb2799ef007959cc5e8b7cf8 (patch)
tree244c590779b6d9c90a7d13d946e63238fa909dd7 /x86_64/emit.c
parentb3762f81b1a276f06bace301d56c9e8f6538058d (diff)
x86-64/emit: implement single-exit-point ret with jump threading
Diffstat (limited to 'x86_64/emit.c')
-rw-r--r--x86_64/emit.c62
1 files changed, 37 insertions, 25 deletions
diff --git a/x86_64/emit.c b/x86_64/emit.c
index 8a1673d..4a9d9d9 100644
--- a/x86_64/emit.c
+++ b/x86_64/emit.c
@@ -1288,15 +1288,8 @@ emitbin(struct function *fn)
struct block *blk;
uchar **pcode = &objout.code;
int npush = 0;
- uint epilogueaddr = 0;
bool saverestore;
- if (nblkaddr < fn->nblk) {
- blkaddr = xrealloc(blkaddr, fn->nblk * sizeof *blkaddr);
- nblkaddr = fn->nblk;
- }
- memset(blkaddr, 0, nblkaddr * sizeof *blkaddr);
-
nops(pcode, 16);
fnstart = *pcode;
curfnsym = fn->name;
@@ -1335,6 +1328,37 @@ emitbin(struct function *fn)
DS("\x48\x81\xEC"), I32(fn->stksiz);
}
+ if (*pcode - fnstart > 6) {
+ /* largue prologue -> largue epilogue -> transform to use single exit point */
+ struct block *exit = NULL;
+ blk = fn->entry->lprev;
+ do {
+ if (blk->jmp.t == Jret) {
+ if (!exit) {
+ if (blk->ins.n == 0) {
+ exit = blk;
+ continue;
+ } else {
+ useblk(fn, exit = newblk(fn));
+ exit->jmp.t = Jret;
+ }
+ }
+ blk->jmp.t = Jb;
+ memset(blk->jmp.arg, 0, sizeof blk->jmp.arg);
+ blk->s1 = exit;
+ } else if (exit) {
+ /* thread jumps to the exit block */
+ if (blk->s1 && !blk->s1->ins.n && blk->s1->s1 == exit && !blk->s1->s2) blk->s1 = exit;
+ if (blk->s2 && !blk->s2->ins.n && blk->s2->s1 == exit && !blk->s2->s2) blk->s2 = exit;
+ }
+ } while ((blk = blk->lprev) != fn->entry);
+ }
+
+ if (nblkaddr < fn->nblk) {
+ blkaddr = xrealloc(blkaddr, (nblkaddr = fn->nblk) * sizeof *blkaddr);
+ }
+ memset(blkaddr, 0, nblkaddr * sizeof *blkaddr);
+
blk = fn->entry;
do {
struct blkaddr *bb = &blkaddr[blk->id];
@@ -1356,24 +1380,12 @@ emitbin(struct function *fn)
}
if (blk->jmp.t == Jret) {
/* epilogue */
- uint here = *pcode - fnstart;
- if (epilogueaddr) {
- int disp = epilogueaddr - (here + 2);
- if ((uint)(disp + 128) < 256) {/* can use 1-byte displacement? */
- B(0xEB), B(disp); /* JMP rel8 */
- } else {
- B(0xE9), I32(disp - 3); /* JMP rel32 */
- }
- } else {
- if (fn->stksiz && (saverestore || !usebp))
- Xadd(pcode, KPTR, mkoper(OREG, .reg = RSP), mkoper(OIMM, .imm = fn->stksiz));
- if (saverestore) {
- epilogueaddr = here;
- calleerestore(pcode, fn);
- }
- if (usebp) B(0xC9); /* leave */
- B(0xC3); /* ret */
- }
+ if (fn->stksiz && (saverestore || !usebp))
+ Xadd(pcode, KPTR, mkoper(OREG, .reg = RSP), mkoper(OIMM, .imm = fn->stksiz));
+ if (saverestore)
+ calleerestore(pcode, fn);
+ if (usebp) B(0xC9); /* leave */
+ B(0xC3); /* ret */
} else if (blk->jmp.t == Jtrap) {
DS("\x0F\x0B"); /* UD2 */
} else emitbranch(pcode, blk);