mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 08:38:14 +02:00

containing multiple locals, instead of creating multiple tai_local directives, each containing a single local. No functional changes.
3892 lines
115 KiB
ObjectPascal
3892 lines
115 KiB
ObjectPascal
{
|
|
Copyright (c) 2019 by Free Pascal and Lazarus foundation
|
|
|
|
Contains the assembler object for the WebAssembly
|
|
|
|
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 aasmcpu;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
cclasses,
|
|
globtype,globals,verbose,
|
|
aasmbase,aasmtai,aasmdata,aasmsym,
|
|
cgbase,cgutils,cpubase,cpuinfo,ogbase,
|
|
symtype,
|
|
widestr;
|
|
|
|
{ fake, there are no "mov reg,reg" instructions here }
|
|
const
|
|
{ "mov reg,reg" source operand number }
|
|
O_MOV_SOURCE = 0;
|
|
{ "mov reg,reg" source operand number }
|
|
O_MOV_DEST = 0;
|
|
|
|
type
|
|
TWasmBasicTypeList = array of TWasmBasicType;
|
|
|
|
{ TWasmGlobalAsmSymbol }
|
|
|
|
TWasmGlobalAsmSymbol = class(TAsmSymbol)
|
|
private
|
|
FWasmGlobalType: TWasmBasicType;
|
|
procedure SetWasmGlobalType(AValue: TWasmBasicType);
|
|
public
|
|
property WasmGlobalType: TWasmBasicType read FWasmGlobalType write SetWasmGlobalType;
|
|
end;
|
|
|
|
{ TWasmValueStack }
|
|
|
|
TWasmValueStack = class
|
|
private
|
|
FValStack: array of TWasmBasicType;
|
|
function GetCount: Integer;
|
|
function GetItems(AIndex: Integer): TWasmBasicType;
|
|
procedure SetCount(AValue: Integer);
|
|
procedure SetItems(AIndex: Integer; AValue: TWasmBasicType);
|
|
public
|
|
procedure Push(wbt: TWasmBasicType);
|
|
function Pop: TWasmBasicType;
|
|
property Items[AIndex: Integer]: TWasmBasicType read GetItems write SetItems; default;
|
|
property Count: Integer read GetCount write SetCount;
|
|
end;
|
|
|
|
{ TWasmControlFrame }
|
|
|
|
PWasmControlFrame = ^TWasmControlFrame;
|
|
TWasmControlFrame = record
|
|
opcode: tasmop;
|
|
start_types: TWasmBasicTypeList;
|
|
end_types: TWasmBasicTypeList;
|
|
height: Integer;
|
|
unreachable: Boolean;
|
|
end;
|
|
|
|
{ TWasmControlStack }
|
|
|
|
TWasmControlStack = class
|
|
private
|
|
FControlStack: array of TWasmControlFrame;
|
|
function GetCount: Integer;
|
|
function GetItems(AIndex: Integer): TWasmControlFrame;
|
|
function GetPItems(AIndex: Integer): PWasmControlFrame;
|
|
procedure SetItems(AIndex: Integer; const AValue: TWasmControlFrame);
|
|
public
|
|
procedure Push(const wcf: TWasmControlFrame);
|
|
function Pop: TWasmControlFrame;
|
|
property Items[AIndex: Integer]: TWasmControlFrame read GetItems write SetItems; default;
|
|
property PItems[AIndex: Integer]: PWasmControlFrame read GetPItems;
|
|
property Count: Integer read GetCount;
|
|
end;
|
|
|
|
taicpu = class;
|
|
|
|
TGetLocalTypeProc = function(localidx: Integer): TWasmBasicType of object;
|
|
|
|
{ TWasmValidationStacks }
|
|
|
|
TWasmValidationStacks = class
|
|
private
|
|
FValueStack: TWasmValueStack;
|
|
FCtrlStack: TWasmControlStack;
|
|
FGetLocalType: TGetLocalTypeProc;
|
|
FFuncType: TWasmFuncType;
|
|
FEndFunctionReached: Boolean;
|
|
public
|
|
constructor Create(AGetLocalType: TGetLocalTypeProc; AFuncType: TWasmFuncType);
|
|
destructor Destroy; override;
|
|
|
|
procedure PushVal(vt: TWasmBasicType);
|
|
function PopVal: TWasmBasicType;
|
|
function PopVal(expect: TWasmBasicType): TWasmBasicType;
|
|
function PopVal_RefType: TWasmBasicType;
|
|
procedure PushVals(vals: TWasmBasicTypeList);
|
|
function PopVals(vals: TWasmBasicTypeList): TWasmBasicTypeList;
|
|
|
|
procedure PushCtrl(_opcode: tasmop; _in, _out: TWasmBasicTypeList);
|
|
function PopCtrl: TWasmControlFrame;
|
|
|
|
function label_types(const frame: TWasmControlFrame): TWasmBasicTypeList;
|
|
procedure Unreachable;
|
|
|
|
procedure Validate(a: taicpu);
|
|
end;
|
|
|
|
twasmstruc_stack = class;
|
|
TAsmMapFuncResultType = (amfrtNoChange, amfrtNewAi, amfrtNewList, amfrtDeleteAi);
|
|
TAsmMapFuncResult = record
|
|
case typ: TAsmMapFuncResultType of
|
|
amfrtNoChange: ();
|
|
amfrtNewAi: (newai: tai);
|
|
amfrtNewList: (newlist: TAsmList);
|
|
amfrtDeleteAi: ();
|
|
end;
|
|
TAsmMapFunc = function(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult of object;
|
|
TWasmLocalAllocator = function(wbt: TWasmBasicType): Integer of object;
|
|
|
|
{ taicpu }
|
|
|
|
taicpu = class(tai_cpu_abstract_sym)
|
|
private
|
|
insoffset : longint;
|
|
public
|
|
is_br_generated_by_goto: boolean;
|
|
|
|
constructor Create(op : tasmop);override;
|
|
|
|
constructor op_none(op : tasmop);
|
|
|
|
constructor op_reg(op : tasmop;_op1 : tregister);
|
|
constructor op_const(op : tasmop;_op1 : aint);
|
|
constructor op_ref(op : tasmop;const _op1 : treference);
|
|
constructor op_sym(op : tasmop;_op1 : tasmsymbol);
|
|
|
|
constructor op_sym_const(op : tasmop;_op1 : tasmsymbol;_op2 : aint);
|
|
constructor op_sym_functype(op : tasmop;_op1 : tasmsymbol;_op2 : TWasmFuncType);
|
|
|
|
constructor op_single(op : tasmop;_op1 : single);
|
|
constructor op_double(op : tasmop;_op1 : double);
|
|
|
|
constructor op_functype(op : tasmop; _op1: TWasmFuncType);
|
|
|
|
procedure loadfunctype(opidx:longint;ft:TWasmFuncType);
|
|
procedure loadsingle(opidx:longint;f:single);
|
|
procedure loaddouble(opidx:longint;d:double);
|
|
|
|
{ register allocation }
|
|
function is_same_reg_move(regtype: Tregistertype):boolean; override;
|
|
|
|
{ register spilling code }
|
|
function spilling_get_operation_type(opnr: longint): topertype;override;
|
|
|
|
function Pass1(objdata:TObjData):longint;override;
|
|
procedure Pass2(objdata:TObjData);override;
|
|
end;
|
|
|
|
taiwstype = (
|
|
aitws_if,
|
|
aitws_block,
|
|
aitws_loop,
|
|
aitws_try_delegate,
|
|
aitws_try_catch
|
|
);
|
|
|
|
{ taicpu_wasm_structured_instruction }
|
|
|
|
taicpu_wasm_structured_instruction = class(tai)
|
|
protected
|
|
FLabel: TAsmLabel;
|
|
FLabelIsNew: Boolean;
|
|
public
|
|
wstyp: taiwstype;
|
|
|
|
constructor Create;
|
|
procedure Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);virtual;abstract;
|
|
procedure ConvertToFlatList(l: TAsmList);virtual;abstract;
|
|
function getlabel: TAsmLabel;
|
|
end;
|
|
|
|
{ tai_wasmstruc_if }
|
|
|
|
tai_wasmstruc_if = class(taicpu_wasm_structured_instruction)
|
|
if_instr: taicpu;
|
|
then_asmlist: TAsmList;
|
|
else_asmlist: TAsmList;
|
|
|
|
constructor create_from(a_if_instr: taicpu; srclist: TAsmList);
|
|
destructor Destroy; override;
|
|
function getcopy:TLinkedListItem;override;
|
|
procedure Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);override;
|
|
procedure ConvertToFlatList(l: TAsmList);override;
|
|
procedure ConvertToBrIf(list: TAsmList; local_alloc: TWasmLocalAllocator);
|
|
end;
|
|
|
|
{ tai_wasmstruc_block }
|
|
|
|
tai_wasmstruc_block = class(taicpu_wasm_structured_instruction)
|
|
block_instr: taicpu;
|
|
inner_asmlist: TAsmList;
|
|
|
|
constructor create_from(a_block_instr: taicpu; srclist: TAsmList);
|
|
destructor Destroy; override;
|
|
function getcopy:TLinkedListItem;override;
|
|
procedure Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);override;
|
|
procedure ConvertToFlatList(l: TAsmList);override;
|
|
end;
|
|
|
|
{ tai_wasmstruc_loop }
|
|
|
|
tai_wasmstruc_loop = class(taicpu_wasm_structured_instruction)
|
|
loop_instr: taicpu;
|
|
inner_asmlist: TAsmList;
|
|
|
|
constructor create_from(a_loop_instr: taicpu; srclist: TAsmList);
|
|
destructor Destroy; override;
|
|
function getcopy:TLinkedListItem;override;
|
|
procedure Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);override;
|
|
procedure ConvertToBr(list: TAsmList);
|
|
procedure ConvertToFlatList(l: TAsmList);override;
|
|
end;
|
|
|
|
{ tai_wasmstruc_try }
|
|
|
|
tai_wasmstruc_try = class(taicpu_wasm_structured_instruction)
|
|
private
|
|
class function create_from(srclist: TAsmList): tai_wasmstruc_try;
|
|
public
|
|
try_asmlist: TAsmList;
|
|
|
|
constructor internal_create(a_try_asmlist: TAsmList);
|
|
destructor Destroy; override;
|
|
function getcopy:TLinkedListItem;override;
|
|
procedure ConvertToFlatList(l: TAsmList);override;
|
|
end;
|
|
|
|
{ tai_wasmstruc_try_delegate }
|
|
|
|
tai_wasmstruc_try_delegate = class(tai_wasmstruc_try)
|
|
delegate_instr: taicpu;
|
|
|
|
constructor internal_create(first_ins: taicpu; a_try_asmlist, srclist: TAsmList);
|
|
destructor Destroy; override;
|
|
function getcopy:TLinkedListItem;override;
|
|
procedure Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);override;
|
|
procedure ConvertToFlatList(l: TAsmList);override;
|
|
end;
|
|
|
|
{ tai_wasmstruc_try_catch }
|
|
|
|
tai_wasmstruc_try_catch = class(tai_wasmstruc_try)
|
|
catch_list: array of record
|
|
catch_instr: taicpu;
|
|
asmlist: TAsmList;
|
|
end;
|
|
catch_all_asmlist: TAsmList;
|
|
|
|
constructor internal_create(first_ins: taicpu; a_try_asmlist, srclist: TAsmList);
|
|
destructor Destroy; override;
|
|
function getcopy:TLinkedListItem;override;
|
|
procedure Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);override;
|
|
procedure ConvertToFlatList(l: TAsmList);override;
|
|
end;
|
|
|
|
{ twasmstruc_stack }
|
|
|
|
twasmstruc_stack = class
|
|
private
|
|
FStack: array of taicpu_wasm_structured_instruction;
|
|
function Get(Index: Integer): taicpu_wasm_structured_instruction;
|
|
public
|
|
procedure push(ins: taicpu_wasm_structured_instruction);
|
|
procedure pop;
|
|
property Items [Index: Integer]: taicpu_wasm_structured_instruction read Get;default;
|
|
end;
|
|
|
|
tai_align = class(tai_align_abstract)
|
|
{ nothing to add }
|
|
end;
|
|
|
|
TImpExpType= (
|
|
ie_Func, // functions
|
|
ie_Table, // tables (arrays of methods)
|
|
ie_Memory, // memory reference
|
|
ie_Global // global variables
|
|
);
|
|
|
|
{ tai_export_name }
|
|
|
|
tai_export_name = class(tai)
|
|
extname : ansistring; // external name
|
|
intname : ansistring; // internal name
|
|
symstype: TImpExpType;
|
|
constructor create(const aextname, aintname: ansistring; asymtype: timpexptype);
|
|
end;
|
|
|
|
// local variable declaration
|
|
|
|
{ tai_local }
|
|
|
|
tai_local = class(tai)
|
|
locals: TWasmLocalsDynArray;
|
|
constructor create(alocals: TWasmLocalsDynArray);
|
|
procedure AddLocal(abasictype: TWasmBasicType);
|
|
procedure AddLocals(alocals: TWasmLocalsDynArray);
|
|
end;
|
|
|
|
{ tai_globaltype }
|
|
|
|
tai_globaltype = class(tai)
|
|
globalname: string;
|
|
gtype: TWasmBasicType;
|
|
immutable: boolean;
|
|
is_external: boolean;
|
|
is_global: boolean;
|
|
sym : TWasmGlobalAsmSymbol;
|
|
constructor create(const aglobalname:string; atype: TWasmBasicType; aimmutable: boolean);
|
|
constructor create_local(const aglobalname:string; atype: TWasmBasicType; aimmutable: boolean; def: tdef);
|
|
constructor create_global(const aglobalname:string; atype: TWasmBasicType; aimmutable: boolean; def: tdef);
|
|
end;
|
|
|
|
{ tai_functype }
|
|
|
|
tai_functype = class(tai)
|
|
funcname: string;
|
|
functype: TWasmFuncType;
|
|
is_forward: Boolean;
|
|
constructor create(const afuncname: string; afunctype: TWasmFuncType; aisforward: Boolean);
|
|
destructor destroy;override;
|
|
end;
|
|
|
|
{ tai_tagtype }
|
|
|
|
tai_tagtype = class(tai)
|
|
tagname: string;
|
|
params: TWasmResultType;
|
|
constructor create(const atagname: string; aparams: TWasmResultType);
|
|
end;
|
|
|
|
{ tai_import_module }
|
|
|
|
tai_import_module = class(tai)
|
|
symname: string;
|
|
importmodule: string;
|
|
constructor create(const asymname, aimportmodule: string);
|
|
end;
|
|
|
|
{ tai_import_name }
|
|
|
|
tai_import_name = class(tai)
|
|
symname: string;
|
|
importname: string;
|
|
constructor create(const asymname, aimportname: string);
|
|
end;
|
|
|
|
procedure InitAsm;
|
|
procedure DoneAsm;
|
|
|
|
function spilling_create_load(const ref:treference;r:tregister):Taicpu;
|
|
function spilling_create_store(r:tregister; const ref:treference):Taicpu;
|
|
|
|
procedure wasm_convert_to_structured_asmlist(var asmlist: TAsmList);
|
|
procedure wasm_convert_to_flat_asmlist(var asmlist: TAsmList);
|
|
procedure map_structured_asmlist(l: TAsmList; f: TAsmMapFunc);
|
|
|
|
implementation
|
|
|
|
uses
|
|
ogwasm;
|
|
|
|
function wasm_convert_first_item_to_structured(srclist: TAsmList): tai; forward;
|
|
procedure map_structured_asmlist_inner(l: TAsmList; f: TAsmMapFunc; blockstack: twasmstruc_stack); forward;
|
|
|
|
{ TWasmGlobalAsmSymbol }
|
|
|
|
procedure TWasmGlobalAsmSymbol.SetWasmGlobalType(AValue: TWasmBasicType);
|
|
begin
|
|
if FWasmGlobalType=AValue then
|
|
Exit;
|
|
if FWasmGlobalType<>wbt_Unknown then
|
|
Internalerror(2024022503);
|
|
FWasmGlobalType:=AValue;
|
|
end;
|
|
|
|
{ TWasmValueStack }
|
|
|
|
function TWasmValueStack.GetItems(AIndex: Integer): TWasmBasicType;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I:=High(FValStack)-AIndex;
|
|
if (I<Low(FValStack)) or (I>High(FValStack)) then
|
|
internalerror(2024011702);
|
|
Result:=FValStack[I];
|
|
end;
|
|
|
|
procedure TWasmValueStack.SetCount(AValue: Integer);
|
|
begin
|
|
SetLength(FValStack,AValue);
|
|
end;
|
|
|
|
function TWasmValueStack.GetCount: Integer;
|
|
begin
|
|
Result:=Length(FValStack);
|
|
end;
|
|
|
|
procedure TWasmValueStack.SetItems(AIndex: Integer; AValue: TWasmBasicType);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I:=High(FValStack)-AIndex;
|
|
if (I<Low(FValStack)) or (I>High(FValStack)) then
|
|
internalerror(2024011703);
|
|
FValStack[I]:=AValue;
|
|
end;
|
|
|
|
procedure TWasmValueStack.Push(wbt: TWasmBasicType);
|
|
begin
|
|
SetLength(FValStack,Length(FValStack)+1);
|
|
FValStack[High(FValStack)]:=wbt;
|
|
end;
|
|
|
|
function TWasmValueStack.Pop: TWasmBasicType;
|
|
begin
|
|
if Length(FValStack)=0 then
|
|
internalerror(2024011701);
|
|
Result:=FValStack[High(FValStack)];
|
|
SetLength(FValStack,Length(FValStack)-1);
|
|
end;
|
|
|
|
{ TWasmControlStack }
|
|
|
|
function TWasmControlStack.GetItems(AIndex: Integer): TWasmControlFrame;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I:=High(FControlStack)-AIndex;
|
|
if (I<Low(FControlStack)) or (I>High(FControlStack)) then
|
|
internalerror(2024013101);
|
|
Result:=FControlStack[I];
|
|
end;
|
|
|
|
function TWasmControlStack.GetPItems(AIndex: Integer): PWasmControlFrame;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I:=High(FControlStack)-AIndex;
|
|
if (I<Low(FControlStack)) or (I>High(FControlStack)) then
|
|
internalerror(2024013101);
|
|
Result:=@(FControlStack[I]);
|
|
end;
|
|
|
|
function TWasmControlStack.GetCount: Integer;
|
|
begin
|
|
Result:=Length(FControlStack);
|
|
end;
|
|
|
|
procedure TWasmControlStack.SetItems(AIndex: Integer; const AValue: TWasmControlFrame);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I:=High(FControlStack)-AIndex;
|
|
if (I<Low(FControlStack)) or (I>High(FControlStack)) then
|
|
internalerror(2024013102);
|
|
FControlStack[I]:=AValue;
|
|
end;
|
|
|
|
procedure TWasmControlStack.Push(const wcf: TWasmControlFrame);
|
|
begin
|
|
SetLength(FControlStack,Length(FControlStack)+1);
|
|
FControlStack[High(FControlStack)]:=wcf;
|
|
end;
|
|
|
|
function TWasmControlStack.Pop: TWasmControlFrame;
|
|
begin
|
|
if Length(FControlStack)=0 then
|
|
internalerror(2024013103);
|
|
Result:=FControlStack[High(FControlStack)];
|
|
SetLength(FControlStack,Length(FControlStack)-1);
|
|
end;
|
|
|
|
{ TWasmValidationStacks }
|
|
|
|
constructor TWasmValidationStacks.Create(AGetLocalType: TGetLocalTypeProc; AFuncType: TWasmFuncType);
|
|
begin
|
|
FEndFunctionReached:=False;
|
|
FGetLocalType:=AGetLocalType;
|
|
FValueStack:=TWasmValueStack.Create;
|
|
FCtrlStack:=TWasmControlStack.Create;
|
|
FFuncType:=AFuncType;
|
|
PushCtrl(a_block,[],[]);
|
|
end;
|
|
|
|
destructor TWasmValidationStacks.Destroy;
|
|
begin
|
|
FValueStack.Free;
|
|
FCtrlStack.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TWasmValidationStacks.PushVal(vt: TWasmBasicType);
|
|
begin
|
|
FValueStack.Push(vt);
|
|
end;
|
|
|
|
function TWasmValidationStacks.PopVal: TWasmBasicType;
|
|
begin
|
|
if FValueStack.Count = FCtrlStack[0].height then
|
|
begin
|
|
Result:=wbt_Unknown;
|
|
if not FCtrlStack[0].unreachable then
|
|
internalerror(2024013104);
|
|
end
|
|
else
|
|
Result:=FValueStack.Pop;
|
|
end;
|
|
|
|
function TWasmValidationStacks.PopVal(expect: TWasmBasicType): TWasmBasicType;
|
|
begin
|
|
Result:=wbt_Unknown;
|
|
Result:=PopVal();
|
|
if (Result<>expect) and (Result<>wbt_Unknown) and (expect<>wbt_Unknown) then
|
|
internalerror(2024013105);
|
|
end;
|
|
|
|
function TWasmValidationStacks.PopVal_RefType: TWasmBasicType;
|
|
begin
|
|
Result:=wbt_Unknown;
|
|
Result:=PopVal;
|
|
if not (Result in (WasmReferenceTypes + [wbt_Unknown])) then
|
|
internalerror(2024020501);
|
|
end;
|
|
|
|
procedure TWasmValidationStacks.PushVals(vals: TWasmBasicTypeList);
|
|
var
|
|
v: TWasmBasicType;
|
|
begin
|
|
for v in vals do
|
|
PushVal(v);
|
|
end;
|
|
|
|
function TWasmValidationStacks.PopVals(vals: TWasmBasicTypeList): TWasmBasicTypeList;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result:=nil;
|
|
SetLength(Result,Length(vals));
|
|
for I:=High(vals) downto Low(Vals) do
|
|
Result[I]:=PopVal(vals[I]);
|
|
end;
|
|
|
|
procedure TWasmValidationStacks.PushCtrl(_opcode: tasmop; _in, _out: TWasmBasicTypeList);
|
|
var
|
|
frame: TWasmControlFrame;
|
|
begin
|
|
FillChar(frame,SizeOf(frame),0);
|
|
with frame do
|
|
begin
|
|
opcode:=_opcode;
|
|
start_types:=Copy(_in);
|
|
end_types:=Copy(_out);
|
|
height:=FValueStack.Count;
|
|
unreachable:=False;
|
|
end;
|
|
FCtrlStack.Push(frame);
|
|
end;
|
|
|
|
function TWasmValidationStacks.PopCtrl: TWasmControlFrame;
|
|
begin
|
|
Result:=Default(TWasmControlFrame);
|
|
if FCtrlStack.Count=0 then
|
|
internalerror(2024013106);
|
|
Result:=FCtrlStack[0];
|
|
PopVals(Result.end_types);
|
|
if FValueStack.Count<>Result.height then
|
|
internalerror(2024013107);
|
|
FCtrlStack.Pop;
|
|
end;
|
|
|
|
function TWasmValidationStacks.label_types(const frame: TWasmControlFrame): TWasmBasicTypeList;
|
|
begin
|
|
if frame.opcode=a_loop then
|
|
Result:=frame.start_types
|
|
else
|
|
Result:=frame.end_types;
|
|
end;
|
|
|
|
procedure TWasmValidationStacks.Unreachable;
|
|
var
|
|
c: PWasmControlFrame;
|
|
begin
|
|
c:=FCtrlStack.PItems[0];
|
|
FValueStack.Count:=c^.height;
|
|
c^.unreachable:=true;
|
|
end;
|
|
|
|
procedure TWasmValidationStacks.Validate(a: taicpu);
|
|
|
|
function GetLocalIndex: Integer;
|
|
begin
|
|
Result:=-1;
|
|
with a do
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2024020801);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
internalerror(2024020802);
|
|
if ref^.base<>NR_STACK_POINTER_REG then
|
|
internalerror(2024020803);
|
|
if ref^.index<>NR_NO then
|
|
internalerror(2024020804);
|
|
Result:=ref^.offset;
|
|
end;
|
|
top_const:
|
|
Result:=val;
|
|
else
|
|
internalerror(2024020805);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
frame: TWasmControlFrame;
|
|
n: TCGInt;
|
|
begin
|
|
if FEndFunctionReached then
|
|
internalerror(2024022602);
|
|
case a.opcode of
|
|
a_nop:
|
|
;
|
|
a_i32_const:
|
|
PushVal(wbt_i32);
|
|
a_i64_const:
|
|
PushVal(wbt_i64);
|
|
a_f32_const:
|
|
PushVal(wbt_f32);
|
|
a_f64_const:
|
|
PushVal(wbt_f64);
|
|
a_i32_add,
|
|
a_i32_sub,
|
|
a_i32_mul,
|
|
a_i32_div_s, a_i32_div_u,
|
|
a_i32_rem_s, a_i32_rem_u,
|
|
a_i32_and,
|
|
a_i32_or,
|
|
a_i32_xor,
|
|
a_i32_shl,
|
|
a_i32_shr_s, a_i32_shr_u,
|
|
a_i32_rotl,
|
|
a_i32_rotr:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_add,
|
|
a_i64_sub,
|
|
a_i64_mul,
|
|
a_i64_div_s, a_i64_div_u,
|
|
a_i64_rem_s, a_i64_rem_u,
|
|
a_i64_and,
|
|
a_i64_or,
|
|
a_i64_xor,
|
|
a_i64_shl,
|
|
a_i64_shr_s, a_i64_shr_u,
|
|
a_i64_rotl,
|
|
a_i64_rotr:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_i64);
|
|
end;
|
|
a_f32_add,
|
|
a_f32_sub,
|
|
a_f32_mul,
|
|
a_f32_div,
|
|
a_f32_min,
|
|
a_f32_max,
|
|
a_f32_copysign:
|
|
begin
|
|
PopVal(wbt_f32);
|
|
PopVal(wbt_f32);
|
|
PushVal(wbt_f32);
|
|
end;
|
|
a_f64_add,
|
|
a_f64_sub,
|
|
a_f64_mul,
|
|
a_f64_div,
|
|
a_f64_min,
|
|
a_f64_max,
|
|
a_f64_copysign:
|
|
begin
|
|
PopVal(wbt_f64);
|
|
PopVal(wbt_f64);
|
|
PushVal(wbt_f64);
|
|
end;
|
|
a_i32_clz,
|
|
a_i32_ctz,
|
|
a_i32_popcnt:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_clz,
|
|
a_i64_ctz,
|
|
a_i64_popcnt:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_i64);
|
|
end;
|
|
a_f32_abs,
|
|
a_f32_neg,
|
|
a_f32_sqrt,
|
|
a_f32_ceil,
|
|
a_f32_floor,
|
|
a_f32_trunc,
|
|
a_f32_nearest:
|
|
begin
|
|
PopVal(wbt_f32);
|
|
PushVal(wbt_f32);
|
|
end;
|
|
a_f64_abs,
|
|
a_f64_neg,
|
|
a_f64_sqrt,
|
|
a_f64_ceil,
|
|
a_f64_floor,
|
|
a_f64_trunc,
|
|
a_f64_nearest:
|
|
begin
|
|
PopVal(wbt_f64);
|
|
PushVal(wbt_f64);
|
|
end;
|
|
a_i32_eqz:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_eqz:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i32_eq,
|
|
a_i32_ne,
|
|
a_i32_lt_s, a_i32_lt_u,
|
|
a_i32_gt_s, a_i32_gt_u,
|
|
a_i32_le_s, a_i32_le_u,
|
|
a_i32_ge_s, a_i32_ge_u:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_eq,
|
|
a_i64_ne,
|
|
a_i64_lt_s, a_i64_lt_u,
|
|
a_i64_gt_s, a_i64_gt_u,
|
|
a_i64_le_s, a_i64_le_u,
|
|
a_i64_ge_s, a_i64_ge_u:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_f32_eq,
|
|
a_f32_ne,
|
|
a_f32_lt,
|
|
a_f32_gt,
|
|
a_f32_le,
|
|
a_f32_ge:
|
|
begin
|
|
PopVal(wbt_f32);
|
|
PopVal(wbt_f32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_f64_eq,
|
|
a_f64_ne,
|
|
a_f64_lt,
|
|
a_f64_gt,
|
|
a_f64_le,
|
|
a_f64_ge:
|
|
begin
|
|
PopVal(wbt_f64);
|
|
PopVal(wbt_f64);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i32_extend8_s,
|
|
a_i32_extend16_s:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_extend8_s,
|
|
a_i64_extend16_s,
|
|
a_i64_extend32_s:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_i64);
|
|
end;
|
|
a_i32_wrap_i64:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_extend_i32_s,
|
|
a_i64_extend_i32_u:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i64);
|
|
end;
|
|
a_i32_trunc_f32_s,
|
|
a_i32_trunc_f32_u,
|
|
a_i32_trunc_sat_f32_s,
|
|
a_i32_trunc_sat_f32_u:
|
|
begin
|
|
PopVal(wbt_f32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i32_trunc_f64_s,
|
|
a_i32_trunc_f64_u,
|
|
a_i32_trunc_sat_f64_s,
|
|
a_i32_trunc_sat_f64_u:
|
|
begin
|
|
PopVal(wbt_f64);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_trunc_f32_s,
|
|
a_i64_trunc_f32_u,
|
|
a_i64_trunc_sat_f32_s,
|
|
a_i64_trunc_sat_f32_u:
|
|
begin
|
|
PopVal(wbt_f32);
|
|
PushVal(wbt_i64);
|
|
end;
|
|
a_i64_trunc_f64_s,
|
|
a_i64_trunc_f64_u,
|
|
a_i64_trunc_sat_f64_s,
|
|
a_i64_trunc_sat_f64_u:
|
|
begin
|
|
PopVal(wbt_f64);
|
|
PushVal(wbt_i64);
|
|
end;
|
|
a_f32_demote_f64:
|
|
begin
|
|
PopVal(wbt_f64);
|
|
PushVal(wbt_f32);
|
|
end;
|
|
a_f64_promote_f32:
|
|
begin
|
|
PopVal(wbt_f32);
|
|
PushVal(wbt_f64);
|
|
end;
|
|
a_f32_convert_i32_s,
|
|
a_f32_convert_i32_u:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_f32);
|
|
end;
|
|
a_f32_convert_i64_s,
|
|
a_f32_convert_i64_u:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_f32);
|
|
end;
|
|
a_f64_convert_i32_s,
|
|
a_f64_convert_i32_u:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_f64);
|
|
end;
|
|
a_f64_convert_i64_s,
|
|
a_f64_convert_i64_u:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_f64);
|
|
end;
|
|
a_i32_reinterpret_f32:
|
|
begin
|
|
PopVal(wbt_f32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_reinterpret_f64:
|
|
begin
|
|
PopVal(wbt_f64);
|
|
PushVal(wbt_i64);
|
|
end;
|
|
a_f32_reinterpret_i32:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_f32);
|
|
end;
|
|
a_f64_reinterpret_i64:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PushVal(wbt_f64);
|
|
end;
|
|
a_ref_null_externref:
|
|
PushVal(wbt_externref);
|
|
a_ref_null_funcref:
|
|
PushVal(wbt_funcref);
|
|
a_ref_is_null:
|
|
begin
|
|
PopVal_RefType;
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_drop:
|
|
PopVal;
|
|
a_unreachable:
|
|
Unreachable;
|
|
a_i32_load,
|
|
a_i32_load16_s, a_i32_load16_u,
|
|
a_i32_load8_s, a_i32_load8_u:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_i64_load,
|
|
a_i64_load32_s, a_i64_load32_u,
|
|
a_i64_load16_s, a_i64_load16_u,
|
|
a_i64_load8_s, a_i64_load8_u:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i64);
|
|
end;
|
|
a_f32_load:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_f32);
|
|
end;
|
|
a_f64_load:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_f64);
|
|
end;
|
|
a_i32_store,
|
|
a_i32_store16,
|
|
a_i32_store8:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PopVal(wbt_i32);
|
|
end;
|
|
a_i64_store,
|
|
a_i64_store32,
|
|
a_i64_store16,
|
|
a_i64_store8:
|
|
begin
|
|
PopVal(wbt_i64);
|
|
PopVal(wbt_i32);
|
|
end;
|
|
a_f32_store:
|
|
begin
|
|
PopVal(wbt_f32);
|
|
PopVal(wbt_i32);
|
|
end;
|
|
a_f64_store:
|
|
begin
|
|
PopVal(wbt_f64);
|
|
PopVal(wbt_i32);
|
|
end;
|
|
a_memory_size:
|
|
PushVal(wbt_i32);
|
|
a_memory_grow:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PushVal(wbt_i32);
|
|
end;
|
|
a_memory_fill,
|
|
a_memory_copy:
|
|
begin
|
|
PopVal(wbt_i32);
|
|
PopVal(wbt_i32);
|
|
PopVal(wbt_i32);
|
|
end;
|
|
a_local_get:
|
|
PushVal(FGetLocalType(GetLocalIndex));
|
|
a_local_set:
|
|
PopVal(FGetLocalType(GetLocalIndex));
|
|
a_local_tee:
|
|
begin
|
|
PopVal(FGetLocalType(GetLocalIndex));
|
|
PushVal(FGetLocalType(GetLocalIndex));
|
|
end;
|
|
a_global_get,
|
|
a_global_set:
|
|
begin
|
|
if a.ops<>1 then
|
|
internalerror(2024022504);
|
|
if a.oper[0]^.typ<>top_ref then
|
|
internalerror(2024022505);
|
|
if not assigned(a.oper[0]^.ref^.symbol) then
|
|
internalerror(2024022506);
|
|
if (a.oper[0]^.ref^.base<>NR_NO) or (a.oper[0]^.ref^.index<>NR_NO) or (a.oper[0]^.ref^.offset<>0) then
|
|
internalerror(2024022507);
|
|
if a.oper[0]^.ref^.symbol.typ<>AT_WASM_GLOBAL then
|
|
internalerror(2024022508);
|
|
case a.opcode of
|
|
a_global_get:
|
|
PushVal(TWasmGlobalAsmSymbol(a.oper[0]^.ref^.symbol).WasmGlobalType);
|
|
a_global_set:
|
|
PopVal(TWasmGlobalAsmSymbol(a.oper[0]^.ref^.symbol).WasmGlobalType);
|
|
else
|
|
internalerror(2024022509);
|
|
end;
|
|
end;
|
|
a_call:
|
|
begin
|
|
if a.ops<>2 then
|
|
internalerror(2024022501);
|
|
if a.oper[1]^.typ<>top_functype then
|
|
internalerror(2024022502);
|
|
PopVals(a.oper[1]^.functype.params);
|
|
PushVals(a.oper[1]^.functype.results);
|
|
end;
|
|
a_call_indirect:
|
|
begin
|
|
if a.ops<>1 then
|
|
internalerror(2024022401);
|
|
if a.oper[0]^.typ<>top_functype then
|
|
internalerror(2024022402);
|
|
PopVal(wbt_i32);
|
|
PopVals(a.oper[0]^.functype.params);
|
|
PushVals(a.oper[0]^.functype.results);
|
|
end;
|
|
a_if,
|
|
a_block,
|
|
a_loop,
|
|
a_try:
|
|
begin
|
|
if a.opcode=a_if then
|
|
PopVal(wbt_i32);
|
|
if a.ops>1 then
|
|
internalerror(2024022510);
|
|
if a.ops=0 then
|
|
PushCtrl(a.opcode,[],[])
|
|
else
|
|
begin
|
|
if a.oper[0]^.typ<>top_functype then
|
|
internalerror(2024022511);
|
|
PopVals(a.oper[0]^.functype.params);
|
|
PushCtrl(a.opcode,a.oper[0]^.functype.params,a.oper[0]^.functype.results);
|
|
end;
|
|
end;
|
|
a_else:
|
|
begin
|
|
frame:=PopCtrl;
|
|
if frame.opcode<>a_if then
|
|
internalerror(2024022512);
|
|
PushCtrl(a_else,frame.start_types,frame.end_types);
|
|
end;
|
|
a_catch:
|
|
begin
|
|
frame:=PopCtrl;
|
|
if (frame.opcode<>a_try) and (frame.opcode<>a_catch) then
|
|
internalerror(2024022701);
|
|
PushCtrl(a_catch,frame.start_types,frame.end_types);
|
|
end;
|
|
a_end_if:
|
|
begin
|
|
frame:=PopCtrl;
|
|
if (frame.opcode<>a_if) and (frame.opcode<>a_else) then
|
|
internalerror(2024022513);
|
|
PushVals(frame.end_types);
|
|
end;
|
|
a_end_block:
|
|
begin
|
|
frame:=PopCtrl;
|
|
if frame.opcode<>a_block then
|
|
internalerror(2024022514);
|
|
PushVals(frame.end_types);
|
|
end;
|
|
a_end_loop:
|
|
begin
|
|
frame:=PopCtrl;
|
|
if frame.opcode<>a_loop then
|
|
internalerror(2024022515);
|
|
PushVals(frame.end_types);
|
|
end;
|
|
a_end_try:
|
|
begin
|
|
frame:=PopCtrl;
|
|
if (frame.opcode<>a_try) and (frame.opcode<>a_catch) then
|
|
internalerror(2024022702);
|
|
PushVals(frame.end_types);
|
|
end;
|
|
a_br:
|
|
begin
|
|
if a.ops<>1 then
|
|
internalerror(2024022516);
|
|
if a.oper[0]^.typ<>top_const then
|
|
internalerror(2024022517);
|
|
n:=a.oper[0]^.val;
|
|
if FCtrlStack.Count < n then
|
|
internalerror(2024022518);
|
|
PopVals(label_types(FCtrlStack[n]));
|
|
Unreachable;
|
|
end;
|
|
a_br_if:
|
|
begin
|
|
if a.ops<>1 then
|
|
internalerror(2024022519);
|
|
if a.oper[0]^.typ<>top_const then
|
|
internalerror(2024022520);
|
|
n:=a.oper[0]^.val;
|
|
if FCtrlStack.Count < n then
|
|
internalerror(2024022521);
|
|
PopVal(wbt_i32);
|
|
PopVals(label_types(FCtrlStack[n]));
|
|
PushVals(label_types(FCtrlStack[n]));
|
|
end;
|
|
a_throw:
|
|
Unreachable;
|
|
a_rethrow:
|
|
Unreachable;
|
|
a_return:
|
|
begin
|
|
PopVals(FFuncType.results);
|
|
Unreachable;
|
|
end;
|
|
a_end_function:
|
|
FEndFunctionReached:=True;
|
|
else
|
|
internalerror(2024030502);
|
|
end;
|
|
end;
|
|
|
|
{ twasmstruc_stack }
|
|
|
|
function twasmstruc_stack.Get(Index: Integer): taicpu_wasm_structured_instruction;
|
|
begin
|
|
{$push}{$r+,q+}
|
|
Result:=FStack[High(FStack)-Index];
|
|
{$pop}
|
|
end;
|
|
|
|
procedure twasmstruc_stack.push(ins: taicpu_wasm_structured_instruction);
|
|
begin
|
|
SetLength(FStack,Length(FStack)+1);
|
|
FStack[High(FStack)]:=ins;
|
|
end;
|
|
|
|
procedure twasmstruc_stack.pop;
|
|
begin
|
|
SetLength(FStack,Length(FStack)-1);
|
|
end;
|
|
|
|
{ taicpu_wasm_structured_instruction }
|
|
|
|
constructor taicpu_wasm_structured_instruction.Create;
|
|
begin
|
|
inherited;
|
|
typ:=ait_wasm_structured_instruction;
|
|
end;
|
|
|
|
function taicpu_wasm_structured_instruction.getlabel: TAsmLabel;
|
|
begin
|
|
if not assigned(FLabel) then
|
|
begin
|
|
current_asmdata.getjumplabel(FLabel);
|
|
FLabelIsNew:=true;
|
|
end;
|
|
result:=FLabel;
|
|
end;
|
|
|
|
{ tai_wasmstruc_if }
|
|
|
|
constructor tai_wasmstruc_if.create_from(a_if_instr: taicpu; srclist: TAsmList);
|
|
var
|
|
p: tai;
|
|
ThenDone, ElsePresent, ElseDone: Boolean;
|
|
begin
|
|
wstyp:=aitws_if;
|
|
inherited Create;
|
|
if assigned(a_if_instr.Previous) or assigned(a_if_instr.Next) then
|
|
internalerror(2023100301);
|
|
if_instr:=a_if_instr;
|
|
|
|
then_asmlist:=TAsmList.Create;
|
|
|
|
ThenDone:=False;
|
|
ElsePresent:=False;
|
|
repeat
|
|
p:=tai(srclist.First);
|
|
if not assigned(p) then
|
|
internalerror(2023100302);
|
|
if (p.typ=ait_instruction) and (taicpu(p).opcode in [a_else,a_end_if,a_end_block,a_end_loop,a_end_try,a_catch,a_catch_all,a_delegate]) then
|
|
begin
|
|
srclist.Remove(p);
|
|
case taicpu(p).opcode of
|
|
a_else:
|
|
begin
|
|
ThenDone:=True;
|
|
ElsePresent:=True;
|
|
end;
|
|
a_end_if:
|
|
ThenDone:=True;
|
|
else
|
|
internalerror(2023100501);
|
|
end;
|
|
end
|
|
else
|
|
then_asmlist.Concat(wasm_convert_first_item_to_structured(srclist));
|
|
until ThenDone;
|
|
|
|
if ElsePresent then
|
|
begin
|
|
else_asmlist:=TAsmList.Create;
|
|
ElseDone:=False;
|
|
repeat
|
|
p:=tai(srclist.First);
|
|
if not assigned(p) then
|
|
internalerror(2023100303);
|
|
if (p.typ=ait_instruction) and (taicpu(p).opcode=a_end_if) then
|
|
begin
|
|
srclist.Remove(p);
|
|
ElseDone:=True;
|
|
end
|
|
else
|
|
else_asmlist.Concat(wasm_convert_first_item_to_structured(srclist));
|
|
until ElseDone;
|
|
end;
|
|
end;
|
|
|
|
destructor tai_wasmstruc_if.Destroy;
|
|
begin
|
|
then_asmlist.free;
|
|
else_asmlist.free;
|
|
if_instr.free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function tai_wasmstruc_if.getcopy: TLinkedListItem;
|
|
var
|
|
p: tai_wasmstruc_if;
|
|
begin
|
|
p:=tai_wasmstruc_if(inherited getcopy);
|
|
if assigned(if_instr) then
|
|
p.if_instr:=taicpu(if_instr.getcopy);
|
|
if assigned(then_asmlist) then
|
|
begin
|
|
p.then_asmlist:=TAsmList.Create;
|
|
p.then_asmlist.concatListcopy(then_asmlist);
|
|
end;
|
|
if assigned(else_asmlist) then
|
|
begin
|
|
p.else_asmlist:=TAsmList.Create;
|
|
p.else_asmlist.concatListcopy(else_asmlist);
|
|
end;
|
|
getcopy:=p;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_if.Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);
|
|
begin
|
|
blockstack.push(self);
|
|
map_structured_asmlist_inner(then_asmlist,f,blockstack);
|
|
map_structured_asmlist_inner(else_asmlist,f,blockstack);
|
|
blockstack.pop;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_if.ConvertToFlatList(l: TAsmList);
|
|
begin
|
|
l.Concat(if_instr);
|
|
if_instr:=nil;
|
|
l.concatList(then_asmlist);
|
|
if assigned(else_asmlist) then
|
|
begin
|
|
l.Concat(taicpu.op_none(A_ELSE));
|
|
l.concatList(else_asmlist);
|
|
end;
|
|
l.Concat(taicpu.op_none(a_end_if));
|
|
if FLabelIsNew then
|
|
l.concat(tai_label.create(FLabel));
|
|
end;
|
|
|
|
procedure tai_wasmstruc_if.ConvertToBrIf(list: TAsmList; local_alloc: TWasmLocalAllocator);
|
|
var
|
|
res_ft: TWasmFuncType;
|
|
save_if_reg: Integer;
|
|
save_param_reg: array of Integer;
|
|
save_result_reg: array of Integer;
|
|
|
|
procedure AllocateLocalsForSavingParamsAndResult;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if not assigned(res_ft) then
|
|
exit;
|
|
if length(res_ft.params)<>0 then
|
|
begin
|
|
save_if_reg:=local_alloc(wbt_i32);
|
|
SetLength(save_param_reg,length(res_ft.params));
|
|
for i:=low(res_ft.params) to high(res_ft.params) do
|
|
save_param_reg[i]:=local_alloc(res_ft.params[i]);
|
|
end;
|
|
if length(res_ft.results)<>0 then
|
|
begin
|
|
SetLength(save_result_reg,length(res_ft.results));
|
|
for i:=low(res_ft.results) to high(res_ft.results) do
|
|
save_result_reg[i]:=local_alloc(res_ft.results[i]);
|
|
end;
|
|
end;
|
|
|
|
procedure SaveParams;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if (not assigned(res_ft)) or (length(res_ft.params)=0) then
|
|
exit;
|
|
list.concat(taicpu.op_const(a_local_set,save_if_reg));
|
|
for i:=high(res_ft.params) downto low(res_ft.params) do
|
|
list.concat(taicpu.op_const(a_local_set,save_param_reg[i]));
|
|
list.concat(taicpu.op_const(a_local_get,save_if_reg));
|
|
end;
|
|
|
|
procedure RestoreParams;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if (not assigned(res_ft)) or (length(res_ft.params)=0) then
|
|
exit;
|
|
for i:=low(res_ft.params) to high(res_ft.params) do
|
|
list.concat(taicpu.op_const(a_local_get,save_param_reg[i]));
|
|
end;
|
|
|
|
procedure SaveResults;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if (not assigned(res_ft)) or (length(res_ft.results)=0) then
|
|
exit;
|
|
for i:=high(res_ft.results) downto low(res_ft.results) do
|
|
list.concat(taicpu.op_const(a_local_set,save_result_reg[i]));
|
|
end;
|
|
|
|
procedure RestoreResults;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if (not assigned(res_ft)) or (length(res_ft.results)=0) then
|
|
exit;
|
|
for i:=low(res_ft.results) to high(res_ft.results) do
|
|
list.concat(taicpu.op_const(a_local_get,save_result_reg[i]));
|
|
end;
|
|
|
|
var
|
|
then_label: TAsmLabel;
|
|
begin
|
|
if if_instr.ops>1 then
|
|
internalerror(2023101701);
|
|
if (if_instr.ops=1) and (if_instr.oper[0]^.typ=top_functype) then
|
|
res_ft:=if_instr.oper[0]^.functype
|
|
else
|
|
res_ft:=nil;
|
|
AllocateLocalsForSavingParamsAndResult;
|
|
|
|
current_asmdata.getjumplabel(then_label);
|
|
SaveParams;
|
|
list.concat(taicpu.op_sym(a_br_if,then_label));
|
|
RestoreParams;
|
|
if assigned(else_asmlist) then
|
|
list.concatList(else_asmlist);
|
|
SaveResults;
|
|
list.concat(taicpu.op_sym(a_br, GetLabel));
|
|
list.concat(tai_label.create(then_label));
|
|
RestoreParams;
|
|
list.concatList(then_asmlist);
|
|
SaveResults;
|
|
list.concat(tai_label.create(GetLabel));
|
|
RestoreResults;
|
|
end;
|
|
|
|
{ tai_wasmstruc_block }
|
|
|
|
constructor tai_wasmstruc_block.create_from(a_block_instr: taicpu; srclist: TAsmList);
|
|
var
|
|
Done: Boolean;
|
|
p: tai;
|
|
begin
|
|
wstyp:=aitws_block;
|
|
inherited Create;
|
|
if assigned(a_block_instr.Previous) or assigned(a_block_instr.Next) then
|
|
internalerror(2023100304);
|
|
block_instr:=a_block_instr;
|
|
|
|
inner_asmlist:=TAsmList.Create;
|
|
|
|
Done:=False;
|
|
repeat
|
|
p:=tai(srclist.First);
|
|
if not assigned(p) then
|
|
internalerror(2023100305);
|
|
if (p.typ=ait_instruction) and (taicpu(p).opcode=a_end_block) then
|
|
begin
|
|
srclist.Remove(p);
|
|
Done:=True;
|
|
end
|
|
else
|
|
inner_asmlist.Concat(wasm_convert_first_item_to_structured(srclist));
|
|
until Done;
|
|
end;
|
|
|
|
destructor tai_wasmstruc_block.Destroy;
|
|
begin
|
|
inner_asmlist.free;
|
|
block_instr.free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function tai_wasmstruc_block.getcopy: TLinkedListItem;
|
|
var
|
|
p: tai_wasmstruc_block;
|
|
begin
|
|
p:=tai_wasmstruc_block(inherited getcopy);
|
|
if assigned(block_instr) then
|
|
p.block_instr:=taicpu(block_instr.getcopy);
|
|
if assigned(inner_asmlist) then
|
|
begin
|
|
p.inner_asmlist:=TAsmList.Create;
|
|
p.inner_asmlist.concatListcopy(inner_asmlist);
|
|
end;
|
|
getcopy:=p;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_block.Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);
|
|
begin
|
|
blockstack.push(self);
|
|
map_structured_asmlist_inner(inner_asmlist,f,blockstack);
|
|
blockstack.pop;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_block.ConvertToFlatList(l: TAsmList);
|
|
begin
|
|
l.Concat(block_instr);
|
|
block_instr:=nil;
|
|
l.concatList(inner_asmlist);
|
|
l.Concat(taicpu.op_none(a_end_block));
|
|
if FLabelIsNew then
|
|
l.concat(tai_label.create(FLabel));
|
|
end;
|
|
|
|
{ tai_wasmstruc_loop }
|
|
|
|
constructor tai_wasmstruc_loop.create_from(a_loop_instr: taicpu; srclist: TAsmList);
|
|
var
|
|
Done: Boolean;
|
|
p: tai;
|
|
begin
|
|
wstyp:=aitws_loop;
|
|
inherited Create;
|
|
if assigned(a_loop_instr.Previous) or assigned(a_loop_instr.Next) then
|
|
internalerror(2023100306);
|
|
loop_instr:=a_loop_instr;
|
|
|
|
inner_asmlist:=TAsmList.Create;
|
|
|
|
Done:=False;
|
|
repeat
|
|
p:=tai(srclist.First);
|
|
if not assigned(p) then
|
|
internalerror(2023100307);
|
|
if (p.typ=ait_instruction) and (taicpu(p).opcode=a_end_loop) then
|
|
begin
|
|
srclist.Remove(p);
|
|
Done:=True;
|
|
end
|
|
else
|
|
inner_asmlist.Concat(wasm_convert_first_item_to_structured(srclist));
|
|
until Done;
|
|
end;
|
|
|
|
destructor tai_wasmstruc_loop.Destroy;
|
|
begin
|
|
inner_asmlist.free;
|
|
loop_instr.free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function tai_wasmstruc_loop.getcopy: TLinkedListItem;
|
|
var
|
|
p: tai_wasmstruc_loop;
|
|
begin
|
|
p:=tai_wasmstruc_loop(inherited getcopy);
|
|
if assigned(loop_instr) then
|
|
p.loop_instr:=taicpu(loop_instr.getcopy);
|
|
if assigned(inner_asmlist) then
|
|
begin
|
|
p.inner_asmlist:=TAsmList.Create;
|
|
p.inner_asmlist.concatListcopy(inner_asmlist);
|
|
end;
|
|
getcopy:=p;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_loop.Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);
|
|
begin
|
|
blockstack.push(self);
|
|
map_structured_asmlist_inner(inner_asmlist,f,blockstack);
|
|
blockstack.pop;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_loop.ConvertToBr(list: TAsmList);
|
|
begin
|
|
list.concat(tai_label.create(GetLabel));
|
|
list.concatList(inner_asmlist);
|
|
list.concat(taicpu.op_sym(a_br,GetLabel));
|
|
end;
|
|
|
|
procedure tai_wasmstruc_loop.ConvertToFlatList(l: TAsmList);
|
|
begin
|
|
l.Concat(loop_instr);
|
|
loop_instr:=nil;
|
|
if FLabelIsNew then
|
|
l.concat(tai_label.create(FLabel));
|
|
l.concatList(inner_asmlist);
|
|
l.Concat(taicpu.op_none(a_end_loop));
|
|
end;
|
|
|
|
{ tai_wasmstruc_try }
|
|
|
|
class function tai_wasmstruc_try.create_from(srclist: TAsmList): tai_wasmstruc_try;
|
|
var
|
|
Done: Boolean;
|
|
p: tai;
|
|
tmp_asmlist: TAsmList;
|
|
begin
|
|
result:=nil;
|
|
tmp_asmlist:=TAsmList.Create;
|
|
|
|
Done:=False;
|
|
repeat
|
|
p:=tai(srclist.First);
|
|
if not assigned(p) then
|
|
internalerror(2023100308);
|
|
if (p.typ=ait_instruction) and (taicpu(p).opcode in [a_end_try,a_catch,a_catch_all,a_delegate]) then
|
|
begin
|
|
srclist.Remove(p);
|
|
Done:=True;
|
|
end
|
|
else
|
|
tmp_asmlist.Concat(wasm_convert_first_item_to_structured(srclist));
|
|
until Done;
|
|
case taicpu(p).opcode of
|
|
a_end_try,a_catch,a_catch_all:
|
|
result:=tai_wasmstruc_try_catch.internal_create(taicpu(p),tmp_asmlist,srclist);
|
|
a_delegate:
|
|
result:=tai_wasmstruc_try_delegate.internal_create(taicpu(p),tmp_asmlist,srclist);
|
|
else
|
|
internalerror(2023100502);
|
|
end;
|
|
end;
|
|
|
|
constructor tai_wasmstruc_try.internal_create(a_try_asmlist: TAsmList);
|
|
begin
|
|
inherited Create;
|
|
try_asmlist:=a_try_asmlist;
|
|
end;
|
|
|
|
destructor tai_wasmstruc_try.Destroy;
|
|
begin
|
|
try_asmlist.free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function tai_wasmstruc_try.getcopy: TLinkedListItem;
|
|
var
|
|
p: tai_wasmstruc_try;
|
|
begin
|
|
p:=tai_wasmstruc_try(inherited getcopy);
|
|
if assigned(try_asmlist) then
|
|
begin
|
|
p.try_asmlist:=TAsmList.Create;
|
|
p.try_asmlist.concatListcopy(try_asmlist);
|
|
end;
|
|
getcopy:=p;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_try.ConvertToFlatList(l: TAsmList);
|
|
begin
|
|
l.Concat(taicpu.op_none(A_TRY));
|
|
l.concatList(try_asmlist);
|
|
end;
|
|
|
|
{ tai_wasmstruc_try_catch }
|
|
|
|
constructor tai_wasmstruc_try_catch.internal_create(first_ins: taicpu; a_try_asmlist, srclist: TAsmList);
|
|
var
|
|
p: tai;
|
|
|
|
procedure parse_next_catch_block;
|
|
var
|
|
new_catch_index: Integer;
|
|
al: TAsmList;
|
|
Done: Boolean;
|
|
pp: tai;
|
|
begin
|
|
SetLength(catch_list,Length(catch_list)+1);
|
|
new_catch_index:=High(catch_list);
|
|
catch_list[new_catch_index].catch_instr:=taicpu(p);
|
|
al:=TAsmList.Create;
|
|
catch_list[new_catch_index].asmlist:=al;
|
|
Done:=False;
|
|
repeat
|
|
pp:=tai(srclist.First);
|
|
if (pp.typ=ait_instruction) and (taicpu(pp).opcode in [a_catch,a_catch_all,a_end_try]) then
|
|
Done:=True
|
|
else
|
|
al.Concat(wasm_convert_first_item_to_structured(srclist));
|
|
until Done;
|
|
end;
|
|
|
|
procedure parse_catch_all;
|
|
var
|
|
Done: Boolean;
|
|
pp: tai;
|
|
begin
|
|
catch_all_asmlist:=TAsmList.Create;
|
|
Done:=False;
|
|
repeat
|
|
pp:=tai(srclist.First);
|
|
if (pp.typ=ait_instruction) and (taicpu(pp).opcode=a_end_try) then
|
|
begin
|
|
srclist.Remove(pp);
|
|
Done:=True;
|
|
end
|
|
else
|
|
catch_all_asmlist.Concat(wasm_convert_first_item_to_structured(srclist));
|
|
until Done;
|
|
end;
|
|
|
|
var
|
|
Done: Boolean;
|
|
begin
|
|
wstyp:=aitws_try_catch;
|
|
inherited internal_create(a_try_asmlist);
|
|
if assigned(first_ins.Previous) or assigned(first_ins.Next) then
|
|
internalerror(2023100310);
|
|
Done:=False;
|
|
p:=first_ins;
|
|
repeat
|
|
if p.typ=ait_instruction then
|
|
case taicpu(p).opcode of
|
|
a_catch:
|
|
begin
|
|
parse_next_catch_block;
|
|
p:=tai(srclist.First);
|
|
srclist.Remove(p);
|
|
end;
|
|
a_catch_all:
|
|
begin
|
|
parse_catch_all;
|
|
Done:=True;
|
|
end;
|
|
a_end_try:
|
|
Done:=True;
|
|
else
|
|
internalerror(2023100311);
|
|
end
|
|
else
|
|
internalerror(2023100312);
|
|
until Done;
|
|
end;
|
|
|
|
destructor tai_wasmstruc_try_catch.Destroy;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=low(catch_list) to high(catch_list) do
|
|
begin
|
|
catch_list[i].asmlist.free;
|
|
catch_list[i].catch_instr.free;
|
|
end;
|
|
catch_all_asmlist.free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function tai_wasmstruc_try_catch.getcopy: TLinkedListItem;
|
|
var
|
|
p: tai_wasmstruc_try_catch;
|
|
i: Integer;
|
|
begin
|
|
p:=tai_wasmstruc_try_catch(inherited getcopy);
|
|
p.catch_list:=Copy(catch_list);
|
|
for i:=0 to length(catch_list)-1 do
|
|
begin
|
|
if assigned(catch_list[i].asmlist) then
|
|
begin
|
|
p.catch_list[i].asmlist:=TAsmList.Create;
|
|
p.catch_list[i].asmlist.concatListcopy(catch_list[i].asmlist);
|
|
end;
|
|
if assigned(catch_list[i].catch_instr) then
|
|
p.catch_list[i].catch_instr:=taicpu(catch_list[i].catch_instr.getcopy);
|
|
end;
|
|
if assigned(catch_all_asmlist) then
|
|
begin
|
|
p.catch_all_asmlist:=TAsmList.Create;
|
|
p.catch_all_asmlist.concatListcopy(catch_all_asmlist);
|
|
end;
|
|
getcopy:=p;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_try_catch.Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
blockstack.push(self);
|
|
map_structured_asmlist_inner(try_asmlist,f,blockstack);
|
|
for i:=low(catch_list) to high(catch_list) do
|
|
map_structured_asmlist_inner(catch_list[i].asmlist,f,blockstack);
|
|
map_structured_asmlist_inner(catch_all_asmlist,f,blockstack);
|
|
blockstack.pop;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_try_catch.ConvertToFlatList(l: TAsmList);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inherited ConvertToFlatList(l);
|
|
for i:=low(catch_list) to high(catch_list) do
|
|
begin
|
|
l.Concat(catch_list[i].catch_instr);
|
|
catch_list[i].catch_instr:=nil;
|
|
l.concatList(catch_list[i].asmlist);
|
|
end;
|
|
if assigned(catch_all_asmlist) then
|
|
begin
|
|
l.Concat(taicpu.op_none(a_catch_all));
|
|
l.concatList(catch_all_asmlist);
|
|
end;
|
|
l.Concat(taicpu.op_none(a_end_try));
|
|
if FLabelIsNew then
|
|
l.concat(tai_label.create(FLabel));
|
|
end;
|
|
|
|
{ tai_wasmstruc_try_delegate }
|
|
|
|
constructor tai_wasmstruc_try_delegate.internal_create(first_ins: taicpu; a_try_asmlist, srclist: TAsmList);
|
|
begin
|
|
wstyp:=aitws_try_delegate;
|
|
inherited internal_create(a_try_asmlist);
|
|
if assigned(first_ins.Previous) or assigned(first_ins.Next) then
|
|
internalerror(2023100309);
|
|
delegate_instr:=first_ins;
|
|
end;
|
|
|
|
destructor tai_wasmstruc_try_delegate.Destroy;
|
|
begin
|
|
delegate_instr.free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function tai_wasmstruc_try_delegate.getcopy: TLinkedListItem;
|
|
var
|
|
p: tai_wasmstruc_try_delegate;
|
|
begin
|
|
p:=tai_wasmstruc_try_delegate(inherited getcopy);
|
|
if assigned(delegate_instr) then
|
|
p.delegate_instr:=taicpu(delegate_instr.getcopy);
|
|
getcopy:=p;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_try_delegate.Map(f: TAsmMapFunc; blockstack: twasmstruc_stack);
|
|
begin
|
|
blockstack.push(self);
|
|
map_structured_asmlist_inner(try_asmlist,f,blockstack);
|
|
blockstack.pop;
|
|
end;
|
|
|
|
procedure tai_wasmstruc_try_delegate.ConvertToFlatList(l: TAsmList);
|
|
begin
|
|
inherited ConvertToFlatList(l);
|
|
l.Concat(delegate_instr);
|
|
delegate_instr:=nil;
|
|
if FLabelIsNew then
|
|
l.concat(tai_label.create(FLabel));
|
|
end;
|
|
|
|
{ tai_globaltype }
|
|
|
|
constructor tai_globaltype.create(const aglobalname: string; atype: TWasmBasicType; aimmutable: boolean);
|
|
begin
|
|
inherited Create;
|
|
sym:=TWasmGlobalAsmSymbol(current_asmdata.RefAsmSymbolByClass(TWasmGlobalAsmSymbol,aglobalname,AT_WASM_GLOBAL));
|
|
sym.WasmGlobalType:=atype;
|
|
typ:=ait_globaltype;
|
|
globalname:=aglobalname;
|
|
gtype:=atype;
|
|
immutable:=aimmutable;
|
|
is_external:=true;
|
|
is_global:=false;
|
|
end;
|
|
|
|
constructor tai_globaltype.create_local(const aglobalname: string; atype: TWasmBasicType; aimmutable: boolean; def: tdef);
|
|
begin
|
|
inherited Create;
|
|
sym:=TWasmGlobalAsmSymbol(current_asmdata.DefineAsmSymbolByClass(TWasmGlobalAsmSymbol,aglobalname,AB_LOCAL,AT_WASM_GLOBAL,def));
|
|
sym.WasmGlobalType:=atype;
|
|
typ:=ait_globaltype;
|
|
globalname:=aglobalname;
|
|
gtype:=atype;
|
|
immutable:=aimmutable;
|
|
is_external:=false;
|
|
is_global:=false;
|
|
end;
|
|
|
|
constructor tai_globaltype.create_global(const aglobalname: string; atype: TWasmBasicType; aimmutable: boolean; def: tdef);
|
|
begin
|
|
inherited Create;
|
|
sym:=TWasmGlobalAsmSymbol(current_asmdata.DefineAsmSymbolByClass(TWasmGlobalAsmSymbol,aglobalname,AB_GLOBAL,AT_WASM_GLOBAL,def));
|
|
sym.WasmGlobalType:=atype;
|
|
typ:=ait_globaltype;
|
|
globalname:=aglobalname;
|
|
gtype:=atype;
|
|
immutable:=aimmutable;
|
|
is_external:=false;
|
|
is_global:=true;
|
|
end;
|
|
|
|
{ tai_import_name }
|
|
|
|
constructor tai_import_name.create(const asymname, aimportname: string);
|
|
begin
|
|
inherited Create;
|
|
typ:=ait_import_name;
|
|
symname:=asymname;
|
|
importname:=aimportname;
|
|
end;
|
|
|
|
{ tai_import_module }
|
|
|
|
constructor tai_import_module.create(const asymname, aimportmodule: string);
|
|
begin
|
|
inherited Create;
|
|
typ:=ait_import_module;
|
|
symname:=asymname;
|
|
importmodule:=aimportmodule;
|
|
end;
|
|
|
|
{ tai_functype }
|
|
|
|
constructor tai_functype.create(const afuncname: string; afunctype: TWasmFuncType; aisforward: Boolean);
|
|
begin
|
|
inherited Create;
|
|
typ:=ait_functype;
|
|
is_forward:=aisforward;
|
|
funcname:=afuncname;
|
|
functype:=afunctype;
|
|
end;
|
|
|
|
|
|
destructor tai_functype.destroy;
|
|
begin
|
|
functype.free;
|
|
inherited;
|
|
end;
|
|
|
|
{ tai_tagtype }
|
|
|
|
constructor tai_tagtype.create(const atagname: string; aparams: TWasmResultType);
|
|
begin
|
|
typ:=ait_tagtype;
|
|
tagname:=atagname;
|
|
params:=aparams;
|
|
end;
|
|
|
|
{ tai_local }
|
|
|
|
constructor tai_local.create(alocals: TWasmLocalsDynArray);
|
|
begin
|
|
inherited Create;
|
|
locals := Copy(alocals);
|
|
typ := ait_local;
|
|
end;
|
|
|
|
procedure tai_local.AddLocal(abasictype: TWasmBasicType);
|
|
begin
|
|
SetLength(locals,Length(locals)+1);
|
|
locals[high(locals)]:=abasictype;
|
|
end;
|
|
|
|
procedure tai_local.AddLocals(alocals: TWasmLocalsDynArray);
|
|
begin
|
|
locals:=Concat(locals,alocals);
|
|
end;
|
|
|
|
{ timpexp_ai }
|
|
|
|
constructor tai_export_name.create(const aextname, aintname: ansistring;
|
|
asymtype: timpexptype);
|
|
begin
|
|
inherited create;
|
|
typ := ait_export_name;
|
|
extname := aextname;
|
|
intname := aintname;
|
|
symstype:= asymtype;
|
|
end;
|
|
|
|
{*****************************************************************************
|
|
taicpu Constructors
|
|
*****************************************************************************}
|
|
|
|
constructor taicpu.Create(op: tasmop);
|
|
begin
|
|
inherited Create(op);
|
|
if not (ts_wasm_threads in current_settings.targetswitches) and is_atomic_op(op) then
|
|
internalerror(2024070701);
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_none(op : tasmop);
|
|
begin
|
|
inherited create(op);
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_reg(op : tasmop;_op1 : tregister);
|
|
begin
|
|
inherited create(op);
|
|
ops:=1;
|
|
{$ifdef EXTDEBUG}
|
|
if getregtype(_op1)=R_INVALIDREGISTER then
|
|
InternalError(2021011901);
|
|
{$endif EXTDEBUG}
|
|
loadreg(0,_op1);
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_ref(op : tasmop;const _op1 : treference);
|
|
begin
|
|
inherited create(op);
|
|
ops:=1;
|
|
loadref(0,_op1);
|
|
if op in [a_local_get,a_local_set,a_local_tee] then
|
|
begin
|
|
if (_op1.base<>NR_LOCAL_STACK_POINTER_REG) or (_op1.index<>NR_NO) then
|
|
internalerror(2021010201);
|
|
end
|
|
else
|
|
begin
|
|
if (_op1.base<>NR_NO) or (_op1.index<>NR_NO) then
|
|
internalerror(2021010202);
|
|
end;
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_const(op : tasmop;_op1 : aint);
|
|
begin
|
|
inherited create(op);
|
|
ops:=1;
|
|
loadconst(0,_op1);
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
|
|
begin
|
|
inherited create(op);
|
|
ops:=1;
|
|
loadsymbol(0,_op1,0);
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_sym_const(op: tasmop; _op1: tasmsymbol; _op2: aint);
|
|
begin
|
|
inherited create(op);
|
|
ops:=2;
|
|
loadsymbol(0,_op1,0);
|
|
loadconst(1,_op2);
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_sym_functype(op : tasmop;_op1 : tasmsymbol;_op2 : TWasmFuncType);
|
|
begin
|
|
inherited create(op);
|
|
ops:=2;
|
|
loadsymbol(0,_op1,0);
|
|
loadfunctype(1,_op2);
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_single(op: tasmop; _op1: single);
|
|
begin
|
|
inherited create(op);
|
|
ops:=1;
|
|
loadsingle(0,_op1);
|
|
end;
|
|
|
|
|
|
constructor taicpu.op_double(op: tasmop; _op1: double);
|
|
begin
|
|
inherited create(op);
|
|
ops:=1;
|
|
loaddouble(0,_op1);
|
|
end;
|
|
|
|
constructor taicpu.op_functype(op: tasmop; _op1: TWasmFuncType);
|
|
begin
|
|
inherited create(op);
|
|
ops:=1;
|
|
loadfunctype(0,_op1);
|
|
end;
|
|
|
|
procedure taicpu.loadfunctype(opidx: longint; ft: TWasmFuncType);
|
|
begin
|
|
allocate_oper(opidx+1);
|
|
with oper[opidx]^ do
|
|
begin
|
|
if typ<>top_functype then
|
|
clearop(opidx);
|
|
functype:=ft;
|
|
typ:=top_functype;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure taicpu.loadsingle(opidx:longint;f:single);
|
|
begin
|
|
allocate_oper(opidx+1);
|
|
with oper[opidx]^ do
|
|
begin
|
|
if typ<>top_single then
|
|
clearop(opidx);
|
|
sval:=f;
|
|
typ:=top_single;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure taicpu.loaddouble(opidx: longint; d: double);
|
|
begin
|
|
allocate_oper(opidx+1);
|
|
with oper[opidx]^ do
|
|
begin
|
|
if typ<>top_double then
|
|
clearop(opidx);
|
|
dval:=d;
|
|
typ:=top_double;
|
|
end;
|
|
end;
|
|
|
|
|
|
function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
|
|
begin
|
|
result:=false;
|
|
end;
|
|
|
|
|
|
function taicpu.spilling_get_operation_type(opnr: longint): topertype;
|
|
begin
|
|
if opcode in AsmOp_Store then
|
|
result:=operand_write
|
|
else
|
|
result:=operand_read;
|
|
end;
|
|
|
|
|
|
function taicpu.Pass1(objdata: TObjData): longint;
|
|
|
|
function SlebSize(v: tcgint): longint;
|
|
var
|
|
b: byte;
|
|
begin
|
|
result:=0;
|
|
repeat
|
|
b:=byte(v) and 127;
|
|
v:=SarInt64(v,7);
|
|
Inc(result);
|
|
until ((v=0) and ((b and 64)=0)) or ((v=-1) and ((b and 64)<>0));
|
|
end;
|
|
|
|
function UlebSize(v: tcgint): longint;
|
|
begin
|
|
result:=0;
|
|
repeat
|
|
v:=v shr 7;
|
|
Inc(result);
|
|
until v=0;
|
|
end;
|
|
|
|
begin
|
|
result:=0;
|
|
{ Save the old offset and set the new offset }
|
|
InsOffset:=ObjData.CurrObjSec.Size;
|
|
case opcode of
|
|
a_unreachable,
|
|
a_nop,
|
|
a_return,
|
|
a_drop,
|
|
a_i32_eqz,
|
|
a_i32_eq,
|
|
a_i32_ne,
|
|
a_i32_lt_s,
|
|
a_i32_lt_u,
|
|
a_i32_gt_s,
|
|
a_i32_gt_u,
|
|
a_i32_le_s,
|
|
a_i32_le_u,
|
|
a_i32_ge_s,
|
|
a_i32_ge_u,
|
|
a_i64_eqz,
|
|
a_i64_eq,
|
|
a_i64_ne,
|
|
a_i64_lt_s,
|
|
a_i64_lt_u,
|
|
a_i64_gt_s,
|
|
a_i64_gt_u,
|
|
a_i64_le_s,
|
|
a_i64_le_u,
|
|
a_i64_ge_s,
|
|
a_i64_ge_u,
|
|
a_f32_eq,
|
|
a_f32_ne,
|
|
a_f32_lt,
|
|
a_f32_gt,
|
|
a_f32_le,
|
|
a_f32_ge,
|
|
a_f64_eq,
|
|
a_f64_ne,
|
|
a_f64_lt,
|
|
a_f64_gt,
|
|
a_f64_le,
|
|
a_f64_ge,
|
|
a_i32_clz,
|
|
a_i32_ctz,
|
|
a_i32_popcnt,
|
|
a_i32_add,
|
|
a_i32_sub,
|
|
a_i32_mul,
|
|
a_i32_div_s,
|
|
a_i32_div_u,
|
|
a_i32_rem_s,
|
|
a_i32_rem_u,
|
|
a_i32_and,
|
|
a_i32_or,
|
|
a_i32_xor,
|
|
a_i32_shl,
|
|
a_i32_shr_s,
|
|
a_i32_shr_u,
|
|
a_i32_rotl,
|
|
a_i32_rotr,
|
|
a_i64_clz,
|
|
a_i64_ctz,
|
|
a_i64_popcnt,
|
|
a_i64_add,
|
|
a_i64_sub,
|
|
a_i64_mul,
|
|
a_i64_div_s,
|
|
a_i64_div_u,
|
|
a_i64_rem_s,
|
|
a_i64_rem_u,
|
|
a_i64_and,
|
|
a_i64_or,
|
|
a_i64_xor,
|
|
a_i64_shl,
|
|
a_i64_shr_s,
|
|
a_i64_shr_u,
|
|
a_i64_rotl,
|
|
a_i64_rotr,
|
|
a_f32_abs,
|
|
a_f32_neg,
|
|
a_f32_ceil,
|
|
a_f32_floor,
|
|
a_f32_trunc,
|
|
a_f32_nearest,
|
|
a_f32_sqrt,
|
|
a_f32_add,
|
|
a_f32_sub,
|
|
a_f32_mul,
|
|
a_f32_div,
|
|
a_f32_min,
|
|
a_f32_max,
|
|
a_f32_copysign,
|
|
a_f64_abs,
|
|
a_f64_neg,
|
|
a_f64_ceil,
|
|
a_f64_floor,
|
|
a_f64_trunc,
|
|
a_f64_nearest,
|
|
a_f64_sqrt,
|
|
a_f64_add,
|
|
a_f64_sub,
|
|
a_f64_mul,
|
|
a_f64_div,
|
|
a_f64_min,
|
|
a_f64_max,
|
|
a_f64_copysign,
|
|
a_i32_wrap_i64,
|
|
a_i32_trunc_f32_s,
|
|
a_i32_trunc_f32_u,
|
|
a_i32_trunc_f64_s,
|
|
a_i32_trunc_f64_u,
|
|
a_i64_extend_i32_s,
|
|
a_i64_extend_i32_u,
|
|
a_i64_trunc_f32_s,
|
|
a_i64_trunc_f32_u,
|
|
a_i64_trunc_f64_s,
|
|
a_i64_trunc_f64_u,
|
|
a_f32_convert_i32_s,
|
|
a_f32_convert_i32_u,
|
|
a_f32_convert_i64_s,
|
|
a_f32_convert_i64_u,
|
|
a_f32_demote_f64,
|
|
a_f64_convert_i32_s,
|
|
a_f64_convert_i32_u,
|
|
a_f64_convert_i64_s,
|
|
a_f64_convert_i64_u,
|
|
a_f64_promote_f32,
|
|
a_i32_reinterpret_f32,
|
|
a_i64_reinterpret_f64,
|
|
a_f32_reinterpret_i32,
|
|
a_f64_reinterpret_i64,
|
|
a_i32_extend8_s,
|
|
a_i32_extend16_s,
|
|
a_i64_extend8_s,
|
|
a_i64_extend16_s,
|
|
a_i64_extend32_s,
|
|
a_else,
|
|
a_end_block,
|
|
a_end_if,
|
|
a_end_loop,
|
|
a_end_try,
|
|
a_end_function,
|
|
a_catch_all,
|
|
a_ref_is_null:
|
|
result:=1;
|
|
a_i32_trunc_sat_f32_s,
|
|
a_i32_trunc_sat_f32_u,
|
|
a_i32_trunc_sat_f64_s,
|
|
a_i32_trunc_sat_f64_u,
|
|
a_i64_trunc_sat_f32_s,
|
|
a_i64_trunc_sat_f32_u,
|
|
a_i64_trunc_sat_f64_s,
|
|
a_i64_trunc_sat_f64_u,
|
|
a_memory_size,
|
|
a_memory_grow,
|
|
a_ref_null_funcref,
|
|
a_ref_null_externref:
|
|
result:=2;
|
|
a_memory_copy:
|
|
result:=4;
|
|
a_memory_fill,
|
|
a_atomic_fence:
|
|
result:=3;
|
|
a_i32_const:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092001);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
result:=6
|
|
else
|
|
begin
|
|
if assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) then
|
|
internalerror(2021092018);
|
|
result:=1+SlebSize(longint(ref^.offset));
|
|
end;
|
|
end;
|
|
top_const:
|
|
result:=1+SlebSize(longint(val));
|
|
else
|
|
internalerror(2021092615);
|
|
end;
|
|
end;
|
|
a_i64_const:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092001);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
result:=6
|
|
else
|
|
begin
|
|
if assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) then
|
|
internalerror(2021092018);
|
|
result:=1+SlebSize(int64(ref^.offset));
|
|
end;
|
|
end;
|
|
top_const:
|
|
result:=1+SlebSize(int64(val));
|
|
else
|
|
internalerror(2021092615);
|
|
end;
|
|
end;
|
|
a_f32_const:
|
|
result:=5;
|
|
a_f64_const:
|
|
result:=9;
|
|
a_local_get,
|
|
a_local_set,
|
|
a_local_tee:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092001);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
internalerror(2021092005);
|
|
if ref^.base<>NR_STACK_POINTER_REG then
|
|
internalerror(2021092006);
|
|
if ref^.index<>NR_NO then
|
|
internalerror(2021092007);
|
|
result:=1+UlebSize(ref^.offset);
|
|
end;
|
|
top_const:
|
|
result:=1+UlebSize(val);
|
|
else
|
|
internalerror(2021092008);
|
|
end;
|
|
end;
|
|
a_global_get,
|
|
a_global_set:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092010);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if not assigned(ref^.symbol) then
|
|
internalerror(2021092012);
|
|
if (ref^.base<>NR_NO) or (ref^.index<>NR_NO) or (ref^.offset<>0) then
|
|
internalerror(2021092013);
|
|
result:=6;
|
|
end;
|
|
else
|
|
internalerror(2021092011);
|
|
end;
|
|
end;
|
|
a_block,
|
|
a_loop,
|
|
a_if,
|
|
a_try:
|
|
begin
|
|
if ops=0 then
|
|
result:=2
|
|
else
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092015);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_functype:
|
|
begin
|
|
if (length(functype.params)=0) and (length(functype.results)<=1) then
|
|
result:=2
|
|
else
|
|
{ more complex blocktypes are not yet implemented }
|
|
internalerror(2021092621);
|
|
end;
|
|
else
|
|
internalerror(2021092620);
|
|
end;
|
|
end;
|
|
end;
|
|
a_i32_load,
|
|
a_i64_load,
|
|
a_f32_load,
|
|
a_f64_load,
|
|
a_i32_load8_s,
|
|
a_i32_load8_u,
|
|
a_i32_load16_s,
|
|
a_i32_load16_u,
|
|
a_i64_load8_s,
|
|
a_i64_load8_u,
|
|
a_i64_load16_s,
|
|
a_i64_load16_u,
|
|
a_i64_load32_s,
|
|
a_i64_load32_u,
|
|
a_i32_store,
|
|
a_i64_store,
|
|
a_f32_store,
|
|
a_f64_store,
|
|
a_i32_store8,
|
|
a_i32_store16,
|
|
a_i64_store8,
|
|
a_i64_store16,
|
|
a_i64_store32:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092016);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
begin
|
|
Result:=1+
|
|
UlebSize(natural_alignment_for_load_store(opcode))+
|
|
5; { relocation, fixed size = 5 bytes }
|
|
end
|
|
else
|
|
begin
|
|
if assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) then
|
|
internalerror(2021092018);
|
|
Result:=1+
|
|
UlebSize(natural_alignment_for_load_store(opcode))+
|
|
UlebSize(ref^.offset);
|
|
end;
|
|
end;
|
|
top_const:
|
|
begin
|
|
Result:=1+
|
|
UlebSize(natural_alignment_for_load_store(opcode))+
|
|
UlebSize(val);
|
|
end;
|
|
else
|
|
internalerror(2021092017);
|
|
end;
|
|
end;
|
|
a_memory_atomic_notify,
|
|
a_memory_atomic_wait32,
|
|
a_memory_atomic_wait64,
|
|
a_i32_atomic_load,
|
|
a_i64_atomic_load,
|
|
a_i32_atomic_load8_u,
|
|
a_i32_atomic_load16_u,
|
|
a_i64_atomic_load8_u,
|
|
a_i64_atomic_load16_u,
|
|
a_i64_atomic_load32_u,
|
|
a_i32_atomic_store,
|
|
a_i64_atomic_store,
|
|
a_i32_atomic_store8,
|
|
a_i32_atomic_store16,
|
|
a_i64_atomic_store8,
|
|
a_i64_atomic_store16,
|
|
a_i64_atomic_store32,
|
|
a_i32_atomic_rmw_add,
|
|
a_i64_atomic_rmw_add,
|
|
a_i32_atomic_rmw8_add_u,
|
|
a_i32_atomic_rmw16_add_u,
|
|
a_i64_atomic_rmw8_add_u,
|
|
a_i64_atomic_rmw16_add_u,
|
|
a_i64_atomic_rmw32_add_u,
|
|
a_i32_atomic_rmw_sub,
|
|
a_i64_atomic_rmw_sub,
|
|
a_i32_atomic_rmw8_sub_u,
|
|
a_i32_atomic_rmw16_sub_u,
|
|
a_i64_atomic_rmw8_sub_u,
|
|
a_i64_atomic_rmw16_sub_u,
|
|
a_i64_atomic_rmw32_sub_u,
|
|
a_i32_atomic_rmw_and,
|
|
a_i64_atomic_rmw_and,
|
|
a_i32_atomic_rmw8_and_u,
|
|
a_i32_atomic_rmw16_and_u,
|
|
a_i64_atomic_rmw8_and_u,
|
|
a_i64_atomic_rmw16_and_u,
|
|
a_i64_atomic_rmw32_and_u,
|
|
a_i32_atomic_rmw_or,
|
|
a_i64_atomic_rmw_or,
|
|
a_i32_atomic_rmw8_or_u,
|
|
a_i32_atomic_rmw16_or_u,
|
|
a_i64_atomic_rmw8_or_u,
|
|
a_i64_atomic_rmw16_or_u,
|
|
a_i64_atomic_rmw32_or_u,
|
|
a_i32_atomic_rmw_xor,
|
|
a_i64_atomic_rmw_xor,
|
|
a_i32_atomic_rmw8_xor_u,
|
|
a_i32_atomic_rmw16_xor_u,
|
|
a_i64_atomic_rmw8_xor_u,
|
|
a_i64_atomic_rmw16_xor_u,
|
|
a_i64_atomic_rmw32_xor_u,
|
|
a_i32_atomic_rmw_xchg,
|
|
a_i64_atomic_rmw_xchg,
|
|
a_i32_atomic_rmw8_xchg_u,
|
|
a_i32_atomic_rmw16_xchg_u,
|
|
a_i64_atomic_rmw8_xchg_u,
|
|
a_i64_atomic_rmw16_xchg_u,
|
|
a_i64_atomic_rmw32_xchg_u,
|
|
a_i32_atomic_rmw_cmpxchg,
|
|
a_i64_atomic_rmw_cmpxchg,
|
|
a_i32_atomic_rmw8_cmpxchg_u,
|
|
a_i32_atomic_rmw16_cmpxchg_u,
|
|
a_i64_atomic_rmw8_cmpxchg_u,
|
|
a_i64_atomic_rmw16_cmpxchg_u,
|
|
a_i64_atomic_rmw32_cmpxchg_u:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092016);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
begin
|
|
Result:=2+
|
|
UlebSize(natural_alignment_for_load_store(opcode))+
|
|
5; { relocation, fixed size = 5 bytes }
|
|
end
|
|
else
|
|
begin
|
|
if assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) then
|
|
internalerror(2021092018);
|
|
Result:=2+
|
|
UlebSize(natural_alignment_for_load_store(opcode))+
|
|
UlebSize(ref^.offset);
|
|
end;
|
|
end;
|
|
top_const:
|
|
begin
|
|
Result:=2+
|
|
UlebSize(natural_alignment_for_load_store(opcode))+
|
|
UlebSize(val);
|
|
end;
|
|
else
|
|
internalerror(2021092017);
|
|
end;
|
|
end;
|
|
a_call:
|
|
begin
|
|
if ops<>2 then
|
|
internalerror(2021092021);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if not assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) or (ref^.offset<>0) then
|
|
internalerror(2021092023);
|
|
result:=6;
|
|
end;
|
|
else
|
|
internalerror(2021092022);
|
|
end;
|
|
end;
|
|
a_call_indirect:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092610);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_functype:
|
|
begin
|
|
TWasmObjData(objdata).FuncTypes.AddOrGetFuncType(functype);
|
|
result:=6+
|
|
UlebSize(0);
|
|
end;
|
|
else
|
|
internalerror(2021092611);
|
|
end;
|
|
end;
|
|
a_br,
|
|
a_br_if,
|
|
a_rethrow,
|
|
a_delegate:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092610);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_const:
|
|
result:=1+
|
|
UlebSize(val);
|
|
else
|
|
internalerror(2021092625);
|
|
end;
|
|
end;
|
|
a_catch,
|
|
a_throw:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092709);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if not assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) or (ref^.offset<>0) then
|
|
internalerror(2021092711);
|
|
result:=6;
|
|
end;
|
|
else
|
|
internalerror(2021092710);
|
|
end;
|
|
end;
|
|
a_memory_init:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2022052802);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_const:
|
|
result:=3+UlebSize(val);
|
|
else
|
|
internalerror(2022052803);
|
|
end;
|
|
end;
|
|
a_data_drop:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2022052804);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_const:
|
|
result:=2+UlebSize(val);
|
|
else
|
|
internalerror(2022052805);
|
|
end;
|
|
end;
|
|
else
|
|
internalerror(2021092623);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure taicpu.Pass2(objdata: TObjData);
|
|
|
|
procedure WriteByte(b: byte);
|
|
begin
|
|
objdata.writebytes(b,1);
|
|
end;
|
|
|
|
{$ifdef FPC_LITTLE_ENDIAN}
|
|
procedure WriteSingle(s: single);
|
|
begin
|
|
objdata.writebytes(s,4);
|
|
end;
|
|
|
|
procedure WriteDouble(d: double);
|
|
begin
|
|
objdata.writebytes(d,8);
|
|
end;
|
|
{$else FPC_LITTLE_ENDIAN}
|
|
procedure WriteSingle(s: single);
|
|
var
|
|
l: longword;
|
|
begin
|
|
Move(s,l,4);
|
|
l:=SwapEndian(l);
|
|
objdata.writebytes(l,4);
|
|
end;
|
|
|
|
procedure WriteDouble(d: double);
|
|
var
|
|
q: qword;
|
|
begin
|
|
Move(d,q,8);
|
|
q:=SwapEndian(q);
|
|
objdata.writebytes(q,8);
|
|
end;
|
|
{$endif FPC_LITTLE_ENDIAN}
|
|
|
|
procedure WriteSleb(v: tcgint);
|
|
var
|
|
b: byte;
|
|
Done: Boolean=false;
|
|
begin
|
|
repeat
|
|
b:=byte(v) and 127;
|
|
v:=SarInt64(v,7);
|
|
if ((v=0) and ((b and 64)=0)) or ((v=-1) and ((b and 64)<>0)) then
|
|
Done:=true
|
|
else
|
|
b:=b or 128;
|
|
objdata.writebytes(b,1);
|
|
until Done;
|
|
end;
|
|
|
|
procedure WriteUleb(v: tcgint);
|
|
var
|
|
b: byte;
|
|
begin
|
|
repeat
|
|
b:=byte(v) and 127;
|
|
v:=v shr 7;
|
|
if v<>0 then
|
|
b:=b or 128;
|
|
objdata.writebytes(b,1);
|
|
until v=0;
|
|
end;
|
|
|
|
begin
|
|
{ safety check }
|
|
if objdata.currobjsec.size<>longword(insoffset) then
|
|
internalerror(200130121);
|
|
case opcode of
|
|
a_unreachable:
|
|
WriteByte($00);
|
|
a_nop:
|
|
WriteByte($01);
|
|
a_return:
|
|
WriteByte($0F);
|
|
a_drop:
|
|
WriteByte($1A);
|
|
a_memory_size:
|
|
begin
|
|
WriteByte($3F);
|
|
WriteByte($00);
|
|
end;
|
|
a_memory_grow:
|
|
begin
|
|
WriteByte($40);
|
|
WriteByte($00);
|
|
end;
|
|
a_memory_copy:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteUleb(10);
|
|
WriteByte($00);
|
|
WriteByte($00);
|
|
end;
|
|
a_memory_fill:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteUleb(11);
|
|
WriteByte($00);
|
|
end;
|
|
a_atomic_fence:
|
|
begin
|
|
WriteByte($FE);
|
|
WriteByte($03);
|
|
WriteByte($00);
|
|
end;
|
|
a_i32_eqz:
|
|
WriteByte($45);
|
|
a_i32_eq:
|
|
WriteByte($46);
|
|
a_i32_ne:
|
|
WriteByte($47);
|
|
a_i32_lt_s:
|
|
WriteByte($48);
|
|
a_i32_lt_u:
|
|
WriteByte($49);
|
|
a_i32_gt_s:
|
|
WriteByte($4A);
|
|
a_i32_gt_u:
|
|
WriteByte($4B);
|
|
a_i32_le_s:
|
|
WriteByte($4C);
|
|
a_i32_le_u:
|
|
WriteByte($4D);
|
|
a_i32_ge_s:
|
|
WriteByte($4E);
|
|
a_i32_ge_u:
|
|
WriteByte($4F);
|
|
a_i64_eqz:
|
|
WriteByte($50);
|
|
a_i64_eq:
|
|
WriteByte($51);
|
|
a_i64_ne:
|
|
WriteByte($52);
|
|
a_i64_lt_s:
|
|
WriteByte($53);
|
|
a_i64_lt_u:
|
|
WriteByte($54);
|
|
a_i64_gt_s:
|
|
WriteByte($55);
|
|
a_i64_gt_u:
|
|
WriteByte($56);
|
|
a_i64_le_s:
|
|
WriteByte($57);
|
|
a_i64_le_u:
|
|
WriteByte($58);
|
|
a_i64_ge_s:
|
|
WriteByte($59);
|
|
a_i64_ge_u:
|
|
WriteByte($5A);
|
|
a_f32_eq:
|
|
WriteByte($5B);
|
|
a_f32_ne:
|
|
WriteByte($5C);
|
|
a_f32_lt:
|
|
WriteByte($5D);
|
|
a_f32_gt:
|
|
WriteByte($5E);
|
|
a_f32_le:
|
|
WriteByte($5F);
|
|
a_f32_ge:
|
|
WriteByte($60);
|
|
a_f64_eq:
|
|
WriteByte($61);
|
|
a_f64_ne:
|
|
WriteByte($62);
|
|
a_f64_lt:
|
|
WriteByte($63);
|
|
a_f64_gt:
|
|
WriteByte($64);
|
|
a_f64_le:
|
|
WriteByte($65);
|
|
a_f64_ge:
|
|
WriteByte($66);
|
|
a_i32_clz:
|
|
WriteByte($67);
|
|
a_i32_ctz:
|
|
WriteByte($68);
|
|
a_i32_popcnt:
|
|
WriteByte($69);
|
|
a_i32_add:
|
|
WriteByte($6A);
|
|
a_i32_sub:
|
|
WriteByte($6B);
|
|
a_i32_mul:
|
|
WriteByte($6C);
|
|
a_i32_div_s:
|
|
WriteByte($6D);
|
|
a_i32_div_u:
|
|
WriteByte($6E);
|
|
a_i32_rem_s:
|
|
WriteByte($6F);
|
|
a_i32_rem_u:
|
|
WriteByte($70);
|
|
a_i32_and:
|
|
WriteByte($71);
|
|
a_i32_or:
|
|
WriteByte($72);
|
|
a_i32_xor:
|
|
WriteByte($73);
|
|
a_i32_shl:
|
|
WriteByte($74);
|
|
a_i32_shr_s:
|
|
WriteByte($75);
|
|
a_i32_shr_u:
|
|
WriteByte($76);
|
|
a_i32_rotl:
|
|
WriteByte($77);
|
|
a_i32_rotr:
|
|
WriteByte($78);
|
|
a_i64_clz:
|
|
WriteByte($79);
|
|
a_i64_ctz:
|
|
WriteByte($7A);
|
|
a_i64_popcnt:
|
|
WriteByte($7B);
|
|
a_i64_add:
|
|
WriteByte($7C);
|
|
a_i64_sub:
|
|
WriteByte($7D);
|
|
a_i64_mul:
|
|
WriteByte($7E);
|
|
a_i64_div_s:
|
|
WriteByte($7F);
|
|
a_i64_div_u:
|
|
WriteByte($80);
|
|
a_i64_rem_s:
|
|
WriteByte($81);
|
|
a_i64_rem_u:
|
|
WriteByte($82);
|
|
a_i64_and:
|
|
WriteByte($83);
|
|
a_i64_or:
|
|
WriteByte($84);
|
|
a_i64_xor:
|
|
WriteByte($85);
|
|
a_i64_shl:
|
|
WriteByte($86);
|
|
a_i64_shr_s:
|
|
WriteByte($87);
|
|
a_i64_shr_u:
|
|
WriteByte($88);
|
|
a_i64_rotl:
|
|
WriteByte($89);
|
|
a_i64_rotr:
|
|
WriteByte($8A);
|
|
a_f32_abs:
|
|
WriteByte($8B);
|
|
a_f32_neg:
|
|
WriteByte($8C);
|
|
a_f32_ceil:
|
|
WriteByte($8D);
|
|
a_f32_floor:
|
|
WriteByte($8E);
|
|
a_f32_trunc:
|
|
WriteByte($8F);
|
|
a_f32_nearest:
|
|
WriteByte($90);
|
|
a_f32_sqrt:
|
|
WriteByte($91);
|
|
a_f32_add:
|
|
WriteByte($92);
|
|
a_f32_sub:
|
|
WriteByte($93);
|
|
a_f32_mul:
|
|
WriteByte($94);
|
|
a_f32_div:
|
|
WriteByte($95);
|
|
a_f32_min:
|
|
WriteByte($96);
|
|
a_f32_max:
|
|
WriteByte($97);
|
|
a_f32_copysign:
|
|
WriteByte($98);
|
|
a_f64_abs:
|
|
WriteByte($99);
|
|
a_f64_neg:
|
|
WriteByte($9A);
|
|
a_f64_ceil:
|
|
WriteByte($9B);
|
|
a_f64_floor:
|
|
WriteByte($9C);
|
|
a_f64_trunc:
|
|
WriteByte($9D);
|
|
a_f64_nearest:
|
|
WriteByte($9E);
|
|
a_f64_sqrt:
|
|
WriteByte($9F);
|
|
a_f64_add:
|
|
WriteByte($A0);
|
|
a_f64_sub:
|
|
WriteByte($A1);
|
|
a_f64_mul:
|
|
WriteByte($A2);
|
|
a_f64_div:
|
|
WriteByte($A3);
|
|
a_f64_min:
|
|
WriteByte($A4);
|
|
a_f64_max:
|
|
WriteByte($A5);
|
|
a_f64_copysign:
|
|
WriteByte($A6);
|
|
a_i32_wrap_i64:
|
|
WriteByte($A7);
|
|
a_i32_trunc_f32_s:
|
|
WriteByte($A8);
|
|
a_i32_trunc_f32_u:
|
|
WriteByte($A9);
|
|
a_i32_trunc_f64_s:
|
|
WriteByte($AA);
|
|
a_i32_trunc_f64_u:
|
|
WriteByte($AB);
|
|
a_i64_extend_i32_s:
|
|
WriteByte($AC);
|
|
a_i64_extend_i32_u:
|
|
WriteByte($AD);
|
|
a_i64_trunc_f32_s:
|
|
WriteByte($AE);
|
|
a_i64_trunc_f32_u:
|
|
WriteByte($AF);
|
|
a_i64_trunc_f64_s:
|
|
WriteByte($B0);
|
|
a_i64_trunc_f64_u:
|
|
WriteByte($B1);
|
|
a_f32_convert_i32_s:
|
|
WriteByte($B2);
|
|
a_f32_convert_i32_u:
|
|
WriteByte($B3);
|
|
a_f32_convert_i64_s:
|
|
WriteByte($B4);
|
|
a_f32_convert_i64_u:
|
|
WriteByte($B5);
|
|
a_f32_demote_f64:
|
|
WriteByte($B6);
|
|
a_f64_convert_i32_s:
|
|
WriteByte($B7);
|
|
a_f64_convert_i32_u:
|
|
WriteByte($B8);
|
|
a_f64_convert_i64_s:
|
|
WriteByte($B9);
|
|
a_f64_convert_i64_u:
|
|
WriteByte($BA);
|
|
a_f64_promote_f32:
|
|
WriteByte($BB);
|
|
a_i32_reinterpret_f32:
|
|
WriteByte($BC);
|
|
a_i64_reinterpret_f64:
|
|
WriteByte($BD);
|
|
a_f32_reinterpret_i32:
|
|
WriteByte($BE);
|
|
a_f64_reinterpret_i64:
|
|
WriteByte($BF);
|
|
a_i32_extend8_s:
|
|
WriteByte($C0);
|
|
a_i32_extend16_s:
|
|
WriteByte($C1);
|
|
a_i64_extend8_s:
|
|
WriteByte($C2);
|
|
a_i64_extend16_s:
|
|
WriteByte($C3);
|
|
a_i64_extend32_s:
|
|
WriteByte($C4);
|
|
a_end_block,
|
|
a_end_if,
|
|
a_end_loop,
|
|
a_end_try,
|
|
a_end_function:
|
|
WriteByte($0B);
|
|
a_catch_all:
|
|
WriteByte($19);
|
|
a_i32_const:
|
|
begin
|
|
WriteByte($41);
|
|
if ops<>1 then
|
|
internalerror(2021092001);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
objdata.writeReloc(ref^.offset,5,ObjData.symbolref(ref^.symbol),RELOC_MEMORY_ADDR_OR_TABLE_INDEX_SLEB)
|
|
else
|
|
begin
|
|
if assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) then
|
|
internalerror(2021092018);
|
|
WriteSleb(longint(ref^.offset));
|
|
end;
|
|
end;
|
|
top_const:
|
|
WriteSleb(longint(val));
|
|
else
|
|
internalerror(2021092615);
|
|
end;
|
|
end;
|
|
a_i64_const:
|
|
begin
|
|
WriteByte($42);
|
|
if ops<>1 then
|
|
internalerror(2021092001);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
objdata.writeReloc(ref^.offset,5,ObjData.symbolref(ref^.symbol),RELOC_MEMORY_ADDR_OR_TABLE_INDEX_SLEB)
|
|
else
|
|
begin
|
|
if assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) then
|
|
internalerror(2021092018);
|
|
WriteSleb(int64(ref^.offset));
|
|
end;
|
|
end;
|
|
top_const:
|
|
WriteSleb(int64(val));
|
|
else
|
|
internalerror(2021092615);
|
|
end;
|
|
end;
|
|
a_f32_const:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092619);
|
|
WriteByte($43);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_single:
|
|
WriteSingle(sval);
|
|
else
|
|
internalerror(2021092618);
|
|
end;
|
|
end;
|
|
a_f64_const:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092616);
|
|
WriteByte($44);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_double:
|
|
WriteDouble(dval);
|
|
else
|
|
internalerror(2021092617);
|
|
end;
|
|
end;
|
|
a_local_get,
|
|
a_local_set,
|
|
a_local_tee:
|
|
begin
|
|
case opcode of
|
|
a_local_get:
|
|
WriteByte($20);
|
|
a_local_set:
|
|
WriteByte($21);
|
|
a_local_tee:
|
|
WriteByte($22);
|
|
else
|
|
internalerror(2021092003);
|
|
end;
|
|
if ops<>1 then
|
|
internalerror(2021092004);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
internalerror(2021092005);
|
|
if ref^.base<>NR_STACK_POINTER_REG then
|
|
internalerror(2021092006);
|
|
if ref^.index<>NR_NO then
|
|
internalerror(2021092007);
|
|
WriteUleb(ref^.offset);
|
|
end;
|
|
top_const:
|
|
WriteUleb(val);
|
|
else
|
|
internalerror(2021092008);
|
|
end;
|
|
end;
|
|
a_global_get,
|
|
a_global_set:
|
|
begin
|
|
case opcode of
|
|
a_global_get:
|
|
WriteByte($23);
|
|
a_global_set:
|
|
WriteByte($24);
|
|
else
|
|
internalerror(2021092009);
|
|
end;
|
|
if ops<>1 then
|
|
internalerror(2021092010);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if not assigned(ref^.symbol) then
|
|
internalerror(2021092012);
|
|
if (ref^.base<>NR_NO) or (ref^.index<>NR_NO) or (ref^.offset<>0) then
|
|
internalerror(2021092013);
|
|
objdata.writeReloc(0,5,TWasmObjData(ObjData).globalref(ref^.symbol),RELOC_GLOBAL_INDEX_LEB);
|
|
end;
|
|
else
|
|
internalerror(2021092011);
|
|
end;
|
|
end;
|
|
a_block,
|
|
a_loop,
|
|
a_if,
|
|
a_try:
|
|
begin
|
|
case opcode of
|
|
a_block:
|
|
WriteByte($02);
|
|
a_loop:
|
|
WriteByte($03);
|
|
a_if:
|
|
WriteByte($04);
|
|
a_try:
|
|
WriteByte($06);
|
|
else
|
|
internalerror(2021092626);
|
|
end;
|
|
if ops=0 then
|
|
WriteByte($40)
|
|
else
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092015);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_functype:
|
|
begin
|
|
if (length(functype.params)=0) and (length(functype.results)<=1) then
|
|
begin
|
|
if length(functype.results)=1 then
|
|
WriteByte(encode_wasm_basic_type(functype.results[0]))
|
|
else
|
|
WriteByte($40);
|
|
end
|
|
else
|
|
{ more complex blocktypes are not yet implemented }
|
|
internalerror(2021092621);
|
|
end;
|
|
else
|
|
internalerror(2021092620);
|
|
end;
|
|
end;
|
|
end;
|
|
a_else:
|
|
WriteByte($05);
|
|
a_i32_load,
|
|
a_i64_load,
|
|
a_f32_load,
|
|
a_f64_load,
|
|
a_i32_load8_s,
|
|
a_i32_load8_u,
|
|
a_i32_load16_s,
|
|
a_i32_load16_u,
|
|
a_i64_load8_s,
|
|
a_i64_load8_u,
|
|
a_i64_load16_s,
|
|
a_i64_load16_u,
|
|
a_i64_load32_s,
|
|
a_i64_load32_u,
|
|
a_i32_store,
|
|
a_i64_store,
|
|
a_f32_store,
|
|
a_f64_store,
|
|
a_i32_store8,
|
|
a_i32_store16,
|
|
a_i64_store8,
|
|
a_i64_store16,
|
|
a_i64_store32:
|
|
begin
|
|
case opcode of
|
|
a_i32_load:
|
|
WriteByte($28);
|
|
a_i64_load:
|
|
WriteByte($29);
|
|
a_f32_load:
|
|
WriteByte($2A);
|
|
a_f64_load:
|
|
WriteByte($2B);
|
|
a_i32_load8_s:
|
|
WriteByte($2C);
|
|
a_i32_load8_u:
|
|
WriteByte($2D);
|
|
a_i32_load16_s:
|
|
WriteByte($2E);
|
|
a_i32_load16_u:
|
|
WriteByte($2F);
|
|
a_i64_load8_s:
|
|
WriteByte($30);
|
|
a_i64_load8_u:
|
|
WriteByte($31);
|
|
a_i64_load16_s:
|
|
WriteByte($32);
|
|
a_i64_load16_u:
|
|
WriteByte($33);
|
|
a_i64_load32_s:
|
|
WriteByte($34);
|
|
a_i64_load32_u:
|
|
WriteByte($35);
|
|
a_i32_store:
|
|
WriteByte($36);
|
|
a_i64_store:
|
|
WriteByte($37);
|
|
a_f32_store:
|
|
WriteByte($38);
|
|
a_f64_store:
|
|
WriteByte($39);
|
|
a_i32_store8:
|
|
WriteByte($3A);
|
|
a_i32_store16:
|
|
WriteByte($3B);
|
|
a_i64_store8:
|
|
WriteByte($3C);
|
|
a_i64_store16:
|
|
WriteByte($3D);
|
|
a_i64_store32:
|
|
WriteByte($3E);
|
|
else
|
|
internalerror(2021092019);
|
|
end;
|
|
if ops<>1 then
|
|
internalerror(2021092016);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
begin
|
|
WriteUleb(natural_alignment_for_load_store(opcode));
|
|
objdata.writeReloc(ref^.offset,5,ObjData.symbolref(ref^.symbol),RELOC_MEMORY_ADDR_LEB);
|
|
end
|
|
else
|
|
begin
|
|
if assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) then
|
|
internalerror(2021092018);
|
|
WriteUleb(natural_alignment_for_load_store(opcode));
|
|
WriteUleb(ref^.offset);
|
|
end;
|
|
end;
|
|
top_const:
|
|
begin
|
|
WriteUleb(natural_alignment_for_load_store(opcode));
|
|
WriteUleb(val);
|
|
end;
|
|
else
|
|
internalerror(2021092017);
|
|
end;
|
|
end;
|
|
a_memory_atomic_notify,
|
|
a_memory_atomic_wait32,
|
|
a_memory_atomic_wait64,
|
|
a_i32_atomic_load,
|
|
a_i64_atomic_load,
|
|
a_i32_atomic_load8_u,
|
|
a_i32_atomic_load16_u,
|
|
a_i64_atomic_load8_u,
|
|
a_i64_atomic_load16_u,
|
|
a_i64_atomic_load32_u,
|
|
a_i32_atomic_store,
|
|
a_i64_atomic_store,
|
|
a_i32_atomic_store8,
|
|
a_i32_atomic_store16,
|
|
a_i64_atomic_store8,
|
|
a_i64_atomic_store16,
|
|
a_i64_atomic_store32,
|
|
a_i32_atomic_rmw_add,
|
|
a_i64_atomic_rmw_add,
|
|
a_i32_atomic_rmw8_add_u,
|
|
a_i32_atomic_rmw16_add_u,
|
|
a_i64_atomic_rmw8_add_u,
|
|
a_i64_atomic_rmw16_add_u,
|
|
a_i64_atomic_rmw32_add_u,
|
|
a_i32_atomic_rmw_sub,
|
|
a_i64_atomic_rmw_sub,
|
|
a_i32_atomic_rmw8_sub_u,
|
|
a_i32_atomic_rmw16_sub_u,
|
|
a_i64_atomic_rmw8_sub_u,
|
|
a_i64_atomic_rmw16_sub_u,
|
|
a_i64_atomic_rmw32_sub_u,
|
|
a_i32_atomic_rmw_and,
|
|
a_i64_atomic_rmw_and,
|
|
a_i32_atomic_rmw8_and_u,
|
|
a_i32_atomic_rmw16_and_u,
|
|
a_i64_atomic_rmw8_and_u,
|
|
a_i64_atomic_rmw16_and_u,
|
|
a_i64_atomic_rmw32_and_u,
|
|
a_i32_atomic_rmw_or,
|
|
a_i64_atomic_rmw_or,
|
|
a_i32_atomic_rmw8_or_u,
|
|
a_i32_atomic_rmw16_or_u,
|
|
a_i64_atomic_rmw8_or_u,
|
|
a_i64_atomic_rmw16_or_u,
|
|
a_i64_atomic_rmw32_or_u,
|
|
a_i32_atomic_rmw_xor,
|
|
a_i64_atomic_rmw_xor,
|
|
a_i32_atomic_rmw8_xor_u,
|
|
a_i32_atomic_rmw16_xor_u,
|
|
a_i64_atomic_rmw8_xor_u,
|
|
a_i64_atomic_rmw16_xor_u,
|
|
a_i64_atomic_rmw32_xor_u,
|
|
a_i32_atomic_rmw_xchg,
|
|
a_i64_atomic_rmw_xchg,
|
|
a_i32_atomic_rmw8_xchg_u,
|
|
a_i32_atomic_rmw16_xchg_u,
|
|
a_i64_atomic_rmw8_xchg_u,
|
|
a_i64_atomic_rmw16_xchg_u,
|
|
a_i64_atomic_rmw32_xchg_u,
|
|
a_i32_atomic_rmw_cmpxchg,
|
|
a_i64_atomic_rmw_cmpxchg,
|
|
a_i32_atomic_rmw8_cmpxchg_u,
|
|
a_i32_atomic_rmw16_cmpxchg_u,
|
|
a_i64_atomic_rmw8_cmpxchg_u,
|
|
a_i64_atomic_rmw16_cmpxchg_u,
|
|
a_i64_atomic_rmw32_cmpxchg_u:
|
|
begin
|
|
WriteByte($FE);
|
|
case opcode of
|
|
a_memory_atomic_notify:
|
|
WriteByte($00);
|
|
a_memory_atomic_wait32:
|
|
WriteByte($01);
|
|
a_memory_atomic_wait64:
|
|
WriteByte($02);
|
|
a_i32_atomic_load:
|
|
WriteByte($10);
|
|
a_i64_atomic_load:
|
|
WriteByte($11);
|
|
a_i32_atomic_load8_u:
|
|
WriteByte($12);
|
|
a_i32_atomic_load16_u:
|
|
WriteByte($13);
|
|
a_i64_atomic_load8_u:
|
|
WriteByte($14);
|
|
a_i64_atomic_load16_u:
|
|
WriteByte($15);
|
|
a_i64_atomic_load32_u:
|
|
WriteByte($16);
|
|
a_i32_atomic_store:
|
|
WriteByte($17);
|
|
a_i64_atomic_store:
|
|
WriteByte($18);
|
|
a_i32_atomic_store8:
|
|
WriteByte($19);
|
|
a_i32_atomic_store16:
|
|
WriteByte($1A);
|
|
a_i64_atomic_store8:
|
|
WriteByte($1B);
|
|
a_i64_atomic_store16:
|
|
WriteByte($1C);
|
|
a_i64_atomic_store32:
|
|
WriteByte($1D);
|
|
a_i32_atomic_rmw_add:
|
|
WriteByte($1E);
|
|
a_i64_atomic_rmw_add:
|
|
WriteByte($1F);
|
|
a_i32_atomic_rmw8_add_u:
|
|
WriteByte($20);
|
|
a_i32_atomic_rmw16_add_u:
|
|
WriteByte($21);
|
|
a_i64_atomic_rmw8_add_u:
|
|
WriteByte($22);
|
|
a_i64_atomic_rmw16_add_u:
|
|
WriteByte($23);
|
|
a_i64_atomic_rmw32_add_u:
|
|
WriteByte($24);
|
|
a_i32_atomic_rmw_sub:
|
|
WriteByte($25);
|
|
a_i64_atomic_rmw_sub:
|
|
WriteByte($26);
|
|
a_i32_atomic_rmw8_sub_u:
|
|
WriteByte($27);
|
|
a_i32_atomic_rmw16_sub_u:
|
|
WriteByte($28);
|
|
a_i64_atomic_rmw8_sub_u:
|
|
WriteByte($29);
|
|
a_i64_atomic_rmw16_sub_u:
|
|
WriteByte($2A);
|
|
a_i64_atomic_rmw32_sub_u:
|
|
WriteByte($2B);
|
|
a_i32_atomic_rmw_and:
|
|
WriteByte($2C);
|
|
a_i64_atomic_rmw_and:
|
|
WriteByte($2D);
|
|
a_i32_atomic_rmw8_and_u:
|
|
WriteByte($2E);
|
|
a_i32_atomic_rmw16_and_u:
|
|
WriteByte($2F);
|
|
a_i64_atomic_rmw8_and_u:
|
|
WriteByte($30);
|
|
a_i64_atomic_rmw16_and_u:
|
|
WriteByte($31);
|
|
a_i64_atomic_rmw32_and_u:
|
|
WriteByte($32);
|
|
a_i32_atomic_rmw_or:
|
|
WriteByte($33);
|
|
a_i64_atomic_rmw_or:
|
|
WriteByte($34);
|
|
a_i32_atomic_rmw8_or_u:
|
|
WriteByte($35);
|
|
a_i32_atomic_rmw16_or_u:
|
|
WriteByte($36);
|
|
a_i64_atomic_rmw8_or_u:
|
|
WriteByte($37);
|
|
a_i64_atomic_rmw16_or_u:
|
|
WriteByte($38);
|
|
a_i64_atomic_rmw32_or_u:
|
|
WriteByte($39);
|
|
a_i32_atomic_rmw_xor:
|
|
WriteByte($3A);
|
|
a_i64_atomic_rmw_xor:
|
|
WriteByte($3B);
|
|
a_i32_atomic_rmw8_xor_u:
|
|
WriteByte($3C);
|
|
a_i32_atomic_rmw16_xor_u:
|
|
WriteByte($3D);
|
|
a_i64_atomic_rmw8_xor_u:
|
|
WriteByte($3E);
|
|
a_i64_atomic_rmw16_xor_u:
|
|
WriteByte($3F);
|
|
a_i64_atomic_rmw32_xor_u:
|
|
WriteByte($40);
|
|
a_i32_atomic_rmw_xchg:
|
|
WriteByte($41);
|
|
a_i64_atomic_rmw_xchg:
|
|
WriteByte($42);
|
|
a_i32_atomic_rmw8_xchg_u:
|
|
WriteByte($43);
|
|
a_i32_atomic_rmw16_xchg_u:
|
|
WriteByte($44);
|
|
a_i64_atomic_rmw8_xchg_u:
|
|
WriteByte($45);
|
|
a_i64_atomic_rmw16_xchg_u:
|
|
WriteByte($46);
|
|
a_i64_atomic_rmw32_xchg_u:
|
|
WriteByte($47);
|
|
a_i32_atomic_rmw_cmpxchg:
|
|
WriteByte($48);
|
|
a_i64_atomic_rmw_cmpxchg:
|
|
WriteByte($49);
|
|
a_i32_atomic_rmw8_cmpxchg_u:
|
|
WriteByte($4A);
|
|
a_i32_atomic_rmw16_cmpxchg_u:
|
|
WriteByte($4B);
|
|
a_i64_atomic_rmw8_cmpxchg_u:
|
|
WriteByte($4C);
|
|
a_i64_atomic_rmw16_cmpxchg_u:
|
|
WriteByte($4D);
|
|
a_i64_atomic_rmw32_cmpxchg_u:
|
|
WriteByte($4E);
|
|
else
|
|
internalerror(2022052101);
|
|
end;
|
|
if ops<>1 then
|
|
internalerror(2021092016);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if assigned(ref^.symbol) then
|
|
begin
|
|
WriteUleb(natural_alignment_for_load_store(opcode));
|
|
objdata.writeReloc(ref^.offset,5,ObjData.symbolref(ref^.symbol),RELOC_MEMORY_ADDR_LEB);
|
|
end
|
|
else
|
|
begin
|
|
if assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) then
|
|
internalerror(2021092018);
|
|
WriteUleb(natural_alignment_for_load_store(opcode));
|
|
WriteUleb(ref^.offset);
|
|
end;
|
|
end;
|
|
top_const:
|
|
begin
|
|
WriteUleb(natural_alignment_for_load_store(opcode));
|
|
WriteUleb(val);
|
|
end;
|
|
else
|
|
internalerror(2021092017);
|
|
end;
|
|
end;
|
|
a_call:
|
|
begin
|
|
if ops<>2 then
|
|
internalerror(2021092021);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if not assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) or (ref^.offset<>0) then
|
|
internalerror(2021092023);
|
|
WriteByte($10);
|
|
objdata.writeReloc(0,5,ObjData.symbolref(ref^.symbol),RELOC_FUNCTION_INDEX_LEB);
|
|
end;
|
|
else
|
|
internalerror(2021092022);
|
|
end;
|
|
end;
|
|
a_call_indirect:
|
|
begin
|
|
if ops<>1 then
|
|
internalerror(2021092610);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_functype:
|
|
begin
|
|
WriteByte($11);
|
|
objdata.writeReloc(TWasmObjData(objdata).FuncTypes.AddOrGetFuncType(functype),5,nil,RELOC_TYPE_INDEX_LEB);
|
|
WriteUleb(0);
|
|
end;
|
|
else
|
|
internalerror(2021092611);
|
|
end;
|
|
end;
|
|
a_br,
|
|
a_br_if,
|
|
a_rethrow,
|
|
a_delegate:
|
|
begin
|
|
case opcode of
|
|
a_br:
|
|
WriteByte($0C);
|
|
a_br_if:
|
|
WriteByte($0D);
|
|
a_rethrow:
|
|
WriteByte($09);
|
|
a_delegate:
|
|
WriteByte($18);
|
|
else
|
|
internalerror(2021092622);
|
|
end;
|
|
if ops<>1 then
|
|
internalerror(2021092610);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_const:
|
|
WriteUleb(val);
|
|
else
|
|
internalerror(2021092625);
|
|
end;
|
|
end;
|
|
a_catch,
|
|
a_throw:
|
|
begin
|
|
case opcode of
|
|
a_catch:
|
|
WriteByte($07);
|
|
a_throw:
|
|
WriteByte($08);
|
|
else
|
|
internalerror(2021092708);
|
|
end;
|
|
if ops<>1 then
|
|
internalerror(2021092709);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_ref:
|
|
begin
|
|
if not assigned(ref^.symbol) or (ref^.base<>NR_NO) or (ref^.index<>NR_NO) or (ref^.offset<>0) then
|
|
internalerror(2021092711);
|
|
objdata.writeReloc(0,5,TWasmObjData(ObjData).ExceptionTagRef(ref^.symbol),RELOC_TAG_INDEX_LEB);
|
|
end;
|
|
else
|
|
internalerror(2021092710);
|
|
end;
|
|
end;
|
|
a_memory_init:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($08);
|
|
if ops<>1 then
|
|
internalerror(2022052806);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_const:
|
|
WriteUleb(val);
|
|
else
|
|
internalerror(2022052807);
|
|
end;
|
|
WriteByte($00);
|
|
end;
|
|
a_data_drop:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($09);
|
|
if ops<>1 then
|
|
internalerror(2022052808);
|
|
with oper[0]^ do
|
|
case typ of
|
|
top_const:
|
|
WriteUleb(val);
|
|
else
|
|
internalerror(2022052809);
|
|
end;
|
|
end;
|
|
a_i32_trunc_sat_f32_s:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($00);
|
|
end;
|
|
a_i32_trunc_sat_f32_u:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($01);
|
|
end;
|
|
a_i32_trunc_sat_f64_s:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($02);
|
|
end;
|
|
a_i32_trunc_sat_f64_u:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($03);
|
|
end;
|
|
a_i64_trunc_sat_f32_s:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($04);
|
|
end;
|
|
a_i64_trunc_sat_f32_u:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($05);
|
|
end;
|
|
a_i64_trunc_sat_f64_s:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($06);
|
|
end;
|
|
a_i64_trunc_sat_f64_u:
|
|
begin
|
|
WriteByte($FC);
|
|
WriteByte($07);
|
|
end;
|
|
a_ref_null_funcref:
|
|
begin
|
|
WriteByte($D0);
|
|
WriteByte($70);
|
|
end;
|
|
a_ref_null_externref:
|
|
begin
|
|
WriteByte($D0);
|
|
WriteByte($6F);
|
|
end;
|
|
a_ref_is_null:
|
|
WriteByte($D1);
|
|
else
|
|
internalerror(2021092624);
|
|
end;
|
|
end;
|
|
|
|
|
|
function spilling_create_load(const ref:treference;r:tregister):Taicpu;
|
|
begin
|
|
internalerror(2010122614);
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
function spilling_create_store(r:tregister; const ref:treference):Taicpu;
|
|
begin
|
|
internalerror(2010122615);
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
procedure InitAsm;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure DoneAsm;
|
|
begin
|
|
end;
|
|
|
|
|
|
function wasm_convert_first_item_to_structured(srclist: TAsmList): tai;
|
|
begin
|
|
result:=tai(srclist.First);
|
|
if result<>nil then
|
|
begin
|
|
srclist.Remove(result);
|
|
if result.typ=ait_instruction then
|
|
case taicpu(result).opcode of
|
|
a_if:
|
|
result:=tai_wasmstruc_if.create_from(taicpu(result),srclist);
|
|
a_block:
|
|
result:=tai_wasmstruc_block.create_from(taicpu(result),srclist);
|
|
a_loop:
|
|
result:=tai_wasmstruc_loop.create_from(taicpu(result),srclist);
|
|
a_try:
|
|
result:=tai_wasmstruc_try.create_from(srclist);
|
|
a_else,a_end_if,a_end_block,a_end_loop,a_end_try,a_catch,a_catch_all,a_delegate:
|
|
internalerror(2023100503);
|
|
else
|
|
;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure wasm_convert_to_structured_asmlist_internal(srclist, destlist: TAsmList);
|
|
begin
|
|
while not srclist.Empty do
|
|
destlist.Concat(wasm_convert_first_item_to_structured(srclist));
|
|
end;
|
|
|
|
|
|
procedure wasm_convert_to_structured_asmlist(var asmlist: TAsmList);
|
|
var
|
|
tmplist: TAsmList;
|
|
begin
|
|
tmplist:=TAsmList.Create;
|
|
wasm_convert_to_structured_asmlist_internal(asmlist,tmplist);
|
|
asmlist.Free;
|
|
asmlist:=tmplist;
|
|
end;
|
|
|
|
procedure wasm_convert_to_flat_asmlist_internal(srclist, destlist: TAsmList);
|
|
var
|
|
p: tai;
|
|
tmplist: TAsmList;
|
|
begin
|
|
tmplist:=TAsmList.Create;
|
|
while not srclist.Empty do
|
|
begin
|
|
p:=tai(srclist.First);
|
|
srclist.Remove(p);
|
|
if p.typ=ait_wasm_structured_instruction then
|
|
begin
|
|
taicpu_wasm_structured_instruction(p).ConvertToFlatList(tmplist);
|
|
srclist.insertList(tmplist);
|
|
end
|
|
else
|
|
destlist.Concat(p);
|
|
end;
|
|
tmplist.free;
|
|
end;
|
|
|
|
|
|
procedure wasm_convert_to_flat_asmlist(var asmlist: TAsmList);
|
|
var
|
|
tmplist: TAsmList;
|
|
begin
|
|
tmplist:=TAsmList.Create;
|
|
wasm_convert_to_flat_asmlist_internal(asmlist,tmplist);
|
|
asmlist.Free;
|
|
asmlist:=tmplist;
|
|
end;
|
|
|
|
|
|
procedure map_structured_asmlist_inner(l: TAsmList; f: TAsmMapFunc; blockstack: twasmstruc_stack);
|
|
var
|
|
p, q: tai;
|
|
mapres: TAsmMapFuncResult;
|
|
begin
|
|
if not assigned(l) then
|
|
exit;
|
|
p:=tai(l.First);
|
|
while p<>nil do
|
|
begin
|
|
if p.typ=ait_wasm_structured_instruction then
|
|
begin
|
|
mapres:=f(p,blockstack);
|
|
case mapres.typ of
|
|
amfrtNoChange:
|
|
begin
|
|
taicpu_wasm_structured_instruction(p).Map(f,blockstack);
|
|
p:=tai(p.next);
|
|
end;
|
|
amfrtNewAi:
|
|
begin
|
|
q:=mapres.newai;
|
|
if q<>p then
|
|
begin
|
|
l.InsertAfter(q,p);
|
|
l.Remove(p);
|
|
p:=q;
|
|
end;
|
|
p:=tai(p.next);
|
|
end;
|
|
amfrtNewList:
|
|
begin
|
|
q:=tai(mapres.newlist.First);
|
|
l.insertListAfter(p,mapres.newlist);
|
|
mapres.newlist.free;
|
|
l.Remove(p);
|
|
p:=q;
|
|
end;
|
|
amfrtDeleteAi:
|
|
begin
|
|
q:=p;
|
|
p:=tai(p.next);
|
|
l.Remove(q);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
mapres:=f(p,blockstack);
|
|
case mapres.typ of
|
|
amfrtNoChange:
|
|
p:=tai(p.next);
|
|
amfrtNewAi:
|
|
begin
|
|
q:=mapres.newai;
|
|
if q<>p then
|
|
begin
|
|
l.InsertAfter(q,p);
|
|
l.Remove(p);
|
|
p:=tai(q.next);
|
|
end
|
|
else
|
|
p:=tai(p.next);
|
|
end;
|
|
amfrtNewList:
|
|
begin
|
|
q:=tai(mapres.newlist.First);
|
|
l.insertListAfter(p,mapres.newlist);
|
|
mapres.newlist.free;
|
|
l.Remove(p);
|
|
p:=q;
|
|
end;
|
|
amfrtDeleteAi:
|
|
begin
|
|
q:=p;
|
|
p:=tai(p.next);
|
|
l.Remove(q);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure map_structured_asmlist(l: TAsmList; f: TAsmMapFunc);
|
|
var
|
|
blockstack: twasmstruc_stack;
|
|
begin
|
|
blockstack:=twasmstruc_stack.create;
|
|
map_structured_asmlist_inner(l,f,blockstack);
|
|
blockstack.free;
|
|
end;
|
|
|
|
|
|
initialization
|
|
cai_cpu:=taicpu;
|
|
cai_align:=tai_align;
|
|
end.
|