2
$Id: cgcpu.pas,v 1.51 2004/03/31 19:13:04 florian Exp $
4
Copyright (c) 2003 by Florian Klaempfl
5
Member of the Free Pascal development team
7
This unit implements the code generator for the ARM
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2 of the License, or
12
(at your option) any later version.
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
GNU General Public License for more details.
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
****************************************************************************
34
aasmbase,aasmcpu,aasmtai,
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 : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
46
procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
47
procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
49
procedure a_call_name(list : taasmoutput;const s : string);override;
50
procedure a_call_reg(list : taasmoutput;reg: tregister); override;
52
procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister); override;
53
procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
55
procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
56
size: tcgsize; a: aword; src, dst: tregister); override;
57
procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
58
size: tcgsize; src1, src2, dst: tregister); override;
61
procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
62
procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
63
procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
64
procedure a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
66
{ fpu move instructions }
67
procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
68
procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
69
procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
71
{ comparison operations }
72
procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
73
l : tasmlabel);override;
74
procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
76
procedure a_jmp_name(list : taasmoutput;const s : string); override;
77
procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
78
procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
80
procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
82
procedure g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:aword);override;
83
procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
84
procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
85
procedure g_restore_frame_pointer(list : taasmoutput);override;
87
procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
89
procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
91
procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
93
procedure g_save_standard_registers(list : taasmoutput);override;
94
procedure g_restore_standard_registers(list : taasmoutput);override;
95
procedure g_save_all_registers(list : taasmoutput);override;
96
procedure g_restore_all_registers(list : taasmoutput;const funcretparaloc:tparalocation);override;
98
procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
99
procedure fixref(list : taasmoutput;var ref : treference);
100
procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
103
tcg64farm = class(tcg64f32)
104
procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
105
procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);override;
106
procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);override;
107
procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);override;
111
OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
112
C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
114
function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
116
function get_fpu_postfix(def : tdef) : toppostfix;
122
globtype,globals,verbose,systems,cutils,
123
symconst,symdef,symsym,
130
function get_fpu_postfix(def : tdef) : toppostfix;
132
if def.deftype=floatdef then
134
case tfloatdef(def).typ of
142
internalerror(200401272);
146
internalerror(200401271);
150
procedure tcgarm.init_register_allocators;
152
inherited init_register_allocators;
153
{ currently, we save R14 always, so we can use it }
154
rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,
155
[RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
156
RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
157
rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
158
[RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
159
rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
160
[RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
164
procedure tcgarm.done_register_allocators;
166
rg[R_INTREGISTER].free;
167
rg[R_FPUREGISTER].free;
168
rg[R_MMREGISTER].free;
169
inherited done_register_allocators;
173
procedure tcgarm.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
178
LOC_REGISTER,LOC_CREGISTER:
179
a_load_const_reg(list,size,a,locpara.register);
182
reference_reset(ref);
183
ref.base:=locpara.reference.index;
184
ref.offset:=locpara.reference.offset;
185
a_load_const_ref(list,size,a,ref);
188
internalerror(2002081101);
190
if locpara.alignment<>0 then
191
internalerror(2002081102);
195
procedure tcgarm.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
201
LOC_REGISTER,LOC_CREGISTER:
202
a_load_ref_reg(list,size,size,r,locpara.register);
205
reference_reset(ref);
206
ref.base:=locpara.reference.index;
207
ref.offset:=locpara.reference.offset;
208
tmpreg := getintregister(list,size);
209
a_load_ref_reg(list,size,size,r,tmpreg);
210
a_load_reg_ref(list,size,size,tmpreg,ref);
211
ungetregister(list,tmpreg);
213
LOC_FPUREGISTER,LOC_CFPUREGISTER:
216
a_loadfpu_ref_reg(list,size,r,locpara.register);
218
internalerror(2002072801);
221
internalerror(2002081103);
223
if locpara.alignment<>0 then
224
internalerror(2002081104);
228
procedure tcgarm.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
234
LOC_REGISTER,LOC_CREGISTER:
235
a_loadaddr_ref_reg(list,r,locpara.register);
238
reference_reset(ref);
239
ref.base := locpara.reference.index;
240
ref.offset := locpara.reference.offset;
241
tmpreg := getintregister(list,OS_ADDR);
242
a_loadaddr_ref_reg(list,r,tmpreg);
243
a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
244
ungetregister(list,tmpreg);
247
internalerror(2002080701);
252
procedure tcgarm.a_call_name(list : taasmoutput;const s : string);
254
list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
255
if not(pi_do_call in current_procinfo.flags) then
256
internalerror(2003060703);
260
procedure tcgarm.a_call_reg(list : taasmoutput;reg: tregister);
264
list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
265
list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
266
if not(pi_do_call in current_procinfo.flags) then
267
internalerror(2003060704);
271
procedure tcgarm.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister);
273
a_op_const_reg_reg(list,op,size,a,reg,reg);
277
procedure tcgarm.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
281
list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
283
list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
285
a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
291
op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
292
(A_NONE,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
293
A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
296
procedure tcgarm.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
297
size: tcgsize; a: aword; src, dst: tregister);
304
if is_shifter_const(dword(-a),shift) then
318
if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
322
internalerror(200308281);
326
internalerror(200308291);
330
so.shiftmode:=SM_LSL;
332
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
335
list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
340
internalerror(200308292);
344
so.shiftmode:=SM_LSR;
346
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
349
list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
354
internalerror(200308291);
358
so.shiftmode:=SM_ASR;
360
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
363
list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
366
list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a));
370
{ there could be added some more sophisticated optimizations }
371
if (op in [OP_MUL,OP_IMUL]) and (a=1) then
372
a_load_reg_reg(list,size,size,src,dst)
373
else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
374
a_load_const_reg(list,size,0,dst)
375
else if (op in [OP_IMUL]) and (a=-1) then
376
a_op_reg_reg(list,OP_NEG,size,src,dst)
377
{ we do this here instead in the peephole optimizer because
378
it saves us a register }
379
else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) then
380
a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
383
tmpreg:=getintregister(list,size);
384
a_load_const_reg(list,size,a,tmpreg);
385
a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
386
ungetregister(list,tmpreg);
392
procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
393
size: tcgsize; src1, src2, dst: tregister);
401
internalerror(200308281);
406
so.shiftmode:=SM_LSL;
407
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
413
so.shiftmode:=SM_LSR;
414
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
420
so.shiftmode:=SM_ASR;
421
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
426
{ the arm doesn't allow that rd and rm are the same }
430
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
433
tmpreg:=getintregister(list,size);
434
a_load_reg_reg(list,size,size,src2,dst);
435
ungetregister(list,tmpreg);
436
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
440
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
443
list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(setflags)*ord(PF_S))));
448
function rotl(d : dword;b : byte) : dword;
450
result:=(d shr (32-b)) or (d shl b);
454
function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
460
if (d and not(rotl($ff,i*2)))=0 then
471
procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);
477
if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
478
internalerror(2002090902);
479
if is_shifter_const(dword(a),imm_shift) then
480
list.concat(taicpu.op_reg_const(A_MOV,reg,a))
481
else if is_shifter_const(dword(not(a)),imm_shift) then
482
list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
487
objectlibrary.getlabel(l);
488
cg.a_label(current_procinfo.aktlocaldata,l);
489
hr.symboldata:=current_procinfo.aktlocaldata.last;
490
current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
493
list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
498
procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
506
{ Be sure to have a base register }
507
if (ref.base=NR_NO) then
509
if ref.shiftmode<>SM_None then
510
internalerror(200308294);
515
{ absolute symbols can't be handled directly, we've to store the symbol reference
516
in the text segment and access it pc relative
518
For now, we assume that references where base or index equals to PC are already
519
relative, all other references are assumed to be absolute and thus they need
522
A proper solution would be to change refoptions to a set and store the information
523
if the symbol is absolute or relative there.
526
if (assigned(ref.symbol) and
527
not(is_pc(ref.base)) and
528
not(is_pc(ref.index))
530
(ref.offset<-4095) or
532
((oppostfix in [PF_SB,PF_H,PF_SH]) and
533
((ref.offset<-255) or
537
((op in [A_LDF,A_STF]) and
538
((ref.offset<-1020) or
543
reference_reset(tmpref);
544
{ create consts entry }
545
objectlibrary.getlabel(l);
546
cg.a_label(current_procinfo.aktlocaldata,l);
547
tmpref.symboldata:=current_procinfo.aktlocaldata.last;
549
if assigned(ref.symbol) then
550
current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
552
current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
554
{ load consts entry }
555
tmpreg:=getintregister(list,OS_INT);
558
list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
560
if (ref.base<>NR_NO) then
562
if ref.index<>NR_NO then
564
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
572
ref.shiftmode:=SM_None;
581
if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
583
if tmpreg<>NR_NO then
584
a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
587
tmpreg:=getintregister(list,OS_ADDR);
588
a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
594
{ floating point operations have only limited references
595
we expect here, that a base is already set }
596
if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
598
if ref.shiftmode<>SM_none then
599
internalerror(200309121);
600
if tmpreg<>NR_NO then
602
if ref.base=tmpreg then
604
if ref.signindex<0 then
605
list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
607
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
612
if ref.index<>tmpreg then
613
internalerror(200403161);
614
if ref.signindex<0 then
615
list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
617
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
624
tmpreg:=getintregister(list,OS_ADDR);
625
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
630
list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
631
if (tmpreg<>NR_NO) then
632
ungetregister(list,tmpreg);
636
procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
638
oppostfix:toppostfix;
641
{ signed integer registers }
652
InternalError(200308295);
654
handle_load_store(list,A_STR,oppostfix,reg,ref);
658
procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
660
oppostfix:toppostfix;
663
{ signed integer registers }
676
InternalError(200308291);
678
handle_load_store(list,A_LDR,oppostfix,reg,ref);
682
procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
689
(tcgsize2size[tosize] < tcgsize2size[fromsize]) or
690
((tcgsize2size[tosize] = tcgsize2size[fromsize]) and
691
(tosize <> fromsize) and
692
not(fromsize in [OS_32,OS_S32])) then
696
list.concat(taicpu.op_reg_reg_const(A_AND,
700
so.shiftmode:=SM_LSL;
702
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
703
so.shiftmode:=SM_ASR;
705
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
709
so.shiftmode:=SM_LSL;
711
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
712
so.shiftmode:=SM_LSR;
714
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
718
so.shiftmode:=SM_LSL;
720
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
721
so.shiftmode:=SM_ASR;
723
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
727
instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
729
add_move_instruction(instr);
731
else internalerror(2002090901);
737
procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
739
list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
743
procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
745
oppostfix:toppostfix;
755
InternalError(200309021);
757
handle_load_store(list,A_LDF,oppostfix,reg,ref);
761
procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
763
oppostfix:toppostfix;
773
InternalError(200309021);
775
handle_load_store(list,A_STF,oppostfix,reg,ref);
779
{ comparison operations }
780
procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
786
if is_shifter_const(a,b) then
787
list.concat(taicpu.op_reg_const(A_CMP,reg,a))
788
{ CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
789
and CMP reg,$7fffffff regarding the flags according to the ARM manual }
790
else if is_shifter_const(-a,b) and (a<>$7fffffff) and (a<>$ffffffff) then
791
list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
794
tmpreg:=getintregister(list,size);
795
a_load_const_reg(list,size,a,tmpreg);
796
list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
797
ungetregister(list,tmpreg);
799
a_jmp_cond(list,cmp_op,l);
803
procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
805
list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
806
a_jmp_cond(list,cmp_op,l);
810
procedure tcgarm.a_jmp_name(list : taasmoutput;const s : string);
812
list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
816
procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
818
list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name,AB_EXTERNAL,AT_FUNCTION)));
822
procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
826
ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
832
procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
836
list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
837
list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond[flags_to_cond(f)]));
841
procedure tcgarm.g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:aword);
846
procedure tcgarm.g_stackframe_entry(list : taasmoutput;localsize : longint);
850
firstfloatreg,lastfloatreg,
853
LocalSize:=align(LocalSize,4);
854
firstfloatreg:=RS_NO;
855
{ save floating point registers? }
856
for r:=RS_F0 to RS_F7 do
857
if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
859
if firstfloatreg=RS_NO then
863
a_reg_alloc(list,NR_STACK_POINTER_REG);
864
a_reg_alloc(list,NR_FRAME_POINTER_REG);
865
a_reg_alloc(list,NR_R12);
867
list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
868
{ save int registers }
869
reference_reset(ref);
870
ref.index:=NR_STACK_POINTER_REG;
871
ref.addressmode:=AM_PREINDEXED;
872
list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,
873
rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),
876
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
878
{ allocate necessary stack size }
879
{ don't use a_op_const_reg_reg here because we don't allow register allocations
880
in the entry/exit code }
881
if not(is_shifter_const(localsize,shift)) then
883
a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
884
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
885
a_reg_dealloc(list,NR_R12);
889
a_reg_dealloc(list,NR_R12);
890
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
892
if firstfloatreg<>RS_NO then
894
reference_reset(ref);
895
ref.base:=NR_FRAME_POINTER_REG;
896
ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
897
list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
898
lastfloatreg-firstfloatreg+1,ref));
903
procedure tcgarm.g_return_from_proc(list : taasmoutput;parasize : aword);
906
firstfloatreg,lastfloatreg,
909
{ restore floating point register }
910
firstfloatreg:=RS_NO;
911
{ save floating point registers? }
912
for r:=RS_F0 to RS_F7 do
913
if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
915
if firstfloatreg=RS_NO then
919
if firstfloatreg<>RS_NO then
921
reference_reset(ref);
922
ref.base:=NR_FRAME_POINTER_REG;
923
ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
924
list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
925
lastfloatreg-firstfloatreg+1,ref));
928
if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
929
list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
932
{ restore int registers and return }
933
reference_reset(ref);
934
ref.index:=NR_FRAME_POINTER_REG;
935
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));
940
procedure tcgarm.g_restore_frame_pointer(list : taasmoutput);
942
{ the frame pointer on the ARM is restored while the ret is executed }
946
procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
952
if ref.addressmode<>AM_OFFSET then
953
internalerror(200309071);
955
{ Be sure to have a base register }
956
if (tmpref.base=NR_NO) then
958
if tmpref.shiftmode<>SM_None then
959
internalerror(200308294);
960
if tmpref.signindex<0 then
961
internalerror(200312023);
962
tmpref.base:=tmpref.index;
966
if assigned(tmpref.symbol) or
967
not((is_shifter_const(dword(tmpref.offset),b)) or
968
(is_shifter_const(dword(-tmpref.offset),b))
972
{ expect a base here }
973
if tmpref.base=NR_NO then
974
internalerror(200312022);
976
if tmpref.index<>NR_NO then
978
if tmpref.shiftmode<>SM_None then
979
internalerror(200312021);
980
if tmpref.signindex<0 then
981
a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
983
a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
984
if tmpref.offset<>0 then
985
a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
989
if tmpref.offset<>0 then
990
a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
993
instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
995
add_move_instruction(instr);
998
reference_release(list,tmpref);
1002
procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
1005
tmpref : treference;
1008
{ absolute symbols can't be handled directly, we've to store the symbol reference
1009
in the text segment and access it pc relative
1011
For now, we assume that references where base or index equals to PC are already
1012
relative, all other references are assumed to be absolute and thus they need
1013
to be handled extra.
1015
A proper solution would be to change refoptions to a set and store the information
1016
if the symbol is absolute or relative there.
1018
{ create consts entry }
1019
reference_reset(tmpref);
1020
objectlibrary.getlabel(l);
1021
cg.a_label(current_procinfo.aktlocaldata,l);
1022
tmpref.symboldata:=current_procinfo.aktlocaldata.last;
1024
if assigned(ref.symbol) then
1025
current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
1027
current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
1029
{ load consts entry }
1030
tmpreg:=getintregister(list,OS_INT);
1033
list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
1035
if (ref.base<>NR_NO) then
1037
if ref.index<>NR_NO then
1039
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
1047
ref.shiftmode:=SM_None;
1058
procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
1060
srcref,dstref:treference;
1061
srcreg,destreg,countreg,r:tregister;
1066
procedure genloop(count : aword;size : byte);
1068
size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
1072
objectlibrary.getlabel(l);
1073
a_load_const_reg(list,OS_INT,count,countreg);
1075
srcref.addressmode:=AM_POSTINDEXED;
1076
dstref.addressmode:=AM_POSTINDEXED;
1077
srcref.offset:=size;
1078
dstref.offset:=size;
1079
r:=getintregister(list,size2opsize[size]);
1080
a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
1081
a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
1082
ungetregister(list,r);
1083
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
1084
list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
1085
{ keep the registers alive }
1086
list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
1087
list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
1088
list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
1097
if cs_littlesize in aktglobalswitches then
1099
if not loadref and (len<=helpsize) then
1116
r:=getintregister(list,cgsize);
1117
a_load_ref_reg(list,cgsize,cgsize,srcref,r);
1118
if (len=0) and delsource then
1119
reference_release(list,source);
1120
a_load_reg_ref(list,cgsize,cgsize,r,dstref);
1121
inc(srcref.offset,copysize);
1122
inc(dstref.offset,copysize);
1123
ungetregister(list,r);
1128
destreg:=getintregister(list,OS_ADDR);
1129
a_loadaddr_ref_reg(list,dest,destreg);
1130
reference_reset_base(dstref,destreg,0);
1132
srcreg:=getintregister(list,OS_ADDR);
1134
a_load_ref_reg(list,OS_ADDR,OS_ADDR,source,srcreg)
1136
a_loadaddr_ref_reg(list,source,srcreg);
1137
reference_reset_base(srcref,srcreg,0);
1140
reference_release(list,source);
1142
countreg:=getintregister(list,OS_32);
1144
// if cs_littlesize in aktglobalswitches then
1149
helpsize:=len shr 2;
1153
a_load_const_reg(list,OS_INT,helpsize,countreg);
1154
list.concat(Taicpu.op_none(A_REP,S_NO));
1157
list.concat(Taicpu.op_none(A_MOVSD,S_NO));
1161
list.concat(Taicpu.op_none(A_MOVSW,S_NO));
1164
list.concat(Taicpu.op_none(A_MOVSB,S_NO));
1167
ungetregister(list,countreg);
1168
ungetregister(list,srcreg);
1169
ungetregister(list,destreg);
1172
tg.ungetiftemp(list,source);
1176
procedure tcgarm.g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
1181
procedure tcgarm.g_save_standard_registers(list : taasmoutput);
1183
{ we support only ARM standard calling conventions so this procedure has no use on the ARM }
1187
procedure tcgarm.g_restore_standard_registers(list : taasmoutput);
1189
{ we support only ARM standard calling conventions so this procedure has no use on the ARM }
1193
procedure tcgarm.g_save_all_registers(list : taasmoutput);
1195
{ we support only ARM standard calling conventions so this procedure has no use on the ARM }
1199
procedure tcgarm.g_restore_all_registers(list : taasmoutput;const funcretparaloc:tparalocation);
1201
{ we support only ARM standard calling conventions so this procedure has no use on the ARM }
1205
procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
1209
ai:=Taicpu.Op_sym(A_B,l);
1210
ai.SetCondition(OpCmp2AsmCond[cond]);
1216
procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
1223
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
1224
list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
1228
cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
1229
cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
1232
a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
1237
procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
1239
a_op64_const_reg_reg(list,op,value,reg,reg);
1243
procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
1249
OP_AND,OP_OR,OP_XOR:
1251
cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
1252
cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
1256
if is_shifter_const(lo(value),b) then
1257
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
1260
tmpreg:=cg.getintregister(list,OS_32);
1261
cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
1262
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
1263
cg.ungetregister(list,tmpreg);
1266
if is_shifter_const(hi(value),b) then
1267
list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
1270
tmpreg:=cg.getintregister(list,OS_32);
1271
cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
1272
list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
1273
cg.ungetregister(list,tmpreg);
1278
if is_shifter_const(lo(value),b) then
1279
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
1282
tmpreg:=cg.getintregister(list,OS_32);
1283
cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
1284
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
1285
cg.ungetregister(list,tmpreg);
1288
if is_shifter_const(hi(value),b) then
1289
list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
1292
tmpreg:=cg.getintregister(list,OS_32);
1293
cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
1294
list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
1295
cg.ungetregister(list,tmpreg);
1299
internalerror(2003083101);
1304
procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
1307
OP_AND,OP_OR,OP_XOR:
1309
cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
1310
cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
1314
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
1315
list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
1319
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
1320
list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
1323
internalerror(2003083101);
1330
cg64:=tcg64farm.create;
1334
Revision 1.51 2004/03/31 19:13:04 florian
1335
* concatcopy with len=0 exits now immediatly
1337
Revision 1.50 2004/03/29 19:19:35 florian
1338
+ arm floating point register saving implemented
1339
* hopefully stabs generation for MacOSX fixed
1340
+ some defines for arm added
1342
Revision 1.49 2004/03/14 21:42:24 florian
1343
* optimized mul code generation
1345
Revision 1.48 2004/03/14 16:15:40 florian
1346
* spilling problem fixed
1347
* handling of floating point memory references fixed
1349
Revision 1.47 2004/03/10 22:35:40 florian
1350
+ fixed code generation for cmn
1352
Revision 1.46 2004/03/06 20:35:19 florian
1353
* fixed arm compilation
1354
* cleaned up code generation for exported linux procedures
1356
Revision 1.45 2004/03/02 00:36:33 olle
1357
* big transformation of Tai_[const_]Symbol.Create[data]name*
1359
Revision 1.44 2004/02/04 22:01:13 peter
1360
* first try to get cpupara working for x86_64
1362
Revision 1.43 2004/01/29 17:09:32 florian
1363
* handling of floating point references fixed
1365
Revision 1.42 2004/01/28 15:36:47 florian
1366
* fixed another couple of arm bugs
1368
Revision 1.41 2004/01/27 15:04:06 florian
1369
* fixed code generation for math inl. nodes
1370
* more code generator improvements
1372
Revision 1.40 2004/01/26 19:05:56 florian
1373
* fixed several arm issues
1375
Revision 1.39 2004/01/24 20:19:46 florian
1376
* fixed some spilling stuff
1377
+ not(<int64>) implemented
1378
+ small set comparisations implemented
1380
Revision 1.38 2004/01/24 01:33:20 florian
1381
* fixref fixed if index, base and offset were given
1383
Revision 1.37 2004/01/22 20:13:18 florian
1384
* fixed several issues with flags
1386
Revision 1.36 2004/01/22 02:22:47 florian
1387
* op_const_reg_reg with OP_SAR fixed
1389
Revision 1.35 2004/01/22 01:47:15 florian
1390
* improved register usage
1391
+ implemented second_cmp64bit
1393
Revision 1.34 2004/01/21 19:01:03 florian
1394
* fixed handling of max. distance of pc relative symbols
1396
Revision 1.33 2004/01/21 15:41:56 florian
1397
* fixed register allocator problems with concatcopy
1399
Revision 1.32 2004/01/21 14:22:00 florian
1400
+ reintroduce implemented
1402
Revision 1.31 2004/01/21 01:22:35 florian
1403
* fixed a_cmp_const_reg_label
1404
* fixed volatile register handling which was broken by my last patch
1406
Revision 1.30 2004/01/20 23:18:00 florian
1408
+ implemented paramgr.get_volative_registers
1410
Revision 1.29 2003/12/26 14:02:30 peter
1412
* use registertype in spill_register
1414
Revision 1.28 2003/12/18 17:06:21 florian
1415
* arm compiler compilation fixed
1417
Revision 1.27 2003/12/08 17:43:57 florian
1418
* fixed ldm/stm arm assembler reading
1419
* fixed a_load_reg_reg with OS_8 on ARM
1420
* non supported calling conventions cause only a warning now
1422
Revision 1.26 2003/12/03 17:39:05 florian
1423
* fixed several arm calling conventions issues
1424
* fixed reference reading in the assembler reader
1425
* fixed a_loadaddr_ref_reg
1427
Revision 1.25 2003/11/30 19:35:29 florian
1428
* fixed several arm related problems
1430
Revision 1.24 2003/11/24 15:17:37 florian
1431
* changed some types to prevend range check errors
1433
Revision 1.23 2003/11/21 16:29:26 florian
1434
* fixed reading of reg. sets in the arm assembler reader
1436
Revision 1.22 2003/11/07 15:58:32 florian
1437
* Florian's culmutative nr. 1; contains:
1438
- invalid calling conventions for a certain cpu are rejected
1439
- arm softfloat calling conventions
1440
- -Sp for cpu dependend code generation
1442
- remaining code for value open array paras on heap
1444
Revision 1.21 2003/11/02 14:30:03 florian
1445
* fixed ARM for new reg. allocation scheme
1447
Revision 1.20 2003/10/11 16:06:42 florian
1448
* fixed some MMX<->SSE
1449
* started to fix ppc, needs an overhaul
1450
+ stabs info improve for spilling, not sure if it works correctly/completly
1451
- MMX_SUPPORT removed from Makefile.fpc
1453
Revision 1.19 2003/09/11 11:55:00 florian
1454
* improved arm code generation
1455
* move some protected and private field around
1456
* the temp. register for register parameters/arguments are now released
1457
before the move to the parameter register is done. This improves
1458
the code in a lot of cases.
1460
Revision 1.18 2003/09/09 12:53:40 florian
1461
* some assembling problems fixed
1462
* improved loadaddr_ref_reg
1464
Revision 1.17 2003/09/06 16:45:51 florian
1465
* fixed exit code (no preindexed addressing mode in LDM)
1467
Revision 1.16 2003/09/06 11:21:50 florian
1468
* fixed stm and ldm to be usable with preindex operand
1470
Revision 1.15 2003/09/05 23:57:01 florian
1471
* arm is working again as before the new register naming scheme was implemented
1473
Revision 1.14 2003/09/04 21:07:03 florian
1474
* ARM compiler compiles again
1476
Revision 1.13 2003/09/04 00:15:29 florian
1477
* first bunch of adaptions of arm compiler for new register type
1479
Revision 1.12 2003/09/03 19:10:30 florian
1480
* initial revision of new register naming
1482
Revision 1.11 2003/09/03 11:18:37 florian
1483
* fixed arm concatcopy
1484
+ arm support in the common compiler sources added
1485
* moved some generic cg code around
1489
Revision 1.10 2003/09/01 15:11:16 florian
1490
* fixed reference handling
1491
* fixed operand postfix for floating point instructions
1492
* fixed wrong shifter constant handling
1494
Revision 1.9 2003/09/01 09:54:57 florian
1495
* results of work on arm port last weekend
1497
Revision 1.8 2003/08/29 21:36:28 florian
1498
* fixed procedure entry/exit code
1499
* started to fix reference handling
1501
Revision 1.7 2003/08/28 13:26:10 florian
1502
* another couple of arm fixes
1504
Revision 1.6 2003/08/28 00:05:29 florian
1505
* today's arm patches
1507
Revision 1.5 2003/08/25 23:20:38 florian
1508
+ started to implement FPU support for the ARM
1509
* fixed a lot of other things
1511
Revision 1.4 2003/08/24 12:27:26 florian
1512
* continued to work on the arm port
1514
Revision 1.3 2003/08/21 03:14:00 florian
1515
* arm compiler can be compiled; far from being working
1517
Revision 1.2 2003/08/20 15:50:12 florian
1520
Revision 1.1 2003/07/21 16:35:30 florian
1521
* very basic stuff for the arm