+ x86_64: generate position-independent case jump tables (twice smaller than absolute ones and do not require dynamic relocations in .dll/.so).

git-svn-id: trunk@26519 -
This commit is contained in:
sergei 2014-01-19 15:41:05 +00:00
parent eb508a18e9
commit ca58cc1d64

View File

@ -1,7 +1,7 @@
{
Copyright (c) 1998-2002 by Florian Klaempfl
Generate i386 assembler for in set/case nodes
Generate x86_64 assembler for in set/case nodes
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
@ -32,13 +32,26 @@ interface
type
tx8664casenode = class(tx86casenode)
procedure optimizevalues(var max_linear_list:aint;var max_dist:aword);override;
procedure genjumptable(hp : pcaselabel;min_,max_ : aint);override;
end;
implementation
uses
systems,
verbose,globals,constexp,
symconst,symdef,defutil,
aasmbase,aasmtai,aasmdata,aasmcpu,
cgbase,pass_2,
ncon,
cpubase,cpuinfo,procinfo,
cga,cgutils,cgobj,ncgutil,
cgx86;
{*****************************************************************************
TI386CASENODE
TX8664CASENODE
*****************************************************************************}
procedure tx8664casenode.optimizevalues(var max_linear_list:aint;var max_dist:aword);
@ -46,6 +59,79 @@ implementation
inc(max_linear_list,9);
end;
{ Always generate position-independent jump table, it is twice less in size at a price
of two extra instructions (which shouldn't cause more slowdown than pipeline trashing) }
procedure tx8664casenode.genjumptable(hp : pcaselabel; min_,max_ : aint);
var
last: TConstExprInt;
tablelabel: TAsmLabel;
basereg,indexreg,jumpreg: TRegister;
href: TReference;
opcgsize: tcgsize;
procedure genitem(list:TAsmList;t : pcaselabel);
var
i : aint;
begin
if assigned(t^.less) then
genitem(list,t^.less);
{ fill possible hole }
i:=last.svalue+1;
while i<=t^._low.svalue-1 do
begin
list.concat(Tai_const.Create_rel_sym(aitconst_32bit,tablelabel,elselabel));
inc(i);
end;
i:=t^._low.svalue;
while i<=t^._high.svalue do
begin
list.concat(Tai_const.Create_rel_sym(aitconst_32bit,tablelabel,blocklabel(t^.blockid)));
inc(i);
end;
last:=t^._high;
if assigned(t^.greater) then
genitem(list,t^.greater);
end;
begin
last:=min_;
opcgsize:=def_cgsize(opsize);
if not(jumptable_no_range) then
begin
{ a <= x <= b <-> unsigned(x-a) <= (b-a) }
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,opcgsize,aint(min_),hregister);
{ case expr greater than max_ => goto elselabel }
cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opcgsize,OC_A,aint(max_)-aint(min_),hregister,elselabel);
min_:=0;
end;
{ local label in order to avoid using GOT }
current_asmdata.getlabel(tablelabel,alt_data);
indexreg:=cg.makeregsize(current_asmdata.CurrAsmList,hregister,OS_ADDR);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,opcgsize,OS_ADDR,hregister,indexreg);
{ load table address }
reference_reset_symbol(href,tablelabel,0,4);
basereg:=cg.getaddressregister(current_asmdata.CurrAsmList);
cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,basereg);
{ load table slot, 32-bit sign extended }
reference_reset_base(href,basereg,-aint(min_)*4,4);
href.index:=indexreg;
href.scalefactor:=4;
jumpreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,jumpreg);
{ add table address }
reference_reset_base(href,basereg,0,sizeof(pint));
href.index:=jumpreg;
href.scalefactor:=1;
cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,jumpreg);
{ and finally jump }
emit_reg(A_JMP,S_NO,jumpreg);
{ generate jump table }
new_section(current_procinfo.aktlocaldata,sec_rodata,current_procinfo.procdef.mangledname,4);
current_procinfo.aktlocaldata.concat(Tai_label.Create(tablelabel));
genitem(current_procinfo.aktlocaldata,hp);
end;
begin
ccasenode:=tx8664casenode;
end.