]>
Commit | Line | Data |
---|---|---|
2c9c2489 | 1 | ;;- Machine description for the pdp11 for GNU C compiler |
7adcbafe | 2 | ;; Copyright (C) 1994-2022 Free Software Foundation, Inc. |
2c9c2489 RK |
3 | ;; Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at). |
4 | ||
7ec022b2 | 5 | ;; This file is part of GCC. |
2c9c2489 | 6 | |
7ec022b2 | 7 | ;; GCC is free software; you can redistribute it and/or modify |
2c9c2489 | 8 | ;; it under the terms of the GNU General Public License as published by |
2f83c7d6 | 9 | ;; the Free Software Foundation; either version 3, or (at your option) |
2c9c2489 RK |
10 | ;; any later version. |
11 | ||
7ec022b2 | 12 | ;; GCC is distributed in the hope that it will be useful, |
2c9c2489 RK |
13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;; GNU General Public License for more details. | |
16 | ||
17 | ;; You should have received a copy of the GNU General Public License | |
2f83c7d6 NC |
18 | ;; along with GCC; see the file COPYING3. If not see |
19 | ;; <http://www.gnu.org/licenses/>. | |
2c9c2489 | 20 | |
19ce9cf1 PK |
21 | (include "predicates.md") |
22 | (include "constraints.md") | |
f90b7a5a | 23 | |
8662b2ba RH |
24 | (define_c_enum "unspecv" |
25 | [ | |
26 | UNSPECV_BLOCKAGE | |
27 | UNSPECV_SETD | |
28 | UNSPECV_SETI | |
76715c32 | 29 | UNSPECV_CPYMEM |
8662b2ba RH |
30 | ]) |
31 | ||
7021d5df PK |
32 | (define_constants |
33 | [ | |
34 | ;; Register numbers | |
58dd8e86 | 35 | (R0_REGNUM 0) |
a01c666c | 36 | (RETVAL_REGNUM 0) |
442fcea7 | 37 | (FRAME_POINTER_REGNUM 5) |
7021d5df PK |
38 | (STACK_POINTER_REGNUM 6) |
39 | (PC_REGNUM 7) | |
40 | (AC0_REGNUM 8) | |
41 | (AC3_REGNUM 11) | |
42 | (AC4_REGNUM 12) | |
43 | (AC5_REGNUM 13) | |
442fcea7 PK |
44 | ;; The next one is not a physical register but is used for |
45 | ;; addressing arguments. | |
46 | (ARG_POINTER_REGNUM 14) | |
b4324a14 | 47 | ;; Condition code registers |
442fcea7 PK |
48 | (CC_REGNUM 15) |
49 | (FCC_REGNUM 16) | |
b4324a14 | 50 | ;; End of hard registers |
442fcea7 | 51 | (FIRST_PSEUDO_REGISTER 17) |
b4324a14 | 52 | |
aad2444d PK |
53 | ;; Branch offset limits, as byte offsets from (pc). That is NOT |
54 | ;; the same thing as "instruction address" -- it is for backward | |
55 | ;; branches, but for forward branches it refers to the address | |
56 | ;; following the instruction. So the max forward distance | |
57 | ;; matches what the processor handbook says, while the max | |
58 | ;; backward branch is 2 less than the book. | |
7021d5df | 59 | (MIN_BRANCH -254) |
aad2444d PK |
60 | (MAX_BRANCH 254) |
61 | (MIN_SOB -124) | |
7021d5df | 62 | (MAX_SOB 0)]) |
2c9c2489 | 63 | |
b4324a14 PK |
64 | ;; DF is 64 bit |
65 | ;; SF is 32 bit | |
66 | ;; SI is 32 bit | |
2c9c2489 RK |
67 | ;; HI is 16 bit |
68 | ;; QI is 8 bit | |
69 | ||
9546fe6a | 70 | ;; Integer modes supported on the PDP11, with a mapping from machine mode |
b4324a14 | 71 | ;; to mnemonic suffix. SImode and DImode are usually special cases. |
9546fe6a PK |
72 | (define_mode_iterator PDPint [QI HI]) |
73 | (define_mode_attr isfx [(QI "b") (HI "")]) | |
b4324a14 PK |
74 | (define_mode_attr mname [(QI "QImode") (HI "HImode") (SI "SImode") (DI "DImode")]) |
75 | (define_mode_attr e_mname [(QI "E_QImode") (HI "E_HImode") (SI "E_SImode") (DI "E_DImode")]) | |
76 | (define_mode_attr hmode [(QI "hi") (HI "hi") (SI "si") (DI "di")]) | |
77 | ||
78 | ;; These are analogous for use in splitters and expanders. | |
79 | (define_mode_iterator HSint [HI SI]) | |
80 | (define_mode_iterator QHSint [QI HI SI]) | |
81 | (define_mode_iterator QHSDint [QI HI SI DI]) | |
82 | ||
83 | (define_code_iterator SHF [ashift ashiftrt lshiftrt]) | |
84 | ||
be7e8072 MR |
85 | (define_mode_iterator PDPfp [SF DF]) |
86 | ||
b4324a14 PK |
87 | ;; Substitution to turn a CC clobber into a CC setter. We have four of |
88 | ;; these: for CCmode vs. CCNZmode, and for CC_REGNUM vs. FCC_REGNUM. | |
89 | (define_subst "cc_cc" | |
90 | [(set (match_operand 0 "") (match_operand 1 "")) | |
91 | (clobber (reg CC_REGNUM))] | |
92 | "" | |
93 | [(set (reg:CC CC_REGNUM) | |
94 | (compare:CC (match_dup 1) (const_int 0))) | |
95 | (set (match_dup 0) (match_dup 1))]) | |
9546fe6a | 96 | |
b4324a14 PK |
97 | (define_subst "cc_ccnz" |
98 | [(set (match_operand 0 "") (match_operand 1 "")) | |
99 | (clobber (reg CC_REGNUM))] | |
100 | "" | |
101 | [(set (reg:CCNZ CC_REGNUM) | |
102 | (compare:CCNZ (match_dup 1) (const_int 0))) | |
103 | (set (match_dup 0) (match_dup 1))]) | |
2c9c2489 | 104 | |
b4324a14 | 105 | (define_subst "fcc_cc" |
be7e8072 | 106 | [(set (match_operand:PDPfp 0 "") (match_operand:PDPfp 1 "")) |
b4324a14 PK |
107 | (clobber (reg FCC_REGNUM))] |
108 | "" | |
109 | [(set (reg:CC FCC_REGNUM) | |
be7e8072 | 110 | (compare:CC (match_dup 1) (const_double_zero:PDPfp))) |
b4324a14 PK |
111 | (set (match_dup 0) (match_dup 1))]) |
112 | ||
113 | (define_subst "fcc_ccnz" | |
be7e8072 | 114 | [(set (match_operand:PDPfp 0 "") (match_operand:PDPfp 1 "")) |
b4324a14 PK |
115 | (clobber (reg FCC_REGNUM))] |
116 | "" | |
117 | [(set (reg:CCNZ FCC_REGNUM) | |
be7e8072 | 118 | (compare:CCNZ (match_dup 1) (const_double_zero:PDPfp))) |
b4324a14 PK |
119 | (set (match_dup 0) (match_dup 1))]) |
120 | ||
121 | (define_subst_attr "cc_cc" "cc_cc" "_nocc" "_cc") | |
122 | (define_subst_attr "fcc_cc" "fcc_cc" "_nocc" "_cc") | |
123 | (define_subst_attr "cc_ccnz" "cc_ccnz" "_nocc" "_cc") | |
124 | (define_subst_attr "fcc_ccnz" "fcc_ccnz" "_nocc" "_cc") | |
125 | ||
126 | ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. | |
2c9c2489 | 127 | |
2c9c2489 RK |
128 | ;; Compare instructions. |
129 | ||
130 | ;; currently we only support df floats, which saves us quite some | |
131 | ;; hassle switching the FP mode! | |
132 | ;; we assume that CPU is always in long float mode, and | |
133 | ;; 16 bit integer mode - currently, the prologue for main does this, | |
134 | ;; but maybe we should just set up a NEW crt0 properly, | |
135 | ;; -- and what about signal handling code? | |
136 | ;; (we don't even let sf floats in the register file, so | |
137 | ;; we only should have to worry about truncating and widening | |
138 | ;; when going to memory) | |
139 | ||
140 | ;; abort() call by g++ - must define libfunc for cmp_optab | |
141 | ;; and ucmp_optab for mode SImode, because we don't have that!!! | |
142 | ;; - yet since no libfunc is there, we abort () | |
143 | ||
2c9c2489 RK |
144 | ;; define attributes |
145 | ;; currently type is only fpu or arith or unknown, maybe branch later ? | |
146 | ;; default is arith | |
147 | (define_attr "type" "unknown,arith,fp" (const_string "arith")) | |
148 | ||
0f237806 PK |
149 | ;; length default is 2 bytes each |
150 | (define_attr "length" "" (const_int 2)) | |
2c9c2489 | 151 | |
aad2444d PK |
152 | ;; instruction base cost (not counting operands) |
153 | (define_attr "base_cost" "" (const_int 2)) | |
154 | ||
ddd5a7c1 | 155 | ;; a user's asm statement |
2c9c2489 RK |
156 | (define_asm_attributes |
157 | [(set_attr "type" "unknown") | |
0f237806 | 158 | ; length for asm is the max length per statement. That would be |
c67b2d4e PK |
159 | ; 3 words, for a two-operand instruction with extra word addressing |
160 | ; modes for both operands. | |
161 | (set_attr "length" "6")]) | |
2c9c2489 RK |
162 | |
163 | ;; define function units | |
164 | ||
8662b2ba RH |
165 | ;; Prologue and epilogue support. |
166 | ||
167 | (define_expand "prologue" | |
168 | [(const_int 0)] | |
169 | "" | |
170 | { | |
171 | pdp11_expand_prologue (); | |
172 | DONE; | |
173 | }) | |
174 | ||
175 | (define_expand "epilogue" | |
176 | [(const_int 0)] | |
177 | "" | |
178 | { | |
179 | pdp11_expand_epilogue (); | |
180 | DONE; | |
181 | }) | |
182 | ||
442fcea7 | 183 | (define_insn "rtspc" |
8662b2ba RH |
184 | [(return)] |
185 | "" | |
aad2444d | 186 | "rts\tpc") |
8662b2ba RH |
187 | |
188 | (define_insn "blockage" | |
189 | [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] | |
190 | "" | |
191 | "" | |
192 | [(set_attr "length" "0")]) | |
193 | ||
194 | (define_insn "setd" | |
195 | [(unspec_volatile [(const_int 0)] UNSPECV_SETD)] | |
196 | "" | |
197 | "setd") | |
198 | ||
199 | (define_insn "seti" | |
200 | [(unspec_volatile [(const_int 0)] UNSPECV_SETI)] | |
201 | "" | |
202 | "seti") | |
203 | ||
2c9c2489 RK |
204 | ;; arithmetic - values here immediately when next insn issued |
205 | ;; or does it mean the number of cycles after this insn was issued? | |
206 | ;; how do I say that fpu insns use cpu also? (pre-interaction phase) | |
207 | ||
208 | ;(define_function_unit "cpu" 1 1 (eq_attr "type" "arith") 0 0) | |
209 | ;(define_function_unit "fpu" 1 1 (eq_attr "type" "fp") 0 0) | |
210 | ||
211 | ;; compare | |
f90b7a5a | 212 | (define_insn "*cmpdf" |
b4324a14 PK |
213 | [(set (reg:CC FCC_REGNUM) |
214 | (compare:CC (match_operand:DF 0 "general_operand" "fR,fR,Q,QF") | |
215 | (match_operand:DF 1 "register_or_const0_operand" "G,a,G,a")))] | |
216 | "TARGET_FPU && reload_completed" | |
2c9c2489 RK |
217 | "* |
218 | { | |
f90b7a5a | 219 | if (which_alternative == 0 || which_alternative == 2) |
4aef57c9 | 220 | return \"{tstd|tstf}\t%0\"; |
f90b7a5a | 221 | else |
4aef57c9 | 222 | return \"{cmpd|cmpf}\t%0,%1\"; |
2c9c2489 | 223 | }" |
b4324a14 | 224 | [(set_attr "length" "2,2,4,4") |
aad2444d | 225 | (set_attr "base_cost" "4") |
b4324a14 PK |
226 | (set_attr "type" "fp")]) |
227 | ||
228 | ;; Copy floating point processor condition code register to main CPU | |
229 | ;; condition code register. | |
230 | (define_insn "*cfcc" | |
231 | [(set (reg CC_REGNUM) (reg FCC_REGNUM))] | |
232 | "TARGET_FPU && reload_completed" | |
233 | "cfcc") | |
234 | ||
235 | (define_insn "cmp<mode>" | |
236 | [(set (reg:CC CC_REGNUM) | |
237 | (compare:CC (match_operand:PDPint 0 "general_operand" "rR,rR,rR,Q,Qi,Qi") | |
238 | (match_operand:PDPint 1 "general_operand" "N,rR,Qi,N,rR,Qi")))] | |
2c9c2489 | 239 | "" |
f90b7a5a | 240 | "@ |
4aef57c9 PK |
241 | tst<PDPint:isfx>\t%0 |
242 | cmp<PDPint:isfx>\t%0,%1 | |
243 | cmp<PDPint:isfx>\t%0,%1 | |
244 | tst<PDPint:isfx>\t%0 | |
245 | cmp<PDPint:isfx>\t%0,%1 | |
246 | cmp<PDPint:isfx>\t%0,%1" | |
0f237806 | 247 | [(set_attr "length" "2,2,4,4,4,6")]) |
f90b7a5a | 248 | |
442fcea7 PK |
249 | ;; Two word compare |
250 | (define_insn "cmpsi" | |
251 | [(set (reg:CC CC_REGNUM) | |
252 | (compare:CC (match_operand:SI 0 "general_operand" "rDQi") | |
253 | (match_operand:SI 1 "general_operand" "rDQi")))] | |
254 | "" | |
255 | { | |
256 | rtx inops[2]; | |
257 | rtx exops[2][2]; | |
258 | rtx lb[1]; | |
259 | ||
260 | inops[0] = operands[0]; | |
261 | inops[1] = operands[1]; | |
262 | pdp11_expand_operands (inops, exops, 2, 2, NULL, big); | |
263 | lb[0] = gen_label_rtx (); | |
264 | ||
265 | if (CONST_INT_P (exops[0][1]) && INTVAL (exops[0][1]) == 0) | |
266 | output_asm_insn ("tst\t%0", exops[0]); | |
267 | else | |
268 | output_asm_insn ("cmp\t%0,%1", exops[0]); | |
269 | output_asm_insn ("bne\t%l0", lb); | |
270 | if (CONST_INT_P (exops[1][1]) && INTVAL (exops[1][1]) == 0) | |
271 | output_asm_insn ("tst\t%0", exops[1]); | |
272 | else | |
273 | output_asm_insn ("cmp\t%0,%1", exops[1]); | |
274 | output_asm_label (lb[0]); | |
275 | fputs (":\n", asm_out_file); | |
276 | ||
277 | return ""; | |
278 | } | |
279 | [(set (attr "length") | |
280 | (symbol_ref "pdp11_cmp_length (operands, 2)")) | |
281 | (set_attr "base_cost" "0")]) | |
282 | ||
283 | ;; Four word compare | |
284 | (define_insn "cmpdi" | |
285 | [(set (reg:CC CC_REGNUM) | |
286 | (compare:CC (match_operand:DI 0 "general_operand" "rDQi") | |
287 | (match_operand:DI 1 "general_operand" "rDQi")))] | |
288 | "" | |
289 | { | |
290 | rtx inops[4]; | |
291 | rtx exops[4][2]; | |
292 | rtx lb[1]; | |
293 | int i; | |
294 | ||
295 | inops[0] = operands[0]; | |
296 | inops[1] = operands[1]; | |
297 | pdp11_expand_operands (inops, exops, 2, 4, NULL, big); | |
298 | lb[0] = gen_label_rtx (); | |
299 | ||
300 | for (i = 0; i < 3; i++) | |
301 | { | |
302 | if (CONST_INT_P (exops[i][1]) && INTVAL (exops[i][1]) == 0) | |
303 | output_asm_insn ("tst\t%0", exops[i]); | |
304 | else | |
305 | output_asm_insn ("cmp\t%0,%1", exops[i]); | |
306 | output_asm_insn ("bne\t%l0", lb); | |
307 | } | |
308 | if (CONST_INT_P (exops[3][1]) && INTVAL (exops[3][1]) == 0) | |
309 | output_asm_insn ("tst\t%0", exops[3]); | |
310 | else | |
311 | output_asm_insn ("cmp\t%0,%1", exops[3]); | |
312 | output_asm_label (lb[0]); | |
313 | fputs (":\n", asm_out_file); | |
314 | ||
315 | return ""; | |
316 | } | |
317 | [(set (attr "length") | |
318 | (symbol_ref "pdp11_cmp_length (operands, 2)")) | |
319 | (set_attr "base_cost" "0")]) | |
320 | ||
aad2444d PK |
321 | ;; sob instruction |
322 | ;; | |
fe65151b PK |
323 | ;; This expander has to check for mode match because the doloop pass |
324 | ;; in gcc that invokes it does not do so, i.e., it may attempt to apply | |
325 | ;; this pattern even if the count operand is QI or SI mode. | |
326 | (define_expand "doloop_end" | |
327 | [(parallel [(set (pc) | |
328 | (if_then_else | |
329 | (ne (match_operand:HI 0 "nonimmediate_operand" "+r,!m") | |
330 | (const_int 1)) | |
331 | (label_ref (match_operand 1 "" "")) | |
332 | (pc))) | |
333 | (set (match_dup 0) | |
334 | (plus:HI (match_dup 0) | |
335 | (const_int -1)))])] | |
336 | "TARGET_40_PLUS" | |
337 | "{ | |
338 | if (GET_MODE (operands[0]) != HImode) | |
339 | FAIL; | |
340 | }") | |
341 | ||
342 | ;; Do a define_split because some alternatives clobber CC. | |
aad2444d | 343 | ;; Some don't, but it isn't all that interesting to cover that case. |
fe65151b | 344 | (define_insn_and_split "doloop_end_insn" |
2c9c2489 RK |
345 | [(set (pc) |
346 | (if_then_else | |
aad2444d PK |
347 | (ne (match_operand:HI 0 "nonimmediate_operand" "+r,!m") |
348 | (const_int 1)) | |
2c9c2489 RK |
349 | (label_ref (match_operand 1 "" "")) |
350 | (pc))) | |
351 | (set (match_dup 0) | |
352 | (plus:HI (match_dup 0) | |
353 | (const_int -1)))] | |
354 | "TARGET_40_PLUS" | |
aad2444d PK |
355 | "#" |
356 | "&& reload_completed" | |
357 | [(parallel [(set (pc) | |
358 | (if_then_else | |
359 | (ne (match_dup 0) (const_int 1)) | |
360 | (label_ref (match_dup 1)) | |
361 | (pc))) | |
362 | (set (match_dup 0) | |
363 | (plus:HI (match_dup 0) | |
364 | (const_int -1))) | |
365 | (clobber (reg:CC CC_REGNUM))])] | |
366 | "") | |
367 | ||
368 | ;; Note that there is a memory alternative here. This is as documented | |
369 | ;; in gccint, which says that doloop_end, since it has both a jump and | |
370 | ;; an output interrupt "must handle its own reloads". That translates | |
371 | ;; to: must accept memory operands as valid though they may be deprecated. | |
372 | (define_insn "doloop_end_nocc" | |
373 | [(set (pc) | |
374 | (if_then_else | |
375 | (ne (match_operand:HI 0 "nonimmediate_operand" "+r,!m") | |
376 | (const_int 1)) | |
377 | (label_ref (match_operand 1 "" "")) | |
378 | (pc))) | |
379 | (set (match_dup 0) | |
380 | (plus:HI (match_dup 0) | |
381 | (const_int -1))) | |
382 | (clobber (reg:CC CC_REGNUM))] | |
383 | "TARGET_40_PLUS && reload_completed" | |
2c9c2489 RK |
384 | "* |
385 | { | |
aad2444d PK |
386 | rtx lb[1]; |
387 | ||
0f237806 | 388 | if (get_attr_length (insn) == 2) |
4aef57c9 | 389 | return \"sob\t%0,%l1\"; |
2c9c2489 RK |
390 | |
391 | /* emulate sob */ | |
aad2444d | 392 | lb[0] = gen_label_rtx (); |
4aef57c9 | 393 | output_asm_insn (\"dec\t%0\", operands); |
aad2444d | 394 | output_asm_insn (\"beq\t%l0\", lb); |
4aef57c9 | 395 | output_asm_insn (\"jmp\t%l1\", operands); |
2c9c2489 | 396 | |
aad2444d | 397 | output_asm_label (lb[0]); |
b4324a14 | 398 | fputs (\":\\n\", asm_out_file); |
2c9c2489 RK |
399 | |
400 | return \"\"; | |
401 | }" | |
aad2444d PK |
402 | [(set (attr "length") |
403 | (if_then_else (eq (symbol_ref ("which_alternative")) (const_int 1)) | |
404 | (const_int 10) | |
405 | (if_then_else (ior (lt (minus (match_dup 1) (pc)) | |
406 | (const_int MIN_SOB)) | |
407 | (gt (minus (match_dup 1) (pc)) | |
408 | (const_int MAX_SOB))) | |
409 | (const_int 8) | |
410 | (const_int 2))))]) | |
2c9c2489 RK |
411 | |
412 | ;; These control RTL generation for conditional jump insns | |
413 | ;; and match them for register allocation. | |
b4324a14 PK |
414 | ;; Post reload these get expanded into insns that actually |
415 | ;; manipulate the condition code registers. We can't do that before | |
416 | ;; because instructions generated by reload clobber condition codes (new | |
417 | ;; CC design, type #2). | |
418 | (define_insn_and_split "cbranchdf4" | |
419 | [(set (pc) | |
f90b7a5a | 420 | (if_then_else (match_operator 0 "ordered_comparison_operator" |
b4324a14 PK |
421 | [(match_operand:DF 1 "general_operand" "fg") |
422 | (match_operand:DF 2 "general_operand" "a")]) | |
f90b7a5a | 423 | (label_ref (match_operand 3 "" "")) |
2c9c2489 | 424 | (pc)))] |
825cb171 | 425 | "TARGET_FPU" |
b4324a14 PK |
426 | "#" |
427 | "&& reload_completed" | |
428 | [(set (reg:CC FCC_REGNUM) | |
429 | (compare:CC (match_dup 1) (match_dup 2))) | |
430 | (set (pc) | |
431 | (if_then_else (match_op_dup 0 | |
432 | [(reg:CC FCC_REGNUM) (const_int 0)]) | |
433 | (label_ref (match_dup 3)) | |
434 | (pc)))] | |
f90b7a5a | 435 | "") |
2c9c2489 | 436 | |
b4324a14 PK |
437 | (define_insn_and_split "cbranch<mode>4" |
438 | [(set (pc) | |
f90b7a5a | 439 | (if_then_else (match_operator 0 "ordered_comparison_operator" |
442fcea7 PK |
440 | [(match_operand:QHSDint 1 "general_operand" "g") |
441 | (match_operand:QHSDint 2 "general_operand" "g")]) | |
f90b7a5a | 442 | (label_ref (match_operand 3 "" "")) |
2c9c2489 RK |
443 | (pc)))] |
444 | "" | |
b4324a14 PK |
445 | "#" |
446 | "reload_completed" | |
447 | [(set (reg:CC CC_REGNUM) | |
448 | (compare:CC (match_dup 1) (match_dup 2))) | |
449 | (set (pc) | |
450 | (if_then_else (match_op_dup 0 | |
451 | [(reg:CC CC_REGNUM) (const_int 0)]) | |
452 | (label_ref (match_dup 3)) | |
453 | (pc)))] | |
f90b7a5a | 454 | "") |
2c9c2489 | 455 | |
b4324a14 PK |
456 | ;; This splitter turns a branch on float condition into a branch on |
457 | ;; CPU condition, by adding a CFCC. | |
458 | (define_split | |
459 | [(set (pc) | |
460 | (if_then_else (match_operator 0 "ordered_comparison_operator" | |
461 | [(reg:CC FCC_REGNUM) (const_int 0)]) | |
462 | (label_ref (match_operand 1 "" "")) | |
463 | (pc)))] | |
464 | "TARGET_FPU && reload_completed" | |
465 | [(set (reg:CC CC_REGNUM) (reg:CC FCC_REGNUM)) | |
466 | (set (pc) | |
467 | (if_then_else (match_op_dup 0 | |
468 | [(reg:CC CC_REGNUM) (const_int 0)]) | |
469 | (label_ref (match_dup 1)) | |
470 | (pc)))] | |
471 | "") | |
2c9c2489 | 472 | |
b4324a14 | 473 | (define_insn "cond_branch" |
2c9c2489 | 474 | [(set (pc) |
f90b7a5a | 475 | (if_then_else (match_operator 0 "ordered_comparison_operator" |
b4324a14 | 476 | [(reg:CC CC_REGNUM) (const_int 0)]) |
f90b7a5a | 477 | (label_ref (match_operand 1 "" "")) |
2c9c2489 | 478 | (pc)))] |
b4324a14 PK |
479 | "reload_completed" |
480 | "* return output_jump (operands, 0, get_attr_length (insn));" | |
7021d5df | 481 | [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1) |
2c9c2489 | 482 | (pc)) |
7021d5df PK |
483 | (const_int MIN_BRANCH)) |
484 | (gt (minus (match_dup 1) | |
2c9c2489 | 485 | (pc)) |
7021d5df | 486 | (const_int MAX_BRANCH))) |
0f237806 PK |
487 | (const_int 6) |
488 | (const_int 2)))]) | |
2c9c2489 | 489 | |
b4324a14 | 490 | (define_insn "*branch" |
2c9c2489 | 491 | [(set (pc) |
b4324a14 PK |
492 | (if_then_else (match_operator 0 "ccnz_operator" |
493 | [(reg:CCNZ CC_REGNUM) (const_int 0)]) | |
494 | (label_ref (match_operand 1 "" "")) | |
495 | (pc)))] | |
496 | "reload_completed" | |
497 | "* return output_jump (operands, 1, get_attr_length (insn));" | |
7021d5df | 498 | [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1) |
2c9c2489 | 499 | (pc)) |
7021d5df PK |
500 | (const_int MIN_BRANCH)) |
501 | (gt (minus (match_dup 1) | |
2c9c2489 | 502 | (pc)) |
7021d5df | 503 | (const_int MAX_BRANCH))) |
0f237806 PK |
504 | (const_int 6) |
505 | (const_int 2)))]) | |
b4324a14 | 506 | |
2c9c2489 RK |
507 | \f |
508 | ;; Move instructions | |
509 | ||
aad2444d PK |
510 | ;; "length" is defined even though this pattern won't appear at |
511 | ;; assembly language output time. But the length is used by | |
512 | ;; pdp11_insn_cost, before the post-reload splitter adds the | |
513 | ;; CC clobber to the insn. | |
2c9c2489 | 514 | (define_insn "movdi" |
30442c59 PK |
515 | [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g") |
516 | (match_operand:DI 1 "general_operand" "rN,g"))] | |
2c9c2489 | 517 | "" |
aad2444d PK |
518 | "" |
519 | [(set_attr "length" "16,32")]) | |
b4324a14 PK |
520 | |
521 | ||
522 | (define_insn "*movdi_nocc" | |
523 | [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g") | |
524 | (match_operand:DI 1 "general_operand" "rN,g")) | |
525 | (clobber (reg:CC CC_REGNUM))] | |
526 | "" | |
30442c59 | 527 | "* return output_move_multiple (operands);" |
30442c59 | 528 | [(set_attr "length" "16,32")]) |
2c9c2489 RK |
529 | |
530 | (define_insn "movsi" | |
30442c59 PK |
531 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g") |
532 | (match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))] | |
2c9c2489 | 533 | "" |
aad2444d PK |
534 | "" |
535 | [(set_attr "length" "4,6,8,16")]) | |
b4324a14 PK |
536 | |
537 | (define_insn "*movsi_nocc" | |
538 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g") | |
539 | (match_operand:SI 1 "general_operand" "rN,IJ,IJ,g")) | |
540 | (clobber (reg:CC CC_REGNUM))] | |
541 | "" | |
30442c59 | 542 | "* return output_move_multiple (operands);" |
30442c59 | 543 | [(set_attr "length" "4,6,8,16")]) |
2c9c2489 | 544 | |
442fcea7 PK |
545 | ;; That long string of "Z" constraints enforces the restriction that |
546 | ;; a register source and auto increment or decrement destination must | |
547 | ;; not use the same register, because that case is not consistently | |
548 | ;; implemented across the PDP11 models. | |
549 | ;; TODO: the same should be applied to insn like add, but this is not | |
550 | ;; necessary yet because the incdec optimization pass does not apply | |
551 | ;; that optimization to 3-operand insns at the moment. | |
63caf8bb | 552 | (define_insn "mov<mode>" |
442fcea7 PK |
553 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Za,Zb,Zc,Zd,Ze,Zf,Zg,rD,rR,Q,Q") |
554 | (match_operand:PDPint 1 "general_operand" "RN,Z0,Z1,Z2,Z3,Z4,Z5,Z6,r,Qi,rRN,Qi"))] | |
2c9c2489 | 555 | "" |
aad2444d | 556 | "" |
442fcea7 | 557 | [(set_attr "length" "2,2,2,2,2,2,2,2,2,4,4,6")]) |
b4324a14 PK |
558 | |
559 | ;; This splits all the integer moves: DI and SI modes as well as | |
560 | ;; the simple machine operations. | |
561 | (define_split | |
562 | [(set (match_operand:QHSDint 0 "nonimmediate_operand" "") | |
563 | (match_operand:QHSDint 1 "general_operand" ""))] | |
564 | "reload_completed" | |
565 | [(parallel [(set (match_dup 0) | |
566 | (match_dup 1)) | |
567 | (clobber (reg:CC CC_REGNUM))])] | |
568 | "") | |
569 | ||
570 | ;; MOV clears V | |
571 | (define_insn "*mov<mode>_<cc_cc>" | |
442fcea7 PK |
572 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Za,Zb,Zc,Zd,Ze,Zf,Zg,rD,rR,Q,Q") |
573 | (match_operand:PDPint 1 "general_operand" "RN,Z0,Z1,Z2,Z3,Z4,Z5,Z6,r,Qi,rRN,Qi")) | |
b4324a14 PK |
574 | (clobber (reg:CC CC_REGNUM))] |
575 | "reload_completed" | |
2c9c2489 RK |
576 | "* |
577 | { | |
578 | if (operands[1] == const0_rtx) | |
4aef57c9 | 579 | return \"clr<PDPint:isfx>\t%0\"; |
2c9c2489 | 580 | |
4aef57c9 | 581 | return \"mov<PDPint:isfx>\t%1,%0\"; |
2c9c2489 | 582 | }" |
442fcea7 | 583 | [(set_attr "length" "2,2,2,2,2,2,2,2,2,4,4,6")]) |
2c9c2489 | 584 | |
b4324a14 PK |
585 | ;; movdf has unusually complicated condition code handling, because |
586 | ;; load (into float register) updates the FCC, while store (from | |
587 | ;; float register) leaves it untouched. | |
588 | ;; | |
589 | ;; 1. Loads are: ac4, ac5, or non-register into load-register | |
590 | ;; 2. Stores are: load-register to non-register, ac4, or ac5 | |
591 | ;; 3. Moves from ac0-ac3 to another ac0-ac3 can be handled | |
592 | ;; either as loads or as stores. | |
593 | ||
594 | (define_expand "movdf" | |
595 | [(set (match_operand:DF 0 "float_nonimm_operand" "") | |
596 | (match_operand:DF 1 "float_operand" ""))] | |
825cb171 | 597 | "TARGET_FPU" |
b4324a14 | 598 | "") |
2c9c2489 | 599 | |
b4324a14 PK |
600 | ;; Splitter for all these cases. Store is the first two |
601 | ;; alternatives, which are not split. Note that case 3 | |
602 | ;; is treated as a store, i.e., not split. | |
603 | (define_insn_and_split "movdf_split" | |
604 | [(set (match_operand:DF 0 "float_nonimm_operand" "=fR,FQ,a,a,a") | |
605 | (match_operand:DF 1 "float_operand" "a,a,hR,FQ,G"))] | |
2c9c2489 | 606 | "TARGET_FPU" |
b4324a14 PK |
607 | "* |
608 | gcc_assert (which_alternative < 2); | |
4aef57c9 | 609 | return \"std\t%1,%0\"; |
b4324a14 PK |
610 | " |
611 | "&& reload_completed" | |
612 | [(parallel [(set (match_dup 0) | |
613 | (match_dup 1)) | |
614 | (clobber (reg:CC FCC_REGNUM))])] | |
615 | "{ | |
616 | if (GET_CODE (operands[1]) == REG && | |
617 | REGNO_REG_CLASS (REGNO (operands[1])) == LOAD_FPU_REGS) | |
618 | FAIL; | |
619 | }" | |
620 | [(set_attr "length" "2,4,0,0,0")]) | |
621 | ||
622 | ;; Loads (case 1). | |
623 | (define_insn "*ldd<fcc_cc>" | |
624 | [(set (match_operand:DF 0 "float_nonimm_operand" "=a,a,a") | |
625 | (match_operand:DF 1 "float_operand" "hR,FQ,G")) | |
626 | (clobber (reg:CC FCC_REGNUM))] | |
627 | "TARGET_FPU && reload_completed" | |
628 | "@ | |
4aef57c9 PK |
629 | ldd\t%1,%0 |
630 | ldd\t%1,%0 | |
631 | clrd\t%0" | |
b4324a14 PK |
632 | [(set_attr "length" "2,4,2")]) |
633 | ||
634 | ;; SFmode is easier because that uses convert load/store, which | |
635 | ;; always change condition codes. | |
636 | ;; Note that these insns are cheating a bit. We actually have | |
637 | ;; DFmode operands in the FPU registers, which is why the | |
638 | ;; ldcfd and stcdf instructions appear. But GCC likes to think | |
639 | ;; of these as SFmode loads and does the conversion once in the | |
640 | ;; register, at least in many cases. So we pretend to do this, | |
641 | ;; but then extend and truncate register-to-register are NOP and | |
642 | ;; generate no code. | |
643 | (define_insn_and_split "movsf" | |
aad2444d PK |
644 | [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,a") |
645 | (match_operand:SF 1 "float_operand" "fRG,a,FQ,a,G"))] | |
b4324a14 PK |
646 | "TARGET_FPU" |
647 | "#" | |
648 | "&& reload_completed" | |
649 | [(parallel [(set (match_dup 0) | |
650 | (match_dup 1)) | |
651 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
652 | "" |
653 | [(set_attr "length" "2,2,4,4,2")]) | |
b4324a14 PK |
654 | |
655 | (define_insn "*movsf<fcc_ccnz>" | |
656 | [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,a") | |
657 | (match_operand:SF 1 "float_operand" "fR,a,FQ,a,G")) | |
658 | (clobber (reg:CC FCC_REGNUM))] | |
659 | "TARGET_FPU && reload_completed" | |
660 | "@ | |
4aef57c9 PK |
661 | {ldcfd|movof}\t%1,%0 |
662 | {stcdf|movfo}\t%1,%0 | |
663 | {ldcfd|movof}\t%1,%0 | |
664 | {stcdf|movfo}\t%1,%0 | |
665 | clrf\t%0" | |
b4324a14 | 666 | [(set_attr "length" "2,2,4,4,2")]) |
2c9c2489 | 667 | |
a3368b8e | 668 | ;; Expand a block move. We turn this into a move loop. |
76715c32 AS |
669 | (define_expand "cpymemhi" |
670 | [(parallel [(unspec_volatile [(const_int 0)] UNSPECV_CPYMEM) | |
442fcea7 PK |
671 | (match_operand:BLK 0 "general_operand" "=g") |
672 | (match_operand:BLK 1 "general_operand" "g") | |
673 | (match_operand:HI 2 "immediate_operand" "i") | |
674 | (match_operand:HI 3 "immediate_operand" "i") | |
675 | (clobber (mem:BLK (scratch))) | |
676 | (clobber (match_dup 0)) | |
677 | (clobber (match_dup 1)) | |
678 | (clobber (match_dup 2))])] | |
b4324a14 | 679 | "" |
2c9c2489 RK |
680 | " |
681 | { | |
442fcea7 PK |
682 | int count; |
683 | count = INTVAL (operands[2]); | |
684 | if (count == 0) | |
685 | DONE; | |
686 | if (INTVAL (operands [3]) >= 2 && (count & 1) == 0) | |
687 | count >>= 1; | |
688 | else | |
689 | operands[3] = const1_rtx; | |
690 | operands[2] = copy_to_mode_reg (HImode, | |
691 | gen_rtx_CONST_INT (HImode, count)); | |
692 | ||
693 | /* Load BLKmode MEM addresses into scratch registers. */ | |
694 | operands[0] = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); | |
695 | operands[1] = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); | |
2c9c2489 RK |
696 | }") |
697 | ||
442fcea7 | 698 | ;; Expand a block move. We turn this into a move loop. |
76715c32 AS |
699 | (define_insn_and_split "cpymemhi1" |
700 | [(unspec_volatile [(const_int 0)] UNSPECV_CPYMEM) | |
442fcea7 PK |
701 | (match_operand:HI 0 "register_operand" "+r") |
702 | (match_operand:HI 1 "register_operand" "+r") | |
703 | (match_operand:HI 2 "register_operand" "+r") | |
704 | (match_operand:HI 3 "immediate_operand" "i") | |
705 | (clobber (mem:BLK (scratch))) | |
706 | (clobber (match_dup 0)) | |
707 | (clobber (match_dup 1)) | |
708 | (clobber (match_dup 2))] | |
709 | "" | |
710 | "#" | |
711 | "reload_completed" | |
76715c32 | 712 | [(parallel [(unspec_volatile [(const_int 0)] UNSPECV_CPYMEM) |
442fcea7 PK |
713 | (match_dup 0) |
714 | (match_dup 1) | |
715 | (match_dup 2) | |
716 | (match_dup 3) | |
717 | (clobber (mem:BLK (scratch))) | |
718 | (clobber (match_dup 0)) | |
719 | (clobber (match_dup 1)) | |
720 | (clobber (match_dup 2)) | |
721 | (clobber (reg:CC CC_REGNUM))])] | |
722 | "") | |
723 | ||
76715c32 AS |
724 | (define_insn "cpymemhi_nocc" |
725 | [(unspec_volatile [(const_int 0)] UNSPECV_CPYMEM) | |
442fcea7 PK |
726 | (match_operand:HI 0 "register_operand" "+r") |
727 | (match_operand:HI 1 "register_operand" "+r") | |
728 | (match_operand:HI 2 "register_operand" "+r") | |
729 | (match_operand:HI 3 "immediate_operand" "i") | |
730 | (clobber (mem:BLK (scratch))) | |
731 | (clobber (match_dup 0)) | |
732 | (clobber (match_dup 1)) | |
733 | (clobber (match_dup 2)) | |
734 | (clobber (reg:CC CC_REGNUM))] | |
735 | "reload_completed" | |
736 | "* | |
737 | { | |
738 | rtx lb[2]; | |
739 | ||
740 | lb[0] = operands[2]; | |
741 | lb[1] = gen_label_rtx (); | |
742 | ||
743 | output_asm_label (lb[1]); | |
744 | fputs (\":\n\", asm_out_file); | |
745 | if (INTVAL (operands[3]) > 1) | |
746 | output_asm_insn (\"mov\t(%1)+,(%0)+\", operands); | |
747 | else | |
748 | output_asm_insn (\"movb\t(%1)+,(%0)+\", operands); | |
749 | if (TARGET_40_PLUS) | |
750 | output_asm_insn (\"sob\t%0,%l1\", lb); | |
751 | else | |
752 | { | |
753 | output_asm_insn (\"dec\t%0\", lb); | |
754 | output_asm_insn (\"bne\t%l1\", lb); | |
755 | } | |
756 | return \"\"; | |
757 | }" | |
758 | [(set (attr "length") | |
759 | (if_then_else (match_test "TARGET_40_PLUS") | |
760 | (const_int 4) | |
761 | (const_int 6)))]) | |
2c9c2489 RK |
762 | \f |
763 | ;;- truncation instructions | |
764 | ||
b4324a14 PK |
765 | ;; We sometimes end up doing a register to register truncate, |
766 | ;; which isn't right because we actually load registers always | |
767 | ;; with a DFmode value. But even with PROMOTE the compiler | |
768 | ;; doesn't always get that (so we don't use it). That means | |
769 | ;; a register to register truncate is a NOP. | |
770 | (define_insn_and_split "truncdfsf2" | |
166208c2 | 771 | [(set (match_operand:SF 0 "float_nonimm_operand" "=f,R,Q") |
b4324a14 | 772 | (float_truncate:SF (match_operand:DF 1 "register_operand" "0,a,a")))] |
2c9c2489 | 773 | "TARGET_FPU" |
b4324a14 PK |
774 | { |
775 | gcc_assert (which_alternative == 0); | |
776 | return ""; | |
777 | } | |
778 | "&& reload_completed" | |
779 | [(parallel [(set (match_dup 0) (float_truncate:SF (match_dup 1))) | |
780 | (clobber (reg:CC FCC_REGNUM))])] | |
781 | "{ | |
782 | if (GET_CODE (operands[0]) == REG && | |
783 | GET_CODE (operands[1]) == REG && | |
784 | REGNO (operands[0]) == REGNO (operands[1])) | |
785 | FAIL; | |
786 | }" | |
787 | [(set_attr "length" "0,0,0")]) | |
788 | ||
789 | (define_insn "*truncdfsf2_<fcc_cc>" | |
790 | [(set (match_operand:SF 0 "float_nonimm_operand" "=R,Q") | |
791 | (float_truncate:SF (match_operand:DF 1 "register_operand" "a,a"))) | |
792 | (clobber (reg:CC FCC_REGNUM))] | |
793 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 794 | "{stcdf|movfo}\t%1,%0" |
b4324a14 | 795 | [(set_attr "length" "2,4")]) |
2c9c2489 | 796 | |
2c9c2489 | 797 | \f |
aad2444d | 798 | ;;- zero extension instruction |
2c9c2489 | 799 | |
b4324a14 | 800 | (define_insn_and_split "zero_extendqihi2" |
aad2444d PK |
801 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rD,Q,&r,&r") |
802 | (zero_extend:HI (match_operand:QI 1 "general_operand" "0,0,rR,Q")))] | |
2c9c2489 | 803 | "" |
b4324a14 PK |
804 | "#" |
805 | "reload_completed" | |
806 | [(parallel [(set (match_dup 0) (zero_extend:HI (match_dup 1))) | |
807 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
808 | "{ |
809 | rtx r; | |
810 | ||
811 | if (!REG_P (operands[0])) | |
812 | { | |
813 | r = gen_rtx_MEM (QImode, operands[0]); | |
814 | adjust_address (r, QImode, 1); | |
815 | emit_move_insn (r, const0_rtx); | |
816 | DONE; | |
817 | } | |
442fcea7 PK |
818 | else if (!REG_P (operands[1]) || |
819 | REGNO (operands[0]) != REGNO (operands[1])) | |
aad2444d PK |
820 | { |
821 | /* Alternatives 2 and 3 */ | |
822 | emit_move_insn (operands[0], const0_rtx); | |
823 | r = gen_rtx_REG (QImode, REGNO (operands[0])); | |
824 | emit_insn (gen_iorqi3_nocc (r, r, operands[1])); | |
825 | DONE; | |
826 | } | |
827 | }" | |
828 | [(set_attr "length" "4,4,4,6")]) | |
b4324a14 PK |
829 | |
830 | (define_insn "*zero_extendqihi2<cc_cc>" | |
831 | [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") | |
832 | (zero_extend:HI (match_operand:QI 1 "general_operand" "0,0"))) | |
833 | (clobber (reg:CC CC_REGNUM))])] | |
834 | "reload_completed" | |
4aef57c9 | 835 | "bic\t%#0177400,%0" |
0f237806 | 836 | [(set_attr "length" "4,6")]) |
2c9c2489 | 837 | |
2c9c2489 RK |
838 | ;;- sign extension instructions |
839 | ||
b4324a14 PK |
840 | ;; We sometimes end up doing a register to register extend, |
841 | ;; which isn't right because we actually load registers always | |
842 | ;; with a DFmode value. But even with PROMOTE the compiler | |
843 | ;; doesn't always get that (so we don't use it). That means | |
844 | ;; a register to register truncate is a NOP. | |
845 | (define_insn_and_split "extendsfdf2" | |
a01c666c | 846 | [(set (match_operand:DF 0 "register_operand" "=f,a,a") |
b4324a14 | 847 | (float_extend:DF (match_operand:SF 1 "float_operand" "0,R,Q")))] |
2c9c2489 | 848 | "TARGET_FPU" |
b4324a14 PK |
849 | { |
850 | gcc_assert (which_alternative == 0); | |
851 | return ""; | |
852 | } | |
853 | "&& reload_completed" | |
854 | [(parallel [(set (match_dup 0) (float_extend:DF (match_dup 1))) | |
855 | (clobber (reg:CC FCC_REGNUM))])] | |
856 | "{ | |
857 | if (GET_CODE (operands[0]) == REG && | |
858 | GET_CODE (operands[1]) == REG && | |
859 | REGNO (operands[0]) == REGNO (operands[1])) | |
860 | FAIL; | |
861 | }" | |
862 | [(set_attr "length" "0,0,0")]) | |
863 | ||
864 | (define_insn "*extendsfdf2_<fcc_cc>" | |
865 | [(set (match_operand:DF 0 "register_operand" "=a,a") | |
866 | (float_extend:DF (match_operand:SF 1 "float_operand" "R,Q"))) | |
867 | (clobber (reg:CC FCC_REGNUM))] | |
868 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 869 | "{ldcfd|movof}\t%1,%0" |
aad2444d PK |
870 | [(set_attr "length" "2,4") |
871 | (set_attr "base_cost" "6")]) | |
2c9c2489 | 872 | |
b4324a14 PK |
873 | ;; movb sign extends if destination is a register |
874 | (define_insn_and_split "extendqihi2" | |
2c9c2489 RK |
875 | [(set (match_operand:HI 0 "register_operand" "=r,r") |
876 | (sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))] | |
877 | "" | |
b4324a14 PK |
878 | "#" |
879 | "reload_completed" | |
880 | [(parallel [(set (match_dup 0) (sign_extend:HI (match_dup 1))) | |
881 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
882 | "" |
883 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
884 | |
885 | ;; MOVB clears V | |
886 | (define_insn "*extendqihi2<cc_cc>" | |
887 | [(set (match_operand:HI 0 "register_operand" "=r,r") | |
888 | (sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q"))) | |
889 | (clobber (reg:CC CC_REGNUM))] | |
890 | "reload_completed" | |
4aef57c9 | 891 | "movb\t%1,%0" |
0f237806 | 892 | [(set_attr "length" "2,4")]) |
2c9c2489 | 893 | |
b4324a14 | 894 | (define_insn_and_split "extendhisi2" |
166208c2 | 895 | [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r") |
2c9c2489 RK |
896 | (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))] |
897 | "TARGET_40_PLUS" | |
b4324a14 PK |
898 | "#" |
899 | "&& reload_completed" | |
900 | [(parallel [(set (match_dup 0) (sign_extend:SI (match_dup 1))) | |
901 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
902 | "" |
903 | [(set_attr "length" "10,6,6")]) | |
b4324a14 PK |
904 | |
905 | (define_insn "*extendhisi2_nocc" | |
906 | [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r") | |
907 | (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g"))) | |
908 | (clobber (reg:CC CC_REGNUM))] | |
909 | "TARGET_40_PLUS && reload_completed" | |
2c9c2489 RK |
910 | "* |
911 | { | |
912 | rtx latehalf[2]; | |
913 | ||
914 | /* we don't want to mess with auto increment */ | |
915 | ||
b72f00af | 916 | switch (which_alternative) |
2c9c2489 RK |
917 | { |
918 | case 0: | |
919 | ||
920 | latehalf[0] = operands[0]; | |
b72f00af | 921 | operands[0] = adjust_address(operands[0], HImode, 2); |
2c9c2489 | 922 | |
4aef57c9 PK |
923 | output_asm_insn(\"mov\t%1,%0\", operands); |
924 | output_asm_insn(\"sxt\t%0\", latehalf); | |
2c9c2489 RK |
925 | |
926 | return \"\"; | |
927 | ||
928 | case 1: | |
929 | ||
930 | /* - auto-decrement - right direction ;-) */ | |
4aef57c9 PK |
931 | output_asm_insn(\"mov\t%1,%0\", operands); |
932 | output_asm_insn(\"sxt\t%0\", operands); | |
2c9c2489 RK |
933 | |
934 | return \"\"; | |
935 | ||
936 | case 2: | |
937 | ||
938 | /* make register pair available */ | |
939 | latehalf[0] = operands[0]; | |
c5c76735 | 940 | operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1); |
2c9c2489 | 941 | |
4aef57c9 PK |
942 | output_asm_insn(\"mov\t%1,%0\", operands); |
943 | output_asm_insn(\"sxt\t%0\", latehalf); | |
2c9c2489 RK |
944 | |
945 | return \"\"; | |
946 | ||
947 | default: | |
948 | ||
d35d9223 | 949 | gcc_unreachable (); |
2c9c2489 RK |
950 | } |
951 | }" | |
0f237806 | 952 | [(set_attr "length" "10,6,6")]) |
2c9c2489 | 953 | |
2c9c2489 | 954 | ;; make float to int and vice versa |
2c9c2489 RK |
955 | ;; assume that we are normally in double and integer mode - |
956 | ;; what do pdp library routines do to fpu mode ? | |
957 | ||
b4324a14 PK |
958 | ;; Note: the hardware treats register source as |
959 | ;; a 16-bit (high order only) source, which isn't | |
960 | ;; what we want. But we do need to support register | |
961 | ;; dest because gcc asks for it. | |
962 | (define_insn_and_split "floatsidf2" | |
e3be1b32 RK |
963 | [(set (match_operand:DF 0 "register_operand" "=a,a,a") |
964 | (float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))] | |
2c9c2489 | 965 | "TARGET_FPU" |
b4324a14 PK |
966 | "#" |
967 | "&& reload_completed" | |
968 | [(parallel [(set (match_dup 0) (float:DF (match_dup 1))) | |
969 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
970 | "" |
971 | [(set_attr "length" "10,6,8")]) | |
b4324a14 PK |
972 | |
973 | (define_insn "*floatsidf2<fcc_cc>" | |
974 | [(set (match_operand:DF 0 "register_operand" "=a,a,a") | |
975 | (float:DF (match_operand:SI 1 "general_operand" "r,R,Q"))) | |
976 | (clobber (reg:CC FCC_REGNUM))] | |
977 | "TARGET_FPU && reload_completed" | |
e3be1b32 RK |
978 | "* if (which_alternative ==0) |
979 | { | |
980 | rtx latehalf[2]; | |
b4324a14 | 981 | |
e3be1b32 | 982 | latehalf[0] = NULL; |
e7f9979a | 983 | latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1); |
4aef57c9 PK |
984 | output_asm_insn(\"mov\t%1,-(sp)\", latehalf); |
985 | output_asm_insn(\"mov\t%1,-(sp)\", operands); | |
e3be1b32 RK |
986 | |
987 | output_asm_insn(\"setl\", operands); | |
4aef57c9 | 988 | output_asm_insn(\"{ldcld|movif}\t(sp)+,%0\", operands); |
e3be1b32 RK |
989 | output_asm_insn(\"seti\", operands); |
990 | return \"\"; | |
991 | } | |
e3be1b32 | 992 | else |
4aef57c9 | 993 | return \"setl\;{ldcld|movif}\t%1,%0\;seti\"; |
e3be1b32 | 994 | " |
aad2444d PK |
995 | [(set_attr "length" "10,6,8") |
996 | (set_attr "base_cost" "12")]) | |
2c9c2489 | 997 | |
b4324a14 | 998 | (define_insn_and_split "floathidf2" |
2c9c2489 RK |
999 | [(set (match_operand:DF 0 "register_operand" "=a,a") |
1000 | (float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))] | |
1001 | "TARGET_FPU" | |
b4324a14 PK |
1002 | "#" |
1003 | "&& reload_completed" | |
1004 | [(parallel [(set (match_dup 0) (float:DF (match_dup 1))) | |
1005 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
1006 | "" |
1007 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1008 | |
1009 | (define_insn "*floathidf2<fcc_cc>" | |
1010 | [(set (match_operand:DF 0 "register_operand" "=a,a") | |
1011 | (float:DF (match_operand:HI 1 "general_operand" "rR,Qi"))) | |
1012 | (clobber (reg:CC FCC_REGNUM))] | |
1013 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 1014 | "{ldcid|movif}\t%1,%0" |
aad2444d PK |
1015 | [(set_attr "length" "2,4") |
1016 | (set_attr "base_cost" "12")]) | |
1017 | ||
2c9c2489 | 1018 | ;; cut float to int |
b4324a14 PK |
1019 | |
1020 | ;; Note: the hardware treats register destination as | |
1021 | ;; a 16-bit (high order only) destination, which isn't | |
1022 | ;; what we want. But we do need to support register | |
1023 | ;; dest because gcc asks for it. | |
1024 | (define_insn_and_split "fix_truncdfsi2" | |
166208c2 | 1025 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q") |
e3be1b32 | 1026 | (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))] |
2c9c2489 | 1027 | "TARGET_FPU" |
b4324a14 PK |
1028 | "#" |
1029 | "&& reload_completed" | |
1030 | [(parallel [(set (match_dup 0) (fix:SI (fix:DF (match_dup 1)))) | |
1031 | (clobber (reg:CC CC_REGNUM)) | |
1032 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
1033 | "" |
1034 | [(set_attr "length" "10,6,8")]) | |
b4324a14 PK |
1035 | |
1036 | ;; Note: this clobbers both sets of condition codes! | |
1037 | (define_insn "*fix_truncdfsi2_nocc" | |
1038 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q") | |
1039 | (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a")))) | |
1040 | (clobber (reg:CC CC_REGNUM)) | |
1041 | (clobber (reg:CC FCC_REGNUM))] | |
1042 | "TARGET_FPU && reload_completed" | |
e3be1b32 RK |
1043 | "* if (which_alternative ==0) |
1044 | { | |
1045 | output_asm_insn(\"setl\", operands); | |
4aef57c9 | 1046 | output_asm_insn(\"{stcdl|movfi}\t%1,-(sp)\", operands); |
e3be1b32 | 1047 | output_asm_insn(\"seti\", operands); |
4aef57c9 | 1048 | output_asm_insn(\"mov\t(sp)+,%0\", operands); |
c5c76735 | 1049 | operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1); |
4aef57c9 | 1050 | output_asm_insn(\"mov\t(sp)+,%0\", operands); |
e3be1b32 RK |
1051 | return \"\"; |
1052 | } | |
e3be1b32 | 1053 | else |
4aef57c9 | 1054 | return \"setl\;{stcdl|movfi}\t%1,%0\;seti\"; |
e3be1b32 | 1055 | " |
aad2444d PK |
1056 | [(set_attr "length" "10,6,8") |
1057 | (set_attr "base_cost" "12")]) | |
2c9c2489 | 1058 | |
b4324a14 | 1059 | (define_insn_and_split "fix_truncdfhi2" |
166208c2 | 1060 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") |
2c9c2489 RK |
1061 | (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))] |
1062 | "TARGET_FPU" | |
b4324a14 PK |
1063 | "#" |
1064 | "&& reload_completed" | |
1065 | [(parallel [(set (match_dup 0) (fix:HI (fix:DF (match_dup 1)))) | |
1066 | (clobber (reg:CC CC_REGNUM)) | |
1067 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
1068 | "" |
1069 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1070 | |
1071 | ;; Note: this clobbers both sets of condition codes! | |
1072 | (define_insn "*fix_truncdfhi2_nocc" | |
1073 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") | |
1074 | (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a")))) | |
1075 | (clobber (reg:CC CC_REGNUM)) | |
1076 | (clobber (reg:CC FCC_REGNUM))] | |
1077 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 1078 | "{stcdi|movfi}\t%1,%0" |
aad2444d PK |
1079 | [(set_attr "length" "2,4") |
1080 | (set_attr "base_cost" "12")]) | |
2c9c2489 RK |
1081 | |
1082 | \f | |
1083 | ;;- arithmetic instructions | |
1084 | ;;- add instructions | |
1085 | ||
b4324a14 | 1086 | (define_insn_and_split "adddf3" |
c67b2d4e PK |
1087 | [(set (match_operand:DF 0 "register_operand" "=a,a") |
1088 | (plus:DF (match_operand:DF 1 "register_operand" "%0,0") | |
1089 | (match_operand:DF 2 "general_operand" "fR,QF")))] | |
2c9c2489 | 1090 | "TARGET_FPU" |
b4324a14 PK |
1091 | "#" |
1092 | "&& reload_completed" | |
1093 | [(parallel [(set (match_dup 0) | |
1094 | (plus:DF (match_dup 1) (match_dup 2))) | |
1095 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
1096 | "" |
1097 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1098 | |
1099 | ;; Float add sets V if overflow from add | |
1100 | (define_insn "*adddf3<fcc_ccnz>" | |
1101 | [(set (match_operand:DF 0 "register_operand" "=a,a") | |
1102 | (plus:DF (match_operand:DF 1 "register_operand" "%0,0") | |
1103 | (match_operand:DF 2 "general_operand" "fR,QF"))) | |
1104 | (clobber (reg:CC FCC_REGNUM))] | |
1105 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 1106 | "{addd|addf}\t%2,%0" |
aad2444d PK |
1107 | [(set_attr "length" "2,4") |
1108 | (set_attr "base_cost" "6")]) | |
2c9c2489 | 1109 | |
b4324a14 | 1110 | (define_insn_and_split "adddi3" |
30442c59 PK |
1111 | [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") |
1112 | (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0") | |
1113 | (match_operand:DI 2 "general_operand" "r,on,r,on")))] | |
2c9c2489 | 1114 | "" |
b4324a14 PK |
1115 | "#" |
1116 | "reload_completed" | |
1117 | [(parallel [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2))) | |
1118 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1119 | "" |
1120 | [(set_attr "length" "20,28,40,48")]) | |
b4324a14 PK |
1121 | |
1122 | (define_insn "*adddi3_nocc" | |
1123 | [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") | |
1124 | (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0") | |
1125 | (match_operand:DI 2 "general_operand" "r,on,r,on"))) | |
1126 | (clobber (reg:CC CC_REGNUM))] | |
1127 | "reload_completed" | |
2c9c2489 | 1128 | "* |
30442c59 PK |
1129 | { |
1130 | rtx inops[2]; | |
1131 | rtx exops[4][2]; | |
2c9c2489 | 1132 | |
30442c59 PK |
1133 | inops[0] = operands[0]; |
1134 | inops[1] = operands[2]; | |
442fcea7 | 1135 | pdp11_expand_operands (inops, exops, 2, 4, NULL, big); |
2c9c2489 | 1136 | |
442fcea7 | 1137 | if (!CONST_INT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0) |
4aef57c9 | 1138 | output_asm_insn (\"add\t%1,%0\", exops[0]); |
442fcea7 | 1139 | if (!CONST_INT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0) |
2c9c2489 | 1140 | { |
4aef57c9 PK |
1141 | output_asm_insn (\"add\t%1,%0\", exops[1]); |
1142 | output_asm_insn (\"adc\t%0\", exops[0]); | |
30442c59 | 1143 | } |
442fcea7 | 1144 | if (!CONST_INT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0) |
30442c59 | 1145 | { |
4aef57c9 PK |
1146 | output_asm_insn (\"add\t%1,%0\", exops[2]); |
1147 | output_asm_insn (\"adc\t%0\", exops[1]); | |
1148 | output_asm_insn (\"adc\t%0\", exops[0]); | |
30442c59 | 1149 | } |
442fcea7 | 1150 | if (!CONST_INT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0) |
30442c59 | 1151 | { |
4aef57c9 PK |
1152 | output_asm_insn (\"add\t%1,%0\", exops[3]); |
1153 | output_asm_insn (\"adc\t%0\", exops[2]); | |
1154 | output_asm_insn (\"adc\t%0\", exops[1]); | |
1155 | output_asm_insn (\"adc\t%0\", exops[0]); | |
2c9c2489 RK |
1156 | } |
1157 | ||
30442c59 PK |
1158 | return \"\"; |
1159 | }" | |
aad2444d PK |
1160 | [(set_attr "length" "20,28,40,48") |
1161 | (set_attr "base_cost" "0")]) | |
30442c59 PK |
1162 | |
1163 | ;; Note that the register operand is not marked earlyclobber. | |
1164 | ;; The reason is that SI values go in register pairs, so they | |
1165 | ;; can't partially overlap. They can be either disjoint, or | |
1166 | ;; source and destination can be equal. The latter case is | |
1167 | ;; handled properly because of the ordering of the individual | |
1168 | ;; instructions used. Specifically, carry from the low to the | |
1169 | ;; high word is added at the end, so the adding of the high parts | |
1170 | ;; will always used the original high part and not a high part | |
1171 | ;; modified by carry (which would amount to double carry). | |
b4324a14 PK |
1172 | (define_insn_and_split "addsi3" |
1173 | [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o") | |
30442c59 PK |
1174 | (plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0") |
1175 | (match_operand:SI 2 "general_operand" "r,on,r,on")))] | |
1176 | "" | |
b4324a14 PK |
1177 | "#" |
1178 | "reload_completed" | |
1179 | [(parallel [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) | |
1180 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1181 | "" |
1182 | [(set_attr "length" "6,10,12,16")]) | |
b4324a14 PK |
1183 | |
1184 | (define_insn "*addsi3_nocc" | |
1185 | [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o") | |
1186 | (plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0") | |
1187 | (match_operand:SI 2 "general_operand" "r,on,r,on"))) | |
1188 | (clobber (reg:CC CC_REGNUM))] | |
1189 | "reload_completed" | |
30442c59 PK |
1190 | "* |
1191 | { | |
1192 | rtx inops[2]; | |
1193 | rtx exops[2][2]; | |
2c9c2489 | 1194 | |
30442c59 PK |
1195 | inops[0] = operands[0]; |
1196 | inops[1] = operands[2]; | |
442fcea7 | 1197 | pdp11_expand_operands (inops, exops, 2, 2, NULL, big); |
30442c59 | 1198 | |
442fcea7 | 1199 | if (!CONST_INT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0) |
4aef57c9 | 1200 | output_asm_insn (\"add\t%1,%0\", exops[0]); |
442fcea7 | 1201 | if (!CONST_INT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0) |
30442c59 | 1202 | { |
4aef57c9 PK |
1203 | output_asm_insn (\"add\t%1,%0\", exops[1]); |
1204 | output_asm_insn (\"adc\t%0\", exops[0]); | |
2c9c2489 RK |
1205 | } |
1206 | ||
2c9c2489 RK |
1207 | return \"\"; |
1208 | }" | |
aad2444d PK |
1209 | [(set_attr "length" "6,10,12,16") |
1210 | (set_attr "base_cost" "0")]) | |
2c9c2489 | 1211 | |
b4324a14 | 1212 | (define_insn_and_split "addhi3" |
166208c2 | 1213 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") |
2c9c2489 RK |
1214 | (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0") |
1215 | (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))] | |
1216 | "" | |
b4324a14 PK |
1217 | "#" |
1218 | "reload_completed" | |
1219 | [(parallel [(set (match_dup 0) | |
1220 | (plus:HI (match_dup 1) (match_dup 2))) | |
1221 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1222 | "" |
1223 | [(set_attr "length" "2,4,4,6")]) | |
b4324a14 PK |
1224 | |
1225 | ;; Add sets V if overflow from the add | |
1226 | (define_insn "*addhi3<cc_ccnz>" | |
1227 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") | |
1228 | (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0") | |
1229 | (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi"))) | |
1230 | (clobber (reg:CC CC_REGNUM))] | |
1231 | "reload_completed" | |
2c9c2489 RK |
1232 | "* |
1233 | { | |
1234 | if (GET_CODE (operands[2]) == CONST_INT) | |
09b893bb JM |
1235 | { |
1236 | if (INTVAL(operands[2]) == 1) | |
4aef57c9 | 1237 | return \"inc\t%0\"; |
09b893bb | 1238 | else if (INTVAL(operands[2]) == -1) |
4aef57c9 | 1239 | return \"dec\t%0\"; |
09b893bb | 1240 | } |
2c9c2489 | 1241 | |
4aef57c9 | 1242 | return \"add\t%2,%0\"; |
2c9c2489 | 1243 | }" |
0f237806 | 1244 | [(set_attr "length" "2,4,4,6")]) |
2c9c2489 | 1245 | |
fe65151b PK |
1246 | (define_insn_and_split "addqi3" |
1247 | [(set (match_operand:QI 0 "nonimmediate_operand" "=rR,Q") | |
1248 | (plus:QI (match_operand:QI 1 "general_operand" "%0,0") | |
1249 | (match_operand:QI 2 "incdec_operand" "LM,LM")))] | |
1250 | "" | |
1251 | "#" | |
1252 | "reload_completed" | |
1253 | [(parallel [(set (match_dup 0) | |
1254 | (plus:QI (match_dup 1) (match_dup 2))) | |
1255 | (clobber (reg:CC CC_REGNUM))])] | |
1256 | "" | |
1257 | [(set_attr "length" "2,4")]) | |
1258 | ||
1259 | ;; Inc/dec sets V if overflow from the operation | |
1260 | (define_insn "*addqi3<cc_ccnz>" | |
1261 | [(set (match_operand:QI 0 "nonimmediate_operand" "=rR,Q") | |
1262 | (plus:QI (match_operand:QI 1 "general_operand" "%0,0") | |
1263 | (match_operand:QI 2 "incdec_operand" "LM,LM"))) | |
1264 | (clobber (reg:CC CC_REGNUM))] | |
1265 | "reload_completed" | |
1266 | "* | |
1267 | { | |
1268 | if (INTVAL(operands[2]) == 1) | |
1269 | return \"incb\t%0\"; | |
1270 | else | |
1271 | return \"decb\t%0\"; | |
1272 | }" | |
1273 | [(set_attr "length" "2,4")]) | |
1274 | ||
2c9c2489 RK |
1275 | \f |
1276 | ;;- subtract instructions | |
1277 | ;; we don't have to care for constant second | |
ddd5a7c1 | 1278 | ;; args, since they are canonical plus:xx now! |
2c9c2489 RK |
1279 | ;; also for minus:DF ?? |
1280 | ||
b4324a14 | 1281 | (define_insn_and_split "subdf3" |
2c9c2489 RK |
1282 | [(set (match_operand:DF 0 "register_operand" "=a,a") |
1283 | (minus:DF (match_operand:DF 1 "register_operand" "0,0") | |
1284 | (match_operand:DF 2 "general_operand" "fR,Q")))] | |
1285 | "TARGET_FPU" | |
b4324a14 PK |
1286 | "#" |
1287 | "&& reload_completed" | |
1288 | [(parallel [(set (match_dup 0) | |
1289 | (minus:DF (match_dup 1) (match_dup 2))) | |
1290 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
1291 | "" |
1292 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1293 | |
1294 | (define_insn "*subdf3<fcc_ccnz>" | |
1295 | [(set (match_operand:DF 0 "register_operand" "=a,a") | |
1296 | (minus:DF (match_operand:DF 1 "register_operand" "0,0") | |
1297 | (match_operand:DF 2 "general_operand" "fR,QF"))) | |
1298 | (clobber (reg:CC FCC_REGNUM))] | |
1299 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 1300 | "{subd|subf}\t%2,%0" |
aad2444d PK |
1301 | [(set_attr "length" "2,4") |
1302 | (set_attr "base_cost" "6")]) | |
2c9c2489 | 1303 | |
b4324a14 | 1304 | (define_insn_and_split "subdi3" |
30442c59 PK |
1305 | [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") |
1306 | (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0") | |
1307 | (match_operand:DI 2 "general_operand" "r,on,r,on")))] | |
2c9c2489 | 1308 | "" |
b4324a14 PK |
1309 | "#" |
1310 | "reload_completed" | |
1311 | [(parallel [(set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2))) | |
1312 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1313 | "" |
1314 | [(set_attr "length" "20,28,40,48")]) | |
b4324a14 PK |
1315 | |
1316 | (define_insn "*subdi3_nocc" | |
1317 | [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") | |
1318 | (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0") | |
1319 | (match_operand:DI 2 "general_operand" "r,on,r,on"))) | |
1320 | (clobber (reg:CC CC_REGNUM))] | |
1321 | "reload_completed" | |
2c9c2489 | 1322 | "* |
30442c59 PK |
1323 | { |
1324 | rtx inops[2]; | |
1325 | rtx exops[4][2]; | |
1326 | ||
1327 | inops[0] = operands[0]; | |
1328 | inops[1] = operands[2]; | |
442fcea7 | 1329 | pdp11_expand_operands (inops, exops, 2, 4, NULL, big); |
30442c59 | 1330 | |
442fcea7 | 1331 | if (!CONST_INT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0) |
4aef57c9 | 1332 | output_asm_insn (\"sub\t%1,%0\", exops[0]); |
442fcea7 | 1333 | if (!CONST_INT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0) |
30442c59 | 1334 | { |
4aef57c9 PK |
1335 | output_asm_insn (\"sub\t%1,%0\", exops[1]); |
1336 | output_asm_insn (\"sbc\t%0\", exops[0]); | |
30442c59 | 1337 | } |
442fcea7 | 1338 | if (!CONST_INT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0) |
30442c59 | 1339 | { |
4aef57c9 PK |
1340 | output_asm_insn (\"sub\t%1,%0\", exops[2]); |
1341 | output_asm_insn (\"sbc\t%0\", exops[1]); | |
1342 | output_asm_insn (\"sbc\t%0\", exops[0]); | |
30442c59 | 1343 | } |
442fcea7 | 1344 | if (!CONST_INT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0) |
30442c59 | 1345 | { |
4aef57c9 PK |
1346 | output_asm_insn (\"sub\t%1,%0\", exops[3]); |
1347 | output_asm_insn (\"sbc\t%0\", exops[2]); | |
1348 | output_asm_insn (\"sbc\t%0\", exops[1]); | |
1349 | output_asm_insn (\"sbc\t%0\", exops[0]); | |
30442c59 | 1350 | } |
2c9c2489 | 1351 | |
30442c59 PK |
1352 | return \"\"; |
1353 | }" | |
aad2444d PK |
1354 | [(set_attr "length" "20,28,40,48") |
1355 | (set_attr "base_cost" "0")]) | |
2c9c2489 | 1356 | |
b4324a14 PK |
1357 | (define_insn_and_split "subsi3" |
1358 | [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o") | |
30442c59 PK |
1359 | (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") |
1360 | (match_operand:SI 2 "general_operand" "r,on,r,on")))] | |
1361 | "" | |
b4324a14 PK |
1362 | "#" |
1363 | "reload_completed" | |
1364 | [(parallel [(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2))) | |
1365 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1366 | "" |
1367 | [(set_attr "length" "6,10,12,16")]) | |
b4324a14 PK |
1368 | |
1369 | (define_insn "*subsi3_nocc" | |
1370 | [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o") | |
1371 | (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") | |
1372 | (match_operand:SI 2 "general_operand" "r,on,r,on"))) | |
1373 | (clobber (reg:CC CC_REGNUM))] | |
1374 | "reload_completed" | |
30442c59 PK |
1375 | "* |
1376 | { | |
1377 | rtx inops[2]; | |
1378 | rtx exops[2][2]; | |
2c9c2489 | 1379 | |
30442c59 PK |
1380 | inops[0] = operands[0]; |
1381 | inops[1] = operands[2]; | |
442fcea7 | 1382 | pdp11_expand_operands (inops, exops, 2, 2, NULL, big); |
2c9c2489 | 1383 | |
442fcea7 | 1384 | if (!CONST_INT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0) |
4aef57c9 | 1385 | output_asm_insn (\"sub\t%1,%0\", exops[0]); |
442fcea7 | 1386 | if (!CONST_INT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0) |
30442c59 | 1387 | { |
4aef57c9 PK |
1388 | output_asm_insn (\"sub\t%1,%0\", exops[1]); |
1389 | output_asm_insn (\"sbc\t%0\", exops[0]); | |
30442c59 | 1390 | } |
2c9c2489 | 1391 | |
2c9c2489 RK |
1392 | return \"\"; |
1393 | }" | |
aad2444d PK |
1394 | [(set_attr "length" "6,10,12,16") |
1395 | (set_attr "base_cost" "0")]) | |
2c9c2489 | 1396 | |
b4324a14 | 1397 | (define_insn_and_split "subhi3" |
166208c2 | 1398 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") |
2c9c2489 | 1399 | (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0") |
b4324a14 | 1400 | (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))] |
2c9c2489 | 1401 | "" |
b4324a14 PK |
1402 | "#" |
1403 | "reload_completed" | |
1404 | [(parallel [(set (match_dup 0) | |
1405 | (minus:HI (match_dup 1) (match_dup 2))) | |
1406 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1407 | "" |
1408 | [(set_attr "length" "2,4,4,6")]) | |
b4324a14 PK |
1409 | |
1410 | ;; Note: the manual says that (minus m (const_int n)) is converted | |
1411 | ;; to (plus m (const_int -n)) but that does not appear to be | |
1412 | ;; the case when it's wrapped in a PARALLEL. So instead we handle | |
1413 | ;; that case here, which is easy enough. | |
1414 | (define_insn "*subhi3<cc_ccnz>" | |
1415 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") | |
1416 | (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0") | |
1417 | (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi"))) | |
1418 | (clobber (reg:CC CC_REGNUM))] | |
1419 | "reload_completed" | |
2c9c2489 RK |
1420 | "* |
1421 | { | |
b4324a14 PK |
1422 | if (GET_CODE (operands[2]) == CONST_INT) |
1423 | { | |
1424 | if (INTVAL(operands[2]) == 1) | |
4aef57c9 | 1425 | return \"dec\t%0\"; |
b4324a14 | 1426 | else if (INTVAL(operands[2]) == -1) |
4aef57c9 | 1427 | return \"inc\t%0\"; |
b4324a14 | 1428 | } |
2c9c2489 | 1429 | |
4aef57c9 | 1430 | return \"sub\t%2,%0\"; |
2c9c2489 | 1431 | }" |
0f237806 | 1432 | [(set_attr "length" "2,4,4,6")]) |
2c9c2489 | 1433 | |
fe65151b PK |
1434 | (define_insn_and_split "subqi3" |
1435 | [(set (match_operand:QI 0 "nonimmediate_operand" "=rR,Q") | |
1436 | (plus:QI (match_operand:QI 1 "general_operand" "%0,0") | |
1437 | (match_operand:QI 2 "incdec_operand" "LM,LM")))] | |
1438 | "" | |
1439 | "#" | |
1440 | "reload_completed" | |
1441 | [(parallel [(set (match_dup 0) | |
1442 | (plus:QI (match_dup 1) (match_dup 2))) | |
1443 | (clobber (reg:CC CC_REGNUM))])] | |
1444 | "" | |
1445 | [(set_attr "length" "2,4")]) | |
1446 | ||
1447 | ;; Inc/dec sets V if overflow from the operation | |
1448 | (define_insn "*subqi3<cc_ccnz>" | |
1449 | [(set (match_operand:QI 0 "nonimmediate_operand" "=rR,Q") | |
1450 | (plus:QI (match_operand:QI 1 "general_operand" "%0,0") | |
1451 | (match_operand:QI 2 "incdec_operand" "LM,LM"))) | |
1452 | (clobber (reg:CC CC_REGNUM))] | |
1453 | "reload_completed" | |
1454 | "* | |
1455 | { | |
1456 | if (INTVAL(operands[2]) == -1) | |
1457 | return \"incb\t%0\"; | |
1458 | else | |
1459 | return \"decb\t%0\"; | |
1460 | }" | |
1461 | [(set_attr "length" "2,4")]) | |
1462 | ||
2c9c2489 | 1463 | ;;;;- and instructions |
8aeea6e6 | 1464 | ;; Bit-and on the pdp (like on the VAX) is done with a clear-bits insn. |
2c9c2489 | 1465 | |
9546fe6a | 1466 | (define_expand "and<mode>3" |
166208c2 | 1467 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "") |
9546fe6a PK |
1468 | (and:PDPint (not:PDPint (match_operand:PDPint 1 "general_operand" "")) |
1469 | (match_operand:PDPint 2 "general_operand" "")))] | |
2c9c2489 | 1470 | "" |
9546fe6a PK |
1471 | " |
1472 | { | |
1473 | rtx op1 = operands[1]; | |
2c9c2489 | 1474 | |
9546fe6a PK |
1475 | /* If there is a constant argument, complement that one. |
1476 | Similarly, if one of the inputs is the same as the output, | |
1477 | complement the other input. */ | |
1478 | if ((CONST_INT_P (operands[2]) && ! CONST_INT_P (op1)) || | |
1479 | rtx_equal_p (operands[0], operands[1])) | |
1480 | { | |
1481 | operands[1] = operands[2]; | |
1482 | operands[2] = op1; | |
1483 | op1 = operands[1]; | |
1484 | } | |
2c9c2489 | 1485 | |
9546fe6a PK |
1486 | if (CONST_INT_P (op1)) |
1487 | operands[1] = GEN_INT (~INTVAL (op1)); | |
2c9c2489 | 1488 | else |
9546fe6a | 1489 | operands[1] = expand_unop (<MODE>mode, one_cmpl_optab, op1, 0, 1); |
aad2444d PK |
1490 | }" |
1491 | [(set_attr "length" "2,4,4,6")]) | |
2c9c2489 | 1492 | |
b4324a14 | 1493 | (define_insn_and_split "*bic<mode>" |
166208c2 | 1494 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") |
9546fe6a PK |
1495 | (and:PDPint |
1496 | (not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi")) | |
1497 | (match_operand:PDPint 2 "general_operand" "0,0,0,0")))] | |
2c9c2489 | 1498 | "" |
b4324a14 PK |
1499 | "#" |
1500 | "reload_completed" | |
1501 | [(parallel [(set (match_dup 0) | |
1502 | (and:PDPint (not:PDPint (match_dup 1)) (match_dup 2))) | |
1503 | (clobber (reg:CC CC_REGNUM))])] | |
1504 | "") | |
1505 | ||
1506 | (define_insn "*bic<mode><cc_cc>" | |
1507 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") | |
1508 | (and:PDPint | |
1509 | (not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi")) | |
1510 | (match_operand:PDPint 2 "general_operand" "0,0,0,0"))) | |
1511 | (clobber (reg:CC CC_REGNUM))] | |
1512 | "reload_completed" | |
4aef57c9 | 1513 | "bic<PDPint:isfx>\t%1,%0" |
0f237806 | 1514 | [(set_attr "length" "2,4,4,6")]) |
2c9c2489 RK |
1515 | |
1516 | ;;- Bit set (inclusive or) instructions | |
b4324a14 | 1517 | (define_insn_and_split "ior<mode>3" |
63caf8bb PK |
1518 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") |
1519 | (ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0") | |
b4324a14 | 1520 | (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))] |
2c9c2489 | 1521 | "" |
b4324a14 PK |
1522 | "#" |
1523 | "reload_completed" | |
1524 | [(parallel [(set (match_dup 0) | |
1525 | (ior:PDPint (match_dup 1) (match_dup 2))) | |
1526 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1527 | "" |
1528 | [(set_attr "length" "2,4,4,6")]) | |
b4324a14 PK |
1529 | |
1530 | (define_insn "ior<mode>3<cc_cc>" | |
1531 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") | |
1532 | (ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0") | |
1533 | (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi"))) | |
1534 | (clobber (reg:CC CC_REGNUM))] | |
1535 | "reload_completed" | |
4aef57c9 | 1536 | "bis<PDPint:isfx>\t%2,%0" |
0f237806 | 1537 | [(set_attr "length" "2,4,4,6")]) |
2c9c2489 | 1538 | |
2c9c2489 | 1539 | ;;- xor instructions |
b4324a14 | 1540 | (define_insn_and_split "xorhi3" |
166208c2 | 1541 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") |
2c9c2489 RK |
1542 | (xor:HI (match_operand:HI 1 "general_operand" "%0,0") |
1543 | (match_operand:HI 2 "register_operand" "r,r")))] | |
1544 | "TARGET_40_PLUS" | |
b4324a14 PK |
1545 | "#" |
1546 | "&& reload_completed" | |
1547 | [(parallel [(set (match_dup 0) | |
1548 | (xor:HI (match_dup 1) (match_dup 2))) | |
1549 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1550 | "" |
1551 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1552 | |
1553 | (define_insn "*xorhi3<cc_cc>" | |
1554 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") | |
1555 | (xor:HI (match_operand:HI 1 "general_operand" "%0,0") | |
1556 | (match_operand:HI 2 "register_operand" "r,r"))) | |
1557 | (clobber (reg:CC CC_REGNUM))] | |
1558 | "TARGET_40_PLUS && reload_completed" | |
4aef57c9 | 1559 | "xor\t%2,%0" |
0f237806 | 1560 | [(set_attr "length" "2,4")]) |
2c9c2489 RK |
1561 | |
1562 | ;;- one complement instructions | |
1563 | ||
b4324a14 | 1564 | (define_insn_and_split "one_cmpl<mode>2" |
63caf8bb PK |
1565 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") |
1566 | (not:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))] | |
2c9c2489 | 1567 | "" |
b4324a14 PK |
1568 | "#" |
1569 | "reload_completed" | |
1570 | [(parallel [(set (match_dup 0) | |
1571 | (not:PDPint (match_dup 1))) | |
1572 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1573 | "" |
1574 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1575 | |
1576 | (define_insn "*one_cmpl<mode>2<cc_cc>" | |
1577 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") | |
1578 | (not:PDPint (match_operand:PDPint 1 "general_operand" "0,0"))) | |
1579 | (clobber (reg:CC CC_REGNUM))] | |
1580 | "reload_completed" | |
4aef57c9 | 1581 | "com<PDPint:isfx>\t%0" |
0f237806 | 1582 | [(set_attr "length" "2,4")]) |
2c9c2489 RK |
1583 | |
1584 | ;;- arithmetic shift instructions | |
b4324a14 PK |
1585 | ;; |
1586 | ;; There is a fair amount of complexity here because with -m10 | |
1587 | ;; (pdp-11/10, /20) we only have shift by one bit. Iterators are | |
1588 | ;; used to reduce the amount of very similar code. | |
1589 | ;; | |
1590 | ;; First the insns used for small constant shifts. | |
aad2444d | 1591 | (define_insn_and_split "<code><mode>_sc" |
b4324a14 PK |
1592 | [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q") |
1593 | (SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0") | |
1594 | (match_operand:HI 2 "expand_shift_operand" "O,O")))] | |
2c9c2489 | 1595 | "" |
aad2444d PK |
1596 | "#" |
1597 | "reload_completed" | |
1598 | [(parallel [(set (match_dup 0) (SHF:QHSint (match_dup 1) (match_dup 2))) | |
1599 | (clobber (reg:CC CC_REGNUM))])] | |
1600 | "" | |
9cd1665b PK |
1601 | [(set (attr "length") |
1602 | (symbol_ref "pdp11_shift_length (operands, <QHSint:mname>, | |
aad2444d PK |
1603 | <CODE>, which_alternative == 0)")) |
1604 | (set_attr "base_cost" "0")]) | |
1605 | ||
1606 | (define_insn "<code><mode>_sc<cc_ccnz>" | |
1607 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rD,Q") | |
1608 | (SHF:PDPint (match_operand:PDPint 1 "general_operand" "0,0") | |
1609 | (match_operand:HI 2 "expand_shift_operand" "O,O"))) | |
1610 | (clobber (reg:CC CC_REGNUM))] | |
1611 | "reload_completed" | |
1612 | "* return pdp11_assemble_shift (operands, <PDPint:mname>, <CODE>);" | |
1613 | [(set (attr "length") | |
1614 | (symbol_ref "pdp11_shift_length (operands, <PDPint:mname>, | |
1615 | <CODE>, which_alternative == 0)")) | |
1616 | (set_attr "base_cost" "0")]) | |
1617 | ||
1618 | ;; This one comes only in clobber flavor. | |
1619 | (define_insn "<code>si_sc_nocc" | |
1620 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rD,Q") | |
1621 | (SHF:SI (match_operand:SI 1 "general_operand" "0,0") | |
1622 | (match_operand:HI 2 "expand_shift_operand" "O,O"))) | |
1623 | (clobber (reg:CC CC_REGNUM))] | |
1624 | "reload_completed" | |
1625 | "* return pdp11_assemble_shift (operands, SImode, <CODE>);" | |
1626 | [(set (attr "length") | |
1627 | (symbol_ref "pdp11_shift_length (operands, SImode, | |
1628 | <CODE>, which_alternative == 0)")) | |
1629 | (set_attr "base_cost" "0")]) | |
2c9c2489 | 1630 | |
b4324a14 PK |
1631 | ;; Next, shifts that are done as a loop on base (11/10 class) machines. |
1632 | ;; This applies to shift counts too large to unroll, or variable shift | |
1633 | ;; counts. The check for count <= 0 is done before we get here. | |
aad2444d | 1634 | (define_insn_and_split "<code><mode>_base" |
b4324a14 PK |
1635 | [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q") |
1636 | (SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0") | |
1637 | (match_operand:HI 2 "register_operand" "r,r"))) | |
1638 | (clobber (match_dup 2))] | |
2c9c2489 | 1639 | "" |
aad2444d PK |
1640 | "#" |
1641 | "reload_completed" | |
1642 | [(parallel [(set (match_dup 0) (SHF:QHSint (match_dup 1) (match_dup 2))) | |
1643 | (clobber (match_dup 2)) | |
1644 | (clobber (reg:CC CC_REGNUM))])] | |
1645 | "" | |
1646 | [(set (attr "length") | |
1647 | (symbol_ref "pdp11_shift_length (operands, <QHSint:mname>, | |
1648 | <CODE>, which_alternative == 0)")) | |
1649 | (set_attr "base_cost" "0")]) | |
1650 | ||
1651 | (define_insn "<code><mode>_base_nocc" | |
1652 | [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q") | |
1653 | (SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0") | |
1654 | (match_operand:HI 2 "register_operand" "r,r"))) | |
1655 | (clobber (match_dup 2)) | |
1656 | (clobber (reg:CC CC_REGNUM))] | |
1657 | "reload_completed" | |
b4324a14 | 1658 | "* return pdp11_assemble_shift (operands, <QHSint:mname>, <CODE>);" |
9cd1665b PK |
1659 | [(set (attr "length") |
1660 | (symbol_ref "pdp11_shift_length (operands, <QHSint:mname>, | |
aad2444d PK |
1661 | <CODE>, which_alternative == 0)")) |
1662 | (set_attr "base_cost" "0")]) | |
2c9c2489 | 1663 | |
b4324a14 PK |
1664 | ;; Next the insns that use the extended instructions ash and ashc. |
1665 | ;; Note that these are just left shifts, and HI/SI only. (Right shifts | |
1666 | ;; are done by shifting by a negative amount.) | |
aad2444d | 1667 | (define_insn_and_split "aslhi_op" |
b4324a14 | 1668 | [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r") |
2c9c2489 | 1669 | (ashift:HI (match_operand:HI 1 "general_operand" "0,0") |
aad2444d | 1670 | (match_operand:HI 2 "general_operand" "rR,Qi")))] |
b4324a14 | 1671 | "TARGET_40_PLUS" |
aad2444d PK |
1672 | "#" |
1673 | "&& reload_completed" | |
1674 | [(parallel [(set (match_dup 0) | |
1675 | (ashift:HI (match_dup 1) (match_dup 2))) | |
1676 | (clobber (reg:CC CC_REGNUM))])] | |
1677 | "" | |
1678 | [(set_attr "length" "2,4") | |
1679 | (set_attr "base_cost" "8")]) | |
1680 | ||
1681 | (define_insn "aslhi_op<cc_ccnz>" | |
1682 | [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r") | |
1683 | (ashift:HI (match_operand:HI 1 "general_operand" "0,0") | |
1684 | (match_operand:HI 2 "general_operand" "rR,Qi"))) | |
1685 | (clobber (reg:CC CC_REGNUM))] | |
1686 | "TARGET_40_PLUS && reload_completed" | |
4aef57c9 | 1687 | "ash\t%2,%0" |
aad2444d PK |
1688 | [(set_attr "length" "2,4") |
1689 | (set_attr "base_cost" "8")]) | |
2c9c2489 | 1690 | |
aad2444d | 1691 | (define_insn_and_split "aslsi_op" |
b4324a14 PK |
1692 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r") |
1693 | (ashift:SI (match_operand:SI 1 "general_operand" "0,0") | |
aad2444d | 1694 | (match_operand:HI 2 "general_operand" "rR,Qi")))] |
b4324a14 | 1695 | "TARGET_40_PLUS" |
aad2444d PK |
1696 | "#" |
1697 | "&& reload_completed" | |
1698 | [(parallel [(set (match_dup 0) | |
1699 | (ashift:SI (match_dup 1) (match_dup 2))) | |
1700 | (clobber (reg:CC CC_REGNUM))])] | |
1701 | "" | |
1702 | [(set_attr "length" "2,4") | |
1703 | (set_attr "base_cost" "8")]) | |
1704 | ||
1705 | (define_insn "aslsi_op_<cc_ccnz>" | |
1706 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r") | |
1707 | (ashift:SI (match_operand:SI 1 "general_operand" "0,0") | |
1708 | (match_operand:HI 2 "general_operand" "rR,Qi"))) | |
1709 | (clobber (reg:CC CC_REGNUM))] | |
1710 | "TARGET_40_PLUS && reload_completed" | |
4aef57c9 | 1711 | "ashc\t%2,%0" |
aad2444d PK |
1712 | [(set_attr "length" "2,4") |
1713 | (set_attr "base_cost" "8")]) | |
e7f9979a | 1714 | |
b4324a14 PK |
1715 | ;; Now the expanders that produce the insns defined above. |
1716 | (define_expand "ashl<mode>3" | |
1717 | [(match_operand:QHSint 0 "nonimmediate_operand" "") | |
1718 | (match_operand:QHSint 1 "general_operand" "") | |
d5214afa PK |
1719 | (match_operand:HI 2 "general_operand" "")] |
1720 | "" | |
1721 | " | |
1722 | { | |
1723 | rtx r; | |
1724 | ||
b4324a14 | 1725 | if (!pdp11_expand_shift (operands, gen_ashift<mode>_sc, gen_ashift<mode>_base)) |
d5214afa | 1726 | { |
b4324a14 PK |
1727 | if (<QHSint:e_mname> == E_QImode) |
1728 | { | |
1729 | r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1])); | |
1730 | emit_insn (gen_aslhi_op (r, r, operands[2])); | |
1731 | emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0))); | |
1732 | } | |
1733 | else | |
1734 | { | |
1735 | emit_insn (gen_asl<QHSint:hmode>_op (operands[0], operands[1], operands[2])); | |
1736 | } | |
d5214afa PK |
1737 | } |
1738 | DONE; | |
b4324a14 | 1739 | }") |
2c9c2489 | 1740 | |
b4324a14 PK |
1741 | (define_expand "ashr<mode>3" |
1742 | [(match_operand:QHSint 0 "nonimmediate_operand" "") | |
1743 | (match_operand:QHSint 1 "general_operand" "") | |
1744 | (match_operand:HI 2 "general_operand" "")] | |
2c9c2489 | 1745 | "" |
b4324a14 | 1746 | " |
2c9c2489 | 1747 | { |
b4324a14 PK |
1748 | rtx r; |
1749 | ||
1750 | if (!pdp11_expand_shift (operands, gen_ashiftrt<mode>_sc, gen_ashiftrt<mode>_base)) | |
09b893bb | 1751 | { |
b4324a14 PK |
1752 | operands[2] = negate_rtx (HImode, operands[2]); |
1753 | if (<QHSint:e_mname> == E_QImode) | |
1754 | { | |
1755 | r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1])); | |
1756 | emit_insn (gen_aslhi_op (r, r, operands[2])); | |
1757 | emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0))); | |
1758 | } | |
1759 | else | |
1760 | { | |
1761 | emit_insn (gen_asl<QHSint:hmode>_op (operands[0], operands[1], operands[2])); | |
1762 | } | |
09b893bb | 1763 | } |
b4324a14 | 1764 | DONE; |
2c9c2489 RK |
1765 | }") |
1766 | ||
b4324a14 PK |
1767 | (define_expand "lshr<mode>3" |
1768 | [(match_operand:QHSint 0 "nonimmediate_operand" "") | |
1769 | (match_operand:QHSint 1 "general_operand" "") | |
d5214afa PK |
1770 | (match_operand:HI 2 "general_operand" "")] |
1771 | "" | |
1772 | " | |
1773 | { | |
b4324a14 | 1774 | rtx r, n; |
d5214afa | 1775 | |
b4324a14 | 1776 | if (!pdp11_expand_shift (operands, gen_lshiftrt<mode>_sc, gen_lshiftrt<mode>_base)) |
d5214afa | 1777 | { |
b4324a14 PK |
1778 | if (<QHSint:e_mname> == E_QImode) |
1779 | { | |
1780 | r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1])); | |
1781 | emit_insn (gen_aslhi_op (r, r, operands[2])); | |
1782 | emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0))); | |
1783 | } | |
1784 | else | |
1785 | { | |
1786 | r = gen_reg_rtx (<QHSint:mname>); | |
1787 | emit_insn (gen_lshiftrt<mode>_sc (r, operands[1], const1_rtx)); | |
1788 | if (GET_CODE (operands[2]) != CONST_INT) | |
1789 | { | |
1790 | n = gen_reg_rtx (HImode); | |
1791 | emit_insn (gen_addhi3 (n, operands [2], GEN_INT (-1))); | |
1792 | emit_insn (gen_ashr<mode>3 (operands[0], r, n)); | |
1793 | } | |
1794 | else | |
1795 | emit_insn (gen_asl<QHSint:hmode>_op (operands[0], r, | |
1796 | GEN_INT (1 - INTVAL (operands[2])))); | |
1797 | } | |
d5214afa PK |
1798 | } |
1799 | DONE; | |
b4324a14 | 1800 | }") |
2c9c2489 RK |
1801 | |
1802 | ;; absolute | |
1803 | ||
b4324a14 | 1804 | (define_insn_and_split "absdf2" |
166208c2 | 1805 | [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") |
2c9c2489 RK |
1806 | (abs:DF (match_operand:DF 1 "general_operand" "0,0")))] |
1807 | "TARGET_FPU" | |
b4324a14 PK |
1808 | "#" |
1809 | "&& reload_completed" | |
1810 | [(parallel [(set (match_dup 0) (abs:DF (match_dup 1))) | |
1811 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
1812 | "" |
1813 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1814 | |
1815 | (define_insn "absdf2<fcc_cc>" | |
1816 | [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") | |
1817 | (abs:DF (match_operand:DF 1 "general_operand" "0,0"))) | |
1818 | (clobber (reg:CC FCC_REGNUM))] | |
1819 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 1820 | "{absd|absf}\t%0" |
0f237806 | 1821 | [(set_attr "length" "2,4")]) |
2c9c2489 | 1822 | |
2c9c2489 RK |
1823 | ;; negate insns |
1824 | ||
b4324a14 PK |
1825 | (define_insn_and_split "negdf2" |
1826 | [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") | |
1827 | (neg:DF (match_operand:DF 1 "general_operand" "0,0")))] | |
2c9c2489 | 1828 | "TARGET_FPU" |
b4324a14 PK |
1829 | "#" |
1830 | "&& reload_completed" | |
1831 | [(parallel [(set (match_dup 0) (neg:DF (match_dup 1))) | |
1832 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
1833 | "" |
1834 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1835 | |
1836 | (define_insn "negdf2<fcc_cc>" | |
1837 | [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") | |
1838 | (neg:DF (match_operand:DF 1 "general_operand" "0,0"))) | |
1839 | (clobber (reg:CC FCC_REGNUM))] | |
1840 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 1841 | "{negd|negf}\t%0" |
0f237806 | 1842 | [(set_attr "length" "2,4")]) |
2c9c2489 | 1843 | |
b4324a14 | 1844 | (define_insn_and_split "negdi2" |
30442c59 PK |
1845 | [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") |
1846 | (neg:DI (match_operand:DI 1 "general_operand" "0,0")))] | |
e7f9979a | 1847 | "" |
b4324a14 PK |
1848 | "#" |
1849 | "reload_completed" | |
1850 | [(parallel [(set (match_dup 0) (neg:DI (match_dup 1))) | |
1851 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1852 | "" |
1853 | [(set_attr "length" "18,34")]) | |
b4324a14 PK |
1854 | |
1855 | ;; TODO: this can be neg/adc/neg/adc... I believe. Check. Saves one word. | |
1856 | (define_insn "negdi2_nocc" | |
1857 | [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") | |
1858 | (neg:DI (match_operand:DI 1 "general_operand" "0,0"))) | |
1859 | (clobber (reg:CC CC_REGNUM))] | |
1860 | "reload_completed" | |
aad2444d | 1861 | { |
442fcea7 | 1862 | rtx inops[2]; |
aad2444d | 1863 | rtx exops[4][2]; |
442fcea7 PK |
1864 | |
1865 | inops[0] = operands[0]; | |
1866 | pdp11_expand_operands (inops, exops, 1, 4, NULL, big); | |
30442c59 | 1867 | |
aad2444d PK |
1868 | output_asm_insn (\"com\t%0\", exops[3]); |
1869 | output_asm_insn (\"com\t%0\", exops[2]); | |
1870 | output_asm_insn (\"com\t%0\", exops[1]); | |
1871 | output_asm_insn (\"com\t%0\", exops[0]); | |
1872 | output_asm_insn (\"add\t%#1,%0\", exops[3]); | |
1873 | output_asm_insn (\"adc\t%0\", exops[2]); | |
1874 | output_asm_insn (\"adc\t%0\", exops[1]); | |
1875 | output_asm_insn (\"adc\t%0\", exops[0]); | |
1876 | ||
1877 | return \"\"; | |
1878 | } | |
1879 | [(set_attr "length" "18,34") | |
1880 | (set_attr "base_cost" "0")]) | |
e7f9979a | 1881 | |
b4324a14 | 1882 | (define_insn_and_split "negsi2" |
30442c59 PK |
1883 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,o") |
1884 | (neg:SI (match_operand:SI 1 "general_operand" "0,0")))] | |
1885 | "" | |
b4324a14 PK |
1886 | "#" |
1887 | "reload_completed" | |
1888 | [(parallel [(set (match_dup 0) (neg:SI (match_dup 1))) | |
1889 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1890 | "" |
1891 | [(set_attr "length" "10,18")]) | |
b4324a14 PK |
1892 | |
1893 | ;; TODO: this can be neg/adc/neg/adc... I believe. Check. Saves one word. | |
1894 | (define_insn "negsi2_nocc" | |
1895 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,o") | |
1896 | (neg:SI (match_operand:SI 1 "general_operand" "0,0"))) | |
1897 | (clobber (reg:CC CC_REGNUM))] | |
1898 | "reload_completed" | |
aad2444d | 1899 | { |
442fcea7 PK |
1900 | rtx inops[2]; |
1901 | rtx exops[4][2]; | |
1902 | ||
1903 | inops[0] = operands[0]; | |
1904 | pdp11_expand_operands (inops, exops, 1, 2, NULL, big); | |
30442c59 | 1905 | |
aad2444d PK |
1906 | output_asm_insn (\"com\t%0\", exops[1]); |
1907 | output_asm_insn (\"com\t%0\", exops[0]); | |
1908 | output_asm_insn (\"add\t%#1,%0\", exops[1]); | |
1909 | output_asm_insn (\"adc\t%0\", exops[0]); | |
1910 | ||
1911 | return \"\"; | |
1912 | } | |
1913 | [(set_attr "length" "10,18") | |
1914 | (set_attr "base_cost" "0")]) | |
e7f9979a | 1915 | |
b4324a14 | 1916 | (define_insn_and_split "neg<mode>2" |
30442c59 PK |
1917 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") |
1918 | (neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))] | |
2c9c2489 | 1919 | "" |
b4324a14 PK |
1920 | "#" |
1921 | "reload_completed" | |
1922 | [(parallel [(set (match_dup 0) (neg:PDPint (match_dup 1))) | |
1923 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
1924 | "" |
1925 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
1926 | |
1927 | (define_insn "neg<mode>2<cc_ccnz>" | |
1928 | [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") | |
1929 | (neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0"))) | |
1930 | (clobber (reg:CC CC_REGNUM))] | |
1931 | "" | |
4aef57c9 | 1932 | "neg<PDPint:isfx>\t%0" |
0f237806 | 1933 | [(set_attr "length" "2,4")]) |
2c9c2489 RK |
1934 | |
1935 | ||
1936 | ;; Unconditional and other jump instructions | |
1937 | (define_insn "jump" | |
1938 | [(set (pc) | |
1939 | (label_ref (match_operand 0 "" "")))] | |
1940 | "" | |
0f237806 PK |
1941 | "* |
1942 | { | |
b4324a14 | 1943 | if (get_attr_length (insn) == 2) |
4aef57c9 PK |
1944 | return \"br\t%l0\"; |
1945 | return \"jmp\t%l0\"; | |
0f237806 | 1946 | }" |
7021d5df | 1947 | [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 0) |
0f237806 | 1948 | (pc)) |
7021d5df PK |
1949 | (const_int MIN_BRANCH)) |
1950 | (gt (minus (match_dup 0) | |
0f237806 | 1951 | (pc)) |
7021d5df | 1952 | (const_int MAX_BRANCH))) |
0f237806 PK |
1953 | (const_int 4) |
1954 | (const_int 2)))]) | |
2c9c2489 | 1955 | |
2c9c2489 | 1956 | (define_insn "tablejump" |
12eb6ed3 | 1957 | [(set (pc) (match_operand:HI 0 "general_operand" "r,R,Q")) |
2c9c2489 RK |
1958 | (use (label_ref (match_operand 1 "" "")))] |
1959 | "" | |
12eb6ed3 | 1960 | "@ |
4aef57c9 PK |
1961 | jmp\t(%0) |
1962 | jmp\t%@%0 | |
1963 | jmp\t%@%0" | |
12eb6ed3 | 1964 | [(set_attr "length" "2,2,4")]) |
2c9c2489 | 1965 | |
b4324a14 PK |
1966 | ;; indirect jump. TODO: this needs a constraint that allows memory |
1967 | ;; references but not indirection, since we add a level of indirection | |
1968 | ;; in the generated code. | |
2c9c2489 | 1969 | (define_insn "indirect_jump" |
b4324a14 | 1970 | [(set (pc) (match_operand:HI 0 "general_operand" "r"))] |
2c9c2489 | 1971 | "" |
aad2444d | 1972 | "jmp\t@%0" |
b4324a14 | 1973 | [(set_attr "length" "2")]) |
2c9c2489 RK |
1974 | |
1975 | ;;- jump to subroutine | |
1976 | ||
1977 | (define_insn "call" | |
e7f9979a | 1978 | [(call (match_operand:HI 0 "general_operand" "rR,Q") |
b4324a14 | 1979 | (match_operand:HI 1 "general_operand" "g,g"))] |
2c9c2489 RK |
1980 | ;;- Don't use operand 1 for most machines. |
1981 | "" | |
aad2444d | 1982 | "jsr\tpc,%0" |
0f237806 | 1983 | [(set_attr "length" "2,4")]) |
2c9c2489 RK |
1984 | |
1985 | ;;- jump to subroutine | |
1986 | (define_insn "call_value" | |
1987 | [(set (match_operand 0 "" "") | |
e7f9979a | 1988 | (call (match_operand:HI 1 "general_operand" "rR,Q") |
b4324a14 | 1989 | (match_operand:HI 2 "general_operand" "g,g")))] |
2c9c2489 RK |
1990 | ;;- Don't use operand 2 for most machines. |
1991 | "" | |
aad2444d | 1992 | "jsr\tpc,%1" |
0f237806 | 1993 | [(set_attr "length" "2,4")]) |
2c9c2489 | 1994 | |
b4324a14 PK |
1995 | (define_expand "untyped_call" |
1996 | [(parallel [(call (match_operand 0 "" "") | |
1997 | (const_int 0)) | |
1998 | (match_operand 1 "" "") | |
1999 | (match_operand 2 "" "")])] | |
2000 | "" | |
2001 | { | |
2002 | int i; | |
2003 | ||
2004 | emit_call_insn (gen_call (operands[0], const0_rtx)); | |
2005 | ||
2006 | for (i = 0; i < XVECLEN (operands[2], 0); i++) | |
2007 | { | |
2008 | rtx set = XVECEXP (operands[2], 0, i); | |
2009 | emit_move_insn (SET_DEST (set), SET_SRC (set)); | |
2010 | } | |
2011 | ||
2012 | /* The optimizer does not know that the call sets the function value | |
2013 | registers we stored in the result block. We avoid problems by | |
2014 | claiming that all hard registers are used and clobbered at this | |
2015 | point. */ | |
2016 | emit_insn (gen_blockage ()); | |
2017 | ||
2018 | DONE; | |
2019 | }) | |
2020 | ||
2c9c2489 RK |
2021 | ;;- nop instruction |
2022 | (define_insn "nop" | |
2023 | [(const_int 0)] | |
2024 | "" | |
2025 | "nop") | |
2026 | \f | |
2027 | ||
2028 | ;;- multiply | |
2029 | ||
b4324a14 | 2030 | (define_insn_and_split "muldf3" |
c67b2d4e PK |
2031 | [(set (match_operand:DF 0 "register_operand" "=a,a") |
2032 | (mult:DF (match_operand:DF 1 "register_operand" "%0,0") | |
2033 | (match_operand:DF 2 "float_operand" "fR,QF")))] | |
2c9c2489 | 2034 | "TARGET_FPU" |
b4324a14 PK |
2035 | "#" |
2036 | "&& reload_completed" | |
2037 | [(parallel [(set (match_dup 0) (mult:DF (match_dup 1) (match_dup 2))) | |
2038 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
2039 | "" |
2040 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
2041 | |
2042 | (define_insn "muldf3<fcc_ccnz>" | |
2043 | [(set (match_operand:DF 0 "register_operand" "=a,a") | |
2044 | (mult:DF (match_operand:DF 1 "register_operand" "%0,0") | |
2045 | (match_operand:DF 2 "float_operand" "fR,QF"))) | |
2046 | (clobber (reg:CC FCC_REGNUM))] | |
2047 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 2048 | "{muld|mulf}\t%2,%0" |
aad2444d PK |
2049 | [(set_attr "length" "2,4") |
2050 | (set_attr "base_cost" "20")]) | |
2c9c2489 | 2051 | |
b4324a14 | 2052 | ;; 16 bit result multiply. This uses odd numbered registers. |
2c9c2489 | 2053 | |
b4324a14 | 2054 | (define_insn_and_split "mulhi3" |
2c9c2489 RK |
2055 | [(set (match_operand:HI 0 "register_operand" "=d,d") ; multiply regs |
2056 | (mult:HI (match_operand:HI 1 "register_operand" "%0,0") | |
b4324a14 | 2057 | (match_operand:HI 2 "general_operand" "rR,Qi")))] |
b56f8e7c | 2058 | "TARGET_40_PLUS" |
b4324a14 PK |
2059 | "#" |
2060 | "&& reload_completed" | |
2061 | [(parallel [(set (match_dup 0) (mult:HI (match_dup 1) (match_dup 2))) | |
2062 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
2063 | "" |
2064 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
2065 | |
2066 | (define_insn "mulhi3<cc_cc>" | |
2067 | [(set (match_operand:HI 0 "register_operand" "=d,d") | |
2068 | (mult:HI (match_operand:HI 1 "register_operand" "%0,0") | |
2069 | (match_operand:HI 2 "general_operand" "rR,Qi"))) | |
2070 | (clobber (reg:CC CC_REGNUM))] | |
2071 | "TARGET_40_PLUS && reload_completed" | |
4aef57c9 | 2072 | "mul\t%2,%0" |
aad2444d PK |
2073 | [(set_attr "length" "2,4") |
2074 | (set_attr "base_cost" "20")]) | |
2c9c2489 | 2075 | |
b4324a14 PK |
2076 | ;; 32 bit result from 16 bit operands |
2077 | (define_insn_and_split "mulhisi3" | |
2078 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
2079 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,0")) | |
2080 | (sign_extend:SI (match_operand:HI 2 "general_operand" "rR,Qi"))))] | |
b56f8e7c | 2081 | "TARGET_40_PLUS" |
b4324a14 PK |
2082 | "#" |
2083 | "&& reload_completed" | |
2084 | [(parallel [(set (match_dup 0) | |
2085 | (mult:SI (sign_extend:SI (match_dup 1)) | |
2086 | (sign_extend:SI (match_dup 2)))) | |
2087 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
2088 | "" |
2089 | [(set_attr "length" "2,4")]) | |
781e6f76 | 2090 | |
b4324a14 PK |
2091 | (define_insn "mulhisi3<cc_cc>" |
2092 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
2093 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,0")) | |
2094 | (sign_extend:SI (match_operand:HI 2 "general_operand" "rR,Qi")))) | |
2095 | (clobber (reg:CC CC_REGNUM))] | |
2096 | "TARGET_40_PLUS && reload_completed" | |
4aef57c9 | 2097 | "mul\t%2,%0" |
aad2444d PK |
2098 | [(set_attr "length" "2,4") |
2099 | (set_attr "base_cost" "20")]) | |
2c9c2489 RK |
2100 | |
2101 | ;;- divide | |
b4324a14 | 2102 | (define_insn_and_split "divdf3" |
c67b2d4e PK |
2103 | [(set (match_operand:DF 0 "register_operand" "=a,a") |
2104 | (div:DF (match_operand:DF 1 "register_operand" "0,0") | |
2105 | (match_operand:DF 2 "general_operand" "fR,QF")))] | |
2c9c2489 | 2106 | "TARGET_FPU" |
b4324a14 PK |
2107 | "#" |
2108 | "&& reload_completed" | |
2109 | [(parallel [(set (match_dup 0) (div:DF (match_dup 1) (match_dup 2))) | |
2110 | (clobber (reg:CC FCC_REGNUM))])] | |
aad2444d PK |
2111 | "" |
2112 | [(set_attr "length" "2,4")]) | |
b4324a14 PK |
2113 | |
2114 | (define_insn "divdf3<fcc_ccnz>" | |
2115 | [(set (match_operand:DF 0 "register_operand" "=a,a") | |
2116 | (div:DF (match_operand:DF 1 "register_operand" "0,0") | |
2117 | (match_operand:DF 2 "general_operand" "fR,QF"))) | |
2118 | (clobber (reg:CC FCC_REGNUM))] | |
2119 | "TARGET_FPU && reload_completed" | |
4aef57c9 | 2120 | "{divd|divf}\t%2,%0" |
aad2444d PK |
2121 | [(set_attr "length" "2,4") |
2122 | (set_attr "base_cost" "20")]) | |
2c9c2489 | 2123 | |
b4324a14 PK |
2124 | (define_expand "divmodhi4" |
2125 | [(parallel | |
2126 | [(set (subreg:HI (match_dup 1) 0) | |
8f808fc2 | 2127 | (div:HI (match_operand:SI 1 "register_operand" "0") |
0c253776 | 2128 | (match_operand:HI 2 "general_operand" "g"))) |
b4324a14 PK |
2129 | (set (subreg:HI (match_dup 1) 2) |
2130 | (mod:HI (match_dup 1) (match_dup 2)))]) | |
8f808fc2 | 2131 | (set (match_operand:HI 0 "register_operand" "=r") |
b4324a14 PK |
2132 | (subreg:HI (match_dup 1) 0)) |
2133 | (set (match_operand:HI 3 "register_operand" "=r") | |
2134 | (subreg:HI (match_dup 1) 2))] | |
b56f8e7c | 2135 | "TARGET_40_PLUS" |
0c253776 | 2136 | "") |
2c9c2489 | 2137 | |
b4324a14 PK |
2138 | (define_insn_and_split "*divmodhi4" |
2139 | [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r,r") 0) | |
2140 | (div:HI (match_operand:SI 1 "register_operand" "0,0") | |
2141 | (match_operand:HI 2 "general_operand" "rR,Qi"))) | |
2142 | (set (subreg:HI (match_dup 1) 2) | |
2143 | (mod:HI (match_dup 1) (match_dup 2)))] | |
b56f8e7c | 2144 | "TARGET_40_PLUS" |
b4324a14 PK |
2145 | "#" |
2146 | "&& reload_completed" | |
2147 | [(parallel [(set (subreg:HI (match_dup 0) 0) | |
2148 | (div:HI (match_dup 1) (match_dup 2))) | |
2149 | (set (subreg:HI (match_dup 1) 2) | |
2150 | (mod:HI (match_dup 1) (match_dup 2))) | |
2151 | (clobber (reg:CC CC_REGNUM))])] | |
aad2444d PK |
2152 | "" |
2153 | [(set_attr "length" "2,4")]) | |
2c9c2489 | 2154 | |
b4324a14 PK |
2155 | ;; Note that there is no corresponding CC setter pattern. |
2156 | ;; The reason is that it won't be generated, because | |
e53b6e56 | 2157 | ;; compare-elim.cc only does the transformation on input |
b4324a14 PK |
2158 | ;; insns that have a two-element PARALLEL, as opposed to |
2159 | ;; the three-element one we have here. | |
2160 | (define_insn "divmodhi4_nocc" | |
2161 | [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r,r") 0) | |
2162 | (div:HI (match_operand:SI 1 "register_operand" "0,0") | |
2163 | (match_operand:HI 2 "general_operand" "rR,Qi"))) | |
2164 | (set (subreg:HI (match_dup 1) 2) | |
2165 | (mod:HI (match_dup 1) (match_dup 2))) | |
2166 | (clobber (reg:CC CC_REGNUM))] | |
b56f8e7c | 2167 | "TARGET_40_PLUS" |
4aef57c9 | 2168 | "div\t%2,%0" |
aad2444d PK |
2169 | [(set_attr "length" "2,4") |
2170 | (set_attr "base_cost" "40")]) | |
2171 | ||
2172 | ;; Byte swap | |
2173 | (define_insn_and_split "bswaphi2" | |
2174 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") | |
2175 | (bswap:HI (match_operand:HI 1 "general_operand" "0,0")))] | |
2176 | "" | |
2177 | "#" | |
2178 | "reload_completed" | |
2179 | [(parallel [(set (match_dup 0) (bswap:HI (match_dup 1))) | |
2180 | (clobber (reg:CC CC_REGNUM))])] | |
2181 | "" | |
b4324a14 | 2182 | [(set_attr "length" "2,4")]) |
aad2444d PK |
2183 | |
2184 | (define_insn "bswaphi2<cc_ccnz>" | |
2185 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") | |
2186 | (bswap:HI (match_operand:HI 1 "general_operand" "0,0"))) | |
2187 | (clobber (reg:CC CC_REGNUM))] | |
2188 | "" | |
2189 | "swab\t%0" | |
2190 | [(set_attr "length" "2,4")]) | |
2191 | ||
2192 | (define_insn_and_split "bswapsi2" | |
2193 | [(set (match_operand:SI 0 "register_operand" "=&r") | |
2194 | (bswap:SI (match_operand:SI 1 "general_operand" "g")))] | |
2195 | "" | |
2196 | "#" | |
2197 | "reload_completed" | |
2198 | [(parallel [(set (match_dup 0) | |
2199 | (bswap:SI (match_dup 1))) | |
2200 | (clobber (reg:CC CC_REGNUM))])] | |
2201 | "" | |
2202 | [(set_attr "length" "10")]) | |
2203 | ||
2204 | (define_insn "bswapsi2_nocc" | |
2205 | [(set (match_operand:SI 0 "register_operand" "=&r,&r,&r") | |
2206 | (bswap:SI (match_operand:SI 1 "general_operand" "r,D,Q"))) | |
2207 | (clobber (reg:CC CC_REGNUM))] | |
2208 | "" | |
2209 | { | |
442fcea7 | 2210 | rtx inops[2]; |
aad2444d PK |
2211 | rtx exops[2][2]; |
2212 | rtx t; | |
442fcea7 PK |
2213 | |
2214 | inops[0] = operands[0]; | |
2215 | inops[1] = operands[1]; | |
2216 | pdp11_expand_operands (inops, exops, 2, 2, NULL, either); | |
aad2444d PK |
2217 | |
2218 | t = exops[0][0]; | |
2219 | exops[0][0] = exops[1][0]; | |
2220 | exops[1][0] = t; | |
2221 | ||
2222 | output_asm_insn ("mov\t%0,%1", exops[0]); | |
2223 | output_asm_insn ("mov\t%0,%1", exops[1]); | |
2224 | output_asm_insn ("swab\t%0", exops[0]); | |
2225 | output_asm_insn ("swab\t%0", exops[1]); | |
2226 | return ""; | |
2227 | } | |
2228 | [(set_attr "length" "8,10,12")]) | |
2229 | ||
2230 | (define_expand "rotrhi3" | |
2231 | [(match_operand:HI 0 "register_operand" "") | |
2232 | (match_operand:HI 1 "register_operand" "") | |
2233 | (match_operand:HI 2 "general_operand" "")] | |
2234 | "TARGET_40_PLUS" | |
2235 | " | |
2236 | { | |
2237 | operands[2] = negate_rtx (HImode, operands[2]); | |
2238 | emit_insn (gen_rotlhi3 (operands[0], operands[1], operands[2])); | |
2239 | DONE; | |
2240 | }") | |
2241 | ||
2242 | (define_insn_and_split "rotlhi3" | |
2243 | [(set (match_operand:HI 0 "register_operand" "=d,d") | |
2244 | (rotate:HI (match_operand:HI 1 "register_operand" "0,0") | |
2245 | (match_operand:HI 2 "general_operand" "rR,Qi")))] | |
2246 | "TARGET_40_PLUS" | |
2247 | "#" | |
2248 | "&& reload_completed" | |
2249 | [(parallel [(set (match_dup 0) | |
2250 | (rotate:HI (match_dup 1) (match_dup 2))) | |
2251 | (clobber (reg:CC CC_REGNUM))])] | |
2252 | "" | |
2253 | [(set_attr "length" "2,4") | |
2254 | (set_attr "base_cost" "8")]) | |
2255 | ||
2256 | (define_insn "rotlhi3<cc_ccnz>" | |
2257 | [(set (match_operand:HI 0 "register_operand" "=d,d") | |
2258 | (rotate:HI (match_operand:HI 1 "register_operand" "0,0") | |
2259 | (match_operand:HI 2 "general_operand" "rR,Qi"))) | |
2260 | (clobber (reg:CC CC_REGNUM))] | |
2261 | "TARGET_40_PLUS && reload_completed" | |
2262 | "ashc\t%2,%0" | |
2263 | [(set_attr "length" "2,4") | |
2264 | (set_attr "base_cost" "8")]) | |
2265 | ||
2266 | ||
2267 | ||
2268 | ;; Some peephole optimizations | |
2269 | ||
2270 | ;; Move then conditional branch on the result of the move is handled | |
2271 | ;; by compare elimination, but an earlier pass sometimes changes the | |
2272 | ;; compare operand to the move input, and then the compare is not | |
2273 | ;; eliminated. Do so here. | |
2274 | (define_peephole2 | |
2275 | [(parallel [(set (match_operand:PDPint 0 "nonimmediate_operand" "") | |
2276 | (match_operand:PDPint 1 "general_operand" "")) | |
2277 | (clobber (reg:CC CC_REGNUM))]) | |
2278 | (set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))] | |
2279 | "" | |
2280 | [(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0))) | |
2281 | (set (match_dup 0) (match_dup 1))])] | |
2282 | "") |