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