Commit 0d470656 authored by Matthias Braun's avatar Matthias Braun
Browse files

remove cond_kind attribute, it was never used in a consistent or correct way anyway

parent 68a65bfe
......@@ -461,39 +461,8 @@ ir_node *get_IJmp_target(const ir_node *ijmp);
/** Sets the target address of an IJmp */
void set_IJmp_target(ir_node *ijmp, ir_node *tgt);
/* We distinguish three kinds of Cond nodes. These can be distinguished
by the mode of the selector operand and an internal flag of type cond_kind.
First we distinguish binary Conds and switch Conds.
A binary Cond has as selector a boolean value. Proj(0) projects the control
flow for case "False", Proj(1) the control flow for "True". A binary Cond
is recognized by the boolean selector.
The switch Cond has as selector an unsigned integer. It produces as result
an n+1 Tuple (cf0, ... , cfn) of control flows.
We differ two flavors of this Cond. The first, the dense Cond, passes
control along output i if the selector value is i, 0 <= i <= n. If the
selector value is >n it passes control along output n.
The second Cond flavor differences in the treatment of cases not specified in
the source program. It magically knows about the existence of Proj nodes.
It only passes control along output i, 0 <= i <= n, if a node Proj(Cond, i)
exists. Else it passes control along output n (even if this Proj does not
exist.) This Cond we call "fragmentary". There is a special constructor
new_defaultProj that automatically sets the flavor.
The two switch flavors are distinguished by a flag of type cond_kind.
Default flavor is "dense"
typedef enum {
dense, /**< Default. Missing Proj nodes are dead control flow. */
fragmentary /**< Special. No control flow optimizations allowed. Missing
Proj nodes mean default control flow, i.e., Proj(n). */
} cond_kind;
/** Gets the string representation of the Cond node kind. */
const char *get_cond_kind_name(cond_kind kind);
ir_node *get_Cond_selector(const ir_node *node);
void set_Cond_selector(ir_node *node, ir_node *selector);
cond_kind get_Cond_kind(const ir_node *node);
void set_Cond_kind(ir_node *node, cond_kind kind);
long get_Cond_default_proj(const ir_node *node);
void set_Cond_default_proj(ir_node *node, long defproj);
......@@ -258,7 +258,6 @@ new_bd_defaultProj(dbg_info *db, ir_node *block, ir_node *arg,
ir_node *res;
assert(arg->op == op_Cond);
arg->attr.cond.kind = fragmentary;
arg->attr.cond.default_proj = max_proj;
res = new_rd_Proj(db, block, arg, mode_X, max_proj);
return res;
......@@ -1184,7 +1183,6 @@ ir_node *
new_d_defaultProj(dbg_info *db, ir_node *arg, long max_proj) {
ir_node *res;
assert(arg->op == op_Cond);
arg->attr.cond.kind = fragmentary;
arg->attr.cond.default_proj = max_proj;
res = new_d_Proj(db, arg, mode_X, max_proj);
return res;
......@@ -242,8 +242,6 @@ int dump_irnode_to_file(FILE *F, ir_node *n) {
} break;
case iro_Cond: {
fprintf(F, " condition kind: %s\n",
get_Cond_kind(n) == dense ? "dense" : "fragmentary");
fprintf(F, " default ProjNr: %ld\n", get_Cond_default_proj(n));
if (get_Cond_jmp_pred(n) != COND_JMP_PRED_NONE) {
fprintf(F, " jump prediction: %s\n",
......@@ -65,7 +65,6 @@ typedef enum typetag_t
......@@ -229,9 +228,6 @@ static void symtbl_init(void)
INSERTENUM(tt_builtin, ir_bk_outport);
INSERTENUM(tt_builtin, ir_bk_inner_trampoline);
INSERTENUM(tt_cond_kind, dense);
INSERTENUM(tt_cond_kind, fragmentary);
INSERTENUM(tt_cond_jmp_predicate, COND_JMP_PRED_NONE);
INSERTENUM(tt_cond_jmp_predicate, COND_JMP_PRED_TRUE);
INSERTENUM(tt_cond_jmp_predicate, COND_JMP_PRED_FALSE);
......@@ -354,12 +350,6 @@ static void write_builtin_kind(io_env_t *env, ir_node *irn)
fputc(' ', env->file);
static void write_cond_kind(io_env_t *env, ir_node *irn)
fputs(get_cond_kind_name(get_Cond_kind(irn)), env->file);
fputc(' ', env->file);
static void write_cond_jmp_predicate(io_env_t *env, ir_node *irn)
fputs(get_cond_jmp_predicate_name(get_Cond_jmp_pred(irn)), env->file);
......@@ -1107,7 +1097,6 @@ static const char *get_typetag_name(typetag_t typetag)
case tt_variability: return "variability";
case tt_visibility: return "visibility";
case tt_volatility: return "volatility";
case tt_cond_kind: return "cond_kind";
case tt_cond_jmp_predicate: return "cond_jmp_predicate";
case tt_keyword: return "keyword";
case tt_mode_sort: return "mode_sort";
......@@ -1137,7 +1126,6 @@ static unsigned read_enum(io_env_t *env, typetag_t typetag)
#define read_align(env) ((ir_align) read_enum(env, tt_align))
#define read_allocation(env) ((ir_allocation) read_enum(env, tt_allocation))
#define read_builtin_kind(env) ((ir_builtin_kind) read_enum(env, tt_builtin))
#define read_cond_kind(env) ((cond_kind) read_enum(env, tt_cond_kind))
#define read_cond_jmp_predicate(env) ((cond_jmp_predicate) read_enum(env, tt_cond_jmp_predicate))
#define read_initializer_kind(env) ((ir_initializer_kind_t) read_enum(env, tt_initializer))
#define read_mode_arithmetic(env) ((ir_mode_arithmetic) read_enum(env, tt_mode_arithmetic))
......@@ -995,49 +995,6 @@ void set_IJmp_target(ir_node *ijmp, ir_node *tgt) {
set_irn_n(ijmp, 0, tgt);
> Implementing the case construct (which is where the constant Proj node is
> important) involves far more than simply determining the constant values.
> We could argue that this is more properly a function of the translator from
> Firm to the target machine. That could be done if there was some way of
> projecting "default" out of the Cond node.
I know it's complicated.
Basically there are two problems:
- determining the gaps between the Projs
- determining the biggest case constant to know the proj number for
the default node.
I see several solutions:
1. Introduce a ProjDefault node. Solves both problems.
This means to extend all optimizations executed during construction.
2. Give the Cond node for switch two flavors:
a) there are no gaps in the Projs (existing flavor)
b) gaps may exist, default proj is still the Proj with the largest
projection number. This covers also the gaps.
3. Fix the semantic of the Cond to that of 2b)
Solution 2 seems to be the best:
Computing the gaps in the Firm representation is not too hard, i.e.,
libFIRM can implement a routine that transforms between the two
flavours. This is also possible for 1) but 2) does not require to
change any existing optimization.
Further it should be far simpler to determine the biggest constant than
to compute all gaps.
I don't want to choose 3) as 2a) seems to have advantages for
dataflow analysis and 3) does not allow to convert the representation to
const char *get_cond_kind_name(cond_kind kind)
#define X(a) case a: return #a;
switch (kind) {
return "<unknown>";
#undef X
ir_node *
get_Cond_selector(const ir_node *node) {
......@@ -1050,18 +1007,6 @@ set_Cond_selector(ir_node *node, ir_node *selector) {
set_irn_n(node, 0, selector);
get_Cond_kind(const ir_node *node) {
return node->attr.cond.kind;
set_Cond_kind(ir_node *node, cond_kind kind) {
node->attr.cond.kind = kind;
get_Cond_default_proj(const ir_node *node) {
......@@ -156,7 +156,6 @@ typedef struct {
/** Cond attributes. */
typedef struct {
cond_kind kind; /**< flavor of Cond */
long default_proj; /**< only for non-binary Conds: biggest Proj number, i.e. the one used for default. */
cond_jmp_predicate jmp_pred; /**< only for binary Conds: The jump predication. */
} cond_attr;
......@@ -293,11 +293,6 @@ class Cond(Op):
flags = [ "cfopcode", "forking" ]
pinned = "yes"
attrs = [
name = "kind",
type = "cond_kind",
init = "dense"
name = "default_proj",
type = "long",
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment