summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonas Haag <jonas@lophus.org>2015-12-18 15:46:57 +0100
committerPhilipp Serrer <philipp@serrer.de>2018-01-18 17:54:10 +0100
commit5af5cf6fcde6bea4bce1cba091861bdc187ccf71 (patch)
treeff833956159631a67c6b31fc46173fe00e233b69
parent765a4a271bb2832e503bf82d59bd031b15abc518 (diff)
Emit jump after non-fallthrough throwing Call
If a Call's X_regular block isn't fallthrough (which isn't guaranteed to be the case), we need to emit a "jmp" instruction to that block after the "call" instruction.
-rw-r--r--ir/be/ia32/ia32_emitter.c29
-rw-r--r--ir/be/ia32/ia32_spec.pl1
2 files changed, 29 insertions, 1 deletions
diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c
index c234ac6..580b5e7 100644
--- a/ir/be/ia32/ia32_emitter.c
+++ b/ir/be/ia32/ia32_emitter.c
@@ -653,6 +653,11 @@ static void ia32_emit_exc_label(const ir_node *node)
be_emit_irprintf("%lu", get_ia32_exc_label_id(node));
}
+static bool fallthrough_possible(const ir_node *block, const ir_node *target)
+{
+ return be_emit_get_prev_block(target) == block;
+}
+
/**
* Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
*/
@@ -1168,6 +1173,29 @@ static void emit_ia32_Return(const ir_node *node)
}
}
+static void emit_ia32_Call(const ir_node *node)
+{
+ ia32_emitf(node, "call %*AS3");
+
+ if (is_cfop(node)) {
+ /* If the call throws we have to add a jump to its X_regular block. */
+ const ir_node* const block = get_nodes_block(node);
+ const ir_node* const x_regular_proj = get_Proj_for_pn(node, node->op->pn_x_regular);
+ if (x_regular_proj == NULL) {
+ /* Call always throws and/or never returns. */
+ } else {
+ const ir_node* const x_regular_block = be_emit_get_cfop_target(x_regular_proj);
+ assert(x_regular_block != NULL);
+ if (fallthrough_possible(block, x_regular_block)) {
+ if (be_options.verbose_asm)
+ ia32_emitf(x_regular_proj, "/* fallthrough to %L */");
+ } else {
+ ia32_emitf(x_regular_proj, "jmp %L");
+ }
+ }
+ }
+}
+
/**
* Enters the emitter functions for handled nodes into the generic
* pointer of an opcode.
@@ -1196,6 +1224,7 @@ static void ia32_register_emitters(void)
be_set_emitter(op_ia32_Minus64, emit_ia32_Minus64);
be_set_emitter(op_ia32_Setcc, emit_ia32_Setcc);
be_set_emitter(op_ia32_SwitchJmp, emit_ia32_SwitchJmp);
+ be_set_emitter(op_ia32_Call, emit_ia32_Call);
}
/**
diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl
index 6bbe395..7899cca 100644
--- a/ir/be/ia32/ia32_spec.pl
+++ b/ir/be/ia32/ia32_spec.pl
@@ -1251,7 +1251,6 @@ Call => {
ins => [ "base", "index", "mem", "callee", "stack", "first_argument" ],
outs => [ "mem", "stack", "X_regular", "X_except", "first_result" ],
fixed => "x86_insn_size_t const size = X86_SIZE_32;",
- emit => "call %*AS3",
attr_type => "ia32_call_attr_t",
attr => "uint8_t pop, uint8_t n_reg_results",
am => "source,unary",