Skip to content

Commit a603970

Browse files
authored
Merge pull request sysprog21#184 from ChAoSUnItY/feat/arena
Implement arena allocator to reduce allocation
2 parents 6196ab1 + 03878f7 commit a603970

File tree

12 files changed

+183
-74
lines changed

12 files changed

+183
-74
lines changed

lib/c.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,12 +629,27 @@ void *malloc(int size)
629629

630630
void *calloc(int n, int size)
631631
{
632-
char *p = malloc(n * size);
632+
int total = n * size;
633+
char *p = malloc(total);
633634

634635
if (!p)
635636
return NULL;
636-
for (int i = 0; i < n * size; i++)
637-
p[i] = 0;
637+
638+
/* TODO: Replace the byte buffer clearing algorithm with memset once
639+
* implemented.
640+
*/
641+
642+
/* Currently malloc uses mmap(2) to request allocation, which guarantees
643+
* memory to be page-aligned
644+
*/
645+
int *pi = p, num_words = total >> 2, offset = num_words << 2;
646+
647+
for (int i = 0; i < num_words; i++)
648+
pi[i] = 0;
649+
650+
while (offset < total)
651+
p[offset++] = 0;
652+
638653
return p;
639654
}
640655

src/arm-codegen.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ void cfg_flatten()
156156

157157
for (ph2_ir_t *insn = bb->ph2_ir_list.head; insn;
158158
insn = insn->next) {
159-
flatten_ir = add_ph2_ir(OP_generic);
160-
memcpy(flatten_ir, insn, sizeof(ph2_ir_t));
159+
flatten_ir = add_existed_ph2_ir(insn);
161160

162161
if (insn->op == OP_return) {
163162
/* restore sp */
@@ -470,7 +469,7 @@ void code_generate()
470469
emit(__b(__AL, MAIN_BB->elf_offset - elf_code_idx));
471470

472471
for (int i = 0; i < ph2_ir_idx; i++) {
473-
ph2_ir = &PH2_IR[i];
472+
ph2_ir = PH2_IR_FLATTEN[i];
474473
emit_ph2_ir(ph2_ir);
475474
}
476475
}

src/defs.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
#define MAX_OPERAND_STACK_SIZE 32
4242
#define MAX_ANALYSIS_STACK_SIZE 750
4343

44+
/* Default capacities for common data structures */
45+
/* Default arena size is initialized with 256 KiB */
46+
#define DEFAULT_ARENA_SIZE 262144
47+
4448
#define ELF_START 0x10000
4549
#define PTR_SIZE 4
4650

@@ -62,6 +66,18 @@
6266
#define HOST_PTR_SIZE __SIZEOF_POINTER__
6367
#endif
6468

69+
/* Common data structures */
70+
typedef struct arena_block {
71+
char *memory;
72+
int capacity;
73+
int offset;
74+
struct arena_block *next;
75+
} arena_block_t;
76+
77+
typedef struct {
78+
arena_block_t *head;
79+
} arena_t;
80+
6581
/* builtin types */
6682
typedef enum {
6783
TYPE_void = 0,

src/globals.c

Lines changed: 137 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ int global_ir_idx = 0;
3232
ph1_ir_t *PH1_IR;
3333
int ph1_ir_idx = 0;
3434

35-
ph2_ir_t *PH2_IR;
35+
arena_t *INSN_ARENA;
36+
37+
/* BB_ARENA is responsible for basic_block_t / ph2_ir_t allocation */
38+
arena_t *BB_ARENA;
39+
40+
ph2_ir_t **PH2_IR_FLATTEN;
3641
int ph2_ir_idx = 0;
3742

3843
label_lut_t *LABEL_LUT;
@@ -69,6 +74,121 @@ char *elf_symtab;
6974
char *elf_strtab;
7075
char *elf_section;
7176

77+
/**
78+
* arena_block_create() - creates a new arena block with given capacity.
79+
* The created arena block is guaranteed to be zero-initialized.
80+
* @capacity: The capacity of the arena block. Must be positive.
81+
*
82+
* Return: The pointer of created arena block. NULL if failed to allocate.
83+
*/
84+
arena_block_t *arena_block_create(int capacity)
85+
{
86+
arena_block_t *block = malloc(sizeof(arena_block_t));
87+
88+
if (!block) {
89+
printf("Failed to allocate memory for arena block\n");
90+
exit(1);
91+
}
92+
93+
block->memory = calloc(capacity, sizeof(char));
94+
95+
if (!block->memory) {
96+
printf("Failed to allocate memory for arena block\n");
97+
free(block);
98+
exit(1);
99+
}
100+
101+
block->capacity = capacity;
102+
block->offset = 0;
103+
block->next = NULL;
104+
return block;
105+
}
106+
107+
/**
108+
* arena_init() - initializes the given arena with initial capacity.
109+
* @initial_capacity: The initial capacity of the arena. Must be positive.
110+
*
111+
* Return: The pointer of initialized arena.
112+
*/
113+
arena_t *arena_init(int initial_capacity)
114+
{
115+
arena_t *arena = malloc(sizeof(arena_t));
116+
arena->head = arena_block_create(initial_capacity);
117+
return arena;
118+
}
119+
120+
/**
121+
* arena_alloc() - allocates memory from the given arena with given size.
122+
* The arena may create a new arena block if no space is available.
123+
* @arena: The arena to allocate memory from. Must not be NULL.
124+
* @size: The size of memory to allocate. Must be positive.
125+
*
126+
* Return: The pointer of allocated memory. NULL if new arena block is failed to
127+
* allocate.
128+
*/
129+
void *arena_alloc(arena_t *arena, int size)
130+
{
131+
char *ptr;
132+
arena_block_t *block = arena->head;
133+
134+
while (block) {
135+
if (block->offset + size <= block->capacity) {
136+
ptr = block->memory + block->offset;
137+
block->offset += size;
138+
return ptr;
139+
}
140+
if (!block->next)
141+
break;
142+
block = block->next;
143+
}
144+
145+
/* If no space is available, create a new block
146+
* Allocate at least 256 KiB or the requested size
147+
*/
148+
int new_capacity = size > DEFAULT_ARENA_SIZE ? size : DEFAULT_ARENA_SIZE;
149+
arena_block_t *new_block = arena_block_create(new_capacity);
150+
151+
if (!new_block)
152+
return NULL;
153+
154+
block->next = new_block;
155+
ptr = new_block->memory + new_block->offset;
156+
new_block->offset += size;
157+
return ptr;
158+
}
159+
160+
/**
161+
* arena_reset() - resets the given arena by resetting all blocks' offset to 0.
162+
* @arena: The arena to reset. Must not be NULL.
163+
*/
164+
void arena_reset(arena_t *arena)
165+
{
166+
arena_block_t *block = arena->head;
167+
168+
while (block) {
169+
block->offset = 0;
170+
block = block->next;
171+
}
172+
}
173+
174+
/**
175+
* arena_free() - frees the given arena and all its blocks.
176+
* @arena: The arena to free. Must not be NULL.
177+
*/
178+
void arena_free(arena_t *arena)
179+
{
180+
arena_block_t *block = arena->head, *next;
181+
182+
while (block) {
183+
next = block->next;
184+
free(block->memory);
185+
free(block);
186+
block = next;
187+
}
188+
189+
free(arena);
190+
}
191+
72192
/**
73193
* hashmap_hash_index() - hashses a string with FNV-1a hash function
74194
* and converts into usable hashmap index. The range of returned
@@ -312,11 +432,17 @@ ph1_ir_t *add_ph1_ir(opcode_t op)
312432
return ph1_ir;
313433
}
314434

435+
ph2_ir_t *add_existed_ph2_ir(ph2_ir_t *ph2_ir)
436+
{
437+
PH2_IR_FLATTEN[ph2_ir_idx++] = ph2_ir;
438+
return ph2_ir;
439+
}
440+
315441
ph2_ir_t *add_ph2_ir(opcode_t op)
316442
{
317-
ph2_ir_t *ph2_ir = &PH2_IR[ph2_ir_idx++];
443+
ph2_ir_t *ph2_ir = arena_alloc(BB_ARENA, sizeof(ph2_ir_t));
318444
ph2_ir->op = op;
319-
return ph2_ir;
445+
return add_existed_ph2_ir(ph2_ir);
320446
}
321447

322448
void set_var_liveout(var_t *var, int end)
@@ -579,7 +705,7 @@ fn_t *add_fn()
579705
/* Create a basic block and set the scope of variables to 'parent' block */
580706
basic_block_t *bb_create(block_t *parent)
581707
{
582-
basic_block_t *bb = calloc(1, sizeof(basic_block_t));
708+
basic_block_t *bb = arena_alloc(BB_ARENA, sizeof(basic_block_t));
583709

584710
for (int i = 0; i < MAX_BB_PRED; i++) {
585711
bb->prev[i].bb = NULL;
@@ -691,7 +817,7 @@ void add_insn(block_t *block,
691817

692818
bb->scope = block;
693819

694-
insn_t *n = calloc(1, sizeof(insn_t));
820+
insn_t *n = arena_alloc(INSN_ARENA, sizeof(insn_t));
695821
n->opcode = op;
696822
n->rd = rd;
697823
n->rs1 = rs1;
@@ -725,7 +851,9 @@ void global_init()
725851
TYPES = malloc(MAX_TYPES * sizeof(type_t));
726852
GLOBAL_IR = malloc(MAX_GLOBAL_IR * sizeof(ph1_ir_t));
727853
PH1_IR = malloc(MAX_IR_INSTR * sizeof(ph1_ir_t));
728-
PH2_IR = malloc(MAX_IR_INSTR * sizeof(ph2_ir_t));
854+
INSN_ARENA = arena_init(DEFAULT_ARENA_SIZE);
855+
BB_ARENA = arena_init(DEFAULT_ARENA_SIZE);
856+
PH2_IR_FLATTEN = malloc(MAX_IR_INSTR * sizeof(ph2_ir_t *));
729857
LABEL_LUT = malloc(MAX_LABEL * sizeof(label_lut_t));
730858
SOURCE = malloc(MAX_SOURCE);
731859
ALIASES = malloc(MAX_ALIASES * sizeof(alias_t));
@@ -755,7 +883,9 @@ void global_release()
755883
free(TYPES);
756884
free(GLOBAL_IR);
757885
free(PH1_IR);
758-
free(PH2_IR);
886+
arena_free(INSN_ARENA);
887+
arena_free(BB_ARENA);
888+
free(PH2_IR_FLATTEN);
759889
free(LABEL_LUT);
760890
free(SOURCE);
761891
free(ALIASES);

src/main.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ int main(int argc, char *argv[])
115115
elf_generate(out);
116116

117117
/* release allocated objects */
118-
ssa_release();
119118
global_release();
120119

121120
exit(0);

src/reg-alloc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ void refresh(basic_block_t *bb, insn_t *insn)
4949

5050
ph2_ir_t *bb_add_ph2_ir(basic_block_t *bb, opcode_t op)
5151
{
52-
ph2_ir_t *n = calloc(1, sizeof(ph2_ir_t));
52+
ph2_ir_t *n = arena_alloc(BB_ARENA, sizeof(ph2_ir_t));
5353
n->op = op;
5454

5555
if (!bb->ph2_ir_list.head)
@@ -640,7 +640,7 @@ void reg_alloc()
640640
void dump_ph2_ir()
641641
{
642642
for (int i = 0; i < ph2_ir_idx; i++) {
643-
ph2_ir_t *ph2_ir = &PH2_IR[i];
643+
ph2_ir_t *ph2_ir = PH2_IR_FLATTEN[i];
644644

645645
int rd = ph2_ir->dest + 48;
646646
int rs1 = ph2_ir->src0 + 48;

src/riscv-codegen.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,7 @@ void cfg_flatten()
128128

129129
for (ph2_ir_t *insn = bb->ph2_ir_list.head; insn;
130130
insn = insn->next) {
131-
flatten_ir = add_ph2_ir(OP_generic);
132-
memcpy(flatten_ir, insn, sizeof(ph2_ir_t));
131+
flatten_ir = add_existed_ph2_ir(insn);
133132

134133
if (insn->op == OP_return) {
135134
/* restore sp */
@@ -446,7 +445,7 @@ void code_generate()
446445
emit(__jal(__zero, MAIN_BB->elf_offset - elf_code_idx));
447446

448447
for (int i = 0; i < ph2_ir_idx; i++) {
449-
ph2_ir = &PH2_IR[i];
448+
ph2_ir = PH2_IR_FLATTEN[i];
450449
emit_ph2_ir(ph2_ir);
451450
}
452451
}

src/ssa.c

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ bool insert_phi_insn(basic_block_t *bb, var_t *var)
588588
return false;
589589

590590
insn_t *head = bb->insn_list.head;
591-
insn_t *n = calloc(1, sizeof(insn_t));
591+
insn_t *n = arena_alloc(INSN_ARENA, sizeof(insn_t));
592592
n->opcode = OP_phi;
593593
n->rd = var;
594594
n->rs1 = var;
@@ -810,7 +810,7 @@ void solve_phi_params()
810810

811811
void append_unwound_phi_insn(basic_block_t *bb, var_t *dest, var_t *rs)
812812
{
813-
insn_t *n = calloc(1, sizeof(insn_t));
813+
insn_t *n = arena_alloc(INSN_ARENA, sizeof(insn_t));
814814
n->opcode = OP_unwound_phi;
815815
n->rd = dest;
816816
n->rs1 = rs;
@@ -1770,52 +1770,3 @@ void liveness_analysis()
17701770
} while (changed);
17711771
}
17721772
}
1773-
1774-
void bb_release(fn_t *fn, basic_block_t *bb)
1775-
{
1776-
UNUSED(fn);
1777-
1778-
insn_t *insn = bb->insn_list.head;
1779-
insn_t *next_insn;
1780-
while (insn) {
1781-
next_insn = insn->next;
1782-
free(insn);
1783-
insn = next_insn;
1784-
}
1785-
1786-
/* disconnect all predecessors */
1787-
for (int i = 0; i < MAX_BB_PRED; i++) {
1788-
if (!bb->prev[i].bb)
1789-
continue;
1790-
switch (bb->prev[i].type) {
1791-
case NEXT:
1792-
bb->prev[i].bb->next = NULL;
1793-
break;
1794-
case THEN:
1795-
bb->prev[i].bb->then_ = NULL;
1796-
break;
1797-
case ELSE:
1798-
bb->prev[i].bb->else_ = NULL;
1799-
break;
1800-
default:
1801-
abort();
1802-
}
1803-
1804-
bb->prev[i].bb = NULL;
1805-
}
1806-
free(bb);
1807-
}
1808-
1809-
void ssa_release()
1810-
{
1811-
bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t));
1812-
for (fn_t *fn = FUNC_LIST.head; fn; fn = fn->next) {
1813-
args->fn = fn;
1814-
args->bb = fn->bbs;
1815-
1816-
fn->visited++;
1817-
args->postorder_cb = bb_release;
1818-
bb_forward_traversal(args);
1819-
}
1820-
free(args);
1821-
}

tests/snapshots/fib-arm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/fib-riscv.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)