2
$Id: n386add.pas,v 1.96 2004/05/19 23:30:18 peter Exp $
3
Copyright (c) 2000-2002 by Florian Klaempfl
5
Code generation for add nodes on the i386
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
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.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
****************************************************************************
30
node,nadd,cpubase,nx86add;
33
ti386addnode = class(tx86addnode)
35
procedure second_addmmxset;override;
36
procedure second_addmmx;override;
38
procedure second_add64bit;override;
39
procedure second_cmp64bit;override;
40
procedure second_mul;override;
47
cutils,verbose,globals,
49
symconst,symdef,paramgr,
50
aasmbase,aasmtai,aasmcpu,
53
cga,ncgutil,cgobj,cg64f32;
55
{*****************************************************************************
57
*****************************************************************************}
60
procedure ti386addnode.second_addmmxset;
68
pass_left_and_right(pushedfpu);
76
{ are we adding set elements ? }
77
if right.nodetype=setelementn then
79
{ adding elements is not commutative }
80
{ if nf_swaped in flags then
82
{ bts requires both elements to be registers }
83
{ location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
84
location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],true);
105
if (not(nf_swaped in flags) and (nodetype = lten)) or
106
((nf_swaped in flags) and (nodetype = gten)) then
108
location_force_reg(exprasmlist,left.location,opsize,true);
109
emit_op_right_left(A_AND,TCGSize2Opsize[opsize]);
112
{ warning: ugly hack, we need a JE so change the node to equaln }
122
internalerror(2003042215);
124
{ left must be a register }
125
left_must_be_reg(opsize,noswap);
126
{ emit_generic_code(op,opsize,true,extra_not,false);}
127
location_freetemp(exprasmlist,right.location);
128
location_release(exprasmlist,right.location);
131
location_freetemp(exprasmlist,left.location);
132
location_release(exprasmlist,left.location);
134
set_result_location(cmpop,true);
139
{*****************************************************************************
141
*****************************************************************************}
143
procedure ti386addnode.second_add64bit;
149
hregister2 : tregister;
162
unsigned:=((left.resulttype.def.deftype=orddef) and
163
(torddef(left.resulttype.def).typ=u64bit)) or
164
((right.resulttype.def.deftype=orddef) and
165
(torddef(right.resulttype.def).typ=u64bit));
187
{ everything should be handled in pass_1 (JM) }
188
internalerror(200109051);
192
{ left and right no register? }
193
{ then one must be demanded }
194
if (left.location.loc<>LOC_REGISTER) then
196
if (right.location.loc<>LOC_REGISTER) then
198
hregister:=cg.getintregister(exprasmlist,OS_INT);
199
hregister2:=cg.getintregister(exprasmlist,OS_INT);
200
cg64.a_load64_loc_reg(exprasmlist,left.location,joinreg64(hregister,hregister2));
201
location_reset(left.location,LOC_REGISTER,OS_64);
202
left.location.registerlow:=hregister;
203
left.location.registerhigh:=hregister2;
207
location_swap(left.location,right.location);
208
toggleflag(nf_swaped);
212
{ at this point, left.location.loc should be LOC_REGISTER }
213
if right.location.loc=LOC_REGISTER then
215
{ when swapped another result register }
216
if (nodetype=subn) and (nf_swaped in flags) then
218
cg64.a_op64_reg_reg(exprasmlist,op,
219
left.location.register64,
220
right.location.register64);
221
location_swap(left.location,right.location);
222
toggleflag(nf_swaped);
226
cg64.a_op64_reg_reg(exprasmlist,op,
227
right.location.register64,
228
left.location.register64);
230
location_release(exprasmlist,right.location);
234
{ right.location<>LOC_REGISTER }
235
if (nodetype=subn) and (nf_swaped in flags) then
237
r:=cg.getintregister(exprasmlist,OS_INT);
238
cg64.a_load64low_loc_reg(exprasmlist,right.location,r);
239
emit_reg_reg(op1,opsize,left.location.registerlow,r);
240
emit_reg_reg(A_MOV,opsize,r,left.location.registerlow);
241
cg64.a_load64high_loc_reg(exprasmlist,right.location,r);
242
{ the carry flag is still ok }
243
emit_reg_reg(op2,opsize,left.location.registerhigh,r);
244
emit_reg_reg(A_MOV,opsize,r,left.location.registerhigh);
245
cg.ungetregister(exprasmlist,r);
246
if right.location.loc<>LOC_CREGISTER then
248
location_freetemp(exprasmlist,right.location);
249
location_release(exprasmlist,right.location);
254
cg64.a_op64_loc_reg(exprasmlist,op,right.location,
255
left.location.register64);
256
if (right.location.loc<>LOC_CREGISTER) then
258
location_freetemp(exprasmlist,right.location);
259
location_release(exprasmlist,right.location);
264
{ only in case of overflow operations }
265
{ produce overflow code }
266
{ we must put it here directly, because sign of operation }
267
{ is in unsigned VAR!! }
270
if cs_check_overflow in aktlocalswitches then
272
objectlibrary.getlabel(hl4);
274
cg.a_jmp_flags(exprasmlist,F_AE,hl4)
276
cg.a_jmp_flags(exprasmlist,F_NO,hl4);
277
cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
278
cg.a_label(exprasmlist,hl4);
282
location_copy(location,left.location);
286
procedure ti386addnode.second_cmp64bit;
289
hregister2 : tregister;
293
procedure firstjmp64bitcmp;
296
oldnodetype : tnodetype;
300
load_all_regvars(exprasmlist);
302
{ the jump the sequence is a little bit hairy }
306
cg.a_jmp_flags(exprasmlist,getresflags(unsigned),truelabel);
307
{ cheat a little bit for the negative test }
308
toggleflag(nf_swaped);
309
cg.a_jmp_flags(exprasmlist,getresflags(unsigned),falselabel);
310
toggleflag(nf_swaped);
314
oldnodetype:=nodetype;
315
if nodetype=lten then
319
cg.a_jmp_flags(exprasmlist,getresflags(unsigned),truelabel);
320
{ cheat for the negative test }
325
cg.a_jmp_flags(exprasmlist,getresflags(unsigned),falselabel);
326
nodetype:=oldnodetype;
329
cg.a_jmp_flags(exprasmlist,F_NE,falselabel);
331
cg.a_jmp_flags(exprasmlist,F_NE,truelabel);
335
procedure secondjmp64bitcmp;
338
{ the jump the sequence is a little bit hairy }
342
{ the comparisaion of the low dword have to be }
344
cg.a_jmp_flags(exprasmlist,getresflags(true),truelabel);
345
cg.a_jmp_always(exprasmlist,falselabel);
349
cg.a_jmp_flags(exprasmlist,F_NE,falselabel);
350
cg.a_jmp_always(exprasmlist,truelabel);
354
cg.a_jmp_flags(exprasmlist,F_NE,truelabel);
355
cg.a_jmp_always(exprasmlist,falselabel);
365
unsigned:=((left.resulttype.def.deftype=orddef) and
366
(torddef(left.resulttype.def).typ=u64bit)) or
367
((right.resulttype.def.deftype=orddef) and
368
(torddef(right.resulttype.def).typ=u64bit));
370
{ left and right no register? }
371
{ then one must be demanded }
372
if (left.location.loc<>LOC_REGISTER) then
374
if (right.location.loc<>LOC_REGISTER) then
376
{ we can reuse a CREGISTER for comparison }
377
if (left.location.loc<>LOC_CREGISTER) then
379
hregister:=cg.getintregister(exprasmlist,OS_INT);
380
hregister2:=cg.getintregister(exprasmlist,OS_INT);
381
cg64.a_load64_loc_reg(exprasmlist,left.location,joinreg64(hregister,hregister2));
382
location_reset(left.location,LOC_REGISTER,OS_64);
383
left.location.registerlow:=hregister;
384
left.location.registerhigh:=hregister2;
389
location_swap(left.location,right.location);
390
toggleflag(nf_swaped);
394
{ at this point, left.location.loc should be LOC_REGISTER }
395
if right.location.loc=LOC_REGISTER then
397
emit_reg_reg(A_CMP,S_L,right.location.registerhigh,left.location.registerhigh);
399
emit_reg_reg(A_CMP,S_L,right.location.registerlow,left.location.registerlow);
401
location_release(exprasmlist,right.location);
405
case right.location.loc of
408
emit_reg_reg(A_CMP,S_L,right.location.registerhigh,left.location.registerhigh);
410
emit_reg_reg(A_CMP,S_L,right.location.registerlow,left.location.registerlow);
416
href:=right.location.reference;
418
emit_ref_reg(A_CMP,S_L,href,left.location.registerhigh);
420
emit_ref_reg(A_CMP,S_L,right.location.reference,left.location.registerlow);
422
cg.a_jmp_always(exprasmlist,falselabel);
423
location_freetemp(exprasmlist,right.location);
424
location_release(exprasmlist,right.location);
428
exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,aword(hi(right.location.valueqword)),left.location.registerhigh));
430
exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,aword(lo(right.location.valueqword)),left.location.registerlow));
434
internalerror(200203282);
438
if (left.location.loc<>LOC_CREGISTER) then
440
location_freetemp(exprasmlist,left.location);
441
location_release(exprasmlist,left.location);
444
{ we have LOC_JUMP as result }
445
location_reset(location,LOC_JUMP,OS_NO)
449
{*****************************************************************************
451
*****************************************************************************}
454
procedure ti386addnode.second_addmmx;
461
hregister : tregister;
463
pass_left_and_right(pushedfpu);
466
mmxbase:=mmx_type(left.resulttype.def);
470
if (cs_mmx_saturation in aktlocalswitches) then
477
mmxs16bit,mmxfixed16:
488
mmxs16bit,mmxu16bit,mmxfixed16:
506
if (cs_mmx_saturation in aktlocalswitches) then
513
mmxs16bit,mmxfixed16:
524
mmxs16bit,mmxu16bit,mmxfixed16:
538
internalerror(2003042214);
541
{ left and right no register? }
542
{ then one must be demanded }
543
if (left.location.loc<>LOC_MMXREGISTER) then
545
if (right.location.loc=LOC_MMXREGISTER) then
547
location_swap(left.location,right.location);
548
toggleflag(nf_swaped);
552
{ register variable ? }
553
if (left.location.loc=LOC_CMMXREGISTER) then
555
hregister:=cg.getmmxregister(exprasmlist,OS_M64);
556
emit_reg_reg(A_MOVQ,S_NO,left.location.register,hregister);
560
if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
561
internalerror(200203245);
563
location_release(exprasmlist,left.location);
565
hregister:=cg.getmmxregister(exprasmlist,OS_M64);
566
emit_ref_reg(A_MOVQ,S_NO,left.location.reference,hregister);
569
location_reset(left.location,LOC_MMXREGISTER,OS_NO);
570
left.location.register:=hregister;
574
{ at this point, left.location.loc should be LOC_MMXREGISTER }
575
if right.location.loc<>LOC_MMXREGISTER then
577
if (nodetype=subn) and (nf_swaped in flags) then
579
if right.location.loc=LOC_CMMXREGISTER then
581
hreg:=cg.getmmxregister(exprasmlist,OS_M64);
582
emit_reg_reg(A_MOVQ,S_NO,right.location.register,hreg);
583
emit_reg_reg(op,S_NO,left.location.register,hreg);
584
cg.ungetregister(exprasmlist,hreg);
585
emit_reg_reg(A_MOVQ,S_NO,hreg,left.location.register);
589
if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
590
internalerror(200203247);
591
location_release(exprasmlist,right.location);
592
hreg:=cg.getmmxregister(exprasmlist,OS_M64);
593
emit_ref_reg(A_MOVQ,S_NO,right.location.reference,hreg);
594
emit_reg_reg(op,S_NO,left.location.register,hreg);
595
cg.ungetregister(exprasmlist,hreg);
596
emit_reg_reg(A_MOVQ,S_NO,hreg,left.location.register);
601
if (right.location.loc=LOC_CMMXREGISTER) then
602
emit_reg_reg(op,S_NO,right.location.register,left.location.register)
605
if not(right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
606
internalerror(200203246);
607
emit_ref_reg(op,S_NO,right.location.reference,left.location.register);
608
location_release(exprasmlist,right.location);
614
{ right.location=LOC_MMXREGISTER }
615
if (nodetype=subn) and (nf_swaped in flags) then
617
emit_reg_reg(op,S_NO,left.location.register,right.location.register);
618
location_swap(left.location,right.location);
619
toggleflag(nf_swaped);
623
emit_reg_reg(op,S_NO,right.location.register,left.location.register);
627
location_freetemp(exprasmlist,right.location);
628
location_release(exprasmlist,right.location);
631
location_freetemp(exprasmlist,left.location);
632
location_release(exprasmlist,left.location);
634
set_result_location(cmpop,true);
639
{*****************************************************************************
641
*****************************************************************************}
643
procedure ti386addnode.second_mul;
649
{The location.register will be filled in later (JM)}
650
location_reset(location,LOC_REGISTER,OS_INT);
651
{Get a temp register and load the left value into it
652
and free the location.}
653
r:=cg.getintregister(exprasmlist,OS_INT);
654
cg.a_load_loc_reg(exprasmlist,OS_INT,left.location,r);
655
location_release(exprasmlist,left.location);
657
cg.getexplicitregister(exprasmlist,NR_EAX);
658
{Load the right value.}
659
cg.a_load_loc_reg(exprasmlist,OS_INT,right.location,NR_EAX);
660
location_release(exprasmlist,right.location);
661
{The mul instruction frees register r.}
662
cg.ungetregister(exprasmlist,r);
663
{Also allocate EDX, since it is also modified by a mul (JM).}
664
cg.getexplicitregister(exprasmlist,NR_EDX);
665
emit_reg(A_MUL,S_L,r);
666
if cs_check_overflow in aktlocalswitches then
668
objectlibrary.getlabel(hl4);
669
cg.a_jmp_flags(exprasmlist,F_AE,hl4);
670
cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
671
cg.a_label(exprasmlist,hl4);
674
cg.ungetregister(exprasmlist,NR_EDX);
676
cg.ungetregister(exprasmlist,NR_EAX);
677
{Allocate a new register and store the result in EAX in it.}
678
location.register:=cg.getintregister(exprasmlist,OS_INT);
679
emit_reg_reg(A_MOV,S_L,NR_EAX,location.register);
680
location_freetemp(exprasmlist,left.location);
681
location_freetemp(exprasmlist,right.location);
686
caddnode:=ti386addnode;
689
$Log: n386add.pas,v $
690
Revision 1.96 2004/05/19 23:30:18 peter
691
* extra typecast to prevent range check
693
Revision 1.95 2004/02/04 19:22:27 peter
694
*** empty log message ***
696
Revision 1.94 2004/01/20 12:59:37 florian
697
* common addnode code for x86-64 and i386
699
Revision 1.93 2004/01/14 17:19:04 peter