From 8cd6606970c8fedda95a3411d684dbd57379b46d Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Sun, 11 Jun 2023 07:17:04 +0300 Subject: [PATCH] + support nil comparison of WebAssembly reference types (externref and funcref) --- compiler/nadd.pas | 14 ++++++-- compiler/wasm32/hlcgcpu.pas | 51 +++++++++++++++++++++++++++--- tests/test/wasm/twasmexternref1.pp | 10 ++++++ tests/test/wasm/twasmfuncref1.pp | 10 ++++++ 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/compiler/nadd.pas b/compiler/nadd.pas index 77e9cfc464..473a839233 100644 --- a/compiler/nadd.pas +++ b/compiler/nadd.pas @@ -2675,9 +2675,9 @@ implementation case nodetype of equaln,unequaln : begin - if is_voidpointer(right.resultdef) then + if is_voidpointer(right.resultdef) and (left.nodetype<>niln) then inserttypeconv(right,left.resultdef) - else if is_voidpointer(left.resultdef) then + else if is_voidpointer(left.resultdef) and (right.nodetype<>niln) then inserttypeconv(left,right.resultdef) else if not(equal_defs(ld,rd)) then IncompatibleTypes(ld,rd); @@ -2704,6 +2704,16 @@ implementation inserttypeconv_internal(right,charfarpointertype) else inserttypeconv_internal(right,charnearpointertype); +{$elseif defined(wasm)} + if is_wasm_reference_type(left.resultdef) then + inserttypeconv(right,left.resultdef) + else if is_wasm_reference_type(right.resultdef) then + inserttypeconv(left,right.resultdef) + else + begin + inserttypeconv_internal(left,charpointertype); + inserttypeconv_internal(right,charpointertype); + end; {$else} inserttypeconv_internal(left,charpointertype); inserttypeconv_internal(right,charpointertype); diff --git a/compiler/wasm32/hlcgcpu.pas b/compiler/wasm32/hlcgcpu.pas index 65575655df..dcccbbca0e 100644 --- a/compiler/wasm32/hlcgcpu.pas +++ b/compiler/wasm32/hlcgcpu.pas @@ -754,19 +754,62 @@ implementation procedure thlcgwasm.a_cmp_const_ref_stack(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference); var tmpref: treference; + regtyp: TRegisterType; begin tmpref:=ref; if tmpref.base<>NR_EVAL_STACK_BASE then a_load_ref_stack(list,size,tmpref,prepare_stack_for_ref(list,tmpref,false)); - a_load_const_stack(list,size,a,def2regtyp(size)); - a_cmp_stack_stack(list,size,cmp_op); + regtyp:=def2regtyp(size); + case regtyp of + R_EXTERNREFREGISTER, + R_FUNCREFREGISTER: + begin + if a<>0 then + internalerror(2023061103); + if not (cmp_op in [OC_EQ,OC_NE]) then + internalerror(2023061104); + list.Concat(taicpu.op_none(a_ref_is_null)); + if cmp_op=OC_NE then + begin + a_load_const_stack(list,s32inttype,0,R_INTREGISTER); + a_cmp_stack_stack(list,s32inttype,OC_EQ); + end; + end; + else + begin + a_load_const_stack(list,size,a,regtyp); + a_cmp_stack_stack(list,size,cmp_op); + end; + end; end; procedure thlcgwasm.a_cmp_const_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister); + var + regtyp: TRegisterType; begin a_load_reg_stack(list,size,reg); - a_load_const_stack(list,size,a,def2regtyp(size)); - a_cmp_stack_stack(list,size,cmp_op); + regtyp:=def2regtyp(size); + case regtyp of + R_EXTERNREFREGISTER, + R_FUNCREFREGISTER: + begin + if a<>0 then + internalerror(2023061105); + if not (cmp_op in [OC_EQ,OC_NE]) then + internalerror(2023061106); + list.Concat(taicpu.op_none(a_ref_is_null)); + if cmp_op=OC_NE then + begin + a_load_const_stack(list,s32inttype,0,R_INTREGISTER); + a_cmp_stack_stack(list,s32inttype,OC_EQ); + end; + end; + else + begin + a_load_const_stack(list,size,a,regtyp); + a_cmp_stack_stack(list,size,cmp_op); + end; + end; end; procedure thlcgwasm.a_cmp_ref_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister); diff --git a/tests/test/wasm/twasmexternref1.pp b/tests/test/wasm/twasmexternref1.pp index e8ed9f7186..db786f5a23 100644 --- a/tests/test/wasm/twasmexternref1.pp +++ b/tests/test/wasm/twasmexternref1.pp @@ -33,6 +33,16 @@ begin testproc5 := nil; end; +function testproc6: Boolean; +var + q: WasmExternRef; +begin + testproc6 := q = nil; + testproc6 := nil = q; + testproc6 := q <> nil; + testproc6 := nil <> q; +end; + begin testproc5(nil); end. diff --git a/tests/test/wasm/twasmfuncref1.pp b/tests/test/wasm/twasmfuncref1.pp index f3743a68b6..6042d8995f 100644 --- a/tests/test/wasm/twasmfuncref1.pp +++ b/tests/test/wasm/twasmfuncref1.pp @@ -38,6 +38,16 @@ begin testproc5 := nil; end; +function testproc6: Boolean; +var + q: TWasmFuncRef; +begin + testproc6 := q = nil; + testproc6 := nil = q; + testproc6 := q <> nil; + testproc6 := nil <> q; +end; + begin testproc5(nil); end.