mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-10 11:18:45 +02:00
2042 lines
60 KiB
ObjectPascal
2042 lines
60 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
|
|
|
|
{ taicpu }
|
|
|
|
taicpu = class(tai_cpu_abstract_sym)
|
|
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_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;
|
|
|
|
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)
|
|
bastyp: TWasmBasicType;
|
|
name : string;
|
|
first: boolean;
|
|
last: boolean;
|
|
constructor create(abasictype: TWasmBasicType; const aname: string = '');
|
|
end;
|
|
|
|
{ tai_globaltype }
|
|
|
|
tai_globaltype = class(tai)
|
|
globalname: string;
|
|
gtype: TWasmBasicType;
|
|
immutable: boolean;
|
|
is_external: boolean;
|
|
is_global: boolean;
|
|
sym : tasmsymbol;
|
|
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;
|
|
constructor create(const afuncname: string; afunctype: TWasmFuncType);
|
|
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;
|
|
|
|
implementation
|
|
|
|
uses
|
|
ogwasm;
|
|
|
|
{ tai_globaltype }
|
|
|
|
constructor tai_globaltype.create(const aglobalname: string; atype: TWasmBasicType; aimmutable: boolean);
|
|
begin
|
|
inherited Create;
|
|
sym:=current_asmdata.RefAsmSymbol(aglobalname,AT_WASM_GLOBAL);
|
|
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:=current_asmdata.DefineAsmSymbol(aglobalname,AB_LOCAL,AT_WASM_GLOBAL,def);
|
|
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:=current_asmdata.DefineAsmSymbol(aglobalname,AB_GLOBAL,AT_WASM_GLOBAL,def);
|
|
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);
|
|
begin
|
|
inherited Create;
|
|
typ:=ait_functype;
|
|
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(abasictype: TWasmBasicType; const aname: string);
|
|
begin
|
|
inherited Create;
|
|
bastyp := abasictype;
|
|
typ := ait_local;
|
|
name := aname;
|
|
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.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_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;
|
|
begin
|
|
result:=0;
|
|
repeat
|
|
v:=SarInt64(v,7);
|
|
Inc(result);
|
|
until ((v=0) and ((byte(v) and 64)=0)) or ((v=-1) and ((byte(v) 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;
|
|
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_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;
|
|
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_end_function:
|
|
result:=0;
|
|
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<>1 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).AddFuncType(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
|
|
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:
|
|
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;
|
|
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_end_function:
|
|
;
|
|
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<>1 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).AddFuncType(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;
|
|
|
|
initialization
|
|
cai_cpu:=taicpu;
|
|
cai_align:=tai_align;
|
|
end.
|