1;; This file contains instructions that support fixed-point operations 2;; for Atmel AVR micro controllers. 3;; Copyright (C) 2012-2019 Free Software Foundation, Inc. 4;; 5;; Contributed by Sean D'Epagnier (sean@depagnier.com) 6;; Georg-Johann Lay (avr@gjlay.de) 7 8;; This file is part of GCC. 9;; 10;; GCC is free software; you can redistribute it and/or modify 11;; it under the terms of the GNU General Public License as published by 12;; the Free Software Foundation; either version 3, or (at your option) 13;; any later version. 14;; 15;; GCC is distributed in the hope that it will be useful, 16;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18;; GNU General Public License for more details. 19;; 20;; You should have received a copy of the GNU General Public License 21;; along with GCC; see the file COPYING3. If not see 22;; <http://www.gnu.org/licenses/>. 23 24(define_mode_iterator ALL1Q [QQ UQQ]) 25(define_mode_iterator ALL2Q [HQ UHQ]) 26(define_mode_iterator ALL2A [HA UHA]) 27(define_mode_iterator ALL4A [SA USA]) 28(define_mode_iterator ALL2QA [HQ UHQ HA UHA]) 29(define_mode_iterator ALL4QA [SQ USQ SA USA]) 30(define_mode_iterator ALL124QA [ QQ HQ HA SA SQ 31 UQQ UHQ UHA USA USQ]) 32 33(define_mode_iterator ALL2S [HQ HA]) 34(define_mode_iterator ALL4S [SA SQ]) 35(define_mode_iterator ALL24S [ HQ HA SA SQ]) 36(define_mode_iterator ALL124S [ QQ HQ HA SA SQ]) 37(define_mode_iterator ALL124U [UQQ UHQ UHA USA USQ]) 38 39;;; Conversions 40 41(define_mode_iterator FIXED_A 42 [QQ UQQ 43 HQ UHQ HA UHA 44 SQ USQ SA USA 45 DQ UDQ DA UDA 46 TA UTA 47 QI HI SI DI]) 48 49;; Same so that be can build cross products 50 51(define_mode_iterator FIXED_B 52 [QQ UQQ 53 HQ UHQ HA UHA 54 SQ USQ SA USA 55 DQ UDQ DA UDA 56 TA UTA 57 QI HI SI DI]) 58 59(define_insn "fract<FIXED_B:mode><FIXED_A:mode>2" 60 [(set (match_operand:FIXED_A 0 "register_operand" "=r") 61 (fract_convert:FIXED_A 62 (match_operand:FIXED_B 1 "register_operand" "r")))] 63 "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode" 64 { 65 return avr_out_fract (insn, operands, true, NULL); 66 } 67 [(set_attr "cc" "clobber") 68 (set_attr "adjust_len" "sfract")]) 69 70(define_insn "fractuns<FIXED_B:mode><FIXED_A:mode>2" 71 [(set (match_operand:FIXED_A 0 "register_operand" "=r") 72 (unsigned_fract_convert:FIXED_A 73 (match_operand:FIXED_B 1 "register_operand" "r")))] 74 "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode" 75 { 76 return avr_out_fract (insn, operands, false, NULL); 77 } 78 [(set_attr "cc" "clobber") 79 (set_attr "adjust_len" "ufract")]) 80 81;****************************************************************************** 82;** Saturated Addition and Subtraction 83;****************************************************************************** 84 85;; Fixme: It would be nice if we could expand the 32-bit versions to a 86;; transparent libgcc call if $2 is a REG. Problem is that it is 87;; not possible to describe that addition is commutative. 88;; And defining register classes/constraintrs for the involved hard 89;; registers and let IRA do the work, yields inacceptable bloated code. 90;; Thus, we have to live with the up to 11 instructions that are output 91;; for these 32-bit saturated operations. 92 93;; "ssaddqq3" "ssaddhq3" "ssaddha3" "ssaddsq3" "ssaddsa3" 94;; "sssubqq3" "sssubhq3" "sssubha3" "sssubsq3" "sssubsa3" 95(define_insn "<code_stdname><mode>3" 96 [(set (match_operand:ALL124S 0 "register_operand" "=??d,d") 97 (ss_addsub:ALL124S (match_operand:ALL124S 1 "register_operand" "<abelian>0,0") 98 (match_operand:ALL124S 2 "nonmemory_operand" "r,Ynn")))] 99 "" 100 { 101 return avr_out_plus (insn, operands); 102 } 103 [(set_attr "cc" "clobber") 104 (set_attr "adjust_len" "plus")]) 105 106;; "usadduqq3" "usadduhq3" "usadduha3" "usaddusq3" "usaddusa3" 107;; "ussubuqq3" "ussubuhq3" "ussubuha3" "ussubusq3" "ussubusa3" 108(define_insn "<code_stdname><mode>3" 109 [(set (match_operand:ALL124U 0 "register_operand" "=??r,d") 110 (us_addsub:ALL124U (match_operand:ALL124U 1 "register_operand" "<abelian>0,0") 111 (match_operand:ALL124U 2 "nonmemory_operand" "r,Ynn")))] 112 "" 113 { 114 return avr_out_plus (insn, operands); 115 } 116 [(set_attr "cc" "clobber") 117 (set_attr "adjust_len" "plus")]) 118 119;****************************************************************************** 120;** Saturated Negation and Absolute Value 121;****************************************************************************** 122 123;; Fixme: This will always result in 0. Dunno why simplify-rtx.c says 124;; "unknown" on how to optimize this. libgcc call would be in order, 125;; but the performance is *PLAIN* *HORROR* because the optimizers don't 126;; manage to optimize out MEMCPY that's sprincled all over fixed-bit.c */ 127 128(define_expand "usneg<mode>2" 129 [(parallel [(match_operand:ALL124U 0 "register_operand" "") 130 (match_operand:ALL124U 1 "nonmemory_operand" "")])] 131 "" 132 { 133 emit_move_insn (operands[0], CONST0_RTX (<MODE>mode)); 134 DONE; 135 }) 136 137(define_insn "ssnegqq2" 138 [(set (match_operand:QQ 0 "register_operand" "=r") 139 (ss_neg:QQ (match_operand:QQ 1 "register_operand" "0")))] 140 "" 141 "neg %0\;brvc 0f\;dec %0\;0:" 142 [(set_attr "cc" "clobber") 143 (set_attr "length" "3")]) 144 145(define_insn "ssabsqq2" 146 [(set (match_operand:QQ 0 "register_operand" "=r") 147 (ss_abs:QQ (match_operand:QQ 1 "register_operand" "0")))] 148 "" 149 "sbrc %0,7\;neg %0\;sbrc %0,7\;dec %0" 150 [(set_attr "cc" "clobber") 151 (set_attr "length" "4")]) 152 153;; "ssneghq2" "ssnegha2" "ssnegsq2" "ssnegsa2" 154;; "ssabshq2" "ssabsha2" "ssabssq2" "ssabssa2" 155(define_expand "<code_stdname><mode>2" 156 [(set (match_dup 2) 157 (match_operand:ALL24S 1 "register_operand" "")) 158 (set (match_dup 2) 159 (ss_abs_neg:ALL24S (match_dup 2))) 160 (set (match_operand:ALL24S 0 "register_operand" "") 161 (match_dup 2))] 162 "" 163 { 164 operands[2] = gen_rtx_REG (<MODE>mode, 26 - GET_MODE_SIZE (<MODE>mode)); 165 }) 166 167;; "*ssneghq2" "*ssnegha2" 168;; "*ssabshq2" "*ssabsha2" 169(define_insn "*<code_stdname><mode>2" 170 [(set (reg:ALL2S 24) 171 (ss_abs_neg:ALL2S (reg:ALL2S 24)))] 172 "" 173 "%~call __<code_stdname>_2" 174 [(set_attr "type" "xcall") 175 (set_attr "cc" "clobber")]) 176 177;; "*ssnegsq2" "*ssnegsa2" 178;; "*ssabssq2" "*ssabssa2" 179(define_insn "*<code_stdname><mode>2" 180 [(set (reg:ALL4S 22) 181 (ss_abs_neg:ALL4S (reg:ALL4S 22)))] 182 "" 183 "%~call __<code_stdname>_4" 184 [(set_attr "type" "xcall") 185 (set_attr "cc" "clobber")]) 186 187;****************************************************************************** 188; mul 189 190;; "mulqq3" "muluqq3" 191(define_expand "mul<mode>3" 192 [(parallel [(match_operand:ALL1Q 0 "register_operand" "") 193 (match_operand:ALL1Q 1 "register_operand" "") 194 (match_operand:ALL1Q 2 "register_operand" "")])] 195 "" 196 { 197 emit_insn (AVR_HAVE_MUL 198 ? gen_mul<mode>3_enh (operands[0], operands[1], operands[2]) 199 : gen_mul<mode>3_nomul (operands[0], operands[1], operands[2])); 200 DONE; 201 }) 202 203(define_insn "mulqq3_enh" 204 [(set (match_operand:QQ 0 "register_operand" "=r") 205 (mult:QQ (match_operand:QQ 1 "register_operand" "a") 206 (match_operand:QQ 2 "register_operand" "a")))] 207 "AVR_HAVE_MUL" 208 "fmuls %1,%2\;dec r1\;brvs 0f\;inc r1\;0:\;mov %0,r1\;clr __zero_reg__" 209 [(set_attr "length" "6") 210 (set_attr "cc" "clobber")]) 211 212(define_insn "muluqq3_enh" 213 [(set (match_operand:UQQ 0 "register_operand" "=r") 214 (mult:UQQ (match_operand:UQQ 1 "register_operand" "r") 215 (match_operand:UQQ 2 "register_operand" "r")))] 216 "AVR_HAVE_MUL" 217 "mul %1,%2\;mov %0,r1\;clr __zero_reg__" 218 [(set_attr "length" "3") 219 (set_attr "cc" "clobber")]) 220 221(define_expand "mulqq3_nomul" 222 [(set (reg:QQ 24) 223 (match_operand:QQ 1 "register_operand" "")) 224 (set (reg:QQ 25) 225 (match_operand:QQ 2 "register_operand" "")) 226 ;; "*mulqq3.call" 227 (parallel [(set (reg:QQ 23) 228 (mult:QQ (reg:QQ 24) 229 (reg:QQ 25))) 230 (clobber (reg:QI 22)) 231 (clobber (reg:HI 24))]) 232 (set (match_operand:QQ 0 "register_operand" "") 233 (reg:QQ 23))] 234 "!AVR_HAVE_MUL" 235 { 236 avr_fix_inputs (operands, 1 << 2, regmask (QQmode, 24)); 237 }) 238 239 240(define_expand "muluqq3_nomul" 241 [(set (reg:UQQ 22) 242 (match_operand:UQQ 1 "register_operand" "")) 243 (set (reg:UQQ 24) 244 (match_operand:UQQ 2 "register_operand" "")) 245 ;; "*umulqihi3.call" 246 (parallel [(set (reg:HI 24) 247 (mult:HI (zero_extend:HI (reg:QI 22)) 248 (zero_extend:HI (reg:QI 24)))) 249 (clobber (reg:QI 21)) 250 (clobber (reg:HI 22))]) 251 (set (match_operand:UQQ 0 "register_operand" "") 252 (reg:UQQ 25))] 253 "!AVR_HAVE_MUL" 254 { 255 avr_fix_inputs (operands, 1 << 2, regmask (UQQmode, 22)); 256 }) 257 258(define_insn "*mulqq3.call" 259 [(set (reg:QQ 23) 260 (mult:QQ (reg:QQ 24) 261 (reg:QQ 25))) 262 (clobber (reg:QI 22)) 263 (clobber (reg:HI 24))] 264 "!AVR_HAVE_MUL" 265 "%~call __mulqq3" 266 [(set_attr "type" "xcall") 267 (set_attr "cc" "clobber")]) 268 269 270;; "mulhq3" "muluhq3" 271;; "mulha3" "muluha3" 272(define_expand "mul<mode>3" 273 [(set (reg:ALL2QA 18) 274 (match_operand:ALL2QA 1 "register_operand" "")) 275 (set (reg:ALL2QA 26) 276 (match_operand:ALL2QA 2 "register_operand" "")) 277 ;; "*mulhq3.call.enh" 278 (parallel [(set (reg:ALL2QA 24) 279 (mult:ALL2QA (reg:ALL2QA 18) 280 (reg:ALL2QA 26))) 281 (clobber (reg:HI 22))]) 282 (set (match_operand:ALL2QA 0 "register_operand" "") 283 (reg:ALL2QA 24))] 284 "AVR_HAVE_MUL" 285 { 286 avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 18)); 287 }) 288 289;; "*mulhq3.call" "*muluhq3.call" 290;; "*mulha3.call" "*muluha3.call" 291(define_insn "*mul<mode>3.call" 292 [(set (reg:ALL2QA 24) 293 (mult:ALL2QA (reg:ALL2QA 18) 294 (reg:ALL2QA 26))) 295 (clobber (reg:HI 22))] 296 "AVR_HAVE_MUL" 297 "%~call __mul<mode>3" 298 [(set_attr "type" "xcall") 299 (set_attr "cc" "clobber")]) 300 301 302;; On the enhanced core, don't clobber either input and use a separate output 303 304;; "mulsa3" "mulusa3" 305(define_expand "mul<mode>3" 306 [(set (reg:ALL4A 16) 307 (match_operand:ALL4A 1 "register_operand" "")) 308 (set (reg:ALL4A 20) 309 (match_operand:ALL4A 2 "register_operand" "")) 310 (set (reg:ALL4A 24) 311 (mult:ALL4A (reg:ALL4A 16) 312 (reg:ALL4A 20))) 313 (set (match_operand:ALL4A 0 "register_operand" "") 314 (reg:ALL4A 24))] 315 "AVR_HAVE_MUL" 316 { 317 avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 16)); 318 }) 319 320;; "*mulsa3.call" "*mulusa3.call" 321(define_insn "*mul<mode>3.call" 322 [(set (reg:ALL4A 24) 323 (mult:ALL4A (reg:ALL4A 16) 324 (reg:ALL4A 20)))] 325 "AVR_HAVE_MUL" 326 "%~call __mul<mode>3" 327 [(set_attr "type" "xcall") 328 (set_attr "cc" "clobber")]) 329 330; / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / 331; div 332 333(define_code_iterator usdiv [udiv div]) 334 335;; "divqq3" "udivuqq3" 336(define_expand "<code><mode>3" 337 [(set (reg:ALL1Q 25) 338 (match_operand:ALL1Q 1 "register_operand" "")) 339 (set (reg:ALL1Q 22) 340 (match_operand:ALL1Q 2 "register_operand" "")) 341 (parallel [(set (reg:ALL1Q 24) 342 (usdiv:ALL1Q (reg:ALL1Q 25) 343 (reg:ALL1Q 22))) 344 (clobber (reg:QI 25))]) 345 (set (match_operand:ALL1Q 0 "register_operand" "") 346 (reg:ALL1Q 24))] 347 "" 348 { 349 avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 25)); 350 }) 351 352 353;; "*divqq3.call" "*udivuqq3.call" 354(define_insn "*<code><mode>3.call" 355 [(set (reg:ALL1Q 24) 356 (usdiv:ALL1Q (reg:ALL1Q 25) 357 (reg:ALL1Q 22))) 358 (clobber (reg:QI 25))] 359 "" 360 "%~call __<code><mode>3" 361 [(set_attr "type" "xcall") 362 (set_attr "cc" "clobber")]) 363 364;; "divhq3" "udivuhq3" 365;; "divha3" "udivuha3" 366(define_expand "<code><mode>3" 367 [(set (reg:ALL2QA 26) 368 (match_operand:ALL2QA 1 "register_operand" "")) 369 (set (reg:ALL2QA 22) 370 (match_operand:ALL2QA 2 "register_operand" "")) 371 (parallel [(set (reg:ALL2QA 24) 372 (usdiv:ALL2QA (reg:ALL2QA 26) 373 (reg:ALL2QA 22))) 374 (clobber (reg:HI 26)) 375 (clobber (reg:QI 21))]) 376 (set (match_operand:ALL2QA 0 "register_operand" "") 377 (reg:ALL2QA 24))] 378 "" 379 { 380 avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 26)); 381 }) 382 383;; "*divhq3.call" "*udivuhq3.call" 384;; "*divha3.call" "*udivuha3.call" 385(define_insn "*<code><mode>3.call" 386 [(set (reg:ALL2QA 24) 387 (usdiv:ALL2QA (reg:ALL2QA 26) 388 (reg:ALL2QA 22))) 389 (clobber (reg:HI 26)) 390 (clobber (reg:QI 21))] 391 "" 392 "%~call __<code><mode>3" 393 [(set_attr "type" "xcall") 394 (set_attr "cc" "clobber")]) 395 396;; Note the first parameter gets passed in already offset by 2 bytes 397 398;; "divsa3" "udivusa3" 399(define_expand "<code><mode>3" 400 [(set (reg:ALL4A 24) 401 (match_operand:ALL4A 1 "register_operand" "")) 402 (set (reg:ALL4A 18) 403 (match_operand:ALL4A 2 "register_operand" "")) 404 (parallel [(set (reg:ALL4A 22) 405 (usdiv:ALL4A (reg:ALL4A 24) 406 (reg:ALL4A 18))) 407 (clobber (reg:HI 26)) 408 (clobber (reg:HI 30))]) 409 (set (match_operand:ALL4A 0 "register_operand" "") 410 (reg:ALL4A 22))] 411 "" 412 { 413 avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 24)); 414 }) 415 416;; "*divsa3.call" "*udivusa3.call" 417(define_insn "*<code><mode>3.call" 418 [(set (reg:ALL4A 22) 419 (usdiv:ALL4A (reg:ALL4A 24) 420 (reg:ALL4A 18))) 421 (clobber (reg:HI 26)) 422 (clobber (reg:HI 30))] 423 "" 424 "%~call __<code><mode>3" 425 [(set_attr "type" "xcall") 426 (set_attr "cc" "clobber")]) 427 428 429;****************************************************************************** 430;** Rounding 431;****************************************************************************** 432 433;; "roundqq3" "rounduqq3" 434;; "roundhq3" "rounduhq3" "roundha3" "rounduha3" 435;; "roundsq3" "roundusq3" "roundsa3" "roundusa3" 436(define_expand "round<mode>3" 437 [(set (match_dup 4) 438 (match_operand:ALL124QA 1 "register_operand" "")) 439 (set (reg:QI 24) 440 (match_dup 5)) 441 (parallel [(set (match_dup 3) 442 (unspec:ALL124QA [(match_dup 4) 443 (reg:QI 24)] UNSPEC_ROUND)) 444 (clobber (match_dup 4))]) 445 (set (match_operand:ALL124QA 0 "register_operand" "") 446 (match_dup 3)) 447 (use (match_operand:HI 2 "nonmemory_operand" ""))] 448 "" 449 { 450 if (CONST_INT_P (operands[2]) 451 && !(optimize_size 452 && 4 == GET_MODE_SIZE (<MODE>mode))) 453 { 454 emit_insn (gen_round<mode>3_const (operands[0], operands[1], operands[2])); 455 DONE; 456 } 457 458 // Input and output of the libgcc function 459 const unsigned int regno_in[] = { -1U, 22, 22, -1U, 18 }; 460 const unsigned int regno_out[] = { -1U, 24, 24, -1U, 22 }; 461 462 operands[3] = gen_rtx_REG (<MODE>mode, regno_out[(size_t) GET_MODE_SIZE (<MODE>mode)]); 463 operands[4] = gen_rtx_REG (<MODE>mode, regno_in[(size_t) GET_MODE_SIZE (<MODE>mode)]); 464 avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, REGNO (operands[4]))); 465 operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0); 466 // $2 is no more needed, but is referenced for expand. 467 operands[2] = const0_rtx; 468 }) 469 470;; Expand rounding with known rounding points inline so that the addend / mask 471;; will be consumed by operation with immediate operands and there is no 472;; need for a shift with variable offset. 473 474;; "roundqq3_const" "rounduqq3_const" 475;; "roundhq3_const" "rounduhq3_const" "roundha3_const" "rounduha3_const" 476;; "roundsq3_const" "roundusq3_const" "roundsa3_const" "roundusa3_const" 477(define_insn "round<mode>3_const" 478 [(set (match_operand:ALL124QA 0 "register_operand" "=d") 479 (unspec:ALL124QA [(match_operand:ALL124QA 1 "register_operand" "0") 480 (match_operand:HI 2 "const_int_operand" "n") 481 (const_int 0)] 482 UNSPEC_ROUND))] 483 "" 484 { 485 return avr_out_round (insn, operands); 486 } 487 [(set_attr "cc" "clobber") 488 (set_attr "adjust_len" "round")]) 489 490 491;; "*roundqq3.libgcc" "*rounduqq3.libgcc" 492(define_insn "*round<mode>3.libgcc" 493 [(set (reg:ALL1Q 24) 494 (unspec:ALL1Q [(reg:ALL1Q 22) 495 (reg:QI 24)] UNSPEC_ROUND)) 496 (clobber (reg:ALL1Q 22))] 497 "" 498 "%~call __round<mode>3" 499 [(set_attr "type" "xcall") 500 (set_attr "cc" "clobber")]) 501 502;; "*roundhq3.libgcc" "*rounduhq3.libgcc" 503;; "*roundha3.libgcc" "*rounduha3.libgcc" 504(define_insn "*round<mode>3.libgcc" 505 [(set (reg:ALL2QA 24) 506 (unspec:ALL2QA [(reg:ALL2QA 22) 507 (reg:QI 24)] UNSPEC_ROUND)) 508 (clobber (reg:ALL2QA 22))] 509 "" 510 "%~call __round<mode>3" 511 [(set_attr "type" "xcall") 512 (set_attr "cc" "clobber")]) 513 514;; "*roundsq3.libgcc" "*roundusq3.libgcc" 515;; "*roundsa3.libgcc" "*roundusa3.libgcc" 516(define_insn "*round<mode>3.libgcc" 517 [(set (reg:ALL4QA 22) 518 (unspec:ALL4QA [(reg:ALL4QA 18) 519 (reg:QI 24)] UNSPEC_ROUND)) 520 (clobber (reg:ALL4QA 18))] 521 "" 522 "%~call __round<mode>3" 523 [(set_attr "type" "xcall") 524 (set_attr "cc" "clobber")]) 525