1 {
2     Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
3 
4     Contains the base types for the ARM
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20  ****************************************************************************
21 }
22 {# Base unit for processor information. This unit contains
23    enumerations of registers, opcodes, sizes, and other
24    such things which are processor specific.
25 }
26 unit cpubase;
27 
28 {$define USEINLINE}
29 
30 {$i fpcdefs.inc}
31 
32   interface
33 
34     uses
35       globtype,globals,
36       cpuinfo,
37       cgbase
38       ;
39 
40 
41 {*****************************************************************************
42                                 Assembler Opcodes
43 *****************************************************************************}
44 
45     type
46       TAsmOp= {$i armop.inc}
47       {This is a bit of a hack, because there are more than 256 ARM Assembly Ops
48        But FPC currently can't handle more than 256 elements in a set.}
49       TCommonAsmOps = Set of A_None .. A_UADD16;
50 
51       { This should define the array of instructions as string }
52       op2strtable=array[tasmop] of string[11];
53 
54     const
55       { First value of opcode enumeration }
56       firstop = low(tasmop);
57       { Last value of opcode enumeration  }
58       lastop  = high(tasmop);
59 
60 {*****************************************************************************
61                                   Registers
62 *****************************************************************************}
63 
64     type
65       { Number of registers used for indexing in tables }
66       tregisterindex=0..{$i rarmnor.inc}-1;
67 
68     const
69       { Available Superregisters }
70       {$i rarmsup.inc}
71 
72       RS_PC = RS_R15;
73 
74       { No Subregisters }
75       R_SUBWHOLE = R_SUBNONE;
76 
77       { Available Registers }
78       {$i rarmcon.inc}
79 
80       { aliases }
81       NR_PC = NR_R15;
82 
83       { Integer Super registers first and last }
84       first_int_supreg = RS_R0;
85       first_int_imreg = $10;
86 
87       { Float Super register first and last }
88       first_fpu_supreg    = RS_F0;
89       first_fpu_imreg     = $08;
90 
91       { MM Super register first and last }
92       first_mm_supreg    = RS_S0;
93       first_mm_imreg     = $30;
94 
95 { TODO: Calculate bsstart}
96       regnumber_count_bsstart = 128;
97 
98       regnumber_table : array[tregisterindex] of tregister = (
99         {$i rarmnum.inc}
100       );
101 
102       regstabs_table : array[tregisterindex] of shortint = (
103         {$i rarmsta.inc}
104       );
105 
106       regdwarf_table : array[tregisterindex] of shortint = (
107         {$i rarmdwa.inc}
108       );
109       { registers which may be destroyed by calls }
110       VOLATILE_INTREGISTERS = [RS_R0..RS_R3,RS_R12..RS_R14];
111       VOLATILE_FPUREGISTERS = [RS_F0..RS_F3];
112       VOLATILE_MMREGISTERS =  [RS_D0..RS_D7,RS_D16..RS_D31];
113 
114       VOLATILE_INTREGISTERS_DARWIN = [RS_R0..RS_R3,RS_R9,RS_R12..RS_R14];
115 
116     type
117       totherregisterset = set of tregisterindex;
118 
119 {*****************************************************************************
120                           Instruction post fixes
121 *****************************************************************************}
122     type
123       { ARM instructions load/store and arithmetic instructions
124         can have several instruction post fixes which are collected
125         in this enumeration
126       }
127       TOpPostfix = (PF_None,
128         { update condition flags
129           or floating point single }
130         PF_S,
131         { floating point size }
132         PF_D,PF_E,PF_P,PF_EP,
133         { exchange }
134         PF_X,
135         { rounding }
136         PF_R,
137         { load/store }
138         PF_B,PF_SB,PF_BT,PF_H,PF_SH,PF_T,
139         { multiple load/store address modes }
140         PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA,
141         { multiple load/store vfp address modes }
142         PF_IAD,PF_DBD,PF_FDD,PF_EAD,
143         PF_IAS,PF_DBS,PF_FDS,PF_EAS,
144         PF_IAX,PF_DBX,PF_FDX,PF_EAX,
145         { VFP postfixes }
146         PF_8,PF_16,PF_32,PF_64,
147         PF_I8,PF_I16,PF_I32,PF_I64,
148         PF_S8,PF_S16,PF_S32,PF_S64,
149         PF_U8,PF_U16,PF_U32,PF_U64,
150         PF_P8, // polynomial
151         PF_F32,PF_F64,
152         PF_F32F64,PF_F64F32,
153         PF_F32S16,PF_F32U16,PF_S16F32,PF_U16F32,
154         PF_F64S16,PF_F64U16,PF_S16F64,PF_U16F64,
155         PF_F32S32,PF_F32U32,PF_S32F32,PF_U32F32,
156         PF_F64S32,PF_F64U32,PF_S32F64,PF_U32F64
157       );
158 
159       TOpPostfixes = set of TOpPostfix;
160 
161       TRoundingMode = (RM_None,RM_P,RM_M,RM_Z);
162 
163     const
164       cgsize2fpuoppostfix : array[OS_NO..OS_F128] of toppostfix = (
165         PF_None,
166         PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,
167         PF_S,PF_D,PF_E,PF_None,PF_None);
168 
169       oppostfix2str : array[TOpPostfix] of string[8] = ('',
170         's',
171         'd','e','p','ep',
172         'x',
173         'r',
174         'b','sb','bt','h','sh','t',
175         'ia','ib','da','db','fd','fa','ed','ea',
176         'iad','dbd','fdd','ead',
177         'ias','dbs','fds','eas',
178         'iax','dbx','fdx','eax',
179         '.8','.16','.32','.64',
180         '.i8','.i16','.i32','.i64',
181         '.s8','.s16','.s32','.s64',
182         '.u8','.u16','.u32','.u64',
183         '.p8',
184         '.f32','.f64',
185         '.f32.f64','.f64.f32',
186         '.f32.s16','.f32.u16','.s16.f32','.u16.f32',
187         '.f64.s16','.f64.u16','.s16.f64','.u16.f64',
188         '.f32.s32','.f32.u32','.s32.f32','.u32.f32',
189         '.f64.s32','.f64.u32','.s32.f64','.u32.f64');
190 
191       roundingmode2str : array[TRoundingMode] of string[1] = ('',
192         'p','m','z');
193 
194 {*****************************************************************************
195                                 Conditions
196 *****************************************************************************}
197 
198     type
199       TAsmCond=(C_None,
200         C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
201         C_GE,C_LT,C_GT,C_LE,C_AL,C_NV
202       );
203 
204       TAsmConds = set of TAsmCond;
205 
206     const
207       cond2str : array[TAsmCond] of string[2]=('',
208         'eq','ne','cs','cc','mi','pl','vs','vc','hi','ls',
209         'ge','lt','gt','le','al','nv'
210       );
211 
212       uppercond2str : array[TAsmCond] of string[2]=('',
213         'EQ','NE','CS','CC','MI','PL','VS','VC','HI','LS',
214         'GE','LT','GT','LE','AL','NV'
215       );
216 
217 {*****************************************************************************
218                                    Flags
219 *****************************************************************************}
220 
221     type
222       TResFlags = (F_EQ,F_NE,F_CS,F_CC,F_MI,F_PL,F_VS,F_VC,F_HI,F_LS,
223         F_GE,F_LT,F_GT,F_LE);
224 
225 {*****************************************************************************
226                                 Operands
227 *****************************************************************************}
228 
229       taddressmode = (AM_OFFSET,AM_PREINDEXED,AM_POSTINDEXED);
230       tshiftmode = (SM_None,SM_LSL,SM_LSR,SM_ASR,SM_ROR,SM_RRX);
231 
232       tupdatereg = (UR_None,UR_Update);
233 
234       pshifterop = ^tshifterop;
235 
236       tshifterop = record
237         shiftmode : tshiftmode;
238         rs : tregister;
239         shiftimm : byte;
240       end;
241 
242       tcpumodeflag = (mfA, mfI, mfF);
243       tcpumodeflags = set of tcpumodeflag;
244 
245       tspecialregflag = (srC, srX, srS, srF);
246       tspecialregflags = set of tspecialregflag;
247 
248 {*****************************************************************************
249                                  Constants
250 *****************************************************************************}
251 
252     const
253       max_operands = 6;
254 
255       maxintregs = 15;
256       maxfpuregs = 8;
257       maxaddrregs = 0;
258 
259 {*****************************************************************************
260                                 Operand Sizes
261 *****************************************************************************}
262 
263     type
264       topsize = (S_NO,
265         S_B,S_W,S_L,S_BW,S_BL,S_WL,
266         S_IS,S_IL,S_IQ,
267         S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX
268       );
269 
270 {*****************************************************************************
271                                  Constants
272 *****************************************************************************}
273 
274     const
275       maxvarregs = 7;
276       varregs : Array [1..maxvarregs] of tsuperregister =
277                 (RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
278 
279       maxfpuvarregs = 4;
280       fpuvarregs : Array [1..maxfpuvarregs] of tsuperregister =
281                 (RS_F4,RS_F5,RS_F6,RS_F7);
282 
283 {*****************************************************************************
284                           Default generic sizes
285 *****************************************************************************}
286 
287       { Defines the default address size for a processor, }
288       OS_ADDR = OS_32;
289       { the natural int size for a processor,
290         has to match osuinttype/ossinttype as initialized in psystem }
291       OS_INT = OS_32;
292       OS_SINT = OS_S32;
293       { the maximum float size for a processor,           }
294       OS_FLOAT = OS_F64;
295       { the size of a vector register for a processor     }
296       OS_VECTOR = OS_M32;
297 
298 {*****************************************************************************
299                           Generic Register names
300 *****************************************************************************}
301 
302       { Stack pointer register }
303       NR_STACK_POINTER_REG = NR_R13;
304       RS_STACK_POINTER_REG = RS_R13;
305       { Frame pointer register (initialized in tcpuprocinfo.init_framepointer) }
306       RS_FRAME_POINTER_REG: tsuperregister = RS_NO;
307       NR_FRAME_POINTER_REG: tregister = NR_NO;
308       { Register for addressing absolute data in a position independant way,
309         such as in PIC code. The exact meaning is ABI specific. For
310         further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
311       }
312       NR_PIC_OFFSET_REG = NR_R9;
313       { Results are returned in this register (32-bit values) }
314       NR_FUNCTION_RETURN_REG = NR_R0;
315       RS_FUNCTION_RETURN_REG = RS_R0;
316       { The value returned from a function is available in this register }
317       NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
318       RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
319 
320       NR_FPU_RESULT_REG = NR_F0;
321 
322       NR_MM_RESULT_REG  = NR_D0;
323 
324       NR_RETURN_ADDRESS_REG = NR_FUNCTION_RETURN_REG;
325 
326       { Offset where the parent framepointer is pushed }
327       PARENT_FRAMEPOINTER_OFFSET = 0;
328 
329       NR_DEFAULTFLAGS = NR_CPSR;
330       RS_DEFAULTFLAGS = RS_CPSR;
331 
332       { Low part of 64bit return value }
NR_FUNCTION_RESULT64_LOW_REGnull333       function NR_FUNCTION_RESULT64_LOW_REG: tregister;{$ifdef USEINLINE}inline;{$endif USEINLINE}
RS_FUNCTION_RESULT64_LOW_REGnull334       function RS_FUNCTION_RESULT64_LOW_REG: shortint;{$ifdef USEINLINE}inline;{$endif USEINLINE}
335       { High part of 64bit return value }
NR_FUNCTION_RESULT64_HIGH_REGnull336       function NR_FUNCTION_RESULT64_HIGH_REG: tregister;{$ifdef USEINLINE}inline;{$endif USEINLINE}
RS_FUNCTION_RESULT64_HIGH_REGnull337       function RS_FUNCTION_RESULT64_HIGH_REG: shortint;{$ifdef USEINLINE}inline;{$endif USEINLINE}
338 
339 {*****************************************************************************
340                        GCC /ABI linking information
341 *****************************************************************************}
342 
343     const
344       { Required parameter alignment when calling a routine declared as
345         stdcall and cdecl. The alignment value should be the one defined
346         by GCC or the target ABI.
347 
348         The value of this constant is equal to the constant
349         PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
350       }
351       std_param_align = 4;
352 
353 
354 {*****************************************************************************
355                                   Helpers
356 *****************************************************************************}
357 
358     { Returns the tcgsize corresponding with the size of reg.}
reg_cgsizenull359     function reg_cgsize(const reg: tregister) : tcgsize;
cgsize2subregnull360     function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
is_calljmpnull361     function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
362     procedure inverse_flags(var f: TResFlags);
flags_to_condnull363     function flags_to_cond(const f: TResFlags) : TAsmCond;
findreg_by_numbernull364     function findreg_by_number(r:Tregister):tregisterindex;
std_regnum_searchnull365     function std_regnum_search(const s:string):Tregister;
std_regnamenull366     function std_regname(r:Tregister):string;
367 
inverse_condnull368     function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
conditions_equalnull369     function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
370 
371     procedure shifterop_reset(var so : tshifterop); {$ifdef USEINLINE}inline;{$endif USEINLINE}
is_pcnull372     function is_pc(const r : tregister) : boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
373 
is_shifter_constnull374     function is_shifter_const(d : aint;var imm_shift : byte) : boolean;
is_thumb_immnull375     function is_thumb_imm(d: aint): boolean;
376     { Returns true if d is a valid constant for thumb 32 bit,
377       doesn't handle ROR_C detection }
is_thumb32_immnull378     function is_thumb32_imm(d : aint) : boolean;
split_into_shifter_constnull379     function split_into_shifter_const(value : aint;var imm1: dword; var imm2: dword):boolean;
is_continuous_masknull380     function is_continuous_mask(d : aword;var lsb, width: byte) : boolean;
dwarf_regnull381     function dwarf_reg(r:tregister):shortint;
dwarf_reg_no_errornull382     function dwarf_reg_no_error(r:tregister):shortint;
383 
IsITnull384     function IsIT(op: TAsmOp) : boolean;
GetITLevelsnull385     function GetITLevels(op: TAsmOp) : longint;
386 
GenerateARMCodenull387     function GenerateARMCode : boolean;
GenerateThumbCodenull388     function GenerateThumbCode : boolean;
GenerateThumb2Codenull389     function GenerateThumb2Code : boolean;
390 
IsVFPFloatImmediatenull391     function IsVFPFloatImmediate(ft : tfloattype;value : bestreal) : boolean;
392 
393   implementation
394 
395     uses
396       systems,rgBase,verbose;
397 
398 
399     const
400       std_regname_table : TRegNameTable = (
401         {$i rarmstd.inc}
402       );
403 
404       regnumber_index : array[tregisterindex] of tregisterindex = (
405         {$i rarmrni.inc}
406       );
407 
408       std_regname_index : array[tregisterindex] of tregisterindex = (
409         {$i rarmsri.inc}
410       );
411 
412 
cgsize2subregnull413     function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
414       begin
415         case regtype of
416           R_MMREGISTER:
417             begin
418               case s of
419                 OS_F32:
420                   cgsize2subreg:=R_SUBFS;
421                 OS_F64:
422                   cgsize2subreg:=R_SUBFD;
423                 else
424                   internalerror(2009112701);
425               end;
426             end;
427           else
428             cgsize2subreg:=R_SUBWHOLE;
429         end;
430       end;
431 
432 
reg_cgsizenull433     function reg_cgsize(const reg: tregister): tcgsize;
434       begin
435         case getregtype(reg) of
436           R_INTREGISTER :
437             reg_cgsize:=OS_32;
438           R_FPUREGISTER :
439             reg_cgsize:=OS_F80;
440           R_MMREGISTER :
441             begin
442               case getsubreg(reg) of
443                 R_SUBFD,
444                 R_SUBWHOLE:
445                   result:=OS_F64;
446                 R_SUBFS:
447                   result:=OS_F32;
448                 else
449                   internalerror(2009112903);
450               end;
451             end;
452           else
453             internalerror(200303181);
454           end;
455         end;
456 
457 
is_calljmpnull458     function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
459       begin
460         { This isn't 100% perfect because the arm allows jumps also by writing to PC=R15.
461           To overcome this problem we simply forbid that FPC generates jumps by loading R15 }
462         is_calljmp:= o in [A_B,A_BL,A_BX,A_BLX];
463       end;
464 
465 
466     procedure inverse_flags(var f: TResFlags);
467       const
468         inv_flags: array[TResFlags] of TResFlags =
469           (F_NE,F_EQ,F_CC,F_CS,F_PL,F_MI,F_VC,F_VS,F_LS,F_HI,
470           F_LT,F_GE,F_LE,F_GT);
471       begin
472         f:=inv_flags[f];
473       end;
474 
475 
flags_to_condnull476     function flags_to_cond(const f: TResFlags) : TAsmCond;
477       const
478         flag_2_cond: array[F_EQ..F_LE] of TAsmCond =
479           (C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
480            C_GE,C_LT,C_GT,C_LE);
481       begin
482         if f>high(flag_2_cond) then
483           internalerror(200112301);
484         result:=flag_2_cond[f];
485       end;
486 
487 
findreg_by_numbernull488     function findreg_by_number(r:Tregister):tregisterindex;
489       begin
490         result:=rgBase.findreg_by_number_table(r,regnumber_index);
491       end;
492 
493 
std_regnum_searchnull494     function std_regnum_search(const s:string):Tregister;
495       begin
496         result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
497       end;
498 
499 
std_regnamenull500     function std_regname(r:Tregister):string;
501       var
502         p : tregisterindex;
503       begin
504         p:=findreg_by_number_table(r,regnumber_index);
505         if p<>0 then
506           result:=std_regname_table[p]
507         else
508           result:=generic_regname(r);
509       end;
510 
511 
512     procedure shifterop_reset(var so : tshifterop);{$ifdef USEINLINE}inline;{$endif USEINLINE}
513       begin
514         FillChar(so,sizeof(so),0);
515       end;
516 
517 
is_pcnull518     function is_pc(const r : tregister) : boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
519       begin
520         is_pc:=(r=NR_R15);
521       end;
522 
523 
inverse_condnull524     function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
525       const
526         inverse: array[TAsmCond] of TAsmCond=(C_None,
527           C_NE,C_EQ,C_CC,C_CS,C_PL,C_MI,C_VC,C_VS,C_LS,C_HI,
528           C_LT,C_GE,C_LE,C_GT,C_None,C_None
529         );
530       begin
531         result := inverse[c];
532       end;
533 
534 
conditions_equalnull535     function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
536       begin
537         result := c1 = c2;
538       end;
539 
540 
is_shifter_constnull541     function is_shifter_const(d : aint;var imm_shift : byte) : boolean;
542       var
543          i : longint;
544       begin
545         if GenerateThumb2Code then
546           begin
547             for i:=0 to 24 do
548               begin
549                  if (dword(d) and not($ff shl i))=0 then
550                    begin
551                      imm_shift:=i;
552                      result:=true;
553                      exit;
554                    end;
555               end;
556           end
557         else
558           begin
559             for i:=0 to 15 do
560               begin
561                  if (dword(d) and not(roldword($ff,i*2)))=0 then
562                    begin
563                       imm_shift:=i*2;
564                       result:=true;
565                       exit;
566                    end;
567               end;
568           end;
569         result:=false;
570       end;
571 
572 
is_thumb_immnull573     function is_thumb_imm(d: aint): boolean;
574       begin
575         result:=(d and $FF) = d;
576       end;
577 
578 
is_thumb32_immnull579     function is_thumb32_imm(d: aint): boolean;
580       var
581         t : aint;
582         i : longint;
583       begin
584         {Loading 0-255 is simple}
585         if (d and $FF) = d then
586           result:=true
587         { If top and bottom are equal, check if either all 4 bytes are equal
588           or byte 0 and 2 or byte 1 and 3 are equal }
589         else if ((d shr 16)=(d and $FFFF)) and
590                 (
591                   ((d and $FF00FF00) = 0) or
592                   ((d and $00FF00FF) = 0) or
593                   ((d shr 8)=(d and $FF))
594                 ) then
595           result:=true
596         {Can an 8-bit value be shifted accordingly?}
597         else
598           begin
599             result:=false;
600             for i:=8 to 31 do
601               begin
602                 t:=RolDWord(d,i);
603                 if ((t and $FF)=t) and
604                    ((t and $80)=$80) then
605                   begin
606                     result:=true;
607                     exit;
608                   end;
609               end;
610           end;
611       end;
612 
is_continuous_masknull613     function is_continuous_mask(d : aword;var lsb, width: byte) : boolean;
614       var
615         msb : byte;
616       begin
617         lsb:=BsfDword(d);
618         msb:=BsrDword(d);
619 
620         width:=msb-lsb+1;
621 
622         result:=(lsb<>255) and (msb<>255) and (aword(((1 shl (msb-lsb+1))-1) shl lsb) = d);
623       end;
624 
625 
split_into_shifter_constnull626     function split_into_shifter_const(value : aint;var imm1: dword; var imm2: dword) : boolean;
627       var
628         d, i, i2: Dword;
629       begin
630         Result:=false;
631         {Thumb2 is not supported (YET?)}
632         if GenerateThumb2Code then exit;
633         d:=DWord(value);
634         for i:=0 to 15 do
635           begin
636             imm1:=d and rordword($FF, I*2);
637             imm2:=d and not (imm1); {remove already found bits}
638             {is the remainder a shifterconst? YAY! we've done it!}
639             {Could we start from i instead of 0?}
640             for i2:=0 to 15 do
641               begin
642                  if (imm2 and not(rordword($FF,i2*2)))=0 then
643                    begin
644                       result:=true;
645                       exit;
646                    end;
647               end;
648           end;
649       end;
650 
dwarf_regnull651     function dwarf_reg(r:tregister):shortint;
652       begin
653         result:=regdwarf_table[findreg_by_number(r)];
654         if result=-1 then
655           internalerror(200603251);
656       end;
657 
dwarf_reg_no_errornull658     function dwarf_reg_no_error(r:tregister):shortint;
659       begin
660         result:=regdwarf_table[findreg_by_number(r)];
661       end;
662 
663       { Low part of 64bit return value }
NR_FUNCTION_RESULT64_LOW_REGnull664     function NR_FUNCTION_RESULT64_LOW_REG: tregister; {$ifdef USEINLINE}inline;{$endif USEINLINE}
665     begin
666       if target_info.endian=endian_little then
667         result:=NR_R0
668       else
669         result:=NR_R1;
670     end;
671 
RS_FUNCTION_RESULT64_LOW_REGnull672     function RS_FUNCTION_RESULT64_LOW_REG: shortint; {$ifdef USEINLINE}inline;{$endif USEINLINE}
673     begin
674       if target_info.endian=endian_little then
675         result:=RS_R0
676       else
677         result:=RS_R1;
678     end;
679 
680       { High part of 64bit return value }
NR_FUNCTION_RESULT64_HIGH_REGnull681     function NR_FUNCTION_RESULT64_HIGH_REG: tregister; {$ifdef USEINLINE}inline;{$endif USEINLINE}
682     begin
683       if target_info.endian=endian_little then
684         result:=NR_R1
685       else
686         result:=NR_R0;
687     end;
688 
RS_FUNCTION_RESULT64_HIGH_REGnull689     function RS_FUNCTION_RESULT64_HIGH_REG: shortint; {$ifdef USEINLINE}inline;{$endif USEINLINE}
690     begin
691       if target_info.endian=endian_little then
692         result:=RS_R1
693       else
694         result:=RS_R0;
695     end;
696 
IsITnull697     function IsIT(op: TAsmOp) : boolean;
698       begin
699         case op of
700           A_IT,
701           A_ITE, A_ITT,
702           A_ITEE, A_ITTE, A_ITET, A_ITTT,
703           A_ITEEE, A_ITTEE, A_ITETE, A_ITTTE,
704           A_ITEET, A_ITTET, A_ITETT, A_ITTTT:
705             result:=true;
706         else
707           result:=false;
708         end;
709       end;
710 
GetITLevelsnull711     function GetITLevels(op: TAsmOp) : longint;
712       begin
713         case op of
714           A_IT:
715             result:=1;
716           A_ITE, A_ITT:
717             result:=2;
718           A_ITEE, A_ITTE, A_ITET, A_ITTT:
719             result:=3;
720           A_ITEEE, A_ITTEE, A_ITETE, A_ITTTE,
721           A_ITEET, A_ITTET, A_ITETT, A_ITTTT:
722             result:=4;
723         else
724           result:=0;
725         end;
726       end;
727 
728 
GenerateARMCodenull729     function GenerateARMCode : boolean;
730       begin
731         Result:=current_settings.instructionset=is_arm;
732       end;
733 
734 
GenerateThumbCodenull735     function GenerateThumbCode : boolean;
736       begin
737         Result:=(current_settings.instructionset=is_thumb) and not(CPUARM_HAS_THUMB2 in cpu_capabilities[current_settings.cputype]);
738       end;
739 
740 
GenerateThumb2Codenull741     function GenerateThumb2Code : boolean;
742       begin
743         Result:=(current_settings.instructionset=is_thumb) and (CPUARM_HAS_THUMB2 in cpu_capabilities[current_settings.cputype]);
744       end;
745 
746 
IsVFPFloatImmediatenull747     function IsVFPFloatImmediate(ft : tfloattype;value : bestreal) : boolean;
748       var
749         singlerec : tcompsinglerec;
750         doublerec : tcompdoublerec;
751       begin
752         Result:=false;
753         case ft of
754           s32real:
755             begin
756               singlerec.value:=value;
757               singlerec:=tcompsinglerec(NtoLE(DWord(singlerec)));
758               Result:=(singlerec.bytes[0]=0) and (singlerec.bytes[1]=0) and ((singlerec.bytes[2] and 7)=0)  and
759                 (((singlerec.bytes[3] and $7e)=$40) or ((singlerec.bytes[3] and $7e)=$3e));
760             end;
761           s64real:
762             begin
763               doublerec.value:=value;
764               doublerec:=tcompdoublerec(NtoLE(QWord(doublerec)));
765               Result:=(doublerec.bytes[0]=0) and (doublerec.bytes[1]=0) and (doublerec.bytes[2]=0) and
766                       (doublerec.bytes[3]=0) and (doublerec.bytes[4]=0) and (doublerec.bytes[5]=0) and
767                       ((((doublerec.bytes[6] and $7f)=$40) and ((doublerec.bytes[7] and $c0)=0)) or
768                        (((doublerec.bytes[6] and $7f)=$3f) and ((doublerec.bytes[7] and $c0)=$c0)));
769             end;
770         end;
771       end;
772 
773 
774 end.
775 
776