summaryrefslogtreecommitdiffhomepage
path: root/ir/be
diff options
context:
space:
mode:
authorJohannes Bucher <johannes.bucher2@student.kit.edu>2019-06-19 14:48:31 +0200
committerJohannes Bucher <johannes.bucher2@student.kit.edu>2019-06-19 16:00:35 +0200
commit201602dcf9059d2353443caa521289496eff0216 (patch)
treee9f70d9c5f7835c7e94c7edc95945f8dcfa5236c /ir/be
parent7d4909a9bbab9b2573d6e8d674c286152cc68abc (diff)
riscv: add emit function for be_MemPerm nodes
uses a simple approach similar to the arm backend: save registers on the stack, load MemPerm ins in registers, write them back and restore the registers.
Diffstat (limited to 'ir/be')
-rw-r--r--ir/be/riscv/riscv_bearch.c9
-rw-r--r--ir/be/riscv/riscv_emitter.c50
2 files changed, 59 insertions, 0 deletions
diff --git a/ir/be/riscv/riscv_bearch.c b/ir/be/riscv/riscv_bearch.c
index edb78f4..0d6f291 100644
--- a/ir/be/riscv/riscv_bearch.c
+++ b/ir/be/riscv/riscv_bearch.c
@@ -305,6 +305,15 @@ static void riscv_introduce_prologue_epilogue(ir_graph *const irg, bool omit_fp)
static void riscv_sp_sim(ir_node *const node, stack_pointer_state_t *const state)
{
+ if (be_is_MemPerm(node)) {
+ ir_graph *irg = get_irn_irg(node);
+ if (riscv_get_irg_data(irg)->omit_fp) {
+ be_set_MemPerm_offset(node, state->offset);
+ } else {
+ be_set_MemPerm_offset(node, -RISCV_REGISTER_SIZE);
+ }
+ return;
+ }
if (is_riscv_irn(node)) {
switch ((riscv_opcodes)get_riscv_irn_opcode(node)) {
case iro_riscv_addi:
diff --git a/ir/be/riscv/riscv_emitter.c b/ir/be/riscv/riscv_emitter.c
index b794f57..8951797 100644
--- a/ir/be/riscv/riscv_emitter.c
+++ b/ir/be/riscv/riscv_emitter.c
@@ -209,6 +209,55 @@ static void emit_be_Perm(ir_node const *const node)
}
}
+static void emit_be_MemPerm(ir_node const *const node)
+{
+ /* TODO: this implementation is slower than necessary. */
+
+ bool const omit_fp = riscv_get_irg_data(get_irn_irg(node))->omit_fp;
+ int const memperm_arity = be_get_MemPerm_entity_arity(node);
+ int const max_arity = 23;
+ if (memperm_arity > max_arity)
+ panic("memperm with more than %d inputs not supported yet", max_arity);
+
+ char const *const frame_base = omit_fp ? "sp" : "fp";
+
+ int const memperm_offset = be_get_MemPerm_offset(node);
+ int ent_offset = memperm_offset;
+
+ riscv_emitf(node, "addi\tsp, sp, -%d", memperm_arity * RISCV_REGISTER_SIZE);
+ for (int i = 0; i < memperm_arity; ++i) {
+ /* spill register */
+ arch_register_t const *const reg = arch_register_for_index(&riscv_reg_classes[CLASS_riscv_gp], i + 9);
+
+ riscv_emitf(node, "sw\t%s, %d(sp)", reg->name, i * RISCV_REGISTER_SIZE);
+
+ /* load from entity */
+ ir_entity *entity = be_get_MemPerm_in_entity(node, i);
+ int offset = get_entity_offset(entity) + ent_offset;
+ if (omit_fp) {
+ offset += (memperm_arity * RISCV_REGISTER_SIZE);
+ }
+ riscv_emitf(node, "lw\t%s, %d(%s)", reg->name, offset, frame_base);
+ ent_offset += 4;
+ }
+
+ for (int i = memperm_arity; i-- > 0; ) {
+ /* store to new entity */
+ ent_offset -= 4;
+ ir_entity *entity = be_get_MemPerm_out_entity(node, i);
+ int offset = get_entity_offset(entity) + ent_offset;
+ if (omit_fp) {
+ offset += (memperm_arity * RISCV_REGISTER_SIZE);
+ }
+ arch_register_t const *const reg = arch_register_for_index(&riscv_reg_classes[CLASS_riscv_gp], i + 9);
+ riscv_emitf(node, "sw\t%s, %d(%s)", reg->name, offset, frame_base);
+ /* restore register */
+ riscv_emitf(node, "lw\t%s, %d(sp)", reg->name, i * RISCV_REGISTER_SIZE);
+ }
+ riscv_emitf(node, "addi\tsp, sp, %d", memperm_arity * RISCV_REGISTER_SIZE);
+ assert(ent_offset == memperm_offset);
+}
+
static void emit_riscv_bcc(ir_node const *const node)
{
riscv_cond_t const cond = get_riscv_cond_attr_const(node)->cond;
@@ -274,6 +323,7 @@ static void riscv_register_emitters(void)
be_set_emitter(op_be_Copy, emit_be_Copy);
be_set_emitter(op_be_IncSP, emit_be_IncSP);
be_set_emitter(op_be_Perm, emit_be_Perm);
+ be_set_emitter(op_be_MemPerm, emit_be_MemPerm);
be_set_emitter(op_riscv_FrameAddr, emit_riscv_FrameAddr);
be_set_emitter(op_riscv_bcc, emit_riscv_bcc);
be_set_emitter(op_riscv_j, emit_riscv_j);