summaryrefslogtreecommitdiffhomepage
path: root/ir/be
diff options
context:
space:
mode:
authorJohannes Bucher <johannes.bucher2@student.kit.edu>2019-05-27 16:09:46 +0200
committerJohannes Bucher <johannes.bucher2@student.kit.edu>2019-06-11 16:34:58 +0200
commit00b6721751d2c9d227dfc23e0fd580f920d33a25 (patch)
tree065a0df0e3038b5b5950825a29eb5653ff05d07d /ir/be
parent98db20e910bc82cc593520d800aab16f16cf4aeb (diff)
riscv: support frame pointer relative addressing
Diffstat (limited to 'ir/be')
-rw-r--r--ir/be/riscv/riscv_bearch.c107
-rw-r--r--ir/be/riscv/riscv_bearch_t.h10
-rw-r--r--ir/be/riscv/riscv_cconv.c35
-rw-r--r--ir/be/riscv/riscv_cconv.h5
-rw-r--r--ir/be/riscv/riscv_new_nodes.c5
-rw-r--r--ir/be/riscv/riscv_nodes_attr.h4
-rw-r--r--ir/be/riscv/riscv_transform.c20
7 files changed, 154 insertions, 32 deletions
diff --git a/ir/be/riscv/riscv_bearch.c b/ir/be/riscv/riscv_bearch.c
index ee422cf..6b0a3ad 100644
--- a/ir/be/riscv/riscv_bearch.c
+++ b/ir/be/riscv/riscv_bearch.c
@@ -15,12 +15,14 @@
#include "bespillslots.h"
#include "bestack.h"
#include "betranshlp.h"
+#include "beutil.h"
#include "gen_riscv_new_nodes.h"
#include "gen_riscv_regalloc_if.h"
#include "irarch.h"
#include "iredges.h"
#include "irgwalk.h"
#include "irprog_t.h"
+#include "irprintf.h"
#include "lower_builtins.h"
#include "lower_alloc.h"
#include "lowering.h"
@@ -163,11 +165,11 @@ static void riscv_set_frame_entity(ir_node *const node, ir_entity *const entity,
imm->ent = entity;
}
-static void riscv_assign_spill_slots(ir_graph *const irg)
+static void riscv_assign_spill_slots(ir_graph *const irg, bool omit_fp)
{
be_fec_env_t *const fec_env = be_new_frame_entity_coalescer(irg);
irg_walk_graph(irg, NULL, riscv_collect_frame_entity_nodes, fec_env);
- be_assign_entities(fec_env, riscv_set_frame_entity, true);
+ be_assign_entities(fec_env, riscv_set_frame_entity, omit_fp);
be_free_frame_entity_coalescer(fec_env);
}
@@ -176,38 +178,89 @@ static ir_node *riscv_new_IncSP(ir_node *const block, ir_node *const sp, int con
return be_new_IncSP(block, sp, offset, align);
}
-static void riscv_introduce_prologue(ir_graph *const irg, unsigned const size)
+static void riscv_introduce_prologue(ir_graph *const irg, unsigned const size, bool omit_fp)
{
ir_node *const start = get_irg_start(irg);
ir_node *const block = get_nodes_block(start);
ir_node *const start_sp = be_get_Start_proj(irg, &riscv_registers[REG_SP]);
- ir_node *const inc_sp = riscv_new_IncSP(block, start_sp, size, 0);
- sched_add_after(start, inc_sp);
- edges_reroute_except(start_sp, inc_sp, inc_sp);
+ ir_node *const start_fp = be_get_Start_proj(irg, &riscv_registers[REG_S0]);
+
+ if (!omit_fp) {
+ ir_node *const mem = get_irg_initial_mem(irg);
+
+ /* save fp to stack */
+ ir_node *const store_fp = new_bd_riscv_sw(NULL, block, mem, start_sp, start_fp, NULL, -4);
+ sched_add_after(start, store_fp);
+ edges_reroute_except(mem, store_fp, store_fp);
+
+ /* move sp to fp */
+ ir_node *const curr_fp = be_new_Copy(block, start_sp);
+ arch_copy_irn_out_info(curr_fp, 0, start_fp);
+ sched_add_after(store_fp, curr_fp);
+ edges_reroute_except(start_fp, curr_fp, store_fp);
+
+ ir_node *const inc_sp = riscv_new_IncSP(block, start_sp, size, 0);
+ edges_reroute_except(start_sp, inc_sp, inc_sp);
+ sched_add_after(curr_fp, inc_sp);
+
+ /* make sure the initial IncSP is really used by someone */
+ be_keep_if_unused(inc_sp);
+ } else {
+ ir_node *const inc_sp = riscv_new_IncSP(block, start_sp, size, 0);
+ sched_add_after(start, inc_sp);
+ edges_reroute_except(start_sp, inc_sp, inc_sp);
+ }
}
-static void riscv_introduce_epilogue(ir_node *const ret, unsigned const size)
+static void riscv_introduce_epilogue(ir_node *const ret, unsigned const size, bool omit_fp)
{
ir_node *const block = get_nodes_block(ret);
- ir_node *const ret_sp = get_irn_n(ret, n_riscv_ret_stack);
- ir_node *const inc_sp = riscv_new_IncSP(block, ret_sp, -(int)size, 0);
- sched_add_before(ret, inc_sp);
- set_irn_n(ret, n_riscv_ret_stack, inc_sp);
+ if (!omit_fp) {
+ int const n_fp = be_get_input_pos_for_req(ret, &riscv_single_reg_req_gp_s0);
+ ir_node *curr_fp = get_irn_n(ret, n_fp);
+ ir_node *curr_mem = get_irn_n(ret, n_riscv_ret_mem);
+
+ /* Copy fp to sp */
+ ir_node *const curr_sp = be_new_Copy(block, curr_fp);
+ arch_set_irn_register(curr_sp, &riscv_registers[REG_SP]);
+ sched_add_before(ret, curr_sp);
+
+ /* restore old fp */
+ ir_node *const restore = new_bd_riscv_lw(NULL, block, curr_mem, curr_sp, NULL, -4);
+ curr_mem = be_new_Proj(restore, pn_riscv_lw_M);
+ curr_fp = be_new_Proj_reg(restore, pn_riscv_lw_res, &riscv_registers[REG_S0]);
+ sched_add_before(ret, restore);
+
+ set_irn_n(ret, n_fp, curr_fp);
+ set_irn_n(ret, n_riscv_ret_mem, curr_mem);
+ set_irn_n(ret, n_riscv_ret_stack, curr_sp);
+ } else {
+ ir_node *const ret_sp = get_irn_n(ret, n_riscv_ret_stack);
+ ir_node *const inc_sp = riscv_new_IncSP(block, ret_sp, -(int)size, 0);
+ sched_add_before(ret, inc_sp);
+ set_irn_n(ret, n_riscv_ret_stack, inc_sp);
+ }
+
}
-static void riscv_introduce_prologue_epilogue(ir_graph *const irg)
+static void riscv_introduce_prologue_epilogue(ir_graph *const irg, bool omit_fp)
{
ir_type *const frame = get_irg_frame_type(irg);
- unsigned const size = get_type_size(frame);
- if (size == 0)
+ unsigned size = get_type_size(frame);
+ if (size == 0 && omit_fp)
return;
+ if (!omit_fp) {
+ // additional slot for saved frame pointer
+ size += RISCV_MACHINE_SIZE / 8;
+ }
+
foreach_irn_in(get_irg_end_block(irg), i, ret) {
assert(is_riscv_ret(ret));
- riscv_introduce_epilogue(ret, size);
+ riscv_introduce_epilogue(ret, size, omit_fp);
}
- riscv_introduce_prologue(irg, size);
+ riscv_introduce_prologue(irg, size, omit_fp);
}
static void riscv_sp_sim(ir_node *const node, stack_pointer_state_t *const state)
@@ -228,9 +281,15 @@ static void riscv_sp_sim(ir_node *const node, stack_pointer_state_t *const state
ir_entity *const ent = imm->ent;
if (ent && is_frame_type(get_entity_owner(ent))) {
imm->ent = NULL;
- imm->val += state->offset + get_entity_offset(ent);
+ ir_graph *const irg = get_irn_irg(node);
+ if (riscv_get_irg_data(irg)->omit_fp) {
+ imm->val += state->offset;
+ } else if (!(arch_get_irn_flags(node) & (arch_irn_flags_t)riscv_arch_irn_flag_ignore_fp_offset_fix)) {
+ // consider additional slot for saved frame pointer
+ imm->val -= RISCV_MACHINE_SIZE / 8;
+ }
+ imm->val += get_entity_offset(ent);
}
- break;
}
default:
@@ -251,19 +310,25 @@ static void riscv_generate_code(FILE *const output, char const *const cup_name)
continue;
be_irg_t *const birg = be_birg_from_irg(irg);
+
+ struct obstack *obst = be_get_be_obst(irg);
+ birg->isa_link = OALLOCZ(obst, riscv_irg_data_t);
birg->non_ssa_regs = sp_is_non_ssa;
riscv_select_instructions(irg);
be_step_schedule(irg);
be_step_regalloc(irg, &riscv_regalloc_if);
- riscv_assign_spill_slots(irg);
+ riscv_irg_data_t const *const irg_data = riscv_get_irg_data(irg);
+ bool const omit_fp = irg_data->omit_fp;
+
+ riscv_assign_spill_slots(irg, omit_fp);
ir_type *const frame = get_irg_frame_type(irg);
- be_sort_frame_entities(frame, true);
+ be_sort_frame_entities(frame, omit_fp);
be_layout_frame_type(frame, 0, 0);
- riscv_introduce_prologue_epilogue(irg);
+ riscv_introduce_prologue_epilogue(irg, omit_fp);
be_fix_stack_nodes(irg, &riscv_registers[REG_SP]);
birg->non_ssa_regs = NULL;
be_sim_stack_pointer(irg, 0, RISCV_PO2_STACK_ALIGNMENT, &riscv_sp_sim);
diff --git a/ir/be/riscv/riscv_bearch_t.h b/ir/be/riscv/riscv_bearch_t.h
index 62b01f0..1068ee7 100644
--- a/ir/be/riscv/riscv_bearch_t.h
+++ b/ir/be/riscv/riscv_bearch_t.h
@@ -12,8 +12,18 @@
#include <stdbool.h>
#include <stdint.h>
+#include "beirg.h"
#include "firm_types.h"
+typedef struct riscv_irg_data_t {
+ bool omit_fp; /**< No frame pointer is used. */
+} riscv_irg_data_t;
+
+static inline riscv_irg_data_t *riscv_get_irg_data(const ir_graph *irg)
+{
+ return (riscv_irg_data_t*)be_birg_from_irg(irg)->isa_link;
+}
+
static inline bool is_uimm5(long const val)
{
return 0 <= val && val < 32;
diff --git a/ir/be/riscv/riscv_cconv.c b/ir/be/riscv/riscv_cconv.c
index a7bdd9d..349a5f9 100644
--- a/ir/be/riscv/riscv_cconv.c
+++ b/ir/be/riscv/riscv_cconv.c
@@ -3,11 +3,13 @@
* Copyright (C) 2018 Christoph Mallon.
*/
-#include "riscv_cconv.h"
-
+#include "be_t.h"
+#include "becconv.h"
#include "betranshlp.h"
#include "gen_riscv_regalloc_if.h"
+#include "irgwalk.h"
#include "riscv_bearch_t.h"
+#include "riscv_cconv.h"
#include "util.h"
static unsigned const regs_param_gp[] = {
@@ -26,8 +28,28 @@ static unsigned const regs_result_gp[] = {
REG_A1,
};
-void riscv_determine_calling_convention(riscv_calling_convention_t *const cconv, ir_type *const fun_type)
+static void check_omit_fp(ir_node *node, void *env)
{
+ /* omit-fp is not possible if:
+ * - we have allocations on the stack
+ */
+ if (is_Alloc(node) || is_Free(node)) {
+ bool *can_omit_fp = (bool*) env;
+ *can_omit_fp = false;
+ }
+}
+
+void riscv_determine_calling_convention(riscv_calling_convention_t *const cconv, ir_type *const fun_type,
+ ir_graph *const irg)
+{
+ bool omit_fp = false;
+ if (irg != NULL) {
+ omit_fp = be_options.omit_fp;
+ if (omit_fp)
+ irg_walk_graph(irg, check_omit_fp, NULL, &omit_fp);
+ riscv_get_irg_data(irg)->omit_fp = omit_fp;
+ }
+
/* Handle parameters. */
riscv_reg_or_slot_t *params = NULL;
size_t gp_param = 0;
@@ -78,6 +100,13 @@ void riscv_determine_calling_convention(riscv_calling_convention_t *const cconv,
}
}
cconv->results = results;
+
+ if (irg != NULL) {
+ be_irg_t *birg = be_birg_from_irg(irg);
+ if (!omit_fp)
+ rbitset_clear(birg->allocatable_regs, REG_S0); // s0 = frame pointer
+ }
+ cconv->omit_fp = omit_fp;
}
void riscv_layout_parameter_entities(riscv_calling_convention_t *const cconv, ir_graph *const irg)
diff --git a/ir/be/riscv/riscv_cconv.h b/ir/be/riscv/riscv_cconv.h
index d0b0819..6763d1c 100644
--- a/ir/be/riscv/riscv_cconv.h
+++ b/ir/be/riscv/riscv_cconv.h
@@ -6,6 +6,7 @@
#ifndef FIRM_BE_RISCV_RISCV_CCONV_H
#define FIRM_BE_RISCV_RISCV_CCONV_H
+#include <stdbool.h>
#include "be_types.h"
typedef struct riscv_reg_or_slot_t {
@@ -15,13 +16,15 @@ typedef struct riscv_reg_or_slot_t {
} riscv_reg_or_slot_t;
typedef struct riscv_calling_convention_t {
+ bool omit_fp; /**< do not use frame pointer (and no
+ save/restore) */
unsigned param_stack_size;
unsigned n_mem_param;
riscv_reg_or_slot_t *parameters;
riscv_reg_or_slot_t *results;
} riscv_calling_convention_t;
-void riscv_determine_calling_convention(riscv_calling_convention_t *cconv, ir_type *fun_type);
+void riscv_determine_calling_convention(riscv_calling_convention_t *cconv, ir_type *fun_type, ir_graph *irg);
void riscv_layout_parameter_entities(riscv_calling_convention_t *cconv, ir_graph *irg);
diff --git a/ir/be/riscv/riscv_new_nodes.c b/ir/be/riscv/riscv_new_nodes.c
index 0930dc9..5b6aa84 100644
--- a/ir/be/riscv/riscv_new_nodes.c
+++ b/ir/be/riscv/riscv_new_nodes.c
@@ -60,7 +60,10 @@ static void dump_immediate(FILE *const F, char const *const prefix, ir_node cons
fputc(' ', F);
if (prefix)
fprintf(F, "%s(", prefix);
- fputs(get_entity_name(imm->ent), F);
+ const char *name = get_entity_name(imm->ent);
+ if (name) {
+ fputs(name, F);
+ }
if (imm->val != 0)
fprintf(F, "%+" PRId32, imm->val);
if (prefix)
diff --git a/ir/be/riscv/riscv_nodes_attr.h b/ir/be/riscv/riscv_nodes_attr.h
index 931aba8..794635e 100644
--- a/ir/be/riscv/riscv_nodes_attr.h
+++ b/ir/be/riscv/riscv_nodes_attr.h
@@ -14,6 +14,10 @@ typedef struct riscv_attr_t {
except_attr exc; /**< the exception attribute. MUST be the first one. */
} riscv_attr_t;
+enum riscv_arch_irn_flags_t {
+ riscv_arch_irn_flag_ignore_fp_offset_fix = arch_irn_flag_backend << 0,
+};
+
typedef enum riscv_cond_t {
/* Flipping the lowest bit negates the condition. */
riscv_cc_eq,
diff --git a/ir/be/riscv/riscv_transform.c b/ir/be/riscv/riscv_transform.c
index 2d4a843..7502fbd 100644
--- a/ir/be/riscv/riscv_transform.c
+++ b/ir/be/riscv/riscv_transform.c
@@ -63,6 +63,11 @@ static ir_node *get_Start_sp(ir_graph *const irg)
return be_get_Start_proj(irg, &riscv_registers[REG_SP]);
}
+static ir_node *get_Start_fp(ir_graph *const irg)
+{
+ return be_get_Start_proj(irg, &riscv_registers[REG_S0]);
+}
+
ir_node *get_Start_zero(ir_graph *const irg)
{
return be_get_Start_proj(irg, &riscv_registers[REG_ZERO]);
@@ -311,7 +316,7 @@ static ir_node *gen_Alloc(ir_node *node)
long const sizel = get_Const_long(size);
assert((sizel & ((1<<RISCV_PO2_STACK_ALIGNMENT) - 1)) == 0 && "Found Alloc with misaligned constant");
assert(is_simm12(sizel));
- subsp = new_bd_riscv_SubSPimm(dbgi, new_block, new_mem, stack_pred, NULL, sizel);
+ subsp = new_bd_riscv_SubSPimm(dbgi, new_block, new_mem, stack_pred, NULL, -sizel);
} else {
ir_node *new_size = be_transform_node(size);
subsp = new_bd_riscv_SubSP(dbgi, new_block, new_mem, stack_pred, new_size);
@@ -425,7 +430,7 @@ static ir_node *gen_Call(ir_node *const node)
record_returns_twice(irg, fun_type);
riscv_calling_convention_t cconv;
- riscv_determine_calling_convention(&cconv, fun_type);
+ riscv_determine_calling_convention(&cconv, fun_type, NULL);
ir_node *mems[1 + cconv.n_mem_param];
unsigned m = 0;
@@ -905,7 +910,7 @@ static ir_node *gen_Proj_Proj_Call(ir_node *const node)
ir_type *const fun_type = get_Call_type(ocall);
riscv_calling_convention_t cconv;
- riscv_determine_calling_convention(&cconv, fun_type);
+ riscv_determine_calling_convention(&cconv, fun_type, NULL);
ir_node *const call = be_transform_node(ocall);
unsigned const num = get_Proj_num(node);
@@ -930,8 +935,9 @@ static ir_node *gen_Proj_Proj_Start(ir_node *const node)
dbg_info *const dbgi = get_irn_dbg_info(node);
ir_node *const block = be_transform_nodes_block(node);
ir_node *const mem = be_get_Start_mem(irg);
- ir_node *const base = get_Start_sp(irg);
+ ir_node *const base = cur_cconv.omit_fp ? get_Start_sp(irg) : get_Start_fp(irg);
ir_node *const load = new_bd_riscv_lw(dbgi, block, mem, base, param->entity, 0);
+ arch_add_irn_flags(load, (arch_irn_flags_t)riscv_arch_irn_flag_ignore_fp_offset_fix);
return be_new_Proj(load, pn_riscv_lw_res);
}
}
@@ -952,7 +958,7 @@ static ir_node *gen_Proj_Start(ir_node *const node)
ir_graph *const irg = get_irn_irg(node);
switch ((pn_Start)get_Proj_num(node)) {
case pn_Start_M: return be_get_Start_mem(irg);
- case pn_Start_P_frame_base: return get_Start_sp(irg);
+ case pn_Start_P_frame_base: return cur_cconv.omit_fp ? get_Start_sp(irg): get_Start_fp(irg);
case pn_Start_T_args: return new_r_Bad(irg, mode_T);
}
panic("unexpected Proj");
@@ -1073,6 +1079,8 @@ static ir_node *gen_Start(ir_node *const node)
if (reg)
outs[reg->global_index] = BE_START_REG;
}
+ if (!cur_cconv.omit_fp)
+ outs[REG_S0] = BE_START_IGNORE;
return be_new_Start(irg, outs);
}
@@ -1229,7 +1237,7 @@ void riscv_transform_graph(ir_graph *const irg)
ir_entity *const fun_ent = get_irg_entity(irg);
ir_type *const fun_type = get_entity_type(fun_ent);
- riscv_determine_calling_convention(&cur_cconv, fun_type);
+ riscv_determine_calling_convention(&cur_cconv, fun_type, irg);
riscv_layout_parameter_entities(&cur_cconv, irg);
be_add_parameter_entity_stores(irg);
be_transform_graph(irg, NULL);