Add ARM TstBra and use it for comparison with 0.
authorChristoph Mallon <christoph.mallon@gmx.de>
Tue, 24 Jun 2008 18:08:48 +0000 (18:08 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Tue, 24 Jun 2008 18:08:48 +0000 (18:08 +0000)
[r20246]

ir/be/arm/arm_emitter.c
ir/be/arm/arm_spec.pl
ir/be/arm/arm_transform.c

index 7c7b809..6ce78d3 100644 (file)
@@ -453,6 +453,80 @@ static void emit_arm_CmpBra(const ir_node *irn) {
        }
 }
 
+
+/**
+ * Emit a Tst with conditional branch.
+ */
+static void emit_arm_TstBra(const ir_node *irn)
+{
+       const ir_edge_t *edge;
+       const ir_node *proj_true  = NULL;
+       const ir_node *proj_false = NULL;
+       const ir_node *block;
+       const ir_node *next_block;
+       const char *suffix;
+       int proj_num = get_arm_CondJmp_proj_num(irn);
+
+       foreach_out_edge(irn, edge) {
+               ir_node *proj = get_edge_src_irn(edge);
+               long nr = get_Proj_proj(proj);
+               if (nr == pn_Cond_true) {
+                       proj_true = proj;
+               } else {
+                       proj_false = proj;
+               }
+       }
+
+       /* for now, the code works for scheduled and non-schedules blocks */
+       block = get_nodes_block(irn);
+
+       /* we have a block schedule */
+       next_block = sched_next_block(block);
+
+       assert(proj_num != pn_Cmp_False);
+       assert(proj_num != pn_Cmp_True);
+
+       if (get_cfop_target_block(proj_true) == next_block) {
+               /* exchange both proj's so the second one can be omitted */
+               const ir_node *t = proj_true;
+
+               proj_true  = proj_false;
+               proj_false = t;
+               proj_num   = get_negated_pnc(proj_num, mode_Iu);
+       }
+       switch (proj_num) {
+               case pn_Cmp_Eq:  suffix = "eq"; break;
+               case pn_Cmp_Lt:  suffix = "lt"; break;
+               case pn_Cmp_Le:  suffix = "le"; break;
+               case pn_Cmp_Gt:  suffix = "gt"; break;
+               case pn_Cmp_Ge:  suffix = "ge"; break;
+               case pn_Cmp_Lg:  suffix = "ne"; break;
+               case pn_Cmp_Leg: suffix = "al"; break;
+               default: assert(!"Cmp unsupported"); suffix = "al";
+       }
+       be_emit_cstring("\ttst ");
+       arm_emit_source_register(irn, 0);
+       be_emit_cstring(", ");
+       arm_emit_source_register(irn, 1);
+       be_emit_finish_line_gas(irn);
+
+       /* emit the true proj */
+       be_emit_irprintf("\tb%s ", suffix);
+       arm_emit_cfop_target(proj_true);
+       be_emit_finish_line_gas(proj_true);
+
+       if (get_cfop_target_block(proj_false) == next_block) {
+               be_emit_cstring("\t/* fallthrough to ");
+               arm_emit_cfop_target(proj_false);
+               be_emit_cstring(" */");
+               be_emit_finish_line_gas(proj_false);
+       } else {
+               be_emit_cstring("b ");
+               arm_emit_cfop_target(proj_false);
+               be_emit_finish_line_gas(proj_false);
+       }
+}
+
 /**
  * Emit a Compare with conditional branch.
  */
@@ -945,6 +1019,7 @@ static void arm_register_emitters(void) {
 
        /* other emitter functions */
        ARM_EMIT(CmpBra);
+       ARM_EMIT(TstBra);
        ARM_EMIT(fpaCmfBra);
        ARM_EMIT(fpaCmfeBra);
        ARM_EMIT(CopyB);
index 5c9fe4e..a17d473 100644 (file)
@@ -578,6 +578,17 @@ CmpBra => {
        attr_type => "arm_CondJmp_attr_t",
 },
 
+TstBra => {
+       op_flags  => "L|X|Y",
+       state     => "pinned",
+       comment   => "construct conditional branch: TST A, B && JMPxx LABEL",
+       mode      => "mode_T",
+       attr      => "int proj_num",
+       init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);",
+       reg_req   => { "in" => [ "gp", "gp" ], "out" => [ "none", "none"] },
+       attr_type => "arm_CondJmp_attr_t",
+},
+
 SwitchJmp => {
        op_flags  => "L|X|Y",
        state     => "pinned",
index 2be1c7b..27e805c 100644 (file)
@@ -935,9 +935,9 @@ static ir_node *gen_Cond(ir_node *node) {
                ir_node *op1      = get_Cmp_left(cmp_node);
                ir_node *new_op1  = be_transform_node(op1);
                ir_node *op2      = get_Cmp_right(cmp_node);
-               ir_node *new_op2  = be_transform_node(op2);
 
                if (mode_is_float(get_irn_mode(op1))) {
+                       ir_node *new_op2  = be_transform_node(op2);
                        /* floating point compare */
                        pn_Cmp pnc = get_Proj_proj(selector);
 
@@ -947,8 +947,12 @@ static ir_node *gen_Cond(ir_node *node) {
                        }
                        /* Hmm: use need cmfe */
                        return new_rd_arm_fpaCmfeBra(dbg, irg, block, new_op1, new_op2, pnc);
+               } else if (is_Const(op2) && tarval_is_null(get_Const_tarval(op2))) {
+                       /* compare with 0 */
+                       return new_rd_arm_TstBra(dbg, irg, block, new_op1, new_op1, get_Proj_proj(selector));
                } else {
                        /* integer compare */
+                       ir_node *new_op2  = be_transform_node(op2);
                        return new_rd_arm_CmpBra(dbg, irg, block, new_op1, new_op2, get_Proj_proj(selector));
                }
        } else {