3
Copyright (c) 2003 by Florian Klaempfl
4
Member of the Free Pascal development team
6
This unit implements the code generator for the ARM
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program; if not, write to the Free Software
20
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
****************************************************************************
31
globtype,symtype,symdef,
33
aasmbase,aasmcpu,aasmtai,aasmdata,
35
cpubase,cpuinfo,node,cg64f32,rgcpu;
40
{ true, if the next arithmetic operation should modify the flags }
42
procedure init_register_allocators;override;
43
procedure done_register_allocators;override;
45
procedure a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
46
procedure a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
47
procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
49
procedure a_call_name(list : TAsmList;const s : string);override;
50
procedure a_call_reg(list : TAsmList;reg: tregister);override;
51
procedure a_call_ref(list : TAsmList;ref: treference);override;
53
procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
54
procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
56
procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
57
size: tcgsize; a: aint; src, dst: tregister); override;
58
procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
59
size: tcgsize; src1, src2, dst: tregister); override;
60
procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
61
procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
64
procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
65
procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
66
procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
67
procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
68
function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
69
function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
71
{ fpu move instructions }
72
procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
73
procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
74
procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
76
procedure a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
77
{ comparison operations }
78
procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
79
l : tasmlabel);override;
80
procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
82
procedure a_jmp_name(list : TAsmList;const s : string); override;
83
procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
84
procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
86
procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
88
procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
89
procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
91
procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
93
procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
94
procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);override;
95
procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
96
procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
98
procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
99
procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
101
procedure g_save_standard_registers(list : TAsmList);override;
102
procedure g_restore_standard_registers(list : TAsmList);override;
104
procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
105
procedure fixref(list : TAsmList;var ref : treference);
106
function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
108
procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
111
tcg64farm = class(tcg64f32)
112
procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
113
procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
114
procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
115
procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
116
procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
117
procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
121
OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
122
C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
124
winstackpagesize = 4096;
126
function get_fpu_postfix(def : tdef) : toppostfix;
132
globals,verbose,systems,cutils,
140
function get_fpu_postfix(def : tdef) : toppostfix;
142
if def.typ=floatdef then
144
case tfloatdef(def).floattype of
152
internalerror(200401272);
156
internalerror(200401271);
160
procedure tcgarm.init_register_allocators;
162
inherited init_register_allocators;
163
{ currently, we save R14 always, so we can use it }
164
rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
165
[RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
166
RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
167
rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
168
[RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
169
rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
170
[RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
174
procedure tcgarm.done_register_allocators;
176
rg[R_INTREGISTER].free;
177
rg[R_FPUREGISTER].free;
178
rg[R_MMREGISTER].free;
179
inherited done_register_allocators;
183
procedure tcgarm.a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
187
paraloc.check_simple_location;
188
case paraloc.location^.loc of
189
LOC_REGISTER,LOC_CREGISTER:
190
a_load_const_reg(list,size,a,paraloc.location^.register);
193
reference_reset(ref);
194
ref.base:=paraloc.location^.reference.index;
195
ref.offset:=paraloc.location^.reference.offset;
196
a_load_const_ref(list,size,a,ref);
199
internalerror(2002081101);
204
procedure tcgarm.a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
206
tmpref, ref: treference;
207
location: pcgparalocation;
210
location := paraloc.location;
212
sizeleft := paraloc.intsize;
213
while assigned(location) do
215
case location^.loc of
216
LOC_REGISTER,LOC_CREGISTER:
217
a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
220
reference_reset_base(ref,location^.reference.index,location^.reference.offset);
221
{ doubles in softemu mode have a strange order of registers and references }
222
if location^.size=OS_32 then
223
g_concatcopy(list,tmpref,ref,4)
226
g_concatcopy(list,tmpref,ref,sizeleft);
227
if assigned(location^.next) then
228
internalerror(2005010710);
231
LOC_FPUREGISTER,LOC_CFPUREGISTER:
232
case location^.size of
234
a_loadfpu_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
236
internalerror(2002072801);
243
internalerror(2002081103);
245
inc(tmpref.offset,tcgsize2size[location^.size]);
246
dec(sizeleft,tcgsize2size[location^.size]);
247
location := location^.next;
252
procedure tcgarm.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);
257
paraloc.check_simple_location;
258
case paraloc.location^.loc of
259
LOC_REGISTER,LOC_CREGISTER:
260
a_loadaddr_ref_reg(list,r,paraloc.location^.register);
263
reference_reset(ref);
264
ref.base := paraloc.location^.reference.index;
265
ref.offset := paraloc.location^.reference.offset;
266
tmpreg := getintregister(list,OS_ADDR);
267
a_loadaddr_ref_reg(list,r,tmpreg);
268
a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
271
internalerror(2002080701);
276
procedure tcgarm.a_call_name(list : TAsmList;const s : string);
278
list.concat(taicpu.op_sym(A_BL,current_asmdata.RefAsmSymbol(s)));
280
the compiler does not properly set this flag anymore in pass 1, and
281
for now we only need it after pass 2 (I hope) (JM)
282
if not(pi_do_call in current_procinfo.flags) then
283
internalerror(2003060703);
285
include(current_procinfo.flags,pi_do_call);
289
procedure tcgarm.a_call_reg(list : TAsmList;reg: tregister);
291
list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
292
list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
294
the compiler does not properly set this flag anymore in pass 1, and
295
for now we only need it after pass 2 (I hope) (JM)
296
if not(pi_do_call in current_procinfo.flags) then
297
internalerror(2003060703);
299
include(current_procinfo.flags,pi_do_call);
303
procedure tcgarm.a_call_ref(list : TAsmList;ref: treference);
305
a_reg_alloc(list,NR_R12);
306
a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12);
307
list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
308
list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
309
a_reg_dealloc(list,NR_R12);
310
include(current_procinfo.flags,pi_do_call);
314
procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
316
a_op_const_reg_reg(list,op,size,a,reg,reg);
320
procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
324
list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
327
list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
330
a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
332
a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
336
a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
342
op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
343
(A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
344
A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
347
procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
348
size: tcgsize; a: aint; src, dst: tregister);
352
a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
356
procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
357
size: tcgsize; src1, src2, dst: tregister);
361
a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
365
procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
373
if is_shifter_const(-a,shift) then
387
if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
391
internalerror(200308281);
395
internalerror(200308294);
399
so.shiftmode:=SM_LSL;
401
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
404
list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
409
internalerror(200308292);
413
so.shiftmode:=SM_LSR;
415
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
418
list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
423
internalerror(200308295);
427
so.shiftmode:=SM_ASR;
429
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
432
list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
435
list.concat(setoppostfix(
436
taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
438
if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
440
ovloc.loc:=LOC_FLAGS;
443
ovloc.resflags:=F_CS;
445
ovloc.resflags:=F_CC;
451
{ there could be added some more sophisticated optimizations }
452
if (op in [OP_MUL,OP_IMUL]) and (a=1) then
453
a_load_reg_reg(list,size,size,src,dst)
454
else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
455
a_load_const_reg(list,size,0,dst)
456
else if (op in [OP_IMUL]) and (a=-1) then
457
a_op_reg_reg(list,OP_NEG,size,src,dst)
458
{ we do this here instead in the peephole optimizer because
459
it saves us a register }
460
else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
461
a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
462
{ for example : b=a*5 -> b=a*4+a with add instruction and shl }
463
else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
465
if l1>32 then{roozbeh does this ever happen?}
466
internalerror(200308296);
468
so.shiftmode:=SM_LSL;
470
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
474
tmpreg:=getintregister(list,size);
475
a_load_const_reg(list,size,a,tmpreg);
476
a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
482
procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
485
tmpreg,overflowreg : tregister;
492
internalerror(200308281);
497
so.shiftmode:=SM_LSL;
498
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
504
so.shiftmode:=SM_LSR;
505
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
511
so.shiftmode:=SM_ASR;
512
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
517
if cgsetflags or setflags then
519
overflowreg:=getintregister(list,size);
524
{ the arm doesn't allow that rd and rm are the same }
528
list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
531
tmpreg:=getintregister(list,size);
532
a_load_reg_reg(list,size,size,src2,dst);
533
list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
537
list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
541
so.shiftmode:=SM_ASR;
543
list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
546
list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
548
ovloc.loc:=LOC_FLAGS;
549
ovloc.resflags:=F_NE;
553
{ the arm doesn't allow that rd and rm are the same }
557
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
560
tmpreg:=getintregister(list,size);
561
a_load_reg_reg(list,size,size,src2,dst);
562
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
566
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
570
list.concat(setoppostfix(
571
taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
577
procedure tcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
583
if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
584
internalerror(2002090902);
585
if is_shifter_const(a,imm_shift) then
586
list.concat(taicpu.op_reg_const(A_MOV,reg,a))
587
else if is_shifter_const(not(a),imm_shift) then
588
list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
589
{ loading of constants with mov and orr }
590
{else [if (is_shifter_const(a-byte(a),imm_shift)) then
592
}{ roozbeh:why using tmpreg later causes error in compiling of system.pp,and also those other similars}
593
{list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
594
list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
596
else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
598
list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
599
list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
601
else if (is_shifter_const(a-(longint(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((longint(a) shl 8) shr 8,imm_shift)) then
603
list.concat(taicpu.op_reg_const(A_MOV,reg,a-(longint(a) shl 8)shr 8));
604
list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(longint(a) shl 8)shr 8));
610
current_asmdata.getjumplabel(l);
611
cg.a_label(current_procinfo.aktlocaldata,l);
612
hr.symboldata:=current_procinfo.aktlocaldata.last;
613
current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
616
list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
621
function tcgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
629
{ Be sure to have a base register }
630
if (ref.base=NR_NO) then
632
if ref.shiftmode<>SM_None then
633
internalerror(200308294);
638
{ absolute symbols can't be handled directly, we've to store the symbol reference
639
in the text segment and access it pc relative
641
For now, we assume that references where base or index equals to PC are already
642
relative, all other references are assumed to be absolute and thus they need
645
A proper solution would be to change refoptions to a set and store the information
646
if the symbol is absolute or relative there.
649
if (assigned(ref.symbol) and
650
not(is_pc(ref.base)) and
651
not(is_pc(ref.index))
653
{ [#xxx] isn't a valid address operand }
654
((ref.base=NR_NO) and (ref.index=NR_NO)) or
655
(ref.offset<-4095) or
657
((oppostfix in [PF_SB,PF_H,PF_SH]) and
658
((ref.offset<-255) or
662
((op in [A_LDF,A_STF]) and
663
((ref.offset<-1020) or
665
{ the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
670
reference_reset(tmpref);
673
tmpreg:=getintregister(list,OS_INT);
674
if assigned(ref.symbol) then
676
current_asmdata.getjumplabel(l);
677
cg.a_label(current_procinfo.aktlocaldata,l);
678
tmpref.symboldata:=current_procinfo.aktlocaldata.last;
680
current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
682
{ load consts entry }
685
list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
687
{ in case of LDF/STF, we got rid of the NR_R15 }
688
if is_pc(ref.base) then
690
if is_pc(ref.index) then
694
a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
696
if (ref.base<>NR_NO) then
698
if ref.index<>NR_NO then
700
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
708
ref.shiftmode:=SM_None;
717
if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
719
if tmpreg<>NR_NO then
720
a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
723
tmpreg:=getintregister(list,OS_ADDR);
724
a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
730
{ floating point operations have only limited references
731
we expect here, that a base is already set }
732
if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
734
if ref.shiftmode<>SM_none then
735
internalerror(200309121);
736
if tmpreg<>NR_NO then
738
if ref.base=tmpreg then
740
if ref.signindex<0 then
741
list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
743
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
748
if ref.index<>tmpreg then
749
internalerror(200403161);
750
if ref.signindex<0 then
751
list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
753
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
760
tmpreg:=getintregister(list,OS_ADDR);
761
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
766
list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
771
procedure tcgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
773
oppostfix:toppostfix;
774
usedtmpref: treference;
779
{ signed integer registers }
790
InternalError(200308295);
792
if ref.alignment<>0 then
797
shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
798
tmpreg:=getintregister(list,OS_INT);
799
usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,Ref);
800
inc(usedtmpref.offset);
801
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
802
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
806
shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
807
tmpreg:=getintregister(list,OS_INT);
808
usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,Ref);
809
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
810
inc(usedtmpref.offset);
811
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
812
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
813
inc(usedtmpref.offset);
814
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
815
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
816
inc(usedtmpref.offset);
817
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
820
handle_load_store(list,A_STR,oppostfix,reg,ref);
824
handle_load_store(list,A_STR,oppostfix,reg,ref);
828
procedure tcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
830
oppostfix:toppostfix;
831
usedtmpref: treference;
832
tmpreg,tmpreg2,tmpreg3 : tregister;
836
{ signed integer registers }
849
InternalError(200308297);
851
if Ref.alignment<>0 then
856
{ only complicated references need an extra loadaddr }
857
if assigned(ref.symbol) or
858
(ref.index<>NR_NO) or
859
(ref.offset<-4095) or
861
{ sometimes the compiler reused registers }
865
tmpreg3:=getintregister(list,OS_INT);
866
a_loadaddr_ref_reg(list,ref,tmpreg3);
867
reference_reset_base(usedtmpref,tmpreg3,0);
872
shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
873
tmpreg:=getintregister(list,OS_INT);
874
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
875
inc(usedtmpref.offset);
876
tmpreg2:=getintregister(list,OS_INT);
877
if FromSize=OS_16 then
878
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2)
880
a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg2);
881
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
885
tmpreg:=getintregister(list,OS_INT);
886
tmpreg2:=getintregister(list,OS_INT);
888
{ only complicated references need an extra loadaddr }
889
if assigned(ref.symbol) or
890
(ref.index<>NR_NO) or
891
(ref.offset<-4095) or
893
{ sometimes the compiler reused registers }
897
tmpreg3:=getintregister(list,OS_INT);
898
a_loadaddr_ref_reg(list,ref,tmpreg3);
899
reference_reset_base(usedtmpref,tmpreg3,0);
904
shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
905
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
906
inc(usedtmpref.offset);
907
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
908
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg2,reg,tmpreg,so));
909
inc(usedtmpref.offset);
910
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
912
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg,tmpreg2,reg,so));
913
inc(usedtmpref.offset);
914
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2);
916
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
919
handle_load_store(list,A_LDR,oppostfix,reg,ref);
923
handle_load_store(list,A_LDR,oppostfix,reg,ref);
927
function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
929
oppostfix:toppostfix;
932
{ signed integer registers }
943
InternalError(2003082910);
945
result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
949
function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
951
oppostfix:toppostfix;
954
{ signed integer registers }
967
InternalError(200308291);
969
result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
972
procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
977
procedure do_shift(shiftmode : tshiftmode; shiftimm : byte; reg : tregister);
979
so.shiftmode:=shiftmode;
980
so.shiftimm:=shiftimm;
981
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg,so));
984
function do_conv(size : tcgsize) : boolean;
989
list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
992
do_shift(SM_LSL,24,reg1);
993
do_shift(SM_ASR,24,reg2);
997
do_shift(SM_LSL,16,reg1);
999
do_shift(SM_ASR,16,reg2)
1001
do_shift(SM_LSR,16,reg2);
1013
if tcgsize2size[tosize]<>tcgsize2size[fromsize] then
1015
shifterop_reset(so);
1016
if not do_conv(tosize) then
1017
if tosize in [OS_32,OS_S32] then
1020
internalerror(2002090901);
1022
if not conv_done and (reg1<>reg2) then
1024
{ same size, only a register mov required }
1025
instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
1027
{ Notify the register allocator that we have written a move instruction so
1028
it can try to eliminate it. }
1029
add_move_instruction(instr);
1034
procedure tcgarm.a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
1036
href,href2 : treference;
1037
hloc : pcgparalocation;
1040
hloc:=paraloc.location;
1041
while assigned(hloc) do
1044
LOC_FPUREGISTER,LOC_CFPUREGISTER:
1045
a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
1049
a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
1052
cg64.a_param64_ref(list,href,paraloc);
1054
a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
1058
reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
1059
{ concatcopy should choose the best way to copy the data }
1060
g_concatcopy(list,href,href2,tcgsize2size[size]);
1063
internalerror(200408241);
1065
inc(href.offset,tcgsize2size[hloc^.size]);
1071
procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
1073
list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[tosize]));
1077
procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
1079
oppostfix:toppostfix;
1091
InternalError(200309021);
1093
handle_load_store(list,A_LDF,oppostfix,reg,ref);
1097
procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
1099
oppostfix:toppostfix;
1109
InternalError(200309022);
1111
handle_load_store(list,A_STF,oppostfix,reg,ref);
1115
{ comparison operations }
1116
procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
1122
if is_shifter_const(a,b) then
1123
list.concat(taicpu.op_reg_const(A_CMP,reg,a))
1124
{ CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
1125
and CMP reg,$7fffffff regarding the flags according to the ARM manual }
1126
else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
1127
list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
1130
tmpreg:=getintregister(list,size);
1131
a_load_const_reg(list,size,a,tmpreg);
1132
list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
1134
a_jmp_cond(list,cmp_op,l);
1138
procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
1140
list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
1141
a_jmp_cond(list,cmp_op,l);
1145
procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
1149
ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s));
1155
procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
1159
ai:=taicpu.op_sym(A_B,l);
1165
procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
1169
ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
1175
procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
1177
list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
1178
list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
1182
procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
1186
firstfloatreg,lastfloatreg,
1188
regs : tcpuregisterset;
1190
LocalSize:=align(LocalSize,4);
1191
if not(nostackframe) then
1193
firstfloatreg:=RS_NO;
1194
{ save floating point registers? }
1195
for r:=RS_F0 to RS_F7 do
1196
if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
1198
if firstfloatreg=RS_NO then
1202
a_reg_alloc(list,NR_STACK_POINTER_REG);
1203
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
1205
a_reg_alloc(list,NR_FRAME_POINTER_REG);
1206
a_reg_alloc(list,NR_R12);
1208
list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
1210
{ save int registers }
1211
reference_reset(ref);
1212
ref.index:=NR_STACK_POINTER_REG;
1213
ref.addressmode:=AM_PREINDEXED;
1214
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
1215
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
1216
regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
1218
if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
1219
include(regs,RS_R14);
1221
list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
1223
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
1224
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
1226
{ allocate necessary stack size
1227
not necessary according to Yury Sidorov
1229
{ don't use a_op_const_reg_reg here because we don't allow register allocations
1230
in the entry/exit code }
1231
if (target_info.system in [system_arm_wince]) and
1232
(localsize>=winstackpagesize) then
1234
if localsize div winstackpagesize<=5 then
1236
if is_shifter_const(localsize,shift) then
1237
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
1240
a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
1241
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
1244
for i:=1 to localsize div winstackpagesize do
1246
if localsize-i*winstackpagesize<4096 then
1247
reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize))
1250
a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
1251
reference_reset_base(href,NR_STACK_POINTER_REG,0);
1254
{ the data stored doesn't matter }
1255
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
1257
a_reg_dealloc(list,NR_R12);
1258
reference_reset_base(href,NR_STACK_POINTER_REG,0);
1259
{ the data stored doesn't matter }
1260
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
1264
current_asmdata.getjumplabel(again);
1265
list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
1266
a_label(list,again);
1267
{ always shifterop }
1268
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
1269
reference_reset_base(href,NR_STACK_POINTER_REG,0);
1270
{ the data stored doesn't matter }
1271
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
1272
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
1273
a_jmp_cond(list,OC_NE,again);
1274
if is_shifter_const(localsize mod winstackpagesize,shift) then
1275
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
1278
a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
1279
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
1281
a_reg_dealloc(list,NR_R12);
1282
reference_reset_base(href,NR_STACK_POINTER_REG,0);
1283
{ the data stored doesn't matter }
1284
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
1289
if LocalSize<>0 then
1290
if not(is_shifter_const(localsize,shift)) then
1292
if current_procinfo.framepointer=NR_STACK_POINTER_REG then
1293
a_reg_alloc(list,NR_R12);
1294
a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
1295
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
1296
a_reg_dealloc(list,NR_R12);
1300
a_reg_dealloc(list,NR_R12);
1301
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
1304
if firstfloatreg<>RS_NO then
1306
reference_reset(ref);
1307
if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
1309
a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
1310
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
1315
ref.base:=current_procinfo.framepointer;
1316
ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
1318
list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
1319
lastfloatreg-firstfloatreg+1,ref));
1325
procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
1328
firstfloatreg,lastfloatreg,
1331
regs : tcpuregisterset;
1332
LocalSize : longint;
1334
if not(nostackframe) then
1336
{ restore floating point register }
1337
firstfloatreg:=RS_NO;
1338
{ save floating point registers? }
1339
for r:=RS_F0 to RS_F7 do
1340
if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
1342
if firstfloatreg=RS_NO then
1347
if firstfloatreg<>RS_NO then
1349
reference_reset(ref);
1350
if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
1352
a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
1353
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
1358
ref.base:=current_procinfo.framepointer;
1359
ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
1361
list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
1362
lastfloatreg-firstfloatreg+1,ref));
1365
if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
1367
LocalSize:=current_procinfo.calc_stackframe_size;
1368
if LocalSize<>0 then
1369
if not(is_shifter_const(LocalSize,shift)) then
1371
a_reg_alloc(list,NR_R12);
1372
a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
1373
list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
1374
a_reg_dealloc(list,NR_R12);
1378
list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
1381
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
1382
if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
1384
exclude(regs,RS_R14);
1385
include(regs,RS_R15);
1388
list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
1391
reference_reset(ref);
1392
ref.index:=NR_STACK_POINTER_REG;
1393
ref.addressmode:=AM_PREINDEXED;
1394
list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
1399
{ restore int registers and return }
1400
reference_reset(ref);
1401
ref.index:=NR_FRAME_POINTER_REG;
1402
list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R13,RS_R15]),PF_EA));
1406
list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
1410
procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
1413
tmpref : treference;
1416
if ref.addressmode<>AM_OFFSET then
1417
internalerror(200309071);
1419
{ Be sure to have a base register }
1420
if (tmpref.base=NR_NO) then
1422
if tmpref.shiftmode<>SM_None then
1423
internalerror(200308294);
1424
if tmpref.signindex<0 then
1425
internalerror(200312023);
1426
tmpref.base:=tmpref.index;
1427
tmpref.index:=NR_NO;
1430
if assigned(tmpref.symbol) or
1431
not((is_shifter_const(tmpref.offset,b)) or
1432
(is_shifter_const(-tmpref.offset,b))
1434
fixref(list,tmpref);
1436
{ expect a base here if there is an index }
1437
if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
1438
internalerror(200312022);
1440
if tmpref.index<>NR_NO then
1442
if tmpref.shiftmode<>SM_None then
1443
internalerror(200312021);
1444
if tmpref.signindex<0 then
1445
a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
1447
a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
1448
if tmpref.offset<>0 then
1449
a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
1453
if tmpref.base=NR_NO then
1454
a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
1456
if tmpref.offset<>0 then
1457
a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
1460
instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
1462
add_move_instruction(instr);
1468
procedure tcgarm.fixref(list : TAsmList;var ref : treference);
1471
tmpref : treference;
1474
{ absolute symbols can't be handled directly, we've to store the symbol reference
1475
in the text segment and access it pc relative
1477
For now, we assume that references where base or index equals to PC are already
1478
relative, all other references are assumed to be absolute and thus they need
1479
to be handled extra.
1481
A proper solution would be to change refoptions to a set and store the information
1482
if the symbol is absolute or relative there.
1484
{ create consts entry }
1485
reference_reset(tmpref);
1486
current_asmdata.getjumplabel(l);
1487
cg.a_label(current_procinfo.aktlocaldata,l);
1488
tmpref.symboldata:=current_procinfo.aktlocaldata.last;
1490
if assigned(ref.symbol) then
1491
current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
1493
current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
1495
{ load consts entry }
1496
tmpreg:=getintregister(list,OS_INT);
1499
list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
1501
if (ref.base<>NR_NO) then
1503
if ref.index<>NR_NO then
1505
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
1509
if ref.base<>NR_PC then
1514
ref.shiftmode:=SM_None;
1526
procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
1528
paraloc1,paraloc2,paraloc3 : TCGPara;
1533
paramanager.getintparaloc(pocall_default,1,paraloc1);
1534
paramanager.getintparaloc(pocall_default,2,paraloc2);
1535
paramanager.getintparaloc(pocall_default,3,paraloc3);
1536
paramanager.allocparaloc(list,paraloc3);
1537
a_param_const(list,OS_INT,len,paraloc3);
1538
paramanager.allocparaloc(list,paraloc2);
1539
a_paramaddr_ref(list,dest,paraloc2);
1540
paramanager.allocparaloc(list,paraloc2);
1541
a_paramaddr_ref(list,source,paraloc1);
1542
paramanager.freeparaloc(list,paraloc3);
1543
paramanager.freeparaloc(list,paraloc2);
1544
paramanager.freeparaloc(list,paraloc1);
1545
alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
1546
alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
1547
a_call_name(list,'FPC_MOVE');
1548
dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
1549
dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
1556
procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
1558
maxtmpreg=10;{roozbeh: can be reduced to 8 or lower if might conflick with reserved ones,also +2 is used becouse of regs required for referencing}
1561
srcref,dstref,usedtmpref,usedtmpref2:treference;
1562
srcreg,destreg,countreg,r,tmpreg:tregister;
1566
tmpregisters:array[1..maxtmpreg] of tregister;
1567
tmpregi,tmpregi2:byte;
1569
{ will never be called with count<=4 }
1570
procedure genloop(count : aword;size : byte);
1572
size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
1576
current_asmdata.getjumplabel(l);
1577
if count<size then size:=1;
1578
a_load_const_reg(list,OS_INT,count div size,countreg);
1580
srcref.addressmode:=AM_POSTINDEXED;
1581
dstref.addressmode:=AM_POSTINDEXED;
1582
srcref.offset:=size;
1583
dstref.offset:=size;
1584
r:=getintregister(list,size2opsize[size]);
1585
a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
1586
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
1587
a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
1588
a_jmp_flags(list,F_NE,l);
1591
case count mod size of
1594
a_load_ref_reg(list,OS_8,OS_8,srcref,r);
1595
a_load_reg_ref(list,OS_8,OS_8,r,dstref);
1600
a_load_ref_reg(list,OS_16,OS_16,srcref,r);
1601
a_load_reg_ref(list,OS_16,OS_16,r,dstref);
1605
a_load_ref_reg(list,OS_8,OS_8,srcref,r);
1606
a_load_reg_ref(list,OS_8,OS_8,r,dstref);
1607
a_load_ref_reg(list,OS_8,OS_8,srcref,r);
1608
a_load_reg_ref(list,OS_8,OS_8,r,dstref);
1615
a_load_ref_reg(list,OS_16,OS_16,srcref,r);
1616
a_load_reg_ref(list,OS_16,OS_16,r,dstref);
1617
a_load_ref_reg(list,OS_8,OS_8,srcref,r);
1618
a_load_reg_ref(list,OS_8,OS_8,r,dstref);
1622
a_load_ref_reg(list,OS_8,OS_8,srcref,r);
1623
a_load_reg_ref(list,OS_8,OS_8,r,dstref);
1624
a_load_ref_reg(list,OS_8,OS_8,srcref,r);
1625
a_load_reg_ref(list,OS_8,OS_8,r,dstref);
1626
a_load_ref_reg(list,OS_8,OS_8,srcref,r);
1627
a_load_reg_ref(list,OS_8,OS_8,r,dstref);
1630
{ keep the registers alive }
1631
list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
1632
list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
1633
list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
1639
helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
1642
if cs_opt_size in current_settings.optimizerswitches then
1644
if (len<=helpsize) and aligned then
1647
srcreg:=getintregister(list,OS_ADDR);
1649
{ explicit pc relative addressing, could be
1650
e.g. a floating point constant }
1651
if source.base=NR_PC then
1653
{ ... then we don't need a loadaddr }
1658
a_loadaddr_ref_reg(list,source,srcreg);
1659
reference_reset_base(srcref,srcreg,0);
1662
while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
1665
tmpregisters[tmpregi]:=getintregister(list,OS_32);
1666
a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
1667
inc(srcref.offset,4);
1671
destreg:=getintregister(list,OS_ADDR);
1672
a_loadaddr_ref_reg(list,dest,destreg);
1673
reference_reset_base(dstref,destreg,0);
1675
while (tmpregi2<=tmpregi) do
1677
a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
1678
inc(dstref.offset,4);
1697
r:=getintregister(list,cgsize);
1698
a_load_ref_reg(list,cgsize,cgsize,srcref,r);
1699
a_load_reg_ref(list,cgsize,cgsize,r,dstref);
1700
inc(srcref.offset,copysize);
1701
inc(dstref.offset,copysize);
1707
if (len<=4) then{len<=4 and not aligned}
1709
r:=getintregister(list,cgsize);
1710
usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
1712
a_load_reg_ref(list,OS_8,OS_8,r,dstref)
1715
tmpreg:=getintregister(list,cgsize);
1716
usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
1717
inc(usedtmpref.offset,1);
1718
a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
1719
inc(usedtmpref2.offset,1);
1720
a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
1723
inc(usedtmpref.offset,1);
1724
a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
1725
inc(usedtmpref2.offset,1);
1726
a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
1729
inc(usedtmpref.offset,1);
1730
a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
1731
inc(usedtmpref2.offset,1);
1732
a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
1736
end{end of if len<=4}
1738
begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
1739
destreg:=getintregister(list,OS_ADDR);
1740
a_loadaddr_ref_reg(list,dest,destreg);
1741
reference_reset_base(dstref,destreg,0);
1743
srcreg:=getintregister(list,OS_ADDR);
1744
a_loadaddr_ref_reg(list,source,srcreg);
1745
reference_reset_base(srcref,srcreg,0);
1747
countreg:=getintregister(list,OS_32);
1749
// if cs_opt_size in current_settings.optimizerswitches then
1750
{ roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
1759
procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
1761
g_concatcopy_internal(list,source,dest,len,false);
1765
procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
1767
if (source.alignment in [1..3]) or
1768
(dest.alignment in [1..3]) then
1769
g_concatcopy_internal(list,source,dest,len,false)
1771
g_concatcopy_internal(list,source,dest,len,true);
1775
procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
1779
ovloc.loc:=LOC_VOID;
1780
g_overflowCheck_loc(list,l,def,ovloc);
1784
procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
1790
if not(cs_check_overflow in current_settings.localswitches) then
1792
current_asmdata.getjumplabel(hl);
1796
ai:=taicpu.op_sym(A_B,hl);
1799
if not((def.typ=pointerdef) or
1800
((def.typ=orddef) and
1801
(torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
1802
ai.SetCondition(C_VC)
1804
if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
1805
ai.SetCondition(C_CS)
1807
ai.SetCondition(C_CC);
1813
hflags:=ovloc.resflags;
1814
inverse_flags(hflags);
1815
cg.a_jmp_flags(list,hflags,hl);
1818
internalerror(200409281);
1821
a_call_name(list,'FPC_OVERFLOW');
1826
procedure tcgarm.g_save_standard_registers(list : TAsmList);
1828
{ this work is done in g_proc_entry }
1832
procedure tcgarm.g_restore_standard_registers(list : TAsmList);
1834
{ this work is done in g_proc_exit }
1838
procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
1842
ai:=Taicpu.Op_sym(A_B,l);
1843
ai.SetCondition(OpCmp2AsmCond[cond]);
1849
procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
1851
procedure loadvmttor12;
1855
reference_reset_base(href,NR_R0,0);
1856
cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
1860
procedure op_onr12methodaddr;
1864
if (procdef.extnumber=$ffff) then
1865
Internalerror(200006139);
1866
{ call/jmp vmtoffs(%eax) ; method offs }
1867
reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
1868
cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
1869
list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
1873
make_global : boolean;
1875
if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
1876
Internalerror(200006137);
1877
if not assigned(procdef._class) or
1878
(procdef.procoptions*[po_classmethod, po_staticmethod,
1879
po_methodpointer, po_interrupt, po_iocheck]<>[]) then
1880
Internalerror(200006138);
1881
if procdef.owner.symtabletype<>ObjectSymtable then
1882
Internalerror(200109191);
1885
if (not current_module.is_unit) or
1886
(cs_create_smart in current_settings.moduleswitches) or
1887
(procdef.owner.defowner.owner.symtabletype=globalsymtable) then
1891
list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
1893
list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
1895
{ set param1 interface to self }
1896
g_adjust_self_value(list,procdef,ioffset);
1899
if po_virtualmethod in procdef.procoptions then
1906
list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
1908
list.concat(Tai_symbol_end.Createname(labelname));
1912
procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
1917
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
1918
list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
1922
cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
1923
cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
1926
a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
1931
procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
1933
a_op64_const_reg_reg(list,op,size,value,reg,reg);
1937
procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
1941
a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
1945
procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
1949
a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
1953
procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
1958
ovloc.loc:=LOC_VOID;
1962
internalerror(200306017);
1964
if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
1969
if is_shifter_const(lo(value),b) then
1970
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
1973
tmpreg:=cg.getintregister(list,OS_32);
1974
cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
1975
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
1978
if is_shifter_const(hi(value),b) then
1979
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
1982
tmpreg:=cg.getintregister(list,OS_32);
1983
cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
1984
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
1989
if is_shifter_const(lo(value),b) then
1990
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
1993
tmpreg:=cg.getintregister(list,OS_32);
1994
cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
1995
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
1998
if is_shifter_const(hi(value),b) then
1999
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
2002
tmpreg:=cg.getintregister(list,OS_32);
2003
cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
2004
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
2008
internalerror(200502131);
2012
{ the arm has an weired opinion how flags for SUB/ADD are handled }
2013
ovloc.loc:=LOC_FLAGS;
2016
ovloc.resflags:=F_CS;
2018
ovloc.resflags:=F_CC;
2025
OP_AND,OP_OR,OP_XOR:
2027
cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
2028
cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
2032
if is_shifter_const(aint(lo(value)),b) then
2033
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
2036
tmpreg:=cg.getintregister(list,OS_32);
2037
cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
2038
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
2041
if is_shifter_const(aint(hi(value)),b) then
2042
list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
2045
tmpreg:=cg.getintregister(list,OS_32);
2046
cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
2047
list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
2052
if is_shifter_const(aint(lo(value)),b) then
2053
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
2056
tmpreg:=cg.getintregister(list,OS_32);
2057
cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
2058
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
2061
if is_shifter_const(aint(hi(value)),b) then
2062
list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
2065
tmpreg:=cg.getintregister(list,OS_32);
2066
cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
2067
list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
2071
internalerror(2003083101);
2077
procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
2079
ovloc.loc:=LOC_VOID;
2083
internalerror(200306017);
2085
if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
2090
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
2091
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
2095
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
2096
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
2099
internalerror(2003083101);
2103
{ the arm has an weired opinion how flags for SUB/ADD are handled }
2104
ovloc.loc:=LOC_FLAGS;
2107
ovloc.resflags:=F_CS;
2109
ovloc.resflags:=F_CC;
2116
OP_AND,OP_OR,OP_XOR:
2118
cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
2119
cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
2123
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
2124
list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
2128
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
2129
list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
2132
internalerror(2003083101);
2140
cg64:=tcg64farm.create;