mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 15:31:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			506 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			506 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
 | |
| 
 | |
|     Contains the base types for the i386 and x86-64 architecture
 | |
| 
 | |
|     * This code was inspired by the NASM sources
 | |
|       The Netwide Assembler is Copyright (c) 1996 Simon Tatham and
 | |
|       Julian Hall. All rights reserved.
 | |
| 
 | |
|     This program is free software; you can redistribute it and/or modify
 | |
|     it under the terms of the GNU General Public License as published by
 | |
|     the Free Software Foundation; either version 2 of the License, or
 | |
|     (at your option) any later version.
 | |
| 
 | |
|     This program is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU General Public License
 | |
|     along with this program; if not, write to the Free Software
 | |
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
| 
 | |
|  ****************************************************************************
 | |
| }
 | |
| {# Base unit for processor information. This unit contains
 | |
|    enumerations of registers, opcodes, sizes, and other
 | |
|    such things which are processor specific.
 | |
| }
 | |
| unit cpubase;
 | |
| 
 | |
| {$i fpcdefs.inc}
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses
 | |
|   cutils,cclasses,
 | |
|   globtype,
 | |
|   cgbase
 | |
|   ;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                 Assembler Opcodes
 | |
| *****************************************************************************}
 | |
| 
 | |
|     type
 | |
| {$ifdef x86_64}
 | |
|       TAsmOp={$i x8664op.inc}
 | |
| {$else x86_64}
 | |
|       TAsmOp={$i i386op.inc}
 | |
| {$endif x86_64}
 | |
| 
 | |
|       { This should define the array of instructions as string }
 | |
|       op2strtable=array[tasmop] of string[15];
 | |
| 
 | |
|     const
 | |
|       { First value of opcode enumeration }
 | |
|       firstop = low(tasmop);
 | |
|       { Last value of opcode enumeration  }
 | |
|       lastop  = high(tasmop);
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                   Registers
 | |
| *****************************************************************************}
 | |
| 
 | |
|    const
 | |
|       { Invalid register number }
 | |
|       RS_INVALID    = $ff;
 | |
| 
 | |
|       { Integer Super registers }
 | |
|       RS_RAX        = $00;      {EAX}
 | |
|       RS_RCX        = $01;      {ECX}
 | |
|       RS_RDX        = $02;      {EDX}
 | |
|       RS_RBX        = $03;      {EBX}
 | |
|       RS_RSI        = $04;      {ESI}
 | |
|       RS_RDI        = $05;      {EDI}
 | |
|       RS_RBP        = $06;      {EBP}
 | |
|       RS_RSP        = $07;      {ESP}
 | |
|       RS_R8         = $08;      {R8}
 | |
|       RS_R9         = $09;      {R9}
 | |
|       RS_R10        = $0a;      {R10}
 | |
|       RS_R11        = $0b;      {R11}
 | |
|       RS_R12        = $0c;      {R12}
 | |
|       RS_R13        = $0d;      {R13}
 | |
|       RS_R14        = $0e;      {R14}
 | |
|       RS_R15        = $0f;      {R15}
 | |
|       { create aliases to allow code sharing between x86-64 and i386 }
 | |
|       RS_EAX        = RS_RAX;
 | |
|       RS_EBX        = RS_RBX;
 | |
|       RS_ECX        = RS_RCX;
 | |
|       RS_EDX        = RS_RDX;
 | |
|       RS_ESI        = RS_RSI;
 | |
|       RS_EDI        = RS_RDI;
 | |
|       RS_EBP        = RS_RBP;
 | |
|       RS_ESP        = RS_RSP;
 | |
| 
 | |
|       { Number of first imaginary register }
 | |
|       first_int_imreg     = $10;
 | |
| 
 | |
|       { Float Super registers }
 | |
|       RS_ST0        = $00;
 | |
|       RS_ST1        = $01;
 | |
|       RS_ST2        = $02;
 | |
|       RS_ST3        = $03;
 | |
|       RS_ST4        = $04;
 | |
|       RS_ST5        = $05;
 | |
|       RS_ST6        = $06;
 | |
|       RS_ST7        = $07;
 | |
| 
 | |
|       { Number of first imaginary register }
 | |
|       first_fpu_imreg     = $08;
 | |
| 
 | |
|       { MM Super registers }
 | |
|       RS_XMM0        = $00;
 | |
|       RS_XMM1        = $01;
 | |
|       RS_XMM2        = $02;
 | |
|       RS_XMM3        = $03;
 | |
|       RS_XMM4        = $04;
 | |
|       RS_XMM5        = $05;
 | |
|       RS_XMM6        = $06;
 | |
|       RS_XMM7        = $07;
 | |
|       RS_XMM8        = $08;
 | |
|       RS_XMM9        = $09;
 | |
|       RS_XMM10       = $0a;
 | |
|       RS_XMM11       = $0b;
 | |
|       RS_XMM12       = $0c;
 | |
|       RS_XMM13       = $0d;
 | |
|       RS_XMM14       = $0e;
 | |
|       RS_XMM15       = $0f;
 | |
| 
 | |
|       { Number of first imaginary register }
 | |
| {$ifdef x86_64}
 | |
|       first_mm_imreg     = $10;
 | |
| {$else x86_64}
 | |
|       first_mm_imreg     = $08;
 | |
| {$endif x86_64}
 | |
| 
 | |
|       { The subregister that specifies the entire register and an address }
 | |
| {$ifdef x86_64}
 | |
|       { Hammer }
 | |
|       R_SUBWHOLE    = R_SUBQ;
 | |
|       R_SUBADDR     = R_SUBQ;
 | |
| {$else x86_64}
 | |
|       { i386 }
 | |
|       R_SUBWHOLE    = R_SUBD;
 | |
|       R_SUBADDR     = R_SUBD;
 | |
| {$endif x86_64}
 | |
| 
 | |
|       { Available Registers }
 | |
| {$ifdef x86_64}
 | |
|       {$i r8664con.inc}
 | |
| {$else x86_64}
 | |
|       {$i r386con.inc}
 | |
| {$endif x86_64}
 | |
| 
 | |
|     type
 | |
|       { Number of registers used for indexing in tables }
 | |
| {$ifdef x86_64}
 | |
|       tregisterindex=0..{$i r8664nor.inc}-1;
 | |
| {$else x86_64}
 | |
|       tregisterindex=0..{$i r386nor.inc}-1;
 | |
| {$endif x86_64}
 | |
| 
 | |
|     const
 | |
| { TODO: Calculate bsstart}
 | |
|       regnumber_count_bsstart = 64;
 | |
| 
 | |
|       regnumber_table : array[tregisterindex] of tregister = (
 | |
| {$ifdef x86_64}
 | |
|         {$i r8664num.inc}
 | |
| {$else x86_64}
 | |
|         {$i r386num.inc}
 | |
| {$endif x86_64}
 | |
|       );
 | |
| 
 | |
|       regstabs_table : array[tregisterindex] of shortint = (
 | |
| {$ifdef x86_64}
 | |
|         {$i r8664stab.inc}
 | |
| {$else x86_64}
 | |
|         {$i r386stab.inc}
 | |
| {$endif x86_64}
 | |
|       );
 | |
| 
 | |
|       regdwarf_table : array[tregisterindex] of shortint = (
 | |
| {$ifdef x86_64}
 | |
|         {$i r8664dwrf.inc}
 | |
| {$else x86_64}
 | |
|         {$i r386dwrf.inc}
 | |
| {$endif x86_64}
 | |
|       );
 | |
| 
 | |
|    type
 | |
|       totherregisterset = set of tregisterindex;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                 Conditions
 | |
| *****************************************************************************}
 | |
| 
 | |
|     type
 | |
|       TAsmCond=(C_None,
 | |
|         C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE,
 | |
|         C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP,
 | |
|         C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z
 | |
|       );
 | |
| 
 | |
|     const
 | |
|       cond2str:array[TAsmCond] of string[3]=('',
 | |
|         'a','ae','b','be','c','e','g','ge','l','le','na','nae',
 | |
|         'nb','nbe','nc','ne','ng','nge','nl','nle','no','np',
 | |
|         'ns','nz','o','p','pe','po','s','z'
 | |
|       );
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                    Flags
 | |
| *****************************************************************************}
 | |
| 
 | |
|     type
 | |
|       TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,
 | |
|                    F_A,F_AE,F_B,F_BE,
 | |
|                    F_S,F_NS,F_O,F_NO);
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                  Constants
 | |
| *****************************************************************************}
 | |
| 
 | |
|     const
 | |
|       { declare aliases }
 | |
|       LOC_SSEREGISTER = LOC_MMREGISTER;
 | |
|       LOC_CSSEREGISTER = LOC_CMMREGISTER;
 | |
| 
 | |
|       max_operands = 3;
 | |
|       maxfpuregs = 8;
 | |
| 
 | |
| {*****************************************************************************
 | |
|                             CPU Dependent Constants
 | |
| *****************************************************************************}
 | |
| 
 | |
|     {$i cpubase.inc}
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                   Helpers
 | |
| *****************************************************************************}
 | |
| 
 | |
|     function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
 | |
|     function reg2opsize(r:Tregister):topsize;
 | |
|     function reg_cgsize(const reg: tregister): tcgsize;
 | |
|     function is_calljmp(o:tasmop):boolean;
 | |
|     procedure inverse_flags(var f: TResFlags);
 | |
|     function flags_to_cond(const f: TResFlags) : TAsmCond;
 | |
|     function is_segment_reg(r:tregister):boolean;
 | |
|     function findreg_by_number(r:Tregister):tregisterindex;
 | |
|     function std_regnum_search(const s:string):Tregister;
 | |
|     function std_regname(r:Tregister):string;
 | |
|     function dwarf_reg(r:tregister):shortint;
 | |
| 
 | |
|     function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
 | |
|     function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
 | |
| 
 | |
| implementation
 | |
| 
 | |
|     uses
 | |
|       rgbase,verbose;
 | |
| 
 | |
|     const
 | |
|     {$ifdef x86_64}
 | |
|       std_regname_table : array[tregisterindex] of string[7] = (
 | |
|         {$i r8664std.inc}
 | |
|       );
 | |
| 
 | |
|       regnumber_index : array[tregisterindex] of tregisterindex = (
 | |
|         {$i r8664rni.inc}
 | |
|       );
 | |
|       std_regname_index : array[tregisterindex] of tregisterindex = (
 | |
|         {$i r8664sri.inc}
 | |
|       );
 | |
|     {$else x86_64}
 | |
|       std_regname_table : array[tregisterindex] of string[7] = (
 | |
|         {$i r386std.inc}
 | |
|       );
 | |
| 
 | |
|       regnumber_index : array[tregisterindex] of tregisterindex = (
 | |
|         {$i r386rni.inc}
 | |
|       );
 | |
| 
 | |
|       std_regname_index : array[tregisterindex] of tregisterindex = (
 | |
|         {$i r386sri.inc}
 | |
|       );
 | |
|     {$endif x86_64}
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                   Helpers
 | |
| *****************************************************************************}
 | |
| 
 | |
|     function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
 | |
|       begin
 | |
|         case s of
 | |
|           OS_8,OS_S8:
 | |
|             cgsize2subreg:=R_SUBL;
 | |
|           OS_16,OS_S16:
 | |
|             cgsize2subreg:=R_SUBW;
 | |
|           OS_32,OS_S32:
 | |
|             cgsize2subreg:=R_SUBD;
 | |
|           OS_64,OS_S64:
 | |
|             cgsize2subreg:=R_SUBQ;
 | |
|           OS_M64:
 | |
|             cgsize2subreg:=R_SUBNONE;
 | |
|           OS_F32,OS_F64,OS_C64:
 | |
|             case regtype of
 | |
|               R_FPUREGISTER:
 | |
|                 cgsize2subreg:=R_SUBWHOLE;
 | |
|               R_MMREGISTER:
 | |
|                 case s of
 | |
|                   OS_F32:
 | |
|                     cgsize2subreg:=R_SUBMMS;
 | |
|                   OS_F64:
 | |
|                     cgsize2subreg:=R_SUBMMD;
 | |
|                   else
 | |
|                     internalerror(2009071901);
 | |
|                 end;
 | |
|               else
 | |
|                 internalerror(2009071902);
 | |
|             end;
 | |
|           OS_M128,OS_MS128:
 | |
|             cgsize2subreg:=R_SUBMMWHOLE;
 | |
|           else
 | |
|             internalerror(200301231);
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function reg_cgsize(const reg: tregister): tcgsize;
 | |
|       const subreg2cgsize:array[Tsubregister] of Tcgsize =
 | |
|             (OS_NO,OS_8,OS_8,OS_16,OS_32,OS_64,OS_NO,OS_NO,OS_NO,OS_F32,OS_F64,OS_M128);
 | |
|       begin
 | |
|         case getregtype(reg) of
 | |
|           R_INTREGISTER :
 | |
|             reg_cgsize:=subreg2cgsize[getsubreg(reg)];
 | |
|           R_FPUREGISTER :
 | |
|             reg_cgsize:=OS_F80;
 | |
|           R_MMXREGISTER:
 | |
|             reg_cgsize:=OS_M64;
 | |
|           R_MMREGISTER:
 | |
|             reg_cgsize:=subreg2cgsize[getsubreg(reg)];
 | |
|           R_SPECIALREGISTER :
 | |
|             case reg of
 | |
|               NR_CS,NR_DS,NR_ES,NR_SS,NR_FS,NR_GS:
 | |
|                 reg_cgsize:=OS_16
 | |
|               else
 | |
|                 reg_cgsize:=OS_32
 | |
|             end
 | |
|           else
 | |
|             internalerror(200303181);
 | |
|           end;
 | |
|         end;
 | |
| 
 | |
| 
 | |
|     function reg2opsize(r:Tregister):topsize;
 | |
|       const
 | |
|         subreg2opsize : array[tsubregister] of topsize =
 | |
|           (S_NO,S_B,S_B,S_W,S_L,S_Q,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
 | |
|       begin
 | |
|         reg2opsize:=S_L;
 | |
|         case getregtype(r) of
 | |
|           R_INTREGISTER :
 | |
|             reg2opsize:=subreg2opsize[getsubreg(r)];
 | |
|           R_FPUREGISTER :
 | |
|             reg2opsize:=S_FL;
 | |
|           R_MMXREGISTER,
 | |
|           R_MMREGISTER :
 | |
|             reg2opsize:=S_MD;
 | |
|           R_SPECIALREGISTER :
 | |
|             begin
 | |
|               case r of
 | |
|                 NR_CS,NR_DS,NR_ES,
 | |
|                 NR_SS,NR_FS,NR_GS :
 | |
|                   reg2opsize:=S_W;
 | |
|               end;
 | |
|             end;
 | |
|           else
 | |
|             internalerror(200303181);
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function is_calljmp(o:tasmop):boolean;
 | |
|       begin
 | |
|         case o of
 | |
|           A_CALL,
 | |
| {$ifdef i386}
 | |
|           A_JCXZ,
 | |
| {$endif i386}
 | |
|           A_JECXZ,
 | |
| {$ifdef x86_64}
 | |
|           A_JRCXZ,
 | |
| {$endif x86_64}
 | |
|           A_JMP,
 | |
|           A_LOOP,
 | |
|           A_LOOPE,
 | |
|           A_LOOPNE,
 | |
|           A_LOOPNZ,
 | |
|           A_LOOPZ,
 | |
|           A_Jcc :
 | |
|             is_calljmp:=true;
 | |
|           else
 | |
|             is_calljmp:=false;
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure inverse_flags(var f: TResFlags);
 | |
|       const
 | |
|         inv_flags: array[TResFlags] of TResFlags =
 | |
|           (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
 | |
|            F_BE,F_B,F_AE,F_A,
 | |
|            F_NS,F_S,F_NO,F_O);
 | |
|       begin
 | |
|         f:=inv_flags[f];
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function flags_to_cond(const f: TResFlags) : TAsmCond;
 | |
|       const
 | |
|         flags_2_cond : array[TResFlags] of TAsmCond =
 | |
|           (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE,C_S,C_NS,C_O,C_NO);
 | |
|       begin
 | |
|         result := flags_2_cond[f];
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function is_segment_reg(r:tregister):boolean;
 | |
|       begin
 | |
|         result:=false;
 | |
|         case r of
 | |
|           NR_CS,NR_DS,NR_ES,
 | |
|           NR_SS,NR_FS,NR_GS :
 | |
|             result:=true;
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function findreg_by_number(r:Tregister):tregisterindex;
 | |
|       var
 | |
|         hr : tregister;
 | |
|       begin
 | |
|         { for the name the sub reg doesn't matter }
 | |
|         hr:=r;
 | |
|         case getsubreg(hr) of
 | |
|           R_SUBMMS,R_SUBMMD,R_SUBMMWHOLE:
 | |
|             setsubreg(hr,R_SUBNONE);
 | |
|         end;
 | |
|         result:=findreg_by_number_table(hr,regnumber_index);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function std_regnum_search(const s:string):Tregister;
 | |
|       begin
 | |
|         result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function std_regname(r:Tregister):string;
 | |
|       var
 | |
|         p : tregisterindex;
 | |
|       begin
 | |
|         if getregtype(r) in [R_MMREGISTER,R_MMXREGISTER] then
 | |
|           r:=newreg(getregtype(r),getsupreg(r),R_SUBNONE);
 | |
|         p:=findreg_by_number_table(r,regnumber_index);
 | |
|         if p<>0 then
 | |
|           result:=std_regname_table[p]
 | |
|         else
 | |
|           result:=generic_regname(r);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
 | |
|       const
 | |
|         inverse: array[TAsmCond] of TAsmCond=(C_None,
 | |
|           C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE,
 | |
|           C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P,
 | |
|           C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ
 | |
|         );
 | |
|       begin
 | |
|         result := inverse[c];
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
 | |
|       begin
 | |
|         result := c1 = c2;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function dwarf_reg(r:tregister):shortint;
 | |
|       begin
 | |
|         result:=regdwarf_table[findreg_by_number(r)];
 | |
|         if result=-1 then
 | |
|           internalerror(200603251);
 | |
|       end;
 | |
| 
 | |
| 
 | |
| end.
 | 
