|
@@ -2,7 +2,7 @@
|
|
|
$Id$
|
|
|
Copyright (c) 1998-2002 by Florian Klaempfl
|
|
|
|
|
|
- This unit exports some help routines for the code generation
|
|
|
+ Some basic types and constants for the code generation
|
|
|
|
|
|
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
|
|
@@ -20,461 +20,310 @@
|
|
|
|
|
|
****************************************************************************
|
|
|
}
|
|
|
-{# Some helpers for the code generator.
|
|
|
-}
|
|
|
+{# This unit exports some types which are used across the code generator }
|
|
|
unit cgbase;
|
|
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
|
|
- interface
|
|
|
+interface
|
|
|
|
|
|
uses
|
|
|
- { common }
|
|
|
- cclasses,
|
|
|
- { global }
|
|
|
- globtype,globals,verbose,
|
|
|
- { symtable }
|
|
|
- symconst,symtype,symdef,symsym,
|
|
|
- { aasm }
|
|
|
- cpubase,cpuinfo,cginfo,aasmbase,aasmtai
|
|
|
- ;
|
|
|
-
|
|
|
+ cpuinfo,
|
|
|
+ symconst;
|
|
|
|
|
|
type
|
|
|
- tprocinfoflag=(
|
|
|
- {# procedure uses asm }
|
|
|
- pi_uses_asm,
|
|
|
- {# procedure does a call }
|
|
|
- pi_do_call,
|
|
|
- {# procedure has a try statement = no register optimization }
|
|
|
- pi_uses_exceptions,
|
|
|
- {# procedure is declared as @var(assembler), don't optimize}
|
|
|
- pi_is_assembler,
|
|
|
- {# procedure contains data which needs to be finalized }
|
|
|
- pi_needs_implicit_finally
|
|
|
+ { Location types where value can be stored }
|
|
|
+ TCGLoc=(
|
|
|
+ LOC_INVALID, { added for tracking problems}
|
|
|
+ LOC_VOID, { no value is available }
|
|
|
+ LOC_CONSTANT, { constant value }
|
|
|
+ LOC_JUMP, { boolean results only, jump to false or true label }
|
|
|
+ LOC_FLAGS, { boolean results only, flags are set }
|
|
|
+ LOC_CREFERENCE, { in memory constant value reference (cannot change) }
|
|
|
+ LOC_REFERENCE, { in memory value }
|
|
|
+ LOC_REGISTER, { in a processor register }
|
|
|
+ LOC_CREGISTER, { Constant register which shouldn't be modified }
|
|
|
+ LOC_FPUREGISTER, { FPU stack }
|
|
|
+ LOC_CFPUREGISTER, { if it is a FPU register variable on the fpu stack }
|
|
|
+ LOC_MMXREGISTER, { MMX register }
|
|
|
+ { MMX register variable }
|
|
|
+ LOC_CMMXREGISTER,
|
|
|
+ LOC_SSEREGISTER,
|
|
|
+ LOC_CSSEREGISTER,
|
|
|
+ { multimedia register }
|
|
|
+ LOC_MMREGISTER,
|
|
|
+ { Constant multimedia reg which shouldn't be modified }
|
|
|
+ LOC_CMMREGISTER
|
|
|
+ );
|
|
|
+
|
|
|
+ {# Generic opcodes, which must be supported by all processors
|
|
|
+ }
|
|
|
+ topcg =
|
|
|
+ (
|
|
|
+ OP_NONE,
|
|
|
+ OP_ADD, { simple addition }
|
|
|
+ OP_AND, { simple logical and }
|
|
|
+ OP_DIV, { simple unsigned division }
|
|
|
+ OP_IDIV, { simple signed division }
|
|
|
+ OP_IMUL, { simple signed multiply }
|
|
|
+ OP_MUL, { simple unsigned multiply }
|
|
|
+ OP_NEG, { simple negate }
|
|
|
+ OP_NOT, { simple logical not }
|
|
|
+ OP_OR, { simple logical or }
|
|
|
+ OP_SAR, { arithmetic shift-right }
|
|
|
+ OP_SHL, { logical shift left }
|
|
|
+ OP_SHR, { logical shift right }
|
|
|
+ OP_SUB, { simple subtraction }
|
|
|
+ OP_XOR { simple exclusive or }
|
|
|
+ );
|
|
|
+
|
|
|
+ {# Generic flag values - used for jump locations }
|
|
|
+ TOpCmp =
|
|
|
+ (
|
|
|
+ OC_NONE,
|
|
|
+ OC_EQ, { equality comparison }
|
|
|
+ OC_GT, { greater than (signed) }
|
|
|
+ OC_LT, { less than (signed) }
|
|
|
+ OC_GTE, { greater or equal than (signed) }
|
|
|
+ OC_LTE, { less or equal than (signed) }
|
|
|
+ OC_NE, { not equal }
|
|
|
+ OC_BE, { less or equal than (unsigned) }
|
|
|
+ OC_B, { less than (unsigned) }
|
|
|
+ OC_AE, { greater or equal than (unsigned) }
|
|
|
+ OC_A { greater than (unsigned) }
|
|
|
+ );
|
|
|
+
|
|
|
+ { OS_NO is also used memory references with large data that can
|
|
|
+ not be loaded in a register directly }
|
|
|
+ TCgSize = (OS_NO,
|
|
|
+ { integer registers }
|
|
|
+ OS_8,OS_16,OS_32,OS_64,OS_S8,OS_S16,OS_S32,OS_S64,
|
|
|
+ { single,double,extended,comp,float128 }
|
|
|
+ OS_F32,OS_F64,OS_F80,OS_C64,OS_F128,
|
|
|
+ { multi-media sizes: split in byte, word, dword, ... }
|
|
|
+ { entities, then the signed counterparts }
|
|
|
+ OS_M8,OS_M16,OS_M32,OS_M64,OS_M128,OS_MS8,OS_MS16,OS_MS32,
|
|
|
+ OS_MS64,OS_MS128);
|
|
|
+
|
|
|
+ { Register types }
|
|
|
+ TRegisterType = (
|
|
|
+ R_INVALIDREGISTER, { = 0 }
|
|
|
+ R_INTREGISTER, { = 1 }
|
|
|
+ R_FPUREGISTER, { = 2 }
|
|
|
+ { used by Intel only }
|
|
|
+ R_MMXREGISTER, { = 3 }
|
|
|
+ R_MMREGISTER, { = 4 }
|
|
|
+ R_SPECIALREGISTER, { = 5 }
|
|
|
+ R_ADDRESSREGISTER { = 6 }
|
|
|
);
|
|
|
- tprocinfoflags=set of tprocinfoflag;
|
|
|
|
|
|
- type
|
|
|
- {# This object gives information on the current routine being
|
|
|
- compiled.
|
|
|
- }
|
|
|
- tprocinfo = class(tlinkedlistitem)
|
|
|
- { pointer to parent in nested procedures }
|
|
|
- parent : tprocinfo;
|
|
|
- {# the definition of the routine itself }
|
|
|
- procdef : tprocdef;
|
|
|
- { file location of begin of procedure }
|
|
|
- entrypos : tfileposinfo;
|
|
|
- { file location of end of procedure }
|
|
|
- exitpos : tfileposinfo;
|
|
|
- { local switches at begin of procedure }
|
|
|
- entryswitches : tlocalswitches;
|
|
|
- { local switches at end of procedure }
|
|
|
- exitswitches : tlocalswitches;
|
|
|
-
|
|
|
- { Size of the parameters on the stack }
|
|
|
- para_stack_size : longint;
|
|
|
-
|
|
|
- {# some collected informations about the procedure
|
|
|
- see pi_xxxx constants above
|
|
|
- }
|
|
|
- flags : tprocinfoflags;
|
|
|
-
|
|
|
- { register used as frame pointer }
|
|
|
- framepointer : tregister;
|
|
|
-
|
|
|
- { Holds the reference used to store alll saved registers. }
|
|
|
- save_regs_ref : treference;
|
|
|
-
|
|
|
- { label to leave the sub routine }
|
|
|
- aktexitlabel : tasmlabel;
|
|
|
-
|
|
|
- {# The code for the routine itself, excluding entry and
|
|
|
- exit code. This is a linked list of tai classes.
|
|
|
- }
|
|
|
- aktproccode : taasmoutput;
|
|
|
- { Data (like jump tables) that belongs to this routine }
|
|
|
- aktlocaldata : taasmoutput;
|
|
|
-
|
|
|
- constructor create(aparent:tprocinfo);virtual;
|
|
|
- destructor destroy;override;
|
|
|
-
|
|
|
- { Allocate framepointer so it can not be used by the
|
|
|
- register allocator }
|
|
|
- procedure allocate_framepointer_reg;virtual;
|
|
|
-
|
|
|
- procedure allocate_push_parasize(size:longint);virtual;
|
|
|
-
|
|
|
- function calc_stackframe_size:longint;virtual;
|
|
|
-
|
|
|
- { Does the necessary stuff before a procedure body is compiled }
|
|
|
- procedure handle_body_start;virtual;
|
|
|
-
|
|
|
- { This procedure is called after the pass 1 of the subroutine body is done.
|
|
|
- Here the address fix ups to generate code for the body must be done.
|
|
|
- }
|
|
|
- procedure after_pass1;virtual;
|
|
|
- end;
|
|
|
-
|
|
|
- pregvarinfo = ^tregvarinfo;
|
|
|
- tregvarinfo = record
|
|
|
- regvars : array[1..maxvarregs] of tvarsym;
|
|
|
- regvars_para : array[1..maxvarregs] of boolean;
|
|
|
- regvars_refs : array[1..maxvarregs] of longint;
|
|
|
-
|
|
|
- fpuregvars : array[1..maxfpuvarregs] of tvarsym;
|
|
|
- fpuregvars_para : array[1..maxfpuvarregs] of boolean;
|
|
|
- fpuregvars_refs : array[1..maxfpuvarregs] of longint;
|
|
|
- end;
|
|
|
-
|
|
|
- tcprocinfo = class of tprocinfo;
|
|
|
-
|
|
|
- var
|
|
|
- cprocinfo : tcprocinfo;
|
|
|
- {# information about the current sub routine being parsed (@var(pprocinfo))}
|
|
|
- current_procinfo : tprocinfo;
|
|
|
-
|
|
|
- { labels for BREAK and CONTINUE }
|
|
|
- aktbreaklabel,aktcontinuelabel : tasmlabel;
|
|
|
-
|
|
|
- { label when the result is true or false }
|
|
|
- truelabel,falselabel : tasmlabel;
|
|
|
-
|
|
|
- {# true, if there was an error while code generation occurs }
|
|
|
- codegenerror : boolean;
|
|
|
-
|
|
|
- { save the size of pushed parameter, needed for aligning }
|
|
|
- pushedparasize : longint;
|
|
|
-
|
|
|
- { message calls with codegenerror support }
|
|
|
- procedure cgmessage(t : longint);
|
|
|
- procedure cgmessage1(t : longint;const s : string);
|
|
|
- procedure cgmessage2(t : longint;const s1,s2 : string);
|
|
|
- procedure cgmessage3(t : longint;const s1,s2,s3 : string);
|
|
|
- procedure CGMessagePos(const pos:tfileposinfo;t:longint);
|
|
|
- procedure CGMessagePos1(const pos:tfileposinfo;t:longint;const s1:string);
|
|
|
- procedure CGMessagePos2(const pos:tfileposinfo;t:longint;const s1,s2:string);
|
|
|
- procedure CGMessagePos3(const pos:tfileposinfo;t:longint;const s1,s2,s3:string);
|
|
|
-
|
|
|
- { initialize respectively terminates the code generator }
|
|
|
- { for a new module or procedure }
|
|
|
- procedure codegen_newmodule;
|
|
|
- procedure codegen_donemodule;
|
|
|
-
|
|
|
- {# From a definition return the abstract code generator size enum. It is
|
|
|
- to note that the value returned can be @var(OS_NO) }
|
|
|
- function def_cgsize(def: tdef): tcgsize;
|
|
|
+ { Sub registers }
|
|
|
+ TSubRegister = (
|
|
|
+ R_SUBNONE, { = 0; no sub register possible }
|
|
|
+ R_SUBL, { = 1; 8 bits, Like AL }
|
|
|
+ R_SUBH, { = 2; 8 bits, Like AH }
|
|
|
+ R_SUBW, { = 3; 16 bits, Like AX }
|
|
|
+ R_SUBD, { = 4; 32 bits, Like EAX }
|
|
|
+ R_SUBQ { = 5; 64 bits, Like RAX }
|
|
|
+ );
|
|
|
+
|
|
|
+ TSuperRegister = type byte;
|
|
|
+
|
|
|
+ {
|
|
|
+ The new register coding:
|
|
|
+
|
|
|
+ SuperRegister (bits 0..7)
|
|
|
+ Unused (bits 8..15)
|
|
|
+ Subregister (bits 16..23)
|
|
|
+ Register type (bits 24..31)
|
|
|
+ }
|
|
|
+ TRegister = type cardinal;
|
|
|
+ TRegisterRec=packed record
|
|
|
+{$ifdef FPC_BIG_ENDIAN}
|
|
|
+ regtype : Tregistertype;
|
|
|
+ subreg : Tsubregister;
|
|
|
+ unused : byte;
|
|
|
+ supreg : Tsuperregister;
|
|
|
+{$else FPC_BIG_ENDIAN}
|
|
|
+ supreg : Tsuperregister;
|
|
|
+ unused : byte;
|
|
|
+ subreg : Tsubregister;
|
|
|
+ regtype : Tregistertype;
|
|
|
+{$endif FPC_BIG_ENDIAN}
|
|
|
+ end;
|
|
|
+
|
|
|
+ { A type to store register locations for 64 Bit values. }
|
|
|
+{$ifdef cpu64bit}
|
|
|
+ tregister64 = tregister;
|
|
|
+{$else cpu64bit}
|
|
|
+ tregister64 = packed record
|
|
|
+ reglo,reghi : tregister;
|
|
|
+ end;
|
|
|
+{$endif cpu64bit}
|
|
|
+
|
|
|
+ { Set type definition for registers }
|
|
|
+ tsuperregisterset = set of tsuperregister;
|
|
|
+
|
|
|
+ { Temp types }
|
|
|
+ ttemptype = (tt_none,
|
|
|
+ tt_free,tt_normal,tt_persistent,
|
|
|
+ tt_noreuse,tt_freenoreuse,
|
|
|
+ tt_ansistring,tt_freeansistring,
|
|
|
+ tt_widestring,tt_freewidestring,
|
|
|
+ tt_interfacecom,tt_freeinterfacecom);
|
|
|
+ ttemptypeset = set of ttemptype;
|
|
|
+
|
|
|
+
|
|
|
+ const
|
|
|
+ { Invalid register number }
|
|
|
+ RS_INVALID = $ff;
|
|
|
+
|
|
|
+ tcgsize2size : Array[tcgsize] of integer =
|
|
|
+ { integer values }
|
|
|
+ (0,1,2,4,8,1,2,4,8,
|
|
|
+ { floating point values }
|
|
|
+ 4,8,EXTENDED_SIZE,8,16,
|
|
|
+ { multimedia values }
|
|
|
+ 1,2,4,8,16,1,2,4,8,16);
|
|
|
+
|
|
|
+ tfloat2tcgsize: array[tfloattype] of tcgsize =
|
|
|
+ (OS_F32,OS_F64,OS_F80,OS_C64,OS_C64,OS_F128);
|
|
|
+
|
|
|
+ tcgsize2tfloat: array[OS_F32..OS_C64] of tfloattype =
|
|
|
+ (s32real,s64real,s80real,s64comp);
|
|
|
+
|
|
|
+ { Table to convert tcgsize variables to the correspondending
|
|
|
+ unsigned types }
|
|
|
+ tcgsize2unsigned : array[tcgsize] of tcgsize = (OS_NO,
|
|
|
+ OS_8,OS_16,OS_32,OS_64,OS_8,OS_16,OS_32,OS_64,
|
|
|
+ OS_F32,OS_F64,OS_F80,OS_C64,OS_F128,
|
|
|
+ OS_M8,OS_M16,OS_M32,OS_M64,OS_M128,OS_M8,OS_M16,OS_M32,
|
|
|
+ OS_M64,OS_M128);
|
|
|
+
|
|
|
+ tcgloc2str : array[TCGLoc] of string[11] = (
|
|
|
+ 'LOC_INVALID',
|
|
|
+ 'LOC_VOID',
|
|
|
+ 'LOC_CONST',
|
|
|
+ 'LOC_JUMP',
|
|
|
+ 'LOC_FLAGS',
|
|
|
+ 'LOC_CREF',
|
|
|
+ 'LOC_REF',
|
|
|
+ 'LOC_REG',
|
|
|
+ 'LOC_CREG',
|
|
|
+ 'LOC_FPUREG',
|
|
|
+ 'LOC_CFPUREG',
|
|
|
+ 'LOC_MMXREG',
|
|
|
+ 'LOC_CMMXREG',
|
|
|
+ 'LOC_SSEREG',
|
|
|
+ 'LOC_CSSEREG',
|
|
|
+ 'LOC_MMREG',
|
|
|
+ 'LOC_CMMREG');
|
|
|
+
|
|
|
+ function newreg(rt:tregistertype;sr:tsuperregister;sb:tsubregister):tregister;{$ifdef USEINLINE}inline;{$endif}
|
|
|
+ function getsubreg(r:tregister):tsubregister;{$ifdef USEINLINE}inline;{$endif}
|
|
|
+ function getsupreg(r:tregister):tsuperregister;{$ifdef USEINLINE}inline;{$endif}
|
|
|
+ function getregtype(r:tregister):tregistertype;{$ifdef USEINLINE}inline;{$endif}
|
|
|
+ procedure setsubreg(var r:tregister;sr:tsubregister);{$ifdef USEINLINE}inline;{$endif}
|
|
|
+ procedure setsupreg(var r:tregister;sr:tsuperregister);{$ifdef USEINLINE}inline;{$endif}
|
|
|
+ function generic_regname(r:tregister):string;
|
|
|
+
|
|
|
{# From a constant numeric value, return the abstract code generator
|
|
|
size.
|
|
|
}
|
|
|
function int_cgsize(const a: aword): tcgsize;
|
|
|
|
|
|
- {# return the inverse condition of opcmp }
|
|
|
+ { return the inverse condition of opcmp }
|
|
|
function inverse_opcmp(opcmp: topcmp): topcmp;
|
|
|
|
|
|
- {# return whether op is commutative }
|
|
|
+ { return whether op is commutative }
|
|
|
function commutativeop(op: topcg): boolean;
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
- uses
|
|
|
- cutils,systems,
|
|
|
- cresstr,
|
|
|
- tgobj,rgobj,
|
|
|
- defutil,
|
|
|
- fmodule
|
|
|
- ,symbase,paramgr
|
|
|
- ;
|
|
|
-
|
|
|
-
|
|
|
-{*****************************************************************************
|
|
|
- override the message calls to set codegenerror
|
|
|
-*****************************************************************************}
|
|
|
-
|
|
|
- procedure cgmessage(t : longint);
|
|
|
- var
|
|
|
- olderrorcount : longint;
|
|
|
- begin
|
|
|
- if not(codegenerror) then
|
|
|
- begin
|
|
|
- olderrorcount:=Errorcount;
|
|
|
- verbose.Message(t);
|
|
|
- codegenerror:=olderrorcount<>Errorcount;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- procedure cgmessage1(t : longint;const s : string);
|
|
|
- var
|
|
|
- olderrorcount : longint;
|
|
|
- begin
|
|
|
- if not(codegenerror) then
|
|
|
- begin
|
|
|
- olderrorcount:=Errorcount;
|
|
|
- verbose.Message1(t,s);
|
|
|
- codegenerror:=olderrorcount<>Errorcount;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- procedure cgmessage2(t : longint;const s1,s2 : string);
|
|
|
- var
|
|
|
- olderrorcount : longint;
|
|
|
- begin
|
|
|
- if not(codegenerror) then
|
|
|
- begin
|
|
|
- olderrorcount:=Errorcount;
|
|
|
- verbose.Message2(t,s1,s2);
|
|
|
- codegenerror:=olderrorcount<>Errorcount;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- procedure cgmessage3(t : longint;const s1,s2,s3 : string);
|
|
|
- var
|
|
|
- olderrorcount : longint;
|
|
|
- begin
|
|
|
- if not(codegenerror) then
|
|
|
- begin
|
|
|
- olderrorcount:=Errorcount;
|
|
|
- verbose.Message3(t,s1,s2,s3);
|
|
|
- codegenerror:=olderrorcount<>Errorcount;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
- procedure cgmessagepos(const pos:tfileposinfo;t : longint);
|
|
|
- var
|
|
|
- olderrorcount : longint;
|
|
|
- begin
|
|
|
- if not(codegenerror) then
|
|
|
- begin
|
|
|
- olderrorcount:=Errorcount;
|
|
|
- verbose.MessagePos(pos,t);
|
|
|
- codegenerror:=olderrorcount<>Errorcount;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- procedure cgmessagepos1(const pos:tfileposinfo;t : longint;const s1 : string);
|
|
|
- var
|
|
|
- olderrorcount : longint;
|
|
|
- begin
|
|
|
- if not(codegenerror) then
|
|
|
- begin
|
|
|
- olderrorcount:=Errorcount;
|
|
|
- verbose.MessagePos1(pos,t,s1);
|
|
|
- codegenerror:=olderrorcount<>Errorcount;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- procedure cgmessagepos2(const pos:tfileposinfo;t : longint;const s1,s2 : string);
|
|
|
- var
|
|
|
- olderrorcount : longint;
|
|
|
- begin
|
|
|
- if not(codegenerror) then
|
|
|
- begin
|
|
|
- olderrorcount:=Errorcount;
|
|
|
- verbose.MessagePos2(pos,t,s1,s2);
|
|
|
- codegenerror:=olderrorcount<>Errorcount;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- procedure cgmessagepos3(const pos:tfileposinfo;t : longint;const s1,s2,s3 : string);
|
|
|
- var
|
|
|
- olderrorcount : longint;
|
|
|
- begin
|
|
|
- if not(codegenerror) then
|
|
|
- begin
|
|
|
- olderrorcount:=Errorcount;
|
|
|
- verbose.MessagePos3(pos,t,s1,s2,s3);
|
|
|
- codegenerror:=olderrorcount<>Errorcount;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
-{****************************************************************************
|
|
|
- TProcInfo
|
|
|
-****************************************************************************}
|
|
|
-
|
|
|
- constructor tprocinfo.create(aparent:tprocinfo);
|
|
|
- begin
|
|
|
- parent:=aparent;
|
|
|
- procdef:=nil;
|
|
|
- para_stack_size:=0;
|
|
|
- flags:=[];
|
|
|
- framepointer:=NR_FRAME_POINTER_REG;
|
|
|
- { asmlists }
|
|
|
- aktproccode:=Taasmoutput.Create;
|
|
|
- aktlocaldata:=Taasmoutput.Create;
|
|
|
- reference_reset(save_regs_ref);
|
|
|
- { labels }
|
|
|
- objectlibrary.getlabel(aktexitlabel);
|
|
|
- end;
|
|
|
-
|
|
|
+ uses
|
|
|
+ verbose;
|
|
|
|
|
|
- destructor tprocinfo.destroy;
|
|
|
+ function newreg(rt:tregistertype;sr:tsuperregister;sb:tsubregister):tregister;{$ifdef USEINLINE}inline;{$endif}
|
|
|
begin
|
|
|
- aktproccode.free;
|
|
|
- aktlocaldata.free;
|
|
|
+ tregisterrec(result).regtype:=rt;
|
|
|
+ tregisterrec(result).unused:=0;
|
|
|
+ tregisterrec(result).supreg:=sr;
|
|
|
+ tregisterrec(result).subreg:=sb;
|
|
|
end;
|
|
|
|
|
|
|
|
|
- procedure tprocinfo.allocate_framepointer_reg;
|
|
|
+ function getsubreg(r:tregister):tsubregister;{$ifdef USEINLINE}inline;{$endif}
|
|
|
begin
|
|
|
- if framepointer=NR_FRAME_POINTER_REG then
|
|
|
- begin
|
|
|
- { Make sure the register allocator won't allocate registers
|
|
|
- into ebp }
|
|
|
- include(rg.used_in_proc_int,RS_FRAME_POINTER_REG);
|
|
|
- exclude(rg.unusedregsint,RS_FRAME_POINTER_REG);
|
|
|
- end;
|
|
|
+ result:=tregisterrec(r).subreg;
|
|
|
end;
|
|
|
|
|
|
|
|
|
- procedure tprocinfo.allocate_push_parasize(size:longint);
|
|
|
+ function getsupreg(r:tregister):tsuperregister;{$ifdef USEINLINE}inline;{$endif}
|
|
|
begin
|
|
|
+ result:=tregisterrec(r).supreg;
|
|
|
end;
|
|
|
|
|
|
|
|
|
- function tprocinfo.calc_stackframe_size:longint;
|
|
|
- var
|
|
|
- _align : longint;
|
|
|
+ function getregtype(r:tregister):tregistertype;{$ifdef USEINLINE}inline;{$endif}
|
|
|
begin
|
|
|
- { align to 4 bytes at least
|
|
|
- otherwise all those subl $2,%esp are meaningless PM }
|
|
|
- _align:=target_info.alignment.localalignmin;
|
|
|
- if _align<4 then
|
|
|
- _align:=4;
|
|
|
- result:=Align(tg.direction*tg.lasttemp,_align);
|
|
|
+ result:=tregisterrec(r).regtype;
|
|
|
end;
|
|
|
|
|
|
|
|
|
- procedure tprocinfo.handle_body_start;
|
|
|
+ procedure setsubreg(var r:tregister;sr:tsubregister);{$ifdef USEINLINE}inline;{$endif}
|
|
|
begin
|
|
|
+ tregisterrec(r).subreg:=sr;
|
|
|
end;
|
|
|
|
|
|
|
|
|
- procedure tprocinfo.after_pass1;
|
|
|
+ procedure setsupreg(var r:tregister;sr:tsuperregister);{$ifdef USEINLINE}inline;{$endif}
|
|
|
begin
|
|
|
+ tregisterrec(r).supreg:=sr;
|
|
|
end;
|
|
|
|
|
|
|
|
|
-{*****************************************************************************
|
|
|
- initialize/terminate the codegen for procedure and modules
|
|
|
-*****************************************************************************}
|
|
|
-
|
|
|
- procedure codegen_newmodule;
|
|
|
- begin
|
|
|
- exprasmlist:=taasmoutput.create;
|
|
|
- datasegment:=taasmoutput.create;
|
|
|
- codesegment:=taasmoutput.create;
|
|
|
- bsssegment:=taasmoutput.create;
|
|
|
- debuglist:=taasmoutput.create;
|
|
|
- withdebuglist:=taasmoutput.create;
|
|
|
- consts:=taasmoutput.create;
|
|
|
- rttilist:=taasmoutput.create;
|
|
|
- ResourceStringList:=Nil;
|
|
|
- importssection:=nil;
|
|
|
- exportssection:=nil;
|
|
|
- resourcesection:=nil;
|
|
|
- { resourcestrings }
|
|
|
- ResourceStrings:=TResourceStrings.Create;
|
|
|
- { use the librarydata from current_module }
|
|
|
- objectlibrary:=current_module.librarydata;
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
- procedure codegen_donemodule;
|
|
|
-{$ifdef MEMDEBUG}
|
|
|
+ function generic_regname(r:tregister):string;
|
|
|
var
|
|
|
- d : tmemdebug;
|
|
|
-{$endif}
|
|
|
- begin
|
|
|
-{$ifdef MEMDEBUG}
|
|
|
- d:=tmemdebug.create(current_module.modulename^+' - asmlists');
|
|
|
-{$endif}
|
|
|
- exprasmlist.free;
|
|
|
- codesegment.free;
|
|
|
- bsssegment.free;
|
|
|
- datasegment.free;
|
|
|
- debuglist.free;
|
|
|
- withdebuglist.free;
|
|
|
- consts.free;
|
|
|
- rttilist.free;
|
|
|
- if assigned(ResourceStringList) then
|
|
|
- ResourceStringList.free;
|
|
|
- if assigned(importssection) then
|
|
|
- importssection.free;
|
|
|
- if assigned(exportssection) then
|
|
|
- exportssection.free;
|
|
|
- if assigned(resourcesection) then
|
|
|
- resourcesection.free;
|
|
|
-{$ifdef MEMDEBUG}
|
|
|
- d.free;
|
|
|
-{$endif}
|
|
|
- { resource strings }
|
|
|
- ResourceStrings.free;
|
|
|
- objectlibrary:=nil;
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
- function def_cgsize(def: tdef): tcgsize;
|
|
|
+ t,sub : char;
|
|
|
+ nr : string[12];
|
|
|
begin
|
|
|
- case def.deftype of
|
|
|
- orddef,
|
|
|
- enumdef,
|
|
|
- setdef:
|
|
|
- begin
|
|
|
- result := int_cgsize(def.size);
|
|
|
- if is_signed(def) then
|
|
|
- result := tcgsize(ord(result)+(ord(OS_S8)-ord(OS_8)));
|
|
|
- end;
|
|
|
- classrefdef,
|
|
|
- pointerdef:
|
|
|
- result := OS_ADDR;
|
|
|
- procvardef:
|
|
|
- begin
|
|
|
- if tprocvardef(def).is_methodpointer and
|
|
|
- (not tprocvardef(def).is_addressonly) then
|
|
|
- result := OS_64
|
|
|
- else
|
|
|
- result := OS_ADDR;
|
|
|
- end;
|
|
|
- stringdef :
|
|
|
- begin
|
|
|
- if is_ansistring(def) or is_widestring(def) then
|
|
|
- result := OS_ADDR
|
|
|
- else
|
|
|
- result := OS_NO;
|
|
|
- end;
|
|
|
- objectdef :
|
|
|
- begin
|
|
|
- if is_class_or_interface(def) then
|
|
|
- result := OS_ADDR
|
|
|
- else
|
|
|
- result := OS_NO;
|
|
|
- end;
|
|
|
- floatdef:
|
|
|
- result := tfloat2tcgsize[tfloatdef(def).typ];
|
|
|
- recorddef :
|
|
|
- result:=int_cgsize(def.size);
|
|
|
- arraydef :
|
|
|
- begin
|
|
|
- if not is_special_array(def) then
|
|
|
- result := int_cgsize(def.size)
|
|
|
- else
|
|
|
- begin
|
|
|
- if is_dynamic_array(def) then
|
|
|
- result := OS_ADDR
|
|
|
- else
|
|
|
- result := OS_NO;
|
|
|
- end;
|
|
|
- end;
|
|
|
+ case getregtype(r) of
|
|
|
+ R_INTREGISTER:
|
|
|
+ t:='i';
|
|
|
+ R_FPUREGISTER:
|
|
|
+ t:='f';
|
|
|
+ R_MMXREGISTER:
|
|
|
+ t:='x';
|
|
|
+ R_MMREGISTER:
|
|
|
+ t:='m';
|
|
|
else
|
|
|
begin
|
|
|
- { undefined size }
|
|
|
- result:=OS_NO;
|
|
|
+ result:='INVALID';
|
|
|
+ exit;
|
|
|
end;
|
|
|
end;
|
|
|
+ str(getsupreg(r),nr);
|
|
|
+ case getsubreg(r) of
|
|
|
+ R_SUBNONE:
|
|
|
+ sub:=' ';
|
|
|
+ R_SUBL:
|
|
|
+ sub:='l';
|
|
|
+ R_SUBH:
|
|
|
+ sub:='h';
|
|
|
+ R_SUBW:
|
|
|
+ sub:='w';
|
|
|
+ R_SUBD:
|
|
|
+ sub:='d';
|
|
|
+ R_SUBQ:
|
|
|
+ sub:='q';
|
|
|
+ else
|
|
|
+ internalerror(200308252);
|
|
|
+ end;
|
|
|
+ if sub<>' ' then
|
|
|
+ result:=t+'reg'+nr+sub
|
|
|
+ else
|
|
|
+ result:=t+'reg'+nr;
|
|
|
end;
|
|
|
|
|
|
|
|
@@ -517,286 +366,14 @@ implementation
|
|
|
commutativeop := list[op];
|
|
|
end;
|
|
|
|
|
|
+
|
|
|
end.
|
|
|
{
|
|
|
$Log$
|
|
|
- Revision 1.66 2003-09-28 17:55:03 peter
|
|
|
- * parent framepointer changed to hidden parameter
|
|
|
- * tloadparentfpnode added
|
|
|
-
|
|
|
- Revision 1.65 2003/09/25 21:25:13 peter
|
|
|
- * remove allocate_intterupt_parameter, allocation is platform
|
|
|
- dependent and needs to be done in create_paraloc_info
|
|
|
-
|
|
|
- Revision 1.64 2003/09/23 17:56:05 peter
|
|
|
- * locals and paras are allocated in the code generation
|
|
|
- * tvarsym.localloc contains the location of para/local when
|
|
|
- generating code for the current procedure
|
|
|
-
|
|
|
- Revision 1.63 2003/09/14 19:18:10 peter
|
|
|
- * remove obsolete code already in comments
|
|
|
-
|
|
|
- Revision 1.62 2003/09/07 22:09:34 peter
|
|
|
- * preparations for different default calling conventions
|
|
|
- * various RA fixes
|
|
|
-
|
|
|
- Revision 1.61 2003/09/03 15:55:00 peter
|
|
|
- * NEWRA branch merged
|
|
|
-
|
|
|
- Revision 1.60.2.1 2003/08/29 17:28:59 peter
|
|
|
- * next batch of updates
|
|
|
-
|
|
|
- Revision 1.60 2003/08/26 12:43:02 peter
|
|
|
- * methodpointer fixes
|
|
|
-
|
|
|
- Revision 1.59 2003/08/20 17:48:49 peter
|
|
|
- * fixed stackalloc to not allocate localst.datasize twice
|
|
|
- * order of stackalloc code fixed for implicit init/final
|
|
|
-
|
|
|
- Revision 1.58 2003/08/11 21:18:20 peter
|
|
|
- * start of sparc support for newra
|
|
|
-
|
|
|
- Revision 1.57 2003/07/06 17:58:22 peter
|
|
|
- * framepointer fixes for sparc
|
|
|
- * parent framepointer code more generic
|
|
|
-
|
|
|
- Revision 1.56 2003/06/13 21:19:30 peter
|
|
|
- * current_procdef removed, use current_procinfo.procdef instead
|
|
|
-
|
|
|
- Revision 1.55 2003/06/12 16:43:07 peter
|
|
|
- * newra compiles for sparc
|
|
|
-
|
|
|
- Revision 1.54 2003/06/09 12:23:29 peter
|
|
|
- * init/final of procedure data splitted from genentrycode
|
|
|
- * use asmnode getposition to insert final at the correct position
|
|
|
- als for the implicit try...finally
|
|
|
-
|
|
|
- Revision 1.53 2003/06/02 21:42:05 jonas
|
|
|
- * function results can now also be regvars
|
|
|
- - removed tprocinfo.return_offset, never use it again since it's invalid
|
|
|
- if the result is a regvar
|
|
|
-
|
|
|
- Revision 1.52 2003/05/26 21:17:17 peter
|
|
|
- * procinlinenode removed
|
|
|
- * aktexit2label removed, fast exit removed
|
|
|
- + tcallnode.inlined_pass_2 added
|
|
|
-
|
|
|
- Revision 1.51 2003/05/23 14:27:35 peter
|
|
|
- * remove some unit dependencies
|
|
|
- * current_procinfo changes to store more info
|
|
|
-
|
|
|
- Revision 1.50 2003/05/16 20:54:12 jonas
|
|
|
- - undid previous commit, it wasn't necessary
|
|
|
-
|
|
|
- Revision 1.49 2003/05/16 20:00:39 jonas
|
|
|
- * powerpc nested procedure fixes, should work completely now if all
|
|
|
- local variables of the parent procedure are declared before the
|
|
|
- nested procedures are declared
|
|
|
-
|
|
|
- Revision 1.48 2003/05/15 18:58:53 peter
|
|
|
- * removed selfpointer_offset, vmtpointer_offset
|
|
|
- * tvarsym.adjusted_address
|
|
|
- * address in localsymtable is now in the real direction
|
|
|
- * removed some obsolete globals
|
|
|
-
|
|
|
- Revision 1.47 2003/05/13 19:14:41 peter
|
|
|
- * failn removed
|
|
|
- * inherited result code check moven to pexpr
|
|
|
-
|
|
|
- Revision 1.46 2003/05/09 17:47:02 peter
|
|
|
- * self moved to hidden parameter
|
|
|
- * removed hdisposen,hnewn,selfn
|
|
|
-
|
|
|
- Revision 1.45 2003/04/27 11:21:32 peter
|
|
|
- * aktprocdef renamed to current_procinfo.procdef
|
|
|
- * procinfo renamed to current_procinfo
|
|
|
- * procinfo will now be stored in current_module so it can be
|
|
|
- cleaned up properly
|
|
|
- * gen_main_procsym changed to create_main_proc and release_main_proc
|
|
|
- to also generate a tprocinfo structure
|
|
|
- * fixed unit implicit initfinal
|
|
|
-
|
|
|
- Revision 1.44 2003/04/27 07:29:50 peter
|
|
|
- * current_procinfo.procdef cleanup, current_procdef is now always nil when parsing
|
|
|
- a new procdef declaration
|
|
|
- * aktprocsym removed
|
|
|
- * lexlevel removed, use symtable.symtablelevel instead
|
|
|
- * implicit init/final code uses the normal genentry/genexit
|
|
|
- * funcret state checking updated for new funcret handling
|
|
|
-
|
|
|
- Revision 1.43 2003/04/26 00:31:42 peter
|
|
|
- * set return_offset moved to after_header
|
|
|
-
|
|
|
- Revision 1.42 2003/04/25 20:59:33 peter
|
|
|
- * removed funcretn,funcretsym, function result is now in varsym
|
|
|
- and aliases for result and function name are added using absolutesym
|
|
|
- * vs_hidden parameter for funcret passed in parameter
|
|
|
- * vs_hidden fixes
|
|
|
- * writenode changed to printnode and released from extdebug
|
|
|
- * -vp option added to generate a tree.log with the nodetree
|
|
|
- * nicer printnode for statements, callnode
|
|
|
-
|
|
|
- Revision 1.41 2003/04/23 12:35:34 florian
|
|
|
- * fixed several issues with powerpc
|
|
|
- + applied a patch from Jonas for nested function calls (PowerPC only)
|
|
|
- * ...
|
|
|
-
|
|
|
- Revision 1.40 2003/04/22 13:47:08 peter
|
|
|
- * fixed C style array of const
|
|
|
- * fixed C array passing
|
|
|
- * fixed left to right with high parameters
|
|
|
-
|
|
|
- Revision 1.39 2003/04/05 21:09:31 jonas
|
|
|
- * several ppc/generic result offset related fixes. The "normal" result
|
|
|
- offset seems now to be calculated correctly and a lot of duplicate
|
|
|
- calculations have been removed. Nested functions accessing the parent's
|
|
|
- function result don't work at all though :(
|
|
|
-
|
|
|
- Revision 1.38 2003/03/28 19:16:56 peter
|
|
|
- * generic constructor working for i386
|
|
|
- * remove fixed self register
|
|
|
- * esi added as address register for i386
|
|
|
-
|
|
|
- Revision 1.37 2003/03/20 17:51:45 peter
|
|
|
- * dynamic arrays have size OS_ADDR
|
|
|
-
|
|
|
- Revision 1.36 2003/01/08 18:43:56 daniel
|
|
|
- * Tregister changed into a record
|
|
|
-
|
|
|
- Revision 1.35 2003/01/01 21:04:48 peter
|
|
|
- * removed unused method
|
|
|
-
|
|
|
- Revision 1.34 2002/11/25 17:43:16 peter
|
|
|
- * splitted defbase in defutil,symutil,defcmp
|
|
|
- * merged isconvertable and is_equal into compare_defs(_ext)
|
|
|
- * made operator search faster by walking the list only once
|
|
|
-
|
|
|
- Revision 1.33 2002/11/18 17:31:54 peter
|
|
|
- * pass proccalloption to ret_in_xxx and push_xxx functions
|
|
|
-
|
|
|
- Revision 1.32 2002/10/05 12:43:23 carl
|
|
|
- * fixes for Delphi 6 compilation
|
|
|
- (warning : Some features do not work under Delphi)
|
|
|
-
|
|
|
- Revision 1.31 2002/10/03 21:20:19 carl
|
|
|
- * range check error fix
|
|
|
-
|
|
|
- Revision 1.30 2002/09/30 07:00:44 florian
|
|
|
- * fixes to common code to get the alpha compiler compiled applied
|
|
|
-
|
|
|
- Revision 1.29 2002/09/07 19:35:45 florian
|
|
|
- + tcg.direction is used now
|
|
|
-
|
|
|
- Revision 1.28 2002/09/07 15:25:01 peter
|
|
|
- * old logs removed and tabs fixed
|
|
|
-
|
|
|
- Revision 1.27 2002/09/05 19:29:42 peter
|
|
|
- * memdebug enhancements
|
|
|
-
|
|
|
- Revision 1.26 2002/08/18 20:06:23 peter
|
|
|
- * inlining is now also allowed in interface
|
|
|
- * renamed write/load to ppuwrite/ppuload
|
|
|
- * tnode storing in ppu
|
|
|
- * nld,ncon,nbas are already updated for storing in ppu
|
|
|
-
|
|
|
- Revision 1.25 2002/08/17 09:23:33 florian
|
|
|
- * first part of procinfo rewrite
|
|
|
-
|
|
|
- Revision 1.24 2002/08/11 14:32:26 peter
|
|
|
- * renamed current_library to objectlibrary
|
|
|
-
|
|
|
- Revision 1.23 2002/08/11 13:24:11 peter
|
|
|
- * saving of asmsymbols in ppu supported
|
|
|
- * asmsymbollist global is removed and moved into a new class
|
|
|
- tasmlibrarydata that will hold the info of a .a file which
|
|
|
- corresponds with a single module. Added librarydata to tmodule
|
|
|
- to keep the library info stored for the module. In the future the
|
|
|
- objectfiles will also be stored to the tasmlibrarydata class
|
|
|
- * all getlabel/newasmsymbol and friends are moved to the new class
|
|
|
-
|
|
|
- Revision 1.22 2002/08/06 20:55:20 florian
|
|
|
- * first part of ppc calling conventions fix
|
|
|
-
|
|
|
- Revision 1.21 2002/08/05 18:27:48 carl
|
|
|
- + more more more documentation
|
|
|
- + first version include/exclude (can't test though, not enough scratch for i386 :()...
|
|
|
-
|
|
|
- Revision 1.20 2002/08/04 19:06:41 carl
|
|
|
- + added generic exception support (still does not work!)
|
|
|
- + more documentation
|
|
|
-
|
|
|
- Revision 1.19 2002/07/20 11:57:53 florian
|
|
|
- * types.pas renamed to defbase.pas because D6 contains a types
|
|
|
- unit so this would conflicts if D6 programms are compiled
|
|
|
- + Willamette/SSE2 instructions to assembler added
|
|
|
-
|
|
|
- Revision 1.18 2002/07/01 18:46:22 peter
|
|
|
- * internal linker
|
|
|
- * reorganized aasm layer
|
|
|
-
|
|
|
- Revision 1.17 2002/05/20 13:30:40 carl
|
|
|
- * bugfix of hdisponen (base must be set, not index)
|
|
|
- * more portability fixes
|
|
|
-
|
|
|
- Revision 1.16 2002/05/18 13:34:05 peter
|
|
|
- * readded missing revisions
|
|
|
-
|
|
|
- Revision 1.15 2002/05/16 19:46:35 carl
|
|
|
- + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
|
|
|
- + try to fix temp allocation (still in ifdef)
|
|
|
- + generic constructor calls
|
|
|
- + start of tassembler / tmodulebase class cleanup
|
|
|
-
|
|
|
- Revision 1.13 2002/04/25 20:16:38 peter
|
|
|
- * moved more routines from cga/n386util
|
|
|
-
|
|
|
- Revision 1.12 2002/04/21 15:28:06 carl
|
|
|
- - remove duplicate constants
|
|
|
- - move some constants to cginfo
|
|
|
-
|
|
|
- Revision 1.11 2002/04/20 21:32:23 carl
|
|
|
- + generic FPC_CHECKPOINTER
|
|
|
- + first parameter offset in stack now portable
|
|
|
- * rename some constants
|
|
|
- + move some cpu stuff to other units
|
|
|
- - remove unused constents
|
|
|
- * fix stacksize for some targets
|
|
|
- * fix generic size problems which depend now on EXTEND_SIZE constant
|
|
|
-
|
|
|
- Revision 1.10 2002/04/07 09:13:39 carl
|
|
|
- + documentation
|
|
|
- - remove unused variables
|
|
|
-
|
|
|
- Revision 1.9 2002/04/04 19:05:54 peter
|
|
|
- * removed unused units
|
|
|
- * use tlocation.size in cg.a_*loc*() routines
|
|
|
-
|
|
|
- Revision 1.8 2002/04/02 17:11:27 peter
|
|
|
- * tlocation,treference update
|
|
|
- * LOC_CONSTANT added for better constant handling
|
|
|
- * secondadd splitted in multiple routines
|
|
|
- * location_force_reg added for loading a location to a register
|
|
|
- of a specified size
|
|
|
- * secondassignment parses now first the right and then the left node
|
|
|
- (this is compatible with Kylix). This saves a lot of push/pop especially
|
|
|
- with string operations
|
|
|
- * adapted some routines to use the new cg methods
|
|
|
-
|
|
|
- Revision 1.7 2002/03/31 20:26:33 jonas
|
|
|
- + a_loadfpu_* and a_loadmm_* methods in tcg
|
|
|
- * register allocation is now handled by a class and is mostly processor
|
|
|
- independent (+rgobj.pas and i386/rgcpu.pas)
|
|
|
- * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
|
|
|
- * some small improvements and fixes to the optimizer
|
|
|
- * some register allocation fixes
|
|
|
- * some fpuvaroffset fixes in the unary minus node
|
|
|
- * push/popusedregisters is now called rg.save/restoreusedregisters and
|
|
|
- (for i386) uses temps instead of push/pop's when using -Op3 (that code is
|
|
|
- also better optimizable)
|
|
|
- * fixed and optimized register saving/restoring for new/dispose nodes
|
|
|
- * LOC_FPU locations now also require their "register" field to be set to
|
|
|
- R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
|
|
|
- - list field removed of the tnode class because it's not used currently
|
|
|
- and can cause hard-to-find bugs
|
|
|
+ Revision 1.67 2003-10-01 20:34:48 peter
|
|
|
+ * procinfo unit contains tprocinfo
|
|
|
+ * cginfo renamed to cgbase
|
|
|
+ * moved cgmessage to verbose
|
|
|
+ * fixed ppc and sparc compiles
|
|
|
|
|
|
}
|