2
Copyright (c) 2000-2002 by the FPC development team
4
Code generation for add nodes (generic version)
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.
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.
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.
20
****************************************************************************
32
tcgaddnode = class(taddnode)
33
{ function pass_1: tnode; override;}
34
procedure pass_generate_code;override;
36
{ call secondpass for both left and right }
37
procedure pass_left_right;
38
{ set the register of the result location }
39
procedure set_result_location_reg;
40
{ load left and right nodes into registers }
41
procedure force_reg_left_right(allow_swap,allow_constant:boolean);
43
procedure second_opfloat;
44
procedure second_opboolean;
45
procedure second_opsmallset;
46
procedure second_op64bit;
47
procedure second_opordinal;
49
procedure second_addstring;virtual;
50
procedure second_addfloat;virtual;abstract;
51
procedure second_addboolean;virtual;
52
procedure second_addsmallset;virtual;
55
procedure second_opmmxset;virtual;abstract;
56
procedure second_opmmx;virtual;abstract;
59
procedure second_opvector;virtual;abstract;
60
procedure second_add64bit;virtual;
61
procedure second_addordinal;virtual;
62
procedure second_cmpfloat;virtual;abstract;
63
procedure second_cmpboolean;virtual;
64
procedure second_cmpsmallset;virtual;abstract;
65
procedure second_cmp64bit;virtual;abstract;
66
procedure second_cmpordinal;virtual;abstract;
73
cutils,verbose,globals,
74
symconst,symdef,paramgr,
75
aasmbase,aasmtai,aasmdata,defutil,
76
cgbase,procinfo,pass_2,
77
ncon,nset,ncgutil,cgobj,cgutils
81
{*****************************************************************************
83
*****************************************************************************}
85
procedure tcgaddnode.pass_left_right;
92
{ calculate the operator which is more difficult }
95
{ in case of constant put it to the left }
96
if (left.nodetype=ordconstn) then
99
isjump:=(left.expectloc=LOC_JUMP);
102
otl:=current_procinfo.CurrTrueLabel;
103
current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
104
ofl:=current_procinfo.CurrFalseLabel;
105
current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
108
if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
109
location_force_reg(current_asmdata.CurrAsmList,left.location,def_cgsize(resultdef),false);
112
current_procinfo.CurrTrueLabel:=otl;
113
current_procinfo.CurrFalseLabel:=ofl;
116
{ are too few registers free? }
117
if left.location.loc=LOC_FPUREGISTER then
118
pushedfpu:=maybe_pushfpu(current_asmdata.CurrAsmList,right.registersfpu,left.location)
121
isjump:=(right.expectloc=LOC_JUMP);
124
otl:=current_procinfo.CurrTrueLabel;
125
current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
126
ofl:=current_procinfo.CurrFalseLabel;
127
current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
130
if right.location.loc in [LOC_FLAGS,LOC_JUMP] then
131
location_force_reg(current_asmdata.CurrAsmList,right.location,def_cgsize(resultdef),false);
134
current_procinfo.CurrTrueLabel:=otl;
135
current_procinfo.CurrFalseLabel:=ofl;
139
tmpreg := cg.getfpuregister(current_asmdata.CurrAsmList,left.location.size);
140
cg.a_loadfpu_loc_reg(current_asmdata.CurrAsmList,left.location.size,left.location,tmpreg);
141
location_reset(left.location,LOC_FPUREGISTER,left.location.size);
142
left.location.register := tmpreg;
144
{ left operand is now on top of the stack, instead of the right one! }
145
toggleflag(nf_swapped);
151
procedure tcgaddnode.set_result_location_reg;
153
location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
155
if left.location.loc=LOC_REGISTER then
157
if TCGSize2Size[left.location.size]<>TCGSize2Size[location.size] then
158
internalerror(200307041);
160
if location.size in [OS_64,OS_S64] then
162
location.register64.reglo := left.location.register64.reglo;
163
location.register64.reghi := left.location.register64.reghi;
167
location.register := left.location.register;
170
if right.location.loc=LOC_REGISTER then
172
if TCGSize2Size[right.location.size]<>TCGSize2Size[location.size] then
173
internalerror(200307042);
175
if location.size in [OS_64,OS_S64] then
177
location.register64.reglo := right.location.register64.reglo;
178
location.register64.reghi := right.location.register64.reghi;
182
location.register := right.location.register;
188
if location.size in [OS_64,OS_S64] then
190
location.register64.reglo := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
191
location.register64.reghi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
195
location.register := cg.getintregister(current_asmdata.CurrAsmList,location.size);
200
procedure tcgaddnode.force_reg_left_right(allow_swap,allow_constant:boolean);
202
if (left.location.loc<>LOC_REGISTER) and
205
(left.location.loc in [LOC_CONSTANT,LOC_CREGISTER])
207
location_force_reg(current_asmdata.CurrAsmList,left.location,left.location.size,false);
208
if (right.location.loc<>LOC_REGISTER) and
211
(right.location.loc in [LOC_CONSTANT,LOC_CREGISTER]) and
212
(left.location.loc<>LOC_CONSTANT)
214
location_force_reg(current_asmdata.CurrAsmList,right.location,right.location.size,false);
216
{ Left is always a register, right can be register or constant }
217
if left.location.loc=LOC_CONSTANT then
219
{ when it is not allowed to swap we have a constant on
220
left, that will give problems }
221
if not allow_swap then
222
internalerror(200307043);
228
{*****************************************************************************
230
*****************************************************************************}
232
procedure tcgaddnode.second_opsmallset;
234
{ when a setdef is passed, it has to be a smallset }
235
if is_varset(left.resultdef) or
236
is_normalset(left.resultdef) or
237
is_varset(right.resultdef) or
238
is_normalset(right.resultdef) then
239
internalerror(200203302);
241
if nodetype in [equaln,unequaln,gtn,gten,lten,ltn] then
248
procedure tcgaddnode.second_addsmallset;
257
force_reg_left_right(true,true);
259
{ setelementn is a special case, it must be on right.
260
We need an extra check if left is a register because the
261
default case can skip the register loading when the
262
setelementn is in a register (PFV) }
263
if (nf_swapped in flags) and
264
(left.nodetype=setelementn) then
266
if (right.nodetype=setelementn) and
267
(left.location.loc<>LOC_REGISTER) then
268
location_force_reg(current_asmdata.CurrAsmList,left.location,left.location.size,false);
270
set_result_location_reg;
275
{ are we adding set elements ? }
276
if right.nodetype=setelementn then
278
{ no range support for smallsets! }
279
if assigned(tsetelementnode(right).right) then
280
internalerror(43244);
281
if (right.location.loc = LOC_CONSTANT) then
282
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_OR,location.size,
283
aint(1 shl right.location.value),
284
left.location.register,location.register)
287
tmpreg := cg.getintregister(current_asmdata.CurrAsmList,location.size);
288
cg.a_load_const_reg(current_asmdata.CurrAsmList,location.size,1,tmpreg);
289
cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_SHL,location.size,
290
right.location.register,tmpreg);
291
if left.location.loc <> LOC_CONSTANT then
292
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,location.size,tmpreg,
293
left.location.register,location.register)
295
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_OR,location.size,
296
left.location.value,tmpreg,location.register);
310
if (not(nf_swapped in flags)) then
311
if (right.location.loc=LOC_CONSTANT) then
312
right.location.value := not(right.location.value)
315
else if (left.location.loc=LOC_CONSTANT) then
316
left.location.value := not(left.location.value)
324
if left.location.loc = LOC_CONSTANT then
326
tmpreg := cg.getintregister(current_asmdata.CurrAsmList,location.size);
327
cg.a_load_const_reg(current_asmdata.CurrAsmList,location.size,
328
left.location.value,tmpreg);
329
cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,location.size,right.location.register,right.location.register);
330
cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_AND,location.size,right.location.register,tmpreg);
331
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,location.size,tmpreg,location.register);
335
cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,right.location.size,right.location.register,right.location.register);
336
cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_AND,left.location.size,right.location.register,left.location.register);
337
cg.a_load_reg_reg(current_asmdata.CurrAsmList,left.location.size,location.size,left.location.register,location.register);
342
internalerror(2002072701);
347
// these are all commutative operations
348
if (left.location.loc = LOC_CONSTANT) then
350
if (right.location.loc = LOC_CONSTANT) then
351
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,cgop,location.size,
352
right.location.value,left.location.register,
355
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,cgop,location.size,
356
right.location.register,left.location.register,
362
{*****************************************************************************
364
*****************************************************************************}
366
procedure tcgaddnode.second_opboolean;
368
if nodetype in [ltn,lten,gtn,gten,equaln,unequaln] then
375
procedure tcgaddnode.second_addboolean;
379
oldflowcontrol : tflowcontrol;
381
{ And,Or will only evaluate from left to right only the
382
needed nodes unless full boolean evaluation is enabled }
383
if (nodetype in [orn,andn]) and
384
(not(cs_full_boolean_eval in current_settings.localswitches) or
385
(nf_short_bool in flags)) then
387
location_reset(location,LOC_JUMP,OS_NO);
391
otl:=current_procinfo.CurrTrueLabel;
392
current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
394
maketojumpbool(current_asmdata.CurrAsmList,left,lr_load_regvars);
395
cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
396
current_procinfo.CurrTrueLabel:=otl;
400
ofl:=current_procinfo.CurrFalseLabel;
401
current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
403
maketojumpbool(current_asmdata.CurrAsmList,left,lr_load_regvars);
404
cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
405
current_procinfo.CurrFalseLabel:=ofl;
408
internalerror(200307044);
410
{ these jumps mean we're now in a flow control construct }
411
oldflowcontrol:=flowcontrol;
412
include(flowcontrol,fc_inflowcontrol);
415
maketojumpbool(current_asmdata.CurrAsmList,right,lr_load_regvars);
417
flowcontrol:=oldflowcontrol+(flowcontrol-[fc_inflowcontrol]);
422
force_reg_left_right(false,true);
423
set_result_location_reg;
433
internalerror(200203247);
436
if right.location.loc <> LOC_CONSTANT then
437
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,cgop,location.size,
438
left.location.register,right.location.register,
441
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,cgop,location.size,
442
right.location.value,left.location.register,
448
{*****************************************************************************
450
*****************************************************************************}
452
procedure tcgaddnode.second_op64bit;
454
if nodetype in [ltn,lten,gtn,gten,equaln,unequaln] then
461
procedure tcgaddnode.second_add64bit;
464
checkoverflow : boolean;
470
force_reg_left_right(false,true);
471
set_result_location_reg;
473
{ assume no overflow checking is required }
474
checkoverflow := false;
494
{ should be handled in pass_1 (JM) }
495
internalerror(200109051);
498
internalerror(2002072705);
503
(left.resultdef.typ<>pointerdef) and
504
(right.resultdef.typ<>pointerdef);
510
if (right.location.loc = LOC_CONSTANT) then
511
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,op,location.size,right.location.value,
512
left.location.register,location.register)
514
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,op,location.size,right.location.register,
515
left.location.register,location.register);
519
if (nf_swapped in flags) then
522
if left.location.loc <> LOC_CONSTANT then
524
if right.location.loc <> LOC_CONSTANT then
526
cg.a_op_reg_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
527
right.location.register,left.location.register,location.register,
528
checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc)
531
cg.a_op_const_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
532
right.location.value,left.location.register,location.register,
533
checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc);
538
location_force_reg(current_asmdata.CurrAsmList,left.location,left.location.size,true);
539
cg.a_op_reg_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
540
right.location.register,left.location.register,location.register,
541
checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc);
545
internalerror(2002072803);
551
if (right.location.loc = LOC_CONSTANT) then
552
cg64.a_op64_const_reg_reg_checkoverflow(current_asmdata.CurrAsmList,op,location.size,right.location.value64,
553
left.location.register64,location.register64,
554
checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc)
556
cg64.a_op64_reg_reg_reg_checkoverflow(current_asmdata.CurrAsmList,op,location.size,right.location.register64,
557
left.location.register64,location.register64,
558
checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc);
562
if (nf_swapped in flags) then
565
if left.location.loc <> LOC_CONSTANT then
567
if right.location.loc <> LOC_CONSTANT then
569
cg64.a_op64_reg_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
570
right.location.register64,left.location.register64,
572
checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc)
575
cg64.a_op64_const_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
576
right.location.value64,left.location.register64,
578
checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc)
583
location_force_reg(current_asmdata.CurrAsmList,left.location,left.location.size,true);
584
cg64.a_op64_reg_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
585
right.location.register64,left.location.register64,
587
checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc);
591
internalerror(2002072803);
595
{ emit overflow check if enabled }
596
if checkoverflow then
597
cg.g_overflowcheck_loc(current_asmdata.CurrAsmList,Location,resultdef,ovloc);
601
{*****************************************************************************
603
*****************************************************************************}
605
procedure tcgaddnode.second_addstring;
607
{ this should already be handled in pass1 }
608
internalerror(2002072402);
612
{*****************************************************************************
614
*****************************************************************************}
616
procedure tcgaddnode.second_opfloat;
618
if nodetype in [ltn,lten,gtn,gten,equaln,unequaln] then
625
{*****************************************************************************
627
*****************************************************************************}
629
procedure tcgaddnode.second_opordinal;
631
if (nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) then
638
procedure tcgaddnode.second_addordinal;
641
checkoverflow : boolean;
649
force_reg_left_right(false,true);
650
set_result_location_reg;
652
{ determine if the comparison will be unsigned }
653
unsigned:=not(is_signed(left.resultdef)) or
654
not(is_signed(right.resultdef));
656
{ assume no overflow checking is require }
657
checkoverflow := false;
694
(left.resultdef.typ<>pointerdef) and
695
(right.resultdef.typ<>pointerdef);
697
if nodetype<>subn then
699
if (right.location.loc<>LOC_CONSTANT) then
700
cg.a_op_reg_reg_reg_checkoverflow(current_asmdata.CurrAsmList,cgop,location.size,
701
left.location.register,right.location.register,
702
location.register,checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc)
704
cg.a_op_const_reg_reg_checkoverflow(current_asmdata.CurrAsmList,cgop,location.size,
705
right.location.value,left.location.register,
706
location.register,checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc);
708
else { subtract is a special case since its not commutative }
710
if (nf_swapped in flags) then
712
if left.location.loc<>LOC_CONSTANT then
714
if right.location.loc<>LOC_CONSTANT then
715
cg.a_op_reg_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
716
right.location.register,left.location.register,
717
location.register,checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc)
719
cg.a_op_const_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
720
right.location.value,left.location.register,
721
location.register,checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc);
725
tmpreg:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
726
cg.a_load_const_reg(current_asmdata.CurrAsmList,location.size,
727
left.location.value,tmpreg);
728
cg.a_op_reg_reg_reg_checkoverflow(current_asmdata.CurrAsmList,OP_SUB,location.size,
729
right.location.register,tmpreg,location.register,checkoverflow and (cs_check_overflow in current_settings.localswitches),ovloc);
733
{ emit overflow check if required }
734
if checkoverflow then
735
cg.g_overflowcheck_loc(current_asmdata.CurrAsmList,Location,resultdef,ovloc);
739
procedure tcgaddnode.second_cmpboolean;
745
{*****************************************************************************
747
*****************************************************************************}
749
procedure tcgaddnode.pass_generate_code;
751
case left.resultdef.typ of
754
{ handling boolean expressions }
755
if is_boolean(left.resultdef) and
756
is_boolean(right.resultdef) then
759
else if is_64bit(left.resultdef) then
770
{Normalsets are already handled in pass1 if mmx
772
if is_varset(tsetdef(left.resultdef)) or
773
is_normalset(tsetdef(left.resultdef)) then
777
if cs_mmx in current_settings.localswitches then
782
internalerror(200109041);
789
{ support dynarr=nil }
790
if is_dynamic_array(left.resultdef) then
793
if (cs_support_vectors in current_settings.globalswitches) and
794
is_vector(left.resultdef) then
798
if is_mmx_able_array(left.resultdef) then
802
internalerror(200306016);
812
caddnode:=tcgaddnode;