}
}
+
+/**
+ * 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.
*/
/* other emitter functions */
ARM_EMIT(CmpBra);
+ ARM_EMIT(TstBra);
ARM_EMIT(fpaCmfBra);
ARM_EMIT(fpaCmfeBra);
ARM_EMIT(CopyB);
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",
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);
}
/* 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 {