mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 04:26:13 +02:00
+ improved x86-64 assembler
git-svn-id: trunk@2983 -
This commit is contained in:
parent
37c81492ad
commit
ec768f88ae
@ -250,10 +250,13 @@ interface
|
|||||||
procedure ppuderefoper(var o:toper);override;
|
procedure ppuderefoper(var o:toper);override;
|
||||||
private
|
private
|
||||||
{ next fields are filled in pass1, so pass2 is faster }
|
{ next fields are filled in pass1, so pass2 is faster }
|
||||||
inssize : shortint;
|
insentry : PInsEntry;
|
||||||
insoffset : longint;
|
insoffset : longint;
|
||||||
LastInsOffset : longint; { need to be public to be reset }
|
LastInsOffset : longint; { need to be public to be reset }
|
||||||
insentry : PInsEntry;
|
inssize : shortint;
|
||||||
|
{$ifdef x86_64}
|
||||||
|
rex : byte;
|
||||||
|
{$endif x86_64}
|
||||||
function InsEnd:longint;
|
function InsEnd:longint;
|
||||||
procedure create_ot(objdata:TObjData);
|
procedure create_ot(objdata:TObjData);
|
||||||
function Matches(p:PInsEntry):boolean;
|
function Matches(p:PInsEntry):boolean;
|
||||||
@ -973,12 +976,16 @@ implementation
|
|||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
|
|
||||||
type
|
type
|
||||||
ea=packed record
|
ea = packed record
|
||||||
sib_present : boolean;
|
sib_present : boolean;
|
||||||
bytes : byte;
|
bytes : byte;
|
||||||
size : byte;
|
size : byte;
|
||||||
modrm : byte;
|
modrm : byte;
|
||||||
sib : byte;
|
sib : byte;
|
||||||
|
{$ifdef x86_64}
|
||||||
|
rex_present : boolean;
|
||||||
|
rex : byte;
|
||||||
|
{$endif x86_64}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure taicpu.create_ot(objdata:TObjData);
|
procedure taicpu.create_ot(objdata:TObjData);
|
||||||
@ -1414,7 +1421,19 @@ implementation
|
|||||||
output.bytes:=0;
|
output.bytes:=0;
|
||||||
output.modrm:=$c0 or (rfield shl 3) or rv;
|
output.modrm:=$c0 or (rfield shl 3) or rv;
|
||||||
output.size:=1;
|
output.size:=1;
|
||||||
|
|
||||||
|
if ((getregtype(input.reg)=R_INTREGISTER) and
|
||||||
|
(getsupreg(input.reg)>=RS_R8)) or
|
||||||
|
((getregtype(input.reg)=R_MMREGISTER) and
|
||||||
|
(getsupreg(input.reg)>=RS_XMM8)) then
|
||||||
|
begin
|
||||||
|
output.rex_present:=true;
|
||||||
|
output.rex:=output.rex or $44;
|
||||||
|
inc(output.size,1);
|
||||||
|
end;
|
||||||
|
|
||||||
process_ea:=true;
|
process_ea:=true;
|
||||||
|
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
{No register, so memory reference.}
|
{No register, so memory reference.}
|
||||||
@ -1444,36 +1463,32 @@ implementation
|
|||||||
{ 16 bit address? }
|
{ 16 bit address? }
|
||||||
if ((ir<>NR_NO) and (isub<>R_SUBADDR)) or
|
if ((ir<>NR_NO) and (isub<>R_SUBADDR)) or
|
||||||
((br<>NR_NO) and (bsub<>R_SUBADDR)) then
|
((br<>NR_NO) and (bsub<>R_SUBADDR)) then
|
||||||
{$ifdef x86_64}
|
|
||||||
message(asmw_e_16bit_32bit_not_supported);
|
message(asmw_e_16bit_32bit_not_supported);
|
||||||
{$else x86_64}
|
|
||||||
message(asmw_e_16bit_not_supported);
|
|
||||||
{$endif x86_64}
|
|
||||||
{$ifdef OPTEA}
|
|
||||||
{ make single reg base }
|
|
||||||
if (br=NR_NO) and (s=1) then
|
|
||||||
begin
|
|
||||||
br:=ir;
|
|
||||||
ir:=NR_NO;
|
|
||||||
end;
|
|
||||||
{ convert [3,5,9]*EAX to EAX+[2,4,8]*EAX }
|
|
||||||
if (br=NR_NO) and
|
|
||||||
(((s=2) and (ir<>NR_ESP)) or
|
|
||||||
(s=3) or (s=5) or (s=9)) then
|
|
||||||
begin
|
|
||||||
br:=ir;
|
|
||||||
dec(s);
|
|
||||||
end;
|
|
||||||
{ swap ESP into base if scalefactor is 1 }
|
|
||||||
if (s=1) and (ir=NR_ESP) then
|
|
||||||
begin
|
|
||||||
ir:=br;
|
|
||||||
br:=NR_ESP;
|
|
||||||
end;
|
|
||||||
{$endif OPTEA}
|
|
||||||
{ wrong, for various reasons }
|
{ wrong, for various reasons }
|
||||||
if (ir=NR_ESP) or ((s<>1) and (s<>2) and (s<>4) and (s<>8) and (ir<>NR_NO)) then
|
if (ir=NR_ESP) or ((s<>1) and (s<>2) and (s<>4) and (s<>8) and (ir<>NR_NO)) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
if ((getregtype(br)=R_INTREGISTER) and
|
||||||
|
(getsupreg(br)>=RS_R8)) or
|
||||||
|
((getregtype(br)=R_MMREGISTER) and
|
||||||
|
(getsupreg(br)>=RS_XMM8)) then
|
||||||
|
begin
|
||||||
|
output.rex_present:=true;
|
||||||
|
output.rex:=output.rex or $41;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ((getregtype(ir)=R_INTREGISTER) and
|
||||||
|
(getsupreg(ir)>=RS_R8)) or
|
||||||
|
((getregtype(ir)=R_MMREGISTER) and
|
||||||
|
(getsupreg(ir)>=RS_XMM8)) then
|
||||||
|
begin
|
||||||
|
output.rex_present:=true;
|
||||||
|
output.rex:=output.rex or $42;
|
||||||
|
end;
|
||||||
|
|
||||||
|
process_ea:=true;
|
||||||
|
|
||||||
|
|
||||||
{ base }
|
{ base }
|
||||||
case br of
|
case br of
|
||||||
NR_RAX : base:=0;
|
NR_RAX : base:=0;
|
||||||
@ -1490,14 +1505,14 @@ implementation
|
|||||||
end;
|
end;
|
||||||
{ index }
|
{ index }
|
||||||
case ir of
|
case ir of
|
||||||
NR_EAX : index:=0;
|
NR_RAX : index:=0;
|
||||||
NR_ECX : index:=1;
|
NR_RCX : index:=1;
|
||||||
NR_EDX : index:=2;
|
NR_RDX : index:=2;
|
||||||
NR_EBX : index:=3;
|
NR_RBX : index:=3;
|
||||||
NR_NO : index:=4;
|
NR_NO : index:=4;
|
||||||
NR_EBP : index:=5;
|
NR_RBP : index:=5;
|
||||||
NR_ESI : index:=6;
|
NR_RSI : index:=6;
|
||||||
NR_EDI : index:=7;
|
NR_RDI : index:=7;
|
||||||
else
|
else
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -1535,10 +1550,7 @@ implementation
|
|||||||
output.sib:=(scalefactor shl 6) or (index shl 3) or base;
|
output.sib:=(scalefactor shl 6) or (index shl 3) or base;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
if output.sib_present then
|
output.size:=1+ord(output.sib_present)+ord(output.rex_present)+output.bytes;
|
||||||
output.size:=2+output.bytes
|
|
||||||
else
|
|
||||||
output.size:=1+output.bytes;
|
|
||||||
process_ea:=true;
|
process_ea:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1708,7 +1720,19 @@ implementation
|
|||||||
inc(codes,c);
|
inc(codes,c);
|
||||||
inc(len,c);
|
inc(len,c);
|
||||||
end;
|
end;
|
||||||
8,9,10,11 :
|
8,9,10 :
|
||||||
|
begin
|
||||||
|
{$ifdef x86_64}
|
||||||
|
if ((getregtype(oper[c-8]^.reg)=R_INTREGISTER) and
|
||||||
|
(getsupreg(oper[c-8]^.reg)>=RS_R8)) or
|
||||||
|
((getregtype(oper[c-8]^.reg)=R_MMREGISTER) and
|
||||||
|
(getsupreg(oper[c-8]^.reg)>=RS_XMM8)) then
|
||||||
|
rex:=rex or $41;
|
||||||
|
{$endif x86_64}
|
||||||
|
inc(codes);
|
||||||
|
inc(len);
|
||||||
|
end;
|
||||||
|
11 :
|
||||||
begin
|
begin
|
||||||
inc(codes);
|
inc(codes);
|
||||||
inc(len);
|
inc(len);
|
||||||
@ -1730,7 +1754,13 @@ implementation
|
|||||||
31,
|
31,
|
||||||
48,49,50 :
|
48,49,50 :
|
||||||
inc(len,2);
|
inc(len,2);
|
||||||
28,29,30, { we don't have 16 bit immediates code }
|
28,29,30:
|
||||||
|
begin
|
||||||
|
if opsize=S_Q then
|
||||||
|
inc(len,8)
|
||||||
|
else
|
||||||
|
inc(len,4);
|
||||||
|
end;
|
||||||
32,33,34,
|
32,33,34,
|
||||||
52,53,54,
|
52,53,54,
|
||||||
56,57,58 :
|
56,57,58 :
|
||||||
@ -1741,9 +1771,15 @@ implementation
|
|||||||
208,209,210 :
|
208,209,210 :
|
||||||
begin
|
begin
|
||||||
case (oper[c-208]^.ot and OT_SIZE_MASK) of
|
case (oper[c-208]^.ot and OT_SIZE_MASK) of
|
||||||
OT_BITS16,
|
OT_BITS16:
|
||||||
OT_BITS64 :
|
|
||||||
inc(len);
|
inc(len);
|
||||||
|
{$ifdef x86_64}
|
||||||
|
OT_BITS64:
|
||||||
|
begin
|
||||||
|
rex:=rex or $48;
|
||||||
|
inc(len);
|
||||||
|
end;
|
||||||
|
{$endif x86_64}
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
212,
|
212,
|
||||||
@ -1759,10 +1795,21 @@ implementation
|
|||||||
inc(len);
|
inc(len);
|
||||||
64..191 :
|
64..191 :
|
||||||
begin
|
begin
|
||||||
|
{$ifdef x86_64}
|
||||||
|
ea_data.rex:=0;
|
||||||
|
ea_data.rex_present:=false;
|
||||||
|
{$endif x86_64}
|
||||||
if not process_ea(oper[(c shr 3) and 7]^, ea_data, 0) then
|
if not process_ea(oper[(c shr 3) and 7]^, ea_data, 0) then
|
||||||
Message(asmw_e_invalid_effective_address)
|
Message(asmw_e_invalid_effective_address)
|
||||||
else
|
else
|
||||||
inc(len,ea_data.size);
|
inc(len,ea_data.size);
|
||||||
|
{$ifdef x86_64}
|
||||||
|
{ did we already create include a rex into the length calculation? }
|
||||||
|
if (rex<>0) and (ea_data.rex<>0) then
|
||||||
|
dec(len);
|
||||||
|
rex:=rex or ea_data.rex;
|
||||||
|
{$endif x86_64}
|
||||||
|
|
||||||
end;
|
end;
|
||||||
else
|
else
|
||||||
InternalError(200603141);
|
InternalError(200603141);
|
||||||
@ -1821,26 +1868,26 @@ implementation
|
|||||||
}
|
}
|
||||||
|
|
||||||
var
|
var
|
||||||
currval : longint;
|
currval : aint;
|
||||||
currsym : tobjsymbol;
|
currsym : tobjsymbol;
|
||||||
|
|
||||||
procedure getvalsym(opidx:longint);
|
procedure getvalsym(opidx:longint);
|
||||||
begin
|
begin
|
||||||
case oper[opidx]^.typ of
|
case oper[opidx]^.typ of
|
||||||
top_ref :
|
top_ref :
|
||||||
begin
|
begin
|
||||||
currval:=oper[opidx]^.ref^.offset;
|
currval:=oper[opidx]^.ref^.offset;
|
||||||
currsym:=ObjData.symbolref(oper[opidx]^.ref^.symbol);
|
currsym:=ObjData.symbolref(oper[opidx]^.ref^.symbol);
|
||||||
end;
|
end;
|
||||||
top_const :
|
top_const :
|
||||||
begin
|
begin
|
||||||
currval:=longint(oper[opidx]^.val);
|
currval:=longint(oper[opidx]^.val);
|
||||||
currsym:=nil;
|
currsym:=nil;
|
||||||
end;
|
end;
|
||||||
else
|
else
|
||||||
Message(asmw_e_immediate_or_reference_expected);
|
Message(asmw_e_immediate_or_reference_expected);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
|
||||||
|
|
||||||
const
|
const
|
||||||
CondVal:array[TAsmCond] of byte=($0,
|
CondVal:array[TAsmCond] of byte=($0,
|
||||||
@ -1855,7 +1902,13 @@ implementation
|
|||||||
rfield,
|
rfield,
|
||||||
data,s,opidx : longint;
|
data,s,opidx : longint;
|
||||||
ea_data : ea;
|
ea_data : ea;
|
||||||
|
{$ifdef extdebug}
|
||||||
|
rexwritten : boolean;
|
||||||
|
{$endif extdebug}
|
||||||
begin
|
begin
|
||||||
|
{$ifdef extdebug}
|
||||||
|
rexwritten:=false;
|
||||||
|
{$endif extdebug}
|
||||||
{ safety check }
|
{ safety check }
|
||||||
if objdata.currobjsec.size<>insoffset then
|
if objdata.currobjsec.size<>insoffset then
|
||||||
internalerror(200130121);
|
internalerror(200130121);
|
||||||
@ -1914,6 +1967,13 @@ implementation
|
|||||||
end;
|
end;
|
||||||
8,9,10 :
|
8,9,10 :
|
||||||
begin
|
begin
|
||||||
|
{ rex should be written at this point }
|
||||||
|
{$ifdef x86_64}
|
||||||
|
{$ifdef extdebug}
|
||||||
|
if (rex<>0) and not(rexwritten) then
|
||||||
|
internalerror(200603192);
|
||||||
|
{$endif extdebug}
|
||||||
|
{$endif x86_64}
|
||||||
bytes[0]:=ord(codes^)+regval(oper[c-8]^.reg);
|
bytes[0]:=ord(codes^)+regval(oper[c-8]^.reg);
|
||||||
inc(codes);
|
inc(codes);
|
||||||
objdata.writebytes(bytes,1);
|
objdata.writebytes(bytes,1);
|
||||||
@ -1972,10 +2032,20 @@ implementation
|
|||||||
28,29,30 :
|
28,29,30 :
|
||||||
begin
|
begin
|
||||||
getvalsym(c-28);
|
getvalsym(c-28);
|
||||||
if assigned(currsym) then
|
if opsize=S_Q then
|
||||||
objdata.writereloc(currval,4,currsym,RELOC_ABSOLUTE)
|
begin
|
||||||
|
if assigned(currsym) then
|
||||||
|
objdata.writereloc(currval,8,currsym,RELOC_ABSOLUTE)
|
||||||
|
else
|
||||||
|
objdata.writebytes(currval,8);
|
||||||
|
end
|
||||||
else
|
else
|
||||||
objdata.writebytes(currval,4);
|
begin
|
||||||
|
if assigned(currsym) then
|
||||||
|
objdata.writereloc(currval,4,currsym,RELOC_ABSOLUTE)
|
||||||
|
else
|
||||||
|
objdata.writebytes(currval,4);
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
32,33,34 :
|
32,33,34 :
|
||||||
begin
|
begin
|
||||||
@ -2032,15 +2102,21 @@ implementation
|
|||||||
bytes[0]:=$66;
|
bytes[0]:=$66;
|
||||||
objdata.writebytes(bytes,1);
|
objdata.writebytes(bytes,1);
|
||||||
end;
|
end;
|
||||||
OT_BITS64 :
|
|
||||||
begin
|
|
||||||
{$ifndef x86_64}
|
{$ifndef x86_64}
|
||||||
|
OT_BITS64 :
|
||||||
Message(asmw_e_64bit_not_supported);
|
Message(asmw_e_64bit_not_supported);
|
||||||
{$endif x86_64}
|
{$endif x86_64}
|
||||||
bytes[0]:=$48;
|
|
||||||
objdata.writebytes(bytes,1);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
{$ifdef x86_64}
|
||||||
|
if rex<>0 then
|
||||||
|
begin
|
||||||
|
bytes[0]:=rex;
|
||||||
|
{$ifdef extdebug}
|
||||||
|
rexwritten:=true;
|
||||||
|
{$endif extdebug}
|
||||||
|
objdata.writebytes(bytes,1);
|
||||||
|
end;
|
||||||
|
{$endif x86_64}
|
||||||
end;
|
end;
|
||||||
212 :
|
212 :
|
||||||
begin
|
begin
|
||||||
@ -2081,6 +2157,13 @@ implementation
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
{ rex should be written at this point }
|
||||||
|
{$ifdef x86_64}
|
||||||
|
{$ifdef extdebug}
|
||||||
|
if (rex<>0) and not(rexwritten) then
|
||||||
|
internalerror(200603191);
|
||||||
|
{$endif extdebug}
|
||||||
|
{$endif x86_64}
|
||||||
if (c>=64) and (c<=191) then
|
if (c>=64) and (c<=191) then
|
||||||
begin
|
begin
|
||||||
if (c<127) then
|
if (c<127) then
|
||||||
@ -2094,7 +2177,7 @@ implementation
|
|||||||
rfield:=c and 7;
|
rfield:=c and 7;
|
||||||
opidx:=(c shr 3) and 7;
|
opidx:=(c shr 3) and 7;
|
||||||
if not process_ea(oper[opidx]^,ea_data,rfield) then
|
if not process_ea(oper[opidx]^,ea_data,rfield) then
|
||||||
Message(asmw_e_invalid_effective_address);
|
Message(asmw_e_invalid_effective_address);
|
||||||
|
|
||||||
pb:=@bytes;
|
pb:=@bytes;
|
||||||
pb^:=chr(ea_data.modrm);
|
pb^:=chr(ea_data.modrm);
|
||||||
|
@ -1014,7 +1014,7 @@ mem_offs,reg_ax|32 \300\320\1\xA3\34 8086,SM,NOX86_64
|
|||||||
regmem,reg16|32|64 \320\300\1\x89\101 8086,SM
|
regmem,reg16|32|64 \320\300\1\x89\101 8086,SM
|
||||||
reg_ax|32,mem_offs \325\301\1\xA1\35 8086,SM,NOX86_64
|
reg_ax|32,mem_offs \325\301\1\xA1\35 8086,SM,NOX86_64
|
||||||
reg16|32|64,regmem \320\301\1\x8B\110 8086,SM
|
reg16|32|64,regmem \320\301\1\x8B\110 8086,SM
|
||||||
reg32|64,imm \320\10\xB8\41 386,SD
|
reg32|64,imm \320\10\xB8\35 386,SD
|
||||||
rm32|64,imm \320\300\1\xC7\200\41 386,SD
|
rm32|64,imm \320\300\1\xC7\200\41 386,SD
|
||||||
reg16,imm \324\10\xB8\31 8086,SW
|
reg16,imm \324\10\xB8\31 8086,SW
|
||||||
rm16,imm \324\300\1\xC7\200\31 8086,SW
|
rm16,imm \324\300\1\xC7\200\31 8086,SW
|
||||||
|
@ -2937,7 +2937,7 @@
|
|||||||
opcode : A_MOV;
|
opcode : A_MOV;
|
||||||
ops : 2;
|
ops : 2;
|
||||||
optypes : (ot_reg32 or ot_bits64,ot_immediate,ot_none);
|
optypes : (ot_reg32 or ot_bits64,ot_immediate,ot_none);
|
||||||
code : #208#8#184#33;
|
code : #208#8#184#29;
|
||||||
flags : if_386 or if_sd
|
flags : if_386 or if_sd
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
Loading…
Reference in New Issue
Block a user