{ Copyright (c) 1998-2020 by Florian Klaempfl and Nikolay Nikolov Generate WebAssembly code for type converting nodes This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by 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 nwasmcnv; {$i fpcdefs.inc} interface uses node,ncnv,ncgcnv; type { twasmtypeconvnode } twasmtypeconvnode = class(tcgtypeconvnode) protected function first_int_to_real: tnode; override; procedure second_int_to_real;override; procedure second_int_to_bool;override; procedure second_ansistring_to_pchar;override; procedure second_class_to_intf;override; public function target_specific_explicit_typeconv: boolean;override; end; implementation uses verbose,globals,globtype,aasmdata, defutil,defcmp,fmodule,cpubase, cgbase,cgutils,pass_1,pass_2, aasmbase,aasmcpu, symdef,symconst, tgobj, hlcgobj,hlcgcpu; { twasmtypeconvnode } function twasmtypeconvnode.first_int_to_real: tnode; begin first_int_to_real:=nil; if left.resultdef.size<4 then begin inserttypeconv(left,s32inttype); firstpass(left); end; expectloc:=LOC_FPUREGISTER; end; procedure twasmtypeconvnode.second_int_to_real; var op: TAsmOp; begin case tfloatdef(resultdef).floattype of s32real: begin if is_64bitint(left.resultdef) or is_currency(left.resultdef) then begin if is_signed(left.resultdef) then op:=a_f32_convert_i64_s else op:=a_f32_convert_i64_u; end else { other integers are supposed to be 32 bit } begin if is_signed(left.resultdef) then op:=a_f32_convert_i32_s else op:=a_f32_convert_i32_u; end; end; s64real: begin if is_64bitint(left.resultdef) or is_currency(left.resultdef) then begin if is_signed(left.resultdef) then op:=a_f64_convert_i64_s else op:=a_f64_convert_i64_u; end else { other integers are supposed to be 32 bit } begin if is_signed(left.resultdef) then op:=a_f64_convert_i32_s else op:=a_f64_convert_i32_u; end; end; else internalerror(2021010501); end; thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location); current_asmdata.CurrAsmList.concat(taicpu.op_none(op)); location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef)); location.register := hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef); thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location); end; procedure twasmtypeconvnode.second_int_to_bool; begin secondpass(left); if codegenerror then exit; thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location); thlcgwasm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,left.resultdef,0,R_INTREGISTER); thlcgwasm(hlcg).a_cmp_stack_stack(current_asmdata.CurrAsmList,left.resultdef,OC_NE); if is_cbool(resultdef) then begin if is_64bit(resultdef) then current_asmdata.CurrAsmList.Concat(taicpu.op_functype(a_if,TWasmFuncType.Create([],[wbt_i64]))) else current_asmdata.CurrAsmList.Concat(taicpu.op_functype(a_if,TWasmFuncType.Create([],[wbt_i32]))); thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1); if is_64bit(resultdef) then current_asmdata.CurrAsmList.Concat( taicpu.op_const(a_i64_const, -1) ) else if is_32bit(resultdef) then current_asmdata.CurrAsmList.Concat( taicpu.op_const(a_i32_const, -1) ) else if is_16bit(resultdef) then current_asmdata.CurrAsmList.Concat( taicpu.op_const(a_i32_const, 65535) ) else if is_8bit(resultdef) then current_asmdata.CurrAsmList.Concat( taicpu.op_const(a_i32_const, 255) ) else internalerror(2021100101); thlcgwasm(hlcg).incstack(current_asmdata.CurrAsmList,1); current_asmdata.CurrAsmList.Concat( taicpu.op_none(a_else) ); thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1); if is_64bit(resultdef) then current_asmdata.CurrAsmList.Concat( taicpu.op_const(a_i64_const, 0) ) else current_asmdata.CurrAsmList.Concat( taicpu.op_const(a_i32_const, 0) ); thlcgwasm(hlcg).incstack(current_asmdata.CurrAsmList,1); current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if)); end else thlcgwasm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,u32inttype,resultdef,false); location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); location.register := hlcg.getintregister(current_asmdata.CurrAsmList,resultdef); thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location); end; procedure twasmtypeconvnode.second_ansistring_to_pchar; var hr : treference; begin thlcgwasm(hlcg).a_cmp_const_loc_stack(current_asmdata.CurrAsmList,left.resultdef,OC_NE,0,left.location); current_asmdata.CurrAsmList.Concat(taicpu.op_functype(a_if,TWasmFuncType.Create([],[wbt_i32]))); thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1); thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location); current_asmdata.CurrAsmList.Concat(taicpu.op_none(a_else)); thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1); { FPC_EMPTYCHAR is a widechar -> 2 bytes } reference_reset(hr,2,[]); hr.symbol:=current_asmdata.RefAsmSymbol('FPC_EMPTYCHAR',AT_DATA); current_module.add_extern_asmsym('FPC_EMPTYCHAR',AB_EXTERNAL,AT_DATA); thlcgwasm(hlcg).a_loadaddr_ref_stack(current_asmdata.CurrAsmList,cwidechartype,resultdef,hr); current_asmdata.CurrAsmList.Concat( taicpu.op_none(a_end_if) ); location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef); thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location); end; procedure twasmtypeconvnode.second_class_to_intf; var hd : tobjectdef; ImplIntf : TImplementedInterface; begin location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); case left.location.loc of LOC_CREFERENCE, LOC_REFERENCE: begin location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef); hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.reference,location.register); location_freetemp(current_asmdata.CurrAsmList,left.location); end; LOC_CREGISTER: begin location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef); hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register); end; LOC_REGISTER: begin location.register:=left.location.register; hlcg.g_ptrtypecast_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,location.register); end; LOC_CONSTANT: begin location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef); hlcg.a_load_const_reg(current_asmdata.CurrAsmList,resultdef,left.location.value,location.register); end else internalerror(121120001); end; hd:=tobjectdef(left.resultdef); while assigned(hd) do begin ImplIntf:=find_implemented_interface(hd,tobjectdef(resultdef)); if assigned(ImplIntf) then begin case ImplIntf.IType of etStandard: begin thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,resultdef,OC_NE,0,location.register); current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if)); thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1); hlcg.a_op_const_reg(current_asmdata.CurrAsmList,OP_ADD,resultdef,ImplIntf.ioffset,location.register); current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if)); break; end; else internalerror(200802163); end; end; hd:=hd.childof; end; if hd=nil then internalerror(2002081301); end; function twasmtypeconvnode.target_specific_explicit_typeconv: boolean; begin result:=false; if is_pointer(left.resultdef) and is_pointer(resultdef) and not tpointerdef(left.resultdef).compatible_with_pointerdef_size(tpointerdef(resultdef)) then CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename); end; begin ctypeconvnode:=twasmtypeconvnode; end.