* properly support accepting register parameters of assembler routines in

the intel assembler reader: no longer parse them as register tokens,
    but as local operands that are later converted into registers. This
    ensures in particular that the type of the operand is set, which is
    necessary in case this operand later subscripted (as in tasm10a)

git-svn-id: trunk@36288 -
This commit is contained in:
Jonas Maebe 2017-05-21 20:17:15 +00:00
parent 61af0fb72d
commit 744facb7fc
4 changed files with 109 additions and 26 deletions

1
.gitattributes vendored
View File

@ -12099,6 +12099,7 @@ tests/test/tarrconstr6.pp svneol=native#text/pascal
tests/test/tarrconstr7.pp svneol=native#text/pascal
tests/test/tasm1.pp svneol=native#text/plain
tests/test/tasm10.pp svneol=native#text/plain
tests/test/tasm10a.pp svneol=native#text/plain
tests/test/tasm2.inc svneol=native#text/plain
tests/test/tasm2.pp svneol=native#text/plain
tests/test/tasm2a.pp svneol=native#text/plain

View File

@ -94,6 +94,9 @@ type
Function SetupVar(const s:string;GetOffset : boolean): Boolean;
Function CheckOperand: boolean; virtual;
Procedure InitRef;
Procedure InitRefConvertLocal;
protected
Procedure InitRefError;
end;
TCOperand = class of TOperand;
@ -177,7 +180,7 @@ Function GetRecordOffsetSize(s:string;Var Offset: aint;var Size:aint; var mangle
Function SearchType(const hs:string;var size:aint): Boolean;
Function SearchRecordType(const s:string): boolean;
Function SearchIConstant(const s:string; var l:aint): boolean;
Function AsmRegisterPara(sym: tabstractnormalvarsym): boolean;
{---------------------------------------------------------------------
Instruction generation routines
@ -1030,16 +1033,56 @@ Begin
opr.ref_farproc_entry:=hsym_farprocentry;
end;
else
begin
Message(asmr_e_invalid_operand_type);
{ Recover }
opr.typ:=OPR_REFERENCE;
opr.varsize:=0;
opr.constoffset:=0;
opr.ref_farproc_entry:=false;
Fillchar(opr.ref,sizeof(treference),0);
end;
end;
InitRefError;
end;
end;
procedure TOperand.InitRefConvertLocal;
var
localvarsize,localconstoffset: asizeint;
localsym:tabstractnormalvarsym;
localsymofs:aint;
localindexreg:tregister;
localscale:byte;
begin
if opr.typ=OPR_LOCAL then
begin
if AsmRegisterPara(opr.localsym) and
not opr.localgetoffset then
begin
localvarsize:=opr.localvarsize;
localconstoffset:=opr.localconstoffset;
localsym:=opr.localsym;
localsymofs:=opr.localsymofs;
localindexreg:=opr.localindexreg;
localscale:=opr.localscale;;
opr.typ:=OPR_REFERENCE;
hasvar:=false;
Fillchar(opr.ref,sizeof(treference),0);
opr.varsize:=localvarsize;
opr.constoffset:=localconstoffset;
opr.ref_farproc_entry:=false;
opr.ref.base:=tparavarsym(localsym).paraloc[calleeside].Location^.register;
opr.ref.offset:=localsymofs;
opr.ref.index:=localindexreg;
opr.ref.scalefactor:=localscale;
end
else
InitRefError;
end
else
InitRef;
end;
procedure TOperand.InitRefError;
begin
Message(asmr_e_invalid_operand_type);
{ Recover }
opr.typ:=OPR_REFERENCE;
opr.varsize:=0;
opr.constoffset:=0;
opr.ref_farproc_entry:=false;
Fillchar(opr.ref,sizeof(treference),0);
end;
Function TOperand.CheckOperand: boolean;
@ -1278,6 +1321,15 @@ Begin
end;
function AsmRegisterPara(sym: tabstractnormalvarsym): boolean;
begin
result:=
(po_assembler in current_procinfo.procdef.procoptions) and
(sym.typ=paravarsym) and
(tparavarsym(sym).paraloc[calleeside].Location^.Loc=LOC_REGISTER);
end;
Function GetRecordOffsetSize(s:string;Var Offset: aint;var Size:aint; var mangledname: string; needvmtofs: boolean; out hastypecast: boolean):boolean;
{ search and returns the offset and size of records/objects of the base }
{ with field name setup in field. }

View File

@ -229,24 +229,12 @@ Unit Rax86int;
function tx86intreader.is_register(const s:string):boolean;
var
entry: TSymEntry;
begin
is_register:=false;
actasmregister:=masm_regnum_search(lower(s));
{ don't acceps "flags" as register name in an instruction }
if (getsupreg(actasmregister)=RS_DEFAULTFLAGS) and (getregtype(actasmregister)=getregtype(NR_DEFAULTFLAGS)) then
actasmregister:=NR_NO;
if (actasmregister=NR_NO) and
(po_assembler in current_procinfo.procdef.procoptions) then
begin
entry:=current_procinfo.procdef.parast.Find(s);
if assigned(entry) and
(entry.typ=paravarsym) and
assigned(tparavarsym(entry).paraloc[calleeside].Location) and
(tparavarsym(entry).paraloc[calleeside].Location^.Loc=LOC_REGISTER) then
actasmregister:=tparavarsym(entry).paraloc[calleeside].Location^.register;
end;
if actasmregister<>NR_NO then
begin
is_register:=true;
@ -1320,9 +1308,10 @@ Unit Rax86int;
else
if oper.SetupVar(tempstr,GotOffset) then
begin
{ force OPR_LOCAL to be a reference }
if oper.opr.typ=OPR_LOCAL then
oper.opr.localforceref:=true
{ convert OPR_LOCAL register para into a reference base }
if (oper.opr.typ=OPR_LOCAL) and
AsmRegisterPara(oper.opr.localsym) then
oper.InitRefConvertLocal
else
begin
{$ifdef x86_64}

41
tests/test/tasm10a.pp Normal file
View File

@ -0,0 +1,41 @@
{ %cpu=x86_64 }
program asmclass;
{$mode delphiunicode}
{$asmmode intel}
type
TMyClass = class
public
Data: longint;
function AsmToClass: longint; ms_abi_default;
end;
function TMyClass.AsmToClass: longint; ms_abi_default;
asm
mov RAX, Self.Data // Error: Can't access fields directly for parameters
end;
function AsmToClassProc(Inst: TMyClass): longint; ms_abi_default;
asm
mov RAX, Inst.Data // Error: Can't access fields directly for parameters
end;
function AsmToClassProc2(Inst: TMyClass): pointer; ms_abi_default;
asm
mov RAX, qword ptr [Inst]
end;
var
C: TMyClass;
begin
C := TMyClass.Create;
c.data:=123548;
if C.AsmToClass<>123548 then
halt(1);
if AsmToClassProc(C)<>123548 then
halt(2);
if AsmToClassProc2(C)<>ppointer(c)^ then
halt(3);
C.Free;
end.