ソースを参照

+ support nil comparison of WebAssembly reference types (externref and funcref)

Nikolay Nikolov 2 年 前
コミット
8cd6606970

+ 12 - 2
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);

+ 47 - 4
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);

+ 10 - 0
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.

+ 10 - 0
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.