From: Christoph Mallon Date: Tue, 24 Jun 2008 18:08:48 +0000 (+0000) Subject: Add ARM TstBra and use it for comparison with 0. X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;ds=sidebyside;h=dc109198dce6364827389be03e29e8f920aaf2c8;p=libfirm Add ARM TstBra and use it for comparison with 0. [r20246] --- diff --git a/ir/be/arm/arm_emitter.c b/ir/be/arm/arm_emitter.c index 7c7b809f9..6ce78d3c7 100644 --- a/ir/be/arm/arm_emitter.c +++ b/ir/be/arm/arm_emitter.c @@ -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); diff --git a/ir/be/arm/arm_spec.pl b/ir/be/arm/arm_spec.pl index 5c9fe4e3c..a17d473d8 100644 --- a/ir/be/arm/arm_spec.pl +++ b/ir/be/arm/arm_spec.pl @@ -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", diff --git a/ir/be/arm/arm_transform.c b/ir/be/arm/arm_transform.c index 2be1c7b78..27e805ce9 100644 --- a/ir/be/arm/arm_transform.c +++ b/ir/be/arm/arm_transform.c @@ -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 {