aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-microblaze/gcc/files/0008-Patch-microblaze-Add-branch_compare-instruction.patch
diff options
context:
space:
mode:
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.patch224
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
+