summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonas Haag <jonas@lophus.org>2016-02-03 01:09:01 +0100
committerPhilipp Serrer <philipp@serrer.de>2018-01-18 18:35:03 +0100
commite10c2412dc428a4cdc3edecb1bf80c4060bc6048 (patch)
tree97ad553099b1c2b3b9aad495daa0e72871e47d9b
parent089e0c083e7983e28f09ac44b3b26b42c28aff92 (diff)
New exception label infrastructure
This is a reimplementation of the unfinished ia32 exception label code.
-rw-r--r--ir/be/amd64/amd64_emitter.c34
-rw-r--r--ir/be/amd64/amd64_transform.c1
-rw-r--r--ir/be/beexc.c168
-rw-r--r--ir/be/beexc.h74
-rw-r--r--ir/be/ia32/ia32_emitter.c151
-rw-r--r--ir/be/ia32/ia32_new_nodes.c28
-rw-r--r--ir/be/ia32/ia32_transform.c13
-rw-r--r--ir/ir/irgraph_t.h2
-rw-r--r--ir/ir/irnode.c4
-rw-r--r--ir/ir/irnode_t.h19
10 files changed, 318 insertions, 176 deletions
diff --git a/ir/be/amd64/amd64_emitter.c b/ir/be/amd64/amd64_emitter.c
index 1aec65c..d96bee7 100644
--- a/ir/be/amd64/amd64_emitter.c
+++ b/ir/be/amd64/amd64_emitter.c
@@ -12,16 +12,19 @@
#include "amd64_bearch_t.h"
#include "amd64_new_nodes.h"
#include "amd64_nodes_attr.h"
-#include "be_t.h"
+#include "bearch.h"
#include "beasm.h"
#include "beblocksched.h"
#include "bediagnostic.h"
#include "beemithlp.h"
#include "beemitter.h"
+#include "beexc.h"
#include "begnuas.h"
#include "beirg.h"
#include "benode.h"
#include "besched.h"
+#include "bestack.h"
+#include "be_t.h"
#include "gen_amd64_emitter.h"
#include "gen_amd64_regalloc_if.h"
#include "iredges_t.h"
@@ -608,6 +611,9 @@ static void emit_amd64_call(const ir_node* node)
{
amd64_emitf(node, "call %*AM");
+ if (be_options.exceptions)
+ be_exc_emit_irn_label(node);
+
if (is_cfop(node)) {
/* If the call throws we have to add a jump to its X_regular block. */
const ir_node* const x_regular_proj = get_Proj_for_pn(node, node->op->pn_x_regular);
@@ -883,25 +889,24 @@ static void amd64_gen_block(ir_node *block)
void amd64_emit_function(ir_graph *irg)
{
- const ir_entity *const entity = get_irg_entity(irg);
-
/* register all emitter functions */
amd64_register_emitters();
ir_node *const *const blk_sched = be_create_block_schedule(irg);
- be_gas_emit_function_prolog(entity, 4, NULL);
-
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
be_emit_init_cf_links(blk_sched);
- amd64_irg_data_t const *const irg_data = amd64_get_irg_data(irg);
- omit_fp = irg_data->omit_fp;
+ const ir_entity *const entity = get_irg_entity(irg);
+ be_gas_emit_function_prolog(entity, 4, NULL);
+ if (be_options.exceptions) {
+ be_exc_init(entity, blk_sched);
+ be_exc_emit_function_prolog();
+ }
+ bool omit_fp = amd64_get_irg_data(irg)->omit_fp;
if (omit_fp) {
- ir_type *frame_type = get_irg_frame_type(irg);
- frame_type_size = get_type_size(frame_type);
be_dwarf_callframe_register(&amd64_registers[REG_RSP]);
} else {
/* well not entirely correct here, we should emit this after the
@@ -912,11 +917,20 @@ void amd64_emit_function(ir_graph *irg)
be_dwarf_callframe_spilloffset(&amd64_registers[REG_RBP], -16);
}
+ /* register all emitter functions */
+ amd64_register_emitters();
+
for (size_t i = 0, n = ARR_LEN(blk_sched); i < n; ++i) {
- ir_node *block = blk_sched[i];
+ ir_node *const block = blk_sched[i];
amd64_gen_block(block);
}
+
ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
+ if (be_options.exceptions) {
+ be_exc_emit_table();
+ be_exc_finish();
+ }
+
be_gas_emit_function_epilog(entity);
}
diff --git a/ir/be/amd64/amd64_transform.c b/ir/be/amd64/amd64_transform.c
index 6433f94..a0b65e5 100644
--- a/ir/be/amd64/amd64_transform.c
+++ b/ir/be/amd64/amd64_transform.c
@@ -2038,6 +2038,7 @@ static ir_node *gen_Proj_Call(ir_node *const node)
case pn_Call_X_regular:
return be_new_Proj(new_call, pn_amd64_call_X_regular);
case pn_Call_X_except:
+ set_needs_exc_label(new_call, true);
return be_new_Proj(new_call, pn_amd64_call_X_except);
case pn_Call_T_result:
break;
diff --git a/ir/be/beexc.c b/ir/be/beexc.c
new file mode 100644
index 0000000..9328104
--- /dev/null
+++ b/ir/be/beexc.c
@@ -0,0 +1,168 @@
+#include "irnode_t.h"
+#include "irnodehashmap.h"
+#include "irgwalk.h"
+#include "iredges_t.h"
+#include "be_t.h"
+#include "beemitter.h"
+#include "besched.h"
+#include "begnuas.h"
+#include "beexc.h"
+#include "util.h"
+
+/** Representation of an entry in the exception table. */
+typedef struct exc_entry {
+ ir_node *instr; /** The instruction that can issue an exception. */
+ ir_node *x_except_block; /** The instruction's X_except block */
+ ir_label_t label; /** The exception label. */
+} exc_entry;
+
+/* Counter; the next exception label to be assigned. */
+static ir_label_t next_exc_label;
+/* Current graph we're dealing with. */
+static ir_entity const *irg_entity = NULL;
+/* The graph's exception entry list. */
+static exc_entry *exc_list = NULL;
+/* Map of ir_node* -> exc_entry (actually bijective). */
+static ir_nodehashmap_t node_exc_map;
+
+static void check_initialized(void)
+{
+ assert(irg_entity != NULL && "beexc not initialized");
+}
+
+/**
+ * Collect list of exception entries in ascending instruction address ordering.
+ */
+static void collect_exception_entries(ir_node *const *const schedule)
+{
+ /* We MUST walk this in schedule order (by contract) */
+ for (size_t i = 0, n = ARR_LEN(schedule); i < n; ++i) {
+ ir_node *const block = schedule[i];
+ sched_foreach(block, node) {
+ if (!needs_exc_label(node))
+ continue;
+
+ /* Find X_except block. */
+ ir_node const *const proj = get_Proj_for_pn(node, node->op->pn_x_except);
+ assert(get_irn_n_edges(proj) == 1);
+ assert(get_irn_n_edges_kind(proj, EDGE_KIND_BLOCK) == 0);
+ ir_node *const except_block = get_edge_src_irn(get_irn_out_edge_first(proj));
+
+ if (!is_x_except_block(except_block))
+ /* End block */
+ continue;
+
+ /* Add exc_entry to list. */
+ exc_entry e = {
+ .instr = node,
+ .x_except_block = except_block,
+ .label = next_exc_label++
+ };
+ ARR_APP1(exc_entry, exc_list, e);
+ }
+ }
+}
+
+/** Emit "__foobar_LSDA". */
+static void emit_function_lsda_name(const ir_entity *const function_entity)
+{
+ be_emit_cstring("__");
+ be_gas_emit_entity(function_entity);
+ be_emit_cstring("_LSDA");
+}
+
+void be_exc_emit_function_prolog(void)
+{
+ if (!ARR_LEN(exc_list))
+ /* No X_except blocks in this irg */
+ return;
+
+ be_emit_cstring("\t.cfi_personality 0x0, " FIRM_PERSONALITY_NAME "\n");
+ be_emit_write_line();
+ be_emit_cstring("\t.cfi_lsda 0x0, ");
+ emit_function_lsda_name(irg_entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+}
+
+/**
+ * Emit an exception label name ("LE123").
+ */
+static void emit_label_name(const ir_label_t label)
+{
+ be_emit_string(be_gas_insn_label_prefix());
+ be_emit_irprintf("%lu", label);
+}
+
+void be_exc_emit_irn_label(const ir_node *const node)
+{
+ check_initialized();
+
+ exc_entry* entry = ir_nodehashmap_get(exc_entry, &node_exc_map, node);
+ if (entry != NULL) {
+ emit_label_name(entry->label);
+ be_emit_char(':');
+ be_emit_write_line();
+ }
+}
+
+void be_exc_emit_table(void)
+{
+ check_initialized();
+
+ size_t n_exc = ARR_LEN(exc_list);
+
+ if (!n_exc)
+ /* No X_except blocks in this irg */
+ return;
+
+ emit_function_lsda_name(irg_entity);
+ be_emit_cstring(":\n");
+ be_emit_write_line();
+
+ if (be_options.verbose_asm) {
+ be_emit_cstring("\t/* Number of entries */\n");
+ be_emit_write_line();
+ }
+ be_emit_irprintf("\t.quad %lu\n", n_exc);
+ be_emit_write_line();
+
+ for (size_t i = 0; i < ARR_LEN(exc_list); ++i) {
+ if (be_options.verbose_asm) {
+ be_emit_irprintf("\t/* Handler for %+F: %+F */\n", exc_list[i].instr, exc_list[i].x_except_block);
+ be_emit_write_line();
+ }
+ be_emit_cstring("\t.quad ");
+ emit_label_name(exc_list[i].label);
+ be_emit_char('\n');
+ be_emit_cstring("\t.quad ");
+ be_gas_emit_block_name(exc_list[i].x_except_block);
+ be_emit_char('\n');
+ }
+}
+
+void be_exc_init(ir_entity const* irg_entity2, ir_node *const *const schedule)
+{
+ irg_entity = irg_entity2;
+
+ exc_list = NEW_ARR_F(exc_entry, 0);
+ collect_exception_entries(schedule);
+
+ /* Build node -> exc_entry map. Note that the exc_list MUST NOT be changed
+ * (e.g., sorted) after building this map; otherwise the exc_entry*
+ * pointers stored in the map may point to the wrong entry or be invalid
+ * entirely. */
+ ir_nodehashmap_init(&node_exc_map);
+ for (size_t i = 0; i < ARR_LEN(exc_list); ++i) {
+ ir_nodehashmap_insert(&node_exc_map, exc_list[i].instr, &exc_list[i]);
+ }
+}
+
+void be_exc_finish(void)
+{
+ check_initialized();
+ DEL_ARR_F(exc_list);
+ ir_nodehashmap_destroy(&node_exc_map);
+ irg_entity = NULL;
+ exc_list = NULL;
+}
diff --git a/ir/be/beexc.h b/ir/be/beexc.h
new file mode 100644
index 0000000..c64caba
--- /dev/null
+++ b/ir/be/beexc.h
@@ -0,0 +1,74 @@
+/** Common infrastructure for generating and emitting exception tables in backends.
+ *
+ * This module implements a map between throwing nodes (e.g. Call) and their
+ * respective X_except blocks ("landing pads"). The map may be used by
+ * exception handling (e.g., unwinding using libunwind) to obtain the catch
+ * block that should be jumped to for a specific node that has thrown a runtime
+ * exception.
+ *
+ * The mapping is constructed by walking a function's schedule and assigning a
+ * unique assembly label to each throwing node ("be_exc_init").
+ *
+ * The backend is responsible for emission of these labels *after* the assembly
+ * instruction of the throwing node ("be_exc_emit_irn_label"). Example:
+ *
+ * main:
+ * ...
+ * call some_throwing_function
+ * .LE123: ...
+ *
+ * At the beginning of each function that contains a throwing node, a reference
+ * to the function's exception table must be made ("be_exc_emit_function_prolog").
+ *
+ * At the end of each function that contains a throwing node, that function's
+ * exception table should be emitted ("be_exc_emit_table"). The exception
+ * table layout is as follows:
+ *
+ * .quad <number of entries that follow>
+ * .quad <node 1 label> <node 1 X_except block label>
+ * [...]
+ * .quad <node N label> <node N X_except block label>
+ *
+ * Entries are in order of the schedule given to "be_exc_init", i.e. if an
+ * instruction is placed "before" another in the assembler code, its exception
+ * table entry is also placed before the other instruction's. In other words,
+ * exception table entries are ascending in the ("instruction pointer") address
+ * of the "node" column. This allows for binary search when looking for the
+ * exception table entry for a certain instruction pointer.
+ *
+ * After exception table emission, this module's internal state must be cleaned
+ * up using "be_exc_finish".
+ */
+#include "firm_types.h"
+
+#define FIRM_PERSONALITY_NAME "firm_personality"
+
+/**
+ * Initialize beexc and assign exception labels to any nodes in the schedule that
+ * have "needs_exc_label" set.
+ * @param irg_entity The ir_entity of the function graph. This is used for
+ * generating labels.
+ * @param schedule The block schedule.
+ */
+void be_exc_init(ir_entity const *irg_entity, ir_node *const *const schedule);
+
+/**
+ * Clean up beexc.
+ */
+void be_exc_finish(void);
+
+/**
+ * Emit exception handling setup function prolog.
+ */
+void be_exc_emit_function_prolog(void);
+
+/**
+ * Emit an exception label ("LE123:") for the given node.
+ */
+void be_exc_emit_irn_label(const ir_node*);
+
+/**
+ * Emit the exception table for the graph.
+ * This calls "emit_entry" for every exception table entry.
+ */
+void be_exc_emit_table(void);
diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c
index 52d7ba5..8ab889c 100644
--- a/ir/be/ia32/ia32_emitter.c
+++ b/ir/be/ia32/ia32_emitter.c
@@ -38,6 +38,7 @@
#include "besched.h"
#include "bestack.h"
#include "beutil.h"
+#include "beexc.h"
#include "debug.h"
#include "execfreq.h"
#include "gen_ia32_emitter.h"
@@ -58,7 +59,6 @@
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
static char pic_base_label[128];
-static ir_label_t exc_label_id;
static bool omit_fp;
static int frame_type_size;
@@ -74,6 +74,11 @@ typedef enum get_ip_style_t {
static int get_ip_style = IA32_GET_IP_THUNK;
/** Checks if the current block is a fall-through target. */
+static bool fallthrough_possible(const ir_node *source_block, const ir_node *target_block)
+{
+ return be_emit_get_prev_block(target_block) == source_block;
+}
+
static bool is_fallthrough(const ir_node *cfgpred)
{
if (!is_Proj(cfgpred))
@@ -644,20 +649,6 @@ x86_condition_code_t ia32_determine_final_cc(ir_node const *const node,
}
/**
- * Emits an exception label for a given node.
- */
-static void ia32_emit_exc_label(const ir_node *node)
-{
- be_emit_string(be_gas_insn_label_prefix());
- 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)
*/
static void emit_ia32_Jcc(const ir_node *node)
@@ -1176,6 +1167,9 @@ static void emit_ia32_Call(const ir_node *node)
{
ia32_emitf(node, "call %*AS3");
+ if (be_options.exceptions)
+ be_exc_emit_irn_label(node);
+
if (is_cfop(node)) {
/* If the call throws we have to add a jump to its X_regular block. */
const ir_node* const x_regular_proj = get_Proj_for_pn(node, node->op->pn_x_regular);
@@ -1224,34 +1218,12 @@ static void ia32_register_emitters(void)
}
/**
- * Assign and emit an exception label if the current instruction can fail.
- */
-static void ia32_assign_exc_label(ir_node *node)
-{
- /* assign a new ID to the instruction */
- set_ia32_exc_label_id(node, ++exc_label_id);
- /* print it */
- ia32_emit_exc_label(node);
- be_emit_char(':');
- be_emit_pad_comment();
- be_emit_cstring("/* exception to Block ");
- be_emit_cfop_target(node);
- be_emit_cstring(" */\n");
- be_emit_write_line();
-}
-
-/**
* Emits code for a node.
*/
static void ia32_emit_node(ir_node *node)
{
DBG((dbg, LEVEL_1, "emitting code for %+F\n", node));
- /* emit the exception label of this instruction */
- if (is_ia32_irn(node) && get_ia32_exc_label(node)) {
- ia32_assign_exc_label(node);
- }
-
be_emit_node(node);
if (omit_fp) {
@@ -1382,79 +1354,12 @@ static void ia32_gen_block(ir_node *block)
}
}
-typedef struct exc_entry {
- ir_node *exc_instr; /** The instruction that can issue an exception. */
- ir_node *block; /** The block to call then. */
-} exc_entry;
-
-/**
- * Block-walker:
- * Sets labels for control flow nodes (jump target).
- * Links control predecessors to there destination blocks.
- */
-static void ia32_gen_labels(ir_node *block, void *data)
-{
- exc_entry **exc_list = (exc_entry**)data;
- for (unsigned n = get_Block_n_cfgpreds(block); n-- > 0; ) {
- ir_node *pred = get_Block_cfgpred(block, n);
-
- pred = skip_Proj(pred);
- if (is_ia32_irn(pred) && get_ia32_exc_label(pred) && exc_list != NULL) {
- exc_entry e;
-
- e.exc_instr = pred;
- e.block = block;
- ARR_APP1(exc_entry, *exc_list, e);
- set_irn_link(pred, block);
- }
- }
-}
-
-/**
- * Compare two exception_entries.
- */
-static int cmp_exc_entry(const void *a, const void *b)
-{
- const exc_entry *ea = (const exc_entry*)a;
- const exc_entry *eb = (const exc_entry*)b;
- if (get_ia32_exc_label_id(ea->exc_instr) < get_ia32_exc_label_id(eb->exc_instr))
- return -1;
- return +1;
-}
-
-static parameter_dbg_info_t *construct_parameter_infos(ir_graph *irg)
-{
- ir_entity *entity = get_irg_entity(irg);
- ir_type *type = get_entity_type(entity);
- ir_type *frame_type = get_irg_frame_type(irg);
- size_t n_params = get_method_n_params(type);
- parameter_dbg_info_t *infos = XMALLOCNZ(parameter_dbg_info_t, n_params);
-
- for (size_t i = 0, n_members = get_compound_n_members(frame_type);
- i < n_members; ++i) {
- ir_entity *member = get_compound_member(frame_type, i);
- if (!is_parameter_entity(member))
- continue;
- size_t param = get_entity_parameter_number(member);
- if (param == IR_VA_START_PARAMETER_NUMBER)
- continue;
- assert(infos[param].entity == NULL && infos[param].reg == NULL);
- infos[param].reg = NULL;
- infos[param].entity = member;
- }
-
- return infos;
-}
-
-static void emit_function_text(ir_graph *const irg, exc_entry **const exc_list)
+static void emit_function_text(ir_graph *const irg, ir_node *const *const blk_sched)
{
ia32_register_emitters();
- ir_node **const blk_sched = be_create_block_schedule(irg);
-
/* we use links to point to target blocks */
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
- irg_block_walk_graph(irg, ia32_gen_labels, NULL, exc_list);
be_emit_init_cf_links(blk_sched);
@@ -1511,13 +1416,11 @@ static unsigned emit_jit_entity_relocation_asm(char *const buffer,
void ia32_emit_function(ir_graph *const irg)
{
- exc_entry *exc_list = NEW_ARR_F(exc_entry, 0);
be_gas_elf_type_char = '@';
+ get_unique_label(pic_base_label, sizeof(pic_base_label), "PIC_BASE");
ir_entity *const entity = get_irg_entity(irg);
- parameter_dbg_info_t *infos = construct_parameter_infos(irg);
- be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment, infos);
- free(infos);
+ be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment, NULL);
omit_fp = ia32_get_irg_data(irg)->omit_fp;
if (omit_fp) {
@@ -1533,9 +1436,6 @@ void ia32_emit_function(ir_graph *const irg)
be_dwarf_callframe_spilloffset(&ia32_registers[REG_EBP], -8);
}
- get_unique_label(pic_base_label, sizeof(pic_base_label), "PIC_BASE");
- x86_pic_base_label = pic_base_label;
-
if (ia32_cg_config.emit_machcode) {
/* For debugging we can jit the code and output it embedded into a
* normal .s file with .byte directives etc. */
@@ -1544,23 +1444,22 @@ void ia32_emit_function(ir_graph *const irg)
be_jit_emit_as_asm(function, emit_jit_entity_relocation_asm);
be_destroy_jit_segment(segment);
} else {
- emit_function_text(irg, &exc_list);
- }
+ ir_node *const *const blk_sched = be_create_block_schedule(irg);
- be_gas_emit_function_epilog(entity);
+ if (be_options.exceptions) {
+ be_exc_init(entity, blk_sched);
+ be_exc_emit_function_prolog();
+ }
- /* Sort the exception table using the exception label id's.
- Those are ascending with ascending addresses. */
- QSORT_ARR(exc_list, cmp_exc_entry);
- for (size_t e = 0; e < ARR_LEN(exc_list); ++e) {
- be_emit_cstring("\t.long ");
- ia32_emit_exc_label(exc_list[e].exc_instr);
- be_emit_char('\n');
- be_emit_cstring("\t.long ");
- be_gas_emit_block_name(exc_list[e].block);
- be_emit_char('\n');
+ emit_function_text(irg, blk_sched);
+
+ if (be_options.exceptions) {
+ be_exc_emit_table();
+ be_exc_finish();
+ }
}
- DEL_ARR_F(exc_list);
+
+ be_gas_emit_function_epilog(entity);
}
void ia32_emit_thunks(void)
diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c
index c8de886..6a8443b 100644
--- a/ir/be/ia32/ia32_new_nodes.c
+++ b/ir/be/ia32/ia32_new_nodes.c
@@ -435,34 +435,6 @@ unsigned get_ia32_copyb_size(const ir_node *node)
return attr->size;
}
-unsigned get_ia32_exc_label(const ir_node *node)
-{
- const ia32_attr_t *attr = get_ia32_attr_const(node);
- return attr->has_except_label;
-}
-
-void set_ia32_exc_label(ir_node *node, unsigned flag)
-{
- ia32_attr_t *attr = get_ia32_attr(node);
- attr->has_except_label = flag;
-}
-
-ir_label_t get_ia32_exc_label_id(const ir_node *node)
-{
- const ia32_attr_t *attr = get_ia32_attr_const(node);
-
- assert(attr->has_except_label);
- return attr->exc_label;
-}
-
-void set_ia32_exc_label_id(ir_node *node, ir_label_t id)
-{
- ia32_attr_t *attr = get_ia32_attr(node);
-
- assert(attr->has_except_label);
- attr->exc_label = id;
-}
-
void ia32_swap_left_right(ir_node *node)
{
ia32_attr_t *attr = get_ia32_attr(node);
diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c
index 0ec5953..3bf05f8 100644
--- a/ir/be/ia32/ia32_transform.c
+++ b/ir/be/ia32/ia32_transform.c
@@ -4483,7 +4483,7 @@ static ir_node *gen_Proj_Load(ir_node *node)
return be_new_Proj(new_pred, pn_ia32_Load_M);
case pn_Load_X_except:
/* This Load might raise an exception. Mark it. */
- set_ia32_exc_label(new_pred, 1);
+ set_needs_exc_label(new_pred, true);
return be_new_Proj(new_pred, pn_ia32_Load_X_except);
case pn_Load_X_regular:
return be_new_Proj(new_pred, pn_ia32_Load_X_regular);
@@ -4497,7 +4497,7 @@ static ir_node *gen_Proj_Load(ir_node *node)
return be_new_Proj(new_pred, pn_ia32_M);
case pn_Load_X_except:
/* This Load might raise an exception. Mark it. */
- set_ia32_exc_label(new_pred, 1);
+ set_needs_exc_label(new_pred, true);
return be_new_Proj(new_pred, pn_ia32_Conv_I2I_X_except);
case pn_Load_X_regular:
return be_new_Proj(new_pred, pn_ia32_Conv_I2I_X_regular);
@@ -4510,7 +4510,7 @@ static ir_node *gen_Proj_Load(ir_node *node)
return be_new_Proj(new_pred, pn_ia32_xLoad_M);
case pn_Load_X_except:
/* This Load might raise an exception. Mark it. */
- set_ia32_exc_label(new_pred, 1);
+ set_needs_exc_label(new_pred, true);
return be_new_Proj(new_pred, pn_ia32_xLoad_X_except);
case pn_Load_X_regular:
return be_new_Proj(new_pred, pn_ia32_xLoad_X_regular);
@@ -4523,7 +4523,7 @@ static ir_node *gen_Proj_Load(ir_node *node)
return be_new_Proj(new_pred, pn_ia32_fld_M);
case pn_Load_X_except:
/* This Load might raise an exception. Mark it. */
- set_ia32_exc_label(new_pred, 1);
+ set_needs_exc_label(new_pred, true);
return be_new_Proj(new_pred, pn_ia32_fld_X_except);
case pn_Load_X_regular:
return be_new_Proj(new_pred, pn_ia32_fld_X_regular);
@@ -4663,7 +4663,7 @@ static ir_node *gen_Proj_Div(ir_node *node)
panic("Div transformed to unexpected thing %+F", new_pred);
}
case pn_Div_X_except:
- set_ia32_exc_label(new_pred, 1);
+ set_needs_exc_label(new_pred, true);
return be_new_Proj(new_pred, pn_ia32_Div_X_except);
case pn_Div_X_regular:
return be_new_Proj(new_pred, pn_ia32_Div_X_regular);
@@ -4691,7 +4691,7 @@ static ir_node *gen_Proj_Mod(ir_node *node)
case pn_Mod_res:
return be_new_Proj(new_pred, pn_ia32_Div_mod_res);
case pn_Mod_X_except:
- set_ia32_exc_label(new_pred, 1);
+ set_needs_exc_label(new_pred, true);
return be_new_Proj(new_pred, pn_ia32_Div_X_except);
case pn_Mod_X_regular:
return be_new_Proj(new_pred, pn_ia32_Div_X_regular);
@@ -4923,6 +4923,7 @@ static ir_node *gen_Proj_Call(ir_node *node)
case pn_Call_X_regular:
return be_new_Proj(new_call, pn_ia32_Call_X_regular);
case pn_Call_X_except:
+ set_needs_exc_label(new_call, true);
return be_new_Proj(new_call, pn_ia32_Call_X_except);
case pn_Call_T_result:
break;
diff --git a/ir/ir/irgraph_t.h b/ir/ir/irgraph_t.h
index 194cf89..a3c33cd 100644
--- a/ir/ir/irgraph_t.h
+++ b/ir/ir/irgraph_t.h
@@ -310,7 +310,7 @@ static inline void set_irg_entity_(ir_graph *irg, ir_entity *ent)
irg->ent = ent;
}
-static inline ir_type *get_irg_frame_type_(ir_graph *irg)
+static inline ir_type *get_irg_frame_type_(const ir_graph *const irg)
{
assert(irg->frame_type);
return irg->frame_type;
diff --git a/ir/ir/irnode.c b/ir/ir/irnode.c
index 5d38ca4..ad12bdc 100644
--- a/ir/ir/irnode.c
+++ b/ir/ir/irnode.c
@@ -666,15 +666,15 @@ int is_x_regular_Proj(const ir_node *node)
void ir_set_throws_exception(ir_node *node, int throws_exception)
{
- except_attr *attr = &node->attr.except;
assert(is_fragile_op(node));
+ except_attr *attr = &node->attr.except;
attr->throws_exception = throws_exception;
}
int ir_throws_exception(const ir_node *node)
{
- const except_attr *attr = &node->attr.except;
assert(is_fragile_op(node));
+ const except_attr *attr = &node->attr.except;
return attr->throws_exception;
}
diff --git a/ir/ir/irnode_t.h b/ir/ir/irnode_t.h
index 69757f8..7336655 100644
--- a/ir/ir/irnode_t.h
+++ b/ir/ir/irnode_t.h
@@ -132,9 +132,11 @@ typedef struct sel_attr {
/** Attributes for nodes with exceptions (fragile flag). */
typedef struct except_attr {
- bool pinned : 1;
- /** Whether a fragile op produces X_except and X_regular values. */
- unsigned throws_exception : 1;
+ bool pinned : 1;
+ /**< Whether a fragile op produces X_except and X_regular values. */
+ bool throws_exception : 1;
+ /**< Whether this node needs a label because of possible exception. */
+ bool needs_except_label : 1;
} except_attr;
/** Attributes for Call nodes. */
@@ -678,6 +680,17 @@ static inline void set_irn_dbg_info_(ir_node *n, dbg_info *db)
n->dbi = db;
}
+static inline int needs_exc_label(const ir_node *node)
+{
+ return is_fragile_op(node) && node->attr.except.needs_except_label;
+}
+
+static inline void set_needs_exc_label(ir_node *node, int flag)
+{
+ assert(is_fragile_op(node));
+ node->attr.except.needs_except_label = flag;
+}
+
/**
* Sets the Phi list of a block.
*/