Skip to content

Commit feca618

Browse files
committed
add link-saving fn prologue helper
1 parent 321f7e9 commit feca618

File tree

3 files changed

+80
-43
lines changed

3 files changed

+80
-43
lines changed

docs/builder.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ around abi registers, stack setup, and label plumbing, and it looks less scary.
88

99
- `cj_builder_fn_prologue(cj, stack_bytes, &frame)`: create a frame and reserve
1010
optional stack space (aligned for both arches).
11+
- `cj_builder_fn_prologue_with_link_save(cj, stack_bytes, &frame)`: like above,
12+
but on ARM64 it also saves/restores `x30` for non-leaf functions.
1113
- `cj_builder_fn_epilogue(cj, &frame)` / `cj_builder_return(cj, &frame)`:
1214
restore the frame and emit `ret`.
1315

examples/minilang.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -334,24 +334,10 @@ static void emit_function(codegen *cg, function *fn)
334334
{
335335
cj_builder_scratch_init(&cg->scratch);
336336
cj_mark_label(cg->cj, fn->entry);
337-
#if defined(__aarch64__) || defined(_M_ARM64)
338-
cj_operand sp = cj_make_register("sp");
339-
cj_sub(cg->cj, sp, cj_make_constant(16));
340-
cj_str(cg->cj, cj_make_register("x30"), cj_make_memory("sp", NULL, 1, 0));
341-
cj_operand result = emit_expr(cg, fn->body);
342-
if (!(result.type == CJ_REGISTER && result.reg && strcmp(result.reg, "w0") == 0))
343-
{
344-
cj_mov(cg->cj, cj_make_register("w0"), result);
345-
}
346-
cj_ldr(cg->cj, cj_make_register("x30"), cj_make_memory("sp", NULL, 1, 0));
347-
cj_add(cg->cj, sp, cj_make_constant(16));
348-
cj_ret(cg->cj);
349-
#else
350337
cj_builder_frame frame;
351-
cj_builder_fn_prologue(cg->cj, 0, &frame);
338+
cj_builder_fn_prologue_with_link_save(cg->cj, 0, &frame);
352339
cj_operand result = emit_expr(cg, fn->body);
353340
cj_builder_return_value(cg->cj, &frame, result);
354-
#endif
355341
cj_builder_scratch_release(&cg->scratch);
356342
}
357343

src/builder.h

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
typedef struct
99
{
1010
size_t stack_size;
11+
size_t lr_offset;
12+
int save_lr;
1113
} cj_builder_frame;
1214

1315
typedef struct
@@ -39,6 +41,10 @@ typedef struct
3941

4042
static inline void cj_builder_fn_prologue(cj_ctx *ctx, size_t requested_stack_bytes,
4143
cj_builder_frame *frame);
44+
static inline void cj_builder_fn_prologue_with_link_save(cj_ctx *ctx, size_t requested_stack_bytes,
45+
cj_builder_frame *frame);
46+
static inline void cj_builder_fn_prologue_ex(cj_ctx *ctx, size_t requested_stack_bytes,
47+
cj_builder_frame *frame, int save_lr);
4248
static inline void cj_builder_fn_epilogue(cj_ctx *ctx, const cj_builder_frame *frame);
4349
static inline void cj_builder_return(cj_ctx *ctx, const cj_builder_frame *frame);
4450

@@ -100,44 +106,26 @@ static inline size_t align_stack_size(size_t size)
100106
static inline void cj_builder_fn_prologue(cj_ctx *ctx, size_t requested_stack_bytes,
101107
cj_builder_frame *frame)
102108
{
103-
if (!ctx)
104-
return;
105-
106-
size_t aligned = align_stack_size(requested_stack_bytes);
107-
if (frame)
108-
frame->stack_size = aligned;
109-
110-
#if defined(__x86_64__) || defined(_M_X64)
111-
cj_operand rbp = cj_make_register("rbp");
112-
cj_operand rsp = cj_make_register("rsp");
113-
114-
cj_push(ctx, rbp);
115-
cj_mov(ctx, rbp, rsp);
109+
cj_builder_fn_prologue_ex(ctx, requested_stack_bytes, frame, 0);
110+
}
116111

117-
if (aligned)
118-
{
119-
cj_operand amount = cj_make_constant((uint64_t)aligned);
120-
cj_sub(ctx, rsp, amount);
121-
}
122-
#elif defined(__aarch64__) || defined(_M_ARM64)
123-
cj_operand sp = cj_make_register("sp");
124-
if (aligned)
125-
{
126-
cj_operand amount = cj_make_constant((uint64_t)aligned);
127-
cj_sub(ctx, sp, amount);
128-
}
129-
#endif
112+
static inline void cj_builder_fn_prologue_with_link_save(cj_ctx *ctx, size_t requested_stack_bytes,
113+
cj_builder_frame *frame)
114+
{
115+
cj_builder_fn_prologue_ex(ctx, requested_stack_bytes, frame, 1);
130116
}
131117

132118
static inline void cj_builder_fn_epilogue(cj_ctx *ctx, const cj_builder_frame *frame)
133119
{
134120
if (!ctx)
135121
return;
136122
size_t aligned = frame ? frame->stack_size : 0;
123+
int save_lr = (frame && frame->save_lr);
137124

138125
#if defined(__x86_64__) || defined(_M_X64)
139126
cj_operand rbp = cj_make_register("rbp");
140127
cj_operand rsp = cj_make_register("rsp");
128+
(void)save_lr;
141129

142130
if (aligned)
143131
{
@@ -148,12 +136,23 @@ static inline void cj_builder_fn_epilogue(cj_ctx *ctx, const cj_builder_frame *f
148136
cj_pop(ctx, rbp);
149137
#elif defined(__aarch64__) || defined(_M_ARM64)
150138
cj_operand sp = cj_make_register("sp");
139+
size_t total = aligned + (save_lr ? 16 : 0);
151140

152-
if (aligned)
141+
if (save_lr)
153142
{
154-
cj_operand amount = cj_make_constant((uint64_t)aligned);
143+
size_t lr_offset = frame ? frame->lr_offset : aligned;
144+
cj_operand lr = cj_make_register("x30");
145+
cj_operand slot = cj_make_memory("sp", NULL, 1, (int32_t)lr_offset);
146+
cj_ldr(ctx, lr, slot);
147+
}
148+
149+
if (total)
150+
{
151+
cj_operand amount = cj_make_constant((uint64_t)total);
155152
cj_add(ctx, sp, amount);
156153
}
154+
#else
155+
(void)save_lr;
157156
#endif
158157
}
159158

@@ -671,3 +670,53 @@ cj_builder_call(cj_ctx *ctx, cj_builder_scratch *scratch, cj_label target,
671670

672671
return cj_builder_return_reg();
673672
}
673+
674+
static inline void cj_builder_fn_prologue_ex(cj_ctx *ctx, size_t requested_stack_bytes,
675+
cj_builder_frame *frame, int save_lr)
676+
{
677+
if (!ctx)
678+
return;
679+
assert(!save_lr || frame);
680+
681+
size_t aligned = align_stack_size(requested_stack_bytes);
682+
size_t lr_offset = aligned;
683+
if (frame)
684+
{
685+
frame->stack_size = aligned;
686+
frame->save_lr = save_lr ? 1 : 0;
687+
frame->lr_offset = save_lr ? lr_offset : 0;
688+
}
689+
690+
#if defined(__x86_64__) || defined(_M_X64)
691+
(void)save_lr;
692+
cj_operand rbp = cj_make_register("rbp");
693+
cj_operand rsp = cj_make_register("rsp");
694+
695+
cj_push(ctx, rbp);
696+
cj_mov(ctx, rbp, rsp);
697+
698+
if (aligned)
699+
{
700+
cj_operand amount = cj_make_constant((uint64_t)aligned);
701+
cj_sub(ctx, rsp, amount);
702+
}
703+
#elif defined(__aarch64__) || defined(_M_ARM64)
704+
size_t total = aligned + (save_lr ? 16 : 0);
705+
cj_operand sp = cj_make_register("sp");
706+
707+
if (total)
708+
{
709+
cj_operand amount = cj_make_constant((uint64_t)total);
710+
cj_sub(ctx, sp, amount);
711+
}
712+
713+
if (save_lr)
714+
{
715+
cj_operand lr = cj_make_register("x30");
716+
cj_operand slot = cj_make_memory("sp", NULL, 1, (int32_t)lr_offset);
717+
cj_str(ctx, lr, slot);
718+
}
719+
#else
720+
(void)save_lr;
721+
#endif
722+
}

0 commit comments

Comments
 (0)