summaryrefslogtreecommitdiff
path: root/closures/compiler/i386/cgcpu.pas
diff options
context:
space:
mode:
Diffstat (limited to 'closures/compiler/i386/cgcpu.pas')
-rw-r--r--closures/compiler/i386/cgcpu.pas862
1 files changed, 862 insertions, 0 deletions
diff --git a/closures/compiler/i386/cgcpu.pas b/closures/compiler/i386/cgcpu.pas
new file mode 100644
index 0000000000..863638d3e7
--- /dev/null
+++ b/closures/compiler/i386/cgcpu.pas
@@ -0,0 +1,862 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ This unit implements the code generator for the i386
+
+ 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.
+
+ ****************************************************************************
+}
+unit cgcpu;
+
+{$i fpcdefs.inc}
+
+ interface
+
+ uses
+ globtype,
+ cgbase,cgobj,cg64f32,cgx86,
+ aasmbase,aasmtai,aasmdata,aasmcpu,
+ cpubase,parabase,cgutils,
+ symconst,symdef
+ ;
+
+ type
+ tcg386 = class(tcgx86)
+ procedure init_register_allocators;override;
+ procedure do_register_allocation(list:TAsmList;headertai:tai);override;
+
+ { passing parameter using push instead of mov }
+ procedure a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
+ procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);override;
+ procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);override;
+ procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);override;
+
+ procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
+ procedure g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);override;
+ procedure g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);override;
+
+ procedure g_exception_reason_save(list : TAsmList; const href : treference);override;
+ procedure g_exception_reason_save_const(list : TAsmList; const href : treference; a: tcgint);override;
+ procedure g_exception_reason_load(list : TAsmList; const href : treference);override;
+ procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+ procedure g_maybe_got_init(list: TAsmList); override;
+ end;
+
+ tcg64f386 = class(tcg64f32)
+ procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override;
+ procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
+ procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
+ procedure a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);override;
+ private
+ procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
+ end;
+
+ procedure create_codegen;
+
+ implementation
+
+ uses
+ globals,verbose,systems,cutils,
+ paramgr,procinfo,fmodule,
+ rgcpu,rgx86,cpuinfo;
+
+ function use_push(const cgpara:tcgpara):boolean;
+ begin
+ result:=(not paramanager.use_fixed_stack) and
+ assigned(cgpara.location) and
+ (cgpara.location^.loc=LOC_REFERENCE) and
+ (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
+ end;
+
+
+ procedure tcg386.init_register_allocators;
+ begin
+ inherited init_register_allocators;
+ if not(target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+ (cs_create_pic in current_settings.moduleswitches) then
+ rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI],first_int_imreg,[RS_EBP])
+ else
+ rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_EAX,RS_EDX,RS_ECX,RS_EBX,RS_ESI,RS_EDI],first_int_imreg,[RS_EBP]);
+ rg[R_MMXREGISTER]:=trgcpu.create(R_MMXREGISTER,R_SUBNONE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
+ rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBWHOLE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
+ rgfpu:=Trgx86fpu.create;
+ end;
+
+ procedure tcg386.do_register_allocation(list:TAsmList;headertai:tai);
+ begin
+ if (pi_needs_got in current_procinfo.flags) then
+ begin
+ if getsupreg(current_procinfo.got) < first_int_imreg then
+ include(rg[R_INTREGISTER].used_in_proc,getsupreg(current_procinfo.got));
+ end;
+ inherited do_register_allocation(list,headertai);
+ end;
+
+
+ procedure tcg386.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
+ var
+ pushsize : tcgsize;
+ begin
+ check_register_size(size,r);
+ if use_push(cgpara) then
+ begin
+ cgpara.check_simple_location;
+ if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
+ pushsize:=cgpara.location^.size
+ else
+ pushsize:=int_cgsize(cgpara.alignment);
+ list.concat(taicpu.op_reg(A_PUSH,tcgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
+ end
+ else
+ inherited a_load_reg_cgpara(list,size,r,cgpara);
+ end;
+
+
+ procedure tcg386.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);
+ var
+ pushsize : tcgsize;
+ begin
+ if use_push(cgpara) then
+ begin
+ cgpara.check_simple_location;
+ if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
+ pushsize:=cgpara.location^.size
+ else
+ pushsize:=int_cgsize(cgpara.alignment);
+ list.concat(taicpu.op_const(A_PUSH,tcgsize2opsize[pushsize],a));
+ end
+ else
+ inherited a_load_const_cgpara(list,size,a,cgpara);
+ end;
+
+
+ procedure tcg386.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);
+
+ procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
+ var
+ pushsize : tcgsize;
+ tmpreg : tregister;
+ href : treference;
+ begin
+ if not assigned(paraloc) then
+ exit;
+ if (paraloc^.loc<>LOC_REFERENCE) or
+ (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
+ (tcgsize2size[paraloc^.size]>sizeof(aint)) then
+ internalerror(200501162);
+ { Pushes are needed in reverse order, add the size of the
+ current location to the offset where to load from. This
+ prevents wrong calculations for the last location when
+ the size is not a power of 2 }
+ if assigned(paraloc^.next) then
+ pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
+ { Push the data starting at ofs }
+ href:=r;
+ inc(href.offset,ofs);
+ if tcgsize2size[paraloc^.size]>cgpara.alignment then
+ pushsize:=paraloc^.size
+ else
+ pushsize:=int_cgsize(cgpara.alignment);
+ if tcgsize2size[paraloc^.size]<cgpara.alignment then
+ begin
+ tmpreg:=getintregister(list,pushsize);
+ a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
+ list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],tmpreg));
+ end
+ else
+ begin
+ make_simple_ref(list,href);
+ list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[pushsize],href));
+ end;
+ end;
+
+ var
+ len : tcgint;
+ href : treference;
+ begin
+ { cgpara.size=OS_NO requires a copy on the stack }
+ if use_push(cgpara) then
+ begin
+ { Record copy? }
+ if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
+ begin
+ cgpara.check_simple_location;
+ len:=align(cgpara.intsize,cgpara.alignment);
+ g_stackpointer_alloc(list,len);
+ reference_reset_base(href,NR_STACK_POINTER_REG,0,4);
+ g_concatcopy(list,r,href,len);
+ end
+ else
+ begin
+ if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
+ internalerror(200501161);
+ { We need to push the data in reverse order,
+ therefor we use a recursive algorithm }
+ pushdata(cgpara.location,0);
+ end
+ end
+ else
+ inherited a_load_ref_cgpara(list,size,r,cgpara);
+ end;
+
+
+ procedure tcg386.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);
+ var
+ tmpreg : tregister;
+ opsize : topsize;
+ tmpref : treference;
+ begin
+ with r do
+ begin
+ if (segment<>NR_NO) then
+ cgmessage(cg_e_cant_use_far_pointer_there);
+ if use_push(cgpara) then
+ begin
+ cgpara.check_simple_location;
+ opsize:=tcgsize2opsize[OS_ADDR];
+ if (segment=NR_NO) and (base=NR_NO) and (index=NR_NO) then
+ begin
+ if assigned(symbol) then
+ begin
+ if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+ ((r.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL]) or
+ (cs_create_pic in current_settings.moduleswitches)) then
+ begin
+ tmpreg:=getaddressregister(list);
+ a_loadaddr_ref_reg(list,r,tmpreg);
+ list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
+ end
+ else if cs_create_pic in current_settings.moduleswitches then
+ begin
+ if offset<>0 then
+ begin
+ tmpreg:=getaddressregister(list);
+ a_loadaddr_ref_reg(list,r,tmpreg);
+ list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
+ end
+ else
+ begin
+ reference_reset_symbol(tmpref,r.symbol,0,r.alignment);
+ tmpref.refaddr:=addr_pic;
+ tmpref.base:=current_procinfo.got;
+ include(current_procinfo.flags,pi_needs_got);
+ list.concat(taicpu.op_ref(A_PUSH,S_L,tmpref));
+ end
+ end
+ else
+ list.concat(Taicpu.Op_sym_ofs(A_PUSH,opsize,symbol,offset));
+ end
+ else
+ list.concat(Taicpu.Op_const(A_PUSH,opsize,offset));
+ end
+ else if (segment=NR_NO) and (base=NR_NO) and (index<>NR_NO) and
+ (offset=0) and (scalefactor=0) and (symbol=nil) then
+ list.concat(Taicpu.Op_reg(A_PUSH,opsize,index))
+ else if (segment=NR_NO) and (base<>NR_NO) and (index=NR_NO) and
+ (offset=0) and (symbol=nil) then
+ list.concat(Taicpu.Op_reg(A_PUSH,opsize,base))
+ else
+ begin
+ tmpreg:=getaddressregister(list);
+ a_loadaddr_ref_reg(list,r,tmpreg);
+ list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
+ end;
+ end
+ else
+ inherited a_loadaddr_ref_cgpara(list,r,cgpara);
+ end;
+ end;
+
+
+ procedure tcg386.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
+ var
+ stacksize : longint;
+ begin
+ { MMX needs to call EMMS }
+ if assigned(rg[R_MMXREGISTER]) and
+ (rg[R_MMXREGISTER].uses_registers) then
+ list.concat(Taicpu.op_none(A_EMMS,S_NO));
+
+ { remove stackframe }
+ if not nostackframe then
+ begin
+ if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
+ begin
+ stacksize:=current_procinfo.calc_stackframe_size;
+ if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+ ((stacksize <> 0) or
+ (pi_do_call in current_procinfo.flags) or
+ { can't detect if a call in this case -> use nostackframe }
+ { if you (think you) know what you are doing }
+ (po_assembler in current_procinfo.procdef.procoptions)) then
+ stacksize := align(stacksize+sizeof(aint),16) - sizeof(aint);
+ if (stacksize<>0) then
+ cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
+ end
+ else
+ list.concat(Taicpu.op_none(A_LEAVE,S_NO));
+ list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
+ end;
+
+ { return from proc }
+ if (po_interrupt in current_procinfo.procdef.procoptions) and
+ { this messes up stack alignment }
+ not(target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
+ begin
+ if assigned(current_procinfo.procdef.funcretloc[calleeside].location) and
+ (current_procinfo.procdef.funcretloc[calleeside].location^.loc=LOC_REGISTER) then
+ begin
+ if (getsupreg(current_procinfo.procdef.funcretloc[calleeside].location^.register)=RS_EAX) then
+ list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
+ else
+ internalerror(2010053001);
+ end
+ else
+ list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EAX));
+ list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EBX));
+ list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ECX));
+
+ if (current_procinfo.procdef.funcretloc[calleeside].size in [OS_64,OS_S64]) and
+ assigned(current_procinfo.procdef.funcretloc[calleeside].location) and
+ assigned(current_procinfo.procdef.funcretloc[calleeside].location^.next) and
+ (current_procinfo.procdef.funcretloc[calleeside].location^.next^.loc=LOC_REGISTER) then
+ begin
+ if (getsupreg(current_procinfo.procdef.funcretloc[calleeside].location^.next^.register)=RS_EDX) then
+ list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
+ else
+ internalerror(2010053002);
+ end
+ else
+ list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDX));
+
+ list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ESI));
+ list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDI));
+ { .... also the segment registers }
+ list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
+ list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
+ list.concat(Taicpu.Op_reg(A_POP,S_W,NR_FS));
+ list.concat(Taicpu.Op_reg(A_POP,S_W,NR_GS));
+ { this restores the flags }
+ list.concat(Taicpu.Op_none(A_IRET,S_NO));
+ end
+ { Routines with the poclearstack flag set use only a ret }
+ else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
+ (not paramanager.use_fixed_stack) then
+ begin
+ { complex return values are removed from stack in C code PM }
+ { but not on win32 }
+ { and not for safecall with hidden exceptions, because the result }
+ { wich contains the exception is passed in EAX }
+ if (target_info.system <> system_i386_win32) and
+ not ((current_procinfo.procdef.proccalloption = pocall_safecall) and
+ (tf_safecall_exceptions in target_info.flags)) and
+ paramanager.ret_in_param(current_procinfo.procdef.returndef,
+ current_procinfo.procdef.proccalloption) then
+ list.concat(Taicpu.Op_const(A_RET,S_W,sizeof(aint)))
+ else
+ list.concat(Taicpu.Op_none(A_RET,S_NO));
+ end
+ { ... also routines with parasize=0 }
+ else if (parasize=0) then
+ list.concat(Taicpu.Op_none(A_RET,S_NO))
+ else
+ begin
+ { parameters are limited to 65535 bytes because ret allows only imm16 }
+ if (parasize>65535) then
+ CGMessage(cg_e_parasize_too_big);
+ list.concat(Taicpu.Op_const(A_RET,S_W,parasize));
+ end;
+ end;
+
+
+ procedure tcg386.g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
+ var
+ power,len : longint;
+ opsize : topsize;
+{$ifndef __NOWINPECOFF__}
+ again,ok : tasmlabel;
+{$endif}
+ begin
+ if paramanager.use_fixed_stack then
+ begin
+ inherited g_copyvaluepara_openarray(list,ref,lenloc,elesize,destreg);
+ exit;
+ end;
+
+ { get stack space }
+ getcpuregister(list,NR_EDI);
+ a_load_loc_reg(list,OS_INT,lenloc,NR_EDI);
+ list.concat(Taicpu.op_reg(A_INC,S_L,NR_EDI));
+ { Now EDI contains (high+1). Copy it to ECX for later use. }
+ getcpuregister(list,NR_ECX);
+ list.concat(Taicpu.op_reg_reg(A_MOV,S_L,NR_EDI,NR_ECX));
+ if (elesize<>1) then
+ begin
+ if ispowerof2(elesize, power) then
+ list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_EDI))
+ else
+ list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,NR_EDI));
+ end;
+{$ifndef __NOWINPECOFF__}
+ { windows guards only a few pages for stack growing, }
+ { so we have to access every page first }
+ if target_info.system=system_i386_win32 then
+ begin
+ current_asmdata.getjumplabel(again);
+ current_asmdata.getjumplabel(ok);
+ a_label(list,again);
+ list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,NR_EDI));
+ a_jmp_cond(list,OC_B,ok);
+ list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
+ list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EDI));
+ list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,NR_EDI));
+ a_jmp_always(list,again);
+
+ a_label(list,ok);
+ end;
+{$endif __NOWINPECOFF__}
+ { If we were probing pages, EDI=(size mod pagesize) and ESP is decremented
+ by (size div pagesize)*pagesize, otherwise EDI=size.
+ Either way, subtracting EDI from ESP will set ESP to desired final value. }
+ list.concat(Taicpu.op_reg_reg(A_SUB,S_L,NR_EDI,NR_ESP));
+ { align stack on 4 bytes }
+ list.concat(Taicpu.op_const_reg(A_AND,S_L,aint($fffffff4),NR_ESP));
+ { load destination, don't use a_load_reg_reg, that will add a move instruction
+ that can confuse the reg allocator }
+ list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,NR_ESP,NR_EDI));
+
+ { Allocate ESI and load it with source }
+ getcpuregister(list,NR_ESI);
+ a_loadaddr_ref_reg(list,ref,NR_ESI);
+
+ { calculate size }
+ len:=elesize;
+ opsize:=S_B;
+ if (len and 3)=0 then
+ begin
+ opsize:=S_L;
+ len:=len shr 2;
+ end
+ else
+ if (len and 1)=0 then
+ begin
+ opsize:=S_W;
+ len:=len shr 1;
+ end;
+
+ if len>1 then
+ begin
+ if ispowerof2(len, power) then
+ list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_ECX))
+ else
+ list.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,NR_ECX));
+ end;
+ list.concat(Taicpu.op_none(A_REP,S_NO));
+ case opsize of
+ S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
+ S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
+ S_L : list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
+ end;
+ ungetcpuregister(list,NR_EDI);
+ ungetcpuregister(list,NR_ECX);
+ ungetcpuregister(list,NR_ESI);
+
+ { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
+ that can confuse the reg allocator }
+ list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,NR_ESP,destreg));
+ end;
+
+
+ procedure tcg386.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
+ begin
+ if paramanager.use_fixed_stack then
+ begin
+ inherited g_releasevaluepara_openarray(list,l);
+ exit;
+ end;
+ { Nothing to release }
+ end;
+
+
+ procedure tcg386.g_exception_reason_save(list : TAsmList; const href : treference);
+ begin
+ if not paramanager.use_fixed_stack then
+ list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
+ else
+ inherited g_exception_reason_save(list,href);
+ end;
+
+
+ procedure tcg386.g_exception_reason_save_const(list : TAsmList;const href : treference; a: tcgint);
+ begin
+ if not paramanager.use_fixed_stack then
+ list.concat(Taicpu.op_const(A_PUSH,tcgsize2opsize[OS_INT],a))
+ else
+ inherited g_exception_reason_save_const(list,href,a);
+ end;
+
+
+ procedure tcg386.g_exception_reason_load(list : TAsmList; const href : treference);
+ begin
+ if not paramanager.use_fixed_stack then
+ begin
+ cg.a_reg_alloc(list,NR_FUNCTION_RESULT_REG);
+ list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
+ end
+ else
+ inherited g_exception_reason_load(list,href);
+ end;
+
+
+ procedure tcg386.g_maybe_got_init(list: TAsmList);
+ var
+ notdarwin: boolean;
+ begin
+ { allocate PIC register }
+ if (cs_create_pic in current_settings.moduleswitches) and
+ (tf_pic_uses_got in target_info.flags) and
+ (pi_needs_got in current_procinfo.flags) then
+ begin
+ notdarwin:=not(target_info.system in [system_i386_darwin,system_i386_iphonesim]);
+ { on darwin, the got register is virtual (and allocated earlier
+ already) }
+ if notdarwin then
+ { ecx could be used in leaf procedures that don't use ecx to pass
+ aparameter }
+ current_procinfo.got:=NR_EBX;
+ if notdarwin { needs testing before it can be enabled for non-darwin platforms
+ and
+ (current_settings.optimizecputype in [cpu_Pentium2,cpu_Pentium3,cpu_Pentium4]) } then
+ begin
+ current_module.requires_ebx_pic_helper:=true;
+ cg.a_call_name_static(list,'fpc_geteipasebx');
+ end
+ else
+ begin
+ { call/pop is faster than call/ret/mov on Core Solo and later
+ according to Apple's benchmarking -- and all Intel Macs
+ have at least a Core Solo (furthermore, the i386 - Pentium 1
+ don't have a return stack buffer) }
+ a_call_name_static(list,current_procinfo.CurrGOTLabel.name);
+ a_label(list,current_procinfo.CurrGotLabel);
+ list.concat(taicpu.op_reg(A_POP,S_L,current_procinfo.got))
+ end;
+ if notdarwin then
+ begin
+ list.concat(taicpu.op_sym_ofs_reg(A_ADD,S_L,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),0,NR_PIC_OFFSET_REG));
+ list.concat(tai_regalloc.alloc(NR_PIC_OFFSET_REG,nil));
+ end;
+ end;
+ end;
+
+
+ procedure tcg386.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
+ {
+ possible calling conventions:
+ default stdcall cdecl pascal register
+ default(0): OK OK OK OK OK
+ virtual(1): OK OK OK OK OK(2)
+
+ (0):
+ set self parameter to correct value
+ jmp mangledname
+
+ (1): The wrapper code use %eax to reach the virtual method address
+ set self to correct value
+ move self,%eax
+ mov 0(%eax),%eax ; load vmt
+ jmp vmtoffs(%eax) ; method offs
+
+ (2): Virtual use values pushed on stack to reach the method address
+ so the following code be generated:
+ set self to correct value
+ push %ebx ; allocate space for function address
+ push %eax
+ mov self,%eax
+ mov 0(%eax),%eax ; load vmt
+ mov vmtoffs(%eax),eax ; method offs
+ mov %eax,4(%esp)
+ pop %eax
+ ret 0; jmp the address
+
+ }
+
+ procedure getselftoeax(offs: longint);
+ var
+ href : treference;
+ selfoffsetfromsp : longint;
+ begin
+ { mov offset(%esp),%eax }
+ if (procdef.proccalloption<>pocall_register) then
+ begin
+ { framepointer is pushed for nested procs }
+ if procdef.parast.symtablelevel>normal_function_level then
+ selfoffsetfromsp:=2*sizeof(aint)
+ else
+ selfoffsetfromsp:=sizeof(aint);
+ reference_reset_base(href,NR_ESP,selfoffsetfromsp+offs,4);
+ cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
+ end;
+ end;
+
+ procedure loadvmttoeax;
+ var
+ href : treference;
+ begin
+ { mov 0(%eax),%eax ; load vmt}
+ reference_reset_base(href,NR_EAX,0,4);
+ cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
+ end;
+
+ procedure op_oneaxmethodaddr(op: TAsmOp);
+ var
+ href : treference;
+ begin
+ if (procdef.extnumber=$ffff) then
+ Internalerror(200006139);
+ { call/jmp vmtoffs(%eax) ; method offs }
+ reference_reset_base(href,NR_EAX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),4);
+ list.concat(taicpu.op_ref(op,S_L,href));
+ end;
+
+
+ procedure loadmethodoffstoeax;
+ var
+ href : treference;
+ begin
+ if (procdef.extnumber=$ffff) then
+ Internalerror(200006139);
+ { mov vmtoffs(%eax),%eax ; method offs }
+ reference_reset_base(href,NR_EAX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),4);
+ cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
+ end;
+
+
+ var
+ lab : tasmsymbol;
+ make_global : boolean;
+ href : treference;
+ begin
+ if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
+ Internalerror(200006137);
+ if not assigned(procdef.struct) or
+ (procdef.procoptions*[po_classmethod, po_staticmethod,
+ po_methodpointer, po_interrupt, po_iocheck]<>[]) then
+ Internalerror(200006138);
+ if procdef.owner.symtabletype<>ObjectSymtable then
+ Internalerror(200109191);
+
+ make_global:=false;
+ if (not current_module.is_unit) or
+ create_smartlink or
+ (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
+ make_global:=true;
+
+ if make_global then
+ List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
+ else
+ List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
+
+ { set param1 interface to self }
+ g_adjust_self_value(list,procdef,ioffset);
+
+ if (po_virtualmethod in procdef.procoptions) and
+ not is_objectpascal_helper(procdef.struct) then
+ begin
+ if (procdef.proccalloption=pocall_register) then
+ begin
+ { case 2 }
+ list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EBX)); { allocate space for address}
+ list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EAX));
+ getselftoeax(8);
+ loadvmttoeax;
+ loadmethodoffstoeax;
+ { mov %eax,4(%esp) }
+ reference_reset_base(href,NR_ESP,4,4);
+ list.concat(taicpu.op_reg_ref(A_MOV,S_L,NR_EAX,href));
+ { pop %eax }
+ list.concat(taicpu.op_reg(A_POP,S_L,NR_EAX));
+ { ret ; jump to the address }
+ list.concat(taicpu.op_none(A_RET,S_L));
+ end
+ else
+ begin
+ { case 1 }
+ getselftoeax(0);
+ loadvmttoeax;
+ op_oneaxmethodaddr(A_JMP);
+ end;
+ end
+ { case 0 }
+ else
+ begin
+ if (target_info.system <> system_i386_darwin) then
+ begin
+ lab:=current_asmdata.RefAsmSymbol(procdef.mangledname);
+ list.concat(taicpu.op_sym(A_JMP,S_NO,lab))
+ end
+ else
+ list.concat(taicpu.op_sym(A_JMP,S_NO,get_darwin_call_stub(procdef.mangledname,false)))
+ end;
+
+ List.concat(Tai_symbol_end.Createname(labelname));
+ end;
+
+
+{ ************* 64bit operations ************ }
+
+ procedure tcg64f386.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
+ begin
+ case op of
+ OP_ADD :
+ begin
+ op1:=A_ADD;
+ op2:=A_ADC;
+ end;
+ OP_SUB :
+ begin
+ op1:=A_SUB;
+ op2:=A_SBB;
+ end;
+ OP_XOR :
+ begin
+ op1:=A_XOR;
+ op2:=A_XOR;
+ end;
+ OP_OR :
+ begin
+ op1:=A_OR;
+ op2:=A_OR;
+ end;
+ OP_AND :
+ begin
+ op1:=A_AND;
+ op2:=A_AND;
+ end;
+ else
+ internalerror(200203241);
+ end;
+ end;
+
+
+ procedure tcg64f386.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
+ var
+ op1,op2 : TAsmOp;
+ tempref : treference;
+ begin
+ if not(op in [OP_NEG,OP_NOT]) then
+ begin
+ get_64bit_ops(op,op1,op2);
+ tempref:=ref;
+ tcgx86(cg).make_simple_ref(list,tempref);
+ list.concat(taicpu.op_ref_reg(op1,S_L,tempref,reg.reglo));
+ inc(tempref.offset,4);
+ list.concat(taicpu.op_ref_reg(op2,S_L,tempref,reg.reghi));
+ end
+ else
+ begin
+ a_load64_ref_reg(list,ref,reg);
+ a_op64_reg_reg(list,op,size,reg,reg);
+ end;
+ end;
+
+
+ procedure tcg64f386.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
+ var
+ op1,op2 : TAsmOp;
+ begin
+ case op of
+ OP_NEG :
+ begin
+ if (regsrc.reglo<>regdst.reglo) then
+ a_load64_reg_reg(list,regsrc,regdst);
+ list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reghi));
+ list.concat(taicpu.op_reg(A_NEG,S_L,regdst.reglo));
+ list.concat(taicpu.op_const_reg(A_SBB,S_L,-1,regdst.reghi));
+ exit;
+ end;
+ OP_NOT :
+ begin
+ if (regsrc.reglo<>regdst.reglo) then
+ a_load64_reg_reg(list,regsrc,regdst);
+ list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reghi));
+ list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reglo));
+ exit;
+ end;
+ end;
+ get_64bit_ops(op,op1,op2);
+ list.concat(taicpu.op_reg_reg(op1,S_L,regsrc.reglo,regdst.reglo));
+ list.concat(taicpu.op_reg_reg(op2,S_L,regsrc.reghi,regdst.reghi));
+ end;
+
+
+ procedure tcg64f386.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
+ var
+ op1,op2 : TAsmOp;
+ begin
+ case op of
+ OP_AND,OP_OR,OP_XOR:
+ begin
+ cg.a_op_const_reg(list,op,OS_32,tcgint(lo(value)),reg.reglo);
+ cg.a_op_const_reg(list,op,OS_32,tcgint(hi(value)),reg.reghi);
+ end;
+ OP_ADD, OP_SUB:
+ begin
+ // can't use a_op_const_ref because this may use dec/inc
+ get_64bit_ops(op,op1,op2);
+ list.concat(taicpu.op_const_reg(op1,S_L,aint(lo(value)),reg.reglo));
+ list.concat(taicpu.op_const_reg(op2,S_L,aint(hi(value)),reg.reghi));
+ end;
+ else
+ internalerror(200204021);
+ end;
+ end;
+
+
+ procedure tcg64f386.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
+ var
+ op1,op2 : TAsmOp;
+ tempref : treference;
+ begin
+ tempref:=ref;
+ tcgx86(cg).make_simple_ref(list,tempref);
+ case op of
+ OP_AND,OP_OR,OP_XOR:
+ begin
+ cg.a_op_const_ref(list,op,OS_32,tcgint(lo(value)),tempref);
+ inc(tempref.offset,4);
+ cg.a_op_const_ref(list,op,OS_32,tcgint(hi(value)),tempref);
+ end;
+ OP_ADD, OP_SUB:
+ begin
+ get_64bit_ops(op,op1,op2);
+ // can't use a_op_const_ref because this may use dec/inc
+ list.concat(taicpu.op_const_ref(op1,S_L,aint(lo(value)),tempref));
+ inc(tempref.offset,4);
+ list.concat(taicpu.op_const_ref(op2,S_L,aint(hi(value)),tempref));
+ end;
+ else
+ internalerror(200204022);
+ end;
+ end;
+
+ procedure create_codegen;
+ begin
+ cg := tcg386.create;
+ cg64 := tcg64f386.create;
+ end;
+
+end.