aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-microblaze/gcc/files/0008-Patch-microblaze-Add-branch_compare-instruction.patch
blob: 4da74f3f88d13ff7af6eec52c7d44b558eff6faa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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