summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTing-Wei Lan <lantw44@gmail.com>2015-12-31 19:11:32 +0800
committerTing-Wei Lan <lantw44@gmail.com>2015-12-31 19:11:32 +0800
commit1342a2cddf984af89bfa554ae9656817b43745a6 (patch)
tree36275174e65f2cbbc2ca5f7cf776d41e7c87a8cf
parent8723485ffe647c10ac97d8dc341dfa601e742bcc (diff)
downloadcompiler2015-1342a2cddf984af89bfa554ae9656817b43745a6.tar
compiler2015-1342a2cddf984af89bfa554ae9656817b43745a6.tar.gz
compiler2015-1342a2cddf984af89bfa554ae9656817b43745a6.tar.bz2
compiler2015-1342a2cddf984af89bfa554ae9656817b43745a6.tar.lz
compiler2015-1342a2cddf984af89bfa554ae9656817b43745a6.tar.xz
compiler2015-1342a2cddf984af89bfa554ae9656817b43745a6.tar.zst
compiler2015-1342a2cddf984af89bfa554ae9656817b43745a6.zip
Use ldr to prevent immediate from becoming too large
-rw-r--r--src/code-generation.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/src/code-generation.c b/src/code-generation.c
index f1cac15..993c8d7 100644
--- a/src/code-generation.c
+++ b/src/code-generation.c
@@ -148,15 +148,40 @@ static void generate_block(
for (CcmmcAst *local = child->child; local != NULL; local = local->right_sibling)
current_offset = generate_local_variable(local, state, current_offset);
offset_diff = current_offset - orig_offset;
- fprintf(state->asm_output, "\tsub\tsp, sp, #%" PRIu64 "\n", offset_diff);
+ if (offset_diff > 0) {
+ if (offset_diff >= 65536) {
+ CcmmcTmp *tmp = ccmmc_register_alloc(state->reg_pool);
+ const char *reg_name = ccmmc_register_lock(state->reg_pool, tmp);
+ fprintf(state->asm_output,
+ "\tldr\t%s, =%" PRIu64 "\n"
+ "\tsub\tsp, sp, %s\n", reg_name, offset_diff, reg_name);
+ ccmmc_register_unlock(state->reg_pool, tmp);
+ ccmmc_register_free(state->reg_pool, tmp);
+ } else {
+ fprintf(state->asm_output, "\tsub\tsp, sp, #%" PRIu64 "\n",
+ offset_diff);
+ }
+ }
child = child->right_sibling;
}
if (child != NULL && child->type_node == CCMMC_AST_NODE_STMT_LIST) {
for (CcmmcAst *stmt = child->child; stmt != NULL; stmt = stmt->right_sibling)
generate_statement(stmt, state, current_offset);
}
- if (offset_diff > 0)
- fprintf(state->asm_output, "\tadd\tsp, sp, #%" PRIu64 "\n", offset_diff);
+ if (offset_diff > 0) {
+ if (offset_diff >= 65536) {
+ CcmmcTmp *tmp = ccmmc_register_alloc(state->reg_pool);
+ const char *reg_name = ccmmc_register_lock(state->reg_pool, tmp);
+ fprintf(state->asm_output,
+ "\tldr\t%s, =%" PRIu64 "\n"
+ "\tadd\tsp, sp, %s\n", reg_name, offset_diff, reg_name);
+ ccmmc_register_unlock(state->reg_pool, tmp);
+ ccmmc_register_free(state->reg_pool, tmp);
+ } else {
+ fprintf(state->asm_output, "\tadd\tsp, sp, #%" PRIu64 "\n",
+ offset_diff);
+ }
+ }
ccmmc_symbol_table_close_scope(state->table);
}