1 { 2 Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe 3 4 Code generation for add nodes on the Motorola 680x0 family 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20 **************************************************************************** 21 } 22 unit n68kadd; 23 24 {$i fpcdefs.inc} 25 26 interface 27 28 uses 29 node,nadd,ncgadd,cpubase,cgbase; 30 31 32 type 33 t68kaddnode = class(tcgaddnode) 34 private getresflagsnull35 function getresflags(unsigned: boolean) : tresflags; getfloatresflagsnull36 function getfloatresflags: tresflags; inlineable_realconstnodenull37 function inlineable_realconstnode(const n: tnode): boolean; 38 procedure second_mul64bit; 39 protected use_generic_mul64bitnull40 function use_generic_mul64bit: boolean; override; use_generic_mul32to64null41 function use_generic_mul32to64: boolean; override; use_mul_helpernull42 function use_mul_helper: boolean; override; 43 procedure second_addfloat;override; 44 procedure second_cmpfloat;override; 45 procedure second_addordinal;override; 46 procedure second_cmpordinal;override; 47 procedure second_cmpsmallset;override; 48 procedure second_add64bit;override; 49 procedure second_cmp64bit;override; 50 end; 51 52 53 implementation 54 55 uses 56 globtype,systems, 57 cutils,verbose,globals, 58 symconst,symdef,paramgr,symtype, 59 aasmbase,aasmtai,aasmdata,aasmcpu,defutil,htypechk, 60 cpuinfo,pass_1,pass_2, 61 cpupara,cgutils,procinfo, 62 ncon,nset, 63 ncgutil,tgobj,rgobj,rgcpu,cgobj,cgcpu,hlcgobj,cg64f32; 64 65 {***************************************************************************** 66 Helpers 67 *****************************************************************************} 68 t68kaddnode.getresflagsnull69 function t68kaddnode.getresflags(unsigned : boolean) : tresflags; 70 begin 71 case nodetype of 72 equaln : getresflags:=F_E; 73 unequaln : getresflags:=F_NE; 74 else 75 if not(unsigned) then 76 begin 77 if nf_swapped in flags then 78 case nodetype of 79 ltn : getresflags:=F_G; 80 lten : getresflags:=F_GE; 81 gtn : getresflags:=F_L; 82 gten : getresflags:=F_LE; 83 else 84 internalerror(2014082030); 85 end 86 else 87 case nodetype of 88 ltn : getresflags:=F_L; 89 lten : getresflags:=F_LE; 90 gtn : getresflags:=F_G; 91 gten : getresflags:=F_GE; 92 else 93 internalerror(2014082031); 94 end; 95 end 96 else 97 begin 98 if nf_swapped in flags then 99 case nodetype of 100 ltn : getresflags:=F_A; 101 lten : getresflags:=F_AE; 102 gtn : getresflags:=F_B; 103 gten : getresflags:=F_BE; 104 else 105 internalerror(2014082032); 106 end 107 else 108 case nodetype of 109 ltn : getresflags:=F_B; 110 lten : getresflags:=F_BE; 111 gtn : getresflags:=F_A; 112 gten : getresflags:=F_AE; 113 else 114 internalerror(2014082033); 115 end; 116 end; 117 end; 118 end; 119 120 t68kaddnode.getfloatresflagsnull121 function t68kaddnode.getfloatresflags : tresflags; 122 begin 123 case nodetype of 124 equaln : getfloatresflags:=F_FE; 125 unequaln : getfloatresflags:=F_FNE; 126 else 127 if nf_swapped in flags then 128 case nodetype of 129 ltn : getfloatresflags:=F_FG; 130 lten : getfloatresflags:=F_FGE; 131 gtn : getfloatresflags:=F_FL; 132 gten : getfloatresflags:=F_FLE; 133 else 134 internalerror(201604260); 135 end 136 else 137 case nodetype of 138 ltn : getfloatresflags:=F_FL; 139 lten : getfloatresflags:=F_FLE; 140 gtn : getfloatresflags:=F_FG; 141 gten : getfloatresflags:=F_FGE; 142 else 143 internalerror(201604261); 144 end; 145 end; 146 end; 147 148 t68kaddnode.inlineable_realconstnodenull149 function t68kaddnode.inlineable_realconstnode(const n: tnode): boolean; 150 begin 151 result:=(n.nodetype = realconstn) and 152 not ((trealconstnode(n).value_real=MathInf.Value) or 153 (trealconstnode(n).value_real=MathNegInf.Value) or 154 (trealconstnode(n).value_real=MathQNaN.value)); 155 end; 156 157 158 {***************************************************************************** 159 AddFloat 160 *****************************************************************************} 161 162 procedure t68kaddnode.second_addfloat; 163 var 164 op : TAsmOp; 165 href : TReference; 166 begin 167 pass_left_right; 168 169 case nodetype of 170 addn : 171 op:=A_FADD; 172 muln : 173 op:=A_FMUL; 174 subn : 175 op:=A_FSUB; 176 slashn : 177 op:=A_FDIV; 178 else 179 internalerror(200403182); 180 end; 181 182 // get the operands in the correct order, there are no special cases 183 // here, everything is register-based 184 if nf_swapped in flags then 185 swapleftright; 186 187 case current_settings.fputype of 188 fpu_68881,fpu_coldfire: 189 begin 190 { initialize the result } 191 location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef)); 192 193 { have left in the register, right can be a memory location } 194 if not (current_settings.fputype = fpu_coldfire) and 195 inlineable_realconstnode(left) then 196 begin 197 location.register := cg.getfpuregister(current_asmdata.CurrAsmList,location.size); 198 current_asmdata.CurrAsmList.concat(taicpu.op_realconst_reg(A_FMOVE,tcgsize2opsize[left.location.size],trealconstnode(left).value_real,location.register)) 199 end 200 else 201 begin 202 hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true); 203 204 location.register := cg.getfpuregister(current_asmdata.CurrAsmList,location.size); 205 cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmlist,left.location.size,location.size,left.location.register,location.register); 206 end; 207 208 { emit the actual operation } 209 case right.location.loc of 210 LOC_FPUREGISTER,LOC_CFPUREGISTER: 211 current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,fpuregopsize,right.location.register,location.register)); 212 LOC_REFERENCE,LOC_CREFERENCE: 213 begin 214 if not (current_settings.fputype = fpu_coldfire) and 215 inlineable_realconstnode(right) then 216 current_asmdata.CurrAsmList.concat(taicpu.op_realconst_reg(op,tcgsize2opsize[right.location.size],trealconstnode(right).value_real,location.register)) 217 else 218 begin 219 href:=right.location.reference; 220 tcg68k(cg).fixref(current_asmdata.CurrAsmList,href,current_settings.fputype = fpu_coldfire); 221 current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(op,tcgsize2opsize[right.location.size],href,location.register)); 222 end; 223 end 224 else 225 internalerror(2015021501); 226 end; 227 end; 228 else 229 // softfpu should be handled in pass1, others are not yet supported... 230 internalerror(2015010201); 231 end; 232 end; 233 234 235 procedure t68kaddnode.second_cmpfloat; 236 var 237 tmpreg : tregister; 238 ai: taicpu; 239 href : TReference; 240 begin 241 pass_left_right; 242 if (nf_swapped in flags) then 243 swapleftright; 244 245 case current_settings.fputype of 246 fpu_68881,fpu_coldfire: 247 begin 248 location_reset(location,LOC_FLAGS,OS_NO); 249 location.resflags:=getfloatresflags; 250 251 { emit compare } 252 case right.location.loc of 253 LOC_FPUREGISTER,LOC_CFPUREGISTER: 254 begin 255 //current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('second_cmpfloat right reg!'))); 256 if left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then 257 begin 258 href:=left.location.reference; 259 tcg68k(cg).fixref(current_asmdata.CurrAsmList,href,current_settings.fputype = fpu_coldfire); 260 current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_FCMP,tcgsize2opsize[left.location.size],href,right.location.register)); 261 toggleflag(nf_swapped); 262 location.resflags:=getfloatresflags; 263 end 264 else 265 begin 266 hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true); 267 current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCMP,fpuregopsize,right.location.register,left.location.register)); 268 end; 269 end; 270 LOC_REFERENCE,LOC_CREFERENCE: 271 begin 272 { use FTST, if realconst is 0.0, it would be hard to do this in the 273 optimizer, because we would need to investigate the referenced value... } 274 if (right.nodetype = realconstn) and 275 (trealconstnode(right).value_real = 0.0) then 276 begin 277 if left.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then 278 current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_FTST,fpuregopsize,left.location.register)) 279 else 280 if left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then 281 begin 282 href:=left.location.reference; 283 tcg68k(cg).fixref(current_asmdata.CurrAsmList,href,false); 284 current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_FTST,tcgsize2opsize[left.location.size],href)) 285 end 286 else 287 internalerror(2016051001); 288 end 289 else 290 begin 291 hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true); 292 if not (current_settings.fputype = fpu_coldfire) and 293 inlineable_realconstnode(right) then 294 current_asmdata.CurrAsmList.concat(taicpu.op_realconst_reg(A_FCMP,tcgsize2opsize[right.location.size],trealconstnode(right).value_real,left.location.register)) 295 else 296 begin 297 href:=right.location.reference; 298 tcg68k(cg).fixref(current_asmdata.CurrAsmList,href,current_settings.fputype = fpu_coldfire); 299 current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_FCMP,tcgsize2opsize[right.location.size],href,left.location.register)); 300 end; 301 end; 302 end 303 else 304 internalerror(2015021502); 305 end; 306 307 end; 308 else 309 // softfpu should be handled in pass1, others are not yet supported... 310 internalerror(2015010201); 311 end; 312 end; 313 314 315 316 317 {***************************************************************************** 318 Smallsets 319 *****************************************************************************} 320 321 procedure t68kaddnode.second_cmpsmallset; 322 var 323 tmpreg : tregister; 324 opsize: topsize; 325 cmpsize : tcgsize; 326 begin 327 pass_left_right; 328 329 location_reset(location,LOC_FLAGS,OS_NO); 330 331 cmpsize:=def_cgsize(left.resultdef); 332 opsize:=tcgsize2opsize[cmpsize]; 333 334 { Coldfire supports byte/word compares only starting with ISA_B, 335 See remark about Qemu weirdness in tcg68k.a_cmp_const_reg_label } 336 if (opsize<>S_L) and (current_settings.cputype in cpu_coldfire{-[cpu_isa_b,cpu_isa_c,cfv4e]}) then 337 begin 338 cmpsize:=OS_32; 339 opsize:=S_L; 340 end; 341 342 if (not(nf_swapped in flags) and 343 (nodetype = lten)) or 344 ((nf_swapped in flags) and 345 (nodetype = gten)) then 346 swapleftright; 347 348 { Try to keep right as a constant } 349 if right.location.loc<>LOC_CONSTANT then 350 hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,cgsize_orddef(cmpsize),true); 351 hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,cgsize_orddef(cmpsize),true); 352 353 case nodetype of 354 equaln, 355 unequaln: 356 begin 357 if right.location.loc=LOC_CONSTANT then 358 current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,opsize,right.location.value,left.location.register)) 359 else 360 current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,opsize,right.location.register,left.location.register)); 361 if nodetype=equaln then 362 location.resflags:=F_E 363 else 364 location.resflags:=F_NE; 365 end; 366 lten, 367 gten: 368 begin 369 tmpreg:=cg.getintregister(current_asmdata.CurrAsmList,left.location.size); 370 if right.location.loc=LOC_CONSTANT then 371 hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,cgsize_orddef(cmpsize),false); 372 cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_AND,cmpsize,left.location.register,right.location.register,tmpreg); 373 current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,opsize,tmpreg,right.location.register)); 374 location.resflags:=F_E; 375 end; 376 else 377 internalerror(2013092701); 378 end; 379 end; 380 381 382 {***************************************************************************** 383 Ordinals 384 *****************************************************************************} 385 t68kaddnode.use_mul_helpernull386 function t68kaddnode.use_mul_helper: boolean; 387 begin 388 result:=(nodetype=muln) and not (CPUM68K_HAS_32BITMUL in cpu_capabilities[current_settings.cputype]); 389 end; 390 391 procedure t68kaddnode.second_addordinal; 392 const 393 mul_op_signed: array[boolean] of tasmop = ( A_MULU, A_MULS ); 394 var 395 cgop : topcg; 396 asmop : tasmop; 397 list : tasmlist; 398 href : treference; 399 begin 400 { if we need to handle overflow checking, fall back to the generic cg } 401 if (nodetype in [addn,subn,muln]) and 402 (left.resultdef.typ<>pointerdef) and 403 (right.resultdef.typ<>pointerdef) and 404 (cs_check_overflow in current_settings.localswitches) then 405 begin 406 inherited; 407 exit; 408 end; 409 410 list:=current_asmdata.CurrAsmList; 411 412 case nodetype of 413 addn: cgop:=OP_ADD; 414 xorn: cgop:=OP_XOR; 415 orn : cgop:=OP_OR; 416 andn: cgop:=OP_AND; 417 subn: cgop:=OP_SUB; 418 muln: 419 begin 420 if not(is_signed(left.resultdef)) or 421 not(is_signed(right.resultdef)) then 422 cgop:=OP_MUL 423 else 424 cgop:=OP_IMUL; 425 end; 426 else 427 internalerror(2013120104); 428 end; 429 430 pass_left_right; 431 if (nodetype=subn) and (nf_swapped in flags) then 432 swapleftright; 433 434 hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false); 435 436 { initialize the result } 437 location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); 438 439 { this is only true, if the CPU supports 32x32 -> 64 bit MUL, see the relevant method } 440 if (nodetype=muln) and is_64bit(resultdef) then 441 begin 442 list.concat(tai_comment.create(strpnew('second_addordinal: mul32to64bit'))); 443 444 asmop:=mul_op_signed[cgop = OP_IMUL]; 445 location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT); 446 location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT); 447 cg.a_load_reg_reg(list,left.location.size,OS_INT,left.location.register,location.register64.reglo); 448 449 if not (right.location.size in [OS_S32, OS_32]) or 450 not (right.location.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_CONSTANT,LOC_REFERENCE,LOC_CREFERENCE]) or 451 ((right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and needs_unaligned(right.location.reference.alignment,def_cgsize(resultdef))) then 452 hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); 453 454 case right.location.loc of 455 LOC_REGISTER, 456 LOC_CREGISTER: 457 list.concat(taicpu.op_reg_reg_reg(asmop,S_L,right.location.register,location.register64.reghi,location.register64.reglo)); 458 LOC_CONSTANT: 459 list.concat(taicpu.op_const_reg_reg(asmop,S_L,right.location.value,location.register64.reghi,location.register64.reglo)); 460 LOC_REFERENCE, 461 LOC_CREFERENCE: 462 begin 463 href:=right.location.reference; 464 tcg68k(cg).fixref(list,href,false); 465 list.concat(taicpu.op_ref_reg_reg(asmop,S_L,href,location.register64.reghi,location.register64.reglo)); 466 end; 467 else 468 internalerror(2017052601); 469 end; 470 exit; 471 end; 472 473 if isaddressregister(left.location.register) and (nodetype in [addn,subn]) then 474 location.register := cg.getaddressregister(current_asmdata.CurrAsmList) 475 else 476 location.register := cg.getintregister(current_asmdata.CurrAsmList,location.size); 477 cg.a_load_reg_reg(current_asmdata.CurrAsmlist,left.location.size,location.size,left.location.register,location.register); 478 479 if ((location.size <> right.location.size) and not (right.location.loc in [LOC_CONSTANT])) or 480 not (right.location.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_CONSTANT,LOC_REFERENCE,LOC_CREFERENCE]) or 481 (not(CPUM68K_HAS_32BITMUL in cpu_capabilities[current_settings.cputype]) and (nodetype = muln)) or 482 ((right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and needs_unaligned(right.location.reference.alignment,def_cgsize(resultdef))) then 483 hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); 484 485 case right.location.loc of 486 LOC_REGISTER, 487 LOC_CREGISTER: 488 cg.a_op_reg_reg(current_asmdata.CurrAsmList,cgop,def_cgsize(resultdef),right.location.register,location.register); 489 LOC_CONSTANT: 490 cg.a_op_const_reg(current_asmdata.CurrAsmList,cgop,def_cgsize(resultdef),right.location.value,location.register); 491 LOC_REFERENCE, 492 LOC_CREFERENCE: 493 cg.a_op_ref_reg(current_asmdata.CurrAsmList,cgop,def_cgsize(resultdef),right.location.reference,location.register); 494 else 495 internalerror(2016052101); 496 end; 497 end; 498 499 500 procedure t68kaddnode.second_cmpordinal; 501 var 502 unsigned : boolean; 503 tmpreg : tregister; 504 opsize : topsize; 505 cmpsize : tcgsize; 506 href: treference; 507 begin 508 { determine if the comparison will be unsigned } 509 unsigned:=not(is_signed(left.resultdef)) or 510 not(is_signed(right.resultdef)); 511 { this puts constant operand (if any) to the right } 512 pass_left_right; 513 { tentatively assume left size (correct for possible TST, will fix later) } 514 cmpsize:=def_cgsize(left.resultdef); 515 opsize:=tcgsize2opsize[cmpsize]; 516 517 { set result location } 518 location_reset(location,LOC_FLAGS,OS_NO); 519 520 { see if we can optimize into TST } 521 if (right.location.loc=LOC_CONSTANT) and (right.location.value=0) then 522 begin 523 { Unsigned <0 or >=0 should not reach pass2, most likely } 524 if (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and not needs_unaligned(left.location.reference.alignment,cmpsize) then 525 begin 526 href:=left.location.reference; 527 tcg68k(cg).fixref(current_asmdata.CurrAsmList,href,false); 528 current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_TST,opsize,href)); 529 location_freetemp(current_asmdata.CurrAsmList,left.location); 530 end 531 else 532 begin 533 hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); 534 if (current_settings.cputype = cpu_mc68000) and isaddressregister(left.location.register) then 535 begin 536 tmpreg:=cg.getintregister(current_asmdata.CurrAsmList,cmpsize); 537 cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,cmpsize,left.location.register,tmpreg); 538 end 539 else 540 tmpreg:=left.location.register; 541 current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_TST,opsize,tmpreg)); 542 end; 543 location.resflags := getresflags(unsigned); 544 exit; 545 end; 546 547 { Coldfire supports byte/word compares only starting with ISA_B, 548 !!see remark about Qemu weirdness in tcg68k.a_cmp_const_reg_label } 549 if (opsize<>S_L) and (current_settings.cputype in cpu_coldfire{-[cpu_isa_b,cpu_isa_c,cfv4e]}) then 550 begin 551 { 1) Extension is needed for LOC_REFERENCE, but what about LOC_REGISTER ? Perhaps after fixing cg we can assume 552 that high bits of registers are correct. 553 2) Assuming that extension depends only on source signedness --> destination OS_32 is acceptable. } 554 hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,cgsize_orddef(OS_32),false); 555 if (right.location.loc<>LOC_CONSTANT) then 556 hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,cgsize_orddef(OS_32),false); 557 opsize:=S_L; 558 end 559 else if not (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then 560 begin 561 if not (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then 562 hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true) 563 else 564 begin 565 location_swap(left.location,right.location); 566 toggleflag(nf_swapped); 567 end; 568 end; 569 570 if (right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and needs_unaligned(right.location.reference.alignment,cmpsize) then 571 hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); 572 573 { left is now in register } 574 case right.location.loc of 575 LOC_CONSTANT: 576 current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,opsize, 577 longint(right.location.value),left.location.register)); 578 LOC_REFERENCE, 579 LOC_CREFERENCE: 580 begin 581 href:=right.location.reference; 582 tcg68k(cg).fixref(current_asmdata.CurrAsmList,href,false); 583 current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_CMP,opsize,href, 584 left.location.register)); 585 end; 586 LOC_REGISTER, 587 LOC_CREGISTER: 588 current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,opsize, 589 right.location.register,left.location.register)); 590 else 591 hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); 592 current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,opsize, 593 right.location.register,left.location.register)); 594 end; 595 596 { update location because sides could have been swapped } 597 location.resflags:=getresflags(unsigned); 598 end; 599 600 601 {***************************************************************************** 602 64-bit 603 *****************************************************************************} 604 t68kaddnode.use_generic_mul32to64null605 function t68kaddnode.use_generic_mul32to64: boolean; 606 begin 607 result:=not (CPUM68K_HAS_64BITMUL in cpu_capabilities[current_settings.cputype]); 608 end; 609 t68kaddnode.use_generic_mul64bitnull610 function t68kaddnode.use_generic_mul64bit: boolean; 611 begin 612 result:=(cs_check_overflow in current_settings.localswitches) or 613 (cs_opt_size in current_settings.optimizerswitches) or 614 not (CPUM68K_HAS_64BITMUL in cpu_capabilities[current_settings.cputype]); 615 end; 616 617 procedure t68kaddnode.second_add64bit; 618 begin 619 if (nodetype=muln) then 620 second_mul64bit 621 else 622 inherited second_add64bit; 623 end; 624 625 procedure t68kaddnode.second_mul64bit; 626 var 627 list: TAsmList; 628 hreg1,hreg2,tmpreg: TRegister; 629 begin 630 list:=current_asmdata.CurrAsmList; 631 pass_left_right; 632 location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); 633 hlcg.location_force_reg(list,left.location,left.resultdef,left.resultdef,true); 634 635 { calculate 32-bit terms lo(right)*hi(left) and hi(left)*lo(right) } 636 hreg1:=NR_NO; 637 hreg2:=NR_NO; 638 tmpreg:=NR_NO; 639 if (right.location.loc=LOC_CONSTANT) then 640 begin 641 //list.concat(tai_comment.create(strpnew('second_mul64bit: with const'))); 642 { Omit zero terms, if any } 643 if hi(right.location.value64)<>0 then 644 begin 645 hreg2:=cg.getintregister(list,OS_INT); 646 cg.a_load_const_reg(list,OS_INT,longint(hi(right.location.value64)),hreg2); 647 list.concat(taicpu.op_reg_reg(A_MULU,S_L,left.location.register64.reglo,hreg2)); 648 end; 649 if lo(right.location.value64)<>0 then 650 begin 651 hreg1:=cg.getintregister(list,OS_INT); 652 tmpreg:=cg.getintregister(list,OS_INT); 653 cg.a_load_const_reg(list,OS_INT,longint(lo(right.location.value64)),hreg1); 654 cg.a_load_reg_reg(list,OS_INT,OS_INT,hreg1,tmpreg); 655 list.concat(taicpu.op_reg_reg(A_MULU,S_L,left.location.register64.reghi,hreg1)); 656 end; 657 end 658 else 659 begin 660 //list.concat(tai_comment.create(strpnew('second_mul64bit: no const'))); 661 hlcg.location_force_reg(list,right.location,right.resultdef,right.resultdef,true); 662 tmpreg:=right.location.register64.reglo; 663 hreg1:=cg.getintregister(list,OS_INT); 664 hreg2:=cg.getintregister(list,OS_INT); 665 cg.a_load_reg_reg(list,OS_INT,OS_INT,right.location.register64.reglo,hreg1); 666 cg.a_load_reg_reg(list,OS_INT,OS_INT,right.location.register64.reghi,hreg2); 667 list.concat(taicpu.op_reg_reg(A_MULU,S_L,left.location.register64.reghi,hreg1)); 668 list.concat(taicpu.op_reg_reg(A_MULU,S_L,left.location.register64.reglo,hreg2)); 669 end; 670 671 { At this point, tmpreg is either lo(right) or NR_NO if lo(left)*lo(right) is zero } 672 if (tmpreg=NR_NO) then 673 begin 674 if (hreg2<>NR_NO) then 675 begin 676 location.register64.reghi:=hreg2; 677 if (hreg1<>NR_NO) then 678 list.concat(taicpu.op_reg_reg(A_ADD,S_L,hreg1,location.register64.reghi)); 679 end 680 else if (hreg1<>NR_NO) then 681 location.register64.reghi:=hreg1 682 else 683 internalerror(2017052501); 684 location.register64.reglo:=cg.getintregister(list,OS_INT); 685 cg.a_load_const_reg(list,OS_INT,0,location.register64.reglo); 686 end 687 else 688 begin 689 location.register64.reghi:=cg.getintregister(list,OS_INT); 690 location.register64.reglo:=cg.getintregister(list,OS_INT); 691 cg.a_load_reg_reg(list,OS_INT,OS_INT,left.location.register64.reglo,location.register64.reglo); 692 list.concat(taicpu.op_reg_reg_reg(A_MULU,S_L,tmpreg,location.register64.reghi,location.register64.reglo)); 693 if (hreg2<>NR_NO) then 694 list.concat(taicpu.op_reg_reg(A_ADD,S_L,hreg2,location.register64.reghi)); 695 if (hreg1<>NR_NO) then 696 list.concat(taicpu.op_reg_reg(A_ADD,S_L,hreg1,location.register64.reghi)); 697 end; 698 end; 699 700 procedure t68kaddnode.second_cmp64bit; 701 var 702 truelabel, 703 falselabel: tasmlabel; 704 hlab: tasmlabel; 705 unsigned : boolean; 706 href: treference; 707 708 procedure firstjmp64bitcmp; 709 var 710 oldnodetype : tnodetype; 711 begin 712 case nodetype of 713 ltn,gtn: 714 begin 715 if (hlab<>location.truelabel) then 716 cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.truelabel); 717 { cheat a little bit for the negative test } 718 toggleflag(nf_swapped); 719 if (hlab<>location.falselabel) then 720 cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.falselabel); 721 toggleflag(nf_swapped); 722 end; 723 lten,gten: 724 begin 725 oldnodetype:=nodetype; 726 if nodetype=lten then 727 nodetype:=ltn 728 else 729 nodetype:=gtn; 730 if (hlab<>location.truelabel) then 731 cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.truelabel); 732 { cheat for the negative test } 733 if nodetype=ltn then 734 nodetype:=gtn 735 else 736 nodetype:=ltn; 737 if (hlab<>location.falselabel) then 738 cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.falselabel); 739 nodetype:=oldnodetype; 740 end; 741 equaln: 742 cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.falselabel); 743 unequaln: 744 cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.truelabel); 745 end; 746 end; 747 748 procedure secondjmp64bitcmp; 749 begin 750 case nodetype of 751 ltn,gtn,lten,gten: 752 begin 753 cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),location.truelabel); 754 cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel); 755 end; 756 equaln: 757 begin 758 cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.falselabel); 759 cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel); 760 end; 761 unequaln: 762 begin 763 cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.truelabel); 764 cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel); 765 end; 766 end; 767 end; 768 769 begin 770 truelabel:=nil; 771 falselabel:=nil; 772 { This puts constant operand (if any) to the right } 773 pass_left_right; 774 775 unsigned:=not(is_signed(left.resultdef)) or 776 not(is_signed(right.resultdef)); 777 778 current_asmdata.getjumplabel(truelabel); 779 current_asmdata.getjumplabel(falselabel); 780 location_reset_jump(location,truelabel,falselabel); 781 782 { Relational compares against constants having low dword=0 can omit the 783 second compare based on the fact that any unsigned value is >=0 } 784 hlab:=nil; 785 if (right.location.loc=LOC_CONSTANT) and 786 (lo(right.location.value64)=0) then 787 begin 788 case getresflags(true) of 789 F_AE: hlab:=location.truelabel; 790 F_B: hlab:=location.falselabel; 791 end; 792 end; 793 794 if (right.location.loc=LOC_CONSTANT) and (right.location.value64=0) and 795 (nodetype in [equaln,unequaln]) then 796 begin 797 if (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and not needs_unaligned(left.location.reference.alignment,OS_INT) then 798 begin 799 href:=left.location.reference; 800 tcg68k(cg).fixref(current_asmdata.CurrAsmList,href,false); 801 current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_TST,S_L,href)); 802 firstjmp64bitcmp; 803 inc(href.offset,4); 804 current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_TST,S_L,href)); 805 secondjmp64bitcmp; 806 location_freetemp(current_asmdata.CurrAsmList,left.location); 807 end 808 else 809 begin 810 hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); 811 current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_TST,S_L,left.location.register64.reglo)); 812 firstjmp64bitcmp; 813 current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_TST,S_L,left.location.register64.reghi)); 814 secondjmp64bitcmp; 815 end; 816 exit; 817 end; 818 819 { left and right no register? } 820 { then one must be demanded } 821 if not (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then 822 begin 823 if not (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then 824 hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true) 825 else 826 begin 827 location_swap(left.location,right.location); 828 toggleflag(nf_swapped); 829 end; 830 end; 831 832 if (right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and needs_unaligned(right.location.reference.alignment,OS_INT) then 833 hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); 834 835 { left is now in register } 836 case right.location.loc of 837 LOC_REGISTER,LOC_CREGISTER: 838 begin 839 current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,S_L,right.location.register64.reghi,left.location.register64.reghi)); 840 firstjmp64bitcmp; 841 current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,S_L,right.location.register64.reglo,left.location.register64.reglo)); 842 secondjmp64bitcmp; 843 end; 844 LOC_REFERENCE,LOC_CREFERENCE: 845 begin 846 href:=right.location.reference; 847 tcg68k(cg).fixref(current_asmdata.CurrAsmList,href,false); 848 current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_CMP,S_L,href,left.location.register64.reghi)); 849 firstjmp64bitcmp; 850 inc(href.offset,4); 851 current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_CMP,S_L,href,left.location.register64.reglo)); 852 secondjmp64bitcmp; 853 location_freetemp(current_asmdata.CurrAsmList,right.location); 854 end; 855 LOC_CONSTANT: 856 begin 857 current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_L,aint(hi(right.location.value64)),left.location.register64.reghi)); 858 firstjmp64bitcmp; 859 if assigned(hlab) then 860 cg.a_jmp_always(current_asmdata.CurrAsmList,hlab) 861 else 862 begin 863 current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_L,aint(lo(right.location.value64)),left.location.register64.reglo)); 864 secondjmp64bitcmp; 865 end; 866 end; 867 else 868 InternalError(2014072501); 869 end; 870 end; 871 872 873 begin 874 caddnode:=t68kaddnode; 875 end. 876