diff options
Diffstat (limited to 'recipes-microblaze/gcc/files/0008-Patch-microblaze-Add-branch_compare-instruction.patch')
-rw-r--r-- | recipes-microblaze/gcc/files/0008-Patch-microblaze-Add-branch_compare-instruction.patch | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/recipes-microblaze/gcc/files/0008-Patch-microblaze-Add-branch_compare-instruction.patch b/recipes-microblaze/gcc/files/0008-Patch-microblaze-Add-branch_compare-instruction.patch new file mode 100644 index 00000000..4da74f3f --- /dev/null +++ b/recipes-microblaze/gcc/files/0008-Patch-microblaze-Add-branch_compare-instruction.patch @@ -0,0 +1,224 @@ +From: David Holsgrove <david.holsgrove@xilinx.com> +Subject: [PATCH 8/8] [Patch, microblaze]: Add branch_compare instruction + +To facilitate optimization pass understanding of the conditional +branch for microblaze, remove the UNSPEC'd signed_compare / +unsigned_compare instructions, and replace with a complete +branch_compare which will output_asm_insn the correct cmp/cmpu +depending on comparison code and signed / unsigned. + +We then return the correct branch instruction. + +cbranchsi now calls an expanded microblaze_expand_conditional_branch +function which will carry out compare against zero, compare EQ/NE, +and all other compares appropriately. + +-funroll-loops optimization pass can now proceed + +Changelog + +2013-03-19 David Holsgrove <david.holsgrove@xilinx.com> + + * gcc/config/microblaze/predicates.md: Add cmp_op predicate. + * gcc/config/microblaze/microblaze.md: Add branch_compare + instruction which uses cmp_op predicate and emits cmp insn + before branch. + * gcc/config/microblaze/microblaze.c + (microblaze_emit_compare): Rename to + microblaze_expand_conditional_branch and consolidate logic. + (microblaze_expand_conditional_branch): emit branch_compare + insn instead of handling cmp op separate from branch insn. + +Signed-off-by: David Holsgrove <david.holsgrove@xilinx.com> +Upstream-Status: Pending + +diff --git a/gcc/config/microblaze/microblaze.c b/gcc/config/microblaze/microblaze.c +index 4417289..84b58bf 100644 +--- a/gcc/config/microblaze/microblaze.c ++++ b/gcc/config/microblaze/microblaze.c +@@ -3336,65 +3336,45 @@ microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) + emit_move_insn (mem, fnaddr); + } + +-/* Emit instruction to perform compare. +- cmp is (compare_op op0 op1). */ +-static rtx +-microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code) ++/* Generate conditional branch -- first, generate test condition, ++ second, generate correct branch instruction. */ ++ ++void ++microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[]) + { +- rtx cmp_op0 = XEXP (cmp, 0); +- rtx cmp_op1 = XEXP (cmp, 1); ++ enum rtx_code code = GET_CODE (operands[0]); ++ rtx cmp_op0 = operands[1]; ++ rtx cmp_op1 = operands[2]; ++ rtx label1 = operands[3]; + rtx comp_reg = gen_reg_rtx (SImode); +- enum rtx_code code = *cmp_code; +- ++ rtx condition; ++ + gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG)); + + /* If comparing against zero, just test source reg. */ +- if (cmp_op1 == const0_rtx) +- return cmp_op0; ++ if (cmp_op1 == const0_rtx) ++ { ++ comp_reg = cmp_op0; ++ condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx); ++ emit_jump_insn (gen_condjump (condition, label1)); ++ } + +- if (code == EQ || code == NE) ++ else if (code == EQ || code == NE) + { + /* Use xor for equal/not-equal comparison. */ + emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1)); ++ condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx); ++ emit_jump_insn (gen_condjump (condition, label1)); + } +- else if (code == GT || code == GTU || code == LE || code == LEU) +- { +- /* MicroBlaze compare is not symmetrical. */ +- /* Swap argument order. */ +- cmp_op1 = force_reg (mode, cmp_op1); +- if (code == GT || code == LE) +- emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1)); +- else +- emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1)); +- /* Translate test condition. */ +- *cmp_code = swap_condition (code); +- } +- else /* if (code == GE || code == GEU || code == LT || code == LTU) */ ++ else + { ++ /* Generate compare and branch in single instruction. */ + cmp_op1 = force_reg (mode, cmp_op1); +- if (code == GE || code == LT) +- emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0)); +- else +- emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0)); ++ condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1); ++ emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1)); + } +- +- return comp_reg; + } + +-/* Generate conditional branch -- first, generate test condition, +- second, generate correct branch instruction. */ +- +-void +-microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[]) +-{ +- enum rtx_code code = GET_CODE (operands[0]); +- rtx comp; +- rtx condition; +- +- comp = microblaze_emit_compare (mode, operands[0], &code); +- condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx); +- emit_jump_insn (gen_condjump (condition, operands[3])); +-} + + void + microblaze_expand_conditional_branch_sf (rtx operands[]) +diff --git a/gcc/config/microblaze/microblaze.md b/gcc/config/microblaze/microblaze.md +index 49d8f01..9c1e1a3 100644 +--- a/gcc/config/microblaze/microblaze.md ++++ b/gcc/config/microblaze/microblaze.md +@@ -1624,28 +1624,6 @@ + (set_attr "length" "4")] + ) + +-(define_insn "signed_compare" +- [(set (match_operand:SI 0 "register_operand" "=d") +- (unspec +- [(match_operand:SI 1 "register_operand" "d") +- (match_operand:SI 2 "register_operand" "d")] UNSPEC_CMP))] +- "" +- "cmp\t%0,%1,%2" +- [(set_attr "type" "arith") +- (set_attr "mode" "SI") +- (set_attr "length" "4")]) +- +-(define_insn "unsigned_compare" +- [(set (match_operand:SI 0 "register_operand" "=d") +- (unspec +- [(match_operand:SI 1 "register_operand" "d") +- (match_operand:SI 2 "register_operand" "d")] UNSPEC_CMPU))] +- "" +- "cmpu\t%0,%1,%2" +- [(set_attr "type" "arith") +- (set_attr "mode" "SI") +- (set_attr "length" "4")]) +- + ;;---------------------------------------------------------------- + ;; Setting a register from an floating point comparison. + ;;---------------------------------------------------------------- +@@ -1719,6 +1697,47 @@ + (set_attr "length" "4")] + ) + ++(define_insn "branch_compare" ++ [(set (pc) ++ (if_then_else (match_operator:SI 0 "cmp_op" ++ [(match_operand:SI 1 "register_operand" "d") ++ (match_operand:SI 2 "register_operand" "d") ++ ]) ++ (label_ref (match_operand 3)) ++ (pc))) ++ (clobber(reg:SI R_TMP))] ++ "" ++ { ++ operands[4] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM); ++ enum rtx_code code = GET_CODE (operands[0]); ++ ++ if (code == GT || code == LE) ++ { ++ output_asm_insn ("cmp\tr18,%z1,%z2", operands); ++ code = swap_condition (code); ++ } ++ else if (code == GTU || code == LEU) ++ { ++ output_asm_insn ("cmpu\tr18,%z1,%z2", operands); ++ code = swap_condition (code); ++ } ++ else if (code == GE || code == LT) ++ { ++ output_asm_insn ("cmp\tr18,%z2,%z1", operands); ++ } ++ else if (code == GEU || code == LTU) ++ { ++ output_asm_insn ("cmpu\tr18,%z2,%z1", operands); ++ } ++ ++ operands[0] = gen_rtx_fmt_ee (signed_condition (code), SImode, operands[4], const0_rtx); ++ return "b%C0i%?\tr18,%3"; ++ } ++ [(set_attr "type" "branch") ++ (set_attr "mode" "none") ++ (set_attr "length" "12")] ++) ++ + ;;---------------------------------------------------------------- + ;; Unconditional branches + ;;---------------------------------------------------------------- +diff --git a/gcc/config/microblaze/predicates.md b/gcc/config/microblaze/predicates.md +index 5fd1bd4..2c23291 100644 +--- a/gcc/config/microblaze/predicates.md ++++ b/gcc/config/microblaze/predicates.md +@@ -119,3 +119,7 @@ + ;; Test for valid PIC call operand + (define_predicate "call_insn_plt_operand" + (match_test "PLT_ADDR_P (op)")) ++ ++;; Return if the code of this rtx pattern is a comparison. ++(define_predicate "cmp_op" ++ (match_code "gt,ge,gtu,geu,lt,le,ltu,leu")) +-- +1.7.5.4 + |