Add alloca()

This commit is contained in:
Rui Ueyama 2020-09-04 11:59:38 +09:00
parent 4064871212
commit 77275c546a
5 changed files with 76 additions and 0 deletions

View File

@ -153,6 +153,7 @@ struct Obj {
Node *body;
Obj *locals;
Obj *va_area;
Obj *alloca_bottom;
int stack_size;
// Static inline function

View File

@ -560,6 +560,34 @@ static void copy_struct_mem(void) {
}
}
static void builtin_alloca(void) {
// Align size to 16 bytes.
println(" add $15, %%rdi");
println(" and $0xfffffff0, %%edi");
// Shift the temporary area by %rdi.
println(" mov %d(%%rbp), %%rcx", current_fn->alloca_bottom->offset);
println(" sub %%rsp, %%rcx");
println(" mov %%rsp, %%rax");
println(" sub %%rdi, %%rsp");
println(" mov %%rsp, %%rdx");
println("1:");
println(" cmp $0, %%rcx");
println(" je 2f");
println(" mov (%%rax), %%r8b");
println(" mov %%r8b, (%%rdx)");
println(" inc %%rdx");
println(" inc %%rax");
println(" dec %%rcx");
println(" jmp 1b");
println("2:");
// Move alloca_bottom pointer.
println(" mov %d(%%rbp), %%rax", current_fn->alloca_bottom->offset);
println(" sub %%rdi, %%rax");
println(" mov %%rax, %d(%%rbp)", current_fn->alloca_bottom->offset);
}
// Generate code for a given node.
static void gen_expr(Node *node) {
println(" .loc %d %d", node->tok->file->file_no, node->tok->line_no);
@ -732,6 +760,13 @@ static void gen_expr(Node *node) {
return;
}
case ND_FUNCALL: {
if (node->lhs->kind == ND_VAR && !strcmp(node->lhs->var->name, "alloca")) {
gen_expr(node->args);
println(" mov %%rax, %%rdi");
builtin_alloca();
return;
}
int stack_args = push_args(node);
gen_expr(node->lhs);
@ -1241,6 +1276,7 @@ static void emit_text(Obj *prog) {
println(" push %%rbp");
println(" mov %%rsp, %%rbp");
println(" sub $%d, %%rsp", fn->stack_size);
println(" mov %%rsp, %d(%%rbp)", fn->alloca_bottom->offset);
// Save arg registers if function is variadic
if (fn->va_area) {

10
parse.c
View File

@ -2912,8 +2912,10 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) {
new_lvar("", pointer_to(rty));
fn->params = locals;
if (ty->is_variadic)
fn->va_area = new_lvar("__va_area__", array_of(ty_char, 136));
fn->alloca_bottom = new_lvar("__alloca_size__", pointer_to(ty_char));
tok = skip(tok, "{");
@ -2999,8 +3001,16 @@ static void scan_globals(void) {
globals = head.next;
}
static void declare_builtin_functions(void) {
Type *ty = func_type(pointer_to(ty_void));
ty->params = copy_type(ty_int);
Obj *builtin = new_gvar("alloca", ty);
builtin->is_definition = false;
}
// program = (typedef | function-definition | global-variable)*
Obj *parse(Token *tok) {
declare_builtin_functions();
globals = NULL;
while (tok->kind != TK_EOF) {

28
test/alloca.c Normal file
View File

@ -0,0 +1,28 @@
#include "test.h"
void *fn(int x, void *p, int y) { return p; }
int main() {
int i = 0;
char *p1 = alloca(16);
char *p2 = alloca(16);
char *p3 = 1 + (char *)alloca(3) + 1;
p3 -= 2;
char *p4 = fn(1, alloca(16), 3);
ASSERT(16, p1 - p2);
ASSERT(16, p2 - p3);
ASSERT(16, p3 - p4);
memcpy(p1, "0123456789abcdef", 16);
memcpy(p2, "ghijklmnopqrstuv", 16);
memcpy(p3, "wxy", 3);
ASSERT(0, memcmp(p1, "0123456789abcdef", 16));
ASSERT(0, memcmp(p2, "ghijklmnopqrstuv", 16));
ASSERT(0, memcmp(p3, "wxy", 3));
printf("OK\n");
return 0;
}

View File

@ -10,3 +10,4 @@ int memcmp(char *p, char *q, long n);
void exit(int n);
int vsprintf();
long strlen(char *s);
void *memcpy(void *dest, void *src, long n);